]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/cvs/src/status.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / contrib / cvs / src / status.c
1 /*
2  * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3  *
4  * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5  *                                  and others.
6  *
7  * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8  * Portions Copyright (C) 1989-1992, Brian Berliner
9  * 
10  * You may distribute under the terms of the GNU General Public License as
11  * specified in the README file that comes with the CVS source distribution.
12  * 
13  * Status Information
14  */
15
16 #include "cvs.h"
17
18 static Dtype status_dirproc PROTO ((void *callerdat, const char *dir,
19                                     const char *repos, const char *update_dir,
20                                     List *entries));
21 static int status_fileproc PROTO ((void *callerdat, struct file_info *finfo));
22 static int tag_list_proc PROTO((Node * p, void *closure));
23
24 static int local = 0;
25 static int long_format = 0;
26 static RCSNode *xrcsnode;
27
28 static const char *const status_usage[] =
29 {
30     "Usage: %s %s [-vlR] [files...]\n",
31     "\t-v\tVerbose format; includes tag information for the file\n",
32     "\t-l\tProcess this directory only (not recursive).\n",
33     "\t-R\tProcess directories recursively.\n",
34     "(Specify the --help global option for a list of other help options)\n",
35     NULL
36 };
37
38 int
39 cvsstatus (argc, argv)
40     int argc;
41     char **argv;
42 {
43     int c;
44     int err = 0;
45
46     if (argc == -1)
47         usage (status_usage);
48
49     optind = 0;
50     while ((c = getopt (argc, argv, "+vlR")) != -1)
51     {
52         switch (c)
53         {
54             case 'v':
55                 long_format = 1;
56                 break;
57             case 'l':
58                 local = 1;
59                 break;
60             case 'R':
61                 local = 0;
62                 break;
63             case '?':
64             default:
65                 usage (status_usage);
66                 break;
67         }
68     }
69     argc -= optind;
70     argv += optind;
71
72     wrap_setup ();
73
74 #ifdef CLIENT_SUPPORT
75     if (current_parsed_root->isremote)
76     {
77         start_server ();
78
79         ign_setup ();
80
81         if (long_format)
82             send_arg("-v");
83         if (local)
84             send_arg("-l");
85         send_arg ("--");
86
87         /* For a while, we tried setting SEND_NO_CONTENTS here so this
88            could be a fast operation.  That prevents the
89            server from updating our timestamp if the timestamp is
90            changed but the file is unmodified.  Worse, it is user-visible
91            (shows "locally modified" instead of "up to date" if
92            timestamp is changed but file is not).  And there is no good
93            workaround (you might not want to run "cvs update"; "cvs -n
94            update" doesn't update CVS/Entries; "cvs diff --brief" or
95            something perhaps could be made to work but somehow that
96            seems nonintuitive to me even if so).  Given that timestamps
97            seem to have the potential to get munged for any number of
98            reasons, it seems better to not rely too much on them.  */
99
100         send_files (argc, argv, local, 0, 0);
101
102         send_file_names (argc, argv, SEND_EXPAND_WILD);
103
104         send_to_server ("status\012", 0);
105         err = get_responses_and_close ();
106
107         return err;
108     }
109 #endif
110
111     /* start the recursion processor */
112     err = start_recursion (status_fileproc, (FILESDONEPROC) NULL,
113                            status_dirproc, (DIRLEAVEPROC) NULL, NULL,
114                            argc, argv, local,
115                            W_LOCAL, 0, CVS_LOCK_READ, (char *) NULL, 1,
116                            (char *) NULL);
117
118     return (err);
119 }
120
121 /*
122  * display the status of a file
123  */
124 /* ARGSUSED */
125 static int
126 status_fileproc (callerdat, finfo)
127     void *callerdat;
128     struct file_info *finfo;
129 {
130     Ctype status;
131     char *sstat;
132     Vers_TS *vers;
133
134     status = Classify_File (finfo, (char *) NULL, (char *) NULL, (char *) NULL,
135                             1, 0, &vers, 0);
136     sstat = "Classify Error";
137     switch (status)
138     {
139         case T_UNKNOWN:
140             sstat = "Unknown";
141             break;
142         case T_CHECKOUT:
143             sstat = "Needs Checkout";
144             break;
145         case T_PATCH:
146             sstat = "Needs Patch";
147             break;
148         case T_CONFLICT:
149             sstat = "Unresolved Conflict";
150             break;
151         case T_ADDED:
152             sstat = "Locally Added";
153             break;
154         case T_REMOVED:
155             sstat = "Locally Removed";
156             break;
157         case T_MODIFIED:
158             if (file_has_markers (finfo))
159                 sstat = "File had conflicts on merge";
160             else
161                 /* Note that we do not re Register() the file when we spot
162                  * a resolved conflict like update_fileproc() does on the
163                  * premise that status should not alter the sandbox.
164                  */
165                 sstat = "Locally Modified";
166             break;
167         case T_REMOVE_ENTRY:
168             sstat = "Entry Invalid";
169             break;
170         case T_UPTODATE:
171             sstat = "Up-to-date";
172             break;
173         case T_NEEDS_MERGE:
174             sstat = "Needs Merge";
175             break;
176         case T_TITLE:
177             /* I don't think this case can occur here.  Just print
178                "Classify Error".  */
179             break;
180     }
181
182     cvs_output ("\
183 ===================================================================\n", 0);
184     if (vers->ts_user == NULL)
185     {
186         cvs_output ("File: no file ", 0);
187         cvs_output (finfo->file, 0);
188         cvs_output ("\t\tStatus: ", 0);
189         cvs_output (sstat, 0);
190         cvs_output ("\n\n", 0);
191     }
192     else
193     {
194         char *buf;
195         buf = xmalloc (strlen (finfo->file) + strlen (sstat) + 80);
196         sprintf (buf, "File: %-17s\tStatus: %s\n\n", finfo->file, sstat);
197         cvs_output (buf, 0);
198         free (buf);
199     }
200
201     if (vers->vn_user == NULL)
202     {
203         cvs_output ("   Working revision:\tNo entry for ", 0);
204         cvs_output (finfo->file, 0);
205         cvs_output ("\n", 0);
206     }
207     else if (vers->vn_user[0] == '0' && vers->vn_user[1] == '\0')
208         cvs_output ("   Working revision:\tNew file!\n", 0);
209     else
210     {
211         cvs_output ("   Working revision:\t", 0);
212         cvs_output (vers->vn_user, 0);
213         if (!server_active)
214         {
215             cvs_output ("\t", 0);
216             cvs_output (vers->ts_rcs, 0);
217         }
218         cvs_output ("\n", 0);
219     }
220
221     if (vers->vn_rcs == NULL)
222         cvs_output ("   Repository revision:\tNo revision control file\n", 0);
223     else
224     {
225         cvs_output ("   Repository revision:\t", 0);
226         cvs_output (vers->vn_rcs, 0);
227         cvs_output ("\t", 0);
228         cvs_output (vers->srcfile->path, 0);
229         cvs_output ("\n", 0);
230     }
231
232     if (vers->entdata)
233     {
234         Entnode *edata;
235
236         edata = vers->entdata;
237         if (edata->tag)
238         {
239             if (vers->vn_rcs == NULL)
240             {
241                 cvs_output ("   Sticky Tag:\t\t", 0);
242                 cvs_output (edata->tag, 0);
243                 cvs_output (" - MISSING from RCS file!\n", 0);
244             }
245             else
246             {
247                 if (isdigit ((unsigned char) edata->tag[0]))
248                 {
249                     cvs_output ("   Sticky Tag:\t\t", 0);
250                     cvs_output (edata->tag, 0);
251                     cvs_output ("\n", 0);
252                 }
253                 else
254                 {
255                     char *branch = NULL;
256
257                     if (RCS_nodeisbranch (finfo->rcs, edata->tag))
258                         branch = RCS_whatbranch(finfo->rcs, edata->tag);
259
260                     cvs_output ("   Sticky Tag:\t\t", 0);
261                     cvs_output (edata->tag, 0);
262                     cvs_output (" (", 0);
263                     cvs_output (branch ? "branch" : "revision", 0);
264                     cvs_output (": ", 0);
265                     cvs_output (branch ? branch : vers->vn_rcs, 0);
266                     cvs_output (")\n", 0);
267
268                     if (branch)
269                         free (branch);
270                 }
271             }
272         }
273         else if (!really_quiet)
274             cvs_output ("   Sticky Tag:\t\t(none)\n", 0);
275
276         if (edata->date)
277         {
278             cvs_output ("   Sticky Date:\t\t", 0);
279             cvs_output (edata->date, 0);
280             cvs_output ("\n", 0);
281         }
282         else if (!really_quiet)
283             cvs_output ("   Sticky Date:\t\t(none)\n", 0);
284
285         if (edata->options && edata->options[0])
286         {
287             cvs_output ("   Sticky Options:\t", 0);
288             cvs_output (edata->options, 0);
289             cvs_output ("\n", 0);
290         }
291         else if (!really_quiet)
292             cvs_output ("   Sticky Options:\t(none)\n", 0);
293     }
294
295     if (long_format && vers->srcfile)
296     {
297         List *symbols = RCS_symbols(vers->srcfile);
298
299         cvs_output ("\n   Existing Tags:\n", 0);
300         if (symbols)
301         {
302             xrcsnode = finfo->rcs;
303             (void) walklist (symbols, tag_list_proc, NULL);
304         }
305         else
306             cvs_output ("\tNo Tags Exist\n", 0);
307     }
308
309     cvs_output ("\n", 0);
310     freevers_ts (&vers);
311     return (0);
312 }
313
314 /*
315  * Print a warm fuzzy message
316  */
317 /* ARGSUSED */
318 static Dtype
319 status_dirproc (callerdat, dir, repos, update_dir, entries)
320     void *callerdat;
321     const char *dir;
322     const char *repos;
323     const char *update_dir;
324     List *entries;
325 {
326     if (!quiet)
327         error (0, 0, "Examining %s", update_dir);
328     return (R_PROCESS);
329 }
330
331 /*
332  * Print out a tag and its type
333  */
334 static int
335 tag_list_proc (p, closure)
336     Node *p;
337     void *closure;
338 {
339     char *branch = NULL;
340     char *buf;
341
342     if (RCS_nodeisbranch (xrcsnode, p->key))
343         branch = RCS_whatbranch(xrcsnode, p->key) ;
344
345     buf = xmalloc (80 + strlen (p->key)
346                    + (branch ? strlen (branch) : strlen (p->data)));
347     sprintf (buf, "\t%-25s\t(%s: %s)\n", p->key,
348              branch ? "branch" : "revision",
349              branch ? branch : (char *)p->data);
350     cvs_output (buf, 0);
351     free (buf);
352
353     if (branch)
354         free (branch);
355
356     return (0);
357 }