Commit | Line | Data |
---|---|---|
9c13eddc | 1 | #ifndef lint |
95f51977 | 2 | static char sccsid[] = "@(#)patch.c 5.3 (Berkeley) 8/16/85"; |
9c13eddc KM |
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 $ | |
56b0c556 KM |
15 | * 85/08/15 van%ucbmonet@berkeley |
16 | * Changes for 4.3bsd diff -c. | |
17 | * | |
9c13eddc KM |
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 | ||
95f51977 | 90 | #define MAXHUNKSIZE 500 |
9c13eddc KM |
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 | |
56b0c556 | 161 | #define NEW_CONTEXT_DIFF 4 |
9c13eddc KM |
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 | } | |
95f51977 | 285 | if (where == Null(LINENUM)) { |
9c13eddc KM |
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 '*': | |
95f51977 | 496 | fprintf(rejfp,"*** %d,%d\n", oldfirst, oldlast); |
9c13eddc KM |
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" : | |
56b0c556 | 1171 | diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" : |
9c13eddc KM |
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) { | |
95f51977 | 1178 | if (filearg[0] == Nullch) { |
9c13eddc KM |
1179 | ask("File to patch: "); |
1180 | filearg[0] = fetchname(buf); | |
1181 | } | |
95f51977 | 1182 | else if (verbose) { |
9c13eddc KM |
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; | |
56b0c556 KM |
1196 | bool last_line_was_stars = FALSE; |
1197 | bool this_line_is_stars = FALSE; | |
9c13eddc KM |
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; | |
56b0c556 | 1208 | last_line_was_stars = this_line_is_stars; |
9c13eddc KM |
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 | } | |
56b0c556 KM |
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++; | |
9c13eddc | 1281 | p_indent = indent; |
56b0c556 KM |
1282 | p_start = previous_line; |
1283 | return (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); | |
9c13eddc KM |
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; | |
56b0c556 | 1358 | register int context = 0; |
9c13eddc KM |
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++) ; | |
95f51977 | 1399 | p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; |
9c13eddc KM |
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++) ; | |
95f51977 | 1415 | p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end; |
9c13eddc KM |
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 | } | |
95f51977 C |
1441 | p_len[p_end] = 0; |
1442 | if (p_line[p_end] != 0) | |
6174924f | 1443 | p_len[p_end] = strlen(p_line[p_end]); |
95f51977 C |
1444 | /* for strncmp() so we do not have */ |
1445 | /* to assume null termination */ | |
9c13eddc KM |
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 | } | |
56b0c556 KM |
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) { | |
95f51977 | 1465 | line_beginning = ftell(pfp); |
56b0c556 KM |
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 */ | |
756fee39 | 1470 | else |
56b0c556 KM |
1471 | fatal("Unexpected end of file in patch.\n"); |
1472 | } | |
1473 | p_input_line++; | |
1474 | p_char[++p_end] = *buf; | |
1475 | switch (*buf) { | |
95f51977 C |
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 | } | |
56b0c556 KM |
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++) ; | |
95f51977 | 1498 | p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; |
56b0c556 KM |
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++) ; | |
95f51977 | 1521 | p_max = ((LINENUM)atol(s)) - p_newfirst + 1 + p_end; |
56b0c556 KM |
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); | |
95f51977 C |
1533 | if (p_end != p_ptrn_lines + 1) { |
1534 | context++; | |
1535 | p_char[p_end] = ' '; | |
1536 | } | |
56b0c556 KM |
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 | } | |
95f51977 C |
1545 | p_len[p_end] = 0; |
1546 | if (p_line[p_end] != 0) | |
6174924f | 1547 | p_len[p_end] = strlen(p_line[p_end]); |
95f51977 C |
1548 | /* for strncmp() so we do not have */ |
1549 | /* to assume null termination */ | |
56b0c556 KM |
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++; | |
95f51977 | 1559 | p_line[filldst] = p_line[fillsrc]; |
56b0c556 KM |
1560 | p_char[filldst] = p_char[fillsrc]; |
1561 | p_len[filldst] = p_len[fillsrc]; | |
1562 | fillsrc++; filldst++; | |
1563 | } | |
95f51977 | 1564 | assert(fillsrc==p_end+1 || fillsrc==repl_beginning); |
756fee39 | 1565 | assert(filldst==p_end+1 || filldst==repl_beginning); |
56b0c556 KM |
1566 | } |
1567 | p_repl_lines = p_end - repl_beginning; | |
1568 | } | |
9c13eddc KM |
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); | |
95f51977 C |
1616 | p_len[i] = 0; |
1617 | if (p_line[i] != 0) | |
6174924f | 1618 | p_len[i] = strlen(p_line[i]); |
9c13eddc KM |
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); | |
95f51977 C |
1642 | p_len[i] = 0; |
1643 | if (p_line[i] != 0) | |
6174924f | 1644 | p_len[i] = strlen(p_line[i]); |
9c13eddc KM |
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 | } |