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