]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - gnu/usr.bin/patch/pch.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / gnu / usr.bin / patch / pch.c
1 /* $FreeBSD$
2  *
3  * $Log: pch.c,v $
4  * Revision 2.0.2.0  90/05/01  22:17:51  davison
5  * patch12u: unidiff support added
6  *
7  * Revision 2.0.1.7  88/06/03  15:13:28  lwall
8  * patch10: Can now find patches in shar scripts.
9  * patch10: Hunks that swapped and then swapped back could core dump.
10  *
11  * Revision 2.0.1.6  87/06/04  16:18:13  lwall
12  * pch_swap didn't swap p_bfake and p_efake.
13  *
14  * Revision 2.0.1.5  87/01/30  22:47:42  lwall
15  * Improved responses to mangled patches.
16  *
17  * Revision 2.0.1.4  87/01/05  16:59:53  lwall
18  * New-style context diffs caused double call to free().
19  *
20  * Revision 2.0.1.3  86/11/14  10:08:33  lwall
21  * Fixed problem where a long pattern wouldn't grow the hunk.
22  * Also restored p_input_line when backtracking so error messages are right.
23  *
24  * Revision 2.0.1.2  86/11/03  17:49:52  lwall
25  * New-style delete triggers spurious assertion error.
26  *
27  * Revision 2.0.1.1  86/10/29  15:52:08  lwall
28  * Could falsely report new-style context diff.
29  *
30  * Revision 2.0  86/09/17  15:39:37  lwall
31  * Baseline for netwide release.
32  *
33  */
34
35 #include "EXTERN.h"
36 #include "common.h"
37 #include "util.h"
38 #include "INTERN.h"
39 #include "pch.h"
40
41 /* Patch (diff listing) abstract type. */
42
43 static long p_filesize;                 /* size of the patch file */
44 static LINENUM p_first;                 /* 1st line number */
45 static LINENUM p_newfirst;              /* 1st line number of replacement */
46 static LINENUM p_ptrn_lines;            /* # lines in pattern */
47 static LINENUM p_repl_lines;            /* # lines in replacement text */
48 static LINENUM p_end = -1;              /* last line in hunk */
49 static LINENUM p_max;                   /* max allowed value of p_end */
50 static LINENUM p_context = 3;           /* # of context lines */
51 static LINENUM p_input_line = 0;        /* current line # from patch file */
52 static char **p_line = Null(char**);    /* the text of the hunk */
53 static short *p_len = Null(short*);     /* length of each line */
54 static char *p_Char = Nullch;           /* +, -, and ! */
55 static int hunkmax = INITHUNKMAX;       /* size of above arrays to begin with */
56 static int p_indent;                    /* indent to patch */
57 static LINENUM p_base;                  /* where to intuit this time */
58 static LINENUM p_bline;                 /* line # of p_base */
59 static LINENUM p_start;                 /* where intuit found a patch */
60 static LINENUM p_sline;                 /* and the line number for it */
61 static LINENUM p_hunk_beg;              /* line number of current hunk */
62 static LINENUM p_efake = -1;            /* end of faked up lines--don't free */
63 static LINENUM p_bfake = -1;            /* beg of faked up lines */
64
65 /*
66  * Prepare to look for the next patch in the patch file.
67  */
68 void
69 re_patch(void)
70 {
71         p_first = Nulline;
72         p_newfirst = Nulline;
73         p_ptrn_lines = Nulline;
74         p_repl_lines = Nulline;
75         p_end = (LINENUM)-1;
76         p_max = Nulline;
77         p_indent = 0;
78 }
79
80 /*
81  * Open the patch file at the beginning of time.
82  */
83 void
84 open_patch_file(char *filename)
85 {
86         if (filename == Nullch || !*filename || strEQ(filename, "-")) {
87                 pfp = fopen(TMPPATNAME, "w");
88                 if (pfp == Nullfp)
89                         pfatal2("can't create %s", TMPPATNAME);
90                 while (fgets(buf, buf_size, stdin) != Nullch)
91                         fputs(buf, pfp);
92                 Fclose(pfp);
93                 filename = TMPPATNAME;
94         }
95         pfp = fopen(filename, "r");
96         if (pfp == Nullfp)
97             pfatal2("patch file %s not found", filename);
98         Fstat(fileno(pfp), &filestat);
99         p_filesize = filestat.st_size;
100         next_intuit_at(0L,1L);                  /* start at the beginning */
101         set_hunkmax();
102 }
103
104 /*
105  * Make sure our dynamically realloced tables are malloced to begin with.
106  */
107 void
108 set_hunkmax(void)
109 {
110 #ifndef lint
111         if (p_line == Null(char**))
112                 p_line = (char**) malloc((MEM)hunkmax * sizeof(char *));
113         if (p_len == Null(short*))
114                 p_len  = (short*) malloc((MEM)hunkmax * sizeof(short));
115 #endif
116         if (p_Char == Nullch)
117                 p_Char = (char*)  malloc((MEM)hunkmax * sizeof(char));
118 }
119
120 /*
121  * Enlarge the arrays containing the current hunk of patch.
122  */
123 void
124 grow_hunkmax(void)
125 {
126         hunkmax *= 2;
127         /*
128          * Note that on most systems, only the p_line array ever gets
129          * fresh memory since p_len can move into p_line's old space,
130          * and p_Char can move into p_len's old space.  Not on PDP-11's
131          * however.  But it doesn't matter.
132          */
133         assert(p_line != Null(char**) && p_len != Null(short*) &&
134             p_Char != Nullch);
135 #ifndef lint
136         p_line = (char**) realloc((char*)p_line, (MEM)hunkmax * sizeof(char *));
137         p_len  = (short*) realloc((char*)p_len,  (MEM)hunkmax * sizeof(short));
138         p_Char = (char*)  realloc((char*)p_Char, (MEM)hunkmax * sizeof(char));
139 #endif
140         if (p_line != Null(char**) && p_len != Null(short*) && p_Char != Nullch)
141                 return;
142         if (!using_plan_a)
143                 fatal1("out of memory\n");
144         out_of_mem = TRUE;      /* whatever is null will be allocated again */
145                                 /* from within plan_a(), of all places */
146 }
147
148 /*
149  * True if the remainder of the patch file contains a diff of some sort.
150  */
151 bool
152 there_is_another_patch(void)
153 {
154         if (p_base != 0L && p_base >= p_filesize) {
155                 if (verbose)
156                         say1("done\n");
157                 return FALSE;
158         }
159         if (verbose)
160                 say1("Hmm...");
161         diff_type = intuit_diff_type();
162         if (!diff_type) {
163                 if (p_base != 0L) {
164                         if (verbose)
165                                 say1("  Ignoring the trailing garbage.\ndone\n");
166                 }
167                 else
168                         say1("  I can't seem to find a patch in there anywhere.\n");
169                 return FALSE;
170         }
171         if (verbose)
172                 say3("  %sooks like %s to me...\n",
173                     (p_base == 0L ? "L" : "The next patch l"),
174                     diff_type == UNI_DIFF ? "a unified diff" :
175                     diff_type == CONTEXT_DIFF ? "a context diff" :
176                     diff_type == NEW_CONTEXT_DIFF ?
177                     "a new-style context diff" :
178                     diff_type == NORMAL_DIFF ? "a normal diff" :
179                     "an ed script" );
180         if (p_indent && verbose)
181                 say3("(Patch is indented %d space%s.)\n",
182                     p_indent, p_indent==1?"":"s");
183         skip_to(p_start,p_sline);
184         while (filearg[0] == Nullch) {
185                 if (force || batch || skip_rest_of_patch) {
186                         say1("No file to patch.  Skipping...\n");
187                         filearg[0] = savestr(bestguess);
188                         skip_rest_of_patch = TRUE;
189                         return TRUE;
190                 }
191                 (void) ask1("File to patch: ");
192                 if (*buf != '\n') {
193                         if (bestguess)
194                                 free(bestguess);
195                         bestguess = savestr(buf);
196                         filearg[0] = fetchname(buf, 0, FALSE);
197                 }
198                 if (filearg[0] == Nullch) {
199                         if (ask1("No file found--skip this patch? [n] ")) {
200                                 if (*buf != 'y') {
201                                         continue;
202                                 }
203                         }
204                         if (verbose)
205                                 say1("Skipping patch...\n");
206                         filearg[0] = fetchname(bestguess, 0, TRUE);
207                         skip_rest_of_patch = TRUE;
208                         return TRUE;
209                 }
210         }
211         return TRUE;
212 }
213
214 /*
215  * Determine what kind of diff is in the remaining part of the patch file.
216  */
217 int
218 intuit_diff_type(void)
219 {
220         Reg4 long this_line = 0;
221         Reg5 long previous_line;
222         Reg6 long first_command_line = -1;
223         long fcl_line;
224         Reg7 bool last_line_was_command = FALSE;
225         Reg8 bool this_is_a_command = FALSE;
226         Reg9 bool stars_last_line = FALSE;
227         Reg10 bool stars_this_line = FALSE;
228         Reg3 int indent;
229         Reg1 char *s;
230         Reg2 char *t;
231         char *indtmp = Nullch;
232         char *oldtmp = Nullch;
233         char *newtmp = Nullch;
234         char *indname = Nullch;
235         char *oldname = Nullch;
236         char *newname = Nullch;
237         Reg11 int retval;
238         bool no_filearg = (filearg[0] == Nullch);
239         extern int index_first;
240
241         ok_to_create_file = FALSE;
242         Fseek(pfp, p_base, 0);
243         p_input_line = p_bline - 1;
244         for (;;) {
245                 previous_line = this_line;
246                 last_line_was_command = this_is_a_command;
247                 stars_last_line = stars_this_line;
248                 this_line = ftell(pfp);
249                 indent = 0;
250                 p_input_line++;
251                 if (pgets(FALSE) == 0) {
252                         if (first_command_line >= 0L) {
253                                 /* nothing but deletes!? */
254                                 p_start = first_command_line;
255                                 p_sline = fcl_line;
256                                 retval = ED_DIFF;
257                                 goto scan_exit;
258                         }
259                         else {
260                                 p_start = this_line;
261                                 p_sline = p_input_line;
262                                 retval = 0;
263                                 goto scan_exit;
264                         }
265                 }
266                 for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
267                         if (*s == '\t')
268                                 indent += 8 - (indent % 8);
269                         else
270                                 indent++;
271                 }
272                 for (t=s; isdigit((unsigned char)*t) || *t == ','; t++)
273                         ;
274                 this_is_a_command = (isdigit((unsigned char)*s) &&
275                     (*t == 'd' || *t == 'c' || *t == 'a') );
276                 if (first_command_line < 0L && this_is_a_command) {
277                         first_command_line = this_line;
278                         fcl_line = p_input_line;
279                         p_indent = indent;      /* assume this for now */
280                 }
281                 if (!stars_last_line && strnEQ(s, "*** ", 4))
282                         oldtmp = savestr(s+4);
283                 else if (strnEQ(s, "--- ", 4))
284                         newtmp = savestr(s+4);
285                 else if (strnEQ(s, "+++ ", 4))
286                         oldtmp = savestr(s+4);  /* pretend it is the old name */
287                 else if (strnEQ(s, "Index:", 6))
288                         indtmp = savestr(s+6);
289                 else if (strnEQ(s, "Prereq:", 7)) {
290                         for (t = s + 7; isspace((unsigned char)*t); t++)
291                                 ;
292                         revision = savestr(t);
293                         for (t = revision; *t && !isspace((unsigned char)*t);
294                             t++)
295                                 ;
296                         *t = '\0';
297                         if (!*revision) {
298                                 free(revision);
299                                 revision = Nullch;
300                         }
301                 }
302                 if ((!diff_type || diff_type == ED_DIFF) &&
303                     first_command_line >= 0L &&
304                     strEQ(s, ".\n") ) {
305                         p_indent = indent;
306                         p_start = first_command_line;
307                         p_sline = fcl_line;
308                         retval = ED_DIFF;
309                         goto scan_exit;
310                 }
311                 if ((!diff_type || diff_type == UNI_DIFF) &&
312                     strnEQ(s, "@@ -", 4)) {
313                         if (!atol(s+3))
314                                 ok_to_create_file = TRUE;
315                         p_indent = indent;
316                         p_start = this_line;
317                         p_sline = p_input_line;
318                         retval = UNI_DIFF;
319                         goto scan_exit;
320                 }
321                 stars_this_line = strnEQ(s, "********", 8);
322                 if ((!diff_type || diff_type == CONTEXT_DIFF) &&
323                     stars_last_line &&
324                     strnEQ(s, "*** ", 4)) {
325                         if (!atol(s+4))
326                                 ok_to_create_file = TRUE;
327                         /*
328                          * If this is a new context diff the character just
329                          * before the newline is a '*'.
330                          */
331                         while (*s != '\n')
332                                 s++;
333                         p_indent = indent;
334                         p_start = previous_line;
335                         p_sline = p_input_line - 1;
336                         retval = (*(s-1) == '*' ?
337                             NEW_CONTEXT_DIFF : CONTEXT_DIFF);
338                         goto scan_exit;
339                 }
340                 if ((!diff_type || diff_type == NORMAL_DIFF) &&
341                     last_line_was_command &&
342                     (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2)) ) {
343                         p_start = previous_line;
344                         p_sline = p_input_line - 1;
345                         p_indent = indent;
346                         retval = NORMAL_DIFF;
347                         goto scan_exit;
348                 }
349         }
350  scan_exit:
351         if (no_filearg) {
352                 if (indtmp != Nullch)
353                         indname = fetchname(indtmp, strippath,
354                             ok_to_create_file);
355                 if (oldtmp != Nullch)
356                         oldname = fetchname(oldtmp, strippath,
357                             ok_to_create_file);
358                 if (newtmp != Nullch)
359                         newname = fetchname(newtmp, strippath,
360                             ok_to_create_file);
361                 if (index_first && indname)
362                         filearg[0] = savestr(indname);
363                 else if (oldname && newname) {
364                         if (strlen(oldname) < strlen(newname))
365                                 filearg[0] = savestr(oldname);
366                         else
367                                 filearg[0] = savestr(newname);
368                 } else if (indname)
369                         filearg[0] = savestr(indname);
370                 else if (oldname)
371                         filearg[0] = savestr(oldname);
372                 else if (newname)
373                         filearg[0] = savestr(newname);
374         }
375         if (bestguess) {
376                 free(bestguess);
377                 bestguess = Nullch;
378         }
379         if (filearg[0] != Nullch)
380                 bestguess = savestr(filearg[0]);
381         else if (indtmp != Nullch)
382                 bestguess = fetchname(indtmp, strippath, TRUE);
383         else {
384                 if (oldtmp != Nullch)
385                         oldname = fetchname(oldtmp, strippath, TRUE);
386                 if (newtmp != Nullch)
387                         newname = fetchname(newtmp, strippath, TRUE);
388                 if (oldname && newname) {
389                         if (strlen(oldname) < strlen(newname))
390                                 bestguess = savestr(oldname);
391                         else
392                                 bestguess = savestr(newname);
393                 }
394                 else if (oldname)
395                         bestguess = savestr(oldname);
396                 else if (newname)
397                         bestguess = savestr(newname);
398         }
399         if (indtmp != Nullch)
400                 free(indtmp);
401         if (oldtmp != Nullch)
402                 free(oldtmp);
403         if (newtmp != Nullch)
404                 free(newtmp);
405         if (indname != Nullch)
406                 free(indname);
407         if (oldname != Nullch)
408                 free(oldname);
409         if (newname != Nullch)
410                 free(newname);
411         return retval;
412 }
413
414 /*
415  * Remember where this patch ends so we know where to start up again.
416  */
417 void
418 next_intuit_at(long file_pos, long file_line)
419 {
420         p_base = file_pos;
421         p_bline = file_line;
422 }
423
424 /*
425  * Basically a verbose fseek() to the actual diff listing.
426  */
427 void
428 skip_to(long file_pos, long file_line)
429 {
430         size_t len;
431
432         assert(p_base <= file_pos);
433         if (verbose && p_base < file_pos) {
434                 Fseek(pfp, p_base, 0);
435                 say1("The text leading up to this was:\n--------------------------\n");
436                 while (ftell(pfp) < file_pos) {
437                         len = pgets(FALSE);
438                         assert(len != 0);
439                         say2("|%s", buf);
440                 }
441                 say1("--------------------------\n");
442         }
443         else
444                 Fseek(pfp, file_pos, 0);
445         p_input_line = file_line - 1;
446 }
447
448 /*
449  * Make this a function for better debugging.
450  */
451 static void
452 malformed(void)
453 {
454         fatal3("malformed patch at line %ld: %s", p_input_line, buf);
455                 /* about as informative as "Syntax error" in C */
456 }
457
458 /*
459  * True if the line has been discarded (i.e. it is a line saying
460  *  "\ No newline at end of file".)
461  */
462 static bool
463 remove_special_line(void)
464 {
465         int c;
466
467         c = fgetc(pfp);
468         if (c == '\\') {
469                 do {
470                         c = fgetc(pfp);
471                 } while (c != EOF && c != '\n');
472
473                 return TRUE;
474         }
475
476         if (c != EOF)
477                 fseek(pfp, -1, SEEK_CUR);
478
479         return FALSE;
480 }
481
482 /*
483  * True if there is more of the current diff listing to process.
484  */
485 bool
486 another_hunk(void)
487 {
488     Reg1 char *s;
489     size_t len;
490     Reg2 int context = 0;
491
492     while (p_end >= 0) {
493         if (p_end == p_efake)
494             p_end = p_bfake;            /* don't free twice */
495         else
496             free(p_line[p_end]);
497         p_end--;
498     }
499     assert(p_end == -1);
500     p_efake = -1;
501
502     p_max = hunkmax;                    /* gets reduced when --- found */
503     if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
504         long line_beginning = ftell(pfp);
505                                         /* file pos of the current line */
506         LINENUM repl_beginning = 0;     /* index of --- line */
507         Reg4 LINENUM fillcnt = 0;       /* #lines of missing ptrn or repl */
508         Reg5 LINENUM fillsrc;           /* index of first line to copy */
509         Reg6 LINENUM filldst;           /* index of first missing line */
510         bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */
511         Reg9 bool repl_could_be_missing = TRUE;
512                                         /* no + or ! lines in this hunk */
513         bool repl_missing = FALSE;      /* we are now backtracking */
514         long repl_backtrack_position = 0;
515                                         /* file pos of first repl line */
516         LINENUM repl_patch_line;        /* input line number for same */
517         Reg7 LINENUM ptrn_copiable = 0;
518                                         /* # of copiable lines in ptrn */
519
520         len = pgets(TRUE);
521         p_input_line++;
522         if (len == 0 || strnNE(buf, "********", 8)) {
523             next_intuit_at(line_beginning,p_input_line);
524             return FALSE;
525         }
526         p_context = 100;
527         p_hunk_beg = p_input_line + 1;
528         while (p_end < p_max) {
529             line_beginning = ftell(pfp);
530             len = pgets(TRUE);
531             p_input_line++;
532             if (len == 0) {
533                 if (p_max - p_end < 4)
534                     Strcpy(buf, "  \n");  /* assume blank lines got chopped */
535                 else {
536                     if (repl_beginning && repl_could_be_missing) {
537                         repl_missing = TRUE;
538                         goto hunk_done;
539                     }
540                     fatal1("unexpected end of file in patch\n");
541                 }
542             }
543             p_end++;
544             assert(p_end < hunkmax);
545             p_Char[p_end] = *buf;
546 #ifdef zilog
547             p_line[(short)p_end] = Nullch;
548 #else
549             p_line[p_end] = Nullch;
550 #endif
551             switch (*buf) {
552             case '*':
553                 if (strnEQ(buf, "********", 8)) {
554                     if (repl_beginning && repl_could_be_missing) {
555                         repl_missing = TRUE;
556                         goto hunk_done;
557                     }
558                     else
559                         fatal2("unexpected end of hunk at line %ld\n",
560                             p_input_line);
561                 }
562                 if (p_end != 0) {
563                     if (repl_beginning && repl_could_be_missing) {
564                         repl_missing = TRUE;
565                         goto hunk_done;
566                     }
567                     fatal3("unexpected *** at line %ld: %s", p_input_line, buf);
568                 }
569                 context = 0;
570                 p_line[p_end] = savestr(buf);
571                 if (out_of_mem) {
572                     p_end--;
573                     return FALSE;
574                 }
575                 for (s=buf; *s && !isdigit((unsigned char)*s); s++) ;
576                 if (!*s)
577                     malformed ();
578                 if (strnEQ(s,"0,0",3))
579                     strcpy(s,s+2);
580                 p_first = (LINENUM) atol(s);
581                 while (isdigit((unsigned char)*s)) s++;
582                 if (*s == ',') {
583                     for (; *s && !isdigit((unsigned char)*s); s++) ;
584                     if (!*s)
585                         malformed ();
586                     p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
587                 }
588                 else if (p_first)
589                     p_ptrn_lines = 1;
590                 else {
591                     p_ptrn_lines = 0;
592                     p_first = 1;
593                 }
594                 p_max = p_ptrn_lines + 6;       /* we need this much at least */
595                 while (p_max >= hunkmax)
596                     grow_hunkmax();
597                 p_max = hunkmax;
598                 break;
599             case '-':
600                 if (buf[1] == '-') {
601                     if (repl_beginning ||
602                         (p_end != p_ptrn_lines + 1 + (p_Char[p_end-1] == '\n')))
603                     {
604                         if (p_end == 1) {
605                             /* `old' lines were omitted - set up to fill */
606                             /* them in from 'new' context lines. */
607                             p_end = p_ptrn_lines + 1;
608                             fillsrc = p_end + 1;
609                             filldst = 1;
610                             fillcnt = p_ptrn_lines;
611                         }
612                         else {
613                             if (repl_beginning) {
614                                 if (repl_could_be_missing){
615                                     repl_missing = TRUE;
616                                     goto hunk_done;
617                                 }
618                                 fatal3(
619 "duplicate \"---\" at line %ld--check line numbers at line %ld\n",
620                                     p_input_line, p_hunk_beg + repl_beginning);
621                             }
622                             else {
623                                 fatal4(
624 "%s \"---\" at line %ld--check line numbers at line %ld\n",
625                                     (p_end <= p_ptrn_lines
626                                         ? "Premature"
627                                         : "Overdue" ),
628                                     p_input_line, p_hunk_beg);
629                             }
630                         }
631                     }
632                     repl_beginning = p_end;
633                     repl_backtrack_position = ftell(pfp);
634                     repl_patch_line = p_input_line;
635                     p_line[p_end] = savestr(buf);
636                     if (out_of_mem) {
637                         p_end--;
638                         return FALSE;
639                     }
640                     p_Char[p_end] = '=';
641                     for (s=buf; *s && !isdigit((unsigned char)*s); s++) ;
642                     if (!*s)
643                         malformed ();
644                     p_newfirst = (LINENUM) atol(s);
645                     while (isdigit((unsigned char)*s)) s++;
646                     if (*s == ',') {
647                         for (; *s && !isdigit((unsigned char)*s); s++) ;
648                         if (!*s)
649                             malformed ();
650                         p_repl_lines = ((LINENUM)atol(s)) - p_newfirst + 1;
651                     }
652                     else if (p_newfirst)
653                         p_repl_lines = 1;
654                     else {
655                         p_repl_lines = 0;
656                         p_newfirst = 1;
657                     }
658                     p_max = p_repl_lines + p_end;
659                     if (p_max > MAXHUNKSIZE)
660                         fatal4("hunk too large (%ld lines) at line %ld: %s",
661                               p_max, p_input_line, buf);
662                     while (p_max >= hunkmax)
663                         grow_hunkmax();
664                     if (p_repl_lines != ptrn_copiable
665                      && (p_context != 0 || p_repl_lines != 1))
666                         repl_could_be_missing = FALSE;
667                     break;
668                 }
669                 goto change_line;
670             case '+':  case '!':
671                 repl_could_be_missing = FALSE;
672               change_line:
673                 if (buf[1] == '\n' && canonicalize)
674                     strcpy(buf+1," \n");
675                 if (!isspace((unsigned char)buf[1]) && buf[1] != '>' && buf[1] != '<' &&
676                   repl_beginning && repl_could_be_missing) {
677                     repl_missing = TRUE;
678                     goto hunk_done;
679                 }
680                 if (context >= 0) {
681                     if (context < p_context)
682                         p_context = context;
683                     context = -1000;
684                 }
685                 p_line[p_end] = savestr(buf+2);
686                 if (out_of_mem) {
687                     p_end--;
688                     return FALSE;
689                 }
690                 if (p_end == p_ptrn_lines)
691                 {
692                         if (remove_special_line()) {
693                                 int len;
694
695                                 len = strlen(p_line[p_end]) - 1;
696                                 (p_line[p_end])[len] = 0;
697                         }
698                 }
699                 break;
700             case '\t': case '\n':       /* assume the 2 spaces got eaten */
701                 if (repl_beginning && repl_could_be_missing &&
702                   (!ptrn_spaces_eaten || diff_type == NEW_CONTEXT_DIFF) ) {
703                     repl_missing = TRUE;
704                     goto hunk_done;
705                 }
706                 p_line[p_end] = savestr(buf);
707                 if (out_of_mem) {
708                     p_end--;
709                     return FALSE;
710                 }
711                 if (p_end != p_ptrn_lines + 1) {
712                     ptrn_spaces_eaten |= (repl_beginning != 0);
713                     context++;
714                     if (!repl_beginning)
715                         ptrn_copiable++;
716                     p_Char[p_end] = ' ';
717                 }
718                 break;
719             case ' ':
720                 if (!isspace((unsigned char)buf[1]) &&
721                   repl_beginning && repl_could_be_missing) {
722                     repl_missing = TRUE;
723                     goto hunk_done;
724                 }
725                 context++;
726                 if (!repl_beginning)
727                     ptrn_copiable++;
728                 p_line[p_end] = savestr(buf+2);
729                 if (out_of_mem) {
730                     p_end--;
731                     return FALSE;
732                 }
733                 break;
734             default:
735                 if (repl_beginning && repl_could_be_missing) {
736                     repl_missing = TRUE;
737                     goto hunk_done;
738                 }
739                 malformed ();
740             }
741             /* set up p_len for strncmp() so we don't have to */
742             /* assume null termination */
743             if (p_line[p_end])
744                 p_len[p_end] = strlen(p_line[p_end]);
745             else
746                 p_len[p_end] = 0;
747         }
748
749     hunk_done:
750         if (p_end >=0 && !repl_beginning)
751             fatal2("no --- found in patch at line %ld\n", pch_hunk_beg());
752
753         if (repl_missing) {
754
755             /* reset state back to just after --- */
756             p_input_line = repl_patch_line;
757             for (p_end--; p_end > repl_beginning; p_end--)
758                 free(p_line[p_end]);
759             Fseek(pfp, repl_backtrack_position, 0);
760
761             /* redundant 'new' context lines were omitted - set */
762             /* up to fill them in from the old file context */
763             if (!p_context && p_repl_lines == 1) {
764                 p_repl_lines = 0;
765                 p_max--;
766             }
767             fillsrc = 1;
768             filldst = repl_beginning+1;
769             fillcnt = p_repl_lines;
770             p_end = p_max;
771         }
772         else if (!p_context && fillcnt == 1) {
773             /* the first hunk was a null hunk with no context */
774             /* and we were expecting one line -- fix it up. */
775             while (filldst < p_end) {
776                 p_line[filldst] = p_line[filldst+1];
777                 p_Char[filldst] = p_Char[filldst+1];
778                 p_len[filldst] = p_len[filldst+1];
779                 filldst++;
780             }
781 #if 0
782             repl_beginning--;           /* this doesn't need to be fixed */
783 #endif
784             p_end--;
785             p_first++;                  /* do append rather than insert */
786             fillcnt = 0;
787             p_ptrn_lines = 0;
788         }
789
790         if (diff_type == CONTEXT_DIFF &&
791           (fillcnt || (p_first > 1 && ptrn_copiable > 2*p_context)) ) {
792             if (verbose)
793                 say4("%s\n%s\n%s\n",
794 "(Fascinating--this is really a new-style context diff but without",
795 "the telltale extra asterisks on the *** line that usually indicate",
796 "the new style...)");
797             diff_type = NEW_CONTEXT_DIFF;
798         }
799
800         /* if there were omitted context lines, fill them in now */
801         if (fillcnt) {
802             p_bfake = filldst;          /* remember where not to free() */
803             p_efake = filldst + fillcnt - 1;
804             while (fillcnt-- > 0) {
805                 while (fillsrc <= p_end && p_Char[fillsrc] != ' ')
806                     fillsrc++;
807                 if (fillsrc > p_end)
808                     fatal2("replacement text or line numbers mangled in hunk at line %ld\n",
809                         p_hunk_beg);
810                 p_line[filldst] = p_line[fillsrc];
811                 p_Char[filldst] = p_Char[fillsrc];
812                 p_len[filldst] = p_len[fillsrc];
813                 fillsrc++; filldst++;
814             }
815             while (fillsrc <= p_end && fillsrc != repl_beginning &&
816               p_Char[fillsrc] != ' ')
817                 fillsrc++;
818 #ifdef DEBUGGING
819             if (debug & 64)
820                 printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
821                     fillsrc,filldst,repl_beginning,p_end+1);
822 #endif
823             assert(fillsrc==p_end+1 || fillsrc==repl_beginning);
824             assert(filldst==p_end+1 || filldst==repl_beginning);
825         }
826
827         if (p_line[p_end] != NULL)
828         {
829                 if (remove_special_line()) {
830                         p_len[p_end] -= 1;
831                         (p_line[p_end])[p_len[p_end]] = 0;
832                 }
833         }
834     }
835     else if (diff_type == UNI_DIFF) {
836         long line_beginning = ftell(pfp);
837                                         /* file pos of the current line */
838         Reg4 LINENUM fillsrc;           /* index of old lines */
839         Reg5 LINENUM filldst;           /* index of new lines */
840         char ch;
841
842         len = pgets(TRUE);
843         p_input_line++;
844         if (len == 0 || strnNE(buf, "@@ -", 4)) {
845             next_intuit_at(line_beginning,p_input_line);
846             return FALSE;
847         }
848         s = buf+4;
849         if (!*s)
850             malformed ();
851         p_first = (LINENUM) atol(s);
852         while (isdigit((unsigned char)*s)) s++;
853         if (*s == ',') {
854             p_ptrn_lines = (LINENUM) atol(++s);
855             while (isdigit((unsigned char)*s)) s++;
856         } else
857             p_ptrn_lines = 1;
858         if (*s == ' ') s++;
859         if (*s != '+' || !*++s)
860             malformed ();
861         p_newfirst = (LINENUM) atol(s);
862         while (isdigit((unsigned char)*s)) s++;
863         if (*s == ',') {
864             p_repl_lines = (LINENUM) atol(++s);
865             while (isdigit((unsigned char)*s)) s++;
866         } else
867             p_repl_lines = 1;
868         if (*s == ' ') s++;
869         if (*s != '@')
870             malformed ();
871         if (!p_ptrn_lines)
872             p_first++;                  /* do append rather than insert */
873         p_max = p_ptrn_lines + p_repl_lines + 1;
874         while (p_max >= hunkmax)
875             grow_hunkmax();
876         fillsrc = 1;
877         filldst = fillsrc + p_ptrn_lines;
878         p_end = filldst + p_repl_lines;
879         Sprintf(buf,"*** %ld,%ld ****\n",p_first,p_first + p_ptrn_lines - 1);
880         p_line[0] = savestr(buf);
881         if (out_of_mem) {
882             p_end = -1;
883             return FALSE;
884         }
885         p_Char[0] = '*';
886         Sprintf(buf,"--- %ld,%ld ----\n",p_newfirst,p_newfirst+p_repl_lines-1);
887         p_line[filldst] = savestr(buf);
888         if (out_of_mem) {
889             p_end = 0;
890             return FALSE;
891         }
892         p_Char[filldst++] = '=';
893         p_context = 100;
894         context = 0;
895         p_hunk_beg = p_input_line + 1;
896         while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
897             line_beginning = ftell(pfp);
898             len = pgets(TRUE);
899             p_input_line++;
900             if (len == 0) {
901                 if (p_max - filldst < 3)
902                     Strcpy(buf, " \n");  /* assume blank lines got chopped */
903                 else {
904                     fatal1("unexpected end of file in patch\n");
905                 }
906             }
907             if (*buf == '\t' || *buf == '\n') {
908                 ch = ' ';               /* assume the space got eaten */
909                 s = savestr(buf);
910             }
911             else {
912                 ch = *buf;
913                 s = savestr(buf+1);
914             }
915             if (out_of_mem) {
916                 while (--filldst > p_ptrn_lines)
917                     free(p_line[filldst]);
918                 p_end = fillsrc-1;
919                 return FALSE;
920             }
921             switch (ch) {
922             case '-':
923                 if (fillsrc > p_ptrn_lines) {
924                     free(s);
925                     p_end = filldst-1;
926                     malformed ();
927                 }
928                 p_Char[fillsrc] = ch;
929                 p_line[fillsrc] = s;
930                 p_len[fillsrc++] = strlen(s);
931                 if (fillsrc > p_ptrn_lines) {
932                         if (remove_special_line()) {
933                                 p_len[fillsrc - 1] -= 1;
934                                 s[p_len[fillsrc - 1]] = 0;
935                         }
936                 }
937                 break;
938             case '=':
939                 ch = ' ';
940                 /* FALLTHROUGH */
941             case ' ':
942                 if (fillsrc > p_ptrn_lines) {
943                     free(s);
944                     while (--filldst > p_ptrn_lines)
945                         free(p_line[filldst]);
946                     p_end = fillsrc-1;
947                     malformed ();
948                 }
949                 context++;
950                 p_Char[fillsrc] = ch;
951                 p_line[fillsrc] = s;
952                 p_len[fillsrc++] = strlen(s);
953                 s = savestr(s);
954                 if (out_of_mem) {
955                     while (--filldst > p_ptrn_lines)
956                         free(p_line[filldst]);
957                     p_end = fillsrc-1;
958                     return FALSE;
959                 }
960                 /* FALLTHROUGH */
961             case '+':
962                 if (filldst > p_end) {
963                     free(s);
964                     while (--filldst > p_ptrn_lines)
965                         free(p_line[filldst]);
966                     p_end = fillsrc-1;
967                     malformed ();
968                 }
969                 p_Char[filldst] = ch;
970                 p_line[filldst] = s;
971                 p_len[filldst++] = strlen(s);
972                 if (fillsrc > p_ptrn_lines) {
973                         if (remove_special_line()) {
974                                 p_len[filldst - 1] -= 1;
975                                 s[p_len[filldst - 1]] = 0;
976                         }
977                 }
978                 break;
979             default:
980                 p_end = filldst;
981                 malformed ();
982             }
983             if (ch != ' ' && context > 0) {
984                 if (context < p_context)
985                     p_context = context;
986                 context = -1000;
987             }
988         }/* while */
989     }
990     else {                              /* normal diff--fake it up */
991         char hunk_type;
992         Reg3 int i;
993         LINENUM min, max;
994         long line_beginning = ftell(pfp);
995
996         p_context = 0;
997         len = pgets(TRUE);
998         p_input_line++;
999         if (len == 0 || !isdigit((unsigned char)*buf)) {
1000             next_intuit_at(line_beginning,p_input_line);
1001             return FALSE;
1002         }
1003         p_first = (LINENUM)atol(buf);
1004         for (s=buf; isdigit((unsigned char)*s); s++) ;
1005         if (*s == ',') {
1006             p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;
1007             while (isdigit((unsigned char)*s)) s++;
1008         }
1009         else
1010             p_ptrn_lines = (*s != 'a');
1011         hunk_type = *s;
1012         if (hunk_type == 'a')
1013             p_first++;                  /* do append rather than insert */
1014         min = (LINENUM)atol(++s);
1015         for (; isdigit((unsigned char)*s); s++) ;
1016         if (*s == ',')
1017             max = (LINENUM)atol(++s);
1018         else
1019             max = min;
1020         if (hunk_type == 'd')
1021             min++;
1022         p_end = p_ptrn_lines + 1 + max - min + 1;
1023         if (p_end > MAXHUNKSIZE)
1024             fatal4("hunk too large (%ld lines) at line %ld: %s",
1025                   p_end, p_input_line, buf);
1026         while (p_end >= hunkmax)
1027             grow_hunkmax();
1028         p_newfirst = min;
1029         p_repl_lines = max - min + 1;
1030         Sprintf(buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1);
1031         p_line[0] = savestr(buf);
1032         if (out_of_mem) {
1033             p_end = -1;
1034             return FALSE;
1035         }
1036         p_Char[0] = '*';
1037         for (i=1; i<=p_ptrn_lines; i++) {
1038             len = pgets(TRUE);
1039             p_input_line++;
1040             if (len == 0)
1041                 fatal2("unexpected end of file in patch at line %ld\n",
1042                   p_input_line);
1043             if (*buf != '<')
1044                 fatal2("< expected at line %ld of patch\n", p_input_line);
1045             p_line[i] = savestr(buf+2);
1046             if (out_of_mem) {
1047                 p_end = i-1;
1048                 return FALSE;
1049             }
1050             p_len[i] = strlen(p_line[i]);
1051             p_Char[i] = '-';
1052         }
1053
1054         if (remove_special_line()) {
1055                 p_len[i-1] -= 1;
1056                 (p_line[i-1])[p_len[i-1]] = 0;
1057         }
1058
1059         if (hunk_type == 'c') {
1060             len = pgets(TRUE);
1061             p_input_line++;
1062             if (len == 0)
1063                 fatal2("unexpected end of file in patch at line %ld\n",
1064                     p_input_line);
1065             if (*buf != '-')
1066                 fatal2("--- expected at line %ld of patch\n", p_input_line);
1067         }
1068         Sprintf(buf, "--- %ld,%ld\n", min, max);
1069         p_line[i] = savestr(buf);
1070         if (out_of_mem) {
1071             p_end = i-1;
1072             return FALSE;
1073         }
1074         p_Char[i] = '=';
1075         for (i++; i<=p_end; i++) {
1076             len = pgets(TRUE);
1077             p_input_line++;
1078             if (len == 0)
1079                 fatal2("unexpected end of file in patch at line %ld\n",
1080                     p_input_line);
1081             if (*buf != '>')
1082                 fatal2("> expected at line %ld of patch\n", p_input_line);
1083             p_line[i] = savestr(buf+2);
1084             if (out_of_mem) {
1085                 p_end = i-1;
1086                 return FALSE;
1087             }
1088             p_len[i] = strlen(p_line[i]);
1089             p_Char[i] = '+';
1090         }
1091
1092         if (remove_special_line()) {
1093                 p_len[i-1] -= 1;
1094                 (p_line[i-1])[p_len[i-1]] = 0;
1095         }
1096     }
1097     if (reverse)                        /* backwards patch? */
1098         if (!pch_swap())
1099             say1("Not enough memory to swap next hunk!\n");
1100 #ifdef DEBUGGING
1101     if (debug & 2) {
1102         int i;
1103         char special;
1104
1105         for (i=0; i <= p_end; i++) {
1106             if (i == p_ptrn_lines)
1107                 special = '^';
1108             else
1109                 special = ' ';
1110             fprintf(stderr, "%3d %c %c %s", i, p_Char[i], special, p_line[i]);
1111             Fflush(stderr);
1112         }
1113     }
1114 #endif
1115     if (p_end+1 < hunkmax)      /* paranoia reigns supreme... */
1116         p_Char[p_end+1] = '^';  /* add a stopper for apply_hunk */
1117     return TRUE;
1118 }
1119
1120 /*
1121  * Input a line from the patch file.
1122  * Worry about indentation if do_indent is true.
1123  * The line is read directly into the buf global variable which
1124  * is resized if necessary in order to hold the complete line.
1125  * Returns the number of characters read including the terminating
1126  * '\n', if any.
1127  */
1128 size_t
1129 pgets(bool do_indent)
1130 {
1131         char *line;
1132         size_t len;
1133         int indent = 0, skipped = 0;
1134
1135         line = fgetln(pfp, &len);
1136         if (line != Nullch) {
1137                 if (len + 1 > buf_size) {
1138                         while (len + 1 > buf_size)
1139                                 buf_size *= 2;
1140                         free(buf);
1141                         buf = malloc(buf_size);
1142                         if (buf == Nullch)
1143                                 fatal1("out of memory\n");
1144                 }
1145                 if (do_indent == TRUE && p_indent) {
1146                         for (;
1147                             indent < p_indent && (*line == ' ' || *line == '\t' || *line == 'X');
1148                             line++, skipped++) {
1149                                 if (*line == '\t')
1150                                         indent += 8 - (indent %7);
1151                                 else
1152                                         indent++;
1153                         }
1154                 }
1155                 Strncpy(buf, line, len - skipped);
1156                 buf[len - skipped] = '\0';
1157         }
1158         return len;
1159 }
1160
1161 /*
1162  * Reverse the old and new portions of the current hunk.
1163  */
1164 bool
1165 pch_swap(void)
1166 {
1167         char **tp_line;         /* the text of the hunk */
1168         short *tp_len;          /* length of each line */
1169         char *tp_char;          /* +, -, and ! */
1170         Reg1 LINENUM i;
1171         Reg2 LINENUM n;
1172         bool blankline = FALSE;
1173         Reg3 char *s;
1174
1175         i = p_first;
1176         p_first = p_newfirst;
1177         p_newfirst = i;
1178
1179         /* make a scratch copy */
1180
1181         tp_line = p_line;
1182         tp_len = p_len;
1183         tp_char = p_Char;
1184         p_line = Null(char**);  /* force set_hunkmax to allocate again */
1185         p_len = Null(short*);
1186         p_Char = Nullch;
1187         set_hunkmax();
1188         if (p_line == Null(char**) || p_len == Null(short*) || p_Char == Nullch) {
1189 #ifndef lint
1190                 if (p_line == Null(char**))
1191                         free((char*)p_line);
1192                 p_line = tp_line;
1193                 if (p_len == Null(short*))
1194                         free((char*)p_len);
1195                 p_len = tp_len;
1196 #endif
1197                 if (p_Char == Nullch)
1198                         free((char*)p_Char);
1199                 p_Char = tp_char;
1200                 return FALSE;           /* not enough memory to swap hunk! */
1201         }
1202
1203         /* now turn the new into the old */
1204
1205         i = p_ptrn_lines + 1;
1206         if (tp_char[i] == '\n') {       /* account for possible blank line */
1207                 blankline = TRUE;
1208                 i++;
1209         }
1210         if (p_efake >= 0) {             /* fix non-freeable ptr range */
1211                 if (p_efake <= i)
1212                         n = p_end - i + 1;
1213                 else
1214                         n = -i;
1215                 p_efake += n;
1216                 p_bfake += n;
1217         }
1218         for (n=0; i <= p_end; i++,n++) {
1219                 p_line[n] = tp_line[i];
1220                 p_Char[n] = tp_char[i];
1221                 if (p_Char[n] == '+')
1222                         p_Char[n] = '-';
1223                 p_len[n] = tp_len[i];
1224         }
1225         if (blankline) {
1226                 i = p_ptrn_lines + 1;
1227                 p_line[n] = tp_line[i];
1228                 p_Char[n] = tp_char[i];
1229                 p_len[n] = tp_len[i];
1230                 n++;
1231         }
1232         assert(p_Char[0] == '=');
1233         p_Char[0] = '*';
1234         for (s=p_line[0]; *s; s++)
1235                 if (*s == '-')
1236                         *s = '*';
1237
1238         /* now turn the old into the new */
1239
1240         assert(tp_char[0] == '*');
1241         tp_char[0] = '=';
1242         for (s=tp_line[0]; *s; s++)
1243                 if (*s == '*')
1244                         *s = '-';
1245         for (i=0; n <= p_end; i++,n++) {
1246                 p_line[n] = tp_line[i];
1247                 p_Char[n] = tp_char[i];
1248                 if (p_Char[n] == '-')
1249                         p_Char[n] = '+';
1250                 p_len[n] = tp_len[i];
1251         }
1252         assert(i == p_ptrn_lines + 1);
1253         i = p_ptrn_lines;
1254         p_ptrn_lines = p_repl_lines;
1255         p_repl_lines = i;
1256 #ifndef lint
1257         if (tp_line == Null(char**))
1258                 free((char*)tp_line);
1259         if (tp_len == Null(short*))
1260                 free((char*)tp_len);
1261 #endif
1262         if (tp_char == Nullch)
1263                 free((char*)tp_char);
1264         return TRUE;
1265 }
1266
1267 /*
1268  * Return the specified line position in the old file of the old context.
1269  */
1270 LINENUM
1271 pch_first(void)
1272 {
1273         return p_first;
1274 }
1275
1276 /*
1277  * Return the number of lines of old context.
1278  */
1279 LINENUM
1280 pch_ptrn_lines(void)
1281 {
1282         return p_ptrn_lines;
1283 }
1284
1285 /*
1286  * Return the probable line position in the new file of the first line.
1287  */
1288 LINENUM
1289 pch_newfirst(void)
1290 {
1291         return p_newfirst;
1292 }
1293
1294 /*
1295  * Return the number of lines in the replacement text including context.
1296  */
1297 LINENUM
1298 pch_repl_lines(void)
1299 {
1300         return p_repl_lines;
1301 }
1302
1303 /*
1304  * Return the number of lines in the whole hunk.
1305  */
1306 LINENUM
1307 pch_end(void)
1308 {
1309         return p_end;
1310 }
1311
1312 /*
1313  * Return the number of context lines before the first changed line.
1314  */
1315 LINENUM
1316 pch_context(void)
1317 {
1318         return p_context;
1319 }
1320
1321 /*
1322  * Return the length of a particular patch line.
1323  */
1324 short
1325 pch_line_len(LINENUM line)
1326 {
1327         return p_len[line];
1328 }
1329
1330 /*
1331  * Return the control character (+, -, *, !, etc) for a patch line.
1332  */
1333 char
1334 pch_char(LINENUM line)
1335 {
1336         return p_Char[line];
1337 }
1338
1339 /*
1340  * Return a pointer to a particular patch line.
1341  */
1342 char *
1343 pfetch(LINENUM line)
1344 {
1345         return p_line[line];
1346 }
1347
1348 /*
1349  * Return where in the patch file this hunk began, for error messages.
1350  */
1351 LINENUM
1352 pch_hunk_beg(void)
1353 {
1354         return p_hunk_beg;
1355 }
1356
1357 /*
1358  * Apply an ed script by feeding ed itself.
1359  */
1360 void
1361 do_ed_script(void)
1362 {
1363         Reg1 char *t;
1364         Reg2 long beginning_of_this_line;
1365         Reg3 bool this_line_is_command = FALSE;
1366         Reg4 FILE *pipefp;
1367
1368         if (!skip_rest_of_patch) {
1369                 Unlink(TMPOUTNAME);
1370                 copy_file(filearg[0], TMPOUTNAME);
1371                 if (verbose)
1372                         Sprintf(buf, "/bin/ed %s", TMPOUTNAME);
1373                 else
1374                         Sprintf(buf, "/bin/ed - %s", TMPOUTNAME);
1375                 pipefp = popen(buf, "w");
1376         }
1377         for (;;) {
1378                 beginning_of_this_line = ftell(pfp);
1379                 if (pgets(TRUE) == 0) {
1380                         next_intuit_at(beginning_of_this_line, p_input_line);
1381                         break;
1382                 }
1383                 p_input_line++;
1384                 for (t=buf; isdigit((unsigned char)*t) || *t == ','; t++)
1385                         ;
1386                 this_line_is_command = (isdigit((unsigned char)*buf) &&
1387                     (*t == 'd' || *t == 'c' || *t == 'a') );
1388                 if (this_line_is_command) {
1389                         if (!skip_rest_of_patch)
1390                                 fputs(buf, pipefp);
1391                         if (*t != 'd') {
1392                                 while (pgets(TRUE) != 0) {
1393                                         p_input_line++;
1394                                         if (!skip_rest_of_patch)
1395                                                 fputs(buf, pipefp);
1396                                         if (strEQ(buf, ".\n"))
1397                                                 break;
1398                                 }
1399                         }
1400                 }
1401                 else {
1402                         next_intuit_at(beginning_of_this_line,p_input_line);
1403                         break;
1404                 }
1405         }
1406         if (skip_rest_of_patch)
1407                 return;
1408         fprintf(pipefp, "w\n");
1409         fprintf(pipefp, "q\n");
1410         Fflush(pipefp);
1411         Pclose(pipefp);
1412         ignore_signals();
1413         if (move_file(TMPOUTNAME, outname) < 0) {
1414                 toutkeep = TRUE;
1415                 chmod(TMPOUTNAME, filemode);
1416         }
1417         else
1418                 chmod(outname, filemode);
1419         set_signals(1);
1420 }