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