1/*-
2 * Copyright 1986, Larry Wall
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following condition is met:
6 * 1. Redistributions of source code must retain the above copyright notice,
7 * this condition and the following disclaimer.
8 *
9 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
10 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
11 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
12 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
13 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
14 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
15 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
16 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
17 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
18 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
19 * SUCH DAMAGE.
20 *
21 * patch - a program to apply diffs to original files
22 *
23 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
24 * behaviour
25 *
26 * $OpenBSD: pch.c,v 1.43 2014/11/18 17:03:35 tobias Exp $
27 * $FreeBSD$
28 */
29
30#include <sys/types.h>
31#include <sys/stat.h>
32
33#include <ctype.h>
34#include <libgen.h>
35#include <limits.h>
36#include <stdint.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <string.h>
40#include <unistd.h>
41
42#include "common.h"
43#include "util.h"
44#include "pch.h"
45#include "pathnames.h"
46
47/* Patch (diff listing) abstract type. */
48
49static off_t	p_filesize;	/* size of the patch file */
50static LINENUM	p_first;	/* 1st line number */
51static LINENUM	p_newfirst;	/* 1st line number of replacement */
52static LINENUM	p_ptrn_lines;	/* # lines in pattern */
53static LINENUM	p_repl_lines;	/* # lines in replacement text */
54static LINENUM	p_end = -1;	/* last line in hunk */
55static LINENUM	p_max;		/* max allowed value of p_end */
56static LINENUM	p_context = 3;	/* # of context lines */
57static LINENUM	p_input_line = 0;	/* current line # from patch file */
58static char	**p_line = NULL;/* the text of the hunk */
59static unsigned short	*p_len = NULL; /* length of each line */
60static char	*p_char = NULL;	/* +, -, and ! */
61static int	hunkmax = INITHUNKMAX;	/* size of above arrays to begin with */
62static int	p_indent;	/* indent to patch */
63static off_t	p_base;		/* where to intuit this time */
64static LINENUM	p_bline;	/* line # of p_base */
65static off_t	p_start;	/* where intuit found a patch */
66static LINENUM	p_sline;	/* and the line number for it */
67static LINENUM	p_hunk_beg;	/* line number of current hunk */
68static LINENUM	p_efake = -1;	/* end of faked up lines--don't free */
69static LINENUM	p_bfake = -1;	/* beg of faked up lines */
70static FILE	*pfp = NULL;	/* patch file pointer */
71static char	*bestguess = NULL;	/* guess at correct filename */
72
73char		*source_file;
74
75static void	grow_hunkmax(void);
76static int	intuit_diff_type(void);
77static void	next_intuit_at(off_t, LINENUM);
78static void	skip_to(off_t, LINENUM);
79static size_t	pgets(bool _do_indent);
80static char	*best_name(const struct file_name *, bool);
81static char	*posix_name(const struct file_name *, bool);
82static size_t	num_components(const char *);
83static LINENUM	strtolinenum(char *, char **);
84
85/*
86 * Prepare to look for the next patch in the patch file.
87 */
88void
89re_patch(void)
90{
91	p_first = 0;
92	p_newfirst = 0;
93	p_ptrn_lines = 0;
94	p_repl_lines = 0;
95	p_end = (LINENUM) - 1;
96	p_max = 0;
97	p_indent = 0;
98}
99
100/*
101 * Open the patch file at the beginning of time.
102 */
103void
104open_patch_file(const char *filename)
105{
106	struct stat filestat;
107	int nr, nw;
108
109	if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) {
110		pfp = fopen(TMPPATNAME, "w");
111		if (pfp == NULL)
112			pfatal("can't create %s", TMPPATNAME);
113		while ((nr = fread(buf, 1, buf_size, stdin)) > 0) {
114			nw = fwrite(buf, 1, nr, pfp);
115			if (nr != nw)
116				pfatal("write error to %s", TMPPATNAME);
117		}
118		if (ferror(pfp) || fclose(pfp))
119			pfatal("can't write %s", TMPPATNAME);
120		filename = TMPPATNAME;
121	}
122	pfp = fopen(filename, "r");
123	if (pfp == NULL)
124		pfatal("patch file %s not found", filename);
125	if (fstat(fileno(pfp), &filestat))
126		pfatal("can't stat %s", filename);
127	p_filesize = filestat.st_size;
128	next_intuit_at(0, 1L);	/* start at the beginning */
129	set_hunkmax();
130}
131
132/*
133 * Make sure our dynamically realloced tables are malloced to begin with.
134 */
135void
136set_hunkmax(void)
137{
138	if (p_line == NULL)
139		p_line = malloc(hunkmax * sizeof(char *));
140	if (p_len == NULL)
141		p_len = malloc(hunkmax * sizeof(unsigned short));
142	if (p_char == NULL)
143		p_char = malloc(hunkmax * sizeof(char));
144}
145
146/*
147 * Enlarge the arrays containing the current hunk of patch.
148 */
149static void
150grow_hunkmax(void)
151{
152	int new_hunkmax = hunkmax * 2;
153
154	if (p_line == NULL || p_len == NULL || p_char == NULL)
155		fatal("Internal memory allocation error\n");
156
157	p_line = reallocf(p_line, new_hunkmax * sizeof(char *));
158	p_len = reallocf(p_len, new_hunkmax * sizeof(unsigned short));
159	p_char = reallocf(p_char, new_hunkmax * sizeof(char));
160
161	if (p_line != NULL && p_len != NULL && p_char != NULL) {
162		hunkmax = new_hunkmax;
163		return;
164	}
165
166	if (!using_plan_a)
167		fatal("out of memory\n");
168	out_of_mem = true;	/* whatever is null will be allocated again */
169				/* from within plan_a(), of all places */
170}
171
172/* True if the remainder of the patch file contains a diff of some sort. */
173
174bool
175there_is_another_patch(void)
176{
177	bool exists = false;
178
179	if (p_base != 0 && p_base >= p_filesize) {
180		if (verbose)
181			say("done\n");
182		return false;
183	}
184	if (p_filesize == 0)
185		return false;
186	nonempty_patchf_seen = true;
187	if (verbose)
188		say("Hmm...");
189	diff_type = intuit_diff_type();
190	if (!diff_type) {
191		if (p_base != 0) {
192			if (verbose)
193				say("  Ignoring the trailing garbage.\ndone\n");
194		} else
195			say("  I can't seem to find a patch in there anywhere.\n");
196		return false;
197	}
198	if (verbose)
199		say("  %sooks like %s to me...\n",
200		    (p_base == 0 ? "L" : "The next patch l"),
201		    diff_type == UNI_DIFF ? "a unified diff" :
202		    diff_type == CONTEXT_DIFF ? "a context diff" :
203		diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
204		    diff_type == NORMAL_DIFF ? "a normal diff" :
205		    "an ed script");
206	if (p_indent && verbose)
207		say("(Patch is indented %d space%s.)\n", p_indent,
208		    p_indent == 1 ? "" : "s");
209	skip_to(p_start, p_sline);
210	while (filearg[0] == NULL) {
211		if (force || batch) {
212			say("No file to patch.  Skipping...\n");
213			filearg[0] = xstrdup(bestguess);
214			skip_rest_of_patch = true;
215			return true;
216		}
217		ask("File to patch: ");
218		if (*buf != '\n') {
219			free(bestguess);
220			bestguess = xstrdup(buf);
221			filearg[0] = fetchname(buf, &exists, 0);
222		}
223		/*
224		 * fetchname can now return buf = NULL, exists = true, to
225		 * indicate to the caller that /dev/null was specified.  Retain
226		 * previous behavior for now until this can be better evaluted.
227		 */
228		if (filearg[0] == NULL || !exists) {
229			int def_skip = *bestguess == '\0';
230			ask("No file found--skip this patch? [%c] ",
231			    def_skip  ? 'y' : 'n');
232			if (*buf == 'n' || (!def_skip && *buf != 'y'))
233				continue;
234			if (verbose)
235				say("Skipping patch...\n");
236			free(filearg[0]);
237			filearg[0] = fetchname(bestguess, &exists, 0);
238			skip_rest_of_patch = true;
239			return true;
240		}
241	}
242	return true;
243}
244
245static void
246p4_fetchname(struct file_name *name, char *str)
247{
248	char *t, *h;
249
250	/* Skip leading whitespace. */
251	while (isspace((unsigned char)*str))
252		str++;
253
254	/* Remove the file revision number. */
255	for (t = str, h = NULL; *t != '\0' && !isspace((unsigned char)*t); t++)
256		if (*t == '#')
257			h = t;
258	if (h != NULL)
259		*h = '\0';
260
261	name->path = fetchname(str, &name->exists, strippath);
262}
263
264/* Determine what kind of diff is in the remaining part of the patch file. */
265
266static int
267intuit_diff_type(void)
268{
269	off_t	this_line = 0, previous_line;
270	off_t	first_command_line = -1;
271	LINENUM	fcl_line = -1;
272	bool	last_line_was_command = false, this_is_a_command = false;
273	bool	stars_last_line = false, stars_this_line = false;
274	char	*s, *t;
275	int	indent, retval;
276	struct file_name names[MAX_FILE];
277	int	piece_of_git = 0;
278
279	memset(names, 0, sizeof(names));
280	ok_to_create_file = false;
281	fseeko(pfp, p_base, SEEK_SET);
282	p_input_line = p_bline - 1;
283	for (;;) {
284		previous_line = this_line;
285		last_line_was_command = this_is_a_command;
286		stars_last_line = stars_this_line;
287		this_line = ftello(pfp);
288		indent = 0;
289		p_input_line++;
290		if (pgets(false) == 0) {
291			if (first_command_line >= 0) {
292				/* nothing but deletes!? */
293				p_start = first_command_line;
294				p_sline = fcl_line;
295				retval = ED_DIFF;
296				goto scan_exit;
297			} else {
298				p_start = this_line;
299				p_sline = p_input_line;
300				retval = 0;
301				goto scan_exit;
302			}
303		}
304		for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
305			if (*s == '\t')
306				indent += 8 - (indent % 8);
307			else
308				indent++;
309		}
310		for (t = s; isdigit((unsigned char)*t) || *t == ','; t++)
311			;
312		this_is_a_command = (isdigit((unsigned char)*s) &&
313		    (*t == 'd' || *t == 'c' || *t == 'a'));
314		if (first_command_line < 0 && this_is_a_command) {
315			first_command_line = this_line;
316			fcl_line = p_input_line;
317			p_indent = indent;	/* assume this for now */
318		}
319		if (!stars_last_line && strnEQ(s, "*** ", 4))
320			names[OLD_FILE].path = fetchname(s + 4,
321			    &names[OLD_FILE].exists, strippath);
322		else if (strnEQ(s, "--- ", 4)) {
323			size_t off = 4;
324			if (piece_of_git && strippath == 957 &&
325			    strnEQ(s, "--- a/", 6))
326				off = 6;
327			names[NEW_FILE].path = fetchname(s + off,
328			    &names[NEW_FILE].exists, strippath);
329		} else if (strnEQ(s, "+++ ", 4)) {
330			/* pretend it is the old name */
331			size_t off = 4;
332			if (piece_of_git && strippath == 957 &&
333			    strnEQ(s, "+++ b/", 6))
334				off = 6;
335			names[OLD_FILE].path = fetchname(s + off,
336			    &names[OLD_FILE].exists, strippath);
337		} else if (strnEQ(s, "Index:", 6))
338			names[INDEX_FILE].path = fetchname(s + 6,
339			    &names[INDEX_FILE].exists, strippath);
340		else if (strnEQ(s, "Prereq:", 7)) {
341			for (t = s + 7; isspace((unsigned char)*t); t++)
342				;
343			revision = xstrdup(t);
344			for (t = revision;
345			     *t && !isspace((unsigned char)*t); t++)
346				;
347			*t = '\0';
348			if (*revision == '\0') {
349				free(revision);
350				revision = NULL;
351			}
352		} else if (strnEQ(s, "diff --git a/", 13)) {
353			/* Git-style diffs. */
354			piece_of_git = 1;
355		} else if (strnEQ(s, "==== ", 5)) {
356			/* Perforce-style diffs. */
357			if ((t = strstr(s + 5, " - ")) != NULL)
358				p4_fetchname(&names[NEW_FILE], t + 3);
359			p4_fetchname(&names[OLD_FILE], s + 5);
360		}
361		if ((!diff_type || diff_type == ED_DIFF) &&
362		    first_command_line >= 0 &&
363		    strEQ(s, ".\n")) {
364			p_indent = indent;
365			p_start = first_command_line;
366			p_sline = fcl_line;
367			retval = ED_DIFF;
368			goto scan_exit;
369		}
370		if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
371			if (strnEQ(s + 4, "0,0", 3))
372				ok_to_create_file = true;
373			p_indent = indent;
374			p_start = this_line;
375			p_sline = p_input_line;
376			retval = UNI_DIFF;
377			goto scan_exit;
378		}
379		stars_this_line = strnEQ(s, "********", 8);
380		if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
381		    strnEQ(s, "*** ", 4)) {
382			if (strtolinenum(s + 4, &s) == 0)
383				ok_to_create_file = true;
384			/*
385			 * If this is a new context diff the character just
386			 * at the end of the line is a '*'.
387			 */
388			while (*s && *s != '\n')
389				s++;
390			p_indent = indent;
391			p_start = previous_line;
392			p_sline = p_input_line - 1;
393			retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
394			goto scan_exit;
395		}
396		if ((!diff_type || diff_type == NORMAL_DIFF) &&
397		    last_line_was_command &&
398		    (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
399			p_start = previous_line;
400			p_sline = p_input_line - 1;
401			p_indent = indent;
402			retval = NORMAL_DIFF;
403			goto scan_exit;
404		}
405	}
406scan_exit:
407	if (retval == UNI_DIFF) {
408		/* unswap old and new */
409		struct file_name tmp = names[OLD_FILE];
410		names[OLD_FILE] = names[NEW_FILE];
411		names[NEW_FILE] = tmp;
412	}
413
414	/* Invalidated */
415	free(source_file);
416	source_file = NULL;
417
418	if (retval != 0) {
419		/*
420		 * If we've successfully determined a diff type, stored in
421		 * retval, path == NULL means _PATH_DEVNULL if exists is set.
422		 * Explicitly specify it here to make it easier to detect later
423		 * on that we're actually creating a file and not that we've
424		 * just goofed something up.
425		 */
426		if (names[OLD_FILE].path != NULL)
427			source_file = xstrdup(names[OLD_FILE].path);
428		else if (names[OLD_FILE].exists)
429			source_file = xstrdup(_PATH_DEVNULL);
430	}
431	if (filearg[0] == NULL) {
432		if (posix)
433			filearg[0] = posix_name(names, ok_to_create_file);
434		else {
435			/* Ignore the Index: name for context diffs, like GNU */
436			if (names[OLD_FILE].path != NULL ||
437			    names[NEW_FILE].path != NULL) {
438				free(names[INDEX_FILE].path);
439				names[INDEX_FILE].path = NULL;
440			}
441			filearg[0] = best_name(names, ok_to_create_file);
442		}
443	}
444
445	free(bestguess);
446	bestguess = NULL;
447	if (filearg[0] != NULL)
448		bestguess = xstrdup(filearg[0]);
449	else if (!ok_to_create_file) {
450		/*
451		 * We don't want to create a new file but we need a
452		 * filename to set bestguess.  Avoid setting filearg[0]
453		 * so the file is not created automatically.
454		 */
455		if (posix)
456			bestguess = posix_name(names, true);
457		else
458			bestguess = best_name(names, true);
459	}
460	free(names[OLD_FILE].path);
461	free(names[NEW_FILE].path);
462	free(names[INDEX_FILE].path);
463	return retval;
464}
465
466/*
467 * Remember where this patch ends so we know where to start up again.
468 */
469static void
470next_intuit_at(off_t file_pos, LINENUM file_line)
471{
472	p_base = file_pos;
473	p_bline = file_line;
474}
475
476/*
477 * Basically a verbose fseeko() to the actual diff listing.
478 */
479static void
480skip_to(off_t file_pos, LINENUM file_line)
481{
482	size_t	len;
483
484	if (p_base > file_pos)
485		fatal("Internal error: seek %lld>%lld\n",
486		   (long long)p_base, (long long)file_pos);
487	if (verbose && p_base < file_pos) {
488		fseeko(pfp, p_base, SEEK_SET);
489		say("The text leading up to this was:\n--------------------------\n");
490		while (ftello(pfp) < file_pos) {
491			len = pgets(false);
492			if (len == 0)
493				fatal("Unexpected end of file\n");
494			say("|%s", buf);
495		}
496		say("--------------------------\n");
497	} else
498		fseeko(pfp, file_pos, SEEK_SET);
499	p_input_line = file_line - 1;
500}
501
502/* Make this a function for better debugging.  */
503static void
504malformed(void)
505{
506	fatal("malformed patch at line %ld: %s", p_input_line, buf);
507	/* about as informative as "Syntax error" in C */
508}
509
510/*
511 * True if the line has been discarded (i.e. it is a line saying
512 *  "\ No newline at end of file".)
513 */
514static bool
515remove_special_line(void)
516{
517	int	c;
518
519	c = fgetc(pfp);
520	if (c == '\\') {
521		do {
522			c = fgetc(pfp);
523		} while (c != EOF && c != '\n');
524
525		return true;
526	}
527	if (c != EOF)
528		fseeko(pfp, -1, SEEK_CUR);
529
530	return false;
531}
532
533/*
534 * True if there is more of the current diff listing to process.
535 */
536bool
537another_hunk(void)
538{
539	off_t	line_beginning;			/* file pos of the current line */
540	LINENUM	repl_beginning;			/* index of --- line */
541	LINENUM	fillcnt;			/* #lines of missing ptrn or repl */
542	LINENUM	fillsrc;			/* index of first line to copy */
543	LINENUM	filldst;			/* index of first missing line */
544	bool	ptrn_spaces_eaten;		/* ptrn was slightly malformed */
545	bool	repl_could_be_missing;		/* no + or ! lines in this hunk */
546	bool	repl_missing;			/* we are now backtracking */
547	off_t	repl_backtrack_position;	/* file pos of first repl line */
548	LINENUM	repl_patch_line;		/* input line number for same */
549	LINENUM	ptrn_copiable;			/* # of copiable lines in ptrn */
550	char	*s;
551	size_t	len;
552	int	context = 0;
553
554	while (p_end >= 0) {
555		if (p_end == p_efake)
556			p_end = p_bfake;	/* don't free twice */
557		else
558			free(p_line[p_end]);
559		p_end--;
560	}
561	p_efake = -1;
562
563	p_max = hunkmax;	/* gets reduced when --- found */
564	if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
565		line_beginning = ftello(pfp);
566		repl_beginning = 0;
567		fillcnt = 0;
568		fillsrc = 0;
569		filldst = 0;
570		ptrn_spaces_eaten = false;
571		repl_could_be_missing = true;
572		repl_missing = false;
573		repl_backtrack_position = 0;
574		repl_patch_line = 0;
575		ptrn_copiable = 0;
576
577		len = pgets(true);
578		p_input_line++;
579		if (len == 0 || strnNE(buf, "********", 8)) {
580			next_intuit_at(line_beginning, p_input_line);
581			return false;
582		}
583		p_context = 100;
584		p_hunk_beg = p_input_line + 1;
585		while (p_end < p_max) {
586			line_beginning = ftello(pfp);
587			len = pgets(true);
588			p_input_line++;
589			if (len == 0) {
590				if (repl_beginning && repl_could_be_missing) {
591					repl_missing = true;
592					goto hunk_done;
593				}
594				fatal("unexpected end of file in patch\n");
595			}
596			p_end++;
597			if (p_end >= hunkmax)
598				fatal("Internal error: hunk larger than hunk "
599				    "buffer size");
600			p_char[p_end] = *buf;
601			p_line[p_end] = NULL;
602			switch (*buf) {
603			case '*':
604				if (strnEQ(buf, "********", 8)) {
605					if (repl_beginning && repl_could_be_missing) {
606						repl_missing = true;
607						goto hunk_done;
608					} else
609						fatal("unexpected end of hunk "
610						    "at line %ld\n",
611						    p_input_line);
612				}
613				if (p_end != 0) {
614					if (repl_beginning && repl_could_be_missing) {
615						repl_missing = true;
616						goto hunk_done;
617					}
618					fatal("unexpected *** at line %ld: %s",
619					    p_input_line, buf);
620				}
621				context = 0;
622				p_line[p_end] = savestr(buf);
623				if (out_of_mem) {
624					p_end--;
625					return false;
626				}
627				for (s = buf;
628				     *s && !isdigit((unsigned char)*s); s++)
629					;
630				if (!*s)
631					malformed();
632				if (strnEQ(s, "0,0", 3))
633					memmove(s, s + 2, strlen(s + 2) + 1);
634				p_first = strtolinenum(s, &s);
635				if (*s == ',') {
636					for (;
637					     *s && !isdigit((unsigned char)*s); s++)
638						;
639					if (!*s)
640						malformed();
641					p_ptrn_lines = strtolinenum(s, &s) - p_first + 1;
642					if (p_ptrn_lines < 0)
643						malformed();
644				} else if (p_first)
645					p_ptrn_lines = 1;
646				else {
647					p_ptrn_lines = 0;
648					p_first = 1;
649				}
650				if (p_first >= LINENUM_MAX - p_ptrn_lines ||
651				    p_ptrn_lines >= LINENUM_MAX - 6)
652					malformed();
653
654				/* we need this much at least */
655				p_max = p_ptrn_lines + 6;
656				while (p_max >= hunkmax)
657					grow_hunkmax();
658				p_max = hunkmax;
659				break;
660			case '-':
661				if (buf[1] == '-') {
662					if (repl_beginning ||
663					    (p_end != p_ptrn_lines + 1 +
664					    (p_char[p_end - 1] == '\n'))) {
665						if (p_end == 1) {
666							/*
667							 * `old' lines were omitted;
668							 * set up to fill them in
669							 * from 'new' context lines.
670							 */
671							p_end = p_ptrn_lines + 1;
672							fillsrc = p_end + 1;
673							filldst = 1;
674							fillcnt = p_ptrn_lines;
675						} else {
676							if (repl_beginning) {
677								if (repl_could_be_missing) {
678									repl_missing = true;
679									goto hunk_done;
680								}
681								fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n",
682								    p_input_line, p_hunk_beg + repl_beginning);
683							} else {
684								fatal("%s \"---\" at line %ld--check line numbers at line %ld\n",
685								    (p_end <= p_ptrn_lines
686								    ? "Premature"
687								    : "Overdue"),
688								    p_input_line, p_hunk_beg);
689							}
690						}
691					}
692					repl_beginning = p_end;
693					repl_backtrack_position = ftello(pfp);
694					repl_patch_line = p_input_line;
695					p_line[p_end] = savestr(buf);
696					if (out_of_mem) {
697						p_end--;
698						return false;
699					}
700					p_char[p_end] = '=';
701					for (s = buf; *s && !isdigit((unsigned char)*s); s++)
702						;
703					if (!*s)
704						malformed();
705					p_newfirst = strtolinenum(s, &s);
706					if (*s == ',') {
707						for (; *s && !isdigit((unsigned char)*s); s++)
708							;
709						if (!*s)
710							malformed();
711						p_repl_lines = strtolinenum(s, &s) -
712						    p_newfirst + 1;
713						if (p_repl_lines < 0)
714							malformed();
715					} else if (p_newfirst)
716						p_repl_lines = 1;
717					else {
718						p_repl_lines = 0;
719						p_newfirst = 1;
720					}
721					if (p_newfirst >= LINENUM_MAX - p_repl_lines ||
722					    p_repl_lines >= LINENUM_MAX - p_end)
723						malformed();
724					p_max = p_repl_lines + p_end;
725					if (p_max > MAXHUNKSIZE)
726						fatal("hunk too large (%ld lines) at line %ld: %s",
727						    p_max, p_input_line, buf);
728					while (p_max >= hunkmax)
729						grow_hunkmax();
730					if (p_repl_lines != ptrn_copiable &&
731					    (p_context != 0 || p_repl_lines != 1))
732						repl_could_be_missing = false;
733					break;
734				}
735				goto change_line;
736			case '+':
737			case '!':
738				repl_could_be_missing = false;
739		change_line:
740				if (buf[1] == '\n' && canonicalize)
741					strlcpy(buf + 1, " \n", buf_size - 1);
742				if (!isspace((unsigned char)buf[1]) &&
743				    buf[1] != '>' && buf[1] != '<' &&
744				    repl_beginning && repl_could_be_missing) {
745					repl_missing = true;
746					goto hunk_done;
747				}
748				if (context >= 0) {
749					if (context < p_context)
750						p_context = context;
751					context = -1000;
752				}
753				p_line[p_end] = savestr(buf + 2);
754				if (out_of_mem) {
755					p_end--;
756					return false;
757				}
758				if (p_end == p_ptrn_lines) {
759					if (remove_special_line()) {
760						int	l;
761
762						l = strlen(p_line[p_end]) - 1;
763						(p_line[p_end])[l] = 0;
764					}
765				}
766				break;
767			case '\t':
768			case '\n':	/* assume the 2 spaces got eaten */
769				if (repl_beginning && repl_could_be_missing &&
770				    (!ptrn_spaces_eaten ||
771				    diff_type == NEW_CONTEXT_DIFF)) {
772					repl_missing = true;
773					goto hunk_done;
774				}
775				p_line[p_end] = savestr(buf);
776				if (out_of_mem) {
777					p_end--;
778					return false;
779				}
780				if (p_end != p_ptrn_lines + 1) {
781					ptrn_spaces_eaten |= (repl_beginning != 0);
782					context++;
783					if (!repl_beginning)
784						ptrn_copiable++;
785					p_char[p_end] = ' ';
786				}
787				break;
788			case ' ':
789				if (!isspace((unsigned char)buf[1]) &&
790				    repl_beginning && repl_could_be_missing) {
791					repl_missing = true;
792					goto hunk_done;
793				}
794				context++;
795				if (!repl_beginning)
796					ptrn_copiable++;
797				p_line[p_end] = savestr(buf + 2);
798				if (out_of_mem) {
799					p_end--;
800					return false;
801				}
802				break;
803			default:
804				if (repl_beginning && repl_could_be_missing) {
805					repl_missing = true;
806					goto hunk_done;
807				}
808				malformed();
809			}
810			/* set up p_len for strncmp() so we don't have to */
811			/* assume null termination */
812			if (p_line[p_end])
813				p_len[p_end] = strlen(p_line[p_end]);
814			else
815				p_len[p_end] = 0;
816		}
817
818hunk_done:
819		if (p_end >= 0 && !repl_beginning)
820			fatal("no --- found in patch at line %ld\n", pch_hunk_beg());
821
822		if (repl_missing) {
823
824			/* reset state back to just after --- */
825			p_input_line = repl_patch_line;
826			for (p_end--; p_end > repl_beginning; p_end--)
827				free(p_line[p_end]);
828			fseeko(pfp, repl_backtrack_position, SEEK_SET);
829
830			/* redundant 'new' context lines were omitted - set */
831			/* up to fill them in from the old file context */
832			if (!p_context && p_repl_lines == 1) {
833				p_repl_lines = 0;
834				p_max--;
835			}
836			fillsrc = 1;
837			filldst = repl_beginning + 1;
838			fillcnt = p_repl_lines;
839			p_end = p_max;
840		} else if (!p_context && fillcnt == 1) {
841			/* the first hunk was a null hunk with no context */
842			/* and we were expecting one line -- fix it up. */
843			while (filldst < p_end) {
844				p_line[filldst] = p_line[filldst + 1];
845				p_char[filldst] = p_char[filldst + 1];
846				p_len[filldst] = p_len[filldst + 1];
847				filldst++;
848			}
849#if 0
850			repl_beginning--;	/* this doesn't need to be fixed */
851#endif
852			p_end--;
853			p_first++;	/* do append rather than insert */
854			fillcnt = 0;
855			p_ptrn_lines = 0;
856		}
857		if (diff_type == CONTEXT_DIFF &&
858		    (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
859			if (verbose)
860				say("%s\n%s\n%s\n",
861				    "(Fascinating--this is really a new-style context diff but without",
862				    "the telltale extra asterisks on the *** line that usually indicate",
863				    "the new style...)");
864			diff_type = NEW_CONTEXT_DIFF;
865		}
866		/* if there were omitted context lines, fill them in now */
867		if (fillcnt) {
868			p_bfake = filldst;	/* remember where not to free() */
869			p_efake = filldst + fillcnt - 1;
870			while (fillcnt-- > 0) {
871				while (fillsrc <= p_end && p_char[fillsrc] != ' ')
872					fillsrc++;
873				if (fillsrc > p_end)
874					fatal("replacement text or line numbers mangled in hunk at line %ld\n",
875					    p_hunk_beg);
876				p_line[filldst] = p_line[fillsrc];
877				p_char[filldst] = p_char[fillsrc];
878				p_len[filldst] = p_len[fillsrc];
879				fillsrc++;
880				filldst++;
881			}
882			while (fillsrc <= p_end && fillsrc != repl_beginning &&
883			    p_char[fillsrc] != ' ')
884				fillsrc++;
885#ifdef DEBUGGING
886			if (debug & 64)
887				printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
888				fillsrc, filldst, repl_beginning, p_end + 1);
889#endif
890			if (fillsrc != p_end + 1 && fillsrc != repl_beginning)
891				malformed();
892			if (filldst != p_end + 1 && filldst != repl_beginning)
893				malformed();
894		}
895		if (p_line[p_end] != NULL) {
896			if (remove_special_line()) {
897				p_len[p_end] -= 1;
898				(p_line[p_end])[p_len[p_end]] = 0;
899			}
900		}
901	} else if (diff_type == UNI_DIFF) {
902		LINENUM	fillold;	/* index of old lines */
903		LINENUM	fillnew;	/* index of new lines */
904		char	ch;
905
906		line_beginning = ftello(pfp); /* file pos of the current line */
907		len = pgets(true);
908		p_input_line++;
909		if (len == 0 || strnNE(buf, "@@ -", 4)) {
910			next_intuit_at(line_beginning, p_input_line);
911			return false;
912		}
913		s = buf + 4;
914		if (!*s)
915			malformed();
916		p_first = strtolinenum(s, &s);
917		if (*s == ',') {
918			p_ptrn_lines = strtolinenum(s + 1, &s);
919		} else
920			p_ptrn_lines = 1;
921		if (*s == ' ')
922			s++;
923		if (*s != '+' || !*++s)
924			malformed();
925		p_newfirst = strtolinenum(s, &s);
926		if (*s == ',') {
927			p_repl_lines = strtolinenum(s + 1, &s);
928		} else
929			p_repl_lines = 1;
930		if (*s == ' ')
931			s++;
932		if (*s != '@')
933			malformed();
934		if (p_first >= LINENUM_MAX - p_ptrn_lines ||
935		    p_newfirst > LINENUM_MAX - p_repl_lines ||
936		    p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1)
937			malformed();
938		if (!p_ptrn_lines)
939			p_first++;	/* do append rather than insert */
940		p_max = p_ptrn_lines + p_repl_lines + 1;
941		while (p_max >= hunkmax)
942			grow_hunkmax();
943		fillold = 1;
944		fillnew = fillold + p_ptrn_lines;
945		p_end = fillnew + p_repl_lines;
946		snprintf(buf, buf_size, "*** %ld,%ld ****\n", p_first,
947		    p_first + p_ptrn_lines - 1);
948		p_line[0] = savestr(buf);
949		if (out_of_mem) {
950			p_end = -1;
951			return false;
952		}
953		p_char[0] = '*';
954		snprintf(buf, buf_size, "--- %ld,%ld ----\n", p_newfirst,
955		    p_newfirst + p_repl_lines - 1);
956		p_line[fillnew] = savestr(buf);
957		if (out_of_mem) {
958			p_end = 0;
959			return false;
960		}
961		p_char[fillnew++] = '=';
962		p_context = 100;
963		context = 0;
964		p_hunk_beg = p_input_line + 1;
965		while (fillold <= p_ptrn_lines || fillnew <= p_end) {
966			line_beginning = ftello(pfp);
967			len = pgets(true);
968			p_input_line++;
969			if (len == 0) {
970				if (p_max - fillnew < 3) {
971					/* assume blank lines got chopped */
972					strlcpy(buf, " \n", buf_size);
973				} else {
974					fatal("unexpected end of file in patch\n");
975				}
976			}
977			if (*buf == '\t' || *buf == '\n') {
978				ch = ' ';	/* assume the space got eaten */
979				s = savestr(buf);
980			} else {
981				ch = *buf;
982				s = savestr(buf + 1);
983			}
984			if (out_of_mem) {
985				while (--fillnew > p_ptrn_lines)
986					free(p_line[fillnew]);
987				p_end = fillold - 1;
988				return false;
989			}
990			switch (ch) {
991			case '-':
992				if (fillold > p_ptrn_lines) {
993					free(s);
994					p_end = fillnew - 1;
995					malformed();
996				}
997				p_char[fillold] = ch;
998				p_line[fillold] = s;
999				p_len[fillold++] = strlen(s);
1000				if (fillold > p_ptrn_lines) {
1001					if (remove_special_line()) {
1002						p_len[fillold - 1] -= 1;
1003						s[p_len[fillold - 1]] = 0;
1004					}
1005				}
1006				break;
1007			case '=':
1008				ch = ' ';
1009				/* FALL THROUGH */
1010			case ' ':
1011				if (fillold > p_ptrn_lines) {
1012					free(s);
1013					while (--fillnew > p_ptrn_lines)
1014						free(p_line[fillnew]);
1015					p_end = fillold - 1;
1016					malformed();
1017				}
1018				context++;
1019				p_char[fillold] = ch;
1020				p_line[fillold] = s;
1021				p_len[fillold++] = strlen(s);
1022				s = savestr(s);
1023				if (out_of_mem) {
1024					while (--fillnew > p_ptrn_lines)
1025						free(p_line[fillnew]);
1026					p_end = fillold - 1;
1027					return false;
1028				}
1029				if (fillold > p_ptrn_lines) {
1030					if (remove_special_line()) {
1031						p_len[fillold - 1] -= 1;
1032						s[p_len[fillold - 1]] = 0;
1033					}
1034				}
1035				/* FALL THROUGH */
1036			case '+':
1037				if (fillnew > p_end) {
1038					free(s);
1039					while (--fillnew > p_ptrn_lines)
1040						free(p_line[fillnew]);
1041					p_end = fillold - 1;
1042					malformed();
1043				}
1044				p_char[fillnew] = ch;
1045				p_line[fillnew] = s;
1046				p_len[fillnew++] = strlen(s);
1047				if (fillold > p_ptrn_lines) {
1048					if (remove_special_line()) {
1049						p_len[fillnew - 1] -= 1;
1050						s[p_len[fillnew - 1]] = 0;
1051					}
1052				}
1053				break;
1054			default:
1055				p_end = fillnew;
1056				malformed();
1057			}
1058			if (ch != ' ' && context > 0) {
1059				if (context < p_context)
1060					p_context = context;
1061				context = -1000;
1062			}
1063		}		/* while */
1064	} else {		/* normal diff--fake it up */
1065		char	hunk_type;
1066		int	i;
1067		LINENUM	min, max;
1068
1069		line_beginning = ftello(pfp);
1070		p_context = 0;
1071		len = pgets(true);
1072		p_input_line++;
1073		if (len == 0 || !isdigit((unsigned char)*buf)) {
1074			next_intuit_at(line_beginning, p_input_line);
1075			return false;
1076		}
1077		p_first = strtolinenum(buf, &s);
1078		if (*s == ',') {
1079			p_ptrn_lines = strtolinenum(s + 1, &s) - p_first + 1;
1080			if (p_ptrn_lines < 0)
1081				malformed();
1082		} else
1083			p_ptrn_lines = (*s != 'a');
1084		hunk_type = *s;
1085		if (hunk_type == 'a')
1086			p_first++;	/* do append rather than insert */
1087		min = strtolinenum(s + 1, &s);
1088		if (*s == ',')
1089			max = strtolinenum(s + 1, &s);
1090		else
1091			max = min;
1092		if (min < 0 || min > max || max - min == LINENUM_MAX)
1093			malformed();
1094		if (hunk_type == 'd')
1095			min++;
1096		p_newfirst = min;
1097		p_repl_lines = max - min + 1;
1098		if (p_newfirst > LINENUM_MAX - p_repl_lines ||
1099		    p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1)
1100			malformed();
1101		p_end = p_ptrn_lines + p_repl_lines + 1;
1102		if (p_end > MAXHUNKSIZE)
1103			fatal("hunk too large (%ld lines) at line %ld: %s",
1104			    p_end, p_input_line, buf);
1105		while (p_end >= hunkmax)
1106			grow_hunkmax();
1107		snprintf(buf, buf_size, "*** %ld,%ld\n", p_first,
1108		    p_first + p_ptrn_lines - 1);
1109		p_line[0] = savestr(buf);
1110		if (out_of_mem) {
1111			p_end = -1;
1112			return false;
1113		}
1114		p_char[0] = '*';
1115		for (i = 1; i <= p_ptrn_lines; i++) {
1116			len = pgets(true);
1117			p_input_line++;
1118			if (len == 0)
1119				fatal("unexpected end of file in patch at line %ld\n",
1120				    p_input_line);
1121			if (*buf != '<')
1122				fatal("< expected at line %ld of patch\n",
1123				    p_input_line);
1124			p_line[i] = savestr(buf + 2);
1125			if (out_of_mem) {
1126				p_end = i - 1;
1127				return false;
1128			}
1129			p_len[i] = strlen(p_line[i]);
1130			p_char[i] = '-';
1131		}
1132
1133		if (remove_special_line()) {
1134			p_len[i - 1] -= 1;
1135			(p_line[i - 1])[p_len[i - 1]] = 0;
1136		}
1137		if (hunk_type == 'c') {
1138			len = pgets(true);
1139			p_input_line++;
1140			if (len == 0)
1141				fatal("unexpected end of file in patch at line %ld\n",
1142				    p_input_line);
1143			if (*buf != '-')
1144				fatal("--- expected at line %ld of patch\n",
1145				    p_input_line);
1146		}
1147		snprintf(buf, buf_size, "--- %ld,%ld\n", min, max);
1148		p_line[i] = savestr(buf);
1149		if (out_of_mem) {
1150			p_end = i - 1;
1151			return false;
1152		}
1153		p_char[i] = '=';
1154		for (i++; i <= p_end; i++) {
1155			len = pgets(true);
1156			p_input_line++;
1157			if (len == 0)
1158				fatal("unexpected end of file in patch at line %ld\n",
1159				    p_input_line);
1160			if (*buf != '>')
1161				fatal("> expected at line %ld of patch\n",
1162				    p_input_line);
1163			/* Don't overrun if we don't have enough line */
1164			if (len > 2)
1165				p_line[i] = savestr(buf + 2);
1166			else
1167				p_line[i] = savestr("");
1168
1169			if (out_of_mem) {
1170				p_end = i - 1;
1171				return false;
1172			}
1173			p_len[i] = strlen(p_line[i]);
1174			p_char[i] = '+';
1175		}
1176
1177		if (remove_special_line()) {
1178			p_len[i - 1] -= 1;
1179			(p_line[i - 1])[p_len[i - 1]] = 0;
1180		}
1181	}
1182	if (reverse)		/* backwards patch? */
1183		if (!pch_swap())
1184			say("Not enough memory to swap next hunk!\n");
1185#ifdef DEBUGGING
1186	if (debug & 2) {
1187		LINENUM	i;
1188		char	special;
1189
1190		for (i = 0; i <= p_end; i++) {
1191			if (i == p_ptrn_lines)
1192				special = '^';
1193			else
1194				special = ' ';
1195			fprintf(stderr, "%3ld %c %c %s", i, p_char[i],
1196			    special, p_line[i]);
1197			fflush(stderr);
1198		}
1199	}
1200#endif
1201	if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
1202		p_char[p_end + 1] = '^';	/* add a stopper for apply_hunk */
1203	return true;
1204}
1205
1206/*
1207 * Input a line from the patch file.
1208 * Worry about indentation if do_indent is true.
1209 * The line is read directly into the buf global variable which
1210 * is resized if necessary in order to hold the complete line.
1211 * Returns the number of characters read including the terminating
1212 * '\n', if any.
1213 */
1214size_t
1215pgets(bool do_indent)
1216{
1217	char *line;
1218	size_t len;
1219	int indent = 0, skipped = 0;
1220
1221	line = fgetln(pfp, &len);
1222	if (line != NULL) {
1223		if (len + 1 > buf_size) {
1224			while (len + 1 > buf_size)
1225				buf_size *= 2;
1226			free(buf);
1227			buf = malloc(buf_size);
1228			if (buf == NULL)
1229				fatal("out of memory\n");
1230		}
1231		if (do_indent == 1 && p_indent) {
1232			for (;
1233			    indent < p_indent && (*line == ' ' || *line == '\t' || *line == 'X');
1234			    line++, skipped++) {
1235				if (*line == '\t')
1236					indent += 8 - (indent %7);
1237				else
1238					indent++;
1239			}
1240		}
1241		memcpy(buf, line, len - skipped);
1242		buf[len - skipped] = '\0';
1243	}
1244	return len;
1245}
1246
1247
1248/*
1249 * Reverse the old and new portions of the current hunk.
1250 */
1251bool
1252pch_swap(void)
1253{
1254	char	**tp_line;	/* the text of the hunk */
1255	unsigned short	*tp_len;/* length of each line */
1256	char	*tp_char;	/* +, -, and ! */
1257	LINENUM	i;
1258	LINENUM	n;
1259	bool	blankline = false;
1260	char	*s;
1261
1262	i = p_first;
1263	p_first = p_newfirst;
1264	p_newfirst = i;
1265
1266	/* make a scratch copy */
1267
1268	tp_line = p_line;
1269	tp_len = p_len;
1270	tp_char = p_char;
1271	p_line = NULL;	/* force set_hunkmax to allocate again */
1272	p_len = NULL;
1273	p_char = NULL;
1274	set_hunkmax();
1275	if (p_line == NULL || p_len == NULL || p_char == NULL) {
1276
1277		free(p_line);
1278		p_line = tp_line;
1279		free(p_len);
1280		p_len = tp_len;
1281		free(p_char);
1282		p_char = tp_char;
1283		return false;	/* not enough memory to swap hunk! */
1284	}
1285	/* now turn the new into the old */
1286
1287	i = p_ptrn_lines + 1;
1288	if (tp_char[i] == '\n') {	/* account for possible blank line */
1289		blankline = true;
1290		i++;
1291	}
1292	if (p_efake >= 0) {	/* fix non-freeable ptr range */
1293		if (p_efake <= i)
1294			n = p_end - i + 1;
1295		else
1296			n = -i;
1297		p_efake += n;
1298		p_bfake += n;
1299	}
1300	for (n = 0; i <= p_end; i++, n++) {
1301		p_line[n] = tp_line[i];
1302		p_char[n] = tp_char[i];
1303		if (p_char[n] == '+')
1304			p_char[n] = '-';
1305		p_len[n] = tp_len[i];
1306	}
1307	if (blankline) {
1308		i = p_ptrn_lines + 1;
1309		p_line[n] = tp_line[i];
1310		p_char[n] = tp_char[i];
1311		p_len[n] = tp_len[i];
1312		n++;
1313	}
1314	if (p_char[0] != '=')
1315		fatal("Malformed patch at line %ld: expected '=' found '%c'\n",
1316		    p_input_line, p_char[0]);
1317	p_char[0] = '*';
1318	for (s = p_line[0]; *s; s++)
1319		if (*s == '-')
1320			*s = '*';
1321
1322	/* now turn the old into the new */
1323
1324	if (p_char[0] != '*')
1325		fatal("Malformed patch at line %ld: expected '*' found '%c'\n",
1326		    p_input_line, p_char[0]);
1327	tp_char[0] = '=';
1328	for (s = tp_line[0]; *s; s++)
1329		if (*s == '*')
1330			*s = '-';
1331	for (i = 0; n <= p_end; i++, n++) {
1332		p_line[n] = tp_line[i];
1333		p_char[n] = tp_char[i];
1334		if (p_char[n] == '-')
1335			p_char[n] = '+';
1336		p_len[n] = tp_len[i];
1337	}
1338
1339	if (i != p_ptrn_lines + 1)
1340		fatal("Malformed patch at line %ld: expected %ld lines, "
1341		    "got %ld\n",
1342		    p_input_line, p_ptrn_lines + 1, i);
1343
1344	i = p_ptrn_lines;
1345	p_ptrn_lines = p_repl_lines;
1346	p_repl_lines = i;
1347
1348	free(tp_line);
1349	free(tp_len);
1350	free(tp_char);
1351
1352	return true;
1353}
1354
1355/*
1356 * Return the specified line position in the old file of the old context.
1357 */
1358LINENUM
1359pch_first(void)
1360{
1361	return p_first;
1362}
1363
1364/*
1365 * Return the number of lines of old context.
1366 */
1367LINENUM
1368pch_ptrn_lines(void)
1369{
1370	return p_ptrn_lines;
1371}
1372
1373/*
1374 * Return the probable line position in the new file of the first line.
1375 */
1376LINENUM
1377pch_newfirst(void)
1378{
1379	return p_newfirst;
1380}
1381
1382/*
1383 * Return the number of lines in the replacement text including context.
1384 */
1385LINENUM
1386pch_repl_lines(void)
1387{
1388	return p_repl_lines;
1389}
1390
1391/*
1392 * Return the number of lines in the whole hunk.
1393 */
1394LINENUM
1395pch_end(void)
1396{
1397	return p_end;
1398}
1399
1400/*
1401 * Return the number of context lines before the first changed line.
1402 */
1403LINENUM
1404pch_context(void)
1405{
1406	return p_context;
1407}
1408
1409/*
1410 * Return the length of a particular patch line.
1411 */
1412unsigned short
1413pch_line_len(LINENUM line)
1414{
1415	return p_len[line];
1416}
1417
1418/*
1419 * Return the control character (+, -, *, !, etc) for a patch line.
1420 */
1421char
1422pch_char(LINENUM line)
1423{
1424	return p_char[line];
1425}
1426
1427/*
1428 * Return a pointer to a particular patch line.
1429 */
1430char *
1431pfetch(LINENUM line)
1432{
1433	return p_line[line];
1434}
1435
1436/*
1437 * Return where in the patch file this hunk began, for error messages.
1438 */
1439LINENUM
1440pch_hunk_beg(void)
1441{
1442	return p_hunk_beg;
1443}
1444
1445/*
1446 * Apply an ed script by feeding ed itself.
1447 */
1448void
1449do_ed_script(void)
1450{
1451	char	*t;
1452	off_t	beginning_of_this_line;
1453	FILE	*pipefp = NULL;
1454	int	continuation;
1455
1456	if (!skip_rest_of_patch) {
1457		if (copy_file(filearg[0], TMPOUTNAME) < 0) {
1458			unlink(TMPOUTNAME);
1459			fatal("can't create temp file %s", TMPOUTNAME);
1460		}
1461		snprintf(buf, buf_size, "%s%s%s", _PATH_RED,
1462		    verbose ? " " : " -s ", TMPOUTNAME);
1463		pipefp = popen(buf, "w");
1464	}
1465	for (;;) {
1466		beginning_of_this_line = ftello(pfp);
1467		if (pgets(true) == 0) {
1468			next_intuit_at(beginning_of_this_line, p_input_line);
1469			break;
1470		}
1471		p_input_line++;
1472		for (t = buf; isdigit((unsigned char)*t) || *t == ','; t++)
1473			;
1474		/* POSIX defines allowed commands as {a,c,d,i,s} */
1475		if (isdigit((unsigned char)*buf) &&
1476		    (*t == 'a' || *t == 'c' || *t == 'd' || *t == 'i' || *t == 's')) {
1477			if (pipefp != NULL)
1478				fputs(buf, pipefp);
1479			if (*t == 's') {
1480				for (;;) {
1481					continuation = 0;
1482					t = strchr(buf, '\0') - 1;
1483					while (--t >= buf && *t == '\\')
1484						continuation = !continuation;
1485					if (!continuation ||
1486					    pgets(true) == 0)
1487						break;
1488					if (pipefp != NULL)
1489						fputs(buf, pipefp);
1490				}
1491			} else if (*t != 'd') {
1492				while (pgets(true)) {
1493					p_input_line++;
1494					if (pipefp != NULL)
1495						fputs(buf, pipefp);
1496					if (strEQ(buf, ".\n"))
1497						break;
1498				}
1499			}
1500		} else {
1501			next_intuit_at(beginning_of_this_line, p_input_line);
1502			break;
1503		}
1504	}
1505	if (pipefp == NULL)
1506		return;
1507	fprintf(pipefp, "w\n");
1508	fprintf(pipefp, "q\n");
1509	fflush(pipefp);
1510	pclose(pipefp);
1511	ignore_signals();
1512	if (!check_only) {
1513		if (move_file(TMPOUTNAME, outname) < 0) {
1514			toutkeep = true;
1515			chmod(TMPOUTNAME, filemode);
1516		} else
1517			chmod(outname, filemode);
1518	}
1519	set_signals(1);
1520}
1521
1522/*
1523 * Choose the name of the file to be patched based on POSIX rules.
1524 * NOTE: the POSIX rules are amazingly stupid and we only follow them
1525 *       if the user specified --posix or set POSIXLY_CORRECT.
1526 */
1527static char *
1528posix_name(const struct file_name *names, bool assume_exists)
1529{
1530	char *path = NULL;
1531	int i;
1532
1533	/*
1534	 * POSIX states that the filename will be chosen from one
1535	 * of the old, new and index names (in that order) if
1536	 * the file exists relative to CWD after -p stripping.
1537	 */
1538	for (i = 0; i < MAX_FILE; i++) {
1539		if (names[i].path != NULL && names[i].exists) {
1540			path = names[i].path;
1541			break;
1542		}
1543	}
1544	if (path == NULL && !assume_exists) {
1545		/*
1546		 * No files found, check to see if the diff could be
1547		 * creating a new file.
1548		 */
1549		if (path == NULL && ok_to_create_file &&
1550		    names[NEW_FILE].path != NULL)
1551			path = names[NEW_FILE].path;
1552	}
1553
1554	return path ? xstrdup(path) : NULL;
1555}
1556
1557static char *
1558compare_names(const struct file_name *names, bool assume_exists)
1559{
1560	size_t min_components, min_baselen, min_len, tmp;
1561	char *best = NULL;
1562	char *path;
1563	int i;
1564
1565	/*
1566	 * The "best" name is the one with the fewest number of path
1567	 * components, the shortest basename length, and the shortest
1568	 * overall length (in that order).  We only use the Index: file
1569	 * if neither of the old or new files could be intuited from
1570	 * the diff header.
1571	 */
1572	min_components = min_baselen = min_len = SIZE_MAX;
1573	for (i = INDEX_FILE; i >= OLD_FILE; i--) {
1574		path = names[i].path;
1575		if (path == NULL || (!names[i].exists && !assume_exists))
1576			continue;
1577		if ((tmp = num_components(path)) > min_components)
1578			continue;
1579		if (tmp < min_components) {
1580			min_components = tmp;
1581			best = path;
1582		}
1583		if ((tmp = strlen(basename(path))) > min_baselen)
1584			continue;
1585		if (tmp < min_baselen) {
1586			min_baselen = tmp;
1587			best = path;
1588		}
1589		if ((tmp = strlen(path)) > min_len)
1590			continue;
1591		min_len = tmp;
1592		best = path;
1593	}
1594	return best;
1595}
1596
1597/*
1598 * Choose the name of the file to be patched based the "best" one
1599 * available.
1600 */
1601static char *
1602best_name(const struct file_name *names, bool assume_exists)
1603{
1604	char *best;
1605
1606	best = compare_names(names, assume_exists);
1607
1608	/* No match?  Check to see if the diff could be creating a new file. */
1609	if (best == NULL && ok_to_create_file)
1610		best = names[NEW_FILE].path;
1611
1612	return best ? xstrdup(best) : NULL;
1613}
1614
1615static size_t
1616num_components(const char *path)
1617{
1618	size_t n;
1619	const char *cp;
1620
1621	for (n = 0, cp = path; (cp = strchr(cp, '/')) != NULL; n++, cp++) {
1622		while (*cp == '/')
1623			cp++;		/* skip consecutive slashes */
1624	}
1625	return n;
1626}
1627
1628/*
1629 * Convert number at NPTR into LINENUM and save address of first
1630 * character that is not a digit in ENDPTR.  If conversion is not
1631 * possible, call fatal.
1632 */
1633static LINENUM
1634strtolinenum(char *nptr, char **endptr)
1635{
1636	LINENUM rv;
1637	char c;
1638	char *p;
1639	const char *errstr;
1640
1641	for (p = nptr; isdigit((unsigned char)*p); p++)
1642		;
1643
1644	if (p == nptr)
1645		malformed();
1646
1647	c = *p;
1648	*p = '\0';
1649
1650	rv = strtonum(nptr, 0, LINENUM_MAX, &errstr);
1651	if (errstr != NULL)
1652		fatal("invalid line number at line %ld: `%s' is %s\n",
1653		    p_input_line, nptr, errstr);
1654
1655	*p = c;
1656	*endptr = p;
1657
1658	return rv;
1659}
1660