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