File: | src/gnu/usr.bin/cvs/src/patch.c |
Warning: | line 743, column 18 The left operand of '!=' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * Copyright (c) 1992, Brian Berliner and Jeff Polk | |||
3 | * Copyright (c) 1989-1992, Brian Berliner | |||
4 | * | |||
5 | * You may distribute under the terms of the GNU General Public License as | |||
6 | * specified in the README file that comes with the CVS source distribution. | |||
7 | * | |||
8 | * Patch | |||
9 | * | |||
10 | * Create a Larry Wall format "patch" file between a previous release and the | |||
11 | * current head of a module, or between two releases. Can specify the | |||
12 | * release as either a date or a revision number. | |||
13 | */ | |||
14 | ||||
15 | #include <assert.h> | |||
16 | #include "cvs.h" | |||
17 | #include "getline.h" | |||
18 | ||||
19 | static RETSIGTYPEvoid patch_cleanup PROTO((void))(void); | |||
20 | static Dtype patch_dirproc PROTO ((void *callerdat, char *dir,(void *callerdat, char *dir, char *repos, char *update_dir, List *entries) | |||
21 | char *repos, char *update_dir,(void *callerdat, char *dir, char *repos, char *update_dir, List *entries) | |||
22 | List *entries))(void *callerdat, char *dir, char *repos, char *update_dir, List *entries); | |||
23 | static int patch_fileproc PROTO ((void *callerdat, struct file_info *finfo))(void *callerdat, struct file_info *finfo); | |||
24 | static int patch_proc PROTO((int argc, char **argv, char *xwhere,(int argc, char **argv, char *xwhere, char *mwhere, char *mfile , int shorten, int local_specified, char *mname, char *msg) | |||
25 | char *mwhere, char *mfile, int shorten,(int argc, char **argv, char *xwhere, char *mwhere, char *mfile , int shorten, int local_specified, char *mname, char *msg) | |||
26 | int local_specified, char *mname, char *msg))(int argc, char **argv, char *xwhere, char *mwhere, char *mfile , int shorten, int local_specified, char *mname, char *msg); | |||
27 | ||||
28 | static int force_tag_match = 1; | |||
29 | static int patch_short = 0; | |||
30 | static int toptwo_diffs = 0; | |||
31 | static int local = 0; | |||
32 | static char *options = NULL((void*)0); | |||
33 | static char *rev1 = NULL((void*)0); | |||
34 | static int rev1_validated = 0; | |||
35 | static char *rev2 = NULL((void*)0); | |||
36 | static int rev2_validated = 0; | |||
37 | static char *date1 = NULL((void*)0); | |||
38 | static char *date2 = NULL((void*)0); | |||
39 | static char *tmpfile1 = NULL((void*)0); | |||
40 | static char *tmpfile2 = NULL((void*)0); | |||
41 | static char *tmpfile3 = NULL((void*)0); | |||
42 | static int unidiff = 0; | |||
43 | ||||
44 | static const char *const patch_usage[] = | |||
45 | { | |||
46 | "Usage: %s %s [-flR] [-c|-u] [-s|-t] [-V %%d]\n", | |||
47 | " -r rev|-D date [-r rev2 | -D date2] modules...\n", | |||
48 | "\t-f\tForce a head revision match if tag/date not found.\n", | |||
49 | "\t-l\tLocal directory only, not recursive\n", | |||
50 | "\t-R\tProcess directories recursively.\n", | |||
51 | "\t-c\tContext diffs (default)\n", | |||
52 | "\t-u\tUnidiff format.\n", | |||
53 | "\t-s\tShort patch - one liner per file.\n", | |||
54 | "\t-t\tTop two diffs - last change made to the file.\n", | |||
55 | "\t-D date\tDate.\n", | |||
56 | "\t-r rev\tRevision - symbolic or numeric.\n", | |||
57 | "\t-V vers\tUse RCS Version \"vers\" for keyword expansion.\n", | |||
58 | "(Specify the --help global option for a list of other help options)\n", | |||
59 | NULL((void*)0) | |||
60 | }; | |||
61 | ||||
62 | int | |||
63 | patch (argc, argv) | |||
64 | int argc; | |||
65 | char **argv; | |||
66 | { | |||
67 | register int i; | |||
68 | int c; | |||
69 | int err = 0; | |||
70 | DBM *db; | |||
71 | ||||
72 | if (argc == -1) | |||
73 | usage (patch_usage); | |||
74 | ||||
75 | optind = 0; | |||
76 | while ((c = getopt (argc, argv, "+V:k:cuftsQqlRD:r:")) != -1) | |||
77 | { | |||
78 | switch (c) | |||
79 | { | |||
80 | case 'Q': | |||
81 | case 'q': | |||
82 | #ifdef SERVER_SUPPORT1 | |||
83 | /* The CVS 1.5 client sends these options (in addition to | |||
84 | Global_option requests), so we must ignore them. */ | |||
85 | if (!server_active) | |||
86 | #endif | |||
87 | error (1, 0, | |||
88 | "-q or -Q must be specified before \"%s\"", | |||
89 | command_name); | |||
90 | break; | |||
91 | case 'f': | |||
92 | force_tag_match = 0; | |||
93 | break; | |||
94 | case 'l': | |||
95 | local = 1; | |||
96 | break; | |||
97 | case 'R': | |||
98 | local = 0; | |||
99 | break; | |||
100 | case 't': | |||
101 | toptwo_diffs = 1; | |||
102 | break; | |||
103 | case 's': | |||
104 | patch_short = 1; | |||
105 | break; | |||
106 | case 'D': | |||
107 | if (rev2 != NULL((void*)0) || date2 != NULL((void*)0)) | |||
108 | error (1, 0, | |||
109 | "no more than two revisions/dates can be specified"); | |||
110 | if (rev1 != NULL((void*)0) || date1 != NULL((void*)0)) | |||
111 | date2 = Make_Date (optarg); | |||
112 | else | |||
113 | date1 = Make_Date (optarg); | |||
114 | break; | |||
115 | case 'r': | |||
116 | if (rev2 != NULL((void*)0) || date2 != NULL((void*)0)) | |||
117 | error (1, 0, | |||
118 | "no more than two revisions/dates can be specified"); | |||
119 | if (rev1 != NULL((void*)0) || date1 != NULL((void*)0)) | |||
120 | rev2 = optarg; | |||
121 | else | |||
122 | rev1 = optarg; | |||
123 | break; | |||
124 | case 'k': | |||
125 | if (options) | |||
126 | free (options); | |||
127 | options = RCS_check_kflag (optarg); | |||
128 | break; | |||
129 | case 'V': | |||
130 | /* This option is pretty seriously broken: | |||
131 | 1. It is not clear what it does (does it change keyword | |||
132 | expansion behavior? If so, how? Or does it have | |||
133 | something to do with what version of RCS we are using? | |||
134 | Or the format we write RCS files in?). | |||
135 | 2. Because both it and -k use the options variable, | |||
136 | specifying both -V and -k doesn't work. | |||
137 | 3. At least as of CVS 1.9, it doesn't work (failed | |||
138 | assertion in RCS_checkout where it asserts that options | |||
139 | starts with -k). Few people seem to be complaining. | |||
140 | In the future (perhaps the near future), I have in mind | |||
141 | removing it entirely, and updating NEWS and cvs.texinfo, | |||
142 | but in case it is a good idea to give people more time | |||
143 | to complain if they would miss it, I'll just add this | |||
144 | quick and dirty error message for now. */ | |||
145 | error (1, 0, | |||
146 | "the -V option is obsolete and should not be used"); | |||
147 | #if 0 | |||
148 | if (atoi (optarg) <= 0) | |||
149 | error (1, 0, "must specify a version number to -V"); | |||
150 | if (options) | |||
151 | free (options); | |||
152 | options = xmalloc (strlen (optarg) + 1 + 2); /* for the -V */ | |||
153 | (void) sprintf (options, "-V%s", optarg); | |||
154 | #endif | |||
155 | break; | |||
156 | case 'u': | |||
157 | unidiff = 1; /* Unidiff */ | |||
158 | break; | |||
159 | case 'c': /* Context diff */ | |||
160 | unidiff = 0; | |||
161 | break; | |||
162 | case '?': | |||
163 | default: | |||
164 | usage (patch_usage); | |||
165 | break; | |||
166 | } | |||
167 | } | |||
168 | argc -= optind; | |||
169 | argv += optind; | |||
170 | ||||
171 | /* Sanity checks */ | |||
172 | if (argc < 1) | |||
173 | usage (patch_usage); | |||
174 | ||||
175 | if (toptwo_diffs && patch_short) | |||
176 | error (1, 0, "-t and -s options are mutually exclusive"); | |||
177 | if (toptwo_diffs && (date1 != NULL((void*)0) || date2 != NULL((void*)0) || | |||
178 | rev1 != NULL((void*)0) || rev2 != NULL((void*)0))) | |||
179 | error (1, 0, "must not specify revisions/dates with -t option!"); | |||
180 | ||||
181 | if (!toptwo_diffs && (date1 == NULL((void*)0) && date2 == NULL((void*)0) && | |||
182 | rev1 == NULL((void*)0) && rev2 == NULL((void*)0))) | |||
183 | error (1, 0, "must specify at least one revision/date!"); | |||
184 | if (date1 != NULL((void*)0) && date2 != NULL((void*)0)) | |||
185 | if (RCS_datecmp (date1, date2) >= 0) | |||
186 | error (1, 0, "second date must come after first date!"); | |||
187 | ||||
188 | /* if options is NULL, make it a NULL string */ | |||
189 | if (options == NULL((void*)0)) | |||
190 | options = xstrdup (""); | |||
191 | ||||
192 | #ifdef CLIENT_SUPPORT1 | |||
193 | if (current_parsed_root->isremote) | |||
194 | { | |||
195 | /* We're the client side. Fire up the remote server. */ | |||
196 | start_server (); | |||
197 | ||||
198 | ign_setup (); | |||
199 | ||||
200 | if (local) | |||
201 | send_arg("-l"); | |||
202 | if (!force_tag_match) | |||
203 | send_arg("-f"); | |||
204 | if (toptwo_diffs) | |||
205 | send_arg("-t"); | |||
206 | if (patch_short) | |||
207 | send_arg("-s"); | |||
208 | if (unidiff) | |||
209 | send_arg("-u"); | |||
210 | ||||
211 | if (rev1) | |||
212 | option_with_arg ("-r", rev1); | |||
213 | if (date1) | |||
214 | client_senddate (date1); | |||
215 | if (rev2) | |||
216 | option_with_arg ("-r", rev2); | |||
217 | if (date2) | |||
218 | client_senddate (date2); | |||
219 | if (options[0] != '\0') | |||
220 | send_arg (options); | |||
221 | ||||
222 | { | |||
223 | int i; | |||
224 | for (i = 0; i < argc; ++i) | |||
225 | send_arg (argv[i]); | |||
226 | } | |||
227 | ||||
228 | send_to_server ("rdiff\012", 0); | |||
229 | return get_responses_and_close (); | |||
230 | } | |||
231 | #endif | |||
232 | ||||
233 | /* clean up if we get a signal */ | |||
234 | #ifdef SIGABRT6 | |||
235 | (void) SIG_register (SIGABRT6, patch_cleanup); | |||
236 | #endif | |||
237 | #ifdef SIGHUP1 | |||
238 | (void) SIG_register (SIGHUP1, patch_cleanup); | |||
239 | #endif | |||
240 | #ifdef SIGINT2 | |||
241 | (void) SIG_register (SIGINT2, patch_cleanup); | |||
242 | #endif | |||
243 | #ifdef SIGQUIT3 | |||
244 | (void) SIG_register (SIGQUIT3, patch_cleanup); | |||
245 | #endif | |||
246 | #ifdef SIGPIPE13 | |||
247 | (void) SIG_register (SIGPIPE13, patch_cleanup); | |||
248 | #endif | |||
249 | #ifdef SIGTERM15 | |||
250 | (void) SIG_register (SIGTERM15, patch_cleanup); | |||
251 | #endif | |||
252 | ||||
253 | db = open_module (); | |||
254 | for (i = 0; i < argc; i++) | |||
255 | err += do_module (db, argv[i], PATCH, "Patching", patch_proc, | |||
256 | (char *) NULL((void*)0), 0, 0, 0, 0, (char *) NULL((void*)0)); | |||
257 | close_module (db); | |||
258 | free (options); | |||
259 | patch_cleanup (); | |||
260 | return (err); | |||
261 | } | |||
262 | ||||
263 | /* | |||
264 | * callback proc for doing the real work of patching | |||
265 | */ | |||
266 | /* ARGSUSED */ | |||
267 | static int | |||
268 | patch_proc (argc, argv, xwhere, mwhere, mfile, shorten, local_specified, | |||
269 | mname, msg) | |||
270 | int argc; | |||
271 | char **argv; | |||
272 | char *xwhere; | |||
273 | char *mwhere; | |||
274 | char *mfile; | |||
275 | int shorten; | |||
276 | int local_specified; | |||
277 | char *mname; | |||
278 | char *msg; | |||
279 | { | |||
280 | char *myargv[2]; | |||
281 | int err = 0; | |||
282 | int which; | |||
283 | char *repository; | |||
284 | char *where; | |||
285 | ||||
286 | repository = xmalloc (strlen (current_parsed_root->directory) + strlen (argv[0]) | |||
287 | + (mfile == NULL((void*)0) ? 0 : strlen (mfile) + 1) + 2); | |||
288 | (void) sprintf (repository, "%s/%s", current_parsed_root->directory, argv[0]); | |||
289 | where = xmalloc (strlen (argv[0]) + (mfile == NULL((void*)0) ? 0 : strlen (mfile) + 1) | |||
290 | + 1); | |||
291 | (void) strcpy (where, argv[0]); | |||
292 | ||||
293 | /* if mfile isn't null, we need to set up to do only part of the module */ | |||
294 | if (mfile != NULL((void*)0)) | |||
295 | { | |||
296 | char *cp; | |||
297 | char *path; | |||
298 | ||||
299 | /* if the portion of the module is a path, put the dir part on repos */ | |||
300 | if ((cp = strrchr (mfile, '/')) != NULL((void*)0)) | |||
301 | { | |||
302 | *cp = '\0'; | |||
303 | (void) strcat (repository, "/"); | |||
304 | (void) strcat (repository, mfile); | |||
305 | (void) strcat (where, "/"); | |||
306 | (void) strcat (where, mfile); | |||
307 | mfile = cp + 1; | |||
308 | } | |||
309 | ||||
310 | /* take care of the rest */ | |||
311 | path = xmalloc (strlen (repository) + strlen (mfile) + 2); | |||
312 | (void) sprintf (path, "%s/%s", repository, mfile); | |||
313 | if (isdir (path)) | |||
314 | { | |||
315 | /* directory means repository gets the dir tacked on */ | |||
316 | (void) strcpy (repository, path); | |||
317 | (void) strcat (where, "/"); | |||
318 | (void) strcat (where, mfile); | |||
319 | } | |||
320 | else | |||
321 | { | |||
322 | myargv[0] = argv[0]; | |||
323 | myargv[1] = mfile; | |||
324 | argc = 2; | |||
325 | argv = myargv; | |||
326 | } | |||
327 | free (path); | |||
328 | } | |||
329 | ||||
330 | /* cd to the starting repository */ | |||
331 | if ( CVS_CHDIRchdir (repository) < 0) | |||
332 | { | |||
333 | error (0, errno(*__errno()), "cannot chdir to %s", repository); | |||
334 | free (repository); | |||
335 | return (1); | |||
336 | } | |||
337 | free (repository); | |||
338 | ||||
339 | if (force_tag_match) | |||
340 | which = W_REPOS0x02 | W_ATTIC0x04; | |||
341 | else | |||
342 | which = W_REPOS0x02; | |||
343 | ||||
344 | if (rev1 != NULL((void*)0) && !rev1_validated) | |||
345 | { | |||
346 | tag_check_valid (rev1, argc - 1, argv + 1, local, 0, NULL((void*)0)); | |||
347 | rev1_validated = 1; | |||
348 | } | |||
349 | if (rev2 != NULL((void*)0) && !rev2_validated) | |||
350 | { | |||
351 | tag_check_valid (rev2, argc - 1, argv + 1, local, 0, NULL((void*)0)); | |||
352 | rev2_validated = 1; | |||
353 | } | |||
354 | ||||
355 | /* start the recursion processor */ | |||
356 | err = start_recursion (patch_fileproc, (FILESDONEPROC) NULL((void*)0), patch_dirproc, | |||
357 | (DIRLEAVEPROC) NULL((void*)0), NULL((void*)0), | |||
358 | argc - 1, argv + 1, local, | |||
359 | which, 0, 1, where, 1); | |||
360 | free (where); | |||
361 | ||||
362 | return (err); | |||
363 | } | |||
364 | ||||
365 | /* | |||
366 | * Called to examine a particular RCS file, as appropriate with the options | |||
367 | * that were set above. | |||
368 | */ | |||
369 | /* ARGSUSED */ | |||
370 | static int | |||
371 | patch_fileproc (callerdat, finfo) | |||
372 | void *callerdat; | |||
373 | struct file_info *finfo; | |||
374 | { | |||
375 | struct utimbuf t; | |||
376 | char *vers_tag, *vers_head; | |||
| ||||
377 | char *rcs = NULL((void*)0); | |||
378 | char *rcs_orig = NULL((void*)0); | |||
379 | RCSNode *rcsfile; | |||
380 | FILE *fp1, *fp2, *fp3; | |||
381 | int ret = 0; | |||
382 | int isattic = 0; | |||
383 | int retcode = 0; | |||
384 | char *file1; | |||
385 | char *file2; | |||
386 | char *strippath; | |||
387 | char *line1, *line2; | |||
388 | size_t line1_chars_allocated; | |||
389 | size_t line2_chars_allocated; | |||
390 | char *cp1, *cp2; | |||
391 | FILE *fp; | |||
392 | int line_length; | |||
393 | ||||
394 | line1 = NULL((void*)0); | |||
395 | line1_chars_allocated = 0; | |||
396 | line2 = NULL((void*)0); | |||
397 | line2_chars_allocated = 0; | |||
398 | ||||
399 | /* find the parsed rcs file */ | |||
400 | if ((rcsfile = finfo->rcs) == NULL((void*)0)) | |||
401 | { | |||
402 | ret = 1; | |||
403 | goto out2; | |||
404 | } | |||
405 | if ((rcsfile->flags & VALID0x1) && (rcsfile->flags & INATTIC0x2)) | |||
406 | isattic = 1; | |||
407 | ||||
408 | rcs_orig = rcs = xmalloc (strlen (finfo->file) + sizeof (RCSEXT",v") + 5); | |||
409 | (void) sprintf (rcs, "%s%s", finfo->file, RCSEXT",v"); | |||
410 | ||||
411 | /* if vers_head is NULL, may have been removed from the release */ | |||
412 | if (isattic && rev2 == NULL((void*)0) && date2 == NULL((void*)0)) | |||
413 | vers_head = NULL((void*)0); | |||
414 | else | |||
415 | { | |||
416 | vers_head = RCS_getversion (rcsfile, rev2, date2, force_tag_match, | |||
417 | (int *) NULL((void*)0)); | |||
418 | if (vers_head != NULL((void*)0) && RCS_isdead (rcsfile, vers_head)) | |||
419 | { | |||
420 | free (vers_head); | |||
421 | vers_head = NULL((void*)0); | |||
422 | } | |||
423 | } | |||
424 | ||||
425 | if (toptwo_diffs) | |||
426 | { | |||
427 | if (vers_head == NULL((void*)0)) | |||
428 | { | |||
429 | ret = 1; | |||
430 | goto out2; | |||
431 | } | |||
432 | ||||
433 | if (!date1) | |||
434 | date1 = xmalloc (MAXDATELEN50); | |||
435 | *date1 = '\0'; | |||
436 | if (RCS_getrevtime (rcsfile, vers_head, date1, 1) == -1) | |||
437 | { | |||
438 | if (!really_quiet) | |||
439 | error (0, 0, "cannot find date in rcs file %s revision %s", | |||
440 | rcs, vers_head); | |||
441 | ret = 1; | |||
442 | goto out2; | |||
443 | } | |||
444 | } | |||
445 | vers_tag = RCS_getversion (rcsfile, rev1, date1, force_tag_match, | |||
446 | (int *) NULL((void*)0)); | |||
447 | if (vers_tag != NULL((void*)0) && RCS_isdead (rcsfile, vers_tag)) | |||
448 | { | |||
449 | free (vers_tag); | |||
450 | vers_tag = NULL((void*)0); | |||
451 | } | |||
452 | ||||
453 | if (vers_tag == NULL((void*)0) && vers_head == NULL((void*)0)) | |||
454 | { | |||
455 | /* Nothing known about specified revs. */ | |||
456 | ret = 0; | |||
457 | goto out2; | |||
458 | } | |||
459 | ||||
460 | if (vers_tag && vers_head && strcmp (vers_head, vers_tag) == 0) | |||
461 | { | |||
462 | /* Not changed between releases. */ | |||
463 | ret = 0; | |||
464 | goto out2; | |||
465 | } | |||
466 | ||||
467 | if (patch_short) | |||
468 | { | |||
469 | cvs_output ("File ", 0); | |||
470 | cvs_output (finfo->fullname, 0); | |||
471 | if (vers_tag == NULL((void*)0)) | |||
472 | { | |||
473 | cvs_output (" is new; current revision ", 0); | |||
474 | cvs_output (vers_head, 0); | |||
475 | cvs_output ("\n", 1); | |||
476 | } | |||
477 | else if (vers_head == NULL((void*)0)) | |||
478 | { | |||
479 | cvs_output (" is removed; not included in ", 0); | |||
480 | if (rev2 != NULL((void*)0)) | |||
481 | { | |||
482 | cvs_output ("release tag ", 0); | |||
483 | cvs_output (rev2, 0); | |||
484 | } | |||
485 | else if (date2 != NULL((void*)0)) | |||
486 | { | |||
487 | cvs_output ("release date ", 0); | |||
488 | cvs_output (date2, 0); | |||
489 | } | |||
490 | else | |||
491 | cvs_output ("current release", 0); | |||
492 | cvs_output ("\n", 1); | |||
493 | } | |||
494 | else | |||
495 | { | |||
496 | cvs_output (" changed from revision ", 0); | |||
497 | cvs_output (vers_tag, 0); | |||
498 | cvs_output (" to ", 0); | |||
499 | cvs_output (vers_head, 0); | |||
500 | cvs_output ("\n", 1); | |||
501 | } | |||
502 | ret = 0; | |||
503 | goto out2; | |||
504 | } | |||
505 | ||||
506 | /* Create 3 empty files. I'm not really sure there is any advantage | |||
507 | * to doing so now rather than just waiting until later. | |||
508 | * | |||
509 | * There is - cvs_temp_file opens the file so that it can guarantee that | |||
510 | * we have exclusive write access to the file. Unfortunately we spoil that | |||
511 | * by closing it and reopening it again. Of course any better solution | |||
512 | * requires that the RCS functions accept open file pointers rather than | |||
513 | * simple file names. | |||
514 | */ | |||
515 | if ((fp1 = cvs_temp_file (&tmpfile1)) == NULL((void*)0)) | |||
516 | { | |||
517 | error (0, errno(*__errno()), "cannot create temporary file %s", tmpfile1); | |||
518 | ret = 1; | |||
519 | goto out; | |||
520 | } | |||
521 | else | |||
522 | if (fclose (fp1) < 0) | |||
523 | error (0, errno(*__errno()), "warning: cannot close %s", tmpfile1); | |||
524 | if ((fp2 = cvs_temp_file (&tmpfile2)) == NULL((void*)0)) | |||
525 | { | |||
526 | error (0, errno(*__errno()), "cannot create temporary file %s", tmpfile2); | |||
527 | ret = 1; | |||
528 | goto out; | |||
529 | } | |||
530 | else | |||
531 | if (fclose (fp2) < 0) | |||
532 | error (0, errno(*__errno()), "warning: cannot close %s", tmpfile2); | |||
533 | if ((fp3 = cvs_temp_file (&tmpfile3)) == NULL((void*)0)) | |||
534 | { | |||
535 | error (0, errno(*__errno()), "cannot create temporary file %s", tmpfile3); | |||
536 | ret = 1; | |||
537 | goto out; | |||
538 | } | |||
539 | else | |||
540 | if (fclose (fp3) < 0) | |||
541 | error (0, errno(*__errno()), "warning: cannot close %s", tmpfile3); | |||
542 | ||||
543 | if (vers_tag != NULL((void*)0)) | |||
544 | { | |||
545 | retcode = RCS_checkout (rcsfile, (char *) NULL((void*)0), vers_tag, | |||
546 | rev1, options, tmpfile1, | |||
547 | (RCSCHECKOUTPROC) NULL((void*)0), (void *) NULL((void*)0)); | |||
548 | if (retcode != 0) | |||
549 | { | |||
550 | error (0, 0, | |||
551 | "cannot check out revision %s of %s", vers_tag, rcs); | |||
552 | ret = 1; | |||
553 | goto out; | |||
554 | } | |||
555 | memset ((char *) &t, 0, sizeof (t)); | |||
556 | if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_tag, | |||
557 | (char *) 0, 0)) != -1) | |||
558 | /* I believe this timestamp only affects the dates in our diffs, | |||
559 | and therefore should be on the server, not the client. */ | |||
560 | (void) utime (tmpfile1, &t); | |||
561 | } | |||
562 | else if (toptwo_diffs) | |||
563 | { | |||
564 | ret = 1; | |||
565 | goto out; | |||
566 | } | |||
567 | if (vers_head != NULL((void*)0)) | |||
568 | { | |||
569 | retcode = RCS_checkout (rcsfile, (char *) NULL((void*)0), vers_head, | |||
570 | rev2, options, tmpfile2, | |||
571 | (RCSCHECKOUTPROC) NULL((void*)0), (void *) NULL((void*)0)); | |||
572 | if (retcode != 0) | |||
573 | { | |||
574 | error (0, 0, | |||
575 | "cannot check out revision %s of %s", vers_head, rcs); | |||
576 | ret = 1; | |||
577 | goto out; | |||
578 | } | |||
579 | if ((t.actime = t.modtime = RCS_getrevtime (rcsfile, vers_head, | |||
580 | (char *) 0, 0)) != -1) | |||
581 | /* I believe this timestamp only affects the dates in our diffs, | |||
582 | and therefore should be on the server, not the client. */ | |||
583 | (void) utime (tmpfile2, &t); | |||
584 | } | |||
585 | ||||
586 | switch (diff_exec (tmpfile1, tmpfile2, NULL((void*)0), NULL((void*)0), unidiff ? "-u" : "-c", tmpfile3)) | |||
587 | { | |||
588 | case -1: /* fork/wait failure */ | |||
589 | error (1, errno(*__errno()), "fork for diff failed on %s", rcs); | |||
590 | break; | |||
591 | case 0: /* nothing to do */ | |||
592 | break; | |||
593 | case 1: | |||
594 | /* | |||
595 | * The two revisions are really different, so read the first two | |||
596 | * lines of the diff output file, and munge them to include more | |||
597 | * reasonable file names that "patch" will understand. | |||
598 | */ | |||
599 | ||||
600 | /* Output an "Index:" line for patch to use */ | |||
601 | cvs_output ("Index: ", 0); | |||
602 | cvs_output (finfo->fullname, 0); | |||
603 | cvs_output ("\n", 1); | |||
604 | ||||
605 | fp = open_file (tmpfile3, "r"); | |||
606 | if (get_line (&line1, &line1_chars_allocated, fp) < 0 || | |||
607 | get_line (&line2, &line2_chars_allocated, fp) < 0) | |||
608 | { | |||
609 | if (feof (fp)(!__isthreaded ? (((fp)->_flags & 0x0020) != 0) : (feof )(fp))) | |||
610 | error (0, 0, "\ | |||
611 | failed to read diff file header %s for %s: end of file", tmpfile3, rcs); | |||
612 | else | |||
613 | error (0, errno(*__errno()), | |||
614 | "failed to read diff file header %s for %s", | |||
615 | tmpfile3, rcs); | |||
616 | ret = 1; | |||
617 | if (fclose (fp) < 0) | |||
618 | error (0, errno(*__errno()), "error closing %s", tmpfile3); | |||
619 | goto out; | |||
620 | } | |||
621 | if (!unidiff) | |||
622 | { | |||
623 | if (strncmp (line1, "*** ", 4) != 0 || | |||
624 | strncmp (line2, "--- ", 4) != 0 || | |||
625 | (cp1 = strchr (line1, '\t')) == NULL((void*)0) || | |||
626 | (cp2 = strchr (line2, '\t')) == NULL((void*)0)) | |||
627 | { | |||
628 | error (0, 0, "invalid diff header for %s", rcs); | |||
629 | ret = 1; | |||
630 | if (fclose (fp) < 0) | |||
631 | error (0, errno(*__errno()), "error closing %s", tmpfile3); | |||
632 | goto out; | |||
633 | } | |||
634 | } | |||
635 | else | |||
636 | { | |||
637 | if (strncmp (line1, "--- ", 4) != 0 || | |||
638 | strncmp (line2, "+++ ", 4) != 0 || | |||
639 | (cp1 = strchr (line1, '\t')) == NULL((void*)0) || | |||
640 | (cp2 = strchr (line2, '\t')) == NULL((void*)0)) | |||
641 | { | |||
642 | error (0, 0, "invalid unidiff header for %s", rcs); | |||
643 | ret = 1; | |||
644 | if (fclose (fp) < 0) | |||
645 | error (0, errno(*__errno()), "error closing %s", tmpfile3); | |||
646 | goto out; | |||
647 | } | |||
648 | } | |||
649 | assert (current_parsed_root != NULL)((current_parsed_root != ((void*)0)) ? (void)0 : __assert2("/usr/src/gnu/usr.bin/cvs/src/patch.c" , 649, __func__, "current_parsed_root != NULL")); | |||
650 | assert (current_parsed_root->directory != NULL)((current_parsed_root->directory != ((void*)0)) ? (void)0 : __assert2("/usr/src/gnu/usr.bin/cvs/src/patch.c", 650, __func__ , "current_parsed_root->directory != NULL")); | |||
651 | { | |||
652 | strippath = xmalloc (strlen (current_parsed_root->directory) + 2); | |||
653 | (void) sprintf (strippath, "%s/", current_parsed_root->directory); | |||
654 | } | |||
655 | /*else | |||
656 | strippath = xstrdup (REPOS_STRIP); */ | |||
657 | if (strncmp (rcs, strippath, strlen (strippath)) == 0) | |||
658 | rcs += strlen (strippath); | |||
659 | free (strippath); | |||
660 | if (vers_tag != NULL((void*)0)) | |||
661 | { | |||
662 | file1 = xmalloc (strlen (finfo->fullname) | |||
663 | + strlen (vers_tag) | |||
664 | + 10); | |||
665 | (void) sprintf (file1, "%s:%s", finfo->fullname, vers_tag); | |||
666 | } | |||
667 | else | |||
668 | { | |||
669 | file1 = xstrdup (DEVNULL"/dev/null"); | |||
670 | } | |||
671 | file2 = xmalloc (strlen (finfo->fullname) | |||
672 | + (vers_head != NULL((void*)0) ? strlen (vers_head) : 10) | |||
673 | + 10); | |||
674 | (void) sprintf (file2, "%s:%s", finfo->fullname, | |||
675 | vers_head ? vers_head : "removed"); | |||
676 | ||||
677 | /* Note that the string "diff" is specified by POSIX (for -c) | |||
678 | and is part of the diff output format, not the name of a | |||
679 | program. */ | |||
680 | if (unidiff) | |||
681 | { | |||
682 | cvs_output ("diff -u ", 0); | |||
683 | cvs_output (file1, 0); | |||
684 | cvs_output (" ", 1); | |||
685 | cvs_output (file2, 0); | |||
686 | cvs_output ("\n", 1); | |||
687 | ||||
688 | cvs_output ("--- ", 0); | |||
689 | cvs_output (file1, 0); | |||
690 | cvs_output (cp1, 0); | |||
691 | cvs_output ("+++ ", 0); | |||
692 | } | |||
693 | else | |||
694 | { | |||
695 | cvs_output ("diff -c ", 0); | |||
696 | cvs_output (file1, 0); | |||
697 | cvs_output (" ", 1); | |||
698 | cvs_output (file2, 0); | |||
699 | cvs_output ("\n", 1); | |||
700 | ||||
701 | cvs_output ("*** ", 0); | |||
702 | cvs_output (file1, 0); | |||
703 | cvs_output (cp1, 0); | |||
704 | cvs_output ("--- ", 0); | |||
705 | } | |||
706 | ||||
707 | cvs_output (finfo->fullname, 0); | |||
708 | cvs_output (cp2, 0); | |||
709 | ||||
710 | /* spew the rest of the diff out */ | |||
711 | while ((line_length | |||
712 | = get_line (&line1, &line1_chars_allocated, fp)) | |||
713 | >= 0) | |||
714 | cvs_output (line1, 0); | |||
715 | if (line_length < 0 && !feof (fp)(!__isthreaded ? (((fp)->_flags & 0x0020) != 0) : (feof )(fp))) | |||
716 | error (0, errno(*__errno()), "cannot read %s", tmpfile3); | |||
717 | ||||
718 | if (fclose (fp) < 0) | |||
719 | error (0, errno(*__errno()), "cannot close %s", tmpfile3); | |||
720 | free (file1); | |||
721 | free (file2); | |||
722 | break; | |||
723 | default: | |||
724 | error (0, 0, "diff failed for %s", finfo->fullname); | |||
725 | } | |||
726 | out: | |||
727 | if (line1) | |||
728 | free (line1); | |||
729 | if (line2) | |||
730 | free (line2); | |||
731 | if (CVS_UNLINKunlink (tmpfile1) < 0) | |||
732 | error (0, errno(*__errno()), "cannot unlink %s", tmpfile1); | |||
733 | if (CVS_UNLINKunlink (tmpfile2) < 0) | |||
734 | error (0, errno(*__errno()), "cannot unlink %s", tmpfile2); | |||
735 | if (CVS_UNLINKunlink (tmpfile3) < 0) | |||
736 | error (0, errno(*__errno()), "cannot unlink %s", tmpfile3); | |||
737 | free (tmpfile1); | |||
738 | free (tmpfile2); | |||
739 | free (tmpfile3); | |||
740 | tmpfile1 = tmpfile2 = tmpfile3 = NULL((void*)0); | |||
741 | ||||
742 | out2: | |||
743 | if (vers_tag != NULL((void*)0)) | |||
| ||||
744 | free (vers_tag); | |||
745 | if (vers_head != NULL((void*)0)) | |||
746 | free (vers_head); | |||
747 | if (rcs_orig) | |||
748 | free (rcs_orig); | |||
749 | return (ret); | |||
750 | } | |||
751 | ||||
752 | /* | |||
753 | * Print a warm fuzzy message | |||
754 | */ | |||
755 | /* ARGSUSED */ | |||
756 | static Dtype | |||
757 | patch_dirproc (callerdat, dir, repos, update_dir, entries) | |||
758 | void *callerdat; | |||
759 | char *dir; | |||
760 | char *repos; | |||
761 | char *update_dir; | |||
762 | List *entries; | |||
763 | { | |||
764 | if (!quiet) | |||
765 | error (0, 0, "Diffing %s", update_dir); | |||
766 | return (R_PROCESS); | |||
767 | } | |||
768 | ||||
769 | /* | |||
770 | * Clean up temporary files | |||
771 | */ | |||
772 | static RETSIGTYPEvoid | |||
773 | patch_cleanup () | |||
774 | { | |||
775 | /* Note that the checks for existence_error are because we are | |||
776 | called from a signal handler, without SIG_begincrsect, so | |||
777 | we don't know whether the files got created. */ | |||
778 | ||||
779 | if (tmpfile1 != NULL((void*)0)) | |||
780 | { | |||
781 | if (unlink_file (tmpfile1) < 0 | |||
782 | && !existence_error (errno)(((*__errno())) == 2)) | |||
783 | error (0, errno(*__errno()), "cannot remove %s", tmpfile1); | |||
784 | free (tmpfile1); | |||
785 | } | |||
786 | if (tmpfile2 != NULL((void*)0)) | |||
787 | { | |||
788 | if (unlink_file (tmpfile2) < 0 | |||
789 | && !existence_error (errno)(((*__errno())) == 2)) | |||
790 | error (0, errno(*__errno()), "cannot remove %s", tmpfile2); | |||
791 | free (tmpfile2); | |||
792 | } | |||
793 | if (tmpfile3 != NULL((void*)0)) | |||
794 | { | |||
795 | if (unlink_file (tmpfile3) < 0 | |||
796 | && !existence_error (errno)(((*__errno())) == 2)) | |||
797 | error (0, errno(*__errno()), "cannot remove %s", tmpfile3); | |||
798 | free (tmpfile3); | |||
799 | } | |||
800 | tmpfile1 = tmpfile2 = tmpfile3 = NULL((void*)0); | |||
801 | } |