Thu Mar 8 20:46:59 2012 UTC ()
add acl support


(christos)
diff -r1.2 -r1.3 src/external/gpl2/xcvs/dist/src/log.c

cvs diff -r1.2 -r1.3 src/external/gpl2/xcvs/dist/src/log.c (switch to unified diff)

--- src/external/gpl2/xcvs/dist/src/log.c 2009/04/10 11:20:30 1.2
+++ src/external/gpl2/xcvs/dist/src/log.c 2012/03/08 20:46:59 1.3
@@ -1,1782 +1,1801 @@ @@ -1,1782 +1,1801 @@
1/* 1/*
2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc. 2 * Copyright (C) 1986-2005 The Free Software Foundation, Inc.
3 * 3 *
4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>, 4 * Portions Copyright (C) 1998-2005 Derek Price, Ximbiot <http://ximbiot.com>,
5 * and others. 5 * and others.
6 * 6 *
7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk 7 * Portions Copyright (C) 1992, Brian Berliner and Jeff Polk
8 * Portions Copyright (C) 1989-1992, Brian Berliner 8 * Portions Copyright (C) 1989-1992, Brian Berliner
9 *  9 *
10 * You may distribute under the terms of the GNU General Public License as 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. 11 * specified in the README file that comes with the CVS source distribution.
12 *  12 *
13 * Print Log Information 13 * Print Log Information
14 *  14 *
15 * Prints the RCS "log" (rlog) information for the specified files. With no 15 * Prints the RCS "log" (rlog) information for the specified files. With no
16 * argument, prints the log information for all the files in the directory 16 * argument, prints the log information for all the files in the directory
17 * (recursive by default). 17 * (recursive by default).
18 */ 18 */
19 19
20#include "cvs.h" 20#include "cvs.h"
21#include <assert.h> 21#include <assert.h>
22 22
23/* This structure holds information parsed from the -r option. */ 23/* This structure holds information parsed from the -r option. */
24 24
25struct option_revlist 25struct option_revlist
26{ 26{
27 /* The next -r option. */ 27 /* The next -r option. */
28 struct option_revlist *next; 28 struct option_revlist *next;
29 /* The first revision to print. This is NULL if the range is 29 /* The first revision to print. This is NULL if the range is
30 :rev, or if no revision is given. */ 30 :rev, or if no revision is given. */
31 char *first; 31 char *first;
32 /* The last revision to print. This is NULL if the range is rev:, 32 /* The last revision to print. This is NULL if the range is rev:,
33 or if no revision is given. If there is no colon, first and 33 or if no revision is given. If there is no colon, first and
34 last are the same. */ 34 last are the same. */
35 char *last; 35 char *last;
36 /* Nonzero if there was a trailing `.', which means to print only 36 /* Nonzero if there was a trailing `.', which means to print only
37 the head revision of a branch. */ 37 the head revision of a branch. */
38 int branchhead; 38 int branchhead;
39 /* Nonzero if first and last are inclusive. */ 39 /* Nonzero if first and last are inclusive. */
40 int inclusive; 40 int inclusive;
41}; 41};
42 42
43/* This structure holds information derived from option_revlist given 43/* This structure holds information derived from option_revlist given
44 a particular RCS file. */ 44 a particular RCS file. */
45 45
46struct revlist 46struct revlist
47{ 47{
48 /* The next pair. */ 48 /* The next pair. */
49 struct revlist *next; 49 struct revlist *next;
50 /* The first numeric revision to print. */ 50 /* The first numeric revision to print. */
51 char *first; 51 char *first;
52 /* The last numeric revision to print. */ 52 /* The last numeric revision to print. */
53 char *last; 53 char *last;
54 /* The number of fields in these revisions (one more than 54 /* The number of fields in these revisions (one more than
55 numdots). */ 55 numdots). */
56 int fields; 56 int fields;
57 /* Whether first & last are to be included or excluded. */ 57 /* Whether first & last are to be included or excluded. */
58 int inclusive; 58 int inclusive;
59}; 59};
60 60
61/* This structure holds information parsed from the -d option. */ 61/* This structure holds information parsed from the -d option. */
62 62
63struct datelist 63struct datelist
64{ 64{
65 /* The next date. */ 65 /* The next date. */
66 struct datelist *next; 66 struct datelist *next;
67 /* The starting date. */ 67 /* The starting date. */
68 char *start; 68 char *start;
69 /* The ending date. */ 69 /* The ending date. */
70 char *end; 70 char *end;
71 /* Nonzero if the range is inclusive rather than exclusive. */ 71 /* Nonzero if the range is inclusive rather than exclusive. */
72 int inclusive; 72 int inclusive;
73}; 73};
74 74
75/* This structure is used to pass information through start_recursion. */ 75/* This structure is used to pass information through start_recursion. */
76struct log_data 76struct log_data
77{ 77{
78 /* Nonzero if the -R option was given, meaning that only the name 78 /* Nonzero if the -R option was given, meaning that only the name
79 of the RCS file should be printed. */ 79 of the RCS file should be printed. */
80 int nameonly; 80 int nameonly;
81 /* Nonzero if the -h option was given, meaning that only header 81 /* Nonzero if the -h option was given, meaning that only header
82 information should be printed. */ 82 information should be printed. */
83 int header; 83 int header;
84 /* Nonzero if the -t option was given, meaning that only the 84 /* Nonzero if the -t option was given, meaning that only the
85 header and the descriptive text should be printed. */ 85 header and the descriptive text should be printed. */
86 int long_header; 86 int long_header;
87 /* Nonzero if the -N option was seen, meaning that tag information 87 /* Nonzero if the -N option was seen, meaning that tag information
88 should not be printed. */ 88 should not be printed. */
89 int notags; 89 int notags;
90 /* Nonzero if the -b option was seen, meaning that only revisions 90 /* Nonzero if the -b option was seen, meaning that only revisions
91 on the default branch should be printed. */ 91 on the default branch should be printed. */
92 int default_branch; 92 int default_branch;
93 /* Nonzero if the -S option was seen, meaning that the header/name 93 /* Nonzero if the -S option was seen, meaning that the header/name
94 should be suppressed if no revisions are selected. */ 94 should be suppressed if no revisions are selected. */
95 int sup_header; 95 int sup_header;
96 /* If not NULL, the value given for the -r option, which lists 96 /* If not NULL, the value given for the -r option, which lists
97 sets of revisions to be printed. */ 97 sets of revisions to be printed. */
98 struct option_revlist *revlist; 98 struct option_revlist *revlist;
99 /* If not NULL, the date pairs given for the -d option, which 99 /* If not NULL, the date pairs given for the -d option, which
100 select date ranges to print. */ 100 select date ranges to print. */
101 struct datelist *datelist; 101 struct datelist *datelist;
102 /* If not NULL, the single dates given for the -d option, which 102 /* If not NULL, the single dates given for the -d option, which
103 select specific revisions to print based on a date. */ 103 select specific revisions to print based on a date. */
104 struct datelist *singledatelist; 104 struct datelist *singledatelist;
105 /* If not NULL, the list of states given for the -s option, which 105 /* If not NULL, the list of states given for the -s option, which
106 only prints revisions of given states. */ 106 only prints revisions of given states. */
107 List *statelist; 107 List *statelist;
108 /* If not NULL, the list of login names given for the -w option, 108 /* If not NULL, the list of login names given for the -w option,
109 which only prints revisions checked in by given users. */ 109 which only prints revisions checked in by given users. */
110 List *authorlist; 110 List *authorlist;
111}; 111};
112 112
113/* This structure is used to pass information through walklist. */ 113/* This structure is used to pass information through walklist. */
114struct log_data_and_rcs 114struct log_data_and_rcs
115{ 115{
116 struct log_data *log_data; 116 struct log_data *log_data;
117 struct revlist *revlist; 117 struct revlist *revlist;
118 RCSNode *rcs; 118 RCSNode *rcs;
119}; 119};
120 120
121static int rlog_proc (int argc, char **argv, char *xwhere, 121static int rlog_proc (int argc, char **argv, char *xwhere,
122 char *mwhere, char *mfile, int shorten, 122 char *mwhere, char *mfile, int shorten,
123 int local_specified, char *mname, char *msg); 123 int local_specified, char *mname, char *msg);
124static Dtype log_dirproc (void *callerdat, const char *dir, 124static Dtype log_dirproc (void *callerdat, const char *dir,
125 const char *repository, const char *update_dir, 125 const char *repository, const char *update_dir,
126 List *entries); 126 List *entries);
127static int log_fileproc (void *callerdat, struct file_info *finfo); 127static int log_fileproc (void *callerdat, struct file_info *finfo);
128static struct option_revlist *log_parse_revlist (const char *); 128static struct option_revlist *log_parse_revlist (const char *);
129static void log_parse_date (struct log_data *, const char *); 129static void log_parse_date (struct log_data *, const char *);
130static void log_parse_list (List **, const char *); 130static void log_parse_list (List **, const char *);
131static struct revlist *log_expand_revlist (RCSNode *, char *, 131static struct revlist *log_expand_revlist (RCSNode *, char *,
132 struct option_revlist *, int); 132 struct option_revlist *, int);
133static void log_free_revlist (struct revlist *); 133static void log_free_revlist (struct revlist *);
134static int log_version_requested (struct log_data *, struct revlist *, 134static int log_version_requested (struct log_data *, struct revlist *,
135 RCSNode *, RCSVers *); 135 RCSNode *, RCSVers *);
136static int log_symbol (Node *, void *); 136static int log_symbol (Node *, void *);
137static int log_count (Node *, void *); 137static int log_count (Node *, void *);
138static int log_fix_singledate (Node *, void *); 138static int log_fix_singledate (Node *, void *);
139static int log_count_print (Node *, void *); 139static int log_count_print (Node *, void *);
140static void log_tree (struct log_data *, struct revlist *, 140static void log_tree (struct log_data *, struct revlist *,
141 RCSNode *, const char *); 141 RCSNode *, const char *);
142static void log_abranch (struct log_data *, struct revlist *, 142static void log_abranch (struct log_data *, struct revlist *,
143 RCSNode *, const char *); 143 RCSNode *, const char *);
144static void log_version (struct log_data *, struct revlist *, 144static void log_version (struct log_data *, struct revlist *,
145 RCSNode *, RCSVers *, int); 145 RCSNode *, RCSVers *, int);
146static int log_branch (Node *, void *); 146static int log_branch (Node *, void *);
147static int version_compare (const char *, const char *, int); 147static int version_compare (const char *, const char *, int);
148 148
149static struct log_data log_data; 149static struct log_data log_data;
150static int is_rlog; 150static int is_rlog;
151 151
152static const char *const log_usage[] = 152static const char *const log_usage[] =
153{ 153{
154 "Usage: %s %s [-lRhtNb] [-r[revisions]] [-d dates] [-s states]\n", 154 "Usage: %s %s [-lRhtNb] [-r[revisions]] [-d dates] [-s states]\n",
155 " [-w[logins]] [files...]\n", 155 " [-w[logins]] [files...]\n",
156 "\t-l\tLocal directory only, no recursion.\n", 156 "\t-l\tLocal directory only, no recursion.\n",
157 "\t-b\tOnly list revisions on the default branch.\n", 157 "\t-b\tOnly list revisions on the default branch.\n",
158 "\t-h\tOnly print header.\n", 158 "\t-h\tOnly print header.\n",
159 "\t-R\tOnly print name of RCS file.\n", 159 "\t-R\tOnly print name of RCS file.\n",
160 "\t-t\tOnly print header and descriptive text.\n", 160 "\t-t\tOnly print header and descriptive text.\n",
161 "\t-N\tDo not list tags.\n", 161 "\t-N\tDo not list tags.\n",
162 "\t-S\tDo not print name/header if no revisions selected. -d, -r,\n", 162 "\t-S\tDo not print name/header if no revisions selected. -d, -r,\n",
163 "\t\t-s, & -w have little effect in conjunction with -b, -h, -R, and\n", 163 "\t\t-s, & -w have little effect in conjunction with -b, -h, -R, and\n",
164 "\t\t-t without this option.\n", 164 "\t\t-t without this option.\n",
165 "\t-r[revisions]\tA comma-separated list of revisions to print:\n", 165 "\t-r[revisions]\tA comma-separated list of revisions to print:\n",
166 "\t rev1:rev2 Between rev1 and rev2, including rev1 and rev2.\n", 166 "\t rev1:rev2 Between rev1 and rev2, including rev1 and rev2.\n",
167 "\t rev1::rev2 Between rev1 and rev2, excluding rev1.\n", 167 "\t rev1::rev2 Between rev1 and rev2, excluding rev1.\n",
168 "\t rev: rev and following revisions on the same branch.\n", 168 "\t rev: rev and following revisions on the same branch.\n",
169 "\t rev:: After rev on the same branch.\n", 169 "\t rev:: After rev on the same branch.\n",
170 "\t :rev rev and previous revisions on the same branch.\n", 170 "\t :rev rev and previous revisions on the same branch.\n",
171 "\t ::rev rev and previous revisions on the same branch.\n", 171 "\t ::rev rev and previous revisions on the same branch.\n",
172 "\t rev Just rev.\n", 172 "\t rev Just rev.\n",
173 "\t branch All revisions on the branch.\n", 173 "\t branch All revisions on the branch.\n",
174 "\t branch. The last revision on the branch.\n", 174 "\t branch. The last revision on the branch.\n",
175 "\t-d dates\tA semicolon-separated list of dates\n", 175 "\t-d dates\tA semicolon-separated list of dates\n",
176 "\t \t(D1<D2 for range, D for latest before).\n", 176 "\t \t(D1<D2 for range, D for latest before).\n",
177 "\t-s states\tOnly list revisions with specified states.\n", 177 "\t-s states\tOnly list revisions with specified states.\n",
178 "\t-w[logins]\tOnly list revisions checked in by specified logins.\n", 178 "\t-w[logins]\tOnly list revisions checked in by specified logins.\n",
179 "(Specify the --help global option for a list of other help options)\n", 179 "(Specify the --help global option for a list of other help options)\n",
180 NULL 180 NULL
181}; 181};
182 182
183#ifdef CLIENT_SUPPORT 183#ifdef CLIENT_SUPPORT
184 184
185 185
186 186
187/* Helper function for send_arg_list. */ 187/* Helper function for send_arg_list. */
188static int 188static int
189send_one (Node *node, void *closure) 189send_one (Node *node, void *closure)
190{ 190{
191 char *option = closure; 191 char *option = closure;
192 192
193 send_to_server ("Argument ", 0); 193 send_to_server ("Argument ", 0);
194 send_to_server (option, 0); 194 send_to_server (option, 0);
195 if (strcmp (node->key, "@@MYSELF") == 0) 195 if (strcmp (node->key, "@@MYSELF") == 0)
196 /* It is a bare -w option. Note that we must send it as 196 /* It is a bare -w option. Note that we must send it as
197 -w rather than messing with getcaller() or something (which on 197 -w rather than messing with getcaller() or something (which on
198 the client will return garbage). */ 198 the client will return garbage). */
199 ; 199 ;
200 else 200 else
201 send_to_server (node->key, 0); 201 send_to_server (node->key, 0);
202 send_to_server ("\012", 0); 202 send_to_server ("\012", 0);
203 return 0; 203 return 0;
204} 204}
205 205
206 206
207 207
208/* For each element in ARG, send an argument consisting of OPTION 208/* For each element in ARG, send an argument consisting of OPTION
209 concatenated with that element. */ 209 concatenated with that element. */
210static void 210static void
211send_arg_list (char *option, List *arg) 211send_arg_list (char *option, List *arg)
212{ 212{
213 if (arg == NULL) 213 if (arg == NULL)
214 return; 214 return;
215 walklist (arg, send_one, option); 215 walklist (arg, send_one, option);
216} 216}
217 217
218#endif 218#endif
219 219
220 220
221 221
222int 222int
223cvslog (int argc, char **argv) 223cvslog (int argc, char **argv)
224{ 224{
225 int c; 225 int c;
226 int err = 0; 226 int err = 0;
227 int local = 0; 227 int local = 0;
228 struct option_revlist **prl; 228 struct option_revlist **prl;
229 229
230 is_rlog = (strcmp (cvs_cmd_name, "rlog") == 0); 230 is_rlog = (strcmp (cvs_cmd_name, "rlog") == 0);
231 231
232 if (argc == -1) 232 if (argc == -1)
233 usage (log_usage); 233 usage (log_usage);
234 234
235 memset (&log_data, 0, sizeof log_data); 235 memset (&log_data, 0, sizeof log_data);
236 prl = &log_data.revlist; 236 prl = &log_data.revlist;
237 237
238 getoptreset (); 238 getoptreset ();
239 while ((c = getopt (argc, argv, "+bd:hlNSRr::s:tw::")) != -1) 239 while ((c = getopt (argc, argv, "+bd:hlNSRr::s:tw::")) != -1)
240 { 240 {
241 switch (c) 241 switch (c)
242 { 242 {
243 case 'b': 243 case 'b':
244 log_data.default_branch = 1; 244 log_data.default_branch = 1;
245 break; 245 break;
246 case 'd': 246 case 'd':
247 log_parse_date (&log_data, optarg); 247 log_parse_date (&log_data, optarg);
248 break; 248 break;
249 case 'h': 249 case 'h':
250 log_data.header = 1; 250 log_data.header = 1;
251 break; 251 break;
252 case 'l': 252 case 'l':
253 local = 1; 253 local = 1;
254 break; 254 break;
255 case 'N': 255 case 'N':
256 log_data.notags = 1; 256 log_data.notags = 1;
257 break; 257 break;
258 case 'S': 258 case 'S':
259 log_data.sup_header = 1; 259 log_data.sup_header = 1;
260 break; 260 break;
261 case 'R': 261 case 'R':
262 log_data.nameonly = 1; 262 log_data.nameonly = 1;
263 break; 263 break;
264 case 'r': 264 case 'r':
265 *prl = log_parse_revlist (optarg); 265 *prl = log_parse_revlist (optarg);
266 prl = &(*prl)->next; 266 prl = &(*prl)->next;
267 break; 267 break;
268 case 's': 268 case 's':
269 log_parse_list (&log_data.statelist, optarg); 269 log_parse_list (&log_data.statelist, optarg);
270 break; 270 break;
271 case 't': 271 case 't':
272 log_data.long_header = 1; 272 log_data.long_header = 1;
273 break; 273 break;
274 case 'w': 274 case 'w':
275 if (optarg != NULL) 275 if (optarg != NULL)
276 log_parse_list (&log_data.authorlist, optarg); 276 log_parse_list (&log_data.authorlist, optarg);
277 else 277 else
278 log_parse_list (&log_data.authorlist, "@@MYSELF"); 278 log_parse_list (&log_data.authorlist, "@@MYSELF");
279 break; 279 break;
280 case '?': 280 case '?':
281 default: 281 default:
282 usage (log_usage); 282 usage (log_usage);
283 break; 283 break;
284 } 284 }
285 } 285 }
286 argc -= optind; 286 argc -= optind;
287 argv += optind; 287 argv += optind;
288 288
289 wrap_setup (); 289 wrap_setup ();
290 290
291#ifdef CLIENT_SUPPORT 291#ifdef CLIENT_SUPPORT
292 if (current_parsed_root->isremote) 292 if (current_parsed_root->isremote)
293 { 293 {
294 struct datelist *p; 294 struct datelist *p;
295 struct option_revlist *rp; 295 struct option_revlist *rp;
296 char datetmp[MAXDATELEN]; 296 char datetmp[MAXDATELEN];
297 297
298 /* We're the local client. Fire up the remote server. */ 298 /* We're the local client. Fire up the remote server. */
299 start_server (); 299 start_server ();
300 300
301 if (is_rlog && !supported_request ("rlog")) 301 if (is_rlog && !supported_request ("rlog"))
302 error (1, 0, "server does not support rlog"); 302 error (1, 0, "server does not support rlog");
303 303
304 ign_setup (); 304 ign_setup ();
305 305
306 if (log_data.default_branch) 306 if (log_data.default_branch)
307 send_arg ("-b"); 307 send_arg ("-b");
308 308
309 while (log_data.datelist != NULL) 309 while (log_data.datelist != NULL)
310 { 310 {
311 p = log_data.datelist; 311 p = log_data.datelist;
312 log_data.datelist = p->next; 312 log_data.datelist = p->next;
313 send_to_server ("Argument -d\012", 0); 313 send_to_server ("Argument -d\012", 0);
314 send_to_server ("Argument ", 0); 314 send_to_server ("Argument ", 0);
315 date_to_internet (datetmp, p->start); 315 date_to_internet (datetmp, p->start);
316 send_to_server (datetmp, 0); 316 send_to_server (datetmp, 0);
317 if (p->inclusive) 317 if (p->inclusive)
318 send_to_server ("<=", 0); 318 send_to_server ("<=", 0);
319 else 319 else
320 send_to_server ("<", 0); 320 send_to_server ("<", 0);
321 date_to_internet (datetmp, p->end); 321 date_to_internet (datetmp, p->end);
322 send_to_server (datetmp, 0); 322 send_to_server (datetmp, 0);
323 send_to_server ("\012", 0); 323 send_to_server ("\012", 0);
324 if (p->start) 324 if (p->start)
325 free (p->start); 325 free (p->start);
326 if (p->end) 326 if (p->end)
327 free (p->end); 327 free (p->end);
328 free (p); 328 free (p);
329 } 329 }
330 while (log_data.singledatelist != NULL) 330 while (log_data.singledatelist != NULL)
331 { 331 {
332 p = log_data.singledatelist; 332 p = log_data.singledatelist;
333 log_data.singledatelist = p->next; 333 log_data.singledatelist = p->next;
334 send_to_server ("Argument -d\012", 0); 334 send_to_server ("Argument -d\012", 0);
335 send_to_server ("Argument ", 0); 335 send_to_server ("Argument ", 0);
336 date_to_internet (datetmp, p->end); 336 date_to_internet (datetmp, p->end);
337 send_to_server (datetmp, 0); 337 send_to_server (datetmp, 0);
338 send_to_server ("\012", 0); 338 send_to_server ("\012", 0);
339 if (p->end) 339 if (p->end)
340 free (p->end); 340 free (p->end);
341 free (p); 341 free (p);
342 } 342 }
343  343
344 if (log_data.header) 344 if (log_data.header)
345 send_arg ("-h"); 345 send_arg ("-h");
346 if (local) 346 if (local)
347 send_arg("-l"); 347 send_arg("-l");
348 if (log_data.notags) 348 if (log_data.notags)
349 send_arg("-N"); 349 send_arg("-N");
350 if (log_data.sup_header) 350 if (log_data.sup_header)
351 send_arg("-S"); 351 send_arg("-S");
352 if (log_data.nameonly) 352 if (log_data.nameonly)
353 send_arg("-R"); 353 send_arg("-R");
354 if (log_data.long_header) 354 if (log_data.long_header)
355 send_arg("-t"); 355 send_arg("-t");
356 356
357 while (log_data.revlist != NULL) 357 while (log_data.revlist != NULL)
358 { 358 {
359 rp = log_data.revlist; 359 rp = log_data.revlist;
360 log_data.revlist = rp->next; 360 log_data.revlist = rp->next;
361 send_to_server ("Argument -r", 0); 361 send_to_server ("Argument -r", 0);
362 if (rp->branchhead) 362 if (rp->branchhead)
363 { 363 {
364 if (rp->first != NULL) 364 if (rp->first != NULL)
365 send_to_server (rp->first, 0); 365 send_to_server (rp->first, 0);
366 send_to_server (".", 1); 366 send_to_server (".", 1);
367 } 367 }
368 else 368 else
369 { 369 {
370 if (rp->first != NULL) 370 if (rp->first != NULL)
371 send_to_server (rp->first, 0); 371 send_to_server (rp->first, 0);
372 send_to_server (":", 1); 372 send_to_server (":", 1);
373 if (!rp->inclusive) 373 if (!rp->inclusive)
374 send_to_server (":", 1); 374 send_to_server (":", 1);
375 if (rp->last != NULL) 375 if (rp->last != NULL)
376 send_to_server (rp->last, 0); 376 send_to_server (rp->last, 0);
377 } 377 }
378 send_to_server ("\012", 0); 378 send_to_server ("\012", 0);
379 if (rp->first) 379 if (rp->first)
380 free (rp->first); 380 free (rp->first);
381 if (rp->last) 381 if (rp->last)
382 free (rp->last); 382 free (rp->last);
383 free (rp); 383 free (rp);
384 } 384 }
385 send_arg_list ("-s", log_data.statelist); 385 send_arg_list ("-s", log_data.statelist);
386 dellist (&log_data.statelist); 386 dellist (&log_data.statelist);
387 send_arg_list ("-w", log_data.authorlist); 387 send_arg_list ("-w", log_data.authorlist);
388 dellist (&log_data.authorlist); 388 dellist (&log_data.authorlist);
389 send_arg ("--"); 389 send_arg ("--");
390 390
391 if (is_rlog) 391 if (is_rlog)
392 { 392 {
393 int i; 393 int i;
394 for (i = 0; i < argc; i++) 394 for (i = 0; i < argc; i++)
395 send_arg (argv[i]); 395 send_arg (argv[i]);
396 send_to_server ("rlog\012", 0); 396 send_to_server ("rlog\012", 0);
397 } 397 }
398 else 398 else
399 { 399 {
400 send_files (argc, argv, local, 0, SEND_NO_CONTENTS); 400 send_files (argc, argv, local, 0, SEND_NO_CONTENTS);
401 send_file_names (argc, argv, SEND_EXPAND_WILD); 401 send_file_names (argc, argv, SEND_EXPAND_WILD);
402 send_to_server ("log\012", 0); 402 send_to_server ("log\012", 0);
403 } 403 }
404 err = get_responses_and_close (); 404 err = get_responses_and_close ();
405 return err; 405 return err;
406 } 406 }
407#endif 407#endif
408 408
409 /* OK, now that we know we are local/server, we can resolve @@MYSELF 409 /* OK, now that we know we are local/server, we can resolve @@MYSELF
410 into our user name. */ 410 into our user name. */
411 if (findnode (log_data.authorlist, "@@MYSELF") != NULL) 411 if (findnode (log_data.authorlist, "@@MYSELF") != NULL)
412 log_parse_list (&log_data.authorlist, getcaller ()); 412 log_parse_list (&log_data.authorlist, getcaller ());
413 413
414 if (is_rlog) 414 if (is_rlog)
415 { 415 {
416 DBM *db; 416 DBM *db;
417 int i; 417 int i;
418 db = open_module (); 418 db = open_module ();
419 for (i = 0; i < argc; i++) 419 for (i = 0; i < argc; i++)
420 { 420 {
421 err += do_module (db, argv[i], MISC, "Logging", rlog_proc, 421 err += do_module (db, argv[i], MISC, "Logging", rlog_proc,
422 NULL, 0, local, 0, 0, NULL); 422 NULL, 0, local, 0, 0, NULL);
423 } 423 }
424 close_module (db); 424 close_module (db);
425 } 425 }
426 else 426 else
427 { 427 {
428 err = rlog_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL, 428 err = rlog_proc (argc + 1, argv - 1, NULL, NULL, NULL, 0, local, NULL,
429 NULL); 429 NULL);
430 } 430 }
431 431
432 while (log_data.revlist) 432 while (log_data.revlist)
433 { 433 {
434 struct option_revlist *rl = log_data.revlist->next; 434 struct option_revlist *rl = log_data.revlist->next;
435 if (log_data.revlist->first) 435 if (log_data.revlist->first)
436 free (log_data.revlist->first); 436 free (log_data.revlist->first);
437 if (log_data.revlist->last) 437 if (log_data.revlist->last)
438 free (log_data.revlist->last); 438 free (log_data.revlist->last);
439 free (log_data.revlist); 439 free (log_data.revlist);
440 log_data.revlist = rl; 440 log_data.revlist = rl;
441 } 441 }
442 while (log_data.datelist) 442 while (log_data.datelist)
443 { 443 {
444 struct datelist *nd = log_data.datelist->next; 444 struct datelist *nd = log_data.datelist->next;
445 if (log_data.datelist->start) 445 if (log_data.datelist->start)
446 free (log_data.datelist->start); 446 free (log_data.datelist->start);
447 if (log_data.datelist->end) 447 if (log_data.datelist->end)
448 free (log_data.datelist->end); 448 free (log_data.datelist->end);
449 free (log_data.datelist); 449 free (log_data.datelist);
450 log_data.datelist = nd; 450 log_data.datelist = nd;
451 } 451 }
452 while (log_data.singledatelist) 452 while (log_data.singledatelist)
453 { 453 {
454 struct datelist *nd = log_data.singledatelist->next; 454 struct datelist *nd = log_data.singledatelist->next;
455 if (log_data.singledatelist->start) 455 if (log_data.singledatelist->start)
456 free (log_data.singledatelist->start); 456 free (log_data.singledatelist->start);
457 if (log_data.singledatelist->end) 457 if (log_data.singledatelist->end)
458 free (log_data.singledatelist->end); 458 free (log_data.singledatelist->end);
459 free (log_data.singledatelist); 459 free (log_data.singledatelist);
460 log_data.singledatelist = nd; 460 log_data.singledatelist = nd;
461 } 461 }
462 dellist (&log_data.statelist); 462 dellist (&log_data.statelist);
463 dellist (&log_data.authorlist); 463 dellist (&log_data.authorlist);
464 464
465 return err; 465 return err;
466} 466}
467 467
468 468
469 469
470static int 470static int
471rlog_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile, 471rlog_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile,
472 int shorten, int local, char *mname, char *msg) 472 int shorten, int local, char *mname, char *msg)
473{ 473{
474 /* Begin section which is identical to patch_proc--should this 474 /* Begin section which is identical to patch_proc--should this
475 be abstracted out somehow? */ 475 be abstracted out somehow? */
476 char *myargv[2]; 476 char *myargv[2];
477 int err = 0; 477 int err = 0;
478 int which; 478 int which;
479 char *repository = NULL; 479 char *repository = NULL;
480 char *where; 480 char *where;
481 481
482 if (is_rlog) 482 if (is_rlog)
483 { 483 {
484 repository = xmalloc (strlen (current_parsed_root->directory) 484 repository = xmalloc (strlen (current_parsed_root->directory)
485 + strlen (argv[0]) 485 + strlen (argv[0])
486 + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2); 486 + (mfile == NULL ? 0 : strlen (mfile) + 1) + 2);
487 (void)sprintf (repository, "%s/%s", 487 (void)sprintf (repository, "%s/%s",
488 current_parsed_root->directory, argv[0]); 488 current_parsed_root->directory, argv[0]);
489 where = xmalloc (strlen (argv[0]) 489 where = xmalloc (strlen (argv[0])
490 + (mfile == NULL ? 0 : strlen (mfile) + 1) 490 + (mfile == NULL ? 0 : strlen (mfile) + 1)
491 + 1); 491 + 1);
492 (void)strcpy (where, argv[0]); 492 (void)strcpy (where, argv[0]);
493 493
494 /* If mfile isn't null, we need to set up to do only part of theu 494 /* If mfile isn't null, we need to set up to do only part of theu
495 * module. 495 * module.
496 */ 496 */
497 if (mfile != NULL) 497 if (mfile != NULL)
498 { 498 {
499 char *cp; 499 char *cp;
500 char *path; 500 char *path;
501 501
502 /* If the portion of the module is a path, put the dir part on 502 /* If the portion of the module is a path, put the dir part on
503 * repos. 503 * repos.
504 */ 504 */
505 if ((cp = strrchr (mfile, '/')) != NULL) 505 if ((cp = strrchr (mfile, '/')) != NULL)
506 { 506 {
507 *cp = '\0'; 507 *cp = '\0';
508 (void)strcat (repository, "/"); 508 (void)strcat (repository, "/");
509 (void)strcat (repository, mfile); 509 (void)strcat (repository, mfile);
510 (void)strcat (where, "/"); 510 (void)strcat (where, "/");
511 (void)strcat (where, mfile); 511 (void)strcat (where, mfile);
512 mfile = cp + 1; 512 mfile = cp + 1;
513 } 513 }
514 514
515 /* take care of the rest */ 515 /* take care of the rest */
516 path = Xasprintf ("%s/%s", repository, mfile); 516 path = Xasprintf ("%s/%s", repository, mfile);
517 if (isdir (path)) 517 if (isdir (path))
518 { 518 {
519 /* directory means repository gets the dir tacked on */ 519 /* directory means repository gets the dir tacked on */
520 (void)strcpy (repository, path); 520 (void)strcpy (repository, path);
521 (void)strcat (where, "/"); 521 (void)strcat (where, "/");
522 (void)strcat (where, mfile); 522 (void)strcat (where, mfile);
523 } 523 }
524 else 524 else
525 { 525 {
526 myargv[0] = argv[0]; 526 myargv[0] = argv[0];
527 myargv[1] = mfile; 527 myargv[1] = mfile;
528 argc = 2; 528 argc = 2;
529 argv = myargv; 529 argv = myargv;
530 } 530 }
531 free (path); 531 free (path);
532 } 532 }
533 533
534 /* cd to the starting repository */ 534 /* cd to the starting repository */
535 if (CVS_CHDIR (repository) < 0) 535 if (CVS_CHDIR (repository) < 0)
536 { 536 {
537 error (0, errno, "cannot chdir to %s", repository); 537 error (0, errno, "cannot chdir to %s", repository);
538 free (repository); 538 free (repository);
539 free (where); 539 free (where);
540 return 1; 540 return 1;
541 } 541 }
542 /* End section which is identical to patch_proc. */ 542 /* End section which is identical to patch_proc. */
543 543
544 which = W_REPOS | W_ATTIC; 544 which = W_REPOS | W_ATTIC;
545 } 545 }
546 else 546 else
547 { 547 {
548 repository = NULL; 548 repository = NULL;
549 where = NULL; 549 where = NULL;
550 which = W_LOCAL | W_REPOS | W_ATTIC; 550 which = W_LOCAL | W_REPOS | W_ATTIC;
551 } 551 }
552 552
553 err = start_recursion (log_fileproc, NULL, log_dirproc, 553 err = start_recursion (log_fileproc, NULL, log_dirproc,
554 NULL, &log_data, 554 NULL, &log_data,
555 argc - 1, argv + 1, local, which, 0, CVS_LOCK_READ, 555 argc - 1, argv + 1, local, which, 0, CVS_LOCK_READ,
556 where, 1, repository); 556 where, 1, repository);
557 557
558 if (!(which & W_LOCAL)) free (repository); 558 if (!(which & W_LOCAL)) free (repository);
559 if (where) free (where); 559 if (where) free (where);
560 560
561 return err; 561 return err;
562} 562}
563 563
564 564
565 565
566/* 566/*
567 * Parse a revision list specification. 567 * Parse a revision list specification.
568 */ 568 */
569static struct option_revlist * 569static struct option_revlist *
570log_parse_revlist (const char *argstring) 570log_parse_revlist (const char *argstring)
571{ 571{
572 char *orig_copy, *copy; 572 char *orig_copy, *copy;
573 struct option_revlist *ret, **pr; 573 struct option_revlist *ret, **pr;
574 574
575 /* Unfortunately, rlog accepts -r without an argument to mean that 575 /* Unfortunately, rlog accepts -r without an argument to mean that
576 latest revision on the default branch, so we must support that 576 latest revision on the default branch, so we must support that
577 for compatibility. */ 577 for compatibility. */
578 if (argstring == NULL) 578 if (argstring == NULL)
579 argstring = ""; 579 argstring = "";
580 580
581 ret = NULL; 581 ret = NULL;
582 pr = &ret; 582 pr = &ret;
583 583
584 /* Copy the argument into memory so that we can change it. We 584 /* Copy the argument into memory so that we can change it. We
585 don't want to change the argument because, at least as of this 585 don't want to change the argument because, at least as of this
586 writing, we will use it if we send the arguments to the server. */ 586 writing, we will use it if we send the arguments to the server. */
587 orig_copy = copy = xstrdup (argstring); 587 orig_copy = copy = xstrdup (argstring);
588 while (copy != NULL) 588 while (copy != NULL)
589 { 589 {
590 char *comma; 590 char *comma;
591 struct option_revlist *r; 591 struct option_revlist *r;
592 592
593 comma = strchr (copy, ','); 593 comma = strchr (copy, ',');
594 if (comma != NULL) 594 if (comma != NULL)
595 *comma++ = '\0'; 595 *comma++ = '\0';
596 596
597 r = xmalloc (sizeof *r); 597 r = xmalloc (sizeof *r);
598 r->next = NULL; 598 r->next = NULL;
599 r->first = copy; 599 r->first = copy;
600 r->branchhead = 0; 600 r->branchhead = 0;
601 r->last = strchr (copy, ':'); 601 r->last = strchr (copy, ':');
602 if (r->last != NULL) 602 if (r->last != NULL)
603 { 603 {
604 *r->last++ = '\0'; 604 *r->last++ = '\0';
605 r->inclusive = (*r->last != ':'); 605 r->inclusive = (*r->last != ':');
606 if (!r->inclusive) 606 if (!r->inclusive)
607 r->last++; 607 r->last++;
608 } 608 }
609 else 609 else
610 { 610 {
611 r->last = r->first; 611 r->last = r->first;
612 r->inclusive = 1; 612 r->inclusive = 1;
613 if (r->first[0] != '\0' && r->first[strlen (r->first) - 1] == '.') 613 if (r->first[0] != '\0' && r->first[strlen (r->first) - 1] == '.')
614 { 614 {
615 r->branchhead = 1; 615 r->branchhead = 1;
616 r->first[strlen (r->first) - 1] = '\0'; 616 r->first[strlen (r->first) - 1] = '\0';
617 } 617 }
618 } 618 }
619 619
620 if (*r->first == '\0') 620 if (*r->first == '\0')
621 r->first = NULL; 621 r->first = NULL;
622 if (*r->last == '\0') 622 if (*r->last == '\0')
623 r->last = NULL; 623 r->last = NULL;
624 624
625 if (r->first != NULL) 625 if (r->first != NULL)
626 r->first = xstrdup (r->first); 626 r->first = xstrdup (r->first);
627 if (r->last != NULL) 627 if (r->last != NULL)
628 r->last = xstrdup (r->last); 628 r->last = xstrdup (r->last);
629 629
630 *pr = r; 630 *pr = r;
631 pr = &r->next; 631 pr = &r->next;
632 632
633 copy = comma; 633 copy = comma;
634 } 634 }
635 635
636 free (orig_copy); 636 free (orig_copy);
637 return ret; 637 return ret;
638} 638}
639 639
640 640
641 641
642/* 642/*
643 * Parse a date specification. 643 * Parse a date specification.
644 */ 644 */
645static void 645static void
646log_parse_date (struct log_data *log_data, const char *argstring) 646log_parse_date (struct log_data *log_data, const char *argstring)
647{ 647{
648 char *orig_copy, *copy; 648 char *orig_copy, *copy;
649 649
650 /* Copy the argument into memory so that we can change it. We 650 /* Copy the argument into memory so that we can change it. We
651 don't want to change the argument because, at least as of this 651 don't want to change the argument because, at least as of this
652 writing, we will use it if we send the arguments to the server. */ 652 writing, we will use it if we send the arguments to the server. */
653 orig_copy = copy = xstrdup (argstring); 653 orig_copy = copy = xstrdup (argstring);
654 while (copy != NULL) 654 while (copy != NULL)
655 { 655 {
656 struct datelist *nd, **pd; 656 struct datelist *nd, **pd;
657 char *cpend, *cp, *ds, *de; 657 char *cpend, *cp, *ds, *de;
658 658
659 nd = xmalloc (sizeof *nd); 659 nd = xmalloc (sizeof *nd);
660 660
661 cpend = strchr (copy, ';'); 661 cpend = strchr (copy, ';');
662 if (cpend != NULL) 662 if (cpend != NULL)
663 *cpend++ = '\0'; 663 *cpend++ = '\0';
664 664
665 pd = &log_data->datelist; 665 pd = &log_data->datelist;
666 nd->inclusive = 0; 666 nd->inclusive = 0;
667 667
668 if ((cp = strchr (copy, '>')) != NULL) 668 if ((cp = strchr (copy, '>')) != NULL)
669 { 669 {
670 *cp++ = '\0'; 670 *cp++ = '\0';
671 if (*cp == '=') 671 if (*cp == '=')
672 { 672 {
673 ++cp; 673 ++cp;
674 nd->inclusive = 1; 674 nd->inclusive = 1;
675 } 675 }
676 ds = cp; 676 ds = cp;
677 de = copy; 677 de = copy;
678 } 678 }
679 else if ((cp = strchr (copy, '<')) != NULL) 679 else if ((cp = strchr (copy, '<')) != NULL)
680 { 680 {
681 *cp++ = '\0'; 681 *cp++ = '\0';
682 if (*cp == '=') 682 if (*cp == '=')
683 { 683 {
684 ++cp; 684 ++cp;
685 nd->inclusive = 1; 685 nd->inclusive = 1;
686 } 686 }
687 ds = copy; 687 ds = copy;
688 de = cp; 688 de = cp;
689 } 689 }
690 else 690 else
691 { 691 {
692 ds = NULL; 692 ds = NULL;
693 de = copy; 693 de = copy;
694 pd = &log_data->singledatelist; 694 pd = &log_data->singledatelist;
695 } 695 }
696 696
697 if (ds == NULL) 697 if (ds == NULL)
698 nd->start = NULL; 698 nd->start = NULL;
699 else if (*ds != '\0') 699 else if (*ds != '\0')
700 nd->start = Make_Date (ds); 700 nd->start = Make_Date (ds);
701 else 701 else
702 { 702 {
703 /* 1970 was the beginning of time, as far as get_date and 703 /* 1970 was the beginning of time, as far as get_date and
704 Make_Date are concerned. FIXME: That is true only if time_t 704 Make_Date are concerned. FIXME: That is true only if time_t
705 is a POSIX-style time and there is nothing in ANSI that 705 is a POSIX-style time and there is nothing in ANSI that
706 mandates that. It would be cleaner to set a flag saying 706 mandates that. It would be cleaner to set a flag saying
707 whether or not there is a start date. */ 707 whether or not there is a start date. */
708 nd->start = Make_Date ("1/1/1970 UTC"); 708 nd->start = Make_Date ("1/1/1970 UTC");
709 } 709 }
710 710
711 if (*de != '\0') 711 if (*de != '\0')
712 nd->end = Make_Date (de); 712 nd->end = Make_Date (de);
713 else 713 else
714 { 714 {
715 /* We want to set the end date to some time sufficiently far 715 /* We want to set the end date to some time sufficiently far
716 in the future to pick up all revisions that have been 716 in the future to pick up all revisions that have been
717 created since the specified date and the time `cvs log' 717 created since the specified date and the time `cvs log'
718 completes. FIXME: The date in question only makes sense 718 completes. FIXME: The date in question only makes sense
719 if time_t is a POSIX-style time and it is 32 bits 719 if time_t is a POSIX-style time and it is 32 bits
720 and signed. We should instead be setting a flag saying 720 and signed. We should instead be setting a flag saying
721 whether or not there is an end date. Note that using 721 whether or not there is an end date. Note that using
722 something like "next week" would break the testsuite (and, 722 something like "next week" would break the testsuite (and,
723 perhaps less importantly, loses if the clock is set grossly 723 perhaps less importantly, loses if the clock is set grossly
724 wrong). */ 724 wrong). */
725 nd->end = Make_Date ("2038-01-01"); 725 nd->end = Make_Date ("2038-01-01");
726 } 726 }
727 727
728 nd->next = *pd; 728 nd->next = *pd;
729 *pd = nd; 729 *pd = nd;
730 730
731 copy = cpend; 731 copy = cpend;
732 } 732 }
733 733
734 free (orig_copy); 734 free (orig_copy);
735} 735}
736 736
737 737
738 738
739/* 739/*
740 * Parse a comma separated list of items, and add each one to *PLIST. 740 * Parse a comma separated list of items, and add each one to *PLIST.
741 */ 741 */
742static void 742static void
743log_parse_list (List **plist, const char *argstring) 743log_parse_list (List **plist, const char *argstring)
744{ 744{
745 while (1) 745 while (1)
746 { 746 {
747 Node *p; 747 Node *p;
748 char *cp; 748 char *cp;
749 749
750 p = getnode (); 750 p = getnode ();
751 751
752 cp = strchr (argstring, ','); 752 cp = strchr (argstring, ',');
753 if (cp == NULL) 753 if (cp == NULL)
754 p->key = xstrdup (argstring); 754 p->key = xstrdup (argstring);
755 else 755 else
756 { 756 {
757 size_t len; 757 size_t len;
758 758
759 len = cp - argstring; 759 len = cp - argstring;
760 p->key = xmalloc (len + 1); 760 p->key = xmalloc (len + 1);
761 strncpy (p->key, argstring, len); 761 strncpy (p->key, argstring, len);
762 p->key[len] = '\0'; 762 p->key[len] = '\0';
763 } 763 }
764 764
765 if (*plist == NULL) 765 if (*plist == NULL)
766 *plist = getlist (); 766 *plist = getlist ();
767 if (addnode (*plist, p) != 0) 767 if (addnode (*plist, p) != 0)
768 freenode (p); 768 freenode (p);
769 769
770 if (cp == NULL) 770 if (cp == NULL)
771 break; 771 break;
772 772
773 argstring = cp + 1; 773 argstring = cp + 1;
774 } 774 }
775} 775}
776 776
777 777
778 778
779static int 779static int
780printlock_proc (Node *lock, void *foo) 780printlock_proc (Node *lock, void *foo)
781{ 781{
782 cvs_output ("\n\t", 2); 782 cvs_output ("\n\t", 2);
783 cvs_output (lock->data, 0); 783 cvs_output (lock->data, 0);
784 cvs_output (": ", 2); 784 cvs_output (": ", 2);
785 cvs_output (lock->key, 0); 785 cvs_output (lock->key, 0);
786 return 0; 786 return 0;
787} 787}
788 788
789 789
790 790
791/* 791/*
792 * Do an rlog on a file 792 * Do an rlog on a file
793 */ 793 */
794static int 794static int
795log_fileproc (void *callerdat, struct file_info *finfo) 795log_fileproc (void *callerdat, struct file_info *finfo)
796{ 796{
797 struct log_data *log_data = callerdat; 797 struct log_data *log_data = callerdat;
798 Node *p; 798 Node *p;
799 char *baserev; 799 char *baserev;
800 int selrev = -1; 800 int selrev = -1;
801 RCSNode *rcsfile; 801 RCSNode *rcsfile;
802 char buf[50]; 802 char buf[50];
803 struct revlist *revlist = NULL; 803 struct revlist *revlist = NULL;
804 struct log_data_and_rcs log_data_and_rcs; 804 struct log_data_and_rcs log_data_and_rcs;
805 805
806 rcsfile = finfo->rcs; 806 rcsfile = finfo->rcs;
807 p = findnode (finfo->entries, finfo->file); 807 p = findnode (finfo->entries, finfo->file);
808 if (p != NULL) 808 if (p != NULL)
809 { 809 {
810 Entnode *e = p->data; 810 Entnode *e = p->data;
811 baserev = e->version; 811 baserev = e->version;
812 if (baserev[0] == '-') ++baserev; 812 if (baserev[0] == '-') ++baserev;
813 } 813 }
814 else 814 else
815 baserev = NULL; 815 baserev = NULL;
816 816
817 if (rcsfile == NULL) 817 if (rcsfile == NULL)
818 { 818 {
819 /* no rcs file. What *do* we know about this file? */ 819 /* no rcs file. What *do* we know about this file? */
820 if (baserev != NULL) 820 if (baserev != NULL)
821 { 821 {
822 if (baserev[0] == '0' && baserev[1] == '\0') 822 if (baserev[0] == '0' && baserev[1] == '\0')
823 { 823 {
824 if (!really_quiet) 824 if (!really_quiet)
825 error (0, 0, "%s has been added, but not committed", 825 error (0, 0, "%s has been added, but not committed",
826 finfo->file); 826 finfo->file);
827 return 0; 827 return 0;
828 } 828 }
829 } 829 }
830  830
831 if (!really_quiet) 831 if (!really_quiet)
832 error (0, 0, "nothing known about %s", finfo->file); 832 error (0, 0, "nothing known about %s", finfo->file);
833  833
834 return 1; 834 return 1;
835 } 835 }
836 836
 837/* cvsacl patch */
 838#ifdef SERVER_SUPPORT
 839 if (use_cvs_acl /* && server_active */)
 840 {
 841 if (!access_allowed (finfo->file, finfo->repository, NULL, 5,
 842 NULL, NULL, 1))
 843 {
 844 if (stop_at_first_permission_denied)
 845 error (1, 0, "permission denied for %s",
 846 Short_Repository (finfo->repository));
 847 else
 848 error (0, 0, "permission denied for %s/%s",
 849 Short_Repository (finfo->repository), finfo->file);
 850
 851 return (0);
 852 }
 853 }
 854#endif
 855
837 if (log_data->sup_header || !log_data->nameonly) 856 if (log_data->sup_header || !log_data->nameonly)
838 { 857 {
839 858
840 /* We will need all the information in the RCS file. */ 859 /* We will need all the information in the RCS file. */
841 RCS_fully_parse (rcsfile); 860 RCS_fully_parse (rcsfile);
842 861
843 /* Turn any symbolic revisions in the revision list into numeric 862 /* Turn any symbolic revisions in the revision list into numeric
844 revisions. */ 863 revisions. */
845 revlist = log_expand_revlist (rcsfile, baserev, log_data->revlist, 864 revlist = log_expand_revlist (rcsfile, baserev, log_data->revlist,
846 log_data->default_branch); 865 log_data->default_branch);
847 if (log_data->sup_header 866 if (log_data->sup_header
848 || (!log_data->header && !log_data->long_header)) 867 || (!log_data->header && !log_data->long_header))
849 { 868 {
850 log_data_and_rcs.log_data = log_data; 869 log_data_and_rcs.log_data = log_data;
851 log_data_and_rcs.revlist = revlist; 870 log_data_and_rcs.revlist = revlist;
852 log_data_and_rcs.rcs = rcsfile; 871 log_data_and_rcs.rcs = rcsfile;
853 872
854 /* If any single dates were specified, we need to identify the 873 /* If any single dates were specified, we need to identify the
855 revisions they select. Each one selects the single 874 revisions they select. Each one selects the single
856 revision, which is otherwise selected, of that date or 875 revision, which is otherwise selected, of that date or
857 earlier. The log_fix_singledate routine will fill in the 876 earlier. The log_fix_singledate routine will fill in the
858 start date for each specific revision. */ 877 start date for each specific revision. */
859 if (log_data->singledatelist != NULL) 878 if (log_data->singledatelist != NULL)
860 walklist (rcsfile->versions, log_fix_singledate, 879 walklist (rcsfile->versions, log_fix_singledate,
861 &log_data_and_rcs); 880 &log_data_and_rcs);
862 881
863 selrev = walklist (rcsfile->versions, log_count_print, 882 selrev = walklist (rcsfile->versions, log_count_print,
864 &log_data_and_rcs); 883 &log_data_and_rcs);
865 if (log_data->sup_header && selrev == 0) 884 if (log_data->sup_header && selrev == 0)
866 { 885 {
867 log_free_revlist (revlist); 886 log_free_revlist (revlist);
868 return 0; 887 return 0;
869 } 888 }
870 } 889 }
871 890
872 } 891 }
873 892
874 if (log_data->nameonly) 893 if (log_data->nameonly)
875 { 894 {
876 cvs_output (rcsfile->print_path, 0); 895 cvs_output (rcsfile->print_path, 0);
877 cvs_output ("\n", 1); 896 cvs_output ("\n", 1);
878 log_free_revlist (revlist); 897 log_free_revlist (revlist);
879 return 0; 898 return 0;
880 } 899 }
881 900
882 /* The output here is intended to be exactly compatible with the 901 /* The output here is intended to be exactly compatible with the
883 output of rlog. I'm not sure whether this code should be here 902 output of rlog. I'm not sure whether this code should be here
884 or in rcs.c; I put it here because it is specific to the log 903 or in rcs.c; I put it here because it is specific to the log
885 function, even though it uses information gathered by the 904 function, even though it uses information gathered by the
886 functions in rcs.c. */ 905 functions in rcs.c. */
887 906
888 cvs_output ("\n", 1); 907 cvs_output ("\n", 1);
889 908
890 cvs_output ("RCS file: ", 0); 909 cvs_output ("RCS file: ", 0);
891 cvs_output (rcsfile->print_path, 0); 910 cvs_output (rcsfile->print_path, 0);
892 911
893 if (!is_rlog) 912 if (!is_rlog)
894 { 913 {
895 cvs_output ("\nWorking file: ", 0); 914 cvs_output ("\nWorking file: ", 0);
896 if (finfo->update_dir[0] != '\0') 915 if (finfo->update_dir[0] != '\0')
897 { 916 {
898 cvs_output (finfo->update_dir, 0); 917 cvs_output (finfo->update_dir, 0);
899 cvs_output ("/", 0); 918 cvs_output ("/", 0);
900 } 919 }
901 cvs_output (finfo->file, 0); 920 cvs_output (finfo->file, 0);
902 } 921 }
903 922
904 cvs_output ("\nhead:", 0); 923 cvs_output ("\nhead:", 0);
905 if (rcsfile->head != NULL) 924 if (rcsfile->head != NULL)
906 { 925 {
907 cvs_output (" ", 1); 926 cvs_output (" ", 1);
908 cvs_output (rcsfile->head, 0); 927 cvs_output (rcsfile->head, 0);
909 } 928 }
910 929
911 cvs_output ("\nbranch:", 0); 930 cvs_output ("\nbranch:", 0);
912 if (rcsfile->branch != NULL) 931 if (rcsfile->branch != NULL)
913 { 932 {
914 cvs_output (" ", 1); 933 cvs_output (" ", 1);
915 cvs_output (rcsfile->branch, 0); 934 cvs_output (rcsfile->branch, 0);
916 } 935 }
917 936
918 cvs_output ("\nlocks:", 0); 937 cvs_output ("\nlocks:", 0);
919 if (rcsfile->strict_locks) 938 if (rcsfile->strict_locks)
920 cvs_output (" strict", 0); 939 cvs_output (" strict", 0);
921 walklist (RCS_getlocks (rcsfile), printlock_proc, NULL); 940 walklist (RCS_getlocks (rcsfile), printlock_proc, NULL);
922 941
923 cvs_output ("\naccess list:", 0); 942 cvs_output ("\naccess list:", 0);
924 if (rcsfile->access != NULL) 943 if (rcsfile->access != NULL)
925 { 944 {
926 const char *cp; 945 const char *cp;
927 946
928 cp = rcsfile->access; 947 cp = rcsfile->access;
929 while (*cp != '\0') 948 while (*cp != '\0')
930 { 949 {
931 const char *cp2; 950 const char *cp2;
932 951
933 cvs_output ("\n\t", 2); 952 cvs_output ("\n\t", 2);
934 cp2 = cp; 953 cp2 = cp;
935 while (!isspace ((unsigned char)*cp2) && *cp2 != '\0') 954 while (!isspace ((unsigned char)*cp2) && *cp2 != '\0')
936 ++cp2; 955 ++cp2;
937 cvs_output (cp, cp2 - cp); 956 cvs_output (cp, cp2 - cp);
938 cp = cp2; 957 cp = cp2;
939 while (isspace ((unsigned char)*cp) && *cp != '\0') 958 while (isspace ((unsigned char)*cp) && *cp != '\0')
940 ++cp; 959 ++cp;
941 } 960 }
942 } 961 }
943 962
944 if (!log_data->notags) 963 if (!log_data->notags)
945 { 964 {
946 List *syms; 965 List *syms;
947 966
948 cvs_output ("\nsymbolic names:", 0); 967 cvs_output ("\nsymbolic names:", 0);
949 syms = RCS_symbols (rcsfile); 968 syms = RCS_symbols (rcsfile);
950 walklist (syms, log_symbol, NULL); 969 walklist (syms, log_symbol, NULL);
951 } 970 }
952 971
953 cvs_output ("\nkeyword substitution: ", 0); 972 cvs_output ("\nkeyword substitution: ", 0);
954 if (rcsfile->expand == NULL) 973 if (rcsfile->expand == NULL)
955 cvs_output ("kv", 2); 974 cvs_output ("kv", 2);
956 else 975 else
957 cvs_output (rcsfile->expand, 0); 976 cvs_output (rcsfile->expand, 0);
958 977
959 cvs_output ("\ntotal revisions: ", 0); 978 cvs_output ("\ntotal revisions: ", 0);
960 sprintf (buf, "%d", walklist (rcsfile->versions, log_count, NULL)); 979 sprintf (buf, "%d", walklist (rcsfile->versions, log_count, NULL));
961 cvs_output (buf, 0); 980 cvs_output (buf, 0);
962 981
963 if (selrev >= 0) 982 if (selrev >= 0)
964 { 983 {
965 cvs_output (";\tselected revisions: ", 0); 984 cvs_output (";\tselected revisions: ", 0);
966 sprintf (buf, "%d", selrev); 985 sprintf (buf, "%d", selrev);
967 cvs_output (buf, 0); 986 cvs_output (buf, 0);
968 } 987 }
969 988
970 cvs_output ("\n", 1); 989 cvs_output ("\n", 1);
971 990
972 if (!log_data->header || log_data->long_header) 991 if (!log_data->header || log_data->long_header)
973 { 992 {
974 cvs_output ("description:\n", 0); 993 cvs_output ("description:\n", 0);
975 if (rcsfile->desc != NULL) 994 if (rcsfile->desc != NULL)
976 cvs_output (rcsfile->desc, 0); 995 cvs_output (rcsfile->desc, 0);
977 } 996 }
978 997
979 if (!log_data->header && ! log_data->long_header && rcsfile->head != NULL) 998 if (!log_data->header && ! log_data->long_header && rcsfile->head != NULL)
980 { 999 {
981 p = findnode (rcsfile->versions, rcsfile->head); 1000 p = findnode (rcsfile->versions, rcsfile->head);
982 if (p == NULL) 1001 if (p == NULL)
983 error (1, 0, "can not find head revision in `%s'", 1002 error (1, 0, "can not find head revision in `%s'",
984 finfo->fullname); 1003 finfo->fullname);
985 while (p != NULL) 1004 while (p != NULL)
986 { 1005 {
987 RCSVers *vers = p->data; 1006 RCSVers *vers = p->data;
988 1007
989 log_version (log_data, revlist, rcsfile, vers, 1); 1008 log_version (log_data, revlist, rcsfile, vers, 1);
990 if (vers->next == NULL) 1009 if (vers->next == NULL)
991 p = NULL; 1010 p = NULL;
992 else 1011 else
993 { 1012 {
994 p = findnode (rcsfile->versions, vers->next); 1013 p = findnode (rcsfile->versions, vers->next);
995 if (p == NULL) 1014 if (p == NULL)
996 error (1, 0, "can not find next revision `%s' in `%s'", 1015 error (1, 0, "can not find next revision `%s' in `%s'",
997 vers->next, finfo->fullname); 1016 vers->next, finfo->fullname);
998 } 1017 }
999 } 1018 }
1000 1019
1001 log_tree (log_data, revlist, rcsfile, rcsfile->head); 1020 log_tree (log_data, revlist, rcsfile, rcsfile->head);
1002 } 1021 }
1003 1022
1004 cvs_output("\ 1023 cvs_output("\
1005=============================================================================\n", 1024=============================================================================\n",
1006 0); 1025 0);
1007 1026
1008 /* Free up the new revlist and restore the old one. */ 1027 /* Free up the new revlist and restore the old one. */
1009 log_free_revlist (revlist); 1028 log_free_revlist (revlist);
1010 1029
1011 /* If singledatelist is not NULL, free up the start dates we added 1030 /* If singledatelist is not NULL, free up the start dates we added
1012 to it. */ 1031 to it. */
1013 if (log_data->singledatelist != NULL) 1032 if (log_data->singledatelist != NULL)
1014 { 1033 {
1015 struct datelist *d; 1034 struct datelist *d;
1016 1035
1017 for (d = log_data->singledatelist; d != NULL; d = d->next) 1036 for (d = log_data->singledatelist; d != NULL; d = d->next)
1018 { 1037 {
1019 if (d->start != NULL) 1038 if (d->start != NULL)
1020 free (d->start); 1039 free (d->start);
1021 d->start = NULL; 1040 d->start = NULL;
1022 } 1041 }
1023 } 1042 }
1024 1043
1025 return 0; 1044 return 0;
1026} 1045}
1027 1046
1028 1047
1029 1048
1030/* 1049/*
1031 * Fix up a revision list in order to compare it against versions. 1050 * Fix up a revision list in order to compare it against versions.
1032 * Expand any symbolic revisions. 1051 * Expand any symbolic revisions.
1033 */ 1052 */
1034static struct revlist * 1053static struct revlist *
1035log_expand_revlist (RCSNode *rcs, char *baserev, 1054log_expand_revlist (RCSNode *rcs, char *baserev,
1036 struct option_revlist *revlist, int default_branch) 1055 struct option_revlist *revlist, int default_branch)
1037{ 1056{
1038 struct option_revlist *r; 1057 struct option_revlist *r;
1039 struct revlist *ret, **pr; 1058 struct revlist *ret, **pr;
1040 1059
1041 ret = NULL; 1060 ret = NULL;
1042 pr = &ret; 1061 pr = &ret;
1043 for (r = revlist; r != NULL; r = r->next) 1062 for (r = revlist; r != NULL; r = r->next)
1044 { 1063 {
1045 struct revlist *nr; 1064 struct revlist *nr;
1046 1065
1047 nr = xmalloc (sizeof *nr); 1066 nr = xmalloc (sizeof *nr);
1048 nr->inclusive = r->inclusive; 1067 nr->inclusive = r->inclusive;
1049 1068
1050 if (r->first == NULL && r->last == NULL) 1069 if (r->first == NULL && r->last == NULL)
1051 { 1070 {
1052 /* If both first and last are NULL, it means that we want 1071 /* If both first and last are NULL, it means that we want
1053 just the head of the default branch, which is RCS_head. */ 1072 just the head of the default branch, which is RCS_head. */
1054 nr->first = RCS_head (rcs); 1073 nr->first = RCS_head (rcs);
1055 if (!nr->first) 1074 if (!nr->first)
1056 { 1075 {
1057 if (!really_quiet) 1076 if (!really_quiet)
1058 error (0, 0, "No head revision in archive `%s'.", 1077 error (0, 0, "No head revision in archive `%s'.",
1059 rcs->path); 1078 rcs->path);
1060 nr->last = NULL; 1079 nr->last = NULL;
1061 nr->fields = 0; 1080 nr->fields = 0;
1062 } 1081 }
1063 else 1082 else
1064 { 1083 {
1065 nr->last = xstrdup (nr->first); 1084 nr->last = xstrdup (nr->first);
1066 nr->fields = numdots (nr->first) + 1; 1085 nr->fields = numdots (nr->first) + 1;
1067 } 1086 }
1068 } 1087 }
1069 else if (r->branchhead) 1088 else if (r->branchhead)
1070 { 1089 {
1071 char *branch; 1090 char *branch;
1072 1091
1073 /* Print just the head of the branch. */ 1092 /* Print just the head of the branch. */
1074 if (isdigit ((unsigned char) r->first[0])) 1093 if (isdigit ((unsigned char) r->first[0]))
1075 nr->first = RCS_getbranch (rcs, r->first, 1); 1094 nr->first = RCS_getbranch (rcs, r->first, 1);
1076 else 1095 else
1077 { 1096 {
1078 branch = RCS_whatbranch (rcs, r->first); 1097 branch = RCS_whatbranch (rcs, r->first);
1079 if (branch == NULL) 1098 if (branch == NULL)
1080 nr->first = NULL; 1099 nr->first = NULL;
1081 else 1100 else
1082 { 1101 {
1083 nr->first = RCS_getbranch (rcs, branch, 1); 1102 nr->first = RCS_getbranch (rcs, branch, 1);
1084 free (branch); 1103 free (branch);
1085 } 1104 }
1086 } 1105 }
1087 if (!nr->first) 1106 if (!nr->first)
1088 { 1107 {
1089 if (!really_quiet) 1108 if (!really_quiet)
1090 error (0, 0, "warning: no branch `%s' in `%s'", 1109 error (0, 0, "warning: no branch `%s' in `%s'",
1091 r->first, rcs->print_path); 1110 r->first, rcs->print_path);
1092 nr->last = NULL; 1111 nr->last = NULL;
1093 nr->fields = 0; 1112 nr->fields = 0;
1094 } 1113 }
1095 else 1114 else
1096 { 1115 {
1097 nr->last = xstrdup (nr->first); 1116 nr->last = xstrdup (nr->first);
1098 nr->fields = numdots (nr->first) + 1; 1117 nr->fields = numdots (nr->first) + 1;
1099 } 1118 }
1100 } 1119 }
1101 else 1120 else
1102 { 1121 {
1103 if (r->first == NULL || isdigit ((unsigned char) r->first[0])) 1122 if (r->first == NULL || isdigit ((unsigned char) r->first[0]))
1104 nr->first = xstrdup (r->first); 1123 nr->first = xstrdup (r->first);
1105 else 1124 else
1106 { 1125 {
1107 if (baserev && strcmp (r->first, TAG_BASE) == 0) 1126 if (baserev && strcmp (r->first, TAG_BASE) == 0)
1108 nr->first = xstrdup (baserev); 1127 nr->first = xstrdup (baserev);
1109 else if (RCS_nodeisbranch (rcs, r->first)) 1128 else if (RCS_nodeisbranch (rcs, r->first))
1110 nr->first = RCS_whatbranch (rcs, r->first); 1129 nr->first = RCS_whatbranch (rcs, r->first);
1111 else 1130 else
1112 nr->first = RCS_gettag (rcs, r->first, 1, NULL); 1131 nr->first = RCS_gettag (rcs, r->first, 1, NULL);
1113 if (nr->first == NULL && !really_quiet) 1132 if (nr->first == NULL && !really_quiet)
1114 { 1133 {
1115 error (0, 0, "warning: no revision `%s' in `%s'", 1134 error (0, 0, "warning: no revision `%s' in `%s'",
1116 r->first, rcs->print_path); 1135 r->first, rcs->print_path);
1117 } 1136 }
1118 } 1137 }
1119 1138
1120 if (r->last == r->first || (r->last != NULL && r->first != NULL && 1139 if (r->last == r->first || (r->last != NULL && r->first != NULL &&
1121 strcmp (r->last, r->first) == 0)) 1140 strcmp (r->last, r->first) == 0))
1122 nr->last = xstrdup (nr->first); 1141 nr->last = xstrdup (nr->first);
1123 else if (r->last == NULL || isdigit ((unsigned char) r->last[0])) 1142 else if (r->last == NULL || isdigit ((unsigned char) r->last[0]))
1124 nr->last = xstrdup (r->last); 1143 nr->last = xstrdup (r->last);
1125 else 1144 else
1126 { 1145 {
1127 if (baserev && strcmp (r->last, TAG_BASE) == 0) 1146 if (baserev && strcmp (r->last, TAG_BASE) == 0)
1128 nr->last = xstrdup (baserev); 1147 nr->last = xstrdup (baserev);
1129 else if (RCS_nodeisbranch (rcs, r->last)) 1148 else if (RCS_nodeisbranch (rcs, r->last))
1130 nr->last = RCS_whatbranch (rcs, r->last); 1149 nr->last = RCS_whatbranch (rcs, r->last);
1131 else 1150 else
1132 nr->last = RCS_gettag (rcs, r->last, 1, NULL); 1151 nr->last = RCS_gettag (rcs, r->last, 1, NULL);
1133 if (nr->last == NULL && !really_quiet) 1152 if (nr->last == NULL && !really_quiet)
1134 { 1153 {
1135 error (0, 0, "warning: no revision `%s' in `%s'", 1154 error (0, 0, "warning: no revision `%s' in `%s'",
1136 r->last, rcs->print_path); 1155 r->last, rcs->print_path);
1137 } 1156 }
1138 } 1157 }
1139 1158
1140 /* Process the revision numbers the same way that rlog 1159 /* Process the revision numbers the same way that rlog
1141 does. This code is a bit cryptic for my tastes, but 1160 does. This code is a bit cryptic for my tastes, but
1142 keeping the same implementation as rlog ensures a 1161 keeping the same implementation as rlog ensures a
1143 certain degree of compatibility. */ 1162 certain degree of compatibility. */
1144 if (r->first == NULL && nr->last != NULL) 1163 if (r->first == NULL && nr->last != NULL)
1145 { 1164 {
1146 nr->fields = numdots (nr->last) + 1; 1165 nr->fields = numdots (nr->last) + 1;
1147 if (nr->fields < 2) 1166 if (nr->fields < 2)
1148 nr->first = xstrdup (".0"); 1167 nr->first = xstrdup (".0");
1149 else 1168 else
1150 { 1169 {
1151 char *cp; 1170 char *cp;
1152 1171
1153 nr->first = xstrdup (nr->last); 1172 nr->first = xstrdup (nr->last);
1154 cp = strrchr (nr->first, '.'); 1173 cp = strrchr (nr->first, '.');
1155 assert (cp); 1174 assert (cp);
1156 strcpy (cp + 1, "0"); 1175 strcpy (cp + 1, "0");
1157 } 1176 }
1158 } 1177 }
1159 else if (r->last == NULL && nr->first != NULL) 1178 else if (r->last == NULL && nr->first != NULL)
1160 { 1179 {
1161 nr->fields = numdots (nr->first) + 1; 1180 nr->fields = numdots (nr->first) + 1;
1162 nr->last = xstrdup (nr->first); 1181 nr->last = xstrdup (nr->first);
1163 if (nr->fields < 2) 1182 if (nr->fields < 2)
1164 nr->last[0] = '\0'; 1183 nr->last[0] = '\0';
1165 else 1184 else
1166 { 1185 {
1167 char *cp; 1186 char *cp;
1168 1187
1169 cp = strrchr (nr->last, '.'); 1188 cp = strrchr (nr->last, '.');
1170 assert (cp); 1189 assert (cp);
1171 *cp = '\0'; 1190 *cp = '\0';
1172 } 1191 }
1173 } 1192 }
1174 else if (nr->first == NULL || nr->last == NULL) 1193 else if (nr->first == NULL || nr->last == NULL)
1175 nr->fields = 0; 1194 nr->fields = 0;
1176 else if (strcmp (nr->first, nr->last) == 0) 1195 else if (strcmp (nr->first, nr->last) == 0)
1177 nr->fields = numdots (nr->last) + 1; 1196 nr->fields = numdots (nr->last) + 1;
1178 else 1197 else
1179 { 1198 {
1180 int ord; 1199 int ord;
1181 int dots1 = numdots (nr->first); 1200 int dots1 = numdots (nr->first);
1182 int dots2 = numdots (nr->last); 1201 int dots2 = numdots (nr->last);
1183 if (dots1 > dots2 || (dots1 == dots2 && 1202 if (dots1 > dots2 || (dots1 == dots2 &&
1184 version_compare (nr->first, nr->last, dots1 + 1) > 0)) 1203 version_compare (nr->first, nr->last, dots1 + 1) > 0))
1185 { 1204 {
1186 char *tmp = nr->first; 1205 char *tmp = nr->first;
1187 nr->first = nr->last; 1206 nr->first = nr->last;
1188 nr->last = tmp; 1207 nr->last = tmp;
1189 nr->fields = dots2 + 1; 1208 nr->fields = dots2 + 1;
1190 dots2 = dots1; 1209 dots2 = dots1;
1191 dots1 = nr->fields - 1; 1210 dots1 = nr->fields - 1;
1192 } 1211 }
1193 else 1212 else
1194 nr->fields = dots1 + 1; 1213 nr->fields = dots1 + 1;
1195 dots1 += (nr->fields & 1); 1214 dots1 += (nr->fields & 1);
1196 ord = version_compare (nr->first, nr->last, dots1); 1215 ord = version_compare (nr->first, nr->last, dots1);
1197 if (ord > 0 || (nr->fields > 2 && ord < 0)) 1216 if (ord > 0 || (nr->fields > 2 && ord < 0))
1198 { 1217 {
1199 error (0, 0, 1218 error (0, 0,
1200 "invalid branch or revision pair %s:%s in `%s'", 1219 "invalid branch or revision pair %s:%s in `%s'",
1201 r->first, r->last, rcs->print_path); 1220 r->first, r->last, rcs->print_path);
1202 free (nr->first); 1221 free (nr->first);
1203 nr->first = NULL; 1222 nr->first = NULL;
1204 free (nr->last); 1223 free (nr->last);
1205 nr->last = NULL; 1224 nr->last = NULL;
1206 nr->fields = 0; 1225 nr->fields = 0;
1207 } 1226 }
1208 else 1227 else
1209 { 1228 {
1210 if (nr->fields <= dots2 && (nr->fields & 1)) 1229 if (nr->fields <= dots2 && (nr->fields & 1))
1211 { 1230 {
1212 char *p = Xasprintf ("%s.0", nr->first); 1231 char *p = Xasprintf ("%s.0", nr->first);
1213 free (nr->first); 1232 free (nr->first);
1214 nr->first = p; 1233 nr->first = p;
1215 ++nr->fields; 1234 ++nr->fields;
1216 } 1235 }
1217 while (nr->fields <= dots2) 1236 while (nr->fields <= dots2)
1218 { 1237 {
1219 char *p; 1238 char *p;
1220 int i; 1239 int i;
1221 1240
1222 nr->next = NULL; 1241 nr->next = NULL;
1223 *pr = nr; 1242 *pr = nr;
1224 nr = xmalloc (sizeof *nr); 1243 nr = xmalloc (sizeof *nr);
1225 nr->inclusive = 1; 1244 nr->inclusive = 1;
1226 nr->first = xstrdup ((*pr)->last); 1245 nr->first = xstrdup ((*pr)->last);
1227 nr->last = xstrdup ((*pr)->last); 1246 nr->last = xstrdup ((*pr)->last);
1228 nr->fields = (*pr)->fields; 1247 nr->fields = (*pr)->fields;
1229 p = (*pr)->last; 1248 p = (*pr)->last;
1230 for (i = 0; i < nr->fields; i++) 1249 for (i = 0; i < nr->fields; i++)
1231 p = strchr (p, '.') + 1; 1250 p = strchr (p, '.') + 1;
1232 p[-1] = '\0'; 1251 p[-1] = '\0';
1233 p = strchr (nr->first + (p - (*pr)->last), '.'); 1252 p = strchr (nr->first + (p - (*pr)->last), '.');
1234 if (p != NULL) 1253 if (p != NULL)
1235 { 1254 {
1236 *++p = '0'; 1255 *++p = '0';
1237 *++p = '\0'; 1256 *++p = '\0';
1238 nr->fields += 2; 1257 nr->fields += 2;
1239 } 1258 }
1240 else 1259 else
1241 ++nr->fields; 1260 ++nr->fields;
1242 pr = &(*pr)->next; 1261 pr = &(*pr)->next;
1243 } 1262 }
1244 } 1263 }
1245 } 1264 }
1246 } 1265 }
1247 1266
1248 nr->next = NULL; 1267 nr->next = NULL;
1249 *pr = nr; 1268 *pr = nr;
1250 pr = &nr->next; 1269 pr = &nr->next;
1251 } 1270 }
1252 1271
1253 /* If the default branch was requested, add a revlist entry for 1272 /* If the default branch was requested, add a revlist entry for
1254 it. This is how rlog handles this option. */ 1273 it. This is how rlog handles this option. */
1255 if (default_branch 1274 if (default_branch
1256 && (rcs->head != NULL || rcs->branch != NULL)) 1275 && (rcs->head != NULL || rcs->branch != NULL))
1257 { 1276 {
1258 struct revlist *nr; 1277 struct revlist *nr;
1259 1278
1260 nr = xmalloc (sizeof *nr); 1279 nr = xmalloc (sizeof *nr);
1261 if (rcs->branch != NULL) 1280 if (rcs->branch != NULL)
1262 nr->first = xstrdup (rcs->branch); 1281 nr->first = xstrdup (rcs->branch);
1263 else 1282 else
1264 { 1283 {
1265 char *cp; 1284 char *cp;
1266 1285
1267 nr->first = xstrdup (rcs->head); 1286 nr->first = xstrdup (rcs->head);
1268 assert (nr->first); 1287 assert (nr->first);
1269 cp = strrchr (nr->first, '.'); 1288 cp = strrchr (nr->first, '.');
1270 assert (cp); 1289 assert (cp);
1271 *cp = '\0'; 1290 *cp = '\0';
1272 } 1291 }
1273 nr->last = xstrdup (nr->first); 1292 nr->last = xstrdup (nr->first);
1274 nr->fields = numdots (nr->first) + 1; 1293 nr->fields = numdots (nr->first) + 1;
1275 nr->inclusive = 1; 1294 nr->inclusive = 1;
1276 1295
1277 nr->next = NULL; 1296 nr->next = NULL;
1278 *pr = nr; 1297 *pr = nr;
1279 } 1298 }
1280 1299
1281 return ret; 1300 return ret;
1282} 1301}
1283 1302
1284 1303
1285 1304
1286/* 1305/*
1287 * Free a revlist created by log_expand_revlist. 1306 * Free a revlist created by log_expand_revlist.
1288 */ 1307 */
1289static void 1308static void
1290log_free_revlist (struct revlist *revlist) 1309log_free_revlist (struct revlist *revlist)
1291{ 1310{
1292 struct revlist *r; 1311 struct revlist *r;
1293 1312
1294 r = revlist; 1313 r = revlist;
1295 while (r != NULL) 1314 while (r != NULL)
1296 { 1315 {
1297 struct revlist *next; 1316 struct revlist *next;
1298 1317
1299 if (r->first != NULL) 1318 if (r->first != NULL)
1300 free (r->first); 1319 free (r->first);
1301 if (r->last != NULL) 1320 if (r->last != NULL)
1302 free (r->last); 1321 free (r->last);
1303 next = r->next; 1322 next = r->next;
1304 free (r); 1323 free (r);
1305 r = next; 1324 r = next;
1306 } 1325 }
1307} 1326}
1308 1327
1309 1328
1310 1329
1311/* 1330/*
1312 * Return nonzero if a revision should be printed, based on the 1331 * Return nonzero if a revision should be printed, based on the
1313 * options provided. 1332 * options provided.
1314 */ 1333 */
1315static int 1334static int
1316log_version_requested (struct log_data *log_data, struct revlist *revlist, 1335log_version_requested (struct log_data *log_data, struct revlist *revlist,
1317 RCSNode *rcs, RCSVers *vnode) 1336 RCSNode *rcs, RCSVers *vnode)
1318{ 1337{
1319 /* Handle the list of states from the -s option. */ 1338 /* Handle the list of states from the -s option. */
1320 if (log_data->statelist != NULL 1339 if (log_data->statelist != NULL
1321 && findnode (log_data->statelist, vnode->state) == NULL) 1340 && findnode (log_data->statelist, vnode->state) == NULL)
1322 { 1341 {
1323 return 0; 1342 return 0;
1324 } 1343 }
1325 1344
1326 /* Handle the list of authors from the -w option. */ 1345 /* Handle the list of authors from the -w option. */
1327 if (log_data->authorlist != NULL) 1346 if (log_data->authorlist != NULL)
1328 { 1347 {
1329 if (vnode->author != NULL 1348 if (vnode->author != NULL
1330 && findnode (log_data->authorlist, vnode->author) == NULL) 1349 && findnode (log_data->authorlist, vnode->author) == NULL)
1331 { 1350 {
1332 return 0; 1351 return 0;
1333 } 1352 }
1334 } 1353 }
1335 1354
1336 /* rlog considers all the -d options together when it decides 1355 /* rlog considers all the -d options together when it decides
1337 whether to print a revision, so we must be compatible. */ 1356 whether to print a revision, so we must be compatible. */
1338 if (log_data->datelist != NULL || log_data->singledatelist != NULL) 1357 if (log_data->datelist != NULL || log_data->singledatelist != NULL)
1339 { 1358 {
1340 struct datelist *d; 1359 struct datelist *d;
1341 1360
1342 for (d = log_data->datelist; d != NULL; d = d->next) 1361 for (d = log_data->datelist; d != NULL; d = d->next)
1343 { 1362 {
1344 int cmp; 1363 int cmp;
1345 1364
1346 cmp = RCS_datecmp (vnode->date, d->start); 1365 cmp = RCS_datecmp (vnode->date, d->start);
1347 if (cmp > 0 || (cmp == 0 && d->inclusive)) 1366 if (cmp > 0 || (cmp == 0 && d->inclusive))
1348 { 1367 {
1349 cmp = RCS_datecmp (vnode->date, d->end); 1368 cmp = RCS_datecmp (vnode->date, d->end);
1350 if (cmp < 0 || (cmp == 0 && d->inclusive)) 1369 if (cmp < 0 || (cmp == 0 && d->inclusive))
1351 break; 1370 break;
1352 } 1371 }
1353 } 1372 }
1354 1373
1355 if (d == NULL) 1374 if (d == NULL)
1356 { 1375 {
1357 /* Look through the list of specific dates. We want to 1376 /* Look through the list of specific dates. We want to
1358 select the revision with the exact date found in the 1377 select the revision with the exact date found in the
1359 start field. The commit code ensures that it is 1378 start field. The commit code ensures that it is
1360 impossible to check in multiple revisions of a single 1379 impossible to check in multiple revisions of a single
1361 file in a single second, so checking the date this way 1380 file in a single second, so checking the date this way
1362 should never select more than one revision. */ 1381 should never select more than one revision. */
1363 for (d = log_data->singledatelist; d != NULL; d = d->next) 1382 for (d = log_data->singledatelist; d != NULL; d = d->next)
1364 { 1383 {
1365 if (d->start != NULL 1384 if (d->start != NULL
1366 && RCS_datecmp (vnode->date, d->start) == 0) 1385 && RCS_datecmp (vnode->date, d->start) == 0)
1367 { 1386 {
1368 break; 1387 break;
1369 } 1388 }
1370 } 1389 }
1371 1390
1372 if (d == NULL) 1391 if (d == NULL)
1373 return 0; 1392 return 0;
1374 } 1393 }
1375 } 1394 }
1376 1395
1377 /* If the -r or -b options were used, REVLIST will be non NULL, 1396 /* If the -r or -b options were used, REVLIST will be non NULL,
1378 and we print the union of the specified revisions. */ 1397 and we print the union of the specified revisions. */
1379 if (revlist != NULL) 1398 if (revlist != NULL)
1380 { 1399 {
1381 char *v; 1400 char *v;
1382 int vfields; 1401 int vfields;
1383 struct revlist *r; 1402 struct revlist *r;
1384 1403
1385 /* This code is taken from rlog. */ 1404 /* This code is taken from rlog. */
1386 v = vnode->version; 1405 v = vnode->version;
1387 vfields = numdots (v) + 1; 1406 vfields = numdots (v) + 1;
1388 for (r = revlist; r != NULL; r = r->next) 1407 for (r = revlist; r != NULL; r = r->next)
1389 { 1408 {
1390 if (vfields == r->fields + (r->fields & 1) && 1409 if (vfields == r->fields + (r->fields & 1) &&
1391 (r->inclusive ? version_compare (v, r->first, r->fields) >= 0 : 1410 (r->inclusive ? version_compare (v, r->first, r->fields) >= 0 :
1392 version_compare (v, r->first, r->fields) > 0) 1411 version_compare (v, r->first, r->fields) > 0)
1393 && version_compare (v, r->last, r->fields) <= 0) 1412 && version_compare (v, r->last, r->fields) <= 0)
1394 { 1413 {
1395 return 1; 1414 return 1;
1396 } 1415 }
1397 } 1416 }
1398 1417
1399 /* If we get here, then the -b and/or the -r option was used, 1418 /* If we get here, then the -b and/or the -r option was used,
1400 but did not match this revision, so we reject it. */ 1419 but did not match this revision, so we reject it. */
1401 1420
1402 return 0; 1421 return 0;
1403 } 1422 }
1404 1423
1405 /* By default, we print all revisions. */ 1424 /* By default, we print all revisions. */
1406 return 1; 1425 return 1;
1407} 1426}
1408 1427
1409 1428
1410 1429
1411/* 1430/*
1412 * Output a single symbol. This is called via walklist. 1431 * Output a single symbol. This is called via walklist.
1413 */ 1432 */
1414/*ARGSUSED*/ 1433/*ARGSUSED*/
1415static int 1434static int
1416log_symbol (Node *p, void *closure) 1435log_symbol (Node *p, void *closure)
1417{ 1436{
1418 cvs_output ("\n\t", 2); 1437 cvs_output ("\n\t", 2);
1419 cvs_output (p->key, 0); 1438 cvs_output (p->key, 0);
1420 cvs_output (": ", 2); 1439 cvs_output (": ", 2);
1421 cvs_output (p->data, 0); 1440 cvs_output (p->data, 0);
1422 return 0; 1441 return 0;
1423} 1442}
1424 1443
1425 1444
1426 1445
1427/* 1446/*
1428 * Count the number of entries on a list. This is called via walklist. 1447 * Count the number of entries on a list. This is called via walklist.
1429 */ 1448 */
1430/*ARGSUSED*/ 1449/*ARGSUSED*/
1431static int 1450static int
1432log_count (Node *p, void *closure) 1451log_count (Node *p, void *closure)
1433{ 1452{
1434 return 1; 1453 return 1;
1435} 1454}
1436 1455
1437 1456
1438 1457
1439/* 1458/*
1440 * Sort out a single date specification by narrowing down the date 1459 * Sort out a single date specification by narrowing down the date
1441 * until we find the specific selected revision. 1460 * until we find the specific selected revision.
1442 */ 1461 */
1443static int 1462static int
1444log_fix_singledate (Node *p, void *closure) 1463log_fix_singledate (Node *p, void *closure)
1445{ 1464{
1446 struct log_data_and_rcs *data = closure; 1465 struct log_data_and_rcs *data = closure;
1447 Node *pv; 1466 Node *pv;
1448 RCSVers *vnode; 1467 RCSVers *vnode;
1449 struct datelist *holdsingle, *holddate; 1468 struct datelist *holdsingle, *holddate;
1450 int requested; 1469 int requested;
1451 1470
1452 pv = findnode (data->rcs->versions, p->key); 1471 pv = findnode (data->rcs->versions, p->key);
1453 if (pv == NULL) 1472 if (pv == NULL)
1454 error (1, 0, "missing version `%s' in RCS file `%s'", 1473 error (1, 0, "missing version `%s' in RCS file `%s'",
1455 p->key, data->rcs->print_path); 1474 p->key, data->rcs->print_path);
1456 vnode = pv->data; 1475 vnode = pv->data;
1457 1476
1458 /* We are only interested if this revision passes any other tests. 1477 /* We are only interested if this revision passes any other tests.
1459 Temporarily clear log_data->singledatelist to avoid confusing 1478 Temporarily clear log_data->singledatelist to avoid confusing
1460 log_version_requested. We also clear log_data->datelist, 1479 log_version_requested. We also clear log_data->datelist,
1461 because rlog considers all the -d options together. We don't 1480 because rlog considers all the -d options together. We don't
1462 want to reject a revision because it does not match a date pair 1481 want to reject a revision because it does not match a date pair
1463 if we are going to select it on the basis of the singledate. */ 1482 if we are going to select it on the basis of the singledate. */
1464 holdsingle = data->log_data->singledatelist; 1483 holdsingle = data->log_data->singledatelist;
1465 data->log_data->singledatelist = NULL; 1484 data->log_data->singledatelist = NULL;
1466 holddate = data->log_data->datelist; 1485 holddate = data->log_data->datelist;
1467 data->log_data->datelist = NULL; 1486 data->log_data->datelist = NULL;
1468 requested = log_version_requested (data->log_data, data->revlist, 1487 requested = log_version_requested (data->log_data, data->revlist,
1469 data->rcs, vnode); 1488 data->rcs, vnode);
1470 data->log_data->singledatelist = holdsingle; 1489 data->log_data->singledatelist = holdsingle;
1471 data->log_data->datelist = holddate; 1490 data->log_data->datelist = holddate;
1472 1491
1473 if (requested) 1492 if (requested)
1474 { 1493 {
1475 struct datelist *d; 1494 struct datelist *d;
1476 1495
1477 /* For each single date, if this revision is before the 1496 /* For each single date, if this revision is before the
1478 specified date, but is closer than the previously selected 1497 specified date, but is closer than the previously selected
1479 revision, select it instead. */ 1498 revision, select it instead. */
1480 for (d = data->log_data->singledatelist; d != NULL; d = d->next) 1499 for (d = data->log_data->singledatelist; d != NULL; d = d->next)
1481 { 1500 {
1482 if (RCS_datecmp (vnode->date, d->end) <= 0 1501 if (RCS_datecmp (vnode->date, d->end) <= 0
1483 && (d->start == NULL 1502 && (d->start == NULL
1484 || RCS_datecmp (vnode->date, d->start) > 0)) 1503 || RCS_datecmp (vnode->date, d->start) > 0))
1485 { 1504 {
1486 if (d->start != NULL) 1505 if (d->start != NULL)
1487 free (d->start); 1506 free (d->start);
1488 d->start = xstrdup (vnode->date); 1507 d->start = xstrdup (vnode->date);
1489 } 1508 }
1490 } 1509 }
1491 } 1510 }
1492 1511
1493 return 0; 1512 return 0;
1494} 1513}
1495 1514
1496 1515
1497 1516
1498/* 1517/*
1499 * Count the number of revisions we are going to print. 1518 * Count the number of revisions we are going to print.
1500 */ 1519 */
1501static int 1520static int
1502log_count_print (Node *p, void *closure) 1521log_count_print (Node *p, void *closure)
1503{ 1522{
1504 struct log_data_and_rcs *data = closure; 1523 struct log_data_and_rcs *data = closure;
1505 Node *pv; 1524 Node *pv;
1506 1525
1507 pv = findnode (data->rcs->versions, p->key); 1526 pv = findnode (data->rcs->versions, p->key);
1508 if (pv == NULL) 1527 if (pv == NULL)
1509 error (1, 0, "missing version `%s' in RCS file `%s'", 1528 error (1, 0, "missing version `%s' in RCS file `%s'",
1510 p->key, data->rcs->print_path); 1529 p->key, data->rcs->print_path);
1511 if (log_version_requested (data->log_data, data->revlist, data->rcs, 1530 if (log_version_requested (data->log_data, data->revlist, data->rcs,
1512 pv->data)) 1531 pv->data))
1513 return 1; 1532 return 1;
1514 else 1533 else
1515 return 0; 1534 return 0;
1516} 1535}
1517 1536
1518 1537
1519 1538
1520/* 1539/*
1521 * Print the list of changes, not including the trunk, in reverse 1540 * Print the list of changes, not including the trunk, in reverse
1522 * order for each branch. 1541 * order for each branch.
1523 */ 1542 */
1524static void 1543static void
1525log_tree (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs, 1544log_tree (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs,
1526 const char *ver) 1545 const char *ver)
1527{ 1546{
1528 Node *p; 1547 Node *p;
1529 RCSVers *vnode; 1548 RCSVers *vnode;
1530 1549
1531 p = findnode (rcs->versions, ver); 1550 p = findnode (rcs->versions, ver);
1532 if (p == NULL) 1551 if (p == NULL)
1533 error (1, 0, "missing version `%s' in RCS file `%s'", 1552 error (1, 0, "missing version `%s' in RCS file `%s'",
1534 ver, rcs->print_path); 1553 ver, rcs->print_path);
1535 vnode = p->data; 1554 vnode = p->data;
1536 if (vnode->next != NULL) 1555 if (vnode->next != NULL)
1537 log_tree (log_data, revlist, rcs, vnode->next); 1556 log_tree (log_data, revlist, rcs, vnode->next);
1538 if (vnode->branches != NULL) 1557 if (vnode->branches != NULL)
1539 { 1558 {
1540 Node *head, *branch; 1559 Node *head, *branch;
1541 1560
1542 /* We need to do the branches in reverse order. This breaks 1561 /* We need to do the branches in reverse order. This breaks
1543 the List abstraction, but so does most of the branch 1562 the List abstraction, but so does most of the branch
1544 manipulation in rcs.c. */ 1563 manipulation in rcs.c. */
1545 head = vnode->branches->list; 1564 head = vnode->branches->list;
1546 for (branch = head->prev; branch != head; branch = branch->prev) 1565 for (branch = head->prev; branch != head; branch = branch->prev)
1547 { 1566 {
1548 log_abranch (log_data, revlist, rcs, branch->key); 1567 log_abranch (log_data, revlist, rcs, branch->key);
1549 log_tree (log_data, revlist, rcs, branch->key); 1568 log_tree (log_data, revlist, rcs, branch->key);
1550 } 1569 }
1551 } 1570 }
1552} 1571}
1553 1572
1554 1573
1555 1574
1556/* 1575/*
1557 * Log the changes for a branch, in reverse order. 1576 * Log the changes for a branch, in reverse order.
1558 */ 1577 */
1559static void 1578static void
1560log_abranch (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs, 1579log_abranch (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs,
1561 const char *ver) 1580 const char *ver)
1562{ 1581{
1563 Node *p; 1582 Node *p;
1564 RCSVers *vnode; 1583 RCSVers *vnode;
1565 1584
1566 p = findnode (rcs->versions, ver); 1585 p = findnode (rcs->versions, ver);
1567 if (p == NULL) 1586 if (p == NULL)
1568 error (1, 0, "missing version `%s' in RCS file `%s'", 1587 error (1, 0, "missing version `%s' in RCS file `%s'",
1569 ver, rcs->print_path); 1588 ver, rcs->print_path);
1570 vnode = p->data; 1589 vnode = p->data;
1571 if (vnode->next != NULL) 1590 if (vnode->next != NULL)
1572 log_abranch (log_data, revlist, rcs, vnode->next); 1591 log_abranch (log_data, revlist, rcs, vnode->next);
1573 log_version (log_data, revlist, rcs, vnode, 0); 1592 log_version (log_data, revlist, rcs, vnode, 0);
1574} 1593}
1575 1594
1576 1595
1577 1596
1578/* 1597/*
1579 * Print the log output for a single version. 1598 * Print the log output for a single version.
1580 */ 1599 */
1581static void 1600static void
1582log_version (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs,  1601log_version (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs,
1583 RCSVers *ver, int trunk) 1602 RCSVers *ver, int trunk)
1584{ 1603{
1585 Node *p; 1604 Node *p;
1586 int year, mon, mday, hour, min, sec; 1605 int year, mon, mday, hour, min, sec;
1587 char buf[100]; 1606 char buf[100];
1588 Node *padd, *pdel; 1607 Node *padd, *pdel;
1589 1608
1590 if (! log_version_requested (log_data, revlist, rcs, ver)) 1609 if (! log_version_requested (log_data, revlist, rcs, ver))
1591 return; 1610 return;
1592 1611
1593 cvs_output ("----------------------------\nrevision ", 0); 1612 cvs_output ("----------------------------\nrevision ", 0);
1594 cvs_output (ver->version, 0); 1613 cvs_output (ver->version, 0);
1595 1614
1596 p = findnode (RCS_getlocks (rcs), ver->version); 1615 p = findnode (RCS_getlocks (rcs), ver->version);
1597 if (p != NULL) 1616 if (p != NULL)
1598 { 1617 {
1599 cvs_output ("\tlocked by: ", 0); 1618 cvs_output ("\tlocked by: ", 0);
1600 cvs_output (p->data, 0); 1619 cvs_output (p->data, 0);
1601 cvs_output (";", 1); 1620 cvs_output (";", 1);
1602 } 1621 }
1603 cvs_output ("\n", 1); 1622 cvs_output ("\n", 1);
1604 1623
1605 cvs_output_tagged ("text", "date: "); 1624 cvs_output_tagged ("text", "date: ");
1606 (void)sscanf (ver->date, SDATEFORM, &year, &mon, &mday, &hour, &min, 1625 (void)sscanf (ver->date, SDATEFORM, &year, &mon, &mday, &hour, &min,
1607 &sec); 1626 &sec);
1608 if (year < 1900) 1627 if (year < 1900)
1609 year += 1900; 1628 year += 1900;
1610 sprintf (buf, "%04d-%02d-%02d %02d:%02d:%02d +0000", year, mon, mday, 1629 sprintf (buf, "%04d-%02d-%02d %02d:%02d:%02d +0000", year, mon, mday,
1611 hour, min, sec); 1630 hour, min, sec);
1612 cvs_output_tagged ("date", buf); 1631 cvs_output_tagged ("date", buf);
1613 1632
1614 cvs_output_tagged ("text", "; author: "); 1633 cvs_output_tagged ("text", "; author: ");
1615 cvs_output_tagged ("text", ver->author); 1634 cvs_output_tagged ("text", ver->author);
1616 1635
1617 cvs_output_tagged ("text", "; state: "); 1636 cvs_output_tagged ("text", "; state: ");
1618 cvs_output_tagged ("text", ver->state); 1637 cvs_output_tagged ("text", ver->state);
1619 cvs_output_tagged ("text", ";"); 1638 cvs_output_tagged ("text", ";");
1620 1639
1621 if (! trunk) 1640 if (! trunk)
1622 { 1641 {
1623 padd = findnode (ver->other, ";add"); 1642 padd = findnode (ver->other, ";add");
1624 pdel = findnode (ver->other, ";delete"); 1643 pdel = findnode (ver->other, ";delete");
1625 } 1644 }
1626 else if (ver->next == NULL) 1645 else if (ver->next == NULL)
1627 { 1646 {
1628 padd = NULL; 1647 padd = NULL;
1629 pdel = NULL; 1648 pdel = NULL;
1630 } 1649 }
1631 else 1650 else
1632 { 1651 {
1633 Node *nextp; 1652 Node *nextp;
1634 RCSVers *nextver; 1653 RCSVers *nextver;
1635 1654
1636 nextp = findnode (rcs->versions, ver->next); 1655 nextp = findnode (rcs->versions, ver->next);
1637 if (nextp == NULL) 1656 if (nextp == NULL)
1638 error (1, 0, "missing version `%s' in `%s'", ver->next, 1657 error (1, 0, "missing version `%s' in `%s'", ver->next,
1639 rcs->print_path); 1658 rcs->print_path);
1640 nextver = nextp->data; 1659 nextver = nextp->data;
1641 pdel = findnode (nextver->other, ";add"); 1660 pdel = findnode (nextver->other, ";add");
1642 padd = findnode (nextver->other, ";delete"); 1661 padd = findnode (nextver->other, ";delete");
1643 } 1662 }
1644 1663
1645 if (padd != NULL) 1664 if (padd != NULL)
1646 { 1665 {
1647 assert (pdel); 1666 assert (pdel);
1648 cvs_output_tagged ("text", " lines: +"); 1667 cvs_output_tagged ("text", " lines: +");
1649 cvs_output_tagged ("text", padd->data); 1668 cvs_output_tagged ("text", padd->data);
1650 cvs_output_tagged ("text", " -"); 1669 cvs_output_tagged ("text", " -");
1651 cvs_output_tagged ("text", pdel->data); 1670 cvs_output_tagged ("text", pdel->data);
1652 cvs_output_tagged ("text", ";"); 1671 cvs_output_tagged ("text", ";");
1653 } 1672 }
1654 1673
1655 p = findnode(ver->other_delta,"commitid"); 1674 p = findnode(ver->other_delta,"commitid");
1656 if(p && p->data) 1675 if(p && p->data)
1657 { 1676 {
1658 cvs_output_tagged ("text", " commitid: "); 1677 cvs_output_tagged ("text", " commitid: ");
1659 cvs_output_tagged ("text", p->data); 1678 cvs_output_tagged ("text", p->data);
1660 cvs_output_tagged ("text", ";"); 1679 cvs_output_tagged ("text", ";");
1661 } 1680 }
1662 1681
1663 cvs_output_tagged ("newline", NULL); 1682 cvs_output_tagged ("newline", NULL);
1664 1683
1665 if (ver->branches != NULL) 1684 if (ver->branches != NULL)
1666 { 1685 {
1667 cvs_output ("branches:", 0); 1686 cvs_output ("branches:", 0);
1668 walklist (ver->branches, log_branch, NULL); 1687 walklist (ver->branches, log_branch, NULL);
1669 cvs_output ("\n", 1); 1688 cvs_output ("\n", 1);
1670 } 1689 }
1671 1690
1672 p = findnode (ver->other, "log"); 1691 p = findnode (ver->other, "log");
1673 /* The p->date == NULL case is the normal one for an empty log 1692 /* The p->date == NULL case is the normal one for an empty log
1674 message (rcs-14 in sanity.sh). I don't think the case where 1693 message (rcs-14 in sanity.sh). I don't think the case where
1675 p->data is "" can happen (getrcskey in rcs.c checks for an 1694 p->data is "" can happen (getrcskey in rcs.c checks for an
1676 empty string and set the value to NULL in that case). My guess 1695 empty string and set the value to NULL in that case). My guess
1677 would be the p == NULL case would mean an RCS file which was 1696 would be the p == NULL case would mean an RCS file which was
1678 missing the "log" keyword (which is invalid according to 1697 missing the "log" keyword (which is invalid according to
1679 rcsfile.5). */ 1698 rcsfile.5). */
1680 if (p == NULL || p->data == NULL || *(char *)p->data == '\0') 1699 if (p == NULL || p->data == NULL || *(char *)p->data == '\0')
1681 cvs_output ("*** empty log message ***\n", 0); 1700 cvs_output ("*** empty log message ***\n", 0);
1682 else 1701 else
1683 { 1702 {
1684 /* FIXME: Technically, the log message could contain a null 1703 /* FIXME: Technically, the log message could contain a null
1685 byte. */ 1704 byte. */
1686 cvs_output (p->data, 0); 1705 cvs_output (p->data, 0);
1687 if (((char *)p->data)[strlen (p->data) - 1] != '\n') 1706 if (((char *)p->data)[strlen (p->data) - 1] != '\n')
1688 cvs_output ("\n", 1); 1707 cvs_output ("\n", 1);
1689 } 1708 }
1690} 1709}
1691 1710
1692 1711
1693 1712
1694/* 1713/*
1695 * Output a branch version. This is called via walklist. 1714 * Output a branch version. This is called via walklist.
1696 */ 1715 */
1697/*ARGSUSED*/ 1716/*ARGSUSED*/
1698static int 1717static int
1699log_branch (Node *p, void *closure) 1718log_branch (Node *p, void *closure)
1700{ 1719{
1701 cvs_output (" ", 2); 1720 cvs_output (" ", 2);
1702 if ((numdots (p->key) & 1) == 0) 1721 if ((numdots (p->key) & 1) == 0)
1703 cvs_output (p->key, 0); 1722 cvs_output (p->key, 0);
1704 else 1723 else
1705 { 1724 {
1706 char *f, *cp; 1725 char *f, *cp;
1707 1726
1708 f = xstrdup (p->key); 1727 f = xstrdup (p->key);
1709 cp = strrchr (f, '.'); 1728 cp = strrchr (f, '.');
1710 *cp = '\0'; 1729 *cp = '\0';
1711 cvs_output (f, 0); 1730 cvs_output (f, 0);
1712 free (f); 1731 free (f);
1713 } 1732 }
1714 cvs_output (";", 1); 1733 cvs_output (";", 1);
1715 return 0; 1734 return 0;
1716} 1735}
1717 1736
1718 1737
1719 1738
1720/* 1739/*
1721 * Print a warm fuzzy message 1740 * Print a warm fuzzy message
1722 */ 1741 */
1723/* ARGSUSED */ 1742/* ARGSUSED */
1724static Dtype 1743static Dtype
1725log_dirproc (void *callerdat, const char *dir, const char *repository, 1744log_dirproc (void *callerdat, const char *dir, const char *repository,
1726 const char *update_dir, List *entries) 1745 const char *update_dir, List *entries)
1727{ 1746{
1728 if (!isdir (dir)) 1747 if (!isdir (dir))
1729 return R_SKIP_ALL; 1748 return R_SKIP_ALL;
1730 1749
1731 if (!quiet) 1750 if (!quiet)
1732 error (0, 0, "Logging %s", update_dir); 1751 error (0, 0, "Logging %s", update_dir);
1733 return R_PROCESS; 1752 return R_PROCESS;
1734} 1753}
1735 1754
1736 1755
1737 1756
1738/* 1757/*
1739 * Compare versions. This is taken from RCS compartial. 1758 * Compare versions. This is taken from RCS compartial.
1740 */ 1759 */
1741static int 1760static int
1742version_compare (const char *v1, const char *v2, int len) 1761version_compare (const char *v1, const char *v2, int len)
1743{ 1762{
1744 while (1) 1763 while (1)
1745 { 1764 {
1746 int d1, d2, r; 1765 int d1, d2, r;
1747 1766
1748 if (*v1 == '\0') 1767 if (*v1 == '\0')
1749 return 1; 1768 return 1;
1750 if (*v2 == '\0') 1769 if (*v2 == '\0')
1751 return -1; 1770 return -1;
1752 1771
1753 while (*v1 == '0') 1772 while (*v1 == '0')
1754 ++v1; 1773 ++v1;
1755 for (d1 = 0; isdigit ((unsigned char) v1[d1]); ++d1) 1774 for (d1 = 0; isdigit ((unsigned char) v1[d1]); ++d1)
1756 ; 1775 ;
1757 1776
1758 while (*v2 == '0') 1777 while (*v2 == '0')
1759 ++v2; 1778 ++v2;
1760 for (d2 = 0; isdigit ((unsigned char) v2[d2]); ++d2) 1779 for (d2 = 0; isdigit ((unsigned char) v2[d2]); ++d2)
1761 ; 1780 ;
1762 1781
1763 if (d1 != d2) 1782 if (d1 != d2)
1764 return d1 < d2 ? -1 : 1; 1783 return d1 < d2 ? -1 : 1;
1765 1784
1766 r = memcmp (v1, v2, d1); 1785 r = memcmp (v1, v2, d1);
1767 if (r != 0) 1786 if (r != 0)
1768 return r; 1787 return r;
1769 1788
1770 --len; 1789 --len;
1771 if (len == 0) 1790 if (len == 0)
1772 return 0; 1791 return 0;
1773 1792
1774 v1 += d1; 1793 v1 += d1;
1775 v2 += d1; 1794 v2 += d1;
1776 1795
1777 if (*v1 == '.') 1796 if (*v1 == '.')
1778 ++v1; 1797 ++v1;
1779 if (*v2 == '.') 1798 if (*v2 == '.')
1780 ++v2; 1799 ++v2;
1781 } 1800 }
1782} 1801}