PageRenderTime 131ms CodeModel.GetById 49ms RepoModel.GetById 9ms app.codeStats 1ms

/gnu/usr.bin/patch/pch.c

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