File: | src/gnu/usr.bin/cvs/src/patch.c |
Warning: | line 658, column 3 Value stored to 'rcs' is never read |
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); |
Value stored to 'rcs' is never read | |
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 | } |