diff options
Diffstat (limited to 'pch.c')
-rw-r--r-- | pch.c | 766 |
1 files changed, 454 insertions, 312 deletions
@@ -1,31 +1,33 @@ /* reading patches */ -/* $Id: pch.c,v 1.26 1997/07/21 17:59:46 eggert Exp $ */ +/* $Id: pch.c,v 1.44 2003/05/20 14:03:17 eggert Exp $ */ -/* -Copyright 1986, 1987, 1988 Larry Wall -Copyright 1990, 1991, 1992, 1993, 1997 Free Software Foundation, Inc. +/* Copyright (C) 1986, 1987, 1988 Larry Wall -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. + Copyright (C) 1990, 1991, 1992, 1993, 1997, 1998, 1999, 2000, 2001, + 2002, 2003 Free Software Foundation, Inc. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. -You should have received a copy of the GNU General Public License -along with this program; see the file COPYING. -If not, write to the Free Software Foundation, -59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #define XTERN extern #include <common.h> #include <backupfile.h> +#include <dirname.h> #include <inp.h> +#include <quotearg.h> #include <util.h> #undef XTERN #define XTERN @@ -36,8 +38,10 @@ If not, write to the Free Software Foundation, /* Patch (diff listing) abstract type. */ static FILE *pfp; /* patch file pointer */ -static int p_says_nonexistent[2]; /* [0] for old file, [1] for new; - value is 0 for nonempty, 1 for empty, 2 for nonexistent */ +static int p_says_nonexistent[2]; /* [0] for old file, [1] for new: + 0 for existent and nonempty, + 1 for existent and probably (but not necessarily) empty, + 2 for nonexistent */ static int p_rfc934_nesting; /* RFC 934 nesting level */ static time_t p_timestamp[2]; /* timestamps in patch headers */ static off_t p_filesize; /* size of the patch file */ @@ -55,6 +59,8 @@ static size_t *p_len; /* line length including \n if any */ static char *p_Char; /* +, -, and ! */ static LINENUM hunkmax = INITHUNKMAX; /* size of above arrays */ static int p_indent; /* indent to patch */ +static bool p_strip_trailing_cr; /* true if stripping trailing \r */ +static bool p_pass_comments_through; /* true if not ignoring # lines */ static file_offset p_base; /* where to intuit this time */ static LINENUM p_bline; /* line # of p_base */ static file_offset p_start; /* where intuit found a patch */ @@ -65,21 +71,23 @@ static LINENUM p_bfake = -1; /* beg of faked up lines */ enum nametype { OLD, NEW, INDEX, NONE }; -static enum diff intuit_diff_type PARAMS ((void)); -static enum nametype best_name PARAMS ((char * const *, int const *)); -static int prefix_components PARAMS ((char *, int)); -static size_t pget_line PARAMS ((int, int)); -static size_t get_line PARAMS ((void)); -static bool incomplete_line PARAMS ((void)); -static bool grow_hunkmax PARAMS ((void)); -static void malformed PARAMS ((void)) __attribute__ ((noreturn)); -static void next_intuit_at PARAMS ((file_offset, LINENUM)); -static void skip_to PARAMS ((file_offset, LINENUM)); +static char *scan_linenum (char *, LINENUM *); +static enum diff intuit_diff_type (void); +static enum nametype best_name (char * const *, int const *); +static int prefix_components (char *, bool); +static size_t pget_line (int, int, bool, bool); +static size_t get_line (void); +static bool incomplete_line (void); +static bool grow_hunkmax (void); +static void malformed (void) __attribute__ ((noreturn)); +static void next_intuit_at (file_offset, LINENUM); +static void skip_to (file_offset, LINENUM); +static char get_ed_command_letter (char const *); /* Prepare to look for the next patch in the patch file. */ void -re_patch() +re_patch (void) { p_first = 0; p_newfirst = 0; @@ -88,20 +96,20 @@ re_patch() p_end = -1; p_max = 0; p_indent = 0; + p_strip_trailing_cr = false; } /* Open the patch file at the beginning of time. */ void -open_patch_file(filename) - char const *filename; +open_patch_file (char const *filename) { file_offset file_pos = 0; struct stat st; if (!filename || !*filename || strEQ (filename, "-")) { file_offset stdin_pos; -#if HAVE_SETMODE +#if HAVE_SETMODE_DOS if (binary_transput) { if (isatty (STDIN_FILENO)) @@ -119,9 +127,14 @@ open_patch_file(filename) else { size_t charsread; - pfp = fopen (TMPPATNAME, "w+b"); + int exclusive = TMPPATNAME_needs_removal ? 0 : O_EXCL; + TMPPATNAME_needs_removal = 1; + pfp = fdopen (create_file (TMPPATNAME, + O_RDWR | O_BINARY | exclusive, + (mode_t) 0), + "w+b"); if (!pfp) - pfatal ("can't create `%s'", TMPPATNAME); + pfatal ("Can't open stream for file %s", quotearg (TMPPATNAME)); for (st.st_size = 0; (charsread = fread (buf, 1, bufsize, stdin)) != 0; st.st_size += charsread) @@ -138,7 +151,7 @@ open_patch_file(filename) { pfp = fopen (filename, binary_transput ? "rb" : "r"); if (!pfp) - pfatal ("can't open patch file `%s'", filename); + pfatal ("Can't open patch file %s", quotearg (filename)); if (fstat (fileno (pfp), &st) != 0) pfatal ("fstat"); } @@ -152,7 +165,7 @@ open_patch_file(filename) /* Make sure our dynamically realloced tables are malloced to begin with. */ void -set_hunkmax() +set_hunkmax (void) { if (!p_line) p_line = (char **) malloc (hunkmax * sizeof *p_line); @@ -165,32 +178,32 @@ set_hunkmax() /* Enlarge the arrays containing the current hunk of patch. */ static bool -grow_hunkmax() +grow_hunkmax (void) { hunkmax *= 2; assert (p_line && p_len && p_Char); if ((p_line = (char **) realloc (p_line, hunkmax * sizeof (*p_line))) && (p_len = (size_t *) realloc (p_len, hunkmax * sizeof (*p_len))) && (p_Char = realloc (p_Char, hunkmax * sizeof (*p_Char)))) - return TRUE; + return true; if (!using_plan_a) memory_fatal (); /* Don't free previous values of p_line etc., since some broken implementations free them for us. Whatever is null will be allocated again from within plan_a (), of all places. */ - return FALSE; + return false; } /* True if the remainder of the patch file contains a diff of some sort. */ bool -there_is_another_patch() +there_is_another_patch (void) { if (p_base != 0 && p_base >= p_filesize) { if (verbosity == VERBOSE) say ("done\n"); - return FALSE; + return false; } if (verbosity == VERBOSE) say ("Hmm..."); @@ -202,13 +215,13 @@ there_is_another_patch() : " I can't seem to find a patch in there anywhere.\n"); if (! p_base && p_filesize) fatal ("Only garbage was found in the patch input."); - return FALSE; + return false; } if (skip_rest_of_patch) { Fseek (pfp, p_start, SEEK_SET); p_input_line = p_sline - 1; - return TRUE; + return true; } if (verbosity == VERBOSE) say (" %sooks like %s to me...\n", @@ -223,22 +236,26 @@ there_is_another_patch() { if (p_indent) say ("(Patch is indented %d space%s.)\n", p_indent, p_indent==1?"":"s"); + if (p_strip_trailing_cr) + say ("(Stripping trailing CRs from patch.)\n"); if (! inname) { - say ("can't find file to patch at input line %ld\n", - p_sline); - say (strippath == INT_MAX - ? "Perhaps you should have used the -p or --strip option?\n" - : "Perhaps you used the wrong -p or --strip option?\n"); + char numbuf[LINENUM_LENGTH_BOUND + 1]; + say ("can't find file to patch at input line %s\n", + format_linenum (numbuf, p_sline)); + if (diff_type != ED_DIFF) + say (strippath == -1 + ? "Perhaps you should have used the -p or --strip option?\n" + : "Perhaps you used the wrong -p or --strip option?\n"); } } skip_to(p_start,p_sline); while (!inname) { - if (force || batch) { + if (force | batch) { say ("No file to patch. Skipping patch.\n"); - skip_rest_of_patch = TRUE; - return TRUE; + skip_rest_of_patch = true; + return true; } ask ("File to patch: "); inname = fetchname (buf, 0, (time_t *) 0); @@ -252,6 +269,7 @@ there_is_another_patch() else { perror (inname); + fflush (stderr); free (inname); inname = 0; } @@ -261,30 +279,25 @@ there_is_another_patch() if (*buf != 'n') { if (verbosity != SILENT) say ("Skipping patch.\n"); - skip_rest_of_patch = TRUE; - return TRUE; + skip_rest_of_patch = true; + return true; } } } - return TRUE; + return true; } /* Determine what kind of diff is in the remaining part of the patch file. */ static enum diff -intuit_diff_type() +intuit_diff_type (void) { - register char *s; - register char *t; - register int indent; register file_offset this_line = 0; - register file_offset previous_line; register file_offset first_command_line = -1; + char first_ed_command_letter = 0; LINENUM fcl_line = 0; /* Pacify `gcc -W'. */ - register bool last_line_was_command = FALSE; - register bool this_is_a_command = FALSE; - register bool stars_last_line = FALSE; - register bool stars_this_line = FALSE; + register bool this_is_a_command = false; + register bool stars_this_line = false; enum nametype i; char *name[3]; struct stat st[3]; @@ -302,13 +315,22 @@ intuit_diff_type() Fseek (pfp, p_base, SEEK_SET); p_input_line = p_bline - 1; for (;;) { - previous_line = this_line; - last_line_was_command = this_is_a_command; - stars_last_line = stars_this_line; + register char *s; + register char *t; + register file_offset previous_line = this_line; + register bool last_line_was_command = this_is_a_command; + register bool stars_last_line = stars_this_line; + register int indent = 0; + char ed_command_letter; + bool strip_trailing_cr; + size_t chars_read; + this_line = file_tell (pfp); - indent = 0; - if (! pget_line (0, 0)) { - if (first_command_line >= 0) { + chars_read = pget_line (0, 0, false, false); + if (chars_read == (size_t) -1) + memory_fatal (); + if (! chars_read) { + if (first_ed_command_letter) { /* nothing but deletes!? */ p_start = first_command_line; p_sline = fcl_line; @@ -321,6 +343,7 @@ intuit_diff_type() return NO_DIFF; } } + strip_trailing_cr = 2 <= chars_read && buf[chars_read - 2] == '\r'; for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) { if (*s == '\t') indent = (indent + 8) & ~7; @@ -331,10 +354,14 @@ intuit_diff_type() continue; this_is_a_command = (ISDIGIT (*s) && (*t == 'd' || *t == 'c' || *t == 'a') ); - if (first_command_line < 0 && this_is_a_command) { + if (first_command_line < 0 + && ((ed_command_letter = get_ed_command_letter (s)) + || this_is_a_command)) { first_command_line = this_line; + first_ed_command_letter = ed_command_letter; fcl_line = p_input_line; p_indent = indent; /* assume this for now */ + p_strip_trailing_cr = strip_trailing_cr; } if (!stars_last_line && strnEQ(s, "*** ", 4)) name[OLD] = fetchname (s+4, strippath, &p_timestamp[OLD]); @@ -347,8 +374,20 @@ intuit_diff_type() for (t = s + 7; ISSPACE ((unsigned char) *t); t++) continue; revision = t; - for (t = revision; *t && !ISSPACE ((unsigned char) *t); t++) - continue; + for (t = revision; *t; t++) + if (ISSPACE ((unsigned char) *t)) + { + char const *u; + for (u = t + 1; ISSPACE ((unsigned char) *u); u++) + continue; + if (*u) + { + char numbuf[LINENUM_LENGTH_BOUND + 1]; + say ("Prereq: with multiple words at line %s of patch\n", + format_linenum (numbuf, this_line)); + } + break; + } if (t == revision) revision = 0; else { @@ -375,7 +414,6 @@ intuit_diff_type() if ((diff_type == NO_DIFF || diff_type == ED_DIFF) && first_command_line >= 0 && strEQ(s, ".\n") ) { - p_indent = indent; p_start = first_command_line; p_sline = fcl_line; retval = ED_DIFF; @@ -393,22 +431,26 @@ intuit_diff_type() name[NEW] = t; s += 4; - if (! atol (s)) + if (s[0] == '0' && !ISDIGIT (s[1])) p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD]; while (*s != ' ' && *s != '\n') s++; while (*s == ' ') s++; - if (! atol (s)) + if (s[0] == '+' && s[1] == '0' && !ISDIGIT (s[2])) p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW]; p_indent = indent; p_start = this_line; p_sline = p_input_line; retval = UNI_DIFF; if (! ((name[OLD] || ! p_timestamp[OLD]) - && (name[NEW] || ! p_timestamp[NEW]))) - say ("missing header for unified diff at line %ld of patch\n", - p_sline); + && (name[NEW] || ! p_timestamp[NEW])) + && ! name[INDEX]) + { + char numbuf[LINENUM_LENGTH_BOUND + 1]; + say ("missing header for unified diff at line %s of patch\n", + format_linenum (numbuf, p_sline)); + } goto scan_exit; } stars_this_line = strnEQ(s, "********", 8); @@ -417,13 +459,14 @@ intuit_diff_type() || diff_type == NEW_CONTEXT_DIFF) && stars_last_line && strnEQ (s, "*** ", 4)) { s += 4; - if (! atol (s)) + if (s[0] == '0' && !ISDIGIT (s[1])) p_says_nonexistent[OLD] = 1 + ! p_timestamp[OLD]; /* if this is a new context diff the character just before */ /* the newline is a '*'. */ while (*s != '\n') s++; p_indent = indent; + p_strip_trailing_cr = strip_trailing_cr; p_start = previous_line; p_sline = p_input_line - 1; retval = (*(s-1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF); @@ -435,16 +478,20 @@ intuit_diff_type() LINENUM saved_p_bline = p_bline; Fseek (pfp, previous_line, SEEK_SET); p_input_line -= 2; - if (another_hunk (retval, 0) + if (another_hunk (retval, false) && ! p_repl_lines && p_newfirst == 1) p_says_nonexistent[NEW] = 1 + ! p_timestamp[NEW]; next_intuit_at (saved_p_base, saved_p_bline); } if (! ((name[OLD] || ! p_timestamp[OLD]) - && (name[NEW] || ! p_timestamp[NEW]))) - say ("missing header for context diff at line %ld of patch\n", - p_sline); + && (name[NEW] || ! p_timestamp[NEW])) + && ! name[INDEX]) + { + char numbuf[LINENUM_LENGTH_BOUND + 1]; + say ("missing header for context diff at line %s of patch\n", + format_linenum (numbuf, p_sline)); + } goto scan_exit; } if ((diff_type == NO_DIFF || diff_type == NORMAL_DIFF) && @@ -453,6 +500,7 @@ intuit_diff_type() p_start = previous_line; p_sline = p_input_line - 1; p_indent = indent; + p_strip_trailing_cr = strip_trailing_cr; retval = NORMAL_DIFF; goto scan_exit; } @@ -461,7 +509,7 @@ intuit_diff_type() scan_exit: /* To intuit `inname', the name of the file to patch, - use the algorithm specified by POSIX 1003.2b/D11 section 5.22.7.2 + use the algorithm specified by POSIX 1003.1-2001 XCU lines 25680-26599 (with some modifications if posixly_correct is zero): - Take the old and new names from the context header if present, @@ -516,6 +564,8 @@ intuit_diff_type() if (! posixly_correct) { + bool is_empty; + i = best_name (name, stat_errno); if (i == NONE && patch_get) @@ -528,7 +578,8 @@ intuit_diff_type() char const *cs; char *getbuf; char *diffbuf; - int readonly = outfile && strcmp (outfile, name[i]) != 0; + bool readonly = (outfile + && strcmp (outfile, name[i]) != 0); if (nope == NONE || strcmp (name[nope], name[i]) != 0) { @@ -538,14 +589,15 @@ intuit_diff_type() version_controlled[i] = !! cs; if (cs) { - if (version_get (name[i], cs, 0, readonly, + if (version_get (name[i], cs, false, readonly, getbuf, &st[i])) stat_errno[i] = 0; else version_controlled[i] = 0; free (getbuf); - free (diffbuf); + if (diffbuf) + free (diffbuf); if (! stat_errno[i]) break; @@ -556,20 +608,21 @@ intuit_diff_type() } } - if (p_says_nonexistent[reverse ^ (i == NONE || st[i].st_size == 0)]) + is_empty = i == NONE || st[i].st_size == 0; + if ((! is_empty) < p_says_nonexistent[reverse ^ is_empty]) { assert (i0 != NONE); - if (ok_to_reverse - ("The next patch%s would %s the file `%s',\nwhich %s!", + reverse ^= + ok_to_reverse + ("The next patch%s would %s the file %s,\nwhich %s!", reverse ? ", when reversed," : "", (i == NONE ? "delete" : st[i].st_size == 0 ? "empty out" : "create"), - name[i == NONE || st[i].st_size == 0 ? i0 : i], + quotearg (name[i == NONE || st[i].st_size == 0 ? i0 : i]), (i == NONE ? "does not exist" : st[i].st_size == 0 ? "is already empty" - : "already exists"))) - reverse ^= 1; + : "already exists")); } if (i == NONE && p_says_nonexistent[reverse]) @@ -581,8 +634,8 @@ intuit_diff_type() for (i = OLD; i <= INDEX; i++) if (name[i]) { - newdirs[i] = (prefix_components (name[i], 0) - - prefix_components (name[i], 1)); + newdirs[i] = (prefix_components (name[i], false) + - prefix_components (name[i], true)); if (newdirs[i] < newdirs_min) newdirs_min = newdirs[i]; } @@ -615,11 +668,9 @@ intuit_diff_type() } /* Count the path name components in FILENAME's prefix. - If CHECKDIRS is nonzero, count only existing directories. */ + If CHECKDIRS is true, count only existing directories. */ static int -prefix_components (filename, checkdirs) - char *filename; - int checkdirs; +prefix_components (char *filename, bool checkdirs) { int count = 0; struct stat stat_buf; @@ -649,23 +700,21 @@ prefix_components (filename, checkdirs) Ignore null names, and ignore NAME[i] if IGNORE[i] is nonzero. Return NONE if all names are ignored. */ static enum nametype -best_name (name, ignore) - char *const *name; - int const *ignore; +best_name (char *const *name, int const *ignore) { enum nametype i; int components[3]; int components_min = INT_MAX; size_t basename_len[3]; - size_t basename_len_min = (size_t) -1; + size_t basename_len_min = SIZE_MAX; size_t len[3]; - size_t len_min = (size_t) -1; + size_t len_min = SIZE_MAX; for (i = OLD; i <= INDEX; i++) if (name[i] && !ignore[i]) { /* Take the names with the fewest prefix components. */ - components[i] = prefix_components (name[i], 0); + components[i] = prefix_components (name[i], false); if (components_min < components[i]) continue; components_min = components[i]; @@ -697,9 +746,7 @@ best_name (name, ignore) /* Remember where this patch ends so we know where to start up again. */ static void -next_intuit_at(file_pos,file_line) -file_offset file_pos; -LINENUM file_line; +next_intuit_at (file_offset file_pos, LINENUM file_line) { p_base = file_pos; p_bline = file_line; @@ -708,9 +755,7 @@ LINENUM file_line; /* Basically a verbose fseek() to the actual diff listing. */ static void -skip_to(file_pos,file_line) -file_offset file_pos; -LINENUM file_line; +skip_to (file_offset file_pos, LINENUM file_line) { register FILE *i = pfp; register FILE *o = stdout; @@ -742,23 +787,56 @@ LINENUM file_line; /* Make this a function for better debugging. */ static void -malformed () +malformed (void) { - fatal ("malformed patch at line %ld: %s", p_input_line, buf); + char numbuf[LINENUM_LENGTH_BOUND + 1]; + fatal ("malformed patch at line %s: %s", + format_linenum (numbuf, p_input_line), buf); /* about as informative as "Syntax error" in C */ } +/* Parse a line number from a string. + Return the address of the first char after the number. */ +static char * +scan_linenum (char *s0, LINENUM *linenum) +{ + char *s; + LINENUM n = 0; + bool overflow = false; + char numbuf[LINENUM_LENGTH_BOUND + 1]; + + for (s = s0; ISDIGIT (*s); s++) + { + LINENUM new_n = 10 * n + (*s - '0'); + overflow |= new_n / 10 != n; + n = new_n; + } + + if (s == s0) + fatal ("missing line number at line %s: %s", + format_linenum (numbuf, p_input_line), buf); + + if (overflow) + fatal ("line number %.*s is too large at line %s: %s", + (int) (s - s0), s0, format_linenum (numbuf, p_input_line), buf); + + *linenum = n; + return s; +} + /* 1 if there is more of the current diff listing to process; 0 if not; -1 if ran out of memory. */ int -another_hunk (difftype, rev) - enum diff difftype; - int rev; +another_hunk (enum diff difftype, bool rev) { register char *s; register LINENUM context = 0; register size_t chars_read; + char numbuf0[LINENUM_LENGTH_BOUND + 1]; + char numbuf1[LINENUM_LENGTH_BOUND + 1]; + char numbuf2[LINENUM_LENGTH_BOUND + 1]; + char numbuf3[LINENUM_LENGTH_BOUND + 1]; while (p_end >= 0) { if (p_end == p_efake) @@ -778,10 +856,11 @@ another_hunk (difftype, rev) register LINENUM fillcnt = 0; /* #lines of missing ptrn or repl */ register LINENUM fillsrc; /* index of first line to copy */ register LINENUM filldst; /* index of first missing line */ - bool ptrn_spaces_eaten = FALSE; /* ptrn was slightly misformed */ - bool some_context = FALSE; /* (perhaps internal) context seen */ - register bool repl_could_be_missing = TRUE; - bool repl_missing = FALSE; /* we are now backtracking */ + bool ptrn_spaces_eaten = false; /* ptrn was slightly misformed */ + bool some_context = false; /* (perhaps internal) context seen */ + register bool repl_could_be_missing = true; + bool ptrn_missing = false; /* The pattern was missing. */ + bool repl_missing = false; /* Likewise for replacement. */ file_offset repl_backtrack_position = 0; /* file pos of first repl line */ LINENUM repl_patch_line; /* input line number for same */ @@ -789,8 +868,8 @@ another_hunk (difftype, rev) LINENUM ptrn_prefix_context = -1; /* lines in pattern prefix context */ LINENUM ptrn_suffix_context = -1; /* lines in pattern suffix context */ LINENUM repl_prefix_context = -1; /* lines in replac. prefix context */ - register LINENUM ptrn_copiable = 0; - /* # of copiable lines in ptrn */ + LINENUM ptrn_copiable = 0; /* # of copiable lines in ptrn */ + LINENUM repl_copiable = 0; /* Likewise for replacement. */ /* Pacify `gcc -Wall'. */ fillsrc = filldst = repl_patch_line = repl_context = 0; @@ -809,7 +888,7 @@ another_hunk (difftype, rev) return -1; if (!chars_read) { if (repl_beginning && repl_could_be_missing) { - repl_missing = TRUE; + repl_missing = true; goto hunk_done; } if (p_max - p_end < 4) { @@ -821,8 +900,9 @@ another_hunk (difftype, rev) } p_end++; if (p_end == hunkmax) - fatal ("unterminated hunk starting at line %ld; giving up at line %ld: %s", - pch_hunk_beg (), p_input_line, buf); + fatal ("unterminated hunk starting at line %s; giving up at line %s: %s", + format_linenum (numbuf0, pch_hunk_beg ()), + format_linenum (numbuf1, p_input_line), buf); assert(p_end < hunkmax); p_Char[p_end] = *buf; p_len[p_end] = 0; @@ -831,20 +911,20 @@ another_hunk (difftype, rev) case '*': if (strnEQ(buf, "********", 8)) { if (repl_beginning && repl_could_be_missing) { - repl_missing = TRUE; + repl_missing = true; goto hunk_done; } else - fatal ("unexpected end of hunk at line %ld", - p_input_line); + fatal ("unexpected end of hunk at line %s", + format_linenum (numbuf0, p_input_line)); } if (p_end != 0) { if (repl_beginning && repl_could_be_missing) { - repl_missing = TRUE; + repl_missing = true; goto hunk_done; } - fatal ("unexpected `***' at line %ld: %s", - p_input_line, buf); + fatal ("unexpected `***' at line %s: %s", + format_linenum (numbuf0, p_input_line), buf); } context = 0; p_len[p_end] = strlen (buf); @@ -854,19 +934,14 @@ another_hunk (difftype, rev) } for (s = buf; *s && !ISDIGIT (*s); s++) continue; - if (!*s) - malformed (); if (strnEQ(s,"0,0",3)) remove_prefix (s, 2); - p_first = (LINENUM) atol(s); - while (ISDIGIT (*s)) - s++; + s = scan_linenum (s, &p_first); if (*s == ',') { while (*s && !ISDIGIT (*s)) s++; - if (!*s) - malformed (); - p_ptrn_lines = ((LINENUM)atol(s)) - p_first + 1; + scan_linenum (s, &p_ptrn_lines); + p_ptrn_lines += 1 - p_first; } else if (p_first) p_ptrn_lines = 1; @@ -894,6 +969,7 @@ another_hunk (difftype, rev) { /* `Old' lines were omitted. Set up to fill them in from `new' context lines. */ + ptrn_missing = true; p_end = p_ptrn_lines + 1; ptrn_prefix_context = ptrn_suffix_context = -1; fillsrc = p_end + 1; @@ -901,17 +977,20 @@ another_hunk (difftype, rev) fillcnt = p_ptrn_lines; } else if (! repl_beginning) - fatal ("%s `---' at line %ld; check line numbers at line %ld", + fatal ("%s `---' at line %s; check line numbers at line %s", (p_end <= p_ptrn_lines ? "Premature" : "Overdue"), - p_input_line, p_hunk_beg); + format_linenum (numbuf0, p_input_line), + format_linenum (numbuf1, p_hunk_beg)); else if (! repl_could_be_missing) - fatal ("duplicate `---' at line %ld; check line numbers at line %ld", - p_input_line, p_hunk_beg + repl_beginning); + fatal ("duplicate `---' at line %s; check line numbers at line %s", + format_linenum (numbuf0, p_input_line), + format_linenum (numbuf1, + p_hunk_beg + repl_beginning)); else { - repl_missing = TRUE; + repl_missing = true; goto hunk_done; } } @@ -928,11 +1007,7 @@ another_hunk (difftype, rev) p_Char[p_end] = '='; for (s = buf; *s && ! ISDIGIT (*s); s++) continue; - if (!*s) - malformed (); - p_newfirst = (LINENUM) atol (s); - while (ISDIGIT (*s)) - s++; + s = scan_linenum (s, &p_newfirst); if (*s == ',') { do @@ -941,7 +1016,8 @@ another_hunk (difftype, rev) malformed (); } while (! ISDIGIT (*s)); - p_repl_lines = (LINENUM) atol (s) - p_newfirst + 1; + scan_linenum (s, &p_repl_lines); + p_repl_lines += 1 - p_newfirst; } else if (p_newfirst) p_repl_lines = 1; @@ -958,11 +1034,11 @@ another_hunk (difftype, rev) && (p_prefix_context != 0 || context != 0 || p_repl_lines != 1)) - repl_could_be_missing = FALSE; + repl_could_be_missing = false; context = 0; break; case '+': case '!': - repl_could_be_missing = FALSE; + repl_could_be_missing = false; change_line: s = buf + 1; chars_read--; @@ -974,7 +1050,7 @@ another_hunk (difftype, rev) s++; chars_read--; } else if (repl_beginning && repl_could_be_missing) { - repl_missing = TRUE; + repl_missing = true; goto hunk_done; } if (! repl_beginning) @@ -1006,7 +1082,7 @@ another_hunk (difftype, rev) } if (repl_beginning && repl_could_be_missing && (!ptrn_spaces_eaten || difftype == NEW_CONTEXT_DIFF) ) { - repl_missing = TRUE; + repl_missing = true; goto hunk_done; } chars_read -= @@ -1020,9 +1096,11 @@ another_hunk (difftype, rev) } if (p_end != p_ptrn_lines + 1) { ptrn_spaces_eaten |= (repl_beginning != 0); - some_context = TRUE; + some_context = true; context++; - if (!repl_beginning) + if (repl_beginning) + repl_copiable++; + else ptrn_copiable++; p_Char[p_end] = ' '; } @@ -1038,12 +1116,14 @@ another_hunk (difftype, rev) s++; chars_read--; } else if (repl_beginning && repl_could_be_missing) { - repl_missing = TRUE; + repl_missing = true; goto hunk_done; } - some_context = TRUE; + some_context = true; context++; - if (!repl_beginning) + if (repl_beginning) + repl_copiable++; + else ptrn_copiable++; chars_read -= (1 < chars_read @@ -1057,7 +1137,7 @@ another_hunk (difftype, rev) break; default: if (repl_beginning && repl_could_be_missing) { - repl_missing = TRUE; + repl_missing = true; goto hunk_done; } malformed (); @@ -1066,7 +1146,8 @@ another_hunk (difftype, rev) hunk_done: if (p_end >=0 && !repl_beginning) - fatal ("no `---' found in patch at line %ld", pch_hunk_beg ()); + fatal ("no `---' found in patch at line %s", + format_linenum (numbuf0, pch_hunk_beg ())); if (repl_missing) { @@ -1084,6 +1165,9 @@ another_hunk (difftype, rev) fillcnt = p_repl_lines; p_end = p_max; } + else if (! ptrn_missing && ptrn_copiable != repl_copiable) + fatal ("context mangled in hunk at line %s", + format_linenum (numbuf0, p_hunk_beg)); else if (!some_context && fillcnt == 1) { /* the first hunk was a null hunk with no context */ /* and we were expecting one line -- fix it up. */ @@ -1132,8 +1216,10 @@ another_hunk (difftype, rev) && p_Char[fillsrc] != ' ') fillsrc++; if (p_end < fillsrc || fillsrc == repl_beginning) - fatal ("replacement text or line numbers mangled in hunk at line %ld", - p_hunk_beg); + { + fatal ("replacement text or line numbers mangled in hunk at line %s", + format_linenum (numbuf0, p_hunk_beg)); + } p_line[filldst] = p_line[fillsrc]; p_Char[filldst] = p_Char[fillsrc]; p_len[filldst] = p_len[fillsrc]; @@ -1142,13 +1228,16 @@ another_hunk (difftype, rev) while (fillsrc <= p_end && fillsrc != repl_beginning) { if (p_Char[fillsrc] == ' ') - fatal ("replacement text or line numbers mangled in hunk at line %ld", - p_hunk_beg); + fatal ("replacement text or line numbers mangled in hunk at line %s", + format_linenum (numbuf0, p_hunk_beg)); fillsrc++; } if (debug & 64) - printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n", - fillsrc,filldst,repl_beginning,p_end+1); + printf ("fillsrc %s, filldst %s, rb %s, e+1 %s\n", + format_linenum (numbuf0, fillsrc), + format_linenum (numbuf1, filldst), + format_linenum (numbuf2, repl_beginning), + format_linenum (numbuf3, p_end + 1)); assert(fillsrc==p_end+1 || fillsrc==repl_beginning); assert(filldst==p_end+1 || filldst==repl_beginning); } @@ -1167,29 +1256,18 @@ another_hunk (difftype, rev) next_intuit_at(line_beginning,p_input_line); return chars_read == (size_t) -1 ? -1 : 0; } - s = buf+4; - if (!*s) - malformed (); - p_first = (LINENUM) atol(s); - while (ISDIGIT (*s)) - s++; - if (*s == ',') { - p_ptrn_lines = (LINENUM) atol(++s); - while (ISDIGIT (*s)) - s++; - } else + s = scan_linenum (buf + 4, &p_first); + if (*s == ',') + s = scan_linenum (s + 1, &p_ptrn_lines); + else p_ptrn_lines = 1; if (*s == ' ') s++; - if (*s != '+' || !*++s) + if (*s != '+') malformed (); - p_newfirst = (LINENUM) atol(s); - while (ISDIGIT (*s)) - s++; - if (*s == ',') { - p_repl_lines = (LINENUM) atol(++s); - while (ISDIGIT (*s)) - s++; - } else + s = scan_linenum (s + 1, &p_newfirst); + if (*s == ',') + s = scan_linenum (s + 1, &p_repl_lines); + else p_repl_lines = 1; if (*s == ' ') s++; if (*s != '@') @@ -1205,14 +1283,18 @@ another_hunk (difftype, rev) fillsrc = 1; filldst = fillsrc + p_ptrn_lines; p_end = filldst + p_repl_lines; - sprintf (buf,"*** %ld,%ld ****\n",p_first,p_first + p_ptrn_lines - 1); + sprintf (buf, "*** %s,%s ****\n", + format_linenum (numbuf0, p_first), + format_linenum (numbuf1, p_first + p_ptrn_lines - 1)); p_len[0] = strlen (buf); if (! (p_line[0] = savestr (buf))) { p_end = -1; return -1; } p_Char[0] = '*'; - sprintf (buf,"--- %ld,%ld ----\n",p_newfirst,p_newfirst+p_repl_lines-1); + sprintf (buf, "--- %s,%s ----\n", + format_linenum (numbuf0, p_newfirst), + format_linenum (numbuf1, p_newfirst + p_repl_lines - 1)); p_len[filldst] = strlen (buf); if (! (p_line[filldst] = savestr (buf))) { p_end = 0; @@ -1322,24 +1404,19 @@ another_hunk (difftype, rev) next_intuit_at(line_beginning,p_input_line); return chars_read == (size_t) -1 ? -1 : 0; } - p_first = (LINENUM)atol(buf); - for (s = buf; ISDIGIT (*s); s++) - continue; + s = scan_linenum (buf, &p_first); if (*s == ',') { - p_ptrn_lines = (LINENUM)atol(++s) - p_first + 1; - while (ISDIGIT (*s)) - s++; + s = scan_linenum (s + 1, &p_ptrn_lines); + p_ptrn_lines += 1 - p_first; } else p_ptrn_lines = (*s != 'a'); hunk_type = *s; if (hunk_type == 'a') p_first++; /* do append rather than insert */ - min = (LINENUM)atol(++s); - while (ISDIGIT (*s)) - s++; + s = scan_linenum (s + 1, &min); if (*s == ',') - max = (LINENUM)atol(++s); + scan_linenum (s + 1, &max); else max = min; if (hunk_type == 'd') @@ -1353,7 +1430,9 @@ another_hunk (difftype, rev) } p_newfirst = min; p_repl_lines = max - min + 1; - sprintf (buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1); + sprintf (buf, "*** %s,%s\n", + format_linenum (numbuf0, p_first), + format_linenum (numbuf1, p_first + p_ptrn_lines - 1)); p_len[0] = strlen (buf); if (! (p_line[0] = savestr (buf))) { p_end = -1; @@ -1368,10 +1447,11 @@ another_hunk (difftype, rev) return -1; } if (!chars_read) - fatal ("unexpected end of file in patch at line %ld", - p_input_line); + fatal ("unexpected end of file in patch at line %s", + format_linenum (numbuf0, p_input_line)); if (buf[0] != '<' || (buf[1] != ' ' && buf[1] != '\t')) - fatal ("`<' expected at line %ld of patch", p_input_line); + fatal ("`<' expected at line %s of patch", + format_linenum (numbuf0, p_input_line)); chars_read -= 2 + (i == p_ptrn_lines && incomplete_line ()); p_len[i] = chars_read; if (! (p_line[i] = savebuf (buf + 2, chars_read))) { @@ -1388,12 +1468,15 @@ another_hunk (difftype, rev) return -1; } if (! chars_read) - fatal ("unexpected end of file in patch at line %ld", - p_input_line); + fatal ("unexpected end of file in patch at line %s", + format_linenum (numbuf0, p_input_line)); if (*buf != '-') - fatal ("`---' expected at line %ld of patch", p_input_line); + fatal ("`---' expected at line %s of patch", + format_linenum (numbuf0, p_input_line)); } - sprintf (buf, "--- %ld,%ld\n", min, max); + sprintf (buf, "--- %s,%s\n", + format_linenum (numbuf0, min), + format_linenum (numbuf1, max)); p_len[i] = strlen (buf); if (! (p_line[i] = savestr (buf))) { p_end = i-1; @@ -1408,10 +1491,11 @@ another_hunk (difftype, rev) return -1; } if (!chars_read) - fatal ("unexpected end of file in patch at line %ld", - p_input_line); + fatal ("unexpected end of file in patch at line %s", + format_linenum (numbuf0, p_input_line)); if (buf[0] != '>' || (buf[1] != ' ' && buf[1] != '\t')) - fatal ("`>' expected at line %ld of patch", p_input_line); + fatal ("`>' expected at line %s of patch", + format_linenum (numbuf0, p_input_line)); chars_read -= 2 + (i == p_end && incomplete_line ()); p_len[i] = chars_read; if (! (p_line[i] = savebuf (buf + 2, chars_read))) { @@ -1433,7 +1517,8 @@ another_hunk (difftype, rev) special = '^'; else special = ' '; - fprintf (stderr, "%3ld %c %c ", i, p_Char[i], special); + fprintf (stderr, "%s %c %c ", format_linenum (numbuf0, i), + p_Char[i], special); pch_write_line (i, stderr); fflush (stderr); } @@ -1444,95 +1529,106 @@ another_hunk (difftype, rev) } static size_t -get_line () +get_line (void) { - return pget_line (p_indent, p_rfc934_nesting); + return pget_line (p_indent, p_rfc934_nesting, p_strip_trailing_cr, + p_pass_comments_through); } /* Input a line from the patch file, worrying about indentation. Strip up to INDENT characters' worth of leading indentation. Then remove up to RFC934_NESTING instances of leading "- ". + If STRIP_TRAILING_CR is true, remove any trailing carriage-return. + Unless PASS_COMMENTS_THROUGH is true, ignore any resulting lines + that begin with '#'; they're comments. Ignore any partial lines at end of input, but warn about them. Succeed if a line was read; it is terminated by "\n\0" for convenience. Return the number of characters read, including '\n' but not '\0'. Return -1 if we ran out of memory. */ static size_t -pget_line (indent, rfc934_nesting) - int indent; - int rfc934_nesting; +pget_line (int indent, int rfc934_nesting, bool strip_trailing_cr, + bool pass_comments_through) { register FILE *fp = pfp; register int c; - register int i = 0; + register int i; register char *b; register size_t s; - for (;;) + do { - c = getc (fp); - if (c == EOF) + i = 0; + for (;;) { - if (ferror (fp)) - read_fatal (); - return 0; + c = getc (fp); + if (c == EOF) + { + if (ferror (fp)) + read_fatal (); + return 0; + } + if (indent <= i) + break; + if (c == ' ' || c == 'X') + i++; + else if (c == '\t') + i = (i + 8) & ~7; + else + break; } - if (indent <= i) - break; - if (c == ' ' || c == 'X') - i++; - else if (c == '\t') - i = (i + 8) & ~7; - else - break; - } - i = 0; - b = buf; + i = 0; + b = buf; - while (c == '-' && 0 <= --rfc934_nesting) - { - c = getc (fp); - if (c == EOF) - goto patch_ends_in_middle_of_line; - if (c != ' ') + while (c == '-' && 0 <= --rfc934_nesting) { - i = 1; - b[0] = '-'; - break; + c = getc (fp); + if (c == EOF) + goto patch_ends_in_middle_of_line; + if (c != ' ') + { + i = 1; + b[0] = '-'; + break; + } + c = getc (fp); + if (c == EOF) + goto patch_ends_in_middle_of_line; } - c = getc (fp); - if (c == EOF) - goto patch_ends_in_middle_of_line; - } - s = bufsize; + s = bufsize; - for (;;) - { - if (i == s - 1) + for (;;) { - s *= 2; - b = realloc (b, s); - if (!b) + if (i == s - 1) { - if (!using_plan_a) - memory_fatal (); - return (size_t) -1; + s *= 2; + b = realloc (b, s); + if (!b) + { + if (!using_plan_a) + memory_fatal (); + return (size_t) -1; + } + buf = b; + bufsize = s; } - buf = b; - bufsize = s; + b[i++] = c; + if (c == '\n') + break; + c = getc (fp); + if (c == EOF) + goto patch_ends_in_middle_of_line; } - b[i++] = c; - if (c == '\n') - break; - c = getc (fp); - if (c == EOF) - goto patch_ends_in_middle_of_line; + + p_input_line++; } + while (*b == '#' && !pass_comments_through); + if (strip_trailing_cr && 2 <= i && b[i - 2] == '\r') + b[i-- - 2] = '\n'; b[i] = '\0'; - p_input_line++; return i; patch_ends_in_middle_of_line: @@ -1543,7 +1639,7 @@ pget_line (indent, rfc934_nesting) } static bool -incomplete_line () +incomplete_line (void) { register FILE *fp = pfp; register int c; @@ -1553,27 +1649,27 @@ incomplete_line () { while ((c = getc (fp)) != '\n' && c != EOF) continue; - return TRUE; + return true; } else { /* We don't trust ungetc. */ Fseek (pfp, line_beginning, SEEK_SET); - return FALSE; + return false; } } /* Reverse the old and new portions of the current hunk. */ bool -pch_swap() +pch_swap (void) { char **tp_line; /* the text of the hunk */ size_t *tp_len; /* length of each line */ char *tp_char; /* +, -, and ! */ register LINENUM i; register LINENUM n; - bool blankline = FALSE; + bool blankline = false; register char *s; i = p_first; @@ -1599,14 +1695,14 @@ pch_swap() if (p_Char) free (p_Char); p_Char = tp_char; - return FALSE; /* not enough memory to swap hunk! */ + return false; /* not enough memory to swap hunk! */ } /* now turn the new into the old */ i = p_ptrn_lines + 1; if (tp_char[i] == '\n') { /* account for possible blank line */ - blankline = TRUE; + blankline = true; i++; } if (p_efake >= 0) { /* fix non-freeable ptr range */ @@ -1661,25 +1757,23 @@ pch_swap() free (tp_len); if (tp_char) free (tp_char); - return TRUE; + return true; } -/* Return whether file WHICH (0 = old, 1 = new) appears to nonexistent. +/* Return whether file WHICH (false = old, true = new) appears to nonexistent. Return 1 for empty, 2 for nonexistent. */ -bool -pch_says_nonexistent (which) - int which; +int +pch_says_nonexistent (bool which) { return p_says_nonexistent[which]; } -/* Return timestamp of patch header for file WHICH (0 = old, 1 = new), +/* Return timestamp of patch header for file WHICH (false = old, true = new), or -1 if there was no timestamp or an error in the timestamp. */ time_t -pch_timestamp (which) - int which; +pch_timestamp (bool which) { return p_timestamp[which]; } @@ -1687,7 +1781,7 @@ pch_timestamp (which) /* Return the specified line position in the old file of the old context. */ LINENUM -pch_first() +pch_first (void) { return p_first; } @@ -1695,7 +1789,7 @@ pch_first() /* Return the number of lines of old context. */ LINENUM -pch_ptrn_lines() +pch_ptrn_lines (void) { return p_ptrn_lines; } @@ -1703,7 +1797,7 @@ pch_ptrn_lines() /* Return the probable line position in the new file of the first line. */ LINENUM -pch_newfirst() +pch_newfirst (void) { return p_newfirst; } @@ -1711,7 +1805,7 @@ pch_newfirst() /* Return the number of lines in the replacement text including context. */ LINENUM -pch_repl_lines() +pch_repl_lines (void) { return p_repl_lines; } @@ -1719,7 +1813,7 @@ pch_repl_lines() /* Return the number of lines in the whole hunk. */ LINENUM -pch_end() +pch_end (void) { return p_end; } @@ -1727,7 +1821,7 @@ pch_end() /* Return the number of context lines before the first changed line. */ LINENUM -pch_prefix_context () +pch_prefix_context (void) { return p_prefix_context; } @@ -1735,7 +1829,7 @@ pch_prefix_context () /* Return the number of context lines after the last changed line. */ LINENUM -pch_suffix_context () +pch_suffix_context (void) { return p_suffix_context; } @@ -1743,8 +1837,7 @@ pch_suffix_context () /* Return the length of a particular patch line. */ size_t -pch_line_len(line) -LINENUM line; +pch_line_len (LINENUM line) { return p_len[line]; } @@ -1752,8 +1845,7 @@ LINENUM line; /* Return the control character (+, -, *, !, etc) for a patch line. */ char -pch_char(line) -LINENUM line; +pch_char (LINENUM line) { return p_Char[line]; } @@ -1761,8 +1853,7 @@ LINENUM line; /* Return a pointer to a particular patch line. */ char * -pfetch(line) -LINENUM line; +pfetch (LINENUM line) { return p_line[line]; } @@ -1770,9 +1861,7 @@ LINENUM line; /* Output a patch line. */ bool -pch_write_line (line, file) - LINENUM line; - FILE *file; +pch_write_line (LINENUM line, FILE *file) { bool after_newline = p_line[line][p_len[line] - 1] == '\n'; if (! fwrite (p_line[line], sizeof (*p_line[line]), p_len[line], file)) @@ -1783,51 +1872,103 @@ pch_write_line (line, file) /* Return where in the patch file this hunk began, for error messages. */ LINENUM -pch_hunk_beg() +pch_hunk_beg (void) { return p_hunk_beg; } +/* Is the newline-terminated line a valid `ed' command for patch + input? If so, return the command character; if not, return 0. + This accepts accepts just a subset of the valid commands, but it's + good enough in practice. */ + +static char +get_ed_command_letter (char const *line) +{ + char const *p = line; + char letter; + bool pair = false; + if (! ISDIGIT (*p)) + return 0; + while (ISDIGIT (*++p)) + continue; + if (*p == ',') + { + if (! ISDIGIT (*++p)) + return 0; + while (ISDIGIT (*++p)) + continue; + pair = true; + } + letter = *p++; + + switch (letter) + { + case 'a': + case 'i': + if (pair) + return 0; + break; + + case 'c': + case 'd': + break; + + case 's': + if (strncmp (p, "/.//", 4) != 0) + return 0; + p += 4; + break; + + default: + return 0; + } + + while (*p == ' ' || *p == '\t') + p++; + if (*p == '\n') + return letter; + return 0; +} + /* Apply an ed script by feeding ed itself. */ void -do_ed_script (ofp) - FILE *ofp; +do_ed_script (FILE *ofp) { static char const ed_program[] = ed_PROGRAM; - register char *t; register file_offset beginning_of_this_line; - register bool this_line_is_command = FALSE; register FILE *pipefp = 0; register size_t chars_read; - if (!skip_rest_of_patch) { + if (! dry_run && ! skip_rest_of_patch) { + int exclusive = TMPOUTNAME_needs_removal ? 0 : O_EXCL; assert (! inerrno); - copy_file (inname, TMPOUTNAME, instat.st_mode); + TMPOUTNAME_needs_removal = 1; + copy_file (inname, TMPOUTNAME, exclusive, instat.st_mode); sprintf (buf, "%s %s%s", ed_program, verbosity == VERBOSE ? "" : "- ", TMPOUTNAME); fflush (stdout); pipefp = popen(buf, binary_transput ? "wb" : "w"); if (!pipefp) - pfatal ("can't open pipe to `%s'", buf); + pfatal ("Can't open pipe to %s", quotearg (buf)); } for (;;) { + char ed_command_letter; beginning_of_this_line = file_tell (pfp); chars_read = get_line (); if (! chars_read) { next_intuit_at(beginning_of_this_line,p_input_line); break; } - for (t = buf; ISDIGIT (*t) || *t == ','; t++) - continue; - this_line_is_command = (ISDIGIT (*buf) && - (*t == 'd' || *t == 'c' || *t == 'a' || *t == 'i' || *t == 's') ); - if (this_line_is_command) { + ed_command_letter = get_ed_command_letter (buf); + if (ed_command_letter) { if (pipefp) if (! fwrite (buf, sizeof *buf, chars_read, pipefp)) write_fatal (); - if (*t != 'd' && *t != 's') { + if (ed_command_letter != 'd' && ed_command_letter != 's') { + p_pass_comments_through = true; while ((chars_read = get_line ()) != 0) { if (pipefp) if (! fwrite (buf, sizeof *buf, chars_read, pipefp)) @@ -1835,6 +1976,7 @@ do_ed_script (ofp) if (chars_read == 2 && strEQ (buf, ".\n")) break; } + p_pass_comments_through = false; } } else { |