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