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