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