| @@ -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 | |
25 | struct option_revlist | | 25 | struct 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 | |
46 | struct revlist | | 46 | struct 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 | |
63 | struct datelist | | 63 | struct 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. */ |
76 | struct log_data | | 76 | struct 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. */ |
114 | struct log_data_and_rcs | | 114 | struct 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 | |
121 | static int rlog_proc (int argc, char **argv, char *xwhere, | | 121 | static 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); |
124 | static Dtype log_dirproc (void *callerdat, const char *dir, | | 124 | static 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); |
127 | static int log_fileproc (void *callerdat, struct file_info *finfo); | | 127 | static int log_fileproc (void *callerdat, struct file_info *finfo); |
128 | static struct option_revlist *log_parse_revlist (const char *); | | 128 | static struct option_revlist *log_parse_revlist (const char *); |
129 | static void log_parse_date (struct log_data *, const char *); | | 129 | static void log_parse_date (struct log_data *, const char *); |
130 | static void log_parse_list (List **, const char *); | | 130 | static void log_parse_list (List **, const char *); |
131 | static struct revlist *log_expand_revlist (RCSNode *, char *, | | 131 | static struct revlist *log_expand_revlist (RCSNode *, char *, |
132 | struct option_revlist *, int); | | 132 | struct option_revlist *, int); |
133 | static void log_free_revlist (struct revlist *); | | 133 | static void log_free_revlist (struct revlist *); |
134 | static int log_version_requested (struct log_data *, struct revlist *, | | 134 | static int log_version_requested (struct log_data *, struct revlist *, |
135 | RCSNode *, RCSVers *); | | 135 | RCSNode *, RCSVers *); |
136 | static int log_symbol (Node *, void *); | | 136 | static int log_symbol (Node *, void *); |
137 | static int log_count (Node *, void *); | | 137 | static int log_count (Node *, void *); |
138 | static int log_fix_singledate (Node *, void *); | | 138 | static int log_fix_singledate (Node *, void *); |
139 | static int log_count_print (Node *, void *); | | 139 | static int log_count_print (Node *, void *); |
140 | static void log_tree (struct log_data *, struct revlist *, | | 140 | static void log_tree (struct log_data *, struct revlist *, |
141 | RCSNode *, const char *); | | 141 | RCSNode *, const char *); |
142 | static void log_abranch (struct log_data *, struct revlist *, | | 142 | static void log_abranch (struct log_data *, struct revlist *, |
143 | RCSNode *, const char *); | | 143 | RCSNode *, const char *); |
144 | static void log_version (struct log_data *, struct revlist *, | | 144 | static void log_version (struct log_data *, struct revlist *, |
145 | RCSNode *, RCSVers *, int); | | 145 | RCSNode *, RCSVers *, int); |
146 | static int log_branch (Node *, void *); | | 146 | static int log_branch (Node *, void *); |
147 | static int version_compare (const char *, const char *, int); | | 147 | static int version_compare (const char *, const char *, int); |
148 | | | 148 | |
149 | static struct log_data log_data; | | 149 | static struct log_data log_data; |
150 | static int is_rlog; | | 150 | static int is_rlog; |
151 | | | 151 | |
152 | static const char *const log_usage[] = | | 152 | static 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. */ |
188 | static int | | 188 | static int |
189 | send_one (Node *node, void *closure) | | 189 | send_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. */ |
210 | static void | | 210 | static void |
211 | send_arg_list (char *option, List *arg) | | 211 | send_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 | |
222 | int | | 222 | int |
223 | cvslog (int argc, char **argv) | | 223 | cvslog (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 | |
470 | static int | | 470 | static int |
471 | rlog_proc (int argc, char **argv, char *xwhere, char *mwhere, char *mfile, | | 471 | rlog_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 | */ |
569 | static struct option_revlist * | | 569 | static struct option_revlist * |
570 | log_parse_revlist (const char *argstring) | | 570 | log_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 | */ |
645 | static void | | 645 | static void |
646 | log_parse_date (struct log_data *log_data, const char *argstring) | | 646 | log_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 | */ |
742 | static void | | 742 | static void |
743 | log_parse_list (List **plist, const char *argstring) | | 743 | log_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 | |
779 | static int | | 779 | static int |
780 | printlock_proc (Node *lock, void *foo) | | 780 | printlock_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 | */ |
794 | static int | | 794 | static int |
795 | log_fileproc (void *callerdat, struct file_info *finfo) | | 795 | log_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 | */ |
1034 | static struct revlist * | | 1053 | static struct revlist * |
1035 | log_expand_revlist (RCSNode *rcs, char *baserev, | | 1054 | log_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 | */ |
1289 | static void | | 1308 | static void |
1290 | log_free_revlist (struct revlist *revlist) | | 1309 | log_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 | */ |
1315 | static int | | 1334 | static int |
1316 | log_version_requested (struct log_data *log_data, struct revlist *revlist, | | 1335 | log_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*/ |
1415 | static int | | 1434 | static int |
1416 | log_symbol (Node *p, void *closure) | | 1435 | log_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*/ |
1431 | static int | | 1450 | static int |
1432 | log_count (Node *p, void *closure) | | 1451 | log_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 | */ |
1443 | static int | | 1462 | static int |
1444 | log_fix_singledate (Node *p, void *closure) | | 1463 | log_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 | */ |
1501 | static int | | 1520 | static int |
1502 | log_count_print (Node *p, void *closure) | | 1521 | log_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 | */ |
1524 | static void | | 1543 | static void |
1525 | log_tree (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs, | | 1544 | log_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 | */ |
1559 | static void | | 1578 | static void |
1560 | log_abranch (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs, | | 1579 | log_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 | */ |
1581 | static void | | 1600 | static void |
1582 | log_version (struct log_data *log_data, struct revlist *revlist, RCSNode *rcs, | | 1601 | log_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*/ |
1698 | static int | | 1717 | static int |
1699 | log_branch (Node *p, void *closure) | | 1718 | log_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 */ |
1724 | static Dtype | | 1743 | static Dtype |
1725 | log_dirproc (void *callerdat, const char *dir, const char *repository, | | 1744 | log_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 | */ |
1741 | static int | | 1760 | static int |
1742 | version_compare (const char *v1, const char *v2, int len) | | 1761 | version_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 | } |