source: trunk/minix/commands/patch/pch.c@ 10

Last change on this file since 10 was 9, checked in by Mattia Monga, 14 years ago

Minix 3.1.2a

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