|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)patch.c 5.3 (Berkeley) 8/16/85";
3: #endif not lint
4:
5: /* patch - a program to apply diffs to original files
6: *
7: * $Header: patch.c,v 1.3 85/03/26 15:07:43 lwall Exp $
8: *
9: * Copyright 1984, Larry Wall
10: *
11: * This program may be copied as long as you don't try to make any
12: * money off of it, or pretend that you wrote it.
13: *
14: * $Log: patch.c,v $
15: * 85/08/15 van%ucbmonet@berkeley
16: * Changes for 4.3bsd diff -c.
17: *
18: * Revision 1.3 85/03/26 15:07:43 lwall
19: * Frozen.
20: *
21: * Revision 1.2.1.9 85/03/12 17:03:35 lwall
22: * Changed pfp->_file to fileno(pfp).
23: *
24: * Revision 1.2.1.8 85/03/12 16:30:43 lwall
25: * Check i_ptr and i_womp to make sure they aren't null before freeing.
26: * Also allow ed output to be suppressed.
27: *
28: * Revision 1.2.1.7 85/03/12 15:56:13 lwall
29: * Added -p option from jromine@uci-750a.
30: *
31: * Revision 1.2.1.6 85/03/12 12:12:51 lwall
32: * Now checks for normalness of file to patch.
33: *
34: * Revision 1.2.1.5 85/03/12 11:52:12 lwall
35: * Added -D (#ifdef) option from joe@fluke.
36: *
37: * Revision 1.2.1.4 84/12/06 11:14:15 lwall
38: * Made smarter about SCCS subdirectories.
39: *
40: * Revision 1.2.1.3 84/12/05 11:18:43 lwall
41: * Added -l switch to do loose string comparison.
42: *
43: * Revision 1.2.1.2 84/12/04 09:47:13 lwall
44: * Failed hunk count not reset on multiple patch file.
45: *
46: * Revision 1.2.1.1 84/12/04 09:42:37 lwall
47: * Branch for sdcrdcf changes.
48: *
49: * Revision 1.2 84/11/29 13:29:51 lwall
50: * Linted. Identifiers uniqified. Fixed i_ptr malloc() bug. Fixed
51: * multiple calls to mktemp(). Will now work on machines that can only
52: * read 32767 chars. Added -R option for diffs with new and old swapped.
53: * Various cosmetic changes.
54: *
55: * Revision 1.1 84/11/09 17:03:58 lwall
56: * Initial revision
57: *
58: */
59:
60: #define DEBUGGING
61:
62: /* shut lint up about the following when return value ignored */
63:
64: #define Signal (void)signal
65: #define Unlink (void)unlink
66: #define Lseek (void)lseek
67: #define Fseek (void)fseek
68: #define Fstat (void)fstat
69: #define Pclose (void)pclose
70: #define Close (void)close
71: #define Fclose (void)fclose
72: #define Fflush (void)fflush
73: #define Sprintf (void)sprintf
74: #define Mktemp (void)mktemp
75: #define Strcpy (void)strcpy
76: #define Strcat (void)strcat
77:
78: #include <stdio.h>
79: #include <assert.h>
80: #include <sys/types.h>
81: #include <sys/stat.h>
82: #include <ctype.h>
83: #include <signal.h>
84:
85: /* constants */
86:
87: #define TRUE (1)
88: #define FALSE (0)
89:
90: #define MAXHUNKSIZE 500
91: #define MAXLINELEN 1024
92: #define BUFFERSIZE 1024
93: #define ORIGEXT ".orig"
94: #define SCCSPREFIX "s."
95: #define GET "get -e %s"
96: #define RCSSUFFIX ",v"
97: #define CHECKOUT "co -l %s"
98:
99: /* handy definitions */
100:
101: #define Null(t) ((t)0)
102: #define Nullch Null(char *)
103: #define Nullfp Null(FILE *)
104:
105: #define Ctl(ch) (ch & 037)
106:
107: #define strNE(s1,s2) (strcmp(s1,s2))
108: #define strEQ(s1,s2) (!strcmp(s1,s2))
109: #define strnNE(s1,s2,l) (strncmp(s1,s2,l))
110: #define strnEQ(s1,s2,l) (!strncmp(s1,s2,l))
111:
112: /* typedefs */
113:
114: typedef char bool;
115: typedef long LINENUM; /* must be signed */
116: typedef unsigned MEM; /* what to feed malloc */
117:
118: /* globals */
119:
120: int Argc; /* guess */
121: char **Argv;
122:
123: struct stat filestat; /* file statistics area */
124:
125: char serrbuf[BUFSIZ]; /* buffer for stderr */
126: char buf[MAXLINELEN]; /* general purpose buffer */
127: FILE *pfp = Nullfp; /* patch file pointer */
128: FILE *ofp = Nullfp; /* output file pointer */
129: FILE *rejfp = Nullfp; /* reject file pointer */
130:
131: LINENUM input_lines = 0; /* how long is input file in lines */
132: LINENUM last_frozen_line = 0; /* how many input lines have been */
133: /* irretractibly output */
134:
135: #define MAXFILEC 2
136: int filec = 0; /* how many file arguments? */
137: char *filearg[MAXFILEC];
138:
139: char *outname = Nullch;
140: char rejname[128];
141:
142: char *origext = Nullch;
143:
144: char TMPOUTNAME[] = "/tmp/patchoXXXXXX";
145: char TMPINNAME[] = "/tmp/patchiXXXXXX"; /* you might want /usr/tmp here */
146: char TMPREJNAME[] = "/tmp/patchrXXXXXX";
147: char TMPPATNAME[] = "/tmp/patchpXXXXXX";
148:
149: LINENUM last_offset = 0;
150: #ifdef DEBUGGING
151: int debug = 0;
152: #endif
153: bool verbose = TRUE;
154: bool reverse = FALSE;
155: bool usepath = FALSE;
156: bool canonicalize = FALSE;
157:
158: #define CONTEXT_DIFF 1
159: #define NORMAL_DIFF 2
160: #define ED_DIFF 3
161: #define NEW_CONTEXT_DIFF 4
162: int diff_type = 0;
163:
164: int do_defines = 0; /* patch using ifdef, ifndef, etc. */
165: char if_defined[128]; /* #ifdef xyzzy */
166: char not_defined[128]; /* #ifndef xyzzy */
167: char else_defined[] = "#else\n"; /* #else */
168: char end_defined[128]; /* #endif xyzzy */
169:
170: char *revision = Nullch; /* prerequisite revision, if any */
171:
172: /* procedures */
173:
174: LINENUM locate_hunk();
175: bool patch_match();
176: bool similar();
177: char *malloc();
178: char *savestr();
179: char *strcpy();
180: char *strcat();
181: char *sprintf(); /* usually */
182: int my_exit();
183: bool rev_in_string();
184: char *fetchname();
185: long atol();
186: long lseek();
187: char *mktemp();
188:
189: /* patch type */
190:
191: bool there_is_another_patch();
192: bool another_hunk();
193: char *pfetch();
194: int pch_line_len();
195: LINENUM pch_first();
196: LINENUM pch_ptrn_lines();
197: LINENUM pch_newfirst();
198: LINENUM pch_repl_lines();
199: LINENUM pch_end();
200: LINENUM pch_context();
201: LINENUM pch_hunk_beg();
202: char pch_char();
203: char *pfetch();
204: char *pgets();
205:
206: /* input file type */
207:
208: char *ifetch();
209:
210: /* apply a context patch to a named file */
211:
212: main(argc,argv)
213: int argc;
214: char **argv;
215: {
216: LINENUM where;
217: int hunk = 0;
218: int failed = 0;
219: int i;
220:
221: setbuf(stderr,serrbuf);
222: for (i = 0; i<MAXFILEC; i++)
223: filearg[i] = Nullch;
224: Mktemp(TMPOUTNAME);
225: Mktemp(TMPINNAME);
226: Mktemp(TMPREJNAME);
227: Mktemp(TMPPATNAME);
228:
229: /* parse switches */
230: Argc = argc;
231: Argv = argv;
232: get_some_switches();
233:
234: /* make sure we clean up /tmp in case of disaster */
235: set_signals();
236:
237: for (
238: open_patch_file(filearg[1]);
239: there_is_another_patch();
240: reinitialize_almost_everything()
241: ) { /* for each patch in patch file */
242:
243: if (outname == Nullch)
244: outname = savestr(filearg[0]);
245:
246: /* initialize the patched file */
247: init_output(TMPOUTNAME);
248:
249: /* for ed script just up and do it and exit */
250: if (diff_type == ED_DIFF) {
251: do_ed_script();
252: continue;
253: }
254:
255: /* initialize reject file */
256: init_reject(TMPREJNAME);
257:
258: /* find out where all the lines are */
259: scan_input(filearg[0]);
260:
261: /* from here on, open no standard i/o files, because malloc */
262: /* might misfire */
263:
264: /* apply each hunk of patch */
265: hunk = 0;
266: failed = 0;
267: while (another_hunk()) {
268: hunk++;
269: where = locate_hunk();
270: if (hunk == 1 && where == Null(LINENUM)) {
271: /* dwim for reversed patch? */
272: pch_swap();
273: reverse = !reverse;
274: where = locate_hunk(); /* try again */
275: if (where == Null(LINENUM)) {
276: pch_swap(); /* no, put it back to normal */
277: reverse = !reverse;
278: }
279: else {
280: say("%seversed (or previously applied) patch detected! %s -R.\n",
281: reverse ? "R" : "Unr",
282: reverse ? "Assuming" : "Ignoring");
283: }
284: }
285: if (where == Null(LINENUM)) {
286: abort_hunk();
287: failed++;
288: if (verbose)
289: say("Hunk #%d failed.\n",hunk);
290: }
291: else {
292: apply_hunk(where);
293: if (verbose)
294: if (last_offset)
295: say("Hunk #%d succeeded (offset %d line%s).\n",
296: hunk,last_offset,last_offset==1?"":"s");
297: else
298: say("Hunk #%d succeeded.\n", hunk);
299: }
300: }
301:
302: assert(hunk);
303:
304: /* finish spewing out the new file */
305: spew_output();
306:
307: /* and put the output where desired */
308: ignore_signals();
309: move_file(TMPOUTNAME,outname);
310: Fclose(rejfp);
311: rejfp = Nullfp;
312: if (failed) {
313: if (!*rejname) {
314: Strcpy(rejname, outname);
315: Strcat(rejname, ".rej");
316: }
317: say("%d out of %d hunks failed--saving rejects to %s\n",
318: failed, hunk, rejname);
319: move_file(TMPREJNAME,rejname);
320: }
321: set_signals();
322: }
323: my_exit(0);
324: }
325:
326: reinitialize_almost_everything()
327: {
328: re_patch();
329: re_input();
330:
331: input_lines = 0;
332: last_frozen_line = 0;
333:
334: filec = 0;
335: if (filearg[0] != Nullch) {
336: free(filearg[0]);
337: filearg[0] = Nullch;
338: }
339:
340: if (outname != Nullch) {
341: free(outname);
342: outname = Nullch;
343: }
344:
345: last_offset = 0;
346:
347: diff_type = 0;
348:
349: if (revision != Nullch) {
350: free(revision);
351: revision = Nullch;
352: }
353:
354: reverse = FALSE;
355:
356: get_some_switches();
357:
358: if (filec >= 2)
359: fatal("You may not change to a different patch file.\n");
360: }
361:
362: get_some_switches()
363: {
364: register char *s;
365:
366: rejname[0] = '\0';
367: if (!Argc)
368: return;
369: for (Argc--,Argv++; Argc; Argc--,Argv++) {
370: s = Argv[0];
371: if (strEQ(s,"+")) {
372: return; /* + will be skipped by for loop */
373: }
374: if (*s != '-' || !s[1]) {
375: if (filec == MAXFILEC)
376: fatal("Too many file arguments.\n");
377: filearg[filec++] = savestr(s);
378: }
379: else {
380: switch (*++s) {
381: case 'b':
382: origext = savestr(Argv[1]);
383: Argc--,Argv++;
384: break;
385: case 'c':
386: diff_type = CONTEXT_DIFF;
387: break;
388: case 'd':
389: if (chdir(Argv[1]) < 0)
390: fatal("Can't cd to %s.\n",Argv[1]);
391: Argc--,Argv++;
392: break;
393: case 'D':
394: do_defines++;
395: Sprintf(if_defined, "#ifdef %s\n", Argv[1]);
396: Sprintf(not_defined, "#ifndef %s\n", Argv[1]);
397: Sprintf(end_defined, "#endif %s\n", Argv[1]);
398: Argc--,Argv++;
399: break;
400: case 'e':
401: diff_type = ED_DIFF;
402: break;
403: case 'l':
404: canonicalize = TRUE;
405: break;
406: case 'n':
407: diff_type = NORMAL_DIFF;
408: break;
409: case 'o':
410: outname = savestr(Argv[1]);
411: Argc--,Argv++;
412: break;
413: case 'p':
414: usepath = TRUE; /* do not strip path names */
415: break;
416: case 'r':
417: Strcpy(rejname,Argv[1]);
418: Argc--,Argv++;
419: break;
420: case 'R':
421: reverse = TRUE;
422: break;
423: case 's':
424: verbose = FALSE;
425: break;
426: #ifdef DEBUGGING
427: case 'x':
428: debug = atoi(s+1);
429: break;
430: #endif
431: default:
432: fatal("Unrecognized switch: %s\n",Argv[0]);
433: }
434: }
435: }
436: }
437:
438: LINENUM
439: locate_hunk()
440: {
441: register LINENUM first_guess = pch_first() + last_offset;
442: register LINENUM offset;
443: LINENUM pat_lines = pch_ptrn_lines();
444: register LINENUM max_pos_offset = input_lines - first_guess
445: - pat_lines + 1;
446: register LINENUM max_neg_offset = first_guess - last_frozen_line - 1
447: - pch_context();
448:
449: if (!pat_lines) /* null range matches always */
450: return first_guess;
451: if (max_neg_offset >= first_guess) /* do not try lines < 0 */
452: max_neg_offset = first_guess - 1;
453: if (first_guess <= input_lines && patch_match(first_guess,(LINENUM)0))
454: return first_guess;
455: for (offset = 1; ; offset++) {
456: bool check_after = (offset <= max_pos_offset);
457: bool check_before = (offset <= max_pos_offset);
458:
459: if (check_after && patch_match(first_guess,offset)) {
460: #ifdef DEBUGGING
461: if (debug & 1)
462: printf("Offset changing from %d to %d\n",last_offset,offset);
463: #endif
464: last_offset = offset;
465: return first_guess+offset;
466: }
467: else if (check_before && patch_match(first_guess,-offset)) {
468: #ifdef DEBUGGING
469: if (debug & 1)
470: printf("Offset changing from %d to %d\n",last_offset,-offset);
471: #endif
472: last_offset = -offset;
473: return first_guess-offset;
474: }
475: else if (!check_before && !check_after)
476: return Null(LINENUM);
477: }
478: }
479:
480: /* we did not find the pattern, dump out the hunk so they can handle it */
481:
482: abort_hunk()
483: {
484: register LINENUM i;
485: register LINENUM pat_end = pch_end();
486: /* add in last_offset to guess the same as the previous successful hunk */
487: int oldfirst = pch_first() + last_offset;
488: int newfirst = pch_newfirst() + last_offset;
489: int oldlast = oldfirst + pch_ptrn_lines() - 1;
490: int newlast = newfirst + pch_repl_lines() - 1;
491:
492: fprintf(rejfp,"***************\n");
493: for (i=0; i<=pat_end; i++) {
494: switch (pch_char(i)) {
495: case '*':
496: fprintf(rejfp,"*** %d,%d\n", oldfirst, oldlast);
497: break;
498: case '=':
499: fprintf(rejfp,"--- %d,%d -----\n", newfirst, newlast);
500: break;
501: case '\n':
502: fprintf(rejfp,"%s", pfetch(i));
503: break;
504: case ' ': case '-': case '+': case '!':
505: fprintf(rejfp,"%c %s", pch_char(i), pfetch(i));
506: break;
507: default:
508: say("Fatal internal error in abort_hunk().\n");
509: abort();
510: }
511: }
512: }
513:
514: /* we found where to apply it (we hope), so do it */
515:
516: apply_hunk(where)
517: LINENUM where;
518: {
519: register LINENUM old = 1;
520: register LINENUM lastline = pch_ptrn_lines();
521: register LINENUM new = lastline+1;
522: register int def_state = 0; /* -1 = ifndef, 1 = ifdef */
523:
524: where--;
525: while (pch_char(new) == '=' || pch_char(new) == '\n')
526: new++;
527:
528: while (old <= lastline) {
529: if (pch_char(old) == '-') {
530: copy_till(where + old - 1);
531: if (do_defines) {
532: if (def_state == 0) {
533: fputs(not_defined, ofp);
534: def_state = -1;
535: } else
536: if (def_state == 1) {
537: fputs(else_defined, ofp);
538: def_state = 2;
539: }
540: fputs(pfetch(old), ofp);
541: }
542: last_frozen_line++;
543: old++;
544: }
545: else if (pch_char(new) == '+') {
546: copy_till(where + old - 1);
547: if (do_defines) {
548: if (def_state == -1) {
549: fputs(else_defined, ofp);
550: def_state = 2;
551: } else
552: if (def_state == 0) {
553: fputs(if_defined, ofp);
554: def_state = 1;
555: }
556: }
557: fputs(pfetch(new),ofp);
558: new++;
559: }
560: else {
561: if (pch_char(new) != pch_char(old)) {
562: say("Out-of-sync patch, lines %d,%d\n",
563: pch_hunk_beg() + old - 1,
564: pch_hunk_beg() + new - 1);
565: #ifdef DEBUGGING
566: printf("oldchar = '%c', newchar = '%c'\n",
567: pch_char(old), pch_char(new));
568: #endif
569: my_exit(1);
570: }
571: if (pch_char(new) == '!') {
572: copy_till(where + old - 1);
573: if (do_defines) {
574: fputs(not_defined,ofp);
575: def_state = -1;
576: }
577: while (pch_char(old) == '!') {
578: if (do_defines) {
579: fputs(pfetch(old),ofp);
580: }
581: last_frozen_line++;
582: old++;
583: }
584: if (do_defines) {
585: fputs(else_defined, ofp);
586: def_state = 2;
587: }
588: while (pch_char(new) == '!') {
589: fputs(pfetch(new),ofp);
590: new++;
591: }
592: if (do_defines) {
593: fputs(end_defined, ofp);
594: def_state = 0;
595: }
596: }
597: else {
598: assert(pch_char(new) == ' ');
599: old++;
600: new++;
601: }
602: }
603: }
604: if (new <= pch_end() && pch_char(new) == '+') {
605: copy_till(where + old - 1);
606: if (do_defines) {
607: if (def_state == 0) {
608: fputs(if_defined, ofp);
609: def_state = 1;
610: } else
611: if (def_state == -1) {
612: fputs(else_defined, ofp);
613: def_state = 2;
614: }
615: }
616: while (new <= pch_end() && pch_char(new) == '+') {
617: fputs(pfetch(new),ofp);
618: new++;
619: }
620: }
621: if (do_defines && def_state) {
622: fputs(end_defined, ofp);
623: }
624: }
625:
626: do_ed_script()
627: {
628: FILE *pipefp, *popen();
629: bool this_line_is_command = FALSE;
630: register char *t;
631: long beginning_of_this_line;
632:
633: Unlink(TMPOUTNAME);
634: copy_file(filearg[0],TMPOUTNAME);
635: if (verbose)
636: Sprintf(buf,"/bin/ed %s",TMPOUTNAME);
637: else
638: Sprintf(buf,"/bin/ed - %s",TMPOUTNAME);
639: pipefp = popen(buf,"w");
640: for (;;) {
641: beginning_of_this_line = ftell(pfp);
642: if (pgets(buf,sizeof buf,pfp) == Nullch) {
643: next_intuit_at(beginning_of_this_line);
644: break;
645: }
646: for (t=buf; isdigit(*t) || *t == ','; t++) ;
647: this_line_is_command = (isdigit(*buf) &&
648: (*t == 'd' || *t == 'c' || *t == 'a') );
649: if (this_line_is_command) {
650: fputs(buf,pipefp);
651: if (*t != 'd') {
652: while (pgets(buf,sizeof buf,pfp) != Nullch) {
653: fputs(buf,pipefp);
654: if (strEQ(buf,".\n"))
655: break;
656: }
657: }
658: }
659: else {
660: next_intuit_at(beginning_of_this_line);
661: break;
662: }
663: }
664: fprintf(pipefp,"w\n");
665: fprintf(pipefp,"q\n");
666: Fflush(pipefp);
667: Pclose(pipefp);
668: ignore_signals();
669: move_file(TMPOUTNAME,outname);
670: set_signals();
671: }
672:
673: init_output(name)
674: char *name;
675: {
676: ofp = fopen(name,"w");
677: if (ofp == Nullfp)
678: fatal("patch: can't create %s.\n",name);
679: }
680:
681: init_reject(name)
682: char *name;
683: {
684: rejfp = fopen(name,"w");
685: if (rejfp == Nullfp)
686: fatal("patch: can't create %s.\n",name);
687: }
688:
689: move_file(from,to)
690: char *from, *to;
691: {
692: char bakname[512];
693: register char *s;
694: int fromfd;
695: register int i;
696:
697: /* to stdout? */
698:
699: if (strEQ(to,"-")) {
700: #ifdef DEBUGGING
701: if (debug & 4)
702: say("Moving %s to stdout.\n",from);
703: #endif
704: fromfd = open(from,0);
705: if (fromfd < 0)
706: fatal("patch: internal error, can't reopen %s\n",from);
707: while ((i=read(fromfd,buf,sizeof buf)) > 0)
708: if (write(1,buf,i) != 1)
709: fatal("patch: write failed\n");
710: Close(fromfd);
711: return;
712: }
713:
714: Strcpy(bakname,to);
715: Strcat(bakname,origext?origext:ORIGEXT);
716: if (stat(to,&filestat) >= 0) { /* output file exists */
717: dev_t to_device = filestat.st_dev;
718: ino_t to_inode = filestat.st_ino;
719: char *simplename = bakname;
720:
721: for (s=bakname; *s; s++) {
722: if (*s == '/')
723: simplename = s+1;
724: }
725: /* find a backup name that is not the same file */
726: while (stat(bakname,&filestat) >= 0 &&
727: to_device == filestat.st_dev && to_inode == filestat.st_ino) {
728: for (s=simplename; *s && !islower(*s); s++) ;
729: if (*s)
730: *s = toupper(*s);
731: else
732: Strcpy(simplename, simplename+1);
733: }
734: while (unlink(bakname) >= 0) ; /* while() is for benefit of Eunice */
735: #ifdef DEBUGGING
736: if (debug & 4)
737: say("Moving %s to %s.\n",to,bakname);
738: #endif
739: if (link(to,bakname) < 0) {
740: say("patch: can't backup %s, output is in %s\n",
741: to,from);
742: return;
743: }
744: while (unlink(to) >= 0) ;
745: }
746: #ifdef DEBUGGING
747: if (debug & 4)
748: say("Moving %s to %s.\n",from,to);
749: #endif
750: if (link(from,to) < 0) { /* different file system? */
751: int tofd;
752:
753: tofd = creat(to,0666);
754: if (tofd < 0) {
755: say("patch: can't create %s, output is in %s.\n",
756: to, from);
757: return;
758: }
759: fromfd = open(from,0);
760: if (fromfd < 0)
761: fatal("patch: internal error, can't reopen %s\n",from);
762: while ((i=read(fromfd,buf,sizeof buf)) > 0)
763: if (write(tofd,buf,i) != i)
764: fatal("patch: write failed\n");
765: Close(fromfd);
766: Close(tofd);
767: }
768: Unlink(from);
769: }
770:
771: copy_file(from,to)
772: char *from, *to;
773: {
774: int tofd;
775: int fromfd;
776: register int i;
777:
778: tofd = creat(to,0666);
779: if (tofd < 0)
780: fatal("patch: can't create %s.\n", to);
781: fromfd = open(from,0);
782: if (fromfd < 0)
783: fatal("patch: internal error, can't reopen %s\n",from);
784: while ((i=read(fromfd,buf,sizeof buf)) > 0)
785: if (write(tofd,buf,i) != i)
786: fatal("patch: write (%s) failed\n", to);
787: Close(fromfd);
788: Close(tofd);
789: }
790:
791: copy_till(lastline)
792: register LINENUM lastline;
793: {
794: if (last_frozen_line > lastline)
795: say("patch: misordered hunks! output will be garbled.\n");
796: while (last_frozen_line < lastline) {
797: dump_line(++last_frozen_line);
798: }
799: }
800:
801: spew_output()
802: {
803: copy_till(input_lines); /* dump remainder of file */
804: Fclose(ofp);
805: ofp = Nullfp;
806: }
807:
808: dump_line(line)
809: LINENUM line;
810: {
811: register char *s;
812:
813: for (s=ifetch(line,0); putc(*s,ofp) != '\n'; s++) ;
814: }
815:
816: /* does the patch pattern match at line base+offset? */
817:
818: bool
819: patch_match(base,offset)
820: LINENUM base;
821: LINENUM offset;
822: {
823: register LINENUM pline;
824: register LINENUM iline;
825: register LINENUM pat_lines = pch_ptrn_lines();
826:
827: for (pline = 1, iline=base+offset; pline <= pat_lines; pline++,iline++) {
828: if (canonicalize) {
829: if (!similar(ifetch(iline,(offset >= 0)),
830: pfetch(pline),
831: pch_line_len(pline) ))
832: return FALSE;
833: }
834: else if (strnNE(ifetch(iline,(offset >= 0)),
835: pfetch(pline),
836: pch_line_len(pline) ))
837: return FALSE;
838: }
839: return TRUE;
840: }
841:
842: /* match two lines with canonicalized white space */
843:
844: bool
845: similar(a,b,len)
846: register char *a, *b;
847: register int len;
848: {
849: while (len) {
850: if (isspace(*b)) { /* whitespace (or \n) to match? */
851: if (!isspace(*a)) /* no corresponding whitespace? */
852: return FALSE;
853: while (len && isspace(*b) && *b != '\n')
854: b++,len--; /* skip pattern whitespace */
855: while (isspace(*a) && *a != '\n')
856: a++; /* skip target whitespace */
857: if (*a == '\n' || *b == '\n')
858: return (*a == *b); /* should end in sync */
859: }
860: else if (*a++ != *b++) /* match non-whitespace chars */
861: return FALSE;
862: else
863: len--; /* probably not necessary */
864: }
865: return TRUE; /* actually, this is not reached */
866: /* since there is always a \n */
867: }
868:
869: /* input file with indexable lines abstract type */
870:
871: bool using_plan_a = TRUE;
872: static long i_size; /* size of the input file */
873: static char *i_womp; /* plan a buffer for entire file */
874: static char **i_ptr; /* pointers to lines in i_womp */
875:
876: static int tifd = -1; /* plan b virtual string array */
877: static char *tibuf[2]; /* plan b buffers */
878: static LINENUM tiline[2] = {-1,-1}; /* 1st line in each buffer */
879: static LINENUM lines_per_buf; /* how many lines per buffer */
880: static int tireclen; /* length of records in tmp file */
881:
882: re_input()
883: {
884: if (using_plan_a) {
885: i_size = 0;
886: /*NOSTRICT*/
887: if (i_ptr != Null(char**))
888: free((char *)i_ptr);
889: if (i_womp != Nullch)
890: free(i_womp);
891: i_womp = Nullch;
892: i_ptr = Null(char **);
893: }
894: else {
895: using_plan_a = TRUE; /* maybe the next one is smaller */
896: Close(tifd);
897: tifd = -1;
898: free(tibuf[0]);
899: free(tibuf[1]);
900: tibuf[0] = tibuf[1] = Nullch;
901: tiline[0] = tiline[1] = -1;
902: tireclen = 0;
903: }
904: }
905:
906: scan_input(filename)
907: char *filename;
908: {
909: bool plan_a();
910:
911: if (!plan_a(filename))
912: plan_b(filename);
913: }
914:
915: /* try keeping everything in memory */
916:
917: bool
918: plan_a(filename)
919: char *filename;
920: {
921: int ifd;
922: register char *s;
923: register LINENUM iline;
924:
925: if (stat(filename,&filestat) < 0) {
926: Sprintf(buf,"RCS/%s%s",filename,RCSSUFFIX);
927: if (stat(buf,&filestat) >= 0 || stat(buf+4,&filestat) >= 0) {
928: Sprintf(buf,CHECKOUT,filename);
929: if (verbose)
930: say("Can't find %s--attempting to check it out from RCS.\n",
931: filename);
932: if (system(buf) || stat(filename,&filestat))
933: fatal("Can't check out %s.\n",filename);
934: }
935: else {
936: Sprintf(buf,"SCCS/%s%s",SCCSPREFIX,filename);
937: if (stat(buf,&filestat) >= 0 || stat(buf+5,&filestat) >= 0) {
938: Sprintf(buf,GET,filename);
939: if (verbose)
940: say("Can't find %s--attempting to get it from SCCS.\n",
941: filename);
942: if (system(buf) || stat(filename,&filestat))
943: fatal("Can't get %s.\n",filename);
944: }
945: else
946: fatal("Can't find %s.\n",filename);
947: }
948: }
949: if ((filestat.st_mode & S_IFMT) & ~S_IFREG)
950: fatal("%s is not a normal file--can't patch.\n",filename);
951: i_size = filestat.st_size;
952: /*NOSTRICT*/
953: i_womp = malloc((MEM)(i_size+2));
954: if (i_womp == Nullch)
955: return FALSE;
956: if ((ifd = open(filename,0)) < 0)
957: fatal("Can't open file %s\n",filename);
958: /*NOSTRICT*/
959: if (read(ifd,i_womp,(int)i_size) != i_size) {
960: Close(ifd);
961: free(i_womp);
962: return FALSE;
963: }
964: Close(ifd);
965: if (i_womp[i_size-1] != '\n')
966: i_womp[i_size++] = '\n';
967: i_womp[i_size] = '\0';
968:
969: /* count the lines in the buffer so we know how many pointers we need */
970:
971: iline = 0;
972: for (s=i_womp; *s; s++) {
973: if (*s == '\n')
974: iline++;
975: }
976: /*NOSTRICT*/
977: i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
978: if (i_ptr == Null(char **)) { /* shucks, it was a near thing */
979: free((char *)i_womp);
980: return FALSE;
981: }
982:
983: /* now scan the buffer and build pointer array */
984:
985: iline = 1;
986: i_ptr[iline] = i_womp;
987: for (s=i_womp; *s; s++) {
988: if (*s == '\n')
989: i_ptr[++iline] = s+1; /* these are NOT null terminated */
990: }
991: input_lines = iline - 1;
992:
993: /* now check for revision, if any */
994:
995: if (revision != Nullch) {
996: if (!rev_in_string(i_womp)) {
997: ask("This file doesn't appear to be the %s version--patch anyway? [n] ",
998: revision);
999: if (*buf != 'y')
1000: fatal("Aborted.\n");
1001: }
1002: else if (verbose)
1003: say("Good. This file appears to be the %s version.\n",
1004: revision);
1005: }
1006: return TRUE; /* plan a will work */
1007: }
1008:
1009: /* keep (virtually) nothing in memory */
1010:
1011: plan_b(filename)
1012: char *filename;
1013: {
1014: FILE *ifp;
1015: register int i = 0;
1016: register int maxlen = 1;
1017: bool found_revision = (revision == Nullch);
1018:
1019: using_plan_a = FALSE;
1020: if ((ifp = fopen(filename,"r")) == Nullfp)
1021: fatal("Can't open file %s\n",filename);
1022: if ((tifd = creat(TMPINNAME,0666)) < 0)
1023: fatal("Can't open file %s\n",TMPINNAME);
1024: while (fgets(buf,sizeof buf, ifp) != Nullch) {
1025: if (revision != Nullch && !found_revision && rev_in_string(buf))
1026: found_revision = TRUE;
1027: if ((i = strlen(buf)) > maxlen)
1028: maxlen = i; /* find longest line */
1029: }
1030: if (revision != Nullch) {
1031: if (!found_revision) {
1032: ask("This file doesn't appear to be the %s version--patch anyway? [n] ",
1033: revision);
1034: if (*buf != 'y')
1035: fatal("Aborted.\n");
1036: }
1037: else if (verbose)
1038: say("Good. This file appears to be the %s version.\n",
1039: revision);
1040: }
1041: Fseek(ifp,0L,0); /* rewind file */
1042: lines_per_buf = BUFFERSIZE / maxlen;
1043: tireclen = maxlen;
1044: tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
1045: tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
1046: if (tibuf[1] == Nullch)
1047: fatal("Can't seem to get enough memory.\n");
1048: for (i=1; ; i++) {
1049: if (! (i % lines_per_buf)) /* new block */
1050: if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE)
1051: fatal("patch: can't write temp file.\n");
1052: if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
1053: == Nullch) {
1054: input_lines = i - 1;
1055: if (i % lines_per_buf)
1056: if (write(tifd,tibuf[0],BUFFERSIZE) < BUFFERSIZE)
1057: fatal("patch: can't write temp file.\n");
1058: break;
1059: }
1060: }
1061: Fclose(ifp);
1062: Close(tifd);
1063: if ((tifd = open(TMPINNAME,0)) < 0) {
1064: fatal("Can't reopen file %s\n",TMPINNAME);
1065: }
1066: }
1067:
1068: /* fetch a line from the input file, \n terminated, not necessarily \0 */
1069: char *
1070: ifetch(line,whichbuf)
1071: register LINENUM line;
1072: int whichbuf; /* ignored when file in memory */
1073: {
1074: if (line < 1 || line > input_lines)
1075: return "";
1076: if (using_plan_a)
1077: return i_ptr[line];
1078: else {
1079: LINENUM offline = line % lines_per_buf;
1080: LINENUM baseline = line - offline;
1081:
1082: if (tiline[0] == baseline)
1083: whichbuf = 0;
1084: else if (tiline[1] == baseline)
1085: whichbuf = 1;
1086: else {
1087: tiline[whichbuf] = baseline;
1088: Lseek(tifd,(long)baseline / lines_per_buf * BUFFERSIZE,0);
1089: if (read(tifd,tibuf[whichbuf],BUFFERSIZE) < 0)
1090: fatal("Error reading tmp file %s.\n",TMPINNAME);
1091: }
1092: return tibuf[whichbuf] + (tireclen*offline);
1093: }
1094: }
1095:
1096: /* patch abstract type */
1097:
1098: static long p_filesize; /* size of the patch file */
1099: static LINENUM p_first; /* 1st line number */
1100: static LINENUM p_newfirst; /* 1st line number of replacement */
1101: static LINENUM p_ptrn_lines; /* # lines in pattern */
1102: static LINENUM p_repl_lines; /* # lines in replacement text */
1103: static LINENUM p_end = -1; /* last line in hunk */
1104: static LINENUM p_max; /* max allowed value of p_end */
1105: static LINENUM p_context = 3; /* # of context lines */
1106: static LINENUM p_input_line = 0; /* current line # from patch file */
1107: static char *p_line[MAXHUNKSIZE]; /* the text of the hunk */
1108: static char p_char[MAXHUNKSIZE]; /* +, -, and ! */
1109: static int p_len[MAXHUNKSIZE]; /* length of each line */
1110: static int p_indent; /* indent to patch */
1111: static long p_base; /* where to intuit this time */
1112: static long p_start; /* where intuit found a patch */
1113:
1114: re_patch()
1115: {
1116: p_first = (LINENUM)0;
1117: p_newfirst = (LINENUM)0;
1118: p_ptrn_lines = (LINENUM)0;
1119: p_repl_lines = (LINENUM)0;
1120: p_end = (LINENUM)-1;
1121: p_max = (LINENUM)0;
1122: p_indent = 0;
1123: }
1124:
1125: open_patch_file(filename)
1126: char *filename;
1127: {
1128: if (filename == Nullch || !*filename || strEQ(filename,"-")) {
1129: pfp = fopen(TMPPATNAME,"w");
1130: if (pfp == Nullfp)
1131: fatal("patch: can't create %s.\n",TMPPATNAME);
1132: while (fgets(buf,sizeof buf,stdin) != NULL)
1133: fputs(buf,pfp);
1134: Fclose(pfp);
1135: filename = TMPPATNAME;
1136: }
1137: pfp = fopen(filename,"r");
1138: if (pfp == Nullfp)
1139: fatal("patch file %s not found\n",filename);
1140: Fstat(fileno(pfp), &filestat);
1141: p_filesize = filestat.st_size;
1142: next_intuit_at(0L); /* start at the beginning */
1143: }
1144:
1145: bool
1146: there_is_another_patch()
1147: {
1148: bool no_input_file = (filearg[0] == Nullch);
1149:
1150: if (p_base != 0L && p_base >= p_filesize) {
1151: if (verbose)
1152: say("done\n");
1153: return FALSE;
1154: }
1155: if (verbose)
1156: say("Hmm...");
1157: diff_type = intuit_diff_type();
1158: if (!diff_type) {
1159: if (p_base != 0L) {
1160: if (verbose)
1161: say(" Ignoring the trailing garbage.\ndone\n");
1162: }
1163: else
1164: say(" I can't seem to find a patch in there anywhere.\n");
1165: return FALSE;
1166: }
1167: if (verbose)
1168: say(" %sooks like %s to me...\n",
1169: (p_base == 0L ? "L" : "The next patch l"),
1170: diff_type == CONTEXT_DIFF ? "a context diff" :
1171: diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
1172: diff_type == NORMAL_DIFF ? "a normal diff" :
1173: "an ed script" );
1174: if (p_indent && verbose)
1175: say("(Patch is indented %d space%s.)\n",p_indent,p_indent==1?"":"s");
1176: skip_to(p_start);
1177: if (no_input_file) {
1178: if (filearg[0] == Nullch) {
1179: ask("File to patch: ");
1180: filearg[0] = fetchname(buf);
1181: }
1182: else if (verbose) {
1183: say("Patching file %s...\n",filearg[0]);
1184: }
1185: }
1186: return TRUE;
1187: }
1188:
1189: intuit_diff_type()
1190: {
1191: long this_line = 0;
1192: long previous_line;
1193: long first_command_line = -1;
1194: bool last_line_was_command = FALSE;
1195: bool this_line_is_command = FALSE;
1196: bool last_line_was_stars = FALSE;
1197: bool this_line_is_stars = FALSE;
1198: register int indent;
1199: register char *s, *t;
1200: char *oldname = Nullch;
1201: char *newname = Nullch;
1202: bool no_filearg = (filearg[0] == Nullch);
1203:
1204: Fseek(pfp,p_base,0);
1205: for (;;) {
1206: previous_line = this_line;
1207: last_line_was_command = this_line_is_command;
1208: last_line_was_stars = this_line_is_stars;
1209: this_line = ftell(pfp);
1210: indent = 0;
1211: if (fgets(buf,sizeof buf,pfp) == Nullch) {
1212: if (first_command_line >= 0L) {
1213: /* nothing but deletes!? */
1214: p_start = first_command_line;
1215: return ED_DIFF;
1216: }
1217: else {
1218: p_start = this_line;
1219: return 0;
1220: }
1221: }
1222: for (s = buf; *s == ' ' || *s == '\t'; s++) {
1223: if (*s == '\t')
1224: indent += 8 - (indent % 8);
1225: else
1226: indent++;
1227: }
1228: for (t=s; isdigit(*t) || *t == ','; t++) ;
1229: this_line_is_command = (isdigit(*s) &&
1230: (*t == 'd' || *t == 'c' || *t == 'a') );
1231: if (first_command_line < 0L && this_line_is_command) {
1232: first_command_line = this_line;
1233: p_indent = indent; /* assume this for now */
1234: }
1235: if (strnEQ(s,"*** ",4))
1236: oldname = fetchname(s+4);
1237: else if (strnEQ(s,"--- ",4)) {
1238: newname = fetchname(s+4);
1239: if (no_filearg) {
1240: if (oldname && newname) {
1241: if (strlen(oldname) < strlen(newname))
1242: filearg[0] = oldname;
1243: else
1244: filearg[0] = newname;
1245: }
1246: else if (oldname)
1247: filearg[0] = oldname;
1248: else if (newname)
1249: filearg[0] = newname;
1250: }
1251: }
1252: else if (strnEQ(s,"Index:",6)) {
1253: if (no_filearg)
1254: filearg[0] = fetchname(s+6);
1255: /* this filearg might get limboed */
1256: }
1257: else if (strnEQ(s,"Prereq:",7)) {
1258: for (t=s+7; isspace(*t); t++) ;
1259: revision = savestr(t);
1260: for (t=revision; *t && !isspace(*t); t++) ;
1261: *t = '\0';
1262: if (!*revision) {
1263: free(revision);
1264: revision = Nullch;
1265: }
1266: }
1267: if ((!diff_type || diff_type == ED_DIFF) &&
1268: first_command_line >= 0L &&
1269: strEQ(s,".\n") ) {
1270: p_indent = indent;
1271: p_start = first_command_line;
1272: return ED_DIFF;
1273: }
1274: this_line_is_stars = strnEQ(s,"********",8);
1275: if ((!diff_type || diff_type == CONTEXT_DIFF) && last_line_was_stars &&
1276: strnEQ(s,"*** ",4)) {
1277: /* if this is a new context diff the character just before */
1278: /* the newline is a '*'. */
1279: while (*s != '\n')
1280: s++;
1281: p_indent = indent;
1282: p_start = previous_line;
1283: return (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
1284: }
1285: if ((!diff_type || diff_type == NORMAL_DIFF) &&
1286: last_line_was_command &&
1287: (strnEQ(s,"< ",2) || strnEQ(s,"> ",2)) ) {
1288: p_start = previous_line;
1289: p_indent = indent;
1290: return NORMAL_DIFF;
1291: }
1292: }
1293: }
1294:
1295: char *
1296: fetchname(at)
1297: char *at;
1298: {
1299: char *s = savestr(at);
1300: char *name;
1301: register char *t;
1302: char tmpbuf[200];
1303:
1304: for (t=s; isspace(*t); t++) ;
1305: name = t;
1306: for (; *t && !isspace(*t); t++)
1307: if (!usepath)
1308: if (*t == '/')
1309: name = t+1;
1310: *t = '\0';
1311: name = savestr(name);
1312: Sprintf(tmpbuf,"RCS/%s",name);
1313: free(s);
1314: if (stat(name,&filestat) < 0) {
1315: Strcat(tmpbuf,RCSSUFFIX);
1316: if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+4,&filestat) < 0) {
1317: Sprintf(tmpbuf,"SCCS/%s%s",SCCSPREFIX,name);
1318: if (stat(tmpbuf,&filestat) < 0 && stat(tmpbuf+5,&filestat) < 0) {
1319: free(name);
1320: name = Nullch;
1321: }
1322: }
1323: }
1324: return name;
1325: }
1326:
1327: next_intuit_at(file_pos)
1328: long file_pos;
1329: {
1330: p_base = file_pos;
1331: }
1332:
1333: skip_to(file_pos)
1334: long file_pos;
1335: {
1336: char *ret;
1337:
1338: assert(p_base <= file_pos);
1339: if (verbose && p_base < file_pos) {
1340: Fseek(pfp,p_base,0);
1341: say("The text leading up to this was:\n--------------------------\n");
1342: while (ftell(pfp) < file_pos) {
1343: ret = fgets(buf,sizeof buf,pfp);
1344: assert(ret != Nullch);
1345: say("|%s",buf);
1346: }
1347: say("--------------------------\n");
1348: }
1349: else
1350: Fseek(pfp,file_pos,0);
1351: }
1352:
1353: bool
1354: another_hunk()
1355: {
1356: register char *s;
1357: char *ret;
1358: register int context = 0;
1359:
1360: while (p_end >= 0) {
1361: free(p_line[p_end--]);
1362: }
1363: assert(p_end == -1);
1364:
1365: p_max = MAXHUNKSIZE; /* gets reduced when --- found */
1366: if (diff_type == CONTEXT_DIFF) {
1367: long line_beginning = ftell(pfp);
1368: LINENUM repl_beginning = 0;
1369:
1370: ret = pgets(buf,sizeof buf, pfp);
1371: if (ret == Nullch || strnNE(buf,"********",8)) {
1372: next_intuit_at(line_beginning);
1373: return FALSE;
1374: }
1375: p_context = 100;
1376: while (p_end < p_max) {
1377: ret = pgets(buf,sizeof buf, pfp);
1378: if (ret == Nullch) {
1379: if (p_max - p_end < 4)
1380: Strcpy(buf," \n"); /* assume blank lines got chopped */
1381: else
1382: fatal("Unexpected end of file in patch.\n");
1383: }
1384: p_input_line++;
1385: if (strnEQ(buf,"********",8))
1386: fatal("Unexpected end of hunk at line %d.\n",
1387: p_input_line);
1388: p_char[++p_end] = *buf;
1389: switch (*buf) {
1390: case '*':
1391: if (p_end != 0)
1392: fatal("Unexpected *** at line %d: %s", p_input_line, buf);
1393: context = 0;
1394: p_line[p_end] = savestr(buf);
1395: for (s=buf; *s && !isdigit(*s); s++) ;
1396: p_first = (LINENUM) atol(s);
1397: while (isdigit(*s)) s++;
1398: for (; *s && !isdigit(*s); s++) ;
1399: p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
1400: break;
1401: case '-':
1402: if (buf[1] == '-') {
1403: if (p_end != p_ptrn_lines + 1 &&
1404: p_end != p_ptrn_lines + 2)
1405: fatal("Unexpected --- at line %d: %s",
1406: p_input_line,buf);
1407: repl_beginning = p_end;
1408: context = 0;
1409: p_line[p_end] = savestr(buf);
1410: p_char[p_end] = '=';
1411: for (s=buf; *s && !isdigit(*s); s++) ;
1412: p_newfirst = (LINENUM) atol(s);
1413: while (isdigit(*s)) s++;
1414: for (; *s && !isdigit(*s); s++) ;
1415: p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end;
1416: break;
1417: }
1418: /* FALL THROUGH */
1419: case '+': case '!':
1420: if (context > 0) {
1421: if (context < p_context)
1422: p_context = context;
1423: context = -100;
1424: }
1425: p_line[p_end] = savestr(buf+2);
1426: break;
1427: case '\t': case '\n': /* assume the 2 spaces got eaten */
1428: p_line[p_end] = savestr(buf);
1429: if (p_end != p_ptrn_lines + 1) {
1430: context++;
1431: p_char[p_end] = ' ';
1432: }
1433: break;
1434: case ' ':
1435: context++;
1436: p_line[p_end] = savestr(buf+2);
1437: break;
1438: default:
1439: fatal("Malformed patch at line %d: %s",p_input_line,buf);
1440: }
1441: p_len[p_end] = 0;
1442: if (p_line[p_end] != 0)
1443: p_len[p_end] = strlen(p_line[p_end]);
1444: /* for strncmp() so we do not have */
1445: /* to assume null termination */
1446: }
1447: if (p_end >=0 && !p_ptrn_lines)
1448: fatal("No --- found in patch at line %d\n", pch_hunk_beg());
1449: p_repl_lines = p_end - repl_beginning;
1450: }
1451: else if (diff_type == NEW_CONTEXT_DIFF) {
1452: long line_beginning = ftell(pfp);
1453: LINENUM repl_beginning = 0;
1454: LINENUM fillcnt = 0;
1455: LINENUM fillsrc;
1456: LINENUM filldst;
1457:
1458: ret = pgets(buf,sizeof buf, pfp);
1459: if (ret == Nullch || strnNE(buf,"********",8)) {
1460: next_intuit_at(line_beginning);
1461: return FALSE;
1462: }
1463: p_context = 0;
1464: while (p_end < p_max) {
1465: line_beginning = ftell(pfp);
1466: ret = pgets(buf,sizeof buf, pfp);
1467: if (ret == Nullch) {
1468: if (p_max - p_end < 4)
1469: Strcpy(buf," \n"); /* assume blank lines got chopped */
1470: else
1471: fatal("Unexpected end of file in patch.\n");
1472: }
1473: p_input_line++;
1474: p_char[++p_end] = *buf;
1475: switch (*buf) {
1476: case '*':
1477: if (strnEQ(buf,"********",8)) {
1478: if (p_end != repl_beginning + 1)
1479: fatal("Unexpected end of hunk at line %d.\n",
1480: p_input_line);
1481: /* redundant 'new' context lines were omitted - set up */
1482: /* to fill them in from the the old file's context */
1483: fillsrc = 1;
1484: filldst = p_end;
1485: fillcnt = p_max - repl_beginning;
1486: p_end = p_max;
1487: Fseek(pfp, line_beginning, 0); /* backup the diff input */
1488: break;
1489: }
1490: if (p_end != 0)
1491: fatal("Unexpected *** at line %d: %s", p_input_line, buf);
1492: context = 0;
1493: p_line[p_end] = savestr(buf);
1494: for (s=buf; *s && !isdigit(*s); s++) ;
1495: p_first = (LINENUM) atol(s);
1496: while (isdigit(*s)) s++;
1497: for (; *s && !isdigit(*s); s++) ;
1498: p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1;
1499: break;
1500: case '-':
1501: if (buf[1] == '-') {
1502: if (p_end != p_ptrn_lines + 1) {
1503: if (p_end == 1) {
1504: /* `old' lines were omitted - set up to fill them */
1505: /* in from 'new' context lines. */
1506: p_end = p_ptrn_lines + 1;
1507: fillsrc = p_end + 1;
1508: filldst = 1;
1509: fillcnt = p_ptrn_lines;
1510: } else
1511: fatal("Unexpected --- at line %d: %s",
1512: p_input_line,buf);
1513: }
1514: repl_beginning = p_end;
1515: p_line[p_end] = savestr(buf);
1516: p_char[p_end] = '=';
1517: for (s=buf; *s && !isdigit(*s); s++) ;
1518: p_newfirst = (LINENUM) atol(s);
1519: while (isdigit(*s)) s++;
1520: for (; *s && !isdigit(*s); s++) ;
1521: p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end;
1522: break;
1523: }
1524: /* FALL THROUGH */
1525: case '+': case '!':
1526: if (context > 0 && p_context == 0) {
1527: p_context = context;
1528: }
1529: p_line[p_end] = savestr(buf+2);
1530: break;
1531: case '\t': case '\n': /* assume the 2 spaces got eaten */
1532: p_line[p_end] = savestr(buf);
1533: if (p_end != p_ptrn_lines + 1) {
1534: context++;
1535: p_char[p_end] = ' ';
1536: }
1537: break;
1538: case ' ':
1539: context++;
1540: p_line[p_end] = savestr(buf+2);
1541: break;
1542: default:
1543: fatal("Malformed patch at line %d: %s",p_input_line,buf);
1544: }
1545: p_len[p_end] = 0;
1546: if (p_line[p_end] != 0)
1547: p_len[p_end] = strlen(p_line[p_end]);
1548: /* for strncmp() so we do not have */
1549: /* to assume null termination */
1550: }
1551: if (p_end >=0 && !p_ptrn_lines)
1552: fatal("No --- found in patch at line %d\n", pch_hunk_beg());
1553:
1554: /* if there were omitted context lines, fill them in */
1555: if (fillcnt) {
1556: while (fillcnt-- > 0) {
1557: while (p_char[fillsrc] != ' ')
1558: fillsrc++;
1559: p_line[filldst] = p_line[fillsrc];
1560: p_char[filldst] = p_char[fillsrc];
1561: p_len[filldst] = p_len[fillsrc];
1562: fillsrc++; filldst++;
1563: }
1564: assert(fillsrc==p_end+1 || fillsrc==repl_beginning);
1565: assert(filldst==p_end+1 || filldst==repl_beginning);
1566: }
1567: p_repl_lines = p_end - repl_beginning;
1568: }
1569: else { /* normal diff--fake it up */
1570: char hunk_type;
1571: register int i;
1572: LINENUM min, max;
1573: long line_beginning = ftell(pfp);
1574:
1575: p_context = 0;
1576: ret = pgets(buf,sizeof buf, pfp);
1577: p_input_line++;
1578: if (ret == Nullch || !isdigit(*buf)) {
1579: next_intuit_at(line_beginning);
1580: return FALSE;
1581: }
1582: p_first = (LINENUM)atol(buf);
1583: for (s=buf; isdigit(*s); s++) ;
1584: if (*s == ',') {
1585: p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1;
1586: while (isdigit(*s)) s++;
1587: }
1588: else
1589: p_ptrn_lines = (*s != 'a');
1590: hunk_type = *s;
1591: if (hunk_type == 'a')
1592: p_first++; /* do append rather than insert */
1593: min = (LINENUM)atol(++s);
1594: for (; isdigit(*s); s++) ;
1595: if (*s == ',')
1596: max = (LINENUM)atol(++s);
1597: else
1598: max = min;
1599: if (hunk_type == 'd')
1600: min++;
1601: p_end = p_ptrn_lines + 1 + max - min + 1;
1602: p_newfirst = min;
1603: p_repl_lines = max - min + 1;
1604: Sprintf(buf,"*** %d,%d\n", p_first, p_first + p_ptrn_lines - 1);
1605: p_line[0] = savestr(buf);
1606: p_char[0] = '*';
1607: for (i=1; i<=p_ptrn_lines; i++) {
1608: ret = pgets(buf,sizeof buf, pfp);
1609: p_input_line++;
1610: if (ret == Nullch)
1611: fatal("Unexpected end of file in patch at line %d.\n",
1612: p_input_line);
1613: if (*buf != '<')
1614: fatal("< expected at line %d of patch.\n", p_input_line);
1615: p_line[i] = savestr(buf+2);
1616: p_len[i] = 0;
1617: if (p_line[i] != 0)
1618: p_len[i] = strlen(p_line[i]);
1619: p_char[i] = '-';
1620: }
1621: if (hunk_type == 'c') {
1622: ret = pgets(buf,sizeof buf, pfp);
1623: p_input_line++;
1624: if (ret == Nullch)
1625: fatal("Unexpected end of file in patch at line %d.\n",
1626: p_input_line);
1627: if (*buf != '-')
1628: fatal("--- expected at line %d of patch.\n", p_input_line);
1629: }
1630: Sprintf(buf,"--- %d,%d\n",min,max);
1631: p_line[i] = savestr(buf);
1632: p_char[i] = '=';
1633: for (i++; i<=p_end; i++) {
1634: ret = pgets(buf,sizeof buf, pfp);
1635: p_input_line++;
1636: if (ret == Nullch)
1637: fatal("Unexpected end of file in patch at line %d.\n",
1638: p_input_line);
1639: if (*buf != '>')
1640: fatal("> expected at line %d of patch.\n", p_input_line);
1641: p_line[i] = savestr(buf+2);
1642: p_len[i] = 0;
1643: if (p_line[i] != 0)
1644: p_len[i] = strlen(p_line[i]);
1645: p_char[i] = '+';
1646: }
1647: }
1648: if (reverse) /* backwards patch? */
1649: pch_swap();
1650: #ifdef DEBUGGING
1651: if (debug & 2) {
1652: int i;
1653: char special;
1654:
1655: for (i=0; i <= p_end; i++) {
1656: if (i == p_ptrn_lines)
1657: special = '^';
1658: else
1659: special = ' ';
1660: printf("%3d %c %c %s",i,p_char[i],special,p_line[i]);
1661: }
1662: }
1663: #endif
1664: return TRUE;
1665: }
1666:
1667: char *
1668: pgets(bf,sz,fp)
1669: char *bf;
1670: int sz;
1671: FILE *fp;
1672: {
1673: char *ret = fgets(bf,sz,fp);
1674: register char *s;
1675: register int indent = 0;
1676:
1677: if (p_indent && ret != Nullch) {
1678: for (s=buf; indent < p_indent && (*s == ' ' || *s == '\t'); s++) {
1679: if (*s == '\t')
1680: indent += 8 - (indent % 7);
1681: else
1682: indent++;
1683: }
1684: if (buf != s)
1685: Strcpy(buf,s);
1686: }
1687: return ret;
1688: }
1689:
1690: pch_swap()
1691: {
1692: char *tp_line[MAXHUNKSIZE]; /* the text of the hunk */
1693: char tp_char[MAXHUNKSIZE]; /* +, -, and ! */
1694: int tp_len[MAXHUNKSIZE]; /* length of each line */
1695: register LINENUM i, n;
1696: bool blankline = FALSE;
1697: register char *s;
1698:
1699: i = p_first;
1700: p_first = p_newfirst;
1701: p_newfirst = i;
1702:
1703: /* make a scratch copy */
1704:
1705: for (i=0; i<=p_end; i++) {
1706: tp_line[i] = p_line[i];
1707: tp_char[i] = p_char[i];
1708: tp_len[i] = p_len[i];
1709: }
1710:
1711: /* now turn the new into the old */
1712:
1713: i = p_ptrn_lines + 1;
1714: if (tp_char[i] == '\n') { /* account for possible blank line */
1715: blankline = TRUE;
1716: i++;
1717: }
1718: for (n=0; i <= p_end; i++,n++) {
1719: p_line[n] = tp_line[i];
1720: p_char[n] = tp_char[i];
1721: if (p_char[n] == '+')
1722: p_char[n] = '-';
1723: p_len[n] = tp_len[i];
1724: }
1725: if (blankline) {
1726: i = p_ptrn_lines + 1;
1727: p_line[n] = tp_line[i];
1728: p_char[n] = tp_char[i];
1729: p_len[n] = tp_len[i];
1730: n++;
1731: }
1732: assert(p_char[0] == '=');
1733: p_char[0] = '*';
1734: for (s=p_line[0]; *s; s++)
1735: if (*s == '-')
1736: *s = '*';
1737:
1738: /* now turn the old into the new */
1739:
1740: assert(tp_char[0] == '*');
1741: tp_char[0] = '=';
1742: for (s=tp_line[0]; *s; s++)
1743: if (*s == '*')
1744: *s = '-';
1745: for (i=0; n <= p_end; i++,n++) {
1746: p_line[n] = tp_line[i];
1747: p_char[n] = tp_char[i];
1748: if (p_char[n] == '-')
1749: p_char[n] = '+';
1750: p_len[n] = tp_len[i];
1751: }
1752: assert(i == p_ptrn_lines + 1);
1753: i = p_ptrn_lines;
1754: p_ptrn_lines = p_repl_lines;
1755: p_repl_lines = i;
1756: }
1757:
1758: LINENUM
1759: pch_first()
1760: {
1761: return p_first;
1762: }
1763:
1764: LINENUM
1765: pch_ptrn_lines()
1766: {
1767: return p_ptrn_lines;
1768: }
1769:
1770: LINENUM
1771: pch_newfirst()
1772: {
1773: return p_newfirst;
1774: }
1775:
1776: LINENUM
1777: pch_repl_lines()
1778: {
1779: return p_repl_lines;
1780: }
1781:
1782: LINENUM
1783: pch_end()
1784: {
1785: return p_end;
1786: }
1787:
1788: LINENUM
1789: pch_context()
1790: {
1791: return p_context;
1792: }
1793:
1794: pch_line_len(line)
1795: LINENUM line;
1796: {
1797: return p_len[line];
1798: }
1799:
1800: char
1801: pch_char(line)
1802: LINENUM line;
1803: {
1804: return p_char[line];
1805: }
1806:
1807: char *
1808: pfetch(line)
1809: LINENUM line;
1810: {
1811: return p_line[line];
1812: }
1813:
1814: LINENUM
1815: pch_hunk_beg()
1816: {
1817: return p_input_line - p_end - 1;
1818: }
1819:
1820: char *
1821: savestr(s)
1822: register char *s;
1823: {
1824: register char *rv,
1825: *t;
1826:
1827: t = s;
1828: while (*t++);
1829: rv = malloc((MEM) (t - s));
1830: if (rv == NULL)
1831: fatal ("patch: out of memory (savestr)\n");
1832: t = rv;
1833: while (*t++ = *s++);
1834: return rv;
1835: }
1836:
1837: my_exit(status)
1838: int status;
1839: {
1840: Unlink(TMPINNAME);
1841: Unlink(TMPOUTNAME);
1842: Unlink(TMPREJNAME);
1843: Unlink(TMPPATNAME);
1844: exit(status);
1845: }
1846:
1847: #ifdef lint
1848:
1849: /*VARARGS ARGSUSED*/
1850: say(pat) char *pat; { ; }
1851: /*VARARGS ARGSUSED*/
1852: fatal(pat) char *pat; { ; }
1853: /*VARARGS ARGSUSED*/
1854: ask(pat) char *pat; { ; }
1855:
1856: #else lint
1857:
1858: say(pat,arg1,arg2,arg3)
1859: char *pat;
1860: int arg1,arg2,arg3;
1861: {
1862: fprintf(stderr,pat,arg1,arg2,arg3);
1863: Fflush(stderr);
1864: }
1865:
1866: fatal(pat,arg1,arg2,arg3)
1867: char *pat;
1868: int arg1,arg2,arg3;
1869: {
1870: say(pat,arg1,arg2,arg3);
1871: my_exit(1);
1872: }
1873:
1874: ask(pat,arg1,arg2,arg3)
1875: char *pat;
1876: int arg1,arg2,arg3;
1877: {
1878: int ttyfd = open("/dev/tty",2);
1879: int r;
1880:
1881: say(pat,arg1,arg2,arg3);
1882: if (ttyfd >= 0) {
1883: r = read(ttyfd, buf, sizeof buf);
1884: Close(ttyfd);
1885: }
1886: else
1887: r = read(2, buf, sizeof buf);
1888: if (r <= 0)
1889: buf[0] = 0;
1890: }
1891: #endif lint
1892:
1893: bool
1894: rev_in_string(string)
1895: char *string;
1896: {
1897: register char *s;
1898: register int patlen;
1899:
1900: if (revision == Nullch)
1901: return TRUE;
1902: patlen = strlen(revision);
1903: for (s = string; *s; s++) {
1904: if (isspace(*s) && strnEQ(s+1,revision,patlen) &&
1905: isspace(s[patlen+1] )) {
1906: return TRUE;
1907: }
1908: }
1909: return FALSE;
1910: }
1911:
1912: set_signals()
1913: {
1914: /*NOSTRICT*/
1915: if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
1916: Signal(SIGHUP, my_exit);
1917: /*NOSTRICT*/
1918: if (signal(SIGINT, SIG_IGN) != SIG_IGN)
1919: Signal(SIGINT, my_exit);
1920: }
1921:
1922: ignore_signals()
1923: {
1924: /*NOSTRICT*/
1925: Signal(SIGHUP, SIG_IGN);
1926: /*NOSTRICT*/
1927: Signal(SIGINT, SIG_IGN);
1928: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.