GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/patch/pch.c Lines: 506 837 60.5 %
Date: 2016-12-06 Branches: 305 655 46.6 %

Line Branch Exec Source
1
/*	$OpenBSD: pch.c,v 1.54 2015/10/16 07:33:47 tobias Exp $	*/
2
3
/*
4
 * patch - a program to apply diffs to original files
5
 *
6
 * Copyright 1986, Larry Wall
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following condition is met:
10
 * 1. Redistributions of source code must retain the above copyright notice,
11
 * this condition and the following disclaimer.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
14
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
17
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
 * SUCH DAMAGE.
24
 *
25
 * -C option added in 1998, original code by Marc Espie, based on FreeBSD
26
 * behaviour
27
 */
28
29
#include <sys/types.h>
30
#include <sys/stat.h>
31
32
#include <ctype.h>
33
#include <libgen.h>
34
#include <limits.h>
35
#include <stdint.h>
36
#include <stdio.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <unistd.h>
40
41
#include "common.h"
42
#include "util.h"
43
#include "pch.h"
44
#include "pathnames.h"
45
46
/* Patch (diff listing) abstract type. */
47
48
FILE	*pfp = NULL;		/* patch file pointer */
49
LINENUM	 p_input_line = 0;	/* current line # from patch file */
50
51
static off_t	p_filesize;	/* size of the patch file */
52
static LINENUM	p_first;	/* 1st line number */
53
static LINENUM	p_newfirst;	/* 1st line number of replacement */
54
static LINENUM	p_ptrn_lines;	/* # lines in pattern */
55
static LINENUM	p_repl_lines;	/* # lines in replacement text */
56
static LINENUM	p_end = -1;	/* last line in hunk */
57
static LINENUM	p_max;		/* max allowed value of p_end */
58
static LINENUM	p_context = 3;	/* # of context lines */
59
static char	**p_line = NULL;/* the text of the hunk */
60
static short	*p_len = NULL;	/* length of each line */
61
static char	*p_char = NULL;	/* +, -, and ! */
62
static int	hunkmax = INITHUNKMAX;	/* size of above arrays to begin with */
63
static int	p_indent;	/* indent to patch */
64
static off_t	p_base;		/* where to intuit this time */
65
static LINENUM	p_bline;	/* line # of p_base */
66
static off_t	p_start;	/* where intuit found a patch */
67
static LINENUM	p_sline;	/* and the line number for it */
68
static LINENUM	p_hunk_beg;	/* line number of current hunk */
69
static LINENUM	p_efake = -1;	/* end of faked up lines--don't free */
70
static LINENUM	p_bfake = -1;	/* beg of faked up lines */
71
static char	*bestguess = NULL;	/* guess at correct filename */
72
73
static void	grow_hunkmax(void);
74
static int	intuit_diff_type(void);
75
static void	skip_to(off_t, LINENUM);
76
static char	*best_name(const struct file_name *, bool);
77
static char	*posix_name(const struct file_name *, bool);
78
static size_t	num_components(const char *);
79
80
/*
81
 * Prepare to look for the next patch in the patch file.
82
 */
83
void
84
re_patch(void)
85
52
{
86
52
	p_first = 0;
87
52
	p_newfirst = 0;
88
52
	p_ptrn_lines = 0;
89
52
	p_repl_lines = 0;
90
52
	p_end = (LINENUM) - 1;
91
52
	p_max = 0;
92
52
	p_indent = 0;
93
52
}
94
95
/*
96
 * Open the patch file at the beginning of time.
97
 */
98
void
99
open_patch_file(const char *filename)
100
60
{
101
	struct stat filestat;
102
103

60
	if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) {
104
		pfp = fopen(TMPPATNAME, "w");
105
		if (pfp == NULL)
106
			pfatal("can't create %s", TMPPATNAME);
107
		while (fgets(buf, sizeof buf, stdin) != NULL)
108
			fputs(buf, pfp);
109
		fclose(pfp);
110
		filename = TMPPATNAME;
111
	}
112
60
	pfp = fopen(filename, "r");
113
60
	if (pfp == NULL)
114
		pfatal("patch file %s not found", filename);
115

60
	if (fstat(fileno(pfp), &filestat))
116
		pfatal("can't stat %s", filename);
117
60
	p_filesize = filestat.st_size;
118
60
	next_intuit_at(0, 1L);	/* start at the beginning */
119
60
	set_hunkmax();
120
60
}
121
122
/*
123
 * Make sure our dynamically realloced tables are malloced to begin with.
124
 */
125
void
126
set_hunkmax(void)
127
60
{
128
60
	if (p_line == NULL)
129
60
		p_line = calloc((size_t) hunkmax, sizeof(char *));
130
60
	if (p_len == NULL)
131
60
		p_len = calloc((size_t) hunkmax, sizeof(short));
132
60
	if (p_char == NULL)
133
60
		p_char = calloc((size_t) hunkmax, sizeof(char));
134
60
}
135
136
/*
137
 * Enlarge the arrays containing the current hunk of patch.
138
 */
139
static void
140
grow_hunkmax(void)
141
19
{
142
	int		new_hunkmax;
143
	char		**new_p_line;
144
	short		*new_p_len;
145
	char		*new_p_char;
146
147
19
	new_hunkmax = hunkmax * 2;
148
149

19
	if (p_line == NULL || p_len == NULL || p_char == NULL)
150
		fatal("Internal memory allocation error\n");
151
152
19
	new_p_line = reallocarray(p_line, new_hunkmax, sizeof(char *));
153
19
	if (new_p_line == NULL)
154
		free(p_line);
155
156
19
	new_p_len = reallocarray(p_len, new_hunkmax, sizeof(short));
157
19
	if (new_p_len == NULL)
158
		free(p_len);
159
160
19
	new_p_char = reallocarray(p_char, new_hunkmax, sizeof(char));
161
19
	if (new_p_char == NULL)
162
		free(p_char);
163
164
19
	p_char = new_p_char;
165
19
	p_len = new_p_len;
166
19
	p_line = new_p_line;
167
168

19
	if (p_line != NULL && p_len != NULL && p_char != NULL) {
169
19
		hunkmax = new_hunkmax;
170
19
		return;
171
	}
172
173
	if (!using_plan_a)
174
		fatal("out of memory\n");
175
	out_of_mem = true;	/* whatever is null will be allocated again */
176
				/* from within plan_a(), of all places */
177
}
178
179
/* True if the remainder of the patch file contains a diff of some sort. */
180
181
bool
182
there_is_another_patch(void)
183
112
{
184
112
	bool exists = false;
185
186

112
	if (p_base != 0 && p_base >= p_filesize) {
187
52
		if (verbose)
188
			say("done\n");
189
52
		return false;
190
	}
191
60
	if (verbose)
192
		say("Hmm...");
193
60
	diff_type = intuit_diff_type();
194
60
	if (!diff_type) {
195
8
		if (p_base != 0) {
196
			if (verbose)
197
				say("  Ignoring the trailing garbage.\ndone\n");
198
		} else
199
8
			say("  I can't seem to find a patch in there anywhere.\n");
200
8
		return false;
201
	}
202
52
	if (verbose)
203
		say("  %sooks like %s to me...\n",
204
		    (p_base == 0 ? "L" : "The next patch l"),
205
		    diff_type == UNI_DIFF ? "a unified diff" :
206
		    diff_type == CONTEXT_DIFF ? "a context diff" :
207
		diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
208
		    diff_type == NORMAL_DIFF ? "a normal diff" :
209
		    "an ed script");
210

52
	if (p_indent && verbose)
211
		say("(Patch is indented %d space%s.)\n", p_indent,
212
		    p_indent == 1 ? "" : "s");
213
52
	skip_to(p_start, p_sline);
214
52
	while (filearg[0] == NULL) {
215
		if (force || batch) {
216
			say("No file to patch.  Skipping...\n");
217
			filearg[0] = xstrdup(bestguess);
218
			skip_rest_of_patch = true;
219
			return true;
220
		}
221
		ask("File to patch: ");
222
		if (*buf != '\n') {
223
			free(bestguess);
224
			bestguess = xstrdup(buf);
225
			filearg[0] = fetchname(buf, &exists, 0);
226
		}
227
		if (!exists) {
228
			ask("No file found--skip this patch? [n] ");
229
			if (*buf != 'y')
230
				continue;
231
			if (verbose)
232
				say("Skipping patch...\n");
233
			free(filearg[0]);
234
			filearg[0] = fetchname(bestguess, &exists, 0);
235
			skip_rest_of_patch = true;
236
			return true;
237
		}
238
	}
239
52
	return true;
240
}
241
242
/* Determine what kind of diff is in the remaining part of the patch file. */
243
244
static int
245
intuit_diff_type(void)
246
60
{
247
60
	off_t	this_line = 0, previous_line;
248
60
	off_t	first_command_line = -1;
249
60
	LINENUM	fcl_line = -1;
250
60
	bool	last_line_was_command = false, this_is_a_command = false;
251
60
	bool	stars_last_line = false, stars_this_line = false;
252
	char	*s, *t;
253
	int	indent, retval;
254
	struct file_name names[MAX_FILE];
255
256
60
	memset(names, 0, sizeof(names));
257
60
	ok_to_create_file = false;
258
60
	fseeko(pfp, p_base, SEEK_SET);
259
60
	p_input_line = p_bline - 1;
260
	for (;;) {
261
891
		previous_line = this_line;
262
891
		last_line_was_command = this_is_a_command;
263
891
		stars_last_line = stars_this_line;
264
891
		this_line = ftello(pfp);
265
891
		indent = 0;
266
891
		p_input_line++;
267
891
		if (fgets(buf, sizeof buf, pfp) == NULL) {
268
12
			if (first_command_line >= 0) {
269
				/* nothing but deletes!? */
270
4
				p_start = first_command_line;
271
4
				p_sline = fcl_line;
272
4
				retval = ED_DIFF;
273
4
				goto scan_exit;
274
			} else {
275
8
				p_start = this_line;
276
8
				p_sline = p_input_line;
277
8
				retval = 0;
278
8
				goto scan_exit;
279
			}
280
		}
281

1789
		for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
282
910
			if (*s == '\t')
283
689
				indent += 8 - (indent % 8);
284
			else
285
221
				indent++;
286
		}
287
879
		for (t = s; isdigit((unsigned char)*t) || *t == ','; t++)
288
			;
289

879
		this_is_a_command = (isdigit((unsigned char)*s) &&
290
		    (*t == 'd' || *t == 'c' || *t == 'a'));
291

879
		if (first_command_line < 0 && this_is_a_command) {
292
26
			first_command_line = this_line;
293
26
			fcl_line = p_input_line;
294
26
			p_indent = indent;	/* assume this for now */
295
		}
296

892
		if (!stars_last_line && strnEQ(s, "*** ", 4))
297
13
			names[OLD_FILE].path = fetchname(s + 4,
298
			    &names[OLD_FILE].exists, strippath);
299
866
		else if (strnEQ(s, "--- ", 4))
300
26
			names[NEW_FILE].path = fetchname(s + 4,
301
			    &names[NEW_FILE].exists, strippath);
302
840
		else if (strnEQ(s, "+++ ", 4))
303
			/* pretend it is the old name */
304
13
			names[OLD_FILE].path = fetchname(s + 4,
305
			    &names[OLD_FILE].exists, strippath);
306
827
		else if (strnEQ(s, "Index:", 6))
307
			names[INDEX_FILE].path = fetchname(s + 6,
308
			    &names[INDEX_FILE].exists, strippath);
309
827
		else if (strnEQ(s, "Prereq:", 7)) {
310
			for (t = s + 7; isspace((unsigned char)*t); t++)
311
				;
312
			revision = xstrdup(t);
313
			for (t = revision;
314
			    *t && !isspace((unsigned char)*t); t++)
315
				;
316
			*t = '\0';
317
			if (*revision == '\0') {
318
				free(revision);
319
				revision = NULL;
320
			}
321
		}
322

879
		if ((!diff_type || diff_type == ED_DIFF) &&
323
		    first_command_line >= 0 &&
324
		    strEQ(s, ".\n")) {
325
9
			p_indent = indent;
326
9
			p_start = first_command_line;
327
9
			p_sline = fcl_line;
328
9
			retval = ED_DIFF;
329
9
			goto scan_exit;
330
		}
331

870
		if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
332
13
			if (strnEQ(s + 4, "0,0", 3))
333
1
				ok_to_create_file = true;
334
13
			p_indent = indent;
335
13
			p_start = this_line;
336
13
			p_sline = p_input_line;
337
13
			retval = UNI_DIFF;
338
13
			goto scan_exit;
339
		}
340
857
		stars_this_line = strnEQ(s, "********", 8);
341

857
		if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
342
		    strnEQ(s, "*** ", 4)) {
343
13
			if (strtolinenum(s + 4, &s) == 0)
344
1
				ok_to_create_file = true;
345
			/*
346
			 * If this is a new context diff the character just
347
			 * at the end of the line is a '*'.
348
			 */
349
105
			while (*s && *s != '\n')
350
92
				s++;
351
13
			p_indent = indent;
352
13
			p_start = previous_line;
353
13
			p_sline = p_input_line - 1;
354
13
			retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
355
13
			goto scan_exit;
356
		}
357


844
		if ((!diff_type || diff_type == NORMAL_DIFF) &&
358
		    last_line_was_command &&
359
		    (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
360
13
			p_start = previous_line;
361
13
			p_sline = p_input_line - 1;
362
13
			p_indent = indent;
363
13
			retval = NORMAL_DIFF;
364
13
			goto scan_exit;
365
		}
366
	}
367
60
scan_exit:
368
60
	if (retval == UNI_DIFF) {
369
		/* unswap old and new */
370
13
		struct file_name tmp = names[OLD_FILE];
371
13
		names[OLD_FILE] = names[NEW_FILE];
372
13
		names[NEW_FILE] = tmp;
373
	}
374
60
	if (filearg[0] == NULL) {
375
		if (posix)
376
			filearg[0] = posix_name(names, ok_to_create_file);
377
		else {
378
			/* Ignore the Index: name for context diffs, like GNU */
379
			if (names[OLD_FILE].path != NULL ||
380
			    names[NEW_FILE].path != NULL) {
381
				free(names[INDEX_FILE].path);
382
				names[INDEX_FILE].path = NULL;
383
			}
384
			filearg[0] = best_name(names, ok_to_create_file);
385
		}
386
	}
387
388
60
	free(bestguess);
389
60
	bestguess = NULL;
390
60
	if (filearg[0] != NULL)
391
60
		bestguess = xstrdup(filearg[0]);
392
	else if (!ok_to_create_file) {
393
		/*
394
		 * We don't want to create a new file but we need a
395
		 * filename to set bestguess.  Avoid setting filearg[0]
396
		 * so the file is not created automatically.
397
		 */
398
		if (posix)
399
			bestguess = posix_name(names, true);
400
		else
401
			bestguess = best_name(names, true);
402
	}
403
60
	free(names[OLD_FILE].path);
404
60
	free(names[NEW_FILE].path);
405
60
	free(names[INDEX_FILE].path);
406
60
	return retval;
407
}
408
409
/*
410
 * Remember where this patch ends so we know where to start up again.
411
 */
412
void
413
next_intuit_at(off_t file_pos, LINENUM file_line)
414
112
{
415
112
	p_base = file_pos;
416
112
	p_bline = file_line;
417
112
}
418
419
/*
420
 * Basically a verbose fseeko() to the actual diff listing.
421
 */
422
static void
423
skip_to(off_t file_pos, LINENUM file_line)
424
52
{
425
	char	*ret;
426
427
52
	if (p_base > file_pos)
428
		fatal("Internal error: seek %lld>%lld\n",
429
		    (long long)p_base, (long long)file_pos);
430

52
	if (verbose && p_base < file_pos) {
431
		fseeko(pfp, p_base, SEEK_SET);
432
		say("The text leading up to this was:\n--------------------------\n");
433
		while (ftello(pfp) < file_pos) {
434
			ret = fgets(buf, sizeof buf, pfp);
435
			if (ret == NULL)
436
				fatal("Unexpected end of file\n");
437
			say("|%s", buf);
438
		}
439
		say("--------------------------\n");
440
	} else
441
52
		fseeko(pfp, file_pos, SEEK_SET);
442
52
	p_input_line = file_line - 1;
443
52
}
444
445
/* Make this a function for better debugging.  */
446
static void
447
malformed(void)
448
{
449
	fatal("malformed patch at line %ld: %s", p_input_line, buf);
450
	/* about as informative as "Syntax error" in C */
451
}
452
453
/*
454
 * True if the line has been discarded (i.e. it is a line saying
455
 *  "\ No newline at end of file".)
456
 */
457
static bool
458
remove_special_line(void)
459
2081
{
460
	int	c;
461
462
2081
	c = fgetc(pfp);
463
2081
	if (c == '\\') {
464
		do {
465
486
			c = fgetc(pfp);
466
486
		} while (c != EOF && c != '\n');
467
468
18
		return true;
469
	}
470
2063
	if (c != EOF)
471
2026
		fseeko(pfp, -1, SEEK_CUR);
472
473
2063
	return false;
474
}
475
476
/*
477
 * True if there is more of the current diff listing to process.
478
 */
479
bool
480
another_hunk(void)
481
825
{
482
	off_t	line_beginning;			/* file pos of the current line */
483
	LINENUM	repl_beginning;			/* index of --- line */
484
	LINENUM	fillcnt;			/* #lines of missing ptrn or repl */
485
	LINENUM	fillsrc;			/* index of first line to copy */
486
	LINENUM	filldst;			/* index of first missing line */
487
	bool	ptrn_spaces_eaten;		/* ptrn was slightly misformed */
488
	bool	repl_could_be_missing;		/* no + or ! lines in this hunk */
489
	bool	repl_missing;			/* we are now backtracking */
490
	off_t	repl_backtrack_position;	/* file pos of first repl line */
491
	LINENUM	repl_patch_line;		/* input line number for same */
492
	LINENUM	ptrn_copiable;			/* # of copiable lines in ptrn */
493
	char	*s, *ret;
494
825
	int	context = 0;
495
496
19710
	while (p_end >= 0) {
497
18060
		if (p_end == p_efake)
498
32
			p_end = p_bfake;	/* don't free twice */
499
		else
500
18028
			free(p_line[p_end]);
501
18060
		p_end--;
502
	}
503
825
	p_efake = -1;
504
505
825
	p_max = hunkmax;	/* gets reduced when --- found */
506
825
	if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
507
129
		line_beginning = ftello(pfp);
508
129
		repl_beginning = 0;
509
129
		fillcnt = 0;
510
129
		fillsrc = 0;
511
129
		ptrn_spaces_eaten = false;
512
129
		repl_could_be_missing = true;
513
129
		repl_missing = false;
514
129
		repl_backtrack_position = 0;
515
129
		repl_patch_line = 0;
516
129
		ptrn_copiable = 0;
517
518
129
		ret = pgets(buf, sizeof buf, pfp);
519
129
		p_input_line++;
520

129
		if (ret == NULL || strnNE(buf, "********", 8)) {
521
13
			next_intuit_at(line_beginning, p_input_line);
522
13
			return false;
523
		}
524
116
		p_context = 100;
525
116
		p_hunk_beg = p_input_line + 1;
526
6778
		while (p_end < p_max) {
527
6547
			line_beginning = ftello(pfp);
528
6547
			ret = pgets(buf, sizeof buf, pfp);
529
6547
			p_input_line++;
530
6547
			if (ret == NULL) {
531
2
				if (p_max - p_end < 4) {
532
					/* assume blank lines got chopped */
533
2
					strlcpy(buf, "  \n", sizeof buf);
534
				} else {
535
					if (repl_beginning && repl_could_be_missing) {
536
						repl_missing = true;
537
						goto hunk_done;
538
					}
539
					fatal("unexpected end of file in patch\n");
540
				}
541
			}
542
6547
			p_end++;
543
6547
			if (p_end >= hunkmax)
544
				fatal("Internal error: hunk larger than hunk "
545
				    "buffer size");
546
6547
			p_char[p_end] = *buf;
547
6547
			p_line[p_end] = NULL;
548

6547
			switch (*buf) {
549
			case '*':
550
117
				if (strnEQ(buf, "********", 8)) {
551

1
					if (repl_beginning && repl_could_be_missing) {
552
1
						repl_missing = true;
553
1
						goto hunk_done;
554
					} else
555
						fatal("unexpected end of hunk "
556
						    "at line %ld\n",
557
						    p_input_line);
558
				}
559
116
				if (p_end != 0) {
560
					if (repl_beginning && repl_could_be_missing) {
561
						repl_missing = true;
562
						goto hunk_done;
563
					}
564
					fatal("unexpected *** at line %ld: %s",
565
					    p_input_line, buf);
566
				}
567
116
				context = 0;
568
116
				p_line[p_end] = savestr(buf);
569
116
				if (out_of_mem) {
570
					p_end--;
571
					return false;
572
				}
573
116
				for (s = buf;
574
116
				    *s && !isdigit((unsigned char)*s); s++)
575
					;
576
116
				if (!*s)
577
					malformed();
578
116
				if (strnEQ(s, "0,0", 3))
579
					memmove(s, s + 2, strlen(s + 2) + 1);
580
116
				p_first = strtolinenum(s, &s);
581
116
				if (*s == ',') {
582
114
					for (; *s && !isdigit((unsigned char)*s); s++)
583
						;
584
114
					if (!*s)
585
						malformed();
586
114
					p_ptrn_lines = strtolinenum(s, &s) - p_first + 1;
587
114
					if (p_ptrn_lines < 0)
588
						malformed();
589
2
				} else if (p_first)
590
1
					p_ptrn_lines = 1;
591
				else {
592
1
					p_ptrn_lines = 0;
593
1
					p_first = 1;
594
				}
595

116
				if (p_first >= LINENUM_MAX - p_ptrn_lines ||
596
				    p_ptrn_lines >= LINENUM_MAX - 6)
597
					malformed();
598
599
				/* we need this much at least */
600
116
				p_max = p_ptrn_lines + 6;
601
236
				while (p_max >= hunkmax)
602
4
					grow_hunkmax();
603
116
				p_max = hunkmax;
604
116
				break;
605
			case '-':
606
229
				if (buf[1] == '-') {
607

116
					if (repl_beginning ||
608
					    (p_end != p_ptrn_lines + 1 +
609
					    (p_char[p_end - 1] == '\n'))) {
610
31
						if (p_end == 1) {
611
							/*
612
							 * `old' lines were omitted;
613
							 * set up to fill them in
614
							 * from 'new' context lines.
615
							 */
616
31
							p_end = p_ptrn_lines + 1;
617
31
							fillsrc = p_end + 1;
618
31
							filldst = 1;
619
31
							fillcnt = p_ptrn_lines;
620
						} else {
621
							if (repl_beginning) {
622
								if (repl_could_be_missing) {
623
									repl_missing = true;
624
									goto hunk_done;
625
								}
626
								fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n",
627
								    p_input_line, p_hunk_beg + repl_beginning);
628
							} else {
629
								fatal("%s \"---\" at line %ld--check line numbers at line %ld\n",
630
								    (p_end <= p_ptrn_lines
631
								    ? "Premature"
632
								    : "Overdue"),
633
								    p_input_line, p_hunk_beg);
634
							}
635
						}
636
					}
637
116
					repl_beginning = p_end;
638
116
					repl_backtrack_position = ftello(pfp);
639
116
					repl_patch_line = p_input_line;
640
116
					p_line[p_end] = savestr(buf);
641
116
					if (out_of_mem) {
642
						p_end--;
643
						return false;
644
					}
645
116
					p_char[p_end] = '=';
646
116
					for (s = buf;
647
116
					    *s && !isdigit((unsigned char)*s); s++)
648
						;
649
116
					if (!*s)
650
						malformed();
651
116
					p_newfirst = strtolinenum(s, &s);
652
116
					if (*s == ',') {
653
114
						for (; *s && !isdigit((unsigned char)*s); s++)
654
							;
655
114
						if (!*s)
656
							malformed();
657
114
						p_repl_lines = strtolinenum(s, &s) -
658
						    p_newfirst + 1;
659
114
						if (p_repl_lines < 0)
660
							malformed();
661
2
					} else if (p_newfirst)
662
1
						p_repl_lines = 1;
663
					else {
664
1
						p_repl_lines = 0;
665
1
						p_newfirst = 1;
666
					}
667

116
					if (p_newfirst >= LINENUM_MAX - p_repl_lines ||
668
					    p_repl_lines >= LINENUM_MAX - p_end)
669
						malformed();
670
116
					p_max = p_repl_lines + p_end;
671
116
					if (p_max > MAXHUNKSIZE)
672
						fatal("hunk too large (%ld lines) at line %ld: %s",
673
						    p_max, p_input_line, buf);
674
120
					while (p_max >= hunkmax)
675
4
						grow_hunkmax();
676

116
					if (p_repl_lines != ptrn_copiable &&
677
					    (p_context != 0 || p_repl_lines != 1))
678
112
						repl_could_be_missing = false;
679
					break;
680
				}
681
				goto change_line;
682
			case '+':
683
			case '!':
684
3523
				repl_could_be_missing = false;
685
3636
		change_line:
686

3636
				if (buf[1] == '\n' && canonicalize)
687
					strlcpy(buf + 1, " \n", sizeof buf - 1);
688


3636
				if (!isspace((unsigned char)buf[1]) &&
689
				    buf[1] != '>' && buf[1] != '<' &&
690
				    repl_beginning && repl_could_be_missing) {
691
					repl_missing = true;
692
					goto hunk_done;
693
				}
694
3636
				if (context >= 0) {
695
116
					if (context < p_context)
696
116
						p_context = context;
697
116
					context = -1000;
698
				}
699
3636
				p_line[p_end] = savestr(buf + 2);
700
3636
				if (out_of_mem) {
701
					p_end--;
702
					return false;
703
				}
704
3636
				if (p_end == p_ptrn_lines) {
705
6
					if (remove_special_line()) {
706
						int	len;
707
708
4
						len = strlen(p_line[p_end]) - 1;
709
4
						(p_line[p_end])[len] = 0;
710
					}
711
				}
712
				break;
713
			case '\t':
714
			case '\n':	/* assume the 2 spaces got eaten */
715
				if (repl_beginning && repl_could_be_missing &&
716
				    (!ptrn_spaces_eaten ||
717
				    diff_type == NEW_CONTEXT_DIFF)) {
718
					repl_missing = true;
719
					goto hunk_done;
720
				}
721
				p_line[p_end] = savestr(buf);
722
				if (out_of_mem) {
723
					p_end--;
724
					return false;
725
				}
726
				if (p_end != p_ptrn_lines + 1) {
727
					ptrn_spaces_eaten |= (repl_beginning != 0);
728
					context++;
729
					if (!repl_beginning)
730
						ptrn_copiable++;
731
					p_char[p_end] = ' ';
732
				}
733
				break;
734
			case ' ':
735

2678
				if (!isspace((unsigned char)buf[1]) &&
736
				    repl_beginning && repl_could_be_missing) {
737
					repl_missing = true;
738
					goto hunk_done;
739
				}
740
2678
				context++;
741
2678
				if (!repl_beginning)
742
1249
					ptrn_copiable++;
743
2678
				p_line[p_end] = savestr(buf + 2);
744
2678
				if (out_of_mem) {
745
					p_end--;
746
					return false;
747
				}
748
				break;
749
			default:
750
				if (repl_beginning && repl_could_be_missing) {
751
					repl_missing = true;
752
					goto hunk_done;
753
				}
754
				malformed();
755
			}
756
			/* set up p_len for strncmp() so we don't have to */
757
			/* assume null termination */
758
6546
			if (p_line[p_end])
759
6546
				p_len[p_end] = strlen(p_line[p_end]);
760
			else
761
				p_len[p_end] = 0;
762
		}
763
764
116
hunk_done:
765
116
		if (p_end >= 0 && !repl_beginning)
766
			fatal("no --- found in patch at line %ld\n", pch_hunk_beg());
767
768
116
		if (repl_missing) {
769
770
			/* reset state back to just after --- */
771
1
			p_input_line = repl_patch_line;
772
1
			for (p_end--; p_end > repl_beginning; p_end--)
773
				free(p_line[p_end]);
774
1
			fseeko(pfp, repl_backtrack_position, SEEK_SET);
775
776
			/* redundant 'new' context lines were omitted - set */
777
			/* up to fill them in from the old file context */
778

1
			if (!p_context && p_repl_lines == 1) {
779
				p_repl_lines = 0;
780
				p_max--;
781
			}
782
1
			fillsrc = 1;
783
1
			filldst = repl_beginning + 1;
784
1
			fillcnt = p_repl_lines;
785
1
			p_end = p_max;
786
115
		} else if (!p_context && fillcnt == 1) {
787
			/* the first hunk was a null hunk with no context */
788
			/* and we were expecting one line -- fix it up. */
789
			while (filldst < p_end) {
790
				p_line[filldst] = p_line[filldst + 1];
791
				p_char[filldst] = p_char[filldst + 1];
792
				p_len[filldst] = p_len[filldst + 1];
793
				filldst++;
794
			}
795
#if 0
796
			repl_beginning--;	/* this doesn't need to be fixed */
797
#endif
798
			p_end--;
799
			p_first++;	/* do append rather than insert */
800
			fillcnt = 0;
801
			p_ptrn_lines = 0;
802
		}
803


116
		if (diff_type == CONTEXT_DIFF &&
804
		    (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
805
			if (verbose)
806
				say("%s\n%s\n%s\n",
807
				    "(Fascinating--this is really a new-style context diff but without",
808
				    "the telltale extra asterisks on the *** line that usually indicate",
809
				    "the new style...)");
810
			diff_type = NEW_CONTEXT_DIFF;
811
		}
812
		/* if there were omitted context lines, fill them in now */
813
116
		if (fillcnt) {
814
32
			p_bfake = filldst;	/* remember where not to free() */
815
32
			p_efake = filldst + fillcnt - 1;
816
256
			while (fillcnt-- > 0) {
817

230
				while (fillsrc <= p_end && p_char[fillsrc] != ' ')
818
38
					fillsrc++;
819
192
				if (fillsrc > p_end)
820
					fatal("replacement text or line numbers mangled in hunk at line %ld\n",
821
					    p_hunk_beg);
822
192
				p_line[filldst] = p_line[fillsrc];
823
192
				p_char[filldst] = p_char[fillsrc];
824
192
				p_len[filldst] = p_len[fillsrc];
825
192
				fillsrc++;
826
192
				filldst++;
827
			}
828

33
			while (fillsrc <= p_end && fillsrc != repl_beginning &&
829
			    p_char[fillsrc] != ' ')
830
1
				fillsrc++;
831
#ifdef DEBUGGING
832
32
			if (debug & 64)
833
				printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
834
				fillsrc, filldst, repl_beginning, p_end + 1);
835
#endif
836
32
			if (fillsrc != p_end + 1 && fillsrc != repl_beginning)
837
				malformed();
838
32
			if (filldst != p_end + 1 && filldst != repl_beginning)
839
				malformed();
840
		}
841
116
		if (p_line[p_end] != NULL) {
842
116
			if (remove_special_line()) {
843
2
				p_len[p_end] -= 1;
844
2
				(p_line[p_end])[p_len[p_end]] = 0;
845
			}
846
		}
847
696
	} else if (diff_type == UNI_DIFF) {
848
129
		off_t	line_beginning = ftello(pfp); /* file pos of the current line */
849
		LINENUM	fillsrc;	/* index of old lines */
850
		LINENUM	filldst;	/* index of new lines */
851
		char	ch;
852
853
129
		ret = pgets(buf, sizeof buf, pfp);
854
129
		p_input_line++;
855

129
		if (ret == NULL || strnNE(buf, "@@ -", 4)) {
856
13
			next_intuit_at(line_beginning, p_input_line);
857
13
			return false;
858
		}
859
116
		s = buf + 4;
860
116
		if (!*s)
861
			malformed();
862
116
		p_first = strtolinenum(s, &s);
863
116
		if (*s == ',') {
864
115
			p_ptrn_lines = strtolinenum(s + 1, &s);
865
		} else
866
1
			p_ptrn_lines = 1;
867
116
		if (*s == ' ')
868
116
			s++;
869

116
		if (*s != '+' || !*++s)
870
			malformed();
871
116
		p_newfirst = strtolinenum(s, &s);
872
116
		if (*s == ',') {
873
115
			p_repl_lines = strtolinenum(s + 1, &s);
874
		} else
875
1
			p_repl_lines = 1;
876
116
		if (*s == ' ')
877
116
			s++;
878
116
		if (*s != '@')
879
			malformed();
880

116
		if (p_first >= LINENUM_MAX - p_ptrn_lines ||
881
		    p_newfirst > LINENUM_MAX - p_repl_lines ||
882
		    p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1)
883
			malformed();
884
116
		if (!p_ptrn_lines)
885
1
			p_first++;	/* do append rather than insert */
886
116
		p_max = p_ptrn_lines + p_repl_lines + 1;
887
240
		while (p_max >= hunkmax)
888
8
			grow_hunkmax();
889
116
		fillsrc = 1;
890
116
		filldst = fillsrc + p_ptrn_lines;
891
116
		p_end = filldst + p_repl_lines;
892
116
		snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first,
893
		    p_first + p_ptrn_lines - 1);
894
116
		p_line[0] = savestr(buf);
895
116
		if (out_of_mem) {
896
			p_end = -1;
897
			return false;
898
		}
899
116
		p_char[0] = '*';
900
116
		snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,
901
		    p_newfirst + p_repl_lines - 1);
902
116
		p_line[filldst] = savestr(buf);
903
116
		if (out_of_mem) {
904
			p_end = 0;
905
			return false;
906
		}
907
116
		p_char[filldst++] = '=';
908
116
		p_context = 100;
909
116
		context = 0;
910
116
		p_hunk_beg = p_input_line + 1;
911

5303
		while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
912
5071
			line_beginning = ftello(pfp);
913
5071
			ret = pgets(buf, sizeof buf, pfp);
914
5071
			p_input_line++;
915
5071
			if (ret == NULL) {
916
				if (p_max - filldst < 3) {
917
					/* assume blank lines got chopped */
918
					strlcpy(buf, " \n", sizeof buf);
919
				} else {
920
					fatal("unexpected end of file in patch\n");
921
				}
922
			}
923
5071
			if (*buf == '\t' || *buf == '\n') {
924
				ch = ' ';	/* assume the space got eaten */
925
				s = savestr(buf);
926
			} else {
927
5071
				ch = *buf;
928
5071
				s = savestr(buf + 1);
929
			}
930
5071
			if (out_of_mem) {
931
				while (--filldst > p_ptrn_lines)
932
					free(p_line[filldst]);
933
				p_end = fillsrc - 1;
934
				return false;
935
			}
936

5071
			switch (ch) {
937
			case '-':
938
1168
				if (fillsrc > p_ptrn_lines) {
939
					free(s);
940
					p_end = filldst - 1;
941
					malformed();
942
				}
943
1168
				p_char[fillsrc] = ch;
944
1168
				p_line[fillsrc] = s;
945
1168
				p_len[fillsrc++] = strlen(s);
946
1168
				if (fillsrc > p_ptrn_lines) {
947
6
					if (remove_special_line()) {
948
4
						p_len[fillsrc - 1] -= 1;
949
4
						s[p_len[fillsrc - 1]] = 0;
950
					}
951
				}
952
				break;
953
			case '=':
954
				ch = ' ';
955
				/* FALL THROUGH */
956
			case ' ':
957
1435
				if (fillsrc > p_ptrn_lines) {
958
					free(s);
959
					while (--filldst > p_ptrn_lines)
960
						free(p_line[filldst]);
961
					p_end = fillsrc - 1;
962
					malformed();
963
				}
964
1435
				context++;
965
1435
				p_char[fillsrc] = ch;
966
1435
				p_line[fillsrc] = s;
967
1435
				p_len[fillsrc++] = strlen(s);
968
1435
				s = savestr(s);
969
1435
				if (out_of_mem) {
970
					while (--filldst > p_ptrn_lines)
971
						free(p_line[filldst]);
972
					p_end = fillsrc - 1;
973
					return false;
974
				}
975
1435
				if (fillsrc > p_ptrn_lines) {
976
109
					if (remove_special_line()) {
977
						p_len[fillsrc - 1] -= 1;
978
						s[p_len[fillsrc - 1]] = 0;
979
					}
980
				}
981
				/* FALL THROUGH */
982
			case '+':
983
3903
				if (filldst > p_end) {
984
					free(s);
985
					while (--filldst > p_ptrn_lines)
986
						free(p_line[filldst]);
987
					p_end = fillsrc - 1;
988
					malformed();
989
				}
990
3903
				p_char[filldst] = ch;
991
3903
				p_line[filldst] = s;
992
3903
				p_len[filldst++] = strlen(s);
993
3903
				if (fillsrc > p_ptrn_lines) {
994
736
					if (remove_special_line()) {
995
2
						p_len[filldst - 1] -= 1;
996
2
						s[p_len[filldst - 1]] = 0;
997
					}
998
				}
999
				break;
1000
			default:
1001
				p_end = filldst;
1002
				malformed();
1003
			}
1004
5071
			if (ch != ' ' && context > 0) {
1005
110
				if (context < p_context)
1006
110
					p_context = context;
1007
110
				context = -1000;
1008
			}
1009
		}		/* while */
1010
	} else {		/* normal diff--fake it up */
1011
		char	hunk_type;
1012
		int	i;
1013
		LINENUM	min, max;
1014
567
		off_t	line_beginning = ftello(pfp);
1015
1016
567
		p_context = 0;
1017
567
		ret = pgets(buf, sizeof buf, pfp);
1018
567
		p_input_line++;
1019

567
		if (ret == NULL || !isdigit((unsigned char)*buf)) {
1020
13
			next_intuit_at(line_beginning, p_input_line);
1021
13
			return false;
1022
		}
1023
554
		p_first = strtolinenum(buf, &s);
1024
554
		if (*s == ',') {
1025
181
			p_ptrn_lines = strtolinenum(s + 1, &s) - p_first + 1;
1026
181
			if (p_ptrn_lines < 0)
1027
				malformed();
1028
		} else
1029
373
			p_ptrn_lines = (*s != 'a');
1030
554
		if (p_first >= LINENUM_MAX - p_ptrn_lines)
1031
			malformed();
1032
554
		hunk_type = *s;
1033
554
		if (hunk_type == 'a')
1034
124
			p_first++;	/* do append rather than insert */
1035
554
		min = strtolinenum(s + 1, &s);
1036
554
		if (*s == ',')
1037
222
			max = strtolinenum(s + 1, &s);
1038
		else
1039
332
			max = min;
1040

554
		if (min < 0 || min > max || max - min == LINENUM_MAX)
1041
			malformed();
1042
554
		if (hunk_type == 'd')
1043
18
			min++;
1044
554
		p_newfirst = min;
1045
554
		p_repl_lines = max - min + 1;
1046

554
		if (p_newfirst > LINENUM_MAX - p_repl_lines ||
1047
		    p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1)
1048
			malformed();
1049
554
		p_end = p_ptrn_lines + p_repl_lines + 1;
1050
554
		if (p_end > MAXHUNKSIZE)
1051
			fatal("hunk too large (%ld lines) at line %ld: %s",
1052
			    p_end, p_input_line, buf);
1053
557
		while (p_end >= hunkmax)
1054
3
			grow_hunkmax();
1055
554
		snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first,
1056
		    p_first + p_ptrn_lines - 1);
1057
554
		p_line[0] = savestr(buf);
1058
554
		if (out_of_mem) {
1059
			p_end = -1;
1060
			return false;
1061
		}
1062
554
		p_char[0] = '*';
1063
1722
		for (i = 1; i <= p_ptrn_lines; i++) {
1064
1168
			ret = pgets(buf, sizeof buf, pfp);
1065
1168
			p_input_line++;
1066
1168
			if (ret == NULL)
1067
				fatal("unexpected end of file in patch at line %ld\n",
1068
				    p_input_line);
1069
1168
			if (*buf != '<')
1070
				fatal("< expected at line %ld of patch\n",
1071
				    p_input_line);
1072
1168
			p_line[i] = savestr(buf + 2);
1073
1168
			if (out_of_mem) {
1074
				p_end = i - 1;
1075
				return false;
1076
			}
1077
1168
			p_len[i] = strlen(p_line[i]);
1078
1168
			p_char[i] = '-';
1079
		}
1080
1081
554
		if (remove_special_line()) {
1082
4
			p_len[i - 1] -= 1;
1083
4
			(p_line[i - 1])[p_len[i - 1]] = 0;
1084
		}
1085
554
		if (hunk_type == 'c') {
1086
412
			ret = pgets(buf, sizeof buf, pfp);
1087
412
			p_input_line++;
1088
412
			if (ret == NULL)
1089
				fatal("unexpected end of file in patch at line %ld\n",
1090
				    p_input_line);
1091
412
			if (*buf != '-')
1092
				fatal("--- expected at line %ld of patch\n",
1093
				    p_input_line);
1094
		}
1095
554
		snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max);
1096
554
		p_line[i] = savestr(buf);
1097
554
		if (out_of_mem) {
1098
			p_end = i - 1;
1099
			return false;
1100
		}
1101
554
		p_char[i] = '=';
1102
3022
		for (i++; i <= p_end; i++) {
1103
2468
			ret = pgets(buf, sizeof buf, pfp);
1104
2468
			p_input_line++;
1105
2468
			if (ret == NULL)
1106
				fatal("unexpected end of file in patch at line %ld\n",
1107
				    p_input_line);
1108
2468
			if (*buf != '>')
1109
				fatal("> expected at line %ld of patch\n",
1110
				    p_input_line);
1111
2468
			p_line[i] = savestr(buf + 2);
1112
2468
			if (out_of_mem) {
1113
				p_end = i - 1;
1114
				return false;
1115
			}
1116
2468
			p_len[i] = strlen(p_line[i]);
1117
2468
			p_char[i] = '+';
1118
		}
1119
1120
554
		if (remove_special_line()) {
1121
2
			p_len[i - 1] -= 1;
1122
2
			(p_line[i - 1])[p_len[i - 1]] = 0;
1123
		}
1124
	}
1125
786
	if (reverse)		/* backwards patch? */
1126
		if (!pch_swap())
1127
			say("Not enough memory to swap next hunk!\n");
1128
#ifdef DEBUGGING
1129
786
	if (debug & 2) {
1130
		int	i;
1131
		char	special;
1132
1133
		for (i = 0; i <= p_end; i++) {
1134
			if (i == p_ptrn_lines)
1135
				special = '^';
1136
			else
1137
				special = ' ';
1138
			fprintf(stderr, "%3d %c %c %s", i, p_char[i],
1139
			    special, p_line[i]);
1140
			fflush(stderr);
1141
		}
1142
	}
1143
#endif
1144
786
	if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
1145
786
		p_char[p_end + 1] = '^';	/* add a stopper for apply_hunk */
1146
786
	return true;
1147
}
1148
1149
/*
1150
 * Input a line from the patch file, worrying about indentation.
1151
 */
1152
char *
1153
pgets(char *bf, int sz, FILE *fp)
1154
22529
{
1155
22529
	char	*s, *ret = fgets(bf, sz, fp);
1156
22529
	int	indent = 0;
1157
1158
22529
	if (p_indent && ret != NULL) {
1159
		for (s = buf;
1160
		    indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X');
1161
		    s++) {
1162
			if (*s == '\t')
1163
				indent += 8 - (indent % 7);
1164
			else
1165
				indent++;
1166
		}
1167
		if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf))
1168
			fatal("buffer too small in pgets()\n");
1169
	}
1170
22529
	return ret;
1171
}
1172
1173
/*
1174
 * Reverse the old and new portions of the current hunk.
1175
 */
1176
bool
1177
pch_swap(void)
1178
{
1179
	char	**tp_line;	/* the text of the hunk */
1180
	short	*tp_len;	/* length of each line */
1181
	char	*tp_char;	/* +, -, and ! */
1182
	LINENUM	i;
1183
	LINENUM	n;
1184
	bool	blankline = false;
1185
	char	*s;
1186
1187
	i = p_first;
1188
	p_first = p_newfirst;
1189
	p_newfirst = i;
1190
1191
	/* make a scratch copy */
1192
1193
	tp_line = p_line;
1194
	tp_len = p_len;
1195
	tp_char = p_char;
1196
	p_line = NULL;	/* force set_hunkmax to allocate again */
1197
	p_len = NULL;
1198
	p_char = NULL;
1199
	set_hunkmax();
1200
	if (p_line == NULL || p_len == NULL || p_char == NULL) {
1201
1202
		free(p_line);
1203
		p_line = tp_line;
1204
		free(p_len);
1205
		p_len = tp_len;
1206
		free(p_char);
1207
		p_char = tp_char;
1208
		return false;	/* not enough memory to swap hunk! */
1209
	}
1210
	/* now turn the new into the old */
1211
1212
	i = p_ptrn_lines + 1;
1213
	if (tp_char[i] == '\n') {	/* account for possible blank line */
1214
		blankline = true;
1215
		i++;
1216
	}
1217
	if (p_efake >= 0) {	/* fix non-freeable ptr range */
1218
		if (p_efake <= i)
1219
			n = p_end - i + 1;
1220
		else
1221
			n = -i;
1222
		p_efake += n;
1223
		p_bfake += n;
1224
	}
1225
	for (n = 0; i <= p_end; i++, n++) {
1226
		p_line[n] = tp_line[i];
1227
		p_char[n] = tp_char[i];
1228
		if (p_char[n] == '+')
1229
			p_char[n] = '-';
1230
		p_len[n] = tp_len[i];
1231
	}
1232
	if (blankline) {
1233
		i = p_ptrn_lines + 1;
1234
		p_line[n] = tp_line[i];
1235
		p_char[n] = tp_char[i];
1236
		p_len[n] = tp_len[i];
1237
		n++;
1238
	}
1239
	if (p_char[0] != '=')
1240
		fatal("Malformed patch at line %ld: expected '=' found '%c'\n",
1241
		    p_input_line, p_char[0]);
1242
	p_char[0] = '*';
1243
	for (s = p_line[0]; *s; s++)
1244
		if (*s == '-')
1245
			*s = '*';
1246
1247
	/* now turn the old into the new */
1248
1249
	if (p_char[0] != '*')
1250
		fatal("Malformed patch at line %ld: expected '*' found '%c'\n",
1251
		    p_input_line, p_char[0]);
1252
	tp_char[0] = '=';
1253
	for (s = tp_line[0]; *s; s++)
1254
		if (*s == '*')
1255
			*s = '-';
1256
	for (i = 0; n <= p_end; i++, n++) {
1257
		p_line[n] = tp_line[i];
1258
		p_char[n] = tp_char[i];
1259
		if (p_char[n] == '-')
1260
			p_char[n] = '+';
1261
		p_len[n] = tp_len[i];
1262
	}
1263
1264
	if (i != p_ptrn_lines + 1)
1265
		fatal("Malformed patch at line %ld: expected %ld lines, "
1266
		    "got %ld\n",
1267
		    p_input_line, p_ptrn_lines + 1, i);
1268
1269
	i = p_ptrn_lines;
1270
	p_ptrn_lines = p_repl_lines;
1271
	p_repl_lines = i;
1272
1273
	free(tp_line);
1274
	free(tp_len);
1275
	free(tp_char);
1276
1277
	return true;
1278
}
1279
1280
/*
1281
 * Return the specified line position in the old file of the old context.
1282
 */
1283
LINENUM
1284
pch_first(void)
1285
786
{
1286
786
	return p_first;
1287
}
1288
1289
/*
1290
 * Return the number of lines of old context.
1291
 */
1292
LINENUM
1293
pch_ptrn_lines(void)
1294
2232
{
1295
2232
	return p_ptrn_lines;
1296
}
1297
1298
/*
1299
 * Return the probable line position in the new file of the first line.
1300
 */
1301
LINENUM
1302
pch_newfirst(void)
1303
786
{
1304
786
	return p_newfirst;
1305
}
1306
1307
/*
1308
 * Return the number of lines in the replacement text including context.
1309
 */
1310
LINENUM
1311
pch_repl_lines(void)
1312
{
1313
	return p_repl_lines;
1314
}
1315
1316
/*
1317
 * Return the number of lines in the whole hunk.
1318
 */
1319
LINENUM
1320
pch_end(void)
1321
786
{
1322
786
	return p_end;
1323
}
1324
1325
/*
1326
 * Return the number of context lines before the first changed line.
1327
 */
1328
LINENUM
1329
pch_context(void)
1330
1572
{
1331
1572
	return p_context;
1332
}
1333
1334
/*
1335
 * Return the length of a particular patch line.
1336
 */
1337
short
1338
pch_line_len(LINENUM line)
1339
6374
{
1340
6374
	return p_len[line];
1341
}
1342
1343
/*
1344
 * Return the control character (+, -, *, !, etc) for a patch line.
1345
 */
1346
char
1347
pch_char(LINENUM line)
1348
36569
{
1349
36569
	return p_char[line];
1350
}
1351
1352
/*
1353
 * Return a pointer to a particular patch line.
1354
 */
1355
char *
1356
pfetch(LINENUM line)
1357
13778
{
1358
13778
	return p_line[line];
1359
}
1360
1361
/*
1362
 * Return where in the patch file this hunk began, for error messages.
1363
 */
1364
LINENUM
1365
pch_hunk_beg(void)
1366
{
1367
	return p_hunk_beg;
1368
}
1369
1370
/*
1371
 * Choose the name of the file to be patched based on POSIX rules.
1372
 * NOTE: the POSIX rules are amazingly stupid and we only follow them
1373
 *       if the user specified --posix or set POSIXLY_CORRECT.
1374
 */
1375
static char *
1376
posix_name(const struct file_name *names, bool assume_exists)
1377
{
1378
	char *path = NULL;
1379
	int i;
1380
1381
	/*
1382
	 * POSIX states that the filename will be chosen from one
1383
	 * of the old, new and index names (in that order) if
1384
	 * the file exists relative to CWD after -p stripping.
1385
	 */
1386
	for (i = 0; i < MAX_FILE; i++) {
1387
		if (names[i].path != NULL && names[i].exists) {
1388
			path = names[i].path;
1389
			break;
1390
		}
1391
	}
1392
	if (path == NULL && !assume_exists) {
1393
		/*
1394
		 * No files found, check to see if the diff could be
1395
		 * creating a new file.
1396
		 */
1397
		if (path == NULL && ok_to_create_file &&
1398
		    names[NEW_FILE].path != NULL)
1399
			path = names[NEW_FILE].path;
1400
	}
1401
1402
	return path ? xstrdup(path) : NULL;
1403
}
1404
1405
static char *
1406
compare_names(const struct file_name *names, bool assume_exists)
1407
{
1408
	size_t min_components, min_baselen, min_len, tmp;
1409
	char *best = NULL;
1410
	char *path;
1411
	int i;
1412
1413
	/*
1414
	 * The "best" name is the one with the fewest number of path
1415
	 * components, the shortest basename length, and the shortest
1416
	 * overall length (in that order).  We only use the Index: file
1417
	 * if neither of the old or new files could be intuited from
1418
	 * the diff header.
1419
	 */
1420
	min_components = min_baselen = min_len = SIZE_MAX;
1421
	for (i = INDEX_FILE; i >= OLD_FILE; i--) {
1422
		path = names[i].path;
1423
		if (path == NULL || (!names[i].exists && !assume_exists))
1424
			continue;
1425
		if ((tmp = num_components(path)) > min_components)
1426
			continue;
1427
		if (tmp < min_components) {
1428
			min_components = tmp;
1429
			best = path;
1430
		}
1431
		if ((tmp = strlen(basename(path))) > min_baselen)
1432
			continue;
1433
		if (tmp < min_baselen) {
1434
			min_baselen = tmp;
1435
			best = path;
1436
		}
1437
		if ((tmp = strlen(path)) > min_len)
1438
			continue;
1439
		min_len = tmp;
1440
		best = path;
1441
	}
1442
	return best;
1443
}
1444
1445
/*
1446
 * Choose the name of the file to be patched based the "best" one
1447
 * available.
1448
 */
1449
static char *
1450
best_name(const struct file_name *names, bool assume_exists)
1451
{
1452
	char *best;
1453
1454
	best = compare_names(names, assume_exists);
1455
1456
	/* No match?  Check to see if the diff could be creating a new file. */
1457
	if (best == NULL && ok_to_create_file)
1458
		best = names[NEW_FILE].path;
1459
1460
	return best ? xstrdup(best) : NULL;
1461
}
1462
1463
static size_t
1464
num_components(const char *path)
1465
{
1466
	size_t n;
1467
	const char *cp;
1468
1469
	for (n = 0, cp = path; (cp = strchr(cp, '/')) != NULL; n++, cp++) {
1470
		while (*cp == '/')
1471
			cp++;		/* skip consecutive slashes */
1472
	}
1473
	return n;
1474
}
1475
1476
/*
1477
 * Convert number at NPTR into LINENUM and save address of first
1478
 * character that is not a digit in ENDPTR.  If conversion is not
1479
 * possible, call fatal.
1480
 */
1481
LINENUM
1482
strtolinenum(char *nptr, char **endptr)
1483
3182
{
1484
	LINENUM rv;
1485
	char c;
1486
	char *p;
1487
	const char *errstr;
1488
1489
3182
	for (p = nptr; isdigit((unsigned char)*p); p++)
1490
		;
1491
1492
3182
	if (p == nptr)
1493
		malformed();
1494
1495
3182
	c = *p;
1496
3182
	*p = '\0';
1497
1498
3182
	rv = strtonum(nptr, 0, LINENUM_MAX, &errstr);
1499
3182
	if (errstr != NULL)
1500
		fatal("invalid line number at line %ld: `%s' is %s\n",
1501
		    p_input_line, nptr, errstr);
1502
1503
3182
	*p = c;
1504
3182
	*endptr = p;
1505
1506
3182
	return rv;
1507
}