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