GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/patch/pch.c Lines: 497 839 59.2 %
Date: 2017-11-07 Branches: 321 663 48.4 %

Line Branch Exec Source
1
/*	$OpenBSD: pch.c,v 1.58 2017/05/30 06:55:40 florian 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
{
86
936
	p_first = 0;
87
468
	p_newfirst = 0;
88
468
	p_ptrn_lines = 0;
89
468
	p_repl_lines = 0;
90
468
	p_end = (LINENUM) - 1;
91
468
	p_max = 0;
92
468
	p_indent = 0;
93
468
}
94
95
/*
96
 * Open the patch file at the beginning of time.
97
 */
98
void
99
open_patch_file(const char *filename)
100
{
101
1080
	struct stat filestat;
102
103

1620
	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
540
	pfp = fopen(filename, "r");
113
540
	if (pfp == NULL)
114
		pfatal("patch file %s not found", filename);
115

1620
	if (fstat(fileno(pfp), &filestat))
116
		pfatal("can't stat %s", filename);
117
540
	p_filesize = filestat.st_size;
118
540
	next_intuit_at(0, 1L);	/* start at the beginning */
119
540
	set_hunkmax();
120
540
}
121
122
/*
123
 * Make sure our dynamically realloced tables are malloced to begin with.
124
 */
125
void
126
set_hunkmax(void)
127
{
128
1080
	if (p_line == NULL)
129
540
		p_line = calloc((size_t) hunkmax, sizeof(char *));
130
540
	if (p_len == NULL)
131
540
		p_len = calloc((size_t) hunkmax, sizeof(short));
132
540
	if (p_char == NULL)
133
540
		p_char = calloc((size_t) hunkmax, sizeof(char));
134
540
}
135
136
/*
137
 * Enlarge the arrays containing the current hunk of patch.
138
 */
139
static void
140
grow_hunkmax(void)
141
{
142
	int		new_hunkmax;
143
	char		**new_p_line;
144
	short		*new_p_len;
145
	char		*new_p_char;
146
147
342
	new_hunkmax = hunkmax * 2;
148
149
171
	if (p_line == NULL || p_len == NULL || p_char == NULL)
150
		fatal("Internal memory allocation error\n");
151
152
171
	new_p_line = reallocarray(p_line, new_hunkmax, sizeof(char *));
153
171
	if (new_p_line == NULL)
154
		free(p_line);
155
156
171
	new_p_len = reallocarray(p_len, new_hunkmax, sizeof(short));
157
171
	if (new_p_len == NULL)
158
		free(p_len);
159
160
171
	new_p_char = recallocarray(p_char, hunkmax, new_hunkmax, sizeof(char));
161
171
	if (new_p_char == NULL)
162
		free(p_char);
163
164
171
	p_char = new_p_char;
165
171
	p_len = new_p_len;
166
171
	p_line = new_p_line;
167
168
171
	if (p_line != NULL && p_len != NULL && p_char != NULL) {
169
171
		hunkmax = new_hunkmax;
170
171
		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
171
}
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
{
184
2016
	bool exists = false;
185
186

1476
	if (p_base != 0 && p_base >= p_filesize) {
187
468
		if (verbose)
188
			say("done\n");
189
468
		return false;
190
	}
191
540
	if (verbose)
192
		say("Hmm...");
193
540
	diff_type = intuit_diff_type();
194
540
	if (!diff_type) {
195
72
		if (p_base != 0) {
196
			if (verbose)
197
				say("  Ignoring the trailing garbage.\ndone\n");
198
		} else
199
72
			say("  I can't seem to find a patch in there anywhere.\n");
200
72
		return false;
201
	}
202
468
	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

468
	if (p_indent && verbose)
211
		say("(Patch is indented %d space%s.)\n", p_indent,
212
		    p_indent == 1 ? "" : "s");
213
468
	skip_to(p_start, p_sline);
214
936
	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
			int def_skip = *bestguess == '\0';
229
			ask("No file found--skip this patch? [%c] ",
230
			    def_skip  ? 'y' : 'n');
231
			if (*buf == 'n' || (!def_skip && *buf != 'y'))
232
				continue;
233
			if (verbose)
234
				say("Skipping patch...\n");
235
			free(filearg[0]);
236
			filearg[0] = fetchname(bestguess, &exists, 0);
237
			skip_rest_of_patch = true;
238
			return true;
239
		}
240
	}
241
468
	return true;
242
1008
}
243
244
/* Determine what kind of diff is in the remaining part of the patch file. */
245
246
static int
247
intuit_diff_type(void)
248
{
249
	off_t	this_line = 0, previous_line;
250
	off_t	first_command_line = -1;
251
	LINENUM	fcl_line = -1;
252
	bool	last_line_was_command = false, this_is_a_command = false;
253
	bool	stars_last_line = false, stars_this_line = false;
254
1080
	char	*s, *t;
255
	int	indent, retval;
256
540
	struct file_name names[MAX_FILE];
257
	int	piece_of_git = 0;
258
259
540
	memset(names, 0, sizeof(names));
260
540
	ok_to_create_file = false;
261
540
	fseeko(pfp, p_base, SEEK_SET);
262
540
	p_input_line = p_bline - 1;
263
540
	for (;;) {
264
		previous_line = this_line;
265
8019
		last_line_was_command = this_is_a_command;
266
8019
		stars_last_line = stars_this_line;
267
8019
		this_line = ftello(pfp);
268
		indent = 0;
269
8019
		p_input_line++;
270
8019
		if (fgets(buf, sizeof buf, pfp) == NULL) {
271
108
			if (first_command_line >= 0) {
272
				/* nothing but deletes!? */
273
36
				p_start = first_command_line;
274
36
				p_sline = fcl_line;
275
				retval = ED_DIFF;
276
36
				goto scan_exit;
277
			} else {
278
72
				p_start = this_line;
279
72
				p_sline = p_input_line;
280
				retval = 0;
281
72
				goto scan_exit;
282
			}
283
		}
284

70326
		for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
285
8190
			if (*s == '\t')
286
6201
				indent += 8 - (indent % 8);
287
			else
288
1989
				indent++;
289
		}
290

24651
		for (t = s; isdigit((unsigned char)*t) || *t == ','; t++)
291
			;
292
15822
		this_is_a_command = (isdigit((unsigned char)*s) &&
293

558
		    (*t == 'd' || *t == 'c' || *t == 'a'));
294

8964
		if (first_command_line < 0 && this_is_a_command) {
295
			first_command_line = this_line;
296
234
			fcl_line = p_input_line;
297
234
			p_indent = indent;	/* assume this for now */
298
234
		}
299

15705
		if (!stars_last_line && strnEQ(s, "*** ", 4))
300
234
			names[OLD_FILE].path = fetchname(s + 4,
301
117
			    &names[OLD_FILE].exists, strippath);
302
7794
		else if (strnEQ(s, "--- ", 4)) {
303
			size_t off = 4;
304
234
			if (piece_of_git && strippath == 957)
305
				off = 6;
306
468
			names[NEW_FILE].path = fetchname(s + off,
307
234
			    &names[NEW_FILE].exists, strippath);
308
7794
		} else if (strnEQ(s, "+++ ", 4)) {
309
			/* pretend it is the old name */
310
			size_t off = 4;
311
117
			if (piece_of_git && strippath == 957)
312
				off = 6;
313
234
			names[OLD_FILE].path = fetchname(s + off,
314
117
			    &names[OLD_FILE].exists, strippath);
315
7560
		} else if (strnEQ(s, "Index:", 6))
316
			names[INDEX_FILE].path = fetchname(s + 6,
317
			    &names[INDEX_FILE].exists, strippath);
318
7443
		else if (strnEQ(s, "Prereq:", 7)) {
319
			for (t = s + 7; isspace((unsigned char)*t); t++)
320
				;
321
			revision = xstrdup(t);
322
			for (t = revision;
323
			    *t && !isspace((unsigned char)*t); t++)
324
				;
325
			*t = '\0';
326
			if (*revision == '\0') {
327
				free(revision);
328
				revision = NULL;
329
			}
330
7443
		} else if (strnEQ(s, "diff --git a/", 13))
331
			piece_of_git = 1;
332

22914
		if ((!diff_type || diff_type == ED_DIFF) &&
333
7911
		    first_command_line >= 0 &&
334
7092
		    strEQ(s, ".\n")) {
335
81
			p_indent = indent;
336
81
			p_start = first_command_line;
337
81
			p_sline = fcl_line;
338
			retval = ED_DIFF;
339
81
			goto scan_exit;
340
		}
341

15660
		if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
342
117
			if (strnEQ(s + 4, "0,0", 3))
343
9
				ok_to_create_file = true;
344
117
			p_indent = indent;
345
117
			p_start = this_line;
346
117
			p_sline = p_input_line;
347
			retval = UNI_DIFF;
348
117
			goto scan_exit;
349
		}
350
7713
		stars_this_line = strnEQ(s, "********", 8);
351

15543
		if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
352
117
		    strnEQ(s, "*** ", 4)) {
353
117
			if (strtolinenum(s + 4, &s) == 0)
354
9
				ok_to_create_file = true;
355
			/*
356
			 * If this is a new context diff the character just
357
			 * at the end of the line is a '*'.
358
			 */
359

2718
			while (*s && *s != '\n')
360
828
				s++;
361
117
			p_indent = indent;
362
117
			p_start = previous_line;
363
117
			p_sline = p_input_line - 1;
364
117
			retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
365
117
			goto scan_exit;
366
		}
367

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

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

2205
		if (ret == NULL || strnNE(buf, "********", 8)) {
531
117
			next_intuit_at(line_beginning, p_input_line);
532
117
			return false;
533
		}
534
1044
		p_context = 100;
535
1044
		p_hunk_beg = p_input_line + 1;
536
119916
		while (p_end < p_max) {
537
58923
			line_beginning = ftello(pfp);
538
58923
			ret = pgets(buf, sizeof buf, pfp);
539
58923
			p_input_line++;
540
58923
			if (ret == NULL) {
541
18
				if (p_max - p_end < 4) {
542
					/* assume blank lines got chopped */
543
18
					strlcpy(buf, "  \n", sizeof buf);
544
18
				} else {
545
					if (repl_beginning && repl_could_be_missing) {
546
						repl_missing = true;
547
						goto hunk_done;
548
					}
549
					fatal("unexpected end of file in patch\n");
550
				}
551
			}
552
58923
			p_end++;
553
58923
			if (p_end >= hunkmax)
554
				fatal("Internal error: hunk larger than hunk "
555
				    "buffer size");
556
58923
			p_char[p_end] = *buf;
557
58923
			p_line[p_end] = NULL;
558


58923
			switch (*buf) {
559
			case '*':
560
1053
				if (strnEQ(buf, "********", 8)) {
561

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

5130
					for (; *s && !isdigit((unsigned char)*s); s++)
593
						;
594
1026
					if (!*s)
595
						malformed();
596
1026
					p_ptrn_lines = strtolinenum(s, &s) - p_first + 1;
597
1026
					if (p_ptrn_lines < 0)
598
						malformed();
599
18
				} else if (p_first)
600
					p_ptrn_lines = 1;
601
				else {
602
9
					p_ptrn_lines = 0;
603
					p_first = 1;
604
				}
605
2088
				if (p_first >= LINENUM_MAX - p_ptrn_lines ||
606
1044
				    p_ptrn_lines >= LINENUM_MAX - 6)
607
					malformed();
608
609
				/* we need this much at least */
610
1044
				p_max = p_ptrn_lines + 6;
611
2160
				while (p_max >= hunkmax)
612
36
					grow_hunkmax();
613
1044
				p_max = hunkmax;
614
1044
				break;
615
			case '-':
616
2061
				if (buf[1] == '-') {
617

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

5130
						for (; *s && !isdigit((unsigned char)*s); s++)
664
							;
665
1026
						if (!*s)
666
							malformed();
667
3078
						p_repl_lines = strtolinenum(s, &s) -
668
2052
						    p_newfirst + 1;
669
1026
						if (p_repl_lines < 0)
670
							malformed();
671
18
					} else if (p_newfirst)
672
						p_repl_lines = 1;
673
					else {
674
9
						p_repl_lines = 0;
675
						p_newfirst = 1;
676
					}
677

2088
					if (p_newfirst >= LINENUM_MAX - p_repl_lines ||
678
1044
					    p_repl_lines >= LINENUM_MAX - p_end)
679
						malformed();
680
1044
					p_max = p_repl_lines + p_end;
681
1044
					if (p_max > MAXHUNKSIZE)
682
						fatal("hunk too large (%ld lines) at line %ld: %s",
683
						    p_max, p_input_line, buf);
684
1116
					while (p_max >= hunkmax)
685
36
						grow_hunkmax();
686
1044
					if (p_repl_lines != ptrn_copiable &&
687
1017
					    (p_context != 0 || p_repl_lines != 1))
688
1008
						repl_could_be_missing = false;
689
					break;
690
				}
691
				goto change_line;
692
			case '+':
693
			case '!':
694
31707
				repl_could_be_missing = false;
695
		change_line:
696

32724
				if (buf[1] == '\n' && canonicalize)
697
					strlcpy(buf + 1, " \n", sizeof buf - 1);
698

32724
				if (!isspace((unsigned char)buf[1]) &&
699
				    buf[1] != '>' && buf[1] != '<' &&
700
				    repl_beginning && repl_could_be_missing) {
701
					repl_missing = true;
702
					goto hunk_done;
703
				}
704
32724
				if (context >= 0) {
705
1044
					if (context < p_context)
706
1044
						p_context = context;
707
					context = -1000;
708
1044
				}
709
32724
				p_line[p_end] = savestr(buf + 2);
710
32724
				if (out_of_mem) {
711
					p_end--;
712
					return false;
713
				}
714
32724
				if (p_end == p_ptrn_lines) {
715
54
					if (remove_special_line()) {
716
						int	len;
717
718
36
						len = strlen(p_line[p_end]) - 1;
719
36
						(p_line[p_end])[len] = 0;
720
36
					}
721
				}
722
				break;
723
			case '\t':
724
			case '\n':	/* assume the 2 spaces got eaten */
725
				if (repl_beginning && repl_could_be_missing &&
726
				    (!ptrn_spaces_eaten ||
727
				    diff_type == NEW_CONTEXT_DIFF)) {
728
					repl_missing = true;
729
					goto hunk_done;
730
				}
731
				p_line[p_end] = savestr(buf);
732
				if (out_of_mem) {
733
					p_end--;
734
					return false;
735
				}
736
				if (p_end != p_ptrn_lines + 1) {
737
					ptrn_spaces_eaten |= (repl_beginning != 0);
738
					context++;
739
					if (!repl_beginning)
740
						ptrn_copiable++;
741
					p_char[p_end] = ' ';
742
				}
743
				break;
744
			case ' ':
745

48204
				if (!isspace((unsigned char)buf[1]) &&
746
24102
				    repl_beginning && repl_could_be_missing) {
747
					repl_missing = true;
748
					goto hunk_done;
749
				}
750
24102
				context++;
751
24102
				if (!repl_beginning)
752
11241
					ptrn_copiable++;
753
24102
				p_line[p_end] = savestr(buf + 2);
754
24102
				if (out_of_mem) {
755
					p_end--;
756
					return false;
757
				}
758
				break;
759
			default:
760
				if (repl_beginning && repl_could_be_missing) {
761
					repl_missing = true;
762
					goto hunk_done;
763
				}
764
				malformed();
765
			}
766
			/* set up p_len for strncmp() so we don't have to */
767
			/* assume null termination */
768
58914
			if (p_line[p_end])
769
58914
				p_len[p_end] = strlen(p_line[p_end]);
770
			else
771
				p_len[p_end] = 0;
772
		}
773
774
hunk_done:
775
1044
		if (p_end >= 0 && !repl_beginning)
776
			fatal("no --- found in patch at line %ld\n", pch_hunk_beg());
777
778
1044
		if (repl_missing) {
779
780
			/* reset state back to just after --- */
781
9
			p_input_line = repl_patch_line;
782
18
			for (p_end--; p_end > repl_beginning; p_end--)
783
				free(p_line[p_end]);
784
9
			fseeko(pfp, repl_backtrack_position, SEEK_SET);
785
786
			/* redundant 'new' context lines were omitted - set */
787
			/* up to fill them in from the old file context */
788
9
			if (!p_context && p_repl_lines == 1) {
789
				p_repl_lines = 0;
790
				p_max--;
791
			}
792
			fillsrc = 1;
793
9
			filldst = repl_beginning + 1;
794
9
			fillcnt = p_repl_lines;
795
9
			p_end = p_max;
796
1044
		} else if (!p_context && fillcnt == 1) {
797
			/* the first hunk was a null hunk with no context */
798
			/* and we were expecting one line -- fix it up. */
799
			while (filldst < p_end) {
800
				p_line[filldst] = p_line[filldst + 1];
801
				p_char[filldst] = p_char[filldst + 1];
802
				p_len[filldst] = p_len[filldst + 1];
803
				filldst++;
804
			}
805
#if 0
806
			repl_beginning--;	/* this doesn't need to be fixed */
807
#endif
808
			p_end--;
809
			p_first++;	/* do append rather than insert */
810
			fillcnt = 0;
811
			p_ptrn_lines = 0;
812
		}
813

1044
		if (diff_type == CONTEXT_DIFF &&
814
		    (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
815
			if (verbose)
816
				say("%s\n%s\n%s\n",
817
				    "(Fascinating--this is really a new-style context diff but without",
818
				    "the telltale extra asterisks on the *** line that usually indicate",
819
				    "the new style...)");
820
			diff_type = NEW_CONTEXT_DIFF;
821
		}
822
		/* if there were omitted context lines, fill them in now */
823
1044
		if (fillcnt) {
824
288
			p_bfake = filldst;	/* remember where not to free() */
825
288
			p_efake = filldst + fillcnt - 1;
826
4032
			while (fillcnt-- > 0) {
827

6552
				while (fillsrc <= p_end && p_char[fillsrc] != ' ')
828
342
					fillsrc++;
829
1728
				if (fillsrc > p_end)
830
					fatal("replacement text or line numbers mangled in hunk at line %ld\n",
831
					    p_hunk_beg);
832
1728
				p_line[filldst] = p_line[fillsrc];
833
1728
				p_char[filldst] = p_char[fillsrc];
834
1728
				p_len[filldst] = p_len[fillsrc];
835
1728
				fillsrc++;
836
1728
				filldst++;
837
			}
838

333
			while (fillsrc <= p_end && fillsrc != repl_beginning &&
839
9
			    p_char[fillsrc] != ' ')
840
9
				fillsrc++;
841
#ifdef DEBUGGING
842
288
			if (debug & 64)
843
				printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
844
				fillsrc, filldst, repl_beginning, p_end + 1);
845
#endif
846

297
			if (fillsrc != p_end + 1 && fillsrc != repl_beginning)
847
				malformed();
848

567
			if (filldst != p_end + 1 && filldst != repl_beginning)
849
				malformed();
850
		}
851
1044
		if (p_line[p_end] != NULL) {
852
1044
			if (remove_special_line()) {
853
18
				p_len[p_end] -= 1;
854
18
				(p_line[p_end])[p_len[p_end]] = 0;
855
18
			}
856
		}
857
6264
	} else if (diff_type == UNI_DIFF) {
858
1161
		off_t	line_beginning = ftello(pfp); /* file pos of the current line */
859
		LINENUM	fillsrc;	/* index of old lines */
860
		LINENUM	filldst;	/* index of new lines */
861
		char	ch;
862
863
1161
		ret = pgets(buf, sizeof buf, pfp);
864
1161
		p_input_line++;
865

2205
		if (ret == NULL || strnNE(buf, "@@ -", 4)) {
866
117
			next_intuit_at(line_beginning, p_input_line);
867
117
			return false;
868
		}
869
1044
		s = buf + 4;
870
1044
		if (!*s)
871
			malformed();
872
1044
		p_first = strtolinenum(s, &s);
873
1044
		if (*s == ',') {
874
1035
			p_ptrn_lines = strtolinenum(s + 1, &s);
875
1035
		} else
876
			p_ptrn_lines = 1;
877
1044
		if (*s == ' ')
878
1044
			s++;
879

2088
		if (*s != '+' || !*++s)
880
			malformed();
881
1044
		p_newfirst = strtolinenum(s, &s);
882
1044
		if (*s == ',') {
883
1035
			p_repl_lines = strtolinenum(s + 1, &s);
884
1035
		} else
885
			p_repl_lines = 1;
886
1044
		if (*s == ' ')
887
1044
			s++;
888
1044
		if (*s != '@')
889
			malformed();
890

2088
		if (p_first >= LINENUM_MAX - p_ptrn_lines ||
891
1044
		    p_newfirst > LINENUM_MAX - p_repl_lines ||
892
1044
		    p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1)
893
			malformed();
894
1044
		if (!p_ptrn_lines)
895
9
			p_first++;	/* do append rather than insert */
896
1044
		p_max = p_ptrn_lines + p_repl_lines + 1;
897
2232
		while (p_max >= hunkmax)
898
72
			grow_hunkmax();
899
		fillsrc = 1;
900
1044
		filldst = fillsrc + p_ptrn_lines;
901
1044
		p_end = filldst + p_repl_lines;
902
2088
		snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first,
903
1044
		    p_first + p_ptrn_lines - 1);
904
1044
		p_line[0] = savestr(buf);
905
1044
		if (out_of_mem) {
906
			p_end = -1;
907
			return false;
908
		}
909
1044
		p_char[0] = '*';
910
2088
		snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst,
911
1044
		    p_newfirst + p_repl_lines - 1);
912
1044
		p_line[filldst] = savestr(buf);
913
1044
		if (out_of_mem) {
914
			p_end = 0;
915
			return false;
916
		}
917
1044
		p_char[filldst++] = '=';
918
1044
		p_context = 100;
919
		context = 0;
920
1044
		p_hunk_beg = p_input_line + 1;
921

54414
		while (fillsrc <= p_ptrn_lines || filldst <= p_end) {
922
45639
			line_beginning = ftello(pfp);
923
45639
			ret = pgets(buf, sizeof buf, pfp);
924
45639
			p_input_line++;
925
45639
			if (ret == NULL) {
926
				if (p_max - filldst < 3) {
927
					/* assume blank lines got chopped */
928
					strlcpy(buf, " \n", sizeof buf);
929
				} else {
930
					fatal("unexpected end of file in patch\n");
931
				}
932
			}
933

91278
			if (*buf == '\t' || *buf == '\n') {
934
				ch = ' ';	/* assume the space got eaten */
935
				s = savestr(buf);
936
			} else {
937
				ch = *buf;
938
45639
				s = savestr(buf + 1);
939
			}
940
45639
			if (out_of_mem) {
941
				while (--filldst > p_ptrn_lines)
942
					free(p_line[filldst]);
943
				p_end = fillsrc - 1;
944
				return false;
945
			}
946

58554
			switch (ch) {
947
			case '-':
948
10512
				if (fillsrc > p_ptrn_lines) {
949
					free(s);
950
					p_end = filldst - 1;
951
					malformed();
952
				}
953
10512
				p_char[fillsrc] = ch;
954
10512
				p_line[fillsrc] = s;
955
10512
				p_len[fillsrc++] = strlen(s);
956
10512
				if (fillsrc > p_ptrn_lines) {
957
54
					if (remove_special_line()) {
958
36
						p_len[fillsrc - 1] -= 1;
959
36
						s[p_len[fillsrc - 1]] = 0;
960
36
					}
961
				}
962
				break;
963
			case '=':
964
				ch = ' ';
965
				/* FALL THROUGH */
966
			case ' ':
967
12915
				if (fillsrc > p_ptrn_lines) {
968
					free(s);
969
					while (--filldst > p_ptrn_lines)
970
						free(p_line[filldst]);
971
					p_end = fillsrc - 1;
972
					malformed();
973
				}
974
12915
				context++;
975
12915
				p_char[fillsrc] = ch;
976
12915
				p_line[fillsrc] = s;
977
12915
				p_len[fillsrc++] = strlen(s);
978
12915
				s = savestr(s);
979
12915
				if (out_of_mem) {
980
					while (--filldst > p_ptrn_lines)
981
						free(p_line[filldst]);
982
					p_end = fillsrc - 1;
983
					return false;
984
				}
985
12915
				if (fillsrc > p_ptrn_lines) {
986
981
					if (remove_special_line()) {
987
						p_len[fillsrc - 1] -= 1;
988
						s[p_len[fillsrc - 1]] = 0;
989
					}
990
				}
991
				/* FALL THROUGH */
992
			case '+':
993
35127
				if (filldst > p_end) {
994
					free(s);
995
					while (--filldst > p_ptrn_lines)
996
						free(p_line[filldst]);
997
					p_end = fillsrc - 1;
998
					malformed();
999
				}
1000
35127
				p_char[filldst] = ch;
1001
35127
				p_line[filldst] = s;
1002
35127
				p_len[filldst++] = strlen(s);
1003
35127
				if (fillsrc > p_ptrn_lines) {
1004
6624
					if (remove_special_line()) {
1005
18
						p_len[filldst - 1] -= 1;
1006
18
						s[p_len[filldst - 1]] = 0;
1007
18
					}
1008
				}
1009
				break;
1010
			default:
1011
				p_end = filldst;
1012
				malformed();
1013
			}
1014
45639
			if (ch != ' ' && context > 0) {
1015
990
				if (context < p_context)
1016
990
					p_context = context;
1017
				context = -1000;
1018
990
			}
1019
		}		/* while */
1020
1044
	} else {		/* normal diff--fake it up */
1021
		char	hunk_type;
1022
		int	i;
1023
		LINENUM	min, max;
1024
5103
		off_t	line_beginning = ftello(pfp);
1025
1026
5103
		p_context = 0;
1027
5103
		ret = pgets(buf, sizeof buf, pfp);
1028
5103
		p_input_line++;
1029

10089
		if (ret == NULL || !isdigit((unsigned char)*buf)) {
1030
117
			next_intuit_at(line_beginning, p_input_line);
1031
117
			return false;
1032
		}
1033
4986
		p_first = strtolinenum(buf, &s);
1034
4986
		if (*s == ',') {
1035
1629
			p_ptrn_lines = strtolinenum(s + 1, &s) - p_first + 1;
1036
1629
			if (p_ptrn_lines < 0)
1037
				malformed();
1038
		} else
1039
3357
			p_ptrn_lines = (*s != 'a');
1040
4986
		if (p_first >= LINENUM_MAX - p_ptrn_lines)
1041
			malformed();
1042
4986
		hunk_type = *s;
1043
4986
		if (hunk_type == 'a')
1044
1116
			p_first++;	/* do append rather than insert */
1045
4986
		min = strtolinenum(s + 1, &s);
1046
4986
		if (*s == ',')
1047
1998
			max = strtolinenum(s + 1, &s);
1048
		else
1049
			max = min;
1050

14958
		if (min < 0 || min > max || max - min == LINENUM_MAX)
1051
			malformed();
1052
4986
		if (hunk_type == 'd')
1053
162
			min++;
1054
4986
		p_newfirst = min;
1055
4986
		p_repl_lines = max - min + 1;
1056

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