Ravenports generated: 25 Apr 2018 12:37
[ravenports.git] / bucket_A7 / bsd-patch
1 # Buildsheet autogenerated by ravenadm tool -- Do not edit.
2
3 NAMEBASE=               bsd-patch
4 VERSION=                20170907
5 KEYWORDS=               devel raven
6 VARIANTS=               standard
7 SDESC[standard]=        BSD variant of famous patch program
8 HOMEPAGE=               https://www.freebsd.org/cgi/man.cgi?patch(1)
9 CONTACT=                John_Marino[draco@marino.st]
10
11 DOWNLOAD_GROUPS=        none
12 SPKGS[standard]=        single
13
14 OPTIONS_AVAILABLE=      none
15 OPTIONS_STANDARD=       none
16
17 B_DEPS[sunos]=          libbsd4sol:single:standard
18 B_DEPS[linux]=          libbsd:single:standard
19
20 LICENSE=                CUSTOM1:single
21 LICENSE_NAME=           CUSTOM1:"Patch license from Larry Wall"
22 LICENSE_FILE=           CUSTOM1:{{WRKSRC}}/LICENSE
23 LICENSE_SCHEME=         solo
24
25 do-extract:
26         ${MKDIR} ${WRKSRC}
27         cp ${FILESDIR}/* ${WRKSRC}/
28
29 [FILE:565:descriptions/desc.single]
30 This version of patch comes FreeBSD which means there are heavy influences
31 from DragonFly, OpenBSD and NetBSD as well.
32
33 The primary purpose of this port is to replace GNU patch in the
34 Ravenports system root.  The BSD version of patch correctly locates
35 upwards relative paths such as "--- ../../module3-2.a/configure" while
36 GNU patch fails to find it.  As this is a crucial feature, especially
37 for "extra patches", the GNU patch program has to be replaced.
38
39 The OpenBSD modification of handling git-style patches (the "--- a/" and
40 "+++ b/" formats are also present.
41
42
43 [FILE:36:manifests/plist.single]
44 bin/patch
45 share/man/man1/patch.1.gz
46
47
48 [FILE:1672:files/LICENSE]
49 /*-
50  * Copyright 1986, Larry Wall
51  * 
52  * Redistribution and use in source and binary forms, with or without
53  * modification, are permitted provided that the following condition is met:
54  * 1. Redistributions of source code must retain the above copyright notice,
55  * this condition and the following disclaimer.
56  * 
57  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
58  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
59  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
60  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
61  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
63  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
64  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67  * SUCH DAMAGE.
68  * 
69  * patch - a program to apply diffs to original files
70  *
71  * -C option added in 1998, original code by Marc Espie, based on FreeBSD
72  * behaviour
73  *
74  */
75
76 /*
77  * backupfile -- declarations for making Emacs style backup file names
78  * Copyright (C) 1990 Free Software Foundation, Inc.
79  * 
80  * This program is free software; you can redistribute it and/or modify it
81  * without restriction.
82  * 
83  * This program is distributed in the hope that it will be useful, but WITHOUT
84  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
85  * FITNESS FOR A PARTICULAR PURPOSE.
86  * 
87  */
88
89
90 [FILE:581:files/Makefile]
91 PROG=           patch
92 SRCS=           ${PROG}.c pch.c inp.c util.c backupfile.c mkpath.c \
93                 linux_support.c
94 PREFIX?=        /usr/local
95 CFLAGS+=        -I${PREFIX}/include -I.
96 STATIC_LIBS=    
97
98 .if "${OPSYS}" == "Linux"
99 STATIC_LIBS+=   ${PREFIX}/lib/libbsd.a
100 .endif
101 .if "${OPSYS}" == "SunOS"
102 STATIC_LIBS+=   ${PREFIX}/lib/libbsd.a
103 CFLAGS+=        -I${PREFIX}/include/bsd
104 .endif
105
106 all: ${PROG}
107
108 clean:
109         rm -f ${OBJS} ${PROG}
110
111 ${PROG}: ${SRCS}
112         ${CC} -o ${PROG} ${.ALLSRC} ${CFLAGS} ${STATIC_LIBS}
113
114 install:
115         ${BSD_INSTALL_PROGRAM} ${PROG} ${DESTDIR}${PREFIX}/bin/
116         ${BSD_INSTALL_MAN} ${PROG}.1 ${DESTDIR}${PREFIX}/share/man/man1
117
118
119 [FILE:5856:files/backupfile.c]
120 #include <ctype.h>
121 #include <dirent.h>
122 #include <libgen.h>
123 #include <stdio.h>
124 #include <stdlib.h>
125 #include <string.h>
126 #include <unistd.h>
127
128 #include "backupfile.h"
129 #include "linux_support.h"
130
131
132 #define ISDIGIT(c) (isascii ((unsigned char)c) && isdigit ((unsigned char)c))
133
134 /* Which type of backup file names are generated. */
135 enum backup_type backup_type = none;
136
137 /*
138  * The extension added to file names to produce a simple (as opposed to
139  * numbered) backup file name.
140  */
141 const char      *simple_backup_suffix = "~";
142
143 static char     *concat(const char *, const char *);
144 static char     *make_version_name(const char *, int);
145 static int      max_backup_version(const char *, const char *);
146 static int      version_number(const char *, const char *, size_t);
147 static int      argmatch(const char *, const char **);
148 static void     invalid_arg(const char *, const char *, int);
149
150 /*
151  * Return the name of the new backup file for file FILE, allocated with
152  * malloc.  Return 0 if out of memory. FILE must not end with a '/' unless it
153  * is the root directory. Do not call this function if backup_type == none.
154  */
155 char *
156 find_backup_file_name(const char *file)
157 {
158         char    *dir, *base_versions, *tmp_file;
159         int     highest_backup;
160
161         if (backup_type == simple)
162                 return concat(file, simple_backup_suffix);
163         tmp_file = strdup(file);
164         if (tmp_file == NULL)
165                 return NULL;
166         base_versions = concat(basename(tmp_file), ".~");
167         free(tmp_file);
168         if (base_versions == NULL)
169                 return NULL;
170         tmp_file = strdup(file);
171         if (tmp_file == NULL) {
172                 free(base_versions);
173                 return NULL;
174         }
175         dir = dirname(tmp_file);
176         if (dir == NULL) {
177                 free(base_versions);
178                 free(tmp_file);
179                 return NULL;
180         }
181         highest_backup = max_backup_version(base_versions, dir);
182         free(base_versions);
183         free(tmp_file);
184         if (backup_type == numbered_existing && highest_backup == 0)
185                 return concat(file, simple_backup_suffix);
186         return make_version_name(file, highest_backup + 1);
187 }
188
189 /*
190  * Return the number of the highest-numbered backup file for file FILE in
191  * directory DIR.  If there are no numbered backups of FILE in DIR, or an
192  * error occurs reading DIR, return 0. FILE should already have ".~" appended
193  * to it.
194  */
195 static int
196 max_backup_version(const char *file, const char *dir)
197 {
198         DIR     *dirp;
199         struct dirent   *dp;
200         int     highest_version, this_version;
201         size_t  file_name_length;
202
203         dirp = opendir(dir);
204         if (dirp == NULL)
205                 return 0;
206
207         highest_version = 0;
208         file_name_length = strlen(file);
209
210         while ((dp = readdir(dirp)) != NULL) {
211                 if (strlen(dp->d_name) <= file_name_length)
212                         continue;
213
214                 this_version = version_number(file, dp->d_name, file_name_length);
215                 if (this_version > highest_version)
216                         highest_version = this_version;
217         }
218         closedir(dirp);
219         return highest_version;
220 }
221
222 /*
223  * Return a string, allocated with malloc, containing "FILE.~VERSION~".
224  * Return 0 if out of memory.
225  */
226 static char *
227 make_version_name(const char *file, int version)
228 {
229         char    *backup_name;
230
231         if (asprintf(&backup_name, "%s.~%d~", file, version) == -1)
232                 return NULL;
233         return backup_name;
234 }
235
236 /*
237  * If BACKUP is a numbered backup of BASE, return its version number;
238  * otherwise return 0.  BASE_LENGTH is the length of BASE. BASE should
239  * already have ".~" appended to it.
240  */
241 static int
242 version_number(const char *base, const char *backup, size_t base_length)
243 {
244         int             version;
245         const char      *p;
246
247         version = 0;
248         if (!strncmp(base, backup, base_length) && ISDIGIT(backup[base_length])) {
249                 for (p = &backup[base_length]; ISDIGIT(*p); ++p)
250                         version = version * 10 + *p - '0';
251                 if (p[0] != '~' || p[1])
252                         version = 0;
253         }
254         return version;
255 }
256
257 /*
258  * Return the newly-allocated concatenation of STR1 and STR2. If out of
259  * memory, return 0.
260  */
261 static char  *
262 concat(const char *str1, const char *str2)
263 {
264         char    *newstr;
265
266         if (asprintf(&newstr, "%s%s", str1, str2) == -1)
267                 return NULL;
268         return newstr;
269 }
270
271 /*
272  * If ARG is an unambiguous match for an element of the null-terminated array
273  * OPTLIST, return the index in OPTLIST of the matched element, else -1 if it
274  * does not match any element or -2 if it is ambiguous (is a prefix of more
275  * than one element).
276  */
277 static int
278 argmatch(const char *arg, const char **optlist)
279 {
280         int     i;      /* Temporary index in OPTLIST. */
281         size_t  arglen; /* Length of ARG. */
282         int     matchind = -1;  /* Index of first nonexact match. */
283         int     ambiguous = 0;  /* If nonzero, multiple nonexact match(es). */
284
285         arglen = strlen(arg);
286
287         /* Test all elements for either exact match or abbreviated matches.  */
288         for (i = 0; optlist[i]; i++) {
289                 if (!strncmp(optlist[i], arg, arglen)) {
290                         if (strlen(optlist[i]) == arglen)
291                                 /* Exact match found.  */
292                                 return i;
293                         else if (matchind == -1)
294                                 /* First nonexact match found.  */
295                                 matchind = i;
296                         else
297                                 /* Second nonexact match found.  */
298                                 ambiguous = 1;
299                 }
300         }
301         if (ambiguous)
302                 return -2;
303         else
304                 return matchind;
305 }
306
307 /*
308  * Error reporting for argmatch. KIND is a description of the type of entity
309  * that was being matched. VALUE is the invalid value that was given. PROBLEM
310  * is the return value from argmatch.
311  */
312 static void
313 invalid_arg(const char *kind, const char *value, int problem)
314 {
315         fprintf(stderr, "patch: ");
316         if (problem == -1)
317                 fprintf(stderr, "invalid");
318         else                    /* Assume -2. */
319                 fprintf(stderr, "ambiguous");
320         fprintf(stderr, " %s `%s'\n", kind, value);
321 }
322
323 static const char *backup_args[] = {
324         "none", "never", "simple", "nil", "existing", "t", "numbered", 0
325 };
326
327 static enum backup_type backup_types[] = {
328         none, simple, simple, numbered_existing,
329         numbered_existing, numbered, numbered
330 };
331
332 /*
333  * Return the type of backup indicated by VERSION. Unique abbreviations are
334  * accepted.
335  */
336 enum backup_type
337 get_version(const char *version)
338 {
339         int     i;
340
341         if (version == NULL || *version == '\0')
342                 return numbered_existing;
343         i = argmatch(version, backup_args);
344         if (i >= 0)
345                 return backup_types[i];
346         invalid_arg("version control type", version, i);
347         exit(2);
348 }
349
350
351 [FILE:514:files/backupfile.h]
352 /* When to make backup files. */
353 enum backup_type {
354         /* Never make backups. */
355         none,
356
357         /* Make simple backups of every file. */
358         simple,
359
360         /*
361          * Make numbered backups of files that already have numbered backups,
362          * and simple backups of the others.
363          */
364         numbered_existing,
365
366         /* Make numbered backups of every file. */
367         numbered
368 };
369
370 extern enum backup_type backup_type;
371 extern const char       *simple_backup_suffix;
372
373 char            *find_backup_file_name(const char *file);
374 enum backup_type get_version(const char *version);
375
376
377 [FILE:1855:files/common.h]
378 #include <sys/types.h>
379
380 #include <stdbool.h>
381 #include <stdint.h>
382 #include "linux_support.h"
383
384 #define DEBUGGING
385
386 /* constants */
387
388 #define MAXHUNKSIZE 200000      /* is this enough lines? */
389 #define INITHUNKMAX 125         /* initial dynamic allocation size */
390 #define INITLINELEN 4096
391 #define BUFFERSIZE 4096
392 #define LINENUM_MAX LONG_MAX
393
394 #define ORIGEXT ".orig"
395 #define REJEXT ".rej"
396
397 /* handy definitions */
398
399 #define strEQ(s1,s2) (strcmp(s1, s2) == 0)
400 #define strnNE(s1,s2,l) (strncmp(s1, s2, l) != 0)
401 #define strnEQ(s1,s2,l) (strncmp(s1, s2, l) == 0)
402
403 /* typedefs */
404
405 typedef long    LINENUM;        /* must be signed */
406 enum vlevel     { NORMAL_LEVEL, SILENT, VERBOSE };
407
408 /* globals */
409
410 extern mode_t   filemode;
411
412 extern char     *buf;           /* general purpose buffer */
413 extern size_t   buf_size;       /* size of general purpose buffer */
414
415 extern bool     using_plan_a;   /* try to keep everything in memory */
416 extern bool     out_of_mem;     /* ran out of memory in plan a */
417
418 #define MAXFILEC 2
419
420 extern char     *filearg[MAXFILEC];
421 extern bool     ok_to_create_file;
422 extern char     *outname;
423 extern char     *origprae;
424
425 extern char     *TMPOUTNAME;
426 extern char     *TMPINNAME;
427 extern char     *TMPREJNAME;
428 extern char     *TMPPATNAME;
429 extern bool     toutkeep;
430 extern bool     trejkeep;
431
432 #ifdef DEBUGGING
433 extern int      debug;
434 #endif
435
436 extern bool     force;
437 extern bool     batch;
438 extern enum     vlevel verbosity;
439 extern bool     reverse;
440 extern bool     noreverse;
441 extern bool     skip_rest_of_patch;
442 extern int      strippath;
443 extern bool     canonicalize;
444 /* TRUE if -C was specified on command line.  */
445 extern bool     check_only;
446 extern bool     warn_on_invalid_line;
447 extern bool     last_line_missing_eol;
448
449
450 #define CONTEXT_DIFF 1
451 #define NORMAL_DIFF 2
452 #define ED_DIFF 3
453 #define NEW_CONTEXT_DIFF 4
454 #define UNI_DIFF 5
455
456 extern int      diff_type;
457 extern char     *revision;      /* prerequisite revision, if any */
458 extern LINENUM  input_lines;    /* how long is input file in lines */
459
460 extern int      posix;
461
462
463
464 [FILE:9806:files/inp.c]
465 #include <sys/types.h>
466 #include <sys/file.h>
467 #include <sys/stat.h>
468 #include <sys/mman.h>
469
470 #include <fcntl.h>
471 #include <ctype.h>
472 #include <libgen.h>
473 #include <stddef.h>
474 #include <stdint.h>
475 #include <stdio.h>
476 #include <stdlib.h>
477 #include <string.h>
478 #include <unistd.h>
479
480 #include "common.h"
481 #include "util.h"
482 #include "pch.h"
483 #include "inp.h"
484
485
486 /* Input-file-with-indexable-lines abstract type */
487
488 static size_t   i_size;         /* size of the input file */
489 static char     *i_womp;        /* plan a buffer for entire file */
490 static char     **i_ptr;        /* pointers to lines in i_womp */
491 static char     empty_line[] = { '\0' };
492
493 static int      tifd = -1;      /* plan b virtual string array */
494 static char     *tibuf[2];      /* plan b buffers */
495 static LINENUM  tiline[2] = {-1, -1};   /* 1st line in each buffer */
496 static size_t   lines_per_buf;  /* how many lines per buffer */
497 static size_t   tibuflen;       /* plan b buffer length */
498 static size_t   tireclen;       /* length of records in tmp file */
499
500 static bool     rev_in_string(const char *);
501 static bool     reallocate_lines(size_t *);
502
503 /* returns false if insufficient memory */
504 static bool     plan_a(const char *);
505
506 static void     plan_b(const char *);
507
508 /* New patch--prepare to edit another file. */
509
510 void
511 re_input(void)
512 {
513         if (using_plan_a) {
514                 free(i_ptr);
515                 i_ptr = NULL;
516                 if (i_womp != NULL) {
517                         munmap(i_womp, i_size);
518                         i_womp = NULL;
519                 }
520                 i_size = 0;
521         } else {
522                 using_plan_a = true;    /* maybe the next one is smaller */
523                 close(tifd);
524                 tifd = -1;
525                 free(tibuf[0]);
526                 free(tibuf[1]);
527                 tibuf[0] = tibuf[1] = NULL;
528                 tiline[0] = tiline[1] = -1;
529                 tireclen = 0;
530         }
531 }
532
533 /* Construct the line index, somehow or other. */
534
535 void
536 scan_input(const char *filename)
537 {
538         if (!plan_a(filename))
539                 plan_b(filename);
540         if (verbosity != SILENT) {
541                 say("Patching file %s using Plan %s...\n", filename,
542                     (using_plan_a ? "A" : "B"));
543         }
544 }
545
546 static bool
547 reallocate_lines(size_t *lines_allocated)
548 {
549         char    **p;
550         size_t  new_size;
551
552         new_size = *lines_allocated * 3 / 2;
553         p = realloc(i_ptr, (new_size + 2) * sizeof(char *));
554         if (p == NULL) {        /* shucks, it was a near thing */
555                 munmap(i_womp, i_size);
556                 i_womp = NULL;
557                 free(i_ptr);
558                 i_ptr = NULL;
559                 *lines_allocated = 0;
560                 return false;
561         }
562         *lines_allocated = new_size;
563         i_ptr = p;
564         return true;
565 }
566
567 /* Try keeping everything in memory. */
568
569 static bool
570 plan_a(const char *filename)
571 {
572         int             ifd, statfailed;
573         char            *p, *s;
574         struct stat     filestat;
575         ptrdiff_t       sz;
576         size_t          i;
577         size_t          iline, lines_allocated;
578
579 #ifdef DEBUGGING
580         if (debug & 8)
581                 return false;
582 #endif
583
584         if (filename == NULL || *filename == '\0')
585                 return false;
586
587         statfailed = stat(filename, &filestat);
588         if (statfailed && ok_to_create_file) {
589                 if (verbosity == VERBOSE)
590                         say("(Creating file %s...)\n", filename);
591
592                 /*
593                  * in check_patch case, we still display `Creating file' even
594                  * though we're not. The rule is that -C should be as similar
595                  * to normal patch behavior as possible
596                  */
597                 if (check_only)
598                         return true;
599                 makedirs(filename, true);
600                 close(creat(filename, 0666));
601                 statfailed = stat(filename, &filestat);
602         }
603         if (statfailed)
604                 fatal("can't find %s\n", filename);
605         filemode = filestat.st_mode;
606         if (!S_ISREG(filemode))
607                 fatal("%s is not a normal file--can't patch\n", filename);
608         if ((uint64_t)filestat.st_size > SIZE_MAX) {
609                 say("block too large to mmap\n");
610                 return false;
611         }
612         i_size = (size_t)filestat.st_size;
613         if (out_of_mem) {
614                 set_hunkmax();  /* make sure dynamic arrays are allocated */
615                 out_of_mem = false;
616                 return false;   /* force plan b because plan a bombed */
617         }
618         if ((ifd = open(filename, O_RDONLY)) < 0)
619                 pfatal("can't open file %s", filename);
620
621         if (i_size) {
622                 i_womp = mmap(NULL, i_size, PROT_READ, MAP_PRIVATE, ifd, 0);
623                 if (i_womp == MAP_FAILED) {
624                         perror("mmap failed");
625                         i_womp = NULL;
626                         close(ifd);
627                         return false;
628                 }
629         } else {
630                 i_womp = NULL;
631         }
632
633         close(ifd);
634         if (i_size)
635                 madvise(i_womp, i_size, MADV_SEQUENTIAL);
636
637         /* estimate the number of lines */
638         lines_allocated = i_size / 25;
639         if (lines_allocated < 100)
640                 lines_allocated = 100;
641
642         if (!reallocate_lines(&lines_allocated))
643                 return false;
644
645         /* now scan the buffer and build pointer array */
646         iline = 1;
647         i_ptr[iline] = i_womp;
648         /* test for NUL too, to maintain the behavior of the original code */
649         for (s = i_womp, i = 0; i < i_size && *s != '\0'; s++, i++) {
650                 if (*s == '\n') {
651                         if (iline == lines_allocated) {
652                                 if (!reallocate_lines(&lines_allocated))
653                                         return false;
654                         }
655                         /* these are NOT NUL terminated */
656                         i_ptr[++iline] = s + 1;
657                 }
658         }
659         /* if the last line contains no EOL, append one */
660         if (i_size > 0 && i_womp[i_size - 1] != '\n') {
661                 last_line_missing_eol = true;
662                 /* fix last line */
663                 sz = s - i_ptr[iline];
664                 p = malloc(sz + 1);
665                 if (p == NULL) {
666                         free(i_ptr);
667                         i_ptr = NULL;
668                         munmap(i_womp, i_size);
669                         i_womp = NULL;
670                         return false;
671                 }
672
673                 memcpy(p, i_ptr[iline], sz);
674                 p[sz] = '\n';
675                 i_ptr[iline] = p;
676                 /* count the extra line and make it point to some valid mem */
677                 i_ptr[++iline] = empty_line;
678         } else
679                 last_line_missing_eol = false;
680
681         input_lines = iline - 1;
682
683         /* now check for revision, if any */
684
685         if (revision != NULL) {
686                 if (i_womp == NULL || !rev_in_string(i_womp)) {
687                         if (force) {
688                                 if (verbosity == VERBOSE)
689                                         say("Warning: this file doesn't appear "
690                                             "to be the %s version--patching anyway.\n",
691                                             revision);
692                         } else if (batch) {
693                                 fatal("this file doesn't appear to be the "
694                                     "%s version--aborting.\n",
695                                     revision);
696                         } else {
697                                 ask("This file doesn't appear to be the "
698                                     "%s version--patch anyway? [n] ",
699                                     revision);
700                                 if (*buf != 'y')
701                                         fatal("aborted\n");
702                         }
703                 } else if (verbosity == VERBOSE)
704                         say("Good.  This file appears to be the %s version.\n",
705                             revision);
706         }
707         return true;            /* plan a will work */
708 }
709
710 /* Keep (virtually) nothing in memory. */
711
712 static void
713 plan_b(const char *filename)
714 {
715         FILE    *ifp;
716         size_t  i = 0, j, len, maxlen = 1;
717         char    *lbuf = NULL, *p;
718         bool    found_revision = (revision == NULL);
719
720         using_plan_a = false;
721         if ((ifp = fopen(filename, "r")) == NULL)
722                 pfatal("can't open file %s", filename);
723         unlink(TMPINNAME);
724         if ((tifd = open(TMPINNAME, O_EXCL | O_CREAT | O_WRONLY, 0666)) < 0)
725                 pfatal("can't open file %s", TMPINNAME);
726         while ((p = fgetln(ifp, &len)) != NULL) {
727                 if (p[len - 1] == '\n')
728                         p[len - 1] = '\0';
729                 else {
730                         /* EOF without EOL, copy and add the NUL */
731                         if ((lbuf = malloc(len + 1)) == NULL)
732                                 fatal("out of memory\n");
733                         memcpy(lbuf, p, len);
734                         lbuf[len] = '\0';
735                         p = lbuf;
736
737                         last_line_missing_eol = true;
738                         len++;
739                 }
740                 if (revision != NULL && !found_revision && rev_in_string(p))
741                         found_revision = true;
742                 if (len > maxlen)
743                         maxlen = len;   /* find longest line */
744         }
745         free(lbuf);
746         if (ferror(ifp))
747                 pfatal("can't read file %s", filename);
748
749         if (revision != NULL) {
750                 if (!found_revision) {
751                         if (force) {
752                                 if (verbosity == VERBOSE)
753                                         say("Warning: this file doesn't appear "
754                                             "to be the %s version--patching anyway.\n",
755                                             revision);
756                         } else if (batch) {
757                                 fatal("this file doesn't appear to be the "
758                                     "%s version--aborting.\n",
759                                     revision);
760                         } else {
761                                 ask("This file doesn't appear to be the %s "
762                                     "version--patch anyway? [n] ",
763                                     revision);
764                                 if (*buf != 'y')
765                                         fatal("aborted\n");
766                         }
767                 } else if (verbosity == VERBOSE)
768                         say("Good.  This file appears to be the %s version.\n",
769                             revision);
770         }
771         fseek(ifp, 0L, SEEK_SET);       /* rewind file */
772         tireclen = maxlen;
773         tibuflen = maxlen > BUFFERSIZE ? maxlen : BUFFERSIZE;
774         lines_per_buf = tibuflen / maxlen;
775         tibuf[0] = malloc(tibuflen + 1);
776         if (tibuf[0] == NULL)
777                 fatal("out of memory\n");
778         tibuf[1] = malloc(tibuflen + 1);
779         if (tibuf[1] == NULL)
780                 fatal("out of memory\n");
781         for (i = 1;; i++) {
782                 p = tibuf[0] + maxlen * (i % lines_per_buf);
783                 if (i % lines_per_buf == 0)     /* new block */
784                         if (write(tifd, tibuf[0], tibuflen) !=
785                             (ssize_t) tibuflen)
786                                 pfatal("can't write temp file");
787                 if (fgets(p, maxlen + 1, ifp) == NULL) {
788                         input_lines = i - 1;
789                         if (i % lines_per_buf != 0)
790                                 if (write(tifd, tibuf[0], tibuflen) !=
791                                     (ssize_t) tibuflen)
792                                         pfatal("can't write temp file");
793                         break;
794                 }
795                 j = strlen(p);
796                 /* These are '\n' terminated strings, so no need to add a NUL */
797                 if (j == 0 || p[j - 1] != '\n')
798                         p[j] = '\n';
799         }
800         fclose(ifp);
801         close(tifd);
802         if ((tifd = open(TMPINNAME, O_RDONLY)) < 0)
803                 pfatal("can't reopen file %s", TMPINNAME);
804 }
805
806 /*
807  * Fetch a line from the input file, \n terminated, not necessarily \0.
808  */
809 char *
810 ifetch(LINENUM line, int whichbuf)
811 {
812         if (line < 1 || line > input_lines) {
813                 if (warn_on_invalid_line) {
814                         say("No such line %ld in input file, ignoring\n", line);
815                         warn_on_invalid_line = false;
816                 }
817                 return NULL;
818         }
819         if (using_plan_a)
820                 return i_ptr[line];
821         else {
822                 LINENUM offline = line % lines_per_buf;
823                 LINENUM baseline = line - offline;
824
825                 if (tiline[0] == baseline)
826                         whichbuf = 0;
827                 else if (tiline[1] == baseline)
828                         whichbuf = 1;
829                 else {
830                         tiline[whichbuf] = baseline;
831
832                         if (lseek(tifd, (off_t) (baseline / lines_per_buf *
833                             tibuflen), SEEK_SET) < 0)
834                                 pfatal("cannot seek in the temporary input file");
835
836                         if (read(tifd, tibuf[whichbuf], tibuflen) !=
837                             (ssize_t) tibuflen)
838                                 pfatal("error reading tmp file %s", TMPINNAME);
839                 }
840                 return tibuf[whichbuf] + (tireclen * offline);
841         }
842 }
843
844 /*
845  * True if the string argument contains the revision number we want.
846  */
847 static bool
848 rev_in_string(const char *string)
849 {
850         const char      *s;
851         size_t          patlen;
852
853         if (revision == NULL)
854                 return true;
855         patlen = strlen(revision);
856         if (strnEQ(string, revision, patlen) && isspace((unsigned char)string[patlen]))
857                 return true;
858         for (s = string; *s; s++) {
859                 if (isspace((unsigned char)*s) && strnEQ(s + 1, revision, patlen) &&
860                     isspace((unsigned char)s[patlen + 1])) {
861                         return true;
862                 }
863         }
864         return false;
865 }
866
867
868 [FILE:83:files/inp.h]
869 void            re_input(void);
870 void            scan_input(const char *);
871 char            *ifetch(LINENUM, int);
872
873
874 [FILE:917:files/linux_support.c]
875 #ifndef LINUX_SUPPORT_C
876 #define LINUX_SUPPORT_C
877
878 #ifdef __linux__
879 #include <stdarg.h>
880 #include "linux_support.h"
881
882 static int
883 bsd_vasprintf(char **strp, const char *fmt, va_list args)
884 {
885     va_list args_copy;
886     int status, needed;
887
888     va_copy(args_copy, args);
889     needed = vsnprintf(NULL, 0, fmt, args_copy);
890     va_end(args_copy);
891     if (needed < 0) {
892         *strp = NULL;
893         return needed;
894     }
895     *strp = malloc(needed + 1);
896     if (*strp == NULL)
897         return -1;
898     status = vsnprintf(*strp, needed + 1, fmt, args);
899     if (status >= 0)
900         return status;
901     else {
902         free(*strp);
903         *strp = NULL;
904         return status;
905     }
906 }
907
908 int
909 bsd_asprintf(char **strp, const char *fmt, ...)
910 {
911     va_list args;
912     int status;
913
914     va_start(args, fmt);
915     status = bsd_vasprintf(strp, fmt, args);
916     va_end(args);
917     return status;
918 }
919 #endif /* __Linux__ */
920
921 #endif /* LINUX_SUPPORT_C */
922
923
924 [FILE:284:files/linux_support.h]
925 #ifndef LINUX_SUPPORT_H
926 #define LINUX_SUPPORT_H
927
928 #ifdef __linux__
929 #include <bsd/stdio.h>
930 #include <bsd/stdlib.h>
931 #include <bsd/unistd.h>
932 #include <bsd/string.h>
933
934 #define asprintf        bsd_asprintf
935
936 int     bsd_asprintf(char **strp, const char *fmt, ...);
937
938 #endif
939
940 #endif /* LINUX_SUPPORT_H */
941
942
943 [FILE:715:files/mkpath.c]
944 #include <sys/types.h>
945 #include <sys/stat.h>
946 #include <err.h>
947 #include <errno.h>
948 #include <string.h>
949
950 int     mkpath(char *);
951
952 /* Code taken directly from mkdir(1).
953
954  * mkpath -- create directories.
955  *      path     - path
956  */
957 int
958 mkpath(char *path)
959 {
960         struct stat sb;
961         char *slash;
962         int done = 0;
963
964         slash = path;
965
966         while (!done) {
967                 slash += strspn(slash, "/");
968                 slash += strcspn(slash, "/");
969
970                 done = (*slash == '\0');
971                 *slash = '\0';
972
973                 if (stat(path, &sb)) {
974                         if (errno != ENOENT || (mkdir(path, 0777) &&
975                             errno != EEXIST)) {
976                                 warn("%s", path);
977                                 return (-1);
978                         }
979                 } else if (!S_ISDIR(sb.st_mode)) {
980                         warnx("%s: %s", path, strerror(ENOTDIR));
981                         return (-1);
982                 }
983
984                 *slash = '/';
985         }
986
987         return (0);
988 }
989
990
991
992 [FILE:19111:files/patch.1]
993 .Dd September 6, 2017
994 .Dt PATCH 1
995 .Os
996 .Sh NAME
997 .Nm patch
998 .Nd apply a diff file to an original
999 .Sh SYNOPSIS
1000 .Nm
1001 .Bk -words
1002 .Op Fl bCcEeflNnRstuv
1003 .Op Fl B Ar backup-prefix
1004 .Op Fl D Ar symbol
1005 .Op Fl d Ar directory
1006 .Op Fl F Ar max-fuzz
1007 .Op Fl i Ar patchfile
1008 .Op Fl o Ar out-file
1009 .Op Fl p Ar strip-count
1010 .Op Fl r Ar rej-name
1011 .Op Fl V Cm t | nil | never | none
1012 .Op Fl x Ar number
1013 .Op Fl z Ar backup-ext
1014 .Op Fl Fl verbose
1015 .Op Fl Fl posix
1016 .Op Ar origfile Op Ar patchfile
1017 .Ek
1018 .Nm
1019 .Pf \*(Lt Ar patchfile
1020 .Sh DESCRIPTION
1021 .Nm
1022 will take a patch file containing any of the four forms of difference
1023 listing produced by the
1024 .Xr diff 1
1025 program and apply those differences to an original file,
1026 producing a patched version.
1027 If
1028 .Ar patchfile
1029 is omitted, or is a hyphen, the patch will be read from the standard input.
1030 .Pp
1031 .Nm
1032 will attempt to determine the type of the diff listing, unless overruled by a
1033 .Fl c ,
1034 .Fl e ,
1035 .Fl n ,
1036 or
1037 .Fl u
1038 option.
1039 Context diffs (old-style, new-style, and unified) and
1040 normal diffs are applied directly by the
1041 .Nm
1042 program itself, whereas ed diffs are simply fed to the
1043 .Xr ed 1
1044 editor via a pipe.
1045 .Pp
1046 If the
1047 .Ar patchfile
1048 contains more than one patch,
1049 .Nm
1050 will try to apply each of them as if they came from separate patch files.
1051 This means, among other things, that it is assumed that the name of the file
1052 to patch must be determined for each diff listing, and that the garbage before
1053 each diff listing will be examined for interesting things such as file names
1054 and revision level (see the section on
1055 .Sx Filename Determination
1056 below).
1057 .Pp
1058 The options are as follows:
1059 .Bl -tag -width Ds
1060 .It Xo
1061 .Fl B Ar backup-prefix ,
1062 .Fl Fl prefix Ar backup-prefix
1063 .Xc
1064 Causes the next argument to be interpreted as a prefix to the backup file
1065 name.
1066 If this argument is specified, any argument to
1067 .Fl z
1068 will be ignored.
1069 .It Fl b , Fl Fl backup
1070 Save a backup copy of the file before it is modified.
1071 By default the original file is saved with a backup extension of
1072 .Qq .orig
1073 unless the file already has a numbered backup, in which case a numbered
1074 backup is made.
1075 This is equivalent to specifying
1076 .Qo Fl V Cm existing Qc .
1077 This option is currently the default, unless
1078 .Fl -posix
1079 is specified.
1080 .It Fl C , Fl Fl check , Fl Fl dry-run
1081 Checks that the patch would apply cleanly, but does not modify anything.
1082 .It Fl c , Fl Fl context
1083 Forces
1084 .Nm
1085 to interpret the patch file as a context diff.
1086 .It Xo
1087 .Fl D Ar symbol ,
1088 .Fl Fl ifdef Ar symbol
1089 .Xc
1090 Causes
1091 .Nm
1092 to use the
1093 .Qq #ifdef...#endif
1094 construct to mark changes.
1095 The argument following will be used as the differentiating symbol.
1096 Note that, unlike the C compiler, there must be a space between the
1097 .Fl D
1098 and the argument.
1099 .It Xo
1100 .Fl d Ar directory ,
1101 .Fl Fl directory Ar directory
1102 .Xc
1103 Causes
1104 .Nm
1105 to interpret the next argument as a directory,
1106 and change the working directory to it before doing anything else.
1107 .It Fl E , Fl Fl remove-empty-files
1108 Causes
1109 .Nm
1110 to remove output files that are empty after the patches have been applied.
1111 This option is useful when applying patches that create or remove files.
1112 .It Fl e , Fl Fl ed
1113 Forces
1114 .Nm
1115 to interpret the patch file as an
1116 .Xr ed 1
1117 script.
1118 .It Xo
1119 .Fl F Ar max-fuzz ,
1120 .Fl Fl fuzz Ar max-fuzz
1121 .Xc
1122 Sets the maximum fuzz factor.
1123 This option only applies to context diffs, and causes
1124 .Nm
1125 to ignore up to that many lines in looking for places to install a hunk.
1126 Note that a larger fuzz factor increases the odds of a faulty patch.
1127 The default fuzz factor is 2, and it may not be set to more than
1128 the number of lines of context in the context diff, ordinarily 3.
1129 .It Fl f , Fl Fl force
1130 Forces
1131 .Nm
1132 to assume that the user knows exactly what he or she is doing, and to not
1133 ask any questions.
1134 It assumes the following:
1135 skip patches for which a file to patch cannot be found;
1136 patch files even though they have the wrong version for the
1137 .Qq Prereq:
1138 line in the patch;
1139 and assume that patches are not reversed even if they look like they are.
1140 This option does not suppress commentary; use
1141 .Fl s
1142 for that.
1143 .It Xo
1144 .Fl i Ar patchfile ,
1145 .Fl Fl input Ar patchfile
1146 .Xc
1147 Causes the next argument to be interpreted as the input file name
1148 (i.e., a patchfile).
1149 This option may be specified multiple times.
1150 .It Fl l , Fl Fl ignore-whitespace
1151 Causes the pattern matching to be done loosely, in case the tabs and
1152 spaces have been munged in your input file.
1153 Any sequence of whitespace in the pattern line will match any sequence
1154 in the input file.
1155 Normal characters must still match exactly.
1156 Each line of the context must still match a line in the input file.
1157 .It Fl N , Fl Fl forward
1158 Causes
1159 .Nm
1160 to ignore patches that it thinks are reversed or already applied.
1161 See also
1162 .Fl R .
1163 .It Fl n , Fl Fl normal
1164 Forces
1165 .Nm
1166 to interpret the patch file as a normal diff.
1167 .It Xo
1168 .Fl o Ar out-file ,
1169 .Fl Fl output Ar out-file
1170 .Xc
1171 Causes the next argument to be interpreted as the output file name.
1172 .It Xo
1173 .Fl p Ar strip-count ,
1174 .Fl Fl strip Ar strip-count
1175 .Xc
1176 Sets the pathname strip count,
1177 which controls how pathnames found in the patch file are treated,
1178 in case you keep your files in a different directory than the person who sent
1179 out the patch.
1180 The strip count specifies how many slashes are to be stripped from
1181 the front of the pathname.
1182 (Any intervening directory names also go away.)
1183 For example, supposing the file name in the patch file was
1184 .Pa /u/howard/src/blurfl/blurfl.c :
1185 .Pp
1186 Setting
1187 .Fl p Ns Ar 0
1188 gives the entire pathname unmodified.
1189 .Pp
1190 .Fl p Ns Ar 1
1191 gives
1192 .Pp
1193 .D1 Pa u/howard/src/blurfl/blurfl.c
1194 .Pp
1195 without the leading slash.
1196 .Pp
1197 .Fl p Ns Ar 4
1198 gives
1199 .Pp
1200 .D1 Pa blurfl/blurfl.c
1201 .Pp
1202 Not specifying
1203 .Fl p
1204 at all just gives you
1205 .Pa blurfl.c ,
1206 unless all of the directories in the leading path
1207 .Pq Pa u/howard/src/blurfl
1208 exist and that path is relative,
1209 in which case you get the entire pathname unmodified.
1210 Whatever you end up with is looked for either in the current directory,
1211 or the directory specified by the
1212 .Fl d
1213 option.
1214 .It Fl R , Fl Fl reverse
1215 Tells
1216 .Nm
1217 that this patch was created with the old and new files swapped.
1218 (Yes, I am afraid that does happen occasionally, human nature being what it
1219 is.)
1220 .Nm
1221 will attempt to swap each hunk around before applying it.
1222 Rejects will come out in the swapped format.
1223 The
1224 .Fl R
1225 option will not work with ed diff scripts because there is too little
1226 information to reconstruct the reverse operation.
1227 .Pp
1228 If the first hunk of a patch fails,
1229 .Nm
1230 will reverse the hunk to see if it can be applied that way.
1231 If it can, you will be asked if you want to have the
1232 .Fl R
1233 option set.
1234 If it cannot, the patch will continue to be applied normally.
1235 (Note: this method cannot detect a reversed patch if it is a normal diff
1236 and if the first command is an append (i.e., it should have been a delete)
1237 since appends always succeed, due to the fact that a null context will match
1238 anywhere.
1239 Luckily, most patches add or change lines rather than delete them, so most
1240 reversed normal diffs will begin with a delete, which will fail, triggering
1241 the heuristic.)
1242 .It Xo
1243 .Fl r Ar rej-name ,
1244 .Fl Fl reject-file Ar rej-name
1245 .Xc
1246 Causes the next argument to be interpreted as the reject file name.
1247 .It Xo
1248 .Fl s , Fl Fl quiet ,
1249 .Fl Fl silent
1250 .Xc
1251 Makes
1252 .Nm
1253 do its work silently, unless an error occurs.
1254 .It Fl t , Fl Fl batch
1255 Similar to
1256 .Fl f ,
1257 in that it suppresses questions, but makes some different assumptions:
1258 skip patches for which a file to patch cannot be found (the same as
1259 .Fl f ) ;
1260 skip patches for which the file has the wrong version for the
1261 .Qq Prereq:
1262 line in the patch;
1263 and assume that patches are reversed if they look like they are.
1264 .It Fl u , Fl Fl unified
1265 Forces
1266 .Nm
1267 to interpret the patch file as a unified context diff (a unidiff).
1268 .It Xo
1269 .Fl V Cm t | nil | never | none ,
1270 .Fl Fl version-control Cm t | nil | never | none
1271 .Xc
1272 Causes the next argument to be interpreted as a method for creating
1273 backup file names.
1274 The type of backups made can also be given in the
1275 .Ev PATCH_VERSION_CONTROL
1276 or
1277 .Ev VERSION_CONTROL
1278 environment variables, which are overridden by this option.
1279 The
1280 .Fl B
1281 option overrides this option, causing the prefix to always be used for
1282 making backup file names.
1283 The values of the
1284 .Ev PATCH_VERSION_CONTROL
1285 and
1286 .Ev VERSION_CONTROL
1287 environment variables and the argument to the
1288 .Fl V
1289 option are like the GNU Emacs
1290 .Dq version-control
1291 variable; they also recognize synonyms that are more descriptive.
1292 The valid values are (unique abbreviations are accepted):
1293 .Bl -tag -width Ds -offset indent
1294 .It Cm t , numbered
1295 Always make numbered backups.
1296 .It Cm nil , existing
1297 Make numbered backups of files that already have them,
1298 simple backups of the others.
1299 .It Cm never , simple
1300 Always make simple backups.
1301 .It Cm none
1302 Do not make backups.
1303 .El
1304 .It Fl v , Fl Fl version
1305 Causes
1306 .Nm
1307 to print out its revision header and patch level.
1308 .It Xo
1309 .Fl x Ar number ,
1310 .Fl Fl debug Ar number
1311 .Xc
1312 Sets internal debugging flags, and is of interest only to
1313 .Nm
1314 patchers.
1315 .It Xo
1316 .Fl z Ar backup-ext ,
1317 .Fl Fl suffix Ar backup-ext
1318 .Xc
1319 Causes the next argument to be interpreted as the backup extension, to be
1320 used in place of
1321 .Qq .orig .
1322 .It Fl Fl verbose
1323 Provides extra information during processing.
1324 .It Fl Fl posix
1325 Enables strict
1326 .St -p1003.1-2008
1327 conformance, specifically:
1328 .Bl -enum
1329 .It
1330 Backup files are not created unless the
1331 .Fl b
1332 option is specified.
1333 .It
1334 If unspecified, the file name used is the first of the old, new and
1335 index files that exists.
1336 .El
1337 .El
1338 .Ss Patch Application
1339 .Nm
1340 will try to skip any leading garbage, apply the diff,
1341 and then skip any trailing garbage.
1342 Thus you could feed an article or message containing a
1343 diff listing to
1344 .Nm ,
1345 and it should work.
1346 If the entire diff is indented by a consistent amount,
1347 this will be taken into account.
1348 .Pp
1349 With context diffs, and to a lesser extent with normal diffs,
1350 .Nm
1351 can detect when the line numbers mentioned in the patch are incorrect,
1352 and will attempt to find the correct place to apply each hunk of the patch.
1353 As a first guess, it takes the line number mentioned for the hunk, plus or
1354 minus any offset used in applying the previous hunk.
1355 If that is not the correct place,
1356 .Nm
1357 will scan both forwards and backwards for a set of lines matching the context
1358 given in the hunk.
1359 First
1360 .Nm
1361 looks for a place where all lines of the context match.
1362 If no such place is found, and it is a context diff, and the maximum fuzz factor
1363 is set to 1 or more, then another scan takes place ignoring the first and last
1364 line of context.
1365 If that fails, and the maximum fuzz factor is set to 2 or more,
1366 the first two and last two lines of context are ignored,
1367 and another scan is made.
1368 .Pq The default maximum fuzz factor is 2.
1369 .Pp
1370 If
1371 .Nm
1372 cannot find a place to install that hunk of the patch, it will put the hunk
1373 out to a reject file, which normally is the name of the output file plus
1374 .Qq .rej .
1375 (Note that the rejected hunk will come out in context diff form whether the
1376 input patch was a context diff or a normal diff.
1377 If the input was a normal diff, many of the contexts will simply be null.)
1378 The line numbers on the hunks in the reject file may be different than
1379 in the patch file: they reflect the approximate location patch thinks the
1380 failed hunks belong in the new file rather than the old one.
1381 .Pp
1382 As each hunk is completed, you will be told whether the hunk succeeded or
1383 failed, and which line (in the new file)
1384 .Nm
1385 thought the hunk should go on.
1386 If this is different from the line number specified in the diff,
1387 you will be told the offset.
1388 A single large offset MAY be an indication that a hunk was installed in the
1389 wrong place.
1390 You will also be told if a fuzz factor was used to make the match, in which
1391 case you should also be slightly suspicious.
1392 .Ss Filename Determination
1393 If no original file is specified on the command line,
1394 .Nm
1395 will try to figure out from the leading garbage what the name of the file
1396 to edit is.
1397 When checking a prospective file name, pathname components are stripped
1398 as specified by the
1399 .Fl p
1400 option and the file's existence and writability are checked relative
1401 to the current working directory (or the directory specified by the
1402 .Fl d
1403 option).
1404 .Pp
1405 If the diff is a context or unified diff,
1406 .Nm
1407 is able to determine the old and new file names from the diff header.
1408 For context diffs, the
1409 .Dq old
1410 file is specified in the line beginning with
1411 .Qq ***
1412 and the
1413 .Dq new
1414 file is specified in the line beginning with
1415 .Qq --- .
1416 For a unified diff, the
1417 .Dq old
1418 file is specified in the line beginning with
1419 .Qq ---
1420 and the
1421 .Dq new
1422 file is specified in the line beginning with
1423 .Qq +++ .
1424 If there is an
1425 .Qq Index:
1426 line in the leading garbage (regardless of the diff type),
1427 .Nm
1428 will use the file name from that line as the
1429 .Dq index
1430 file.
1431 .Pp
1432 .Nm
1433 will choose the file name by performing the following steps, with the first
1434 match used:
1435 .Bl -enum
1436 .It
1437 If
1438 .Nm
1439 is operating in strict
1440 .St -p1003.1-2008
1441 mode, the first of the
1442 .Dq old ,
1443 .Dq new
1444 and
1445 .Dq index
1446 file names that exist is used.
1447 Otherwise,
1448 .Nm
1449 will examine either the
1450 .Dq old
1451 and
1452 .Dq new
1453 file names or, for a non-context diff, the
1454 .Dq index
1455 file name, and choose the file name with the fewest path components,
1456 the shortest basename, and the shortest total file name length (in that order).
1457 .It
1458 If no suitable file was found to patch, the patch file is a context or
1459 unified diff, and the old file was zero length, the new file name is
1460 created and used.
1461 .It
1462 If the file name still cannot be determined,
1463 .Nm
1464 will prompt the user for the file name to use.
1465 .El
1466 .Pp
1467 Additionally, if the leading garbage contains a
1468 .Qq Prereq:\ \&
1469 line,
1470 .Nm
1471 will take the first word from the prerequisites line (normally a version
1472 number) and check the input file to see if that word can be found.
1473 If not,
1474 .Nm
1475 will ask for confirmation before proceeding.
1476 .Pp
1477 The upshot of all this is that you should be able to say, while in a news
1478 interface, the following:
1479 .Pp
1480 .Dl | patch -d /usr/src/local/blurfl
1481 .Pp
1482 and patch a file in the blurfl directory directly from the article containing
1483 the patch.
1484 .Ss Backup Files
1485 By default, the patched version is put in place of the original, with
1486 the original file backed up to the same name with the extension
1487 .Qq .orig ,
1488 or as specified by the
1489 .Fl B ,
1490 .Fl V ,
1491 or
1492 .Fl z
1493 options.
1494 The extension used for making backup files may also be specified in the
1495 .Ev SIMPLE_BACKUP_SUFFIX
1496 environment variable, which is overridden by the options above.
1497 .Pp
1498 If the backup file is a symbolic or hard link to the original file,
1499 .Nm
1500 creates a new backup file name by changing the first lowercase letter
1501 in the last component of the file's name into uppercase.
1502 If there are no more lowercase letters in the name,
1503 it removes the first character from the name.
1504 It repeats this process until it comes up with a
1505 backup file that does not already exist or is not linked to the original file.
1506 .Pp
1507 You may also specify where you want the output to go with the
1508 .Fl o
1509 option; if that file already exists, it is backed up first.
1510 .Ss Notes For Patch Senders
1511 There are several things you should bear in mind if you are going to
1512 be sending out patches:
1513 .Pp
1514 First, you can save people a lot of grief by keeping a
1515 .Pa patchlevel.h
1516 file which is patched to increment the patch level as the first diff in the
1517 patch file you send out.
1518 If you put a
1519 .Qq Prereq:
1520 line in with the patch, it will not let them apply
1521 patches out of order without some warning.
1522 .Pp
1523 Second, make sure you have specified the file names right, either in a
1524 context diff header, or with an
1525 .Qq Index:
1526 line.
1527 If you are patching something in a subdirectory, be sure to tell the patch
1528 user to specify a
1529 .Fl p
1530 option as needed.
1531 .Pp
1532 Third, you can create a file by sending out a diff that compares a
1533 null file to the file you want to create.
1534 This will only work if the file you want to create does not exist already in
1535 the target directory.
1536 .Pp
1537 Fourth, take care not to send out reversed patches, since it makes people wonder
1538 whether they already applied the patch.
1539 .Pp
1540 Fifth, while you may be able to get away with putting 582 diff listings into
1541 one file, it is probably wiser to group related patches into separate files in
1542 case something goes haywire.
1543 .Sh ENVIRONMENT
1544 .Bl -tag -width "PATCH_VERSION_CONTROL" -compact
1545 .It Ev POSIXLY_CORRECT
1546 When set,
1547 .Nm
1548 behaves as if the
1549 .Fl Fl posix
1550 option has been specified.
1551 .It Ev SIMPLE_BACKUP_SUFFIX
1552 Extension to use for backup file names instead of
1553 .Qq .orig .
1554 .It Ev TMPDIR
1555 Directory to put temporary files in; default is
1556 .Pa /tmp .
1557 .It Ev PATCH_VERSION_CONTROL
1558 Selects when numbered backup files are made.
1559 .It Ev VERSION_CONTROL
1560 Same as
1561 .Ev PATCH_VERSION_CONTROL .
1562 .El
1563 .Sh FILES
1564 .Bl -tag -width "$TMPDIR/patch*" -compact
1565 .It Pa $TMPDIR/patch*
1566 .Nm
1567 temporary files
1568 .It Pa /dev/tty
1569 used to read input when
1570 .Nm
1571 prompts the user
1572 .El
1573 .Sh EXIT STATUS
1574 The
1575 .Nm
1576 utility exits with one of the following values:
1577 .Pp
1578 .Bl -tag -width Ds -offset indent -compact
1579 .It \&0
1580 Successful completion.
1581 .It \&1
1582 One or more lines were written to a reject file.
1583 .It \*[Gt]\&1
1584 An error occurred.
1585 .El
1586 .Pp
1587 When applying a set of patches in a loop it behooves you to check this
1588 exit status so you do not apply a later patch to a partially patched file.
1589 .Sh DIAGNOSTICS
1590 Too many to list here, but generally indicative that
1591 .Nm
1592 couldn't parse your patch file.
1593 .Pp
1594 The message
1595 .Qq Hmm...
1596 indicates that there is unprocessed text in the patch file and that
1597 .Nm
1598 is attempting to intuit whether there is a patch in that text and, if so,
1599 what kind of patch it is.
1600 .Sh SEE ALSO
1601 .Xr diff 1
1602 .Sh STANDARDS
1603 The
1604 .Nm
1605 utility is compliant with the
1606 .St -p1003.1-2008
1607 specification,
1608 except as detailed above for the
1609 .Fl -posix
1610 option.
1611 .Pp
1612 The flags
1613 .Op Fl BCEFfstVvxz
1614 and
1615 .Op Fl -posix
1616 are extensions to that specification.
1617 .Sh AUTHORS
1618 .An Larry Wall
1619 with many other contributors.
1620 .Sh CAVEATS
1621 .Nm
1622 cannot tell if the line numbers are off in an ed script, and can only detect
1623 bad line numbers in a normal diff when it finds a
1624 .Qq change
1625 or a
1626 .Qq delete
1627 command.
1628 A context diff using fuzz factor 3 may have the same problem.
1629 Until a suitable interactive interface is added, you should probably do
1630 a context diff in these cases to see if the changes made sense.
1631 Of course, compiling without errors is a pretty good indication that the patch
1632 worked, but not always.
1633 .Pp
1634 .Nm
1635 usually produces the correct results, even when it has to do a lot of
1636 guessing.
1637 However, the results are guaranteed to be correct only when the patch is
1638 applied to exactly the same version of the file that the patch was
1639 generated from.
1640 .Sh BUGS
1641 Could be smarter about partial matches, excessively deviant offsets and
1642 swapped code, but that would take an extra pass.
1643 .Pp
1644 Check patch mode
1645 .Pq Fl C
1646 will fail if you try to check several patches in succession that build on
1647 each other.
1648 The entire
1649 .Nm
1650 code would have to be restructured to keep temporary files around so that it
1651 can handle this situation.
1652 .Pp
1653 If code has been duplicated (for instance with #ifdef OLDCODE ... #else ...
1654 #endif),
1655 .Nm
1656 is incapable of patching both versions, and, if it works at all, will likely
1657 patch the wrong one, and tell you that it succeeded to boot.
1658 .Pp
1659 If you apply a patch you have already applied,
1660 .Nm
1661 will think it is a reversed patch, and offer to un-apply the patch.
1662 This could be construed as a feature.
1663
1664
1665 [FILE:26069:files/patch.c]
1666 #include <sys/types.h>
1667 #include <sys/stat.h>
1668
1669 #include <ctype.h>
1670 #include <getopt.h>
1671 #include <limits.h>
1672 #include <stdio.h>
1673 #include <string.h>
1674 #include <stdlib.h>
1675 #include <unistd.h>
1676
1677 #include "common.h"
1678 #include "util.h"
1679 #include "pch.h"
1680 #include "inp.h"
1681 #include "backupfile.h"
1682 #include "pathnames.h"
1683
1684 #ifndef NAME_MAX
1685 #define NAME_MAX        255
1686 #endif
1687
1688 mode_t          filemode = 0644;
1689
1690 char            *buf;                   /* general purpose buffer */
1691 size_t          buf_size;               /* size of the general purpose buffer */
1692
1693 bool            using_plan_a = true;    /* try to keep everything in memory */
1694 bool            out_of_mem = false;     /* ran out of memory in plan a */
1695
1696 #define MAXFILEC 2
1697
1698 char            *filearg[MAXFILEC];
1699 bool            ok_to_create_file = false;
1700 char            *outname = NULL;
1701 char            *origprae = NULL;
1702 char            *TMPOUTNAME;
1703 char            *TMPINNAME;
1704 char            *TMPREJNAME;
1705 char            *TMPPATNAME;
1706 bool            toutkeep = false;
1707 bool            trejkeep = false;
1708 bool            warn_on_invalid_line;
1709 bool            last_line_missing_eol;
1710
1711 #ifdef DEBUGGING
1712 int             debug = 0;
1713 #endif
1714
1715 bool            force = false;
1716 bool            batch = false;
1717 bool            reverse = false;
1718 bool            noreverse = false;
1719 bool            skip_rest_of_patch = false;
1720 int             strippath = 957;
1721 bool            canonicalize = false;
1722 bool            check_only = false;
1723 int             diff_type = 0;
1724 char            *revision = NULL;       /* prerequisite revision, if any */
1725 LINENUM         input_lines = 0;        /* how long is input file in lines */
1726 int             posix = 0;              /* strict POSIX mode? */
1727 enum vlevel     verbosity = NORMAL_LEVEL;
1728
1729 static void     reinitialize_almost_everything(void);
1730 static void     get_some_switches(void);
1731 static LINENUM  locate_hunk(LINENUM);
1732 static void     abort_context_hunk(void);
1733 static void     rej_line(int, LINENUM);
1734 static void     abort_hunk(void);
1735 static void     apply_hunk(LINENUM);
1736 static void     init_output(const char *);
1737 static void     init_reject(const char *);
1738 static void     copy_till(LINENUM, bool);
1739 static bool     spew_output(void);
1740 static void     dump_line(LINENUM, bool);
1741 static bool     patch_match(LINENUM, LINENUM, LINENUM);
1742 static bool     similar(const char *, const char *, int);
1743 static void     usage(void);
1744
1745 /* true if -E was specified on command line.  */
1746 static bool     remove_empty_files = false;
1747
1748 /* true if -R was specified on command line.  */
1749 static bool     reverse_flag_specified = false;
1750
1751 static bool     Vflag = false;
1752
1753 /* buffer holding the name of the rejected patch file. */
1754 static char     rejname[NAME_MAX + 1];
1755
1756 /* how many input lines have been irretractibly output */
1757 static LINENUM  last_frozen_line = 0;
1758
1759 static int      Argc;           /* guess */
1760 static char     **Argv;
1761 static int      Argc_last;      /* for restarting plan_b */
1762 static char     **Argv_last;
1763
1764 static FILE     *ofp = NULL;    /* output file pointer */
1765 static FILE     *rejfp = NULL;  /* reject file pointer */
1766
1767 static int      filec = 0;      /* how many file arguments? */
1768 static LINENUM  last_offset = 0;
1769 static LINENUM  maxfuzz = 2;
1770
1771 /* patch using ifdef, ifndef, etc. */
1772 static bool             do_defines = false;
1773 /* #ifdef xyzzy */
1774 static char             if_defined[128];
1775 /* #ifndef xyzzy */
1776 static char             not_defined[128];
1777 /* #else */
1778 static const char       else_defined[] = "#else\n";
1779 /* #endif xyzzy */
1780 static char             end_defined[128];
1781
1782
1783 /* Apply a set of diffs as appropriate. */
1784
1785 int
1786 main(int argc, char *argv[])
1787 {
1788         int     error = 0, hunk, failed, i, fd;
1789         bool    patch_seen, reverse_seen;
1790         LINENUM where = 0, newwhere, fuzz, mymaxfuzz;
1791         const   char *tmpdir;
1792         char    *v;
1793
1794         setvbuf(stdout, NULL, _IOLBF, 0);
1795         setvbuf(stderr, NULL, _IOLBF, 0);
1796         for (i = 0; i < MAXFILEC; i++)
1797                 filearg[i] = NULL;
1798
1799         buf_size = INITLINELEN;
1800         buf = malloc((unsigned)(buf_size));
1801         if (buf == NULL)
1802                 fatal("out of memory\n");
1803
1804         /* Cons up the names of the temporary files.  */
1805         if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
1806                 tmpdir = _PATH_TMP;
1807         for (i = strlen(tmpdir) - 1; i > 0 && tmpdir[i] == '/'; i--)
1808                 ;
1809         i++;
1810         if (asprintf(&TMPOUTNAME, "%.*s/patchoXXXXXXXXXX", i, tmpdir) == -1)
1811                 fatal("cannot allocate memory");
1812         if ((fd = mkstemp(TMPOUTNAME)) < 0)
1813                 pfatal("can't create %s", TMPOUTNAME);
1814         close(fd);
1815
1816         if (asprintf(&TMPINNAME, "%.*s/patchiXXXXXXXXXX", i, tmpdir) == -1)
1817                 fatal("cannot allocate memory");
1818         if ((fd = mkstemp(TMPINNAME)) < 0)
1819                 pfatal("can't create %s", TMPINNAME);
1820         close(fd);
1821
1822         if (asprintf(&TMPREJNAME, "%.*s/patchrXXXXXXXXXX", i, tmpdir) == -1)
1823                 fatal("cannot allocate memory");
1824         if ((fd = mkstemp(TMPREJNAME)) < 0)
1825                 pfatal("can't create %s", TMPREJNAME);
1826         close(fd);
1827
1828         if (asprintf(&TMPPATNAME, "%.*s/patchpXXXXXXXXXX", i, tmpdir) == -1)
1829                 fatal("cannot allocate memory");
1830         if ((fd = mkstemp(TMPPATNAME)) < 0)
1831                 pfatal("can't create %s", TMPPATNAME);
1832         close(fd);
1833
1834         v = getenv("SIMPLE_BACKUP_SUFFIX");
1835         if (v)
1836                 simple_backup_suffix = v;
1837         else
1838                 simple_backup_suffix = ORIGEXT;
1839
1840         /* parse switches */
1841         Argc = argc;
1842         Argv = argv;
1843         get_some_switches();
1844
1845         if (!Vflag) {
1846                 if ((v = getenv("PATCH_VERSION_CONTROL")) == NULL)
1847                         v = getenv("VERSION_CONTROL");
1848                 if (v != NULL || !posix)
1849                         backup_type = get_version(v);   /* OK to pass NULL. */
1850         }
1851
1852         /* make sure we clean up /tmp in case of disaster */
1853         set_signals(0);
1854
1855         patch_seen = false;
1856         for (open_patch_file(filearg[1]); there_is_another_patch();
1857             reinitialize_almost_everything()) {
1858                 /* for each patch in patch file */
1859
1860                 patch_seen = true;
1861
1862                 warn_on_invalid_line = true;
1863
1864                 if (outname == NULL)
1865                         outname = xstrdup(filearg[0]);
1866
1867                 /* for ed script just up and do it and exit */
1868                 if (diff_type == ED_DIFF) {
1869                         do_ed_script();
1870                         continue;
1871                 }
1872                 /* initialize the patched file */
1873                 if (!skip_rest_of_patch)
1874                         init_output(TMPOUTNAME);
1875
1876                 /* initialize reject file */
1877                 init_reject(TMPREJNAME);
1878
1879                 /* find out where all the lines are */
1880                 if (!skip_rest_of_patch)
1881                         scan_input(filearg[0]);
1882
1883                 /*
1884                  * from here on, open no standard i/o files, because
1885                  * malloc might misfire and we can't catch it easily
1886                  */
1887
1888                 /* apply each hunk of patch */
1889                 hunk = 0;
1890                 failed = 0;
1891                 reverse_seen = false;
1892                 out_of_mem = false;
1893                 while (another_hunk()) {
1894                         hunk++;
1895                         fuzz = 0;
1896                         mymaxfuzz = pch_context();
1897                         if (maxfuzz < mymaxfuzz)
1898                                 mymaxfuzz = maxfuzz;
1899                         if (!skip_rest_of_patch) {
1900                                 do {
1901                                         where = locate_hunk(fuzz);
1902                                         if (hunk == 1 && where == 0 && !force && !reverse_seen) {
1903                                                 /* dwim for reversed patch? */
1904                                                 if (!pch_swap()) {
1905                                                         if (fuzz == 0)
1906                                                                 say("Not enough memory to try swapped hunk!  Assuming unswapped.\n");
1907                                                         continue;
1908                                                 }
1909                                                 reverse = !reverse;
1910                                                 /* try again */
1911                                                 where = locate_hunk(fuzz);
1912                                                 if (where == 0) {
1913                                                         /* didn't find it swapped */
1914                                                         if (!pch_swap())
1915                                                                 /* put it back to normal */
1916                                                                 fatal("lost hunk on alloc error!\n");
1917                                                         reverse = !reverse;
1918                                                 } else if (noreverse) {
1919                                                         if (!pch_swap())
1920                                                                 /* put it back to normal */
1921                                                                 fatal("lost hunk on alloc error!\n");
1922                                                         reverse = !reverse;
1923                                                         say("Ignoring previously applied (or reversed) patch.\n");
1924                                                         skip_rest_of_patch = true;
1925                                                 } else if (batch) {
1926                                                         if (verbosity != SILENT)
1927                                                                 say("%seversed (or previously applied) patch detected!  %s -R.",
1928                                                                     reverse ? "R" : "Unr",
1929                                                                     reverse ? "Assuming" : "Ignoring");
1930                                                 } else {
1931                                                         ask("%seversed (or previously applied) patch detected!  %s -R? [y] ",
1932                                                             reverse ? "R" : "Unr",
1933                                                             reverse ? "Assume" : "Ignore");
1934                                                         if (*buf == 'n') {
1935                                                                 ask("Apply anyway? [n] ");
1936                                                                 if (*buf != 'y')
1937                                                                         skip_rest_of_patch = true;
1938                                                                 else
1939                                                                         reverse_seen = true;
1940                                                                 where = 0;
1941                                                                 reverse = !reverse;
1942                                                                 if (!pch_swap())
1943                                                                         /* put it back to normal */
1944                                                                         fatal("lost hunk on alloc error!\n");
1945                                                         }
1946                                                 }
1947                                         }
1948                                 } while (!skip_rest_of_patch && where == 0 &&
1949                                     ++fuzz <= mymaxfuzz);
1950
1951                                 if (skip_rest_of_patch) {       /* just got decided */
1952                                         if (ferror(ofp) || fclose(ofp)) {
1953                                                 say("Error writing %s\n",
1954                                                     TMPOUTNAME);
1955                                                 error = 1;
1956                                         }
1957                                         ofp = NULL;
1958                                 }
1959                         }
1960                         newwhere = pch_newfirst() + last_offset;
1961                         if (skip_rest_of_patch) {
1962                                 abort_hunk();
1963                                 failed++;
1964                                 if (verbosity != SILENT)
1965                                         say("Hunk #%d ignored at %ld.\n",
1966                                             hunk, newwhere);
1967                         } else if (where == 0) {
1968                                 abort_hunk();
1969                                 failed++;
1970                                 if (verbosity != SILENT)
1971                                         say("Hunk #%d failed at %ld.\n",
1972                                             hunk, newwhere);
1973                         } else {
1974                                 apply_hunk(where);
1975                                 if (verbosity == VERBOSE
1976                                     || (verbosity != SILENT && (fuzz != 0 || last_offset)))
1977                                 {
1978                                         say("Hunk #%d succeeded at %ld",
1979                                             hunk, newwhere);
1980                                         if (fuzz != 0)
1981                                                 say(" with fuzz %ld", fuzz);
1982                                         if (last_offset)
1983                                                 say(" (offset %ld line%s)",
1984                                                     last_offset,
1985                                                     last_offset == 1L ? "" : "s");
1986                                         say(".\n");
1987                                 }
1988                         }
1989                 }
1990
1991                 if (out_of_mem && using_plan_a) {
1992                         Argc = Argc_last;
1993                         Argv = Argv_last;
1994                         say("\n\nRan out of memory using Plan A--trying again...\n\n");
1995                         if (ofp)
1996                                 fclose(ofp);
1997                         ofp = NULL;
1998                         if (rejfp)
1999                                 fclose(rejfp);
2000                         rejfp = NULL;
2001                         continue;
2002                 }
2003                 if (hunk == 0)
2004                         fatal("Internal error: hunk should not be 0\n");
2005
2006                 /* finish spewing out the new file */
2007                 if (!skip_rest_of_patch && !spew_output()) {
2008                         say("Can't write %s\n", TMPOUTNAME);
2009                         error = 1;
2010                 }
2011
2012                 /* and put the output where desired */
2013                 ignore_signals();
2014                 if (!skip_rest_of_patch) {
2015                         struct stat     statbuf;
2016                         char    *realout = outname;
2017
2018                         if (!check_only) {
2019                                 if (move_file(TMPOUTNAME, outname) < 0) {
2020                                         toutkeep = true;
2021                                         realout = TMPOUTNAME;
2022                                         chmod(TMPOUTNAME, filemode);
2023                                 } else
2024                                         chmod(outname, filemode);
2025
2026                                 if (remove_empty_files &&
2027                                     stat(realout, &statbuf) == 0 &&
2028                                     statbuf.st_size == 0) {
2029                                         if (verbosity == VERBOSE)
2030                                                 say("Removing %s (empty after patching).\n",
2031                                                     realout);
2032                                         unlink(realout);
2033                                 }
2034                         }
2035                 }
2036                 if (ferror(rejfp) || fclose(rejfp)) {
2037                         say("Error writing %s\n", rejname);
2038                         error = 1;
2039                 }
2040                 rejfp = NULL;
2041                 if (failed) {
2042                         error = 1;
2043                         if (*rejname == '\0') {
2044                                 if (strlcpy(rejname, outname,
2045                                     sizeof(rejname)) >= sizeof(rejname))
2046                                         fatal("filename %s is too long\n", outname);
2047                                 if (strlcat(rejname, REJEXT,
2048                                     sizeof(rejname)) >= sizeof(rejname))
2049                                         fatal("filename %s is too long\n", outname);
2050                         }
2051                         if (!check_only)
2052                                 say("%d out of %d hunks %s--saving rejects to %s\n",
2053                                     failed, hunk, skip_rest_of_patch ? "ignored" : "failed", rejname);
2054                         else
2055                                 say("%d out of %d hunks %s while patching %s\n",
2056                                     failed, hunk, skip_rest_of_patch ? "ignored" : "failed", filearg[0]);
2057                         if (!check_only && move_file(TMPREJNAME, rejname) < 0)
2058                                 trejkeep = true;
2059                 }
2060                 set_signals(1);
2061         }
2062
2063         if (!patch_seen)
2064                 error = 2;
2065
2066         my_exit(error);
2067         /* NOTREACHED */
2068 }
2069
2070 /* Prepare to find the next patch to do in the patch file. */
2071
2072 static void
2073 reinitialize_almost_everything(void)
2074 {
2075         re_patch();
2076         re_input();
2077
2078         input_lines = 0;
2079         last_frozen_line = 0;
2080
2081         filec = 0;
2082         if (!out_of_mem) {
2083                 free(filearg[0]);
2084                 filearg[0] = NULL;
2085         }
2086
2087         free(outname);
2088         outname = NULL;
2089
2090         last_offset = 0;
2091         diff_type = 0;
2092
2093         free(revision);
2094         revision = NULL;
2095
2096         reverse = reverse_flag_specified;
2097         skip_rest_of_patch = false;
2098
2099         get_some_switches();
2100 }
2101
2102 /* Process switches and filenames. */
2103
2104 static void
2105 get_some_switches(void)
2106 {
2107         const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:";
2108         static struct option longopts[] = {
2109                 {"backup",              no_argument,            0,      'b'},
2110                 {"batch",               no_argument,            0,      't'},
2111                 {"check",               no_argument,            0,      'C'},
2112                 {"context",             no_argument,            0,      'c'},
2113                 {"debug",               required_argument,      0,      'x'},
2114                 {"directory",           required_argument,      0,      'd'},
2115                 {"dry-run",             no_argument,            0,      'C'},
2116                 {"ed",                  no_argument,            0,      'e'},
2117                 {"force",               no_argument,            0,      'f'},
2118                 {"forward",             no_argument,            0,      'N'},
2119                 {"fuzz",                required_argument,      0,      'F'},
2120                 {"ifdef",               required_argument,      0,      'D'},
2121                 {"input",               required_argument,      0,      'i'},
2122                 {"ignore-whitespace",   no_argument,            0,      'l'},
2123                 {"normal",              no_argument,            0,      'n'},
2124                 {"output",              required_argument,      0,      'o'},
2125                 {"prefix",              required_argument,      0,      'B'},
2126                 {"quiet",               no_argument,            0,      's'},
2127                 {"reject-file",         required_argument,      0,      'r'},
2128                 {"remove-empty-files",  no_argument,            0,      'E'},
2129                 {"reverse",             no_argument,            0,      'R'},
2130                 {"silent",              no_argument,            0,      's'},
2131                 {"strip",               required_argument,      0,      'p'},
2132                 {"suffix",              required_argument,      0,      'z'},
2133                 {"unified",             no_argument,            0,      'u'},
2134                 {"version",             no_argument,            0,      'v'},
2135                 {"version-control",     required_argument,      0,      'V'},
2136                 {"posix",               no_argument,            &posix, 1},
2137                 {"verbose",             no_argument,            0,      2},
2138                 {NULL,                  0,                      0,      0}
2139         };
2140         int ch;
2141
2142         rejname[0] = '\0';
2143         Argc_last = Argc;
2144         Argv_last = Argv;
2145         if (!Argc)
2146                 return;
2147 #ifndef __sun__
2148         optreset = optind = 1;
2149 #endif
2150         while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) {
2151                 switch (ch) {
2152                 case  2 :
2153                         verbosity = VERBOSE;
2154                         break;
2155                 case 'b':
2156                         if (backup_type == none)
2157                                 backup_type = numbered_existing;
2158                         if (optarg == NULL)
2159                                 break;
2160                         if (verbosity != SILENT)
2161                                 say("Warning, the ``-b suffix'' option has been"
2162                                     " obsoleted by the -z option.\n");
2163                         /* FALLTHROUGH */
2164                 case 'z':
2165                         /* must directly follow 'b' case for backwards compat */
2166                         simple_backup_suffix = xstrdup(optarg);
2167                         break;
2168                 case 'B':
2169                         origprae = xstrdup(optarg);
2170                         break;
2171                 case 'c':
2172                         diff_type = CONTEXT_DIFF;
2173                         break;
2174                 case 'C':
2175                         check_only = true;
2176                         break;
2177                 case 'd':
2178                         if (chdir(optarg) < 0)
2179                                 pfatal("can't cd to %s", optarg);
2180                         break;
2181                 case 'D':
2182                         do_defines = true;
2183                         if (!isalpha((unsigned char)*optarg) && *optarg != '_')
2184                                 fatal("argument to -D is not an identifier\n");
2185                         snprintf(if_defined, sizeof if_defined,
2186                             "#ifdef %s\n", optarg);
2187                         snprintf(not_defined, sizeof not_defined,
2188                             "#ifndef %s\n", optarg);
2189                         snprintf(end_defined, sizeof end_defined,
2190                             "#endif /* %s */\n", optarg);
2191                         break;
2192                 case 'e':
2193                         diff_type = ED_DIFF;
2194                         break;
2195                 case 'E':
2196                         remove_empty_files = true;
2197                         break;
2198                 case 'f':
2199                         force = true;
2200                         break;
2201                 case 'F':
2202                         maxfuzz = atoi(optarg);
2203                         break;
2204                 case 'i':
2205                         if (++filec == MAXFILEC)
2206                                 fatal("too many file arguments\n");
2207                         filearg[filec] = xstrdup(optarg);
2208                         break;
2209                 case 'l':
2210                         canonicalize = true;
2211                         break;
2212                 case 'n':
2213                         diff_type = NORMAL_DIFF;
2214                         break;
2215                 case 'N':
2216                         noreverse = true;
2217                         break;
2218                 case 'o':
2219                         outname = xstrdup(optarg);
2220                         break;
2221                 case 'p':
2222                         strippath = atoi(optarg);
2223                         break;
2224                 case 'r':
2225                         if (strlcpy(rejname, optarg,
2226                             sizeof(rejname)) >= sizeof(rejname))
2227                                 fatal("argument for -r is too long\n");
2228                         break;
2229                 case 'R':
2230                         reverse = true;
2231                         reverse_flag_specified = true;
2232                         break;
2233                 case 's':
2234                         verbosity = SILENT;
2235                         break;
2236                 case 't':
2237                         batch = true;
2238                         break;
2239                 case 'u':
2240                         diff_type = UNI_DIFF;
2241                         break;
2242                 case 'v':
2243                         version();
2244                         break;
2245                 case 'V':
2246                         backup_type = get_version(optarg);
2247                         Vflag = true;
2248                         break;
2249 #ifdef DEBUGGING
2250                 case 'x':
2251                         debug = atoi(optarg);
2252                         break;
2253 #endif
2254                 default:
2255                         if (ch != '\0')
2256                                 usage();
2257                         break;
2258                 }
2259         }
2260         Argc -= optind;
2261         Argv += optind;
2262
2263         if (Argc > 0) {
2264                 filearg[0] = xstrdup(*Argv++);
2265                 Argc--;
2266                 while (Argc > 0) {
2267                         if (++filec == MAXFILEC)
2268                                 fatal("too many file arguments\n");
2269                         filearg[filec] = xstrdup(*Argv++);
2270                         Argc--;
2271                 }
2272         }
2273
2274         if (getenv("POSIXLY_CORRECT") != NULL)
2275                 posix = 1;
2276 }
2277
2278 static void
2279 usage(void)
2280 {
2281         fprintf(stderr,
2282 "usage: patch [-bCcEeflNnRstuv] [-B backup-prefix] [-D symbol] [-d directory]\n"
2283 "             [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n"
2284 "             [-r rej-name] [-V t | nil | never | none] [-x number]\n"
2285 "             [-z backup-ext] [--posix] [origfile [patchfile]]\n"
2286 "       patch <patchfile\n");
2287         my_exit(EXIT_FAILURE);
2288 }
2289
2290 /*
2291  * Attempt to find the right place to apply this hunk of patch.
2292  */
2293 static LINENUM
2294 locate_hunk(LINENUM fuzz)
2295 {
2296         LINENUM first_guess = pch_first() + last_offset;
2297         LINENUM offset;
2298         LINENUM pat_lines = pch_ptrn_lines();
2299         LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1;
2300         LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context();
2301
2302         if (pat_lines == 0) {           /* null range matches always */
2303                 if (verbosity == VERBOSE && fuzz == 0 && (diff_type == CONTEXT_DIFF
2304                     || diff_type == NEW_CONTEXT_DIFF
2305                     || diff_type == UNI_DIFF)) {
2306                         say("Empty context always matches.\n");
2307                 }
2308                 return (first_guess);
2309         }
2310         if (max_neg_offset >= first_guess)      /* do not try lines < 0 */
2311                 max_neg_offset = first_guess - 1;
2312         if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz))
2313                 return first_guess;
2314         for (offset = 1; ; offset++) {
2315                 bool    check_after = (offset <= max_pos_offset);
2316                 bool    check_before = (offset <= max_neg_offset);
2317
2318                 if (check_after && patch_match(first_guess, offset, fuzz)) {
2319 #ifdef DEBUGGING
2320                         if (debug & 1)
2321                                 say("Offset changing from %ld to %ld\n",
2322                                     last_offset, offset);
2323 #endif
2324                         last_offset = offset;
2325                         return first_guess + offset;
2326                 } else if (check_before && patch_match(first_guess, -offset, fuzz)) {
2327 #ifdef DEBUGGING
2328                         if (debug & 1)
2329                                 say("Offset changing from %ld to %ld\n",
2330                                     last_offset, -offset);
2331 #endif
2332                         last_offset = -offset;
2333                         return first_guess - offset;
2334                 } else if (!check_before && !check_after)
2335                         return 0;
2336         }
2337 }
2338
2339 /* We did not find the pattern, dump out the hunk so they can handle it. */
2340
2341 static void
2342 abort_context_hunk(void)
2343 {
2344         LINENUM i;
2345         const LINENUM   pat_end = pch_end();
2346         /*
2347          * add in last_offset to guess the same as the previous successful
2348          * hunk
2349          */
2350         const LINENUM   oldfirst = pch_first() + last_offset;
2351         const LINENUM   newfirst = pch_newfirst() + last_offset;
2352         const LINENUM   oldlast = oldfirst + pch_ptrn_lines() - 1;
2353         const LINENUM   newlast = newfirst + pch_repl_lines() - 1;
2354         const char      *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : "");
2355         const char      *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----");
2356
2357         fprintf(rejfp, "***************\n");
2358         for (i = 0; i <= pat_end; i++) {
2359                 switch (pch_char(i)) {
2360                 case '*':
2361                         if (oldlast < oldfirst)
2362                                 fprintf(rejfp, "*** 0%s\n", stars);
2363                         else if (oldlast == oldfirst)
2364                                 fprintf(rejfp, "*** %ld%s\n", oldfirst, stars);
2365                         else
2366                                 fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst,
2367                                     oldlast, stars);
2368                         break;
2369                 case '=':
2370                         if (newlast < newfirst)
2371                                 fprintf(rejfp, "--- 0%s\n", minuses);
2372                         else if (newlast == newfirst)
2373                                 fprintf(rejfp, "--- %ld%s\n", newfirst, minuses);
2374                         else
2375                                 fprintf(rejfp, "--- %ld,%ld%s\n", newfirst,
2376                                     newlast, minuses);
2377                         break;
2378                 case '\n':
2379                         fprintf(rejfp, "%s", pfetch(i));
2380                         break;
2381                 case ' ':
2382                 case '-':
2383                 case '+':
2384                 case '!':
2385                         fprintf(rejfp, "%c %s", pch_char(i), pfetch(i));
2386                         break;
2387                 default:
2388                         fatal("fatal internal error in abort_context_hunk\n");
2389                 }
2390         }
2391 }
2392
2393 static void
2394 rej_line(int ch, LINENUM i)
2395 {
2396         size_t len;
2397         const char *line = pfetch(i);
2398
2399         len = strlen(line);
2400
2401         fprintf(rejfp, "%c%s", ch, line);
2402         if (len == 0 || line[len - 1] != '\n') {
2403                 if (len >= USHRT_MAX)
2404                         fprintf(rejfp, "\n\\ Line too long\n");
2405                 else
2406                         fprintf(rejfp, "\n\\ No newline at end of line\n");
2407         }
2408 }
2409
2410 static void
2411 abort_hunk(void)
2412 {
2413         LINENUM         i, j, split;
2414         int             ch1, ch2;
2415         const LINENUM   pat_end = pch_end();
2416         const LINENUM   oldfirst = pch_first() + last_offset;
2417         const LINENUM   newfirst = pch_newfirst() + last_offset;
2418
2419         if (diff_type != UNI_DIFF) {
2420                 abort_context_hunk();
2421                 return;
2422         }
2423         split = -1;
2424         for (i = 0; i <= pat_end; i++) {
2425                 if (pch_char(i) == '=') {
2426                         split = i;
2427                         break;
2428                 }
2429         }
2430         if (split == -1) {
2431                 fprintf(rejfp, "malformed hunk: no split found\n");
2432                 return;
2433         }
2434         i = 0;
2435         j = split + 1;
2436         fprintf(rejfp, "@@ -%ld,%ld +%ld,%ld @@\n",
2437             pch_ptrn_lines() ? oldfirst : 0,
2438             pch_ptrn_lines(), newfirst, pch_repl_lines());
2439         while (i < split || j <= pat_end) {
2440                 ch1 = i < split ? pch_char(i) : -1;
2441                 ch2 = j <= pat_end ? pch_char(j) : -1;
2442                 if (ch1 == '-') {
2443                         rej_line('-', i);
2444                         i++;
2445                 } else if (ch1 == ' ' && ch2 == ' ') {
2446                         rej_line(' ', i);
2447                         i++;
2448                         j++;
2449                 } else if (ch1 == '!' && ch2 == '!') {
2450                         while (i < split && ch1 == '!') {
2451                                 rej_line('-', i);
2452                                 i++;
2453                                 ch1 = i < split ? pch_char(i) : -1;
2454                         }
2455                         while (j <= pat_end && ch2 == '!') {
2456                                 rej_line('+', j);
2457                                 j++;
2458                                 ch2 = j <= pat_end ? pch_char(j) : -1;
2459                         }
2460                 } else if (ch1 == '*') {
2461                         i++;
2462                 } else if (ch2 == '+' || ch2 == ' ') {
2463                         rej_line(ch2, j);
2464                         j++;
2465                 } else {
2466                         fprintf(rejfp, "internal error on (%ld %ld %ld)\n",
2467                             i, split, j);
2468                         rej_line(ch1, i);
2469                         rej_line(ch2, j);
2470                         return;
2471                 }
2472         }
2473 }
2474
2475 /* We found where to apply it (we hope), so do it. */
2476
2477 static void
2478 apply_hunk(LINENUM where)
2479 {
2480         LINENUM         old = 1;
2481         const LINENUM   lastline = pch_ptrn_lines();
2482         LINENUM         new = lastline + 1;
2483 #define OUTSIDE 0
2484 #define IN_IFNDEF 1
2485 #define IN_IFDEF 2
2486 #define IN_ELSE 3
2487         int             def_state = OUTSIDE;
2488         const LINENUM   pat_end = pch_end();
2489
2490         where--;
2491         while (pch_char(new) == '=' || pch_char(new) == '\n')
2492                 new++;
2493
2494         while (old <= lastline) {
2495                 if (pch_char(old) == '-') {
2496                         copy_till(where + old - 1, false);
2497                         if (do_defines) {
2498                                 if (def_state == OUTSIDE) {
2499                                         fputs(not_defined, ofp);
2500                                         def_state = IN_IFNDEF;
2501                                 } else if (def_state == IN_IFDEF) {
2502                                         fputs(else_defined, ofp);
2503                                         def_state = IN_ELSE;
2504                                 }
2505                                 fputs(pfetch(old), ofp);
2506                         }
2507                         last_frozen_line++;
2508                         old++;
2509                 } else if (new > pat_end) {
2510                         break;
2511                 } else if (pch_char(new) == '+') {
2512                         copy_till(where + old - 1, false);
2513                         if (do_defines) {
2514                                 if (def_state == IN_IFNDEF) {
2515                                         fputs(else_defined, ofp);
2516                                         def_state = IN_ELSE;
2517                                 } else if (def_state == OUTSIDE) {
2518                                         fputs(if_defined, ofp);
2519                                         def_state = IN_IFDEF;
2520                                 }
2521                         }
2522                         fputs(pfetch(new), ofp);
2523                         new++;
2524                 } else if (pch_char(new) != pch_char(old)) {
2525                         say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n",
2526                             pch_hunk_beg() + old,
2527                             pch_hunk_beg() + new);
2528 #ifdef DEBUGGING
2529                         say("oldchar = '%c', newchar = '%c'\n",
2530                             pch_char(old), pch_char(new));
2531 #endif
2532                         my_exit(2);
2533                 } else if (pch_char(new) == '!') {
2534                         copy_till(where + old - 1, false);
2535                         if (do_defines) {
2536                                 fputs(not_defined, ofp);
2537                                 def_state = IN_IFNDEF;
2538                         }
2539                         while (pch_char(old) == '!') {
2540                                 if (do_defines) {
2541                                         fputs(pfetch(old), ofp);
2542                                 }
2543                                 last_frozen_line++;
2544                                 old++;
2545                         }
2546                         if (do_defines) {
2547                                 fputs(else_defined, ofp);
2548                                 def_state = IN_ELSE;
2549                         }
2550                         while (pch_char(new) == '!') {
2551                                 fputs(pfetch(new), ofp);
2552                                 new++;
2553                         }
2554                 } else {
2555                         if (pch_char(new) != ' ')
2556                                 fatal("Internal error: expected ' '\n");
2557                         old++;
2558                         new++;
2559                         if (do_defines && def_state != OUTSIDE) {
2560                                 fputs(end_defined, ofp);
2561                                 def_state = OUTSIDE;
2562                         }
2563                 }
2564         }
2565         if (new <= pat_end && pch_char(new) == '+') {
2566                 copy_till(where + old - 1, false);
2567                 if (do_defines) {
2568                         if (def_state == OUTSIDE) {
2569                                 fputs(if_defined, ofp);
2570                                 def_state = IN_IFDEF;
2571                         } else if (def_state == IN_IFNDEF) {
2572                                 fputs(else_defined, ofp);
2573                                 def_state = IN_ELSE;
2574                         }
2575                 }
2576                 while (new <= pat_end && pch_char(new) == '+') {
2577                         fputs(pfetch(new), ofp);
2578                         new++;
2579                 }
2580         }
2581         if (do_defines && def_state != OUTSIDE) {
2582                 fputs(end_defined, ofp);
2583         }
2584 }
2585
2586 /*
2587  * Open the new file.
2588  */
2589 static void
2590 init_output(const char *name)
2591 {
2592         ofp = fopen(name, "w");
2593         if (ofp == NULL)
2594                 pfatal("can't create %s", name);
2595 }
2596
2597 /*
2598  * Open a file to put hunks we can't locate.
2599  */
2600 static void
2601 init_reject(const char *name)
2602 {
2603         rejfp = fopen(name, "w");
2604         if (rejfp == NULL)
2605                 pfatal("can't create %s", name);
2606 }
2607
2608 /*
2609  * Copy input file to output, up to wherever hunk is to be applied.
2610  * If endoffile is true, treat the last line specially since it may
2611  * lack a newline.
2612  */
2613 static void
2614 copy_till(LINENUM lastline, bool endoffile)
2615 {
2616         if (last_frozen_line > lastline)
2617                 fatal("misordered hunks! output would be garbled\n");
2618         while (last_frozen_line < lastline) {
2619                 if (++last_frozen_line == lastline && endoffile)
2620                         dump_line(last_frozen_line, !last_line_missing_eol);
2621                 else
2622                         dump_line(last_frozen_line, true);
2623         }
2624 }
2625
2626 /*
2627  * Finish copying the input file to the output file.
2628  */
2629 static bool
2630 spew_output(void)
2631 {
2632         int rv;
2633
2634 #ifdef DEBUGGING
2635         if (debug & 256)
2636                 say("il=%ld lfl=%ld\n", input_lines, last_frozen_line);
2637 #endif
2638         if (input_lines)
2639                 copy_till(input_lines, true);   /* dump remainder of file */
2640         rv = ferror(ofp) == 0 && fclose(ofp) == 0;
2641         ofp = NULL;
2642         return rv;
2643 }
2644
2645 /*
2646  * Copy one line from input to output.
2647  */
2648 static void
2649 dump_line(LINENUM line, bool write_newline)
2650 {
2651         char    *s;
2652
2653         s = ifetch(line, 0);
2654         if (s == NULL)
2655                 return;
2656         /* Note: string is not NUL terminated. */
2657         for (; *s != '\n'; s++)
2658                 putc(*s, ofp);
2659         if (write_newline)
2660                 putc('\n', ofp);
2661 }
2662
2663 /*
2664  * Does the patch pattern match at line base+offset?
2665  */
2666 static bool
2667 patch_match(LINENUM base, LINENUM offset, LINENUM fuzz)
2668 {
2669         LINENUM         pline = 1 + fuzz;
2670         LINENUM         iline;
2671         LINENUM         pat_lines = pch_ptrn_lines() - fuzz;
2672         const char      *ilineptr;
2673         const char      *plineptr;
2674         unsigned short  plinelen;
2675
2676         for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) {
2677                 ilineptr = ifetch(iline, offset >= 0);
2678                 if (ilineptr == NULL)
2679                         return false;
2680                 plineptr = pfetch(pline);
2681                 plinelen = pch_line_len(pline);
2682                 if (canonicalize) {
2683                         if (!similar(ilineptr, plineptr, plinelen))
2684                                 return false;
2685                 } else if (strnNE(ilineptr, plineptr, plinelen))
2686                         return false;
2687                 if (iline == input_lines) {
2688                         /*
2689                          * We are looking at the last line of the file.
2690                          * If the file has no eol, the patch line should
2691                          * not have one either and vice-versa. Note that
2692                          * plinelen > 0.
2693                          */
2694                         if (last_line_missing_eol) {
2695                                 if (plineptr[plinelen - 1] == '\n')
2696                                         return false;
2697                         } else {
2698                                 if (plineptr[plinelen - 1] != '\n')
2699                                         return false;
2700                         }
2701                 }
2702         }
2703         return true;
2704 }
2705
2706 /*
2707  * Do two lines match with canonicalized white space?
2708  */
2709 static bool
2710 similar(const char *a, const char *b, int len)
2711 {
2712         while (len) {
2713                 if (isspace((unsigned char)*b)) {       /* whitespace (or \n) to match? */
2714                         if (!isspace((unsigned char)*a))        /* no corresponding whitespace? */
2715                                 return false;
2716                         while (len && isspace((unsigned char)*b) && *b != '\n')
2717                                 b++, len--;     /* skip pattern whitespace */
2718                         while (isspace((unsigned char)*a) && *a != '\n')
2719                                 a++;    /* skip target whitespace */
2720                         if (*a == '\n' || *b == '\n')
2721                                 return (*a == *b);      /* should end in sync */
2722                 } else if (*a++ != *b++)        /* match non-whitespace chars */
2723                         return false;
2724                 else
2725                         len--;  /* probably not necessary */
2726         }
2727         return true;            /* actually, this is not reached */
2728         /* since there is always a \n */
2729 }
2730
2731
2732 [FILE:49:files/pathnames.h]
2733 #include <paths.h>
2734 #define _PATH_RED               "/bin/red"
2735
2736
2737 [FILE:39374:files/pch.c]
2738 #include <sys/types.h>
2739 #include <sys/stat.h>
2740
2741 #include <ctype.h>
2742 #include <libgen.h>
2743 #include <limits.h>
2744 #include <stdint.h>
2745 #include <stdio.h>
2746 #include <stdlib.h>
2747 #include <string.h>
2748 #include <unistd.h>
2749
2750 #include "common.h"
2751 #include "util.h"
2752 #include "pch.h"
2753 #include "pathnames.h"
2754
2755 /* Patch (diff listing) abstract type. */
2756
2757 static off_t    p_filesize;     /* size of the patch file */
2758 static LINENUM  p_first;        /* 1st line number */
2759 static LINENUM  p_newfirst;     /* 1st line number of replacement */
2760 static LINENUM  p_ptrn_lines;   /* # lines in pattern */
2761 static LINENUM  p_repl_lines;   /* # lines in replacement text */
2762 static LINENUM  p_end = -1;     /* last line in hunk */
2763 static LINENUM  p_max;          /* max allowed value of p_end */
2764 static LINENUM  p_context = 3;  /* # of context lines */
2765 static LINENUM  p_input_line = 0;       /* current line # from patch file */
2766 static char     **p_line = NULL;/* the text of the hunk */
2767 static unsigned short   *p_len = NULL; /* length of each line */
2768 static char     *p_char = NULL; /* +, -, and ! */
2769 static int      hunkmax = INITHUNKMAX;  /* size of above arrays to begin with */
2770 static int      p_indent;       /* indent to patch */
2771 static off_t    p_base;         /* where to intuit this time */
2772 static LINENUM  p_bline;        /* line # of p_base */
2773 static off_t    p_start;        /* where intuit found a patch */
2774 static LINENUM  p_sline;        /* and the line number for it */
2775 static LINENUM  p_hunk_beg;     /* line number of current hunk */
2776 static LINENUM  p_efake = -1;   /* end of faked up lines--don't free */
2777 static LINENUM  p_bfake = -1;   /* beg of faked up lines */
2778 static FILE     *pfp = NULL;    /* patch file pointer */
2779 static char     *bestguess = NULL;      /* guess at correct filename */
2780
2781 static void     grow_hunkmax(void);
2782 static int      intuit_diff_type(void);
2783 static void     next_intuit_at(off_t, LINENUM);
2784 static void     skip_to(off_t, LINENUM);
2785 static size_t   pgets(bool _do_indent);
2786 static char     *best_name(const struct file_name *, bool);
2787 static char     *posix_name(const struct file_name *, bool);
2788 static size_t   num_components(const char *);
2789 static LINENUM  strtolinenum(char *, char **);
2790
2791 /*
2792  * Prepare to look for the next patch in the patch file.
2793  */
2794 void
2795 re_patch(void)
2796 {
2797         p_first = 0;
2798         p_newfirst = 0;
2799         p_ptrn_lines = 0;
2800         p_repl_lines = 0;
2801         p_end = (LINENUM) - 1;
2802         p_max = 0;
2803         p_indent = 0;
2804 }
2805
2806 /*
2807  * Open the patch file at the beginning of time.
2808  */
2809 void
2810 open_patch_file(const char *filename)
2811 {
2812         struct stat filestat;
2813         int nr, nw;
2814
2815         if (filename == NULL || *filename == '\0' || strEQ(filename, "-")) {
2816                 pfp = fopen(TMPPATNAME, "w");
2817                 if (pfp == NULL)
2818                         pfatal("can't create %s", TMPPATNAME);
2819                 while ((nr = fread(buf, 1, buf_size, stdin)) > 0) {
2820                         nw = fwrite(buf, 1, nr, pfp);
2821                         if (nr != nw)
2822                                 pfatal("write error to %s", TMPPATNAME);
2823                 }
2824                 if (ferror(pfp) || fclose(pfp))
2825                         pfatal("can't write %s", TMPPATNAME);
2826                 filename = TMPPATNAME;
2827         }
2828         pfp = fopen(filename, "r");
2829         if (pfp == NULL)
2830                 pfatal("patch file %s not found", filename);
2831         if (fstat(fileno(pfp), &filestat))
2832                 pfatal("can't stat %s", filename);
2833         p_filesize = filestat.st_size;
2834         next_intuit_at(0, 1L);  /* start at the beginning */
2835         set_hunkmax();
2836 }
2837
2838 /*
2839  * Make sure our dynamically realloced tables are malloced to begin with.
2840  */
2841 void
2842 set_hunkmax(void)
2843 {
2844         if (p_line == NULL)
2845                 p_line = malloc(hunkmax * sizeof(char *));
2846         if (p_len == NULL)
2847                 p_len = malloc(hunkmax * sizeof(unsigned short));
2848         if (p_char == NULL)
2849                 p_char = malloc(hunkmax * sizeof(char));
2850 }
2851
2852 /*
2853  * Enlarge the arrays containing the current hunk of patch.
2854  */
2855 static void
2856 grow_hunkmax(void)
2857 {
2858         int new_hunkmax = hunkmax * 2;
2859
2860         if (p_line == NULL || p_len == NULL || p_char == NULL)
2861                 fatal("Internal memory allocation error\n");
2862
2863         p_line = reallocf(p_line, new_hunkmax * sizeof(char *));
2864         p_len = reallocf(p_len, new_hunkmax * sizeof(unsigned short));
2865         p_char = reallocf(p_char, new_hunkmax * sizeof(char));
2866
2867         if (p_line != NULL && p_len != NULL && p_char != NULL) {
2868                 hunkmax = new_hunkmax;
2869                 return;
2870         }
2871
2872         if (!using_plan_a)
2873                 fatal("out of memory\n");
2874         out_of_mem = true;      /* whatever is null will be allocated again */
2875                                 /* from within plan_a(), of all places */
2876 }
2877
2878 /* True if the remainder of the patch file contains a diff of some sort. */
2879
2880 bool
2881 there_is_another_patch(void)
2882 {
2883         bool exists = false;
2884
2885         if (p_base != 0 && p_base >= p_filesize) {
2886                 if (verbosity == VERBOSE)
2887                         say("done\n");
2888                 return false;
2889         }
2890         if (verbosity == VERBOSE)
2891                 say("Hmm...");
2892         diff_type = intuit_diff_type();
2893         if (!diff_type) {
2894                 if (p_base != 0) {
2895                         if (verbosity == VERBOSE)
2896                                 say("  Ignoring the trailing garbage.\ndone\n");
2897                 } else
2898                         say("  I can't seem to find a patch in there anywhere.\n");
2899                 return false;
2900         }
2901         if (verbosity == VERBOSE)
2902                 say("  %sooks like %s to me...\n",
2903                     (p_base == 0 ? "L" : "The next patch l"),
2904                     diff_type == UNI_DIFF ? "a unified diff" :
2905                     diff_type == CONTEXT_DIFF ? "a context diff" :
2906                 diff_type == NEW_CONTEXT_DIFF ? "a new-style context diff" :
2907                     diff_type == NORMAL_DIFF ? "a normal diff" :
2908                     "an ed script");
2909         if (p_indent && (verbosity == VERBOSE))
2910                 say("(Patch is indented %d space%s.)\n", p_indent,
2911                     p_indent == 1 ? "" : "s");
2912         skip_to(p_start, p_sline);
2913         while (filearg[0] == NULL) {
2914                 if (force || batch) {
2915                         say("No file to patch.  Skipping...\n");
2916                         filearg[0] = xstrdup(bestguess);
2917                         skip_rest_of_patch = true;
2918                         return true;
2919                 }
2920                 ask("File to patch: ");
2921                 if (*buf != '\n') {
2922                         free(bestguess);
2923                         bestguess = xstrdup(buf);
2924                         filearg[0] = fetchname(buf, &exists, 0);
2925                 }
2926                 if (!exists) {
2927                         int def_skip = *bestguess == '\0';
2928                         ask("No file found--skip this patch? [%c] ",
2929                             def_skip  ? 'y' : 'n');
2930                         if (*buf == 'n' || (!def_skip && *buf != 'y'))
2931                                 continue;
2932                         if (verbosity != SILENT)
2933                                 say("Skipping patch...\n");
2934                         free(filearg[0]);
2935                         filearg[0] = fetchname(bestguess, &exists, 0);
2936                         skip_rest_of_patch = true;
2937                         return true;
2938                 }
2939         }
2940         return true;
2941 }
2942
2943 static void
2944 p4_fetchname(struct file_name *name, char *str)
2945 {
2946         char *t, *h;
2947
2948         /* Skip leading whitespace. */
2949         while (isspace((unsigned char)*str))
2950                 str++;
2951
2952         /* Remove the file revision number. */
2953         for (t = str, h = NULL; *t != '\0' && !isspace((unsigned char)*t); t++)
2954                 if (*t == '#')
2955                         h = t;
2956         if (h != NULL)
2957                 *h = '\0';
2958
2959         name->path = fetchname(str, &name->exists, strippath);
2960 }
2961
2962 /* Determine what kind of diff is in the remaining part of the patch file. */
2963
2964 static int
2965 intuit_diff_type(void)
2966 {
2967         off_t   this_line = 0, previous_line;
2968         off_t   first_command_line = -1;
2969         LINENUM fcl_line = -1;
2970         bool    last_line_was_command = false, this_is_a_command = false;
2971         bool    stars_last_line = false, stars_this_line = false;
2972         char    *s, *t;
2973         int     indent, retval;
2974         struct file_name names[MAX_FILE];
2975         int     piece_of_git = 0;
2976
2977         memset(names, 0, sizeof(names));
2978         ok_to_create_file = false;
2979         fseeko(pfp, p_base, SEEK_SET);
2980         p_input_line = p_bline - 1;
2981         for (;;) {
2982                 previous_line = this_line;
2983                 last_line_was_command = this_is_a_command;
2984                 stars_last_line = stars_this_line;
2985                 this_line = ftello(pfp);
2986                 indent = 0;
2987                 p_input_line++;
2988                 if (pgets(false) == 0) {
2989                         if (first_command_line >= 0) {
2990                                 /* nothing but deletes!? */
2991                                 p_start = first_command_line;
2992                                 p_sline = fcl_line;
2993                                 retval = ED_DIFF;
2994                                 goto scan_exit;
2995                         } else {
2996                                 p_start = this_line;
2997                                 p_sline = p_input_line;
2998                                 retval = 0;
2999                                 goto scan_exit;
3000                         }
3001                 }
3002                 for (s = buf; *s == ' ' || *s == '\t' || *s == 'X'; s++) {
3003                         if (*s == '\t')
3004                                 indent += 8 - (indent % 8);
3005                         else
3006                                 indent++;
3007                 }
3008                 for (t = s; isdigit((unsigned char)*t) || *t == ','; t++)
3009                         ;
3010                 this_is_a_command = (isdigit((unsigned char)*s) &&
3011                     (*t == 'd' || *t == 'c' || *t == 'a'));
3012                 if (first_command_line < 0 && this_is_a_command) {
3013                         first_command_line = this_line;
3014                         fcl_line = p_input_line;
3015                         p_indent = indent;      /* assume this for now */
3016                 }
3017                 if (!stars_last_line && strnEQ(s, "*** ", 4))
3018                         names[OLD_FILE].path = fetchname(s + 4,
3019                             &names[OLD_FILE].exists, strippath);
3020                 else if (strnEQ(s, "--- ", 4)) {
3021                         size_t off = 4;
3022                         if (piece_of_git && strippath == 957)
3023                                 off = 6;
3024                         names[NEW_FILE].path = fetchname(s + off,
3025                             &names[NEW_FILE].exists, strippath);
3026                 } else if (strnEQ(s, "+++ ", 4)) {
3027                         /* pretend it is the old name */
3028                         size_t off = 4;
3029                         if (piece_of_git && strippath == 957)
3030                                 off = 6;
3031                         names[OLD_FILE].path = fetchname(s + off,
3032                             &names[OLD_FILE].exists, strippath);
3033                 } else if (strnEQ(s, "Index:", 6))
3034                         names[INDEX_FILE].path = fetchname(s + 6,
3035                             &names[INDEX_FILE].exists, strippath);
3036                 else if (strnEQ(s, "Prereq:", 7)) {
3037                         for (t = s + 7; isspace((unsigned char)*t); t++)
3038                                 ;
3039                         revision = xstrdup(t);
3040                         for (t = revision;
3041                              *t && !isspace((unsigned char)*t); t++)
3042                                 ;
3043                         *t = '\0';
3044                         if (*revision == '\0') {
3045                                 free(revision);
3046                                 revision = NULL;
3047                         }
3048                 } else if (strnEQ(s, "diff --git a/", 13)) {
3049                         /* Git-style diffs. */
3050                         piece_of_git = 1;
3051                 } else if (strnEQ(s, "==== ", 5)) {
3052                         /* Perforce-style diffs. */
3053                         if ((t = strstr(s + 5, " - ")) != NULL)
3054                                 p4_fetchname(&names[NEW_FILE], t + 3);
3055                         p4_fetchname(&names[OLD_FILE], s + 5);
3056                 }
3057                 if ((!diff_type || diff_type == ED_DIFF) &&
3058                     first_command_line >= 0 &&
3059                     strEQ(s, ".\n")) {
3060                         p_indent = indent;
3061                         p_start = first_command_line;
3062                         p_sline = fcl_line;
3063                         retval = ED_DIFF;
3064                         goto scan_exit;
3065                 }
3066                 if ((!diff_type || diff_type == UNI_DIFF) && strnEQ(s, "@@ -", 4)) {
3067                         if (strnEQ(s + 4, "0,0", 3))
3068                                 ok_to_create_file = true;
3069                         p_indent = indent;
3070                         p_start = this_line;
3071                         p_sline = p_input_line;
3072                         retval = UNI_DIFF;
3073                         goto scan_exit;
3074                 }
3075                 stars_this_line = strnEQ(s, "********", 8);
3076                 if ((!diff_type || diff_type == CONTEXT_DIFF) && stars_last_line &&
3077                     strnEQ(s, "*** ", 4)) {
3078                         if (strtolinenum(s + 4, &s) == 0)
3079                                 ok_to_create_file = true;
3080                         /*
3081                          * If this is a new context diff the character just
3082                          * at the end of the line is a '*'.
3083                          */
3084                         while (*s && *s != '\n')
3085                                 s++;
3086                         p_indent = indent;
3087                         p_start = previous_line;
3088                         p_sline = p_input_line - 1;
3089                         retval = (*(s - 1) == '*' ? NEW_CONTEXT_DIFF : CONTEXT_DIFF);
3090                         goto scan_exit;
3091                 }
3092                 if ((!diff_type || diff_type == NORMAL_DIFF) &&
3093                     last_line_was_command &&
3094                     (strnEQ(s, "< ", 2) || strnEQ(s, "> ", 2))) {
3095                         p_start = previous_line;
3096                         p_sline = p_input_line - 1;
3097                         p_indent = indent;
3098                         retval = NORMAL_DIFF;
3099                         goto scan_exit;
3100                 }
3101         }
3102 scan_exit:
3103         if (retval == UNI_DIFF) {
3104                 /* unswap old and new */
3105                 struct file_name tmp = names[OLD_FILE];
3106                 names[OLD_FILE] = names[NEW_FILE];
3107                 names[NEW_FILE] = tmp;
3108         }
3109         if (filearg[0] == NULL) {
3110                 if (posix)
3111                         filearg[0] = posix_name(names, ok_to_create_file);
3112                 else {
3113                         /* Ignore the Index: name for context diffs, like GNU */
3114                         if (names[OLD_FILE].path != NULL ||
3115                             names[NEW_FILE].path != NULL) {
3116                                 free(names[INDEX_FILE].path);
3117                                 names[INDEX_FILE].path = NULL;
3118                         }
3119                         filearg[0] = best_name(names, ok_to_create_file);
3120                 }
3121         }
3122
3123         free(bestguess);
3124         bestguess = NULL;
3125         if (filearg[0] != NULL)
3126                 bestguess = xstrdup(filearg[0]);
3127         else if (!ok_to_create_file) {
3128                 /*
3129                  * We don't want to create a new file but we need a
3130                  * filename to set bestguess.  Avoid setting filearg[0]
3131                  * so the file is not created automatically.
3132                  */
3133                 if (posix)
3134                         bestguess = posix_name(names, true);
3135                 else
3136                         bestguess = best_name(names, true);
3137         }
3138         free(names[OLD_FILE].path);
3139         free(names[NEW_FILE].path);
3140         free(names[INDEX_FILE].path);
3141         return retval;
3142 }
3143
3144 /*
3145  * Remember where this patch ends so we know where to start up again.
3146  */
3147 static void
3148 next_intuit_at(off_t file_pos, LINENUM file_line)
3149 {
3150         p_base = file_pos;
3151         p_bline = file_line;
3152 }
3153
3154 /*
3155  * Basically a verbose fseeko() to the actual diff listing.
3156  */
3157 static void
3158 skip_to(off_t file_pos, LINENUM file_line)
3159 {
3160         size_t  len;
3161
3162         if (p_base > file_pos)
3163                 fatal("Internal error: seek %lld>%lld\n",
3164                    (long long)p_base, (long long)file_pos);
3165         if (verbosity == VERBOSE && p_base < file_pos) {
3166                 fseeko(pfp, p_base, SEEK_SET);
3167                 say("The text leading up to this was:\n--------------------------\n");
3168                 while (ftello(pfp) < file_pos) {
3169                         len = pgets(false);
3170                         if (len == 0)
3171                                 fatal("Unexpected end of file\n");
3172                         say("|%s", buf);
3173                 }
3174                 say("--------------------------\n");
3175         } else
3176                 fseeko(pfp, file_pos, SEEK_SET);
3177         p_input_line = file_line - 1;
3178 }
3179
3180 /* Make this a function for better debugging.  */
3181 static void
3182 malformed(void)
3183 {
3184         fatal("malformed patch at line %ld: %s", p_input_line, buf);
3185         /* about as informative as "Syntax error" in C */
3186 }
3187
3188 /*
3189  * True if the line has been discarded (i.e. it is a line saying
3190  *  "\ No newline at end of file".)
3191  */
3192 static bool
3193 remove_special_line(void)
3194 {
3195         int     c;
3196
3197         c = fgetc(pfp);
3198         if (c == '\\') {
3199                 do {
3200                         c = fgetc(pfp);
3201                 } while (c != EOF && c != '\n');
3202
3203                 return true;
3204         }
3205         if (c != EOF)
3206                 fseeko(pfp, -1, SEEK_CUR);
3207
3208         return false;
3209 }
3210
3211 /*
3212  * True if there is more of the current diff listing to process.
3213  */
3214 bool
3215 another_hunk(void)
3216 {
3217         off_t   line_beginning;                 /* file pos of the current line */
3218         LINENUM repl_beginning;                 /* index of --- line */
3219         LINENUM fillcnt;                        /* #lines of missing ptrn or repl */
3220         LINENUM fillsrc;                        /* index of first line to copy */
3221         LINENUM filldst;                        /* index of first missing line */
3222         bool    ptrn_spaces_eaten;              /* ptrn was slightly malformed */
3223         bool    repl_could_be_missing;          /* no + or ! lines in this hunk */
3224         bool    repl_missing;                   /* we are now backtracking */
3225         off_t   repl_backtrack_position;        /* file pos of first repl line */
3226         LINENUM repl_patch_line;                /* input line number for same */
3227         LINENUM ptrn_copiable;                  /* # of copiable lines in ptrn */
3228         char    *s;
3229         size_t  len;
3230         int     context = 0;
3231
3232         while (p_end >= 0) {
3233                 if (p_end == p_efake)
3234                         p_end = p_bfake;        /* don't free twice */
3235                 else
3236                         free(p_line[p_end]);
3237                 p_end--;
3238         }
3239         p_efake = -1;
3240
3241         p_max = hunkmax;        /* gets reduced when --- found */
3242         if (diff_type == CONTEXT_DIFF || diff_type == NEW_CONTEXT_DIFF) {
3243                 line_beginning = ftello(pfp);
3244                 repl_beginning = 0;
3245                 fillcnt = 0;
3246                 fillsrc = 0;
3247                 filldst = 0;
3248                 ptrn_spaces_eaten = false;
3249                 repl_could_be_missing = true;
3250                 repl_missing = false;
3251                 repl_backtrack_position = 0;
3252                 repl_patch_line = 0;
3253                 ptrn_copiable = 0;
3254
3255                 len = pgets(true);
3256                 p_input_line++;
3257                 if (len == 0 || strnNE(buf, "********", 8)) {
3258                         next_intuit_at(line_beginning, p_input_line);
3259                         return false;
3260                 }
3261                 p_context = 100;
3262                 p_hunk_beg = p_input_line + 1;
3263                 while (p_end < p_max) {
3264                         line_beginning = ftello(pfp);
3265                         len = pgets(true);
3266                         p_input_line++;
3267                         if (len == 0) {
3268                                 if (p_max - p_end < 4) {
3269                                         /* assume blank lines got chopped */
3270                                         strlcpy(buf, "  \n", buf_size);
3271                                 } else {
3272                                         if (repl_beginning && repl_could_be_missing) {
3273                                                 repl_missing = true;
3274                                                 goto hunk_done;
3275                                         }
3276                                         fatal("unexpected end of file in patch\n");
3277                                 }
3278                         }
3279                         p_end++;
3280                         if (p_end >= hunkmax)
3281                                 fatal("Internal error: hunk larger than hunk "
3282                                     "buffer size");
3283                         p_char[p_end] = *buf;
3284                         p_line[p_end] = NULL;
3285                         switch (*buf) {
3286                         case '*':
3287                                 if (strnEQ(buf, "********", 8)) {
3288                                         if (repl_beginning && repl_could_be_missing) {
3289                                                 repl_missing = true;
3290                                                 goto hunk_done;
3291                                         } else
3292                                                 fatal("unexpected end of hunk "
3293                                                     "at line %ld\n",
3294                                                     p_input_line);
3295                                 }
3296                                 if (p_end != 0) {
3297                                         if (repl_beginning && repl_could_be_missing) {
3298                                                 repl_missing = true;
3299                                                 goto hunk_done;
3300                                         }
3301                                         fatal("unexpected *** at line %ld: %s",
3302                                             p_input_line, buf);
3303                                 }
3304                                 context = 0;
3305                                 p_line[p_end] = savestr(buf);
3306                                 if (out_of_mem) {
3307                                         p_end--;
3308                                         return false;
3309                                 }
3310                                 for (s = buf;
3311                                      *s && !isdigit((unsigned char)*s); s++)
3312                                         ;
3313                                 if (!*s)
3314                                         malformed();
3315                                 if (strnEQ(s, "0,0", 3))
3316                                         memmove(s, s + 2, strlen(s + 2) + 1);
3317                                 p_first = strtolinenum(s, &s);
3318                                 if (*s == ',') {
3319                                         for (;
3320                                              *s && !isdigit((unsigned char)*s); s++)
3321                                                 ;
3322                                         if (!*s)
3323                                                 malformed();
3324                                         p_ptrn_lines = strtolinenum(s, &s) - p_first + 1;
3325                                         if (p_ptrn_lines < 0)
3326                                                 malformed();
3327                                 } else if (p_first)
3328                                         p_ptrn_lines = 1;
3329                                 else {
3330                                         p_ptrn_lines = 0;
3331                                         p_first = 1;
3332                                 }
3333                                 if (p_first >= LINENUM_MAX - p_ptrn_lines ||
3334                                     p_ptrn_lines >= LINENUM_MAX - 6)
3335                                         malformed();
3336
3337                                 /* we need this much at least */
3338                                 p_max = p_ptrn_lines + 6;
3339                                 while (p_max >= hunkmax)
3340                                         grow_hunkmax();
3341                                 p_max = hunkmax;
3342                                 break;
3343                         case '-':
3344                                 if (buf[1] == '-') {
3345                                         if (repl_beginning ||
3346                                             (p_end != p_ptrn_lines + 1 +
3347                                             (p_char[p_end - 1] == '\n'))) {
3348                                                 if (p_end == 1) {
3349                                                         /*
3350                                                          * `old' lines were omitted;
3351                                                          * set up to fill them in
3352                                                          * from 'new' context lines.
3353                                                          */
3354                                                         p_end = p_ptrn_lines + 1;
3355                                                         fillsrc = p_end + 1;
3356                                                         filldst = 1;
3357                                                         fillcnt = p_ptrn_lines;
3358                                                 } else {
3359                                                         if (repl_beginning) {
3360                                                                 if (repl_could_be_missing) {
3361                                                                         repl_missing = true;
3362                                                                         goto hunk_done;
3363                                                                 }
3364                                                                 fatal("duplicate \"---\" at line %ld--check line numbers at line %ld\n",
3365                                                                     p_input_line, p_hunk_beg + repl_beginning);
3366                                                         } else {
3367                                                                 fatal("%s \"---\" at line %ld--check line numbers at line %ld\n",
3368                                                                     (p_end <= p_ptrn_lines
3369                                                                     ? "Premature"
3370                                                                     : "Overdue"),
3371                                                                     p_input_line, p_hunk_beg);
3372                                                         }
3373                                                 }
3374                                         }
3375                                         repl_beginning = p_end;
3376                                         repl_backtrack_position = ftello(pfp);
3377                                         repl_patch_line = p_input_line;
3378                                         p_line[p_end] = savestr(buf);
3379                                         if (out_of_mem) {
3380                                                 p_end--;
3381                                                 return false;
3382                                         }
3383                                         p_char[p_end] = '=';
3384                                         for (s = buf; *s && !isdigit((unsigned char)*s); s++)
3385                                                 ;
3386                                         if (!*s)
3387                                                 malformed();
3388                                         p_newfirst = strtolinenum(s, &s);
3389                                         if (*s == ',') {
3390                                                 for (; *s && !isdigit((unsigned char)*s); s++)
3391                                                         ;
3392                                                 if (!*s)
3393                                                         malformed();
3394                                                 p_repl_lines = strtolinenum(s, &s) -
3395                                                     p_newfirst + 1;
3396                                                 if (p_repl_lines < 0)
3397                                                         malformed();
3398                                         } else if (p_newfirst)
3399                                                 p_repl_lines = 1;
3400                                         else {
3401                                                 p_repl_lines = 0;
3402                                                 p_newfirst = 1;
3403                                         }
3404                                         if (p_newfirst >= LINENUM_MAX - p_repl_lines ||
3405                                             p_repl_lines >= LINENUM_MAX - p_end)
3406                                                 malformed();
3407                                         p_max = p_repl_lines + p_end;
3408                                         if (p_max > MAXHUNKSIZE)
3409                                                 fatal("hunk too large (%ld lines) at line %ld: %s",
3410                                                     p_max, p_input_line, buf);
3411                                         while (p_max >= hunkmax)
3412                                                 grow_hunkmax();
3413                                         if (p_repl_lines != ptrn_copiable &&
3414                                             (p_context != 0 || p_repl_lines != 1))
3415                                                 repl_could_be_missing = false;
3416                                         break;
3417                                 }
3418                                 goto change_line;
3419                         case '+':
3420                         case '!':
3421                                 repl_could_be_missing = false;
3422                 change_line:
3423                                 if (buf[1] == '\n' && canonicalize)
3424                                         strlcpy(buf + 1, " \n", buf_size - 1);
3425                                 if (!isspace((unsigned char)buf[1]) &&
3426                                     buf[1] != '>' && buf[1] != '<' &&
3427                                     repl_beginning && repl_could_be_missing) {
3428                                         repl_missing = true;
3429                                         goto hunk_done;
3430                                 }
3431                                 if (context >= 0) {
3432                                         if (context < p_context)
3433                                                 p_context = context;
3434                                         context = -1000;
3435                                 }
3436                                 p_line[p_end] = savestr(buf + 2);
3437                                 if (out_of_mem) {
3438                                         p_end--;
3439                                         return false;
3440                                 }
3441                                 if (p_end == p_ptrn_lines) {
3442                                         if (remove_special_line()) {
3443                                                 int     l;
3444
3445                                                 l = strlen(p_line[p_end]) - 1;
3446                                                 (p_line[p_end])[l] = 0;
3447                                         }
3448                                 }
3449                                 break;
3450                         case '\t':
3451                         case '\n':      /* assume the 2 spaces got eaten */
3452                                 if (repl_beginning && repl_could_be_missing &&
3453                                     (!ptrn_spaces_eaten ||
3454                                     diff_type == NEW_CONTEXT_DIFF)) {
3455                                         repl_missing = true;
3456                                         goto hunk_done;
3457                                 }
3458                                 p_line[p_end] = savestr(buf);
3459                                 if (out_of_mem) {
3460                                         p_end--;
3461                                         return false;
3462                                 }
3463                                 if (p_end != p_ptrn_lines + 1) {
3464                                         ptrn_spaces_eaten |= (repl_beginning != 0);
3465                                         context++;
3466                                         if (!repl_beginning)
3467                                                 ptrn_copiable++;
3468                                         p_char[p_end] = ' ';
3469                                 }
3470                                 break;
3471                         case ' ':
3472                                 if (!isspace((unsigned char)buf[1]) &&
3473                                     repl_beginning && repl_could_be_missing) {
3474                                         repl_missing = true;
3475                                         goto hunk_done;
3476                                 }
3477                                 context++;
3478                                 if (!repl_beginning)
3479                                         ptrn_copiable++;
3480                                 p_line[p_end] = savestr(buf + 2);
3481                                 if (out_of_mem) {
3482                                         p_end--;
3483                                         return false;
3484                                 }
3485                                 break;
3486                         default:
3487                                 if (repl_beginning && repl_could_be_missing) {
3488                                         repl_missing = true;
3489                                         goto hunk_done;
3490                                 }
3491                                 malformed();
3492                         }
3493                         /* set up p_len for strncmp() so we don't have to */
3494                         /* assume null termination */
3495                         if (p_line[p_end])
3496                                 p_len[p_end] = strlen(p_line[p_end]);
3497                         else
3498                                 p_len[p_end] = 0;
3499                 }
3500
3501 hunk_done:
3502                 if (p_end >= 0 && !repl_beginning)
3503                         fatal("no --- found in patch at line %ld\n", pch_hunk_beg());
3504
3505                 if (repl_missing) {
3506
3507                         /* reset state back to just after --- */
3508                         p_input_line = repl_patch_line;
3509                         for (p_end--; p_end > repl_beginning; p_end--)
3510                                 free(p_line[p_end]);
3511                         fseeko(pfp, repl_backtrack_position, SEEK_SET);
3512
3513                         /* redundant 'new' context lines were omitted - set */
3514                         /* up to fill them in from the old file context */
3515                         if (!p_context && p_repl_lines == 1) {
3516                                 p_repl_lines = 0;
3517                                 p_max--;
3518                         }
3519                         fillsrc = 1;
3520                         filldst = repl_beginning + 1;
3521                         fillcnt = p_repl_lines;
3522                         p_end = p_max;
3523                 } else if (!p_context && fillcnt == 1) {
3524                         /* the first hunk was a null hunk with no context */
3525                         /* and we were expecting one line -- fix it up. */
3526                         while (filldst < p_end) {
3527                                 p_line[filldst] = p_line[filldst + 1];
3528                                 p_char[filldst] = p_char[filldst + 1];
3529                                 p_len[filldst] = p_len[filldst + 1];
3530                                 filldst++;
3531                         }
3532 #if 0
3533                         repl_beginning--;       /* this doesn't need to be fixed */
3534 #endif
3535                         p_end--;
3536                         p_first++;      /* do append rather than insert */
3537                         fillcnt = 0;
3538                         p_ptrn_lines = 0;
3539                 }
3540                 if (diff_type == CONTEXT_DIFF &&
3541                     (fillcnt || (p_first > 1 && ptrn_copiable > 2 * p_context))) {
3542                         if (verbosity == VERBOSE)
3543                                 say("%s\n%s\n%s\n",
3544                                     "(Fascinating--this is really a new-style context diff but without",
3545                                     "the telltale extra asterisks on the *** line that usually indicate",
3546                                     "the new style...)");
3547                         diff_type = NEW_CONTEXT_DIFF;
3548                 }
3549                 /* if there were omitted context lines, fill them in now */
3550                 if (fillcnt) {
3551                         p_bfake = filldst;      /* remember where not to free() */
3552                         p_efake = filldst + fillcnt - 1;
3553                         while (fillcnt-- > 0) {
3554                                 while (fillsrc <= p_end && p_char[fillsrc] != ' ')
3555                                         fillsrc++;
3556                                 if (fillsrc > p_end)
3557                                         fatal("replacement text or line numbers mangled in hunk at line %ld\n",
3558                                             p_hunk_beg);
3559                                 p_line[filldst] = p_line[fillsrc];
3560                                 p_char[filldst] = p_char[fillsrc];
3561                                 p_len[filldst] = p_len[fillsrc];
3562                                 fillsrc++;
3563                                 filldst++;
3564                         }
3565                         while (fillsrc <= p_end && fillsrc != repl_beginning &&
3566                             p_char[fillsrc] != ' ')
3567                                 fillsrc++;
3568 #ifdef DEBUGGING
3569                         if (debug & 64)
3570                                 printf("fillsrc %ld, filldst %ld, rb %ld, e+1 %ld\n",
3571                                 fillsrc, filldst, repl_beginning, p_end + 1);
3572 #endif
3573                         if (fillsrc != p_end + 1 && fillsrc != repl_beginning)
3574                                 malformed();
3575                         if (filldst != p_end + 1 && filldst != repl_beginning)
3576                                 malformed();
3577                 }
3578                 if (p_line[p_end] != NULL) {
3579                         if (remove_special_line()) {
3580                                 p_len[p_end] -= 1;
3581                                 (p_line[p_end])[p_len[p_end]] = 0;
3582                         }
3583                 }
3584         } else if (diff_type == UNI_DIFF) {
3585                 LINENUM fillold;        /* index of old lines */
3586                 LINENUM fillnew;        /* index of new lines */
3587                 char    ch;
3588
3589                 line_beginning = ftello(pfp); /* file pos of the current line */
3590                 len = pgets(true);
3591                 p_input_line++;
3592                 if (len == 0 || strnNE(buf, "@@ -", 4)) {
3593                         next_intuit_at(line_beginning, p_input_line);
3594                         return false;
3595                 }
3596                 s = buf + 4;
3597                 if (!*s)
3598                         malformed();
3599                 p_first = strtolinenum(s, &s);
3600                 if (*s == ',') {
3601                         p_ptrn_lines = strtolinenum(s + 1, &s);
3602                 } else
3603                         p_ptrn_lines = 1;
3604                 if (*s == ' ')
3605                         s++;
3606                 if (*s != '+' || !*++s)
3607                         malformed();
3608                 p_newfirst = strtolinenum(s, &s);
3609                 if (*s == ',') {
3610                         p_repl_lines = strtolinenum(s + 1, &s);
3611                 } else
3612                         p_repl_lines = 1;
3613                 if (*s == ' ')
3614                         s++;
3615                 if (*s != '@')
3616                         malformed();
3617                 if (p_first >= LINENUM_MAX - p_ptrn_lines ||
3618                     p_newfirst > LINENUM_MAX - p_repl_lines ||
3619                     p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1)
3620                         malformed();
3621                 if (!p_ptrn_lines)
3622                         p_first++;      /* do append rather than insert */
3623                 p_max = p_ptrn_lines + p_repl_lines + 1;
3624                 while (p_max >= hunkmax)
3625                         grow_hunkmax();
3626                 fillold = 1;
3627                 fillnew = fillold + p_ptrn_lines;
3628                 p_end = fillnew + p_repl_lines;
3629                 snprintf(buf, buf_size, "*** %ld,%ld ****\n", p_first,
3630                     p_first + p_ptrn_lines - 1);
3631                 p_line[0] = savestr(buf);
3632                 if (out_of_mem) {
3633                         p_end = -1;
3634                         return false;
3635                 }
3636                 p_char[0] = '*';
3637                 snprintf(buf, buf_size, "--- %ld,%ld ----\n", p_newfirst,
3638                     p_newfirst + p_repl_lines - 1);
3639                 p_line[fillnew] = savestr(buf);
3640                 if (out_of_mem) {
3641                         p_end = 0;
3642                         return false;
3643                 }
3644                 p_char[fillnew++] = '=';
3645                 p_context = 100;
3646                 context = 0;
3647                 p_hunk_beg = p_input_line + 1;
3648                 while (fillold <= p_ptrn_lines || fillnew <= p_end) {
3649                         line_beginning = ftello(pfp);
3650                         len = pgets(true);
3651                         p_input_line++;
3652                         if (len == 0) {
3653                                 if (p_max - fillnew < 3) {
3654                                         /* assume blank lines got chopped */
3655                                         strlcpy(buf, " \n", buf_size);
3656                                 } else {
3657                                         fatal("unexpected end of file in patch\n");
3658                                 }
3659                         }
3660                         if (*buf == '\t' || *buf == '\n') {
3661                                 ch = ' ';       /* assume the space got eaten */
3662                                 s = savestr(buf);
3663                         } else {
3664                                 ch = *buf;
3665                                 s = savestr(buf + 1);
3666                         }
3667                         if (out_of_mem) {
3668                                 while (--fillnew > p_ptrn_lines)
3669                                         free(p_line[fillnew]);
3670                                 p_end = fillold - 1;
3671                                 return false;
3672                         }
3673                         switch (ch) {
3674                         case '-':
3675                                 if (fillold > p_ptrn_lines) {
3676                                         free(s);
3677                                         p_end = fillnew - 1;
3678                                         malformed();
3679                                 }
3680                                 p_char[fillold] = ch;
3681                                 p_line[fillold] = s;
3682                                 p_len[fillold++] = strlen(s);
3683                                 if (fillold > p_ptrn_lines) {
3684                                         if (remove_special_line()) {
3685                                                 p_len[fillold - 1] -= 1;
3686                                                 s[p_len[fillold - 1]] = 0;
3687                                         }
3688                                 }
3689                                 break;
3690                         case '=':
3691                                 ch = ' ';
3692                                 /* FALL THROUGH */
3693                         case ' ':
3694                                 if (fillold > p_ptrn_lines) {
3695                                         free(s);
3696                                         while (--fillnew > p_ptrn_lines)
3697                                                 free(p_line[fillnew]);
3698                                         p_end = fillold - 1;
3699                                         malformed();
3700                                 }
3701                                 context++;
3702                                 p_char[fillold] = ch;
3703                                 p_line[fillold] = s;
3704                                 p_len[fillold++] = strlen(s);
3705                                 s = savestr(s);
3706                                 if (out_of_mem) {
3707                                         while (--fillnew > p_ptrn_lines)
3708                                                 free(p_line[fillnew]);
3709                                         p_end = fillold - 1;
3710                                         return false;
3711                                 }
3712                                 if (fillold > p_ptrn_lines) {
3713                                         if (remove_special_line()) {
3714                                                 p_len[fillold - 1] -= 1;
3715                                                 s[p_len[fillold - 1]] = 0;
3716                                         }
3717                                 }
3718                                 /* FALL THROUGH */
3719                         case '+':
3720                                 if (fillnew > p_end) {
3721                                         free(s);
3722                                         while (--fillnew > p_ptrn_lines)
3723                                                 free(p_line[fillnew]);
3724                                         p_end = fillold - 1;
3725                                         malformed();
3726                                 }
3727                                 p_char[fillnew] = ch;
3728                                 p_line[fillnew] = s;
3729                                 p_len[fillnew++] = strlen(s);
3730                                 if (fillold > p_ptrn_lines) {
3731                                         if (remove_special_line()) {
3732                                                 p_len[fillnew - 1] -= 1;
3733                                                 s[p_len[fillnew - 1]] = 0;
3734                                         }
3735                                 }
3736                                 break;
3737                         default:
3738                                 p_end = fillnew;
3739                                 malformed();
3740                         }
3741                         if (ch != ' ' && context > 0) {
3742                                 if (context < p_context)
3743                                         p_context = context;
3744                                 context = -1000;
3745                         }
3746                 }               /* while */
3747         } else {                /* normal diff--fake it up */
3748                 char    hunk_type;
3749                 int     i;
3750                 LINENUM min, max;
3751
3752                 line_beginning = ftello(pfp);
3753                 p_context = 0;
3754                 len = pgets(true);
3755                 p_input_line++;
3756                 if (len == 0 || !isdigit((unsigned char)*buf)) {
3757                         next_intuit_at(line_beginning, p_input_line);
3758                         return false;
3759                 }
3760                 p_first = strtolinenum(buf, &s);
3761                 if (*s == ',') {
3762                         p_ptrn_lines = strtolinenum(s + 1, &s) - p_first + 1;
3763                         if (p_ptrn_lines < 0)
3764                                 malformed();
3765                 } else
3766                         p_ptrn_lines = (*s != 'a');
3767                 hunk_type = *s;
3768                 if (hunk_type == 'a')
3769                         p_first++;      /* do append rather than insert */
3770                 min = strtolinenum(s + 1, &s);
3771                 if (*s == ',')
3772                         max = strtolinenum(s + 1, &s);
3773                 else
3774                         max = min;
3775                 if (min < 0 || min > max || max - min == LINENUM_MAX)
3776                         malformed();
3777                 if (hunk_type == 'd')
3778                         min++;
3779                 p_newfirst = min;
3780                 p_repl_lines = max - min + 1;
3781                 if (p_newfirst > LINENUM_MAX - p_repl_lines ||
3782                     p_ptrn_lines >= LINENUM_MAX - p_repl_lines - 1)
3783                         malformed();
3784                 p_end = p_ptrn_lines + p_repl_lines + 1;
3785                 if (p_end > MAXHUNKSIZE)
3786                         fatal("hunk too large (%ld lines) at line %ld: %s",
3787                             p_end, p_input_line, buf);
3788                 while (p_end >= hunkmax)
3789                         grow_hunkmax();
3790                 snprintf(buf, buf_size, "*** %ld,%ld\n", p_first,
3791                     p_first + p_ptrn_lines - 1);
3792                 p_line[0] = savestr(buf);
3793                 if (out_of_mem) {
3794                         p_end = -1;
3795                         return false;
3796                 }
3797                 p_char[0] = '*';
3798                 for (i = 1; i <= p_ptrn_lines; i++) {
3799                         len = pgets(true);
3800                         p_input_line++;
3801                         if (len == 0)
3802                                 fatal("unexpected end of file in patch at line %ld\n",
3803                                     p_input_line);
3804                         if (*buf != '<')
3805                                 fatal("< expected at line %ld of patch\n",
3806                                     p_input_line);
3807                         p_line[i] = savestr(buf + 2);
3808                         if (out_of_mem) {
3809                                 p_end = i - 1;
3810                                 return false;
3811                         }
3812                         p_len[i] = strlen(p_line[i]);
3813                         p_char[i] = '-';
3814                 }
3815
3816                 if (remove_special_line()) {
3817                         p_len[i - 1] -= 1;
3818                         (p_line[i - 1])[p_len[i - 1]] = 0;
3819                 }
3820                 if (hunk_type == 'c') {
3821                         len = pgets(true);
3822                         p_input_line++;
3823                         if (len == 0)
3824                                 fatal("unexpected end of file in patch at line %ld\n",
3825                                     p_input_line);
3826                         if (*buf != '-')
3827                                 fatal("--- expected at line %ld of patch\n",
3828                                     p_input_line);
3829                 }
3830                 snprintf(buf, buf_size, "--- %ld,%ld\n", min, max);
3831                 p_line[i] = savestr(buf);
3832                 if (out_of_mem) {
3833                         p_end = i - 1;
3834                         return false;
3835                 }
3836                 p_char[i] = '=';
3837                 for (i++; i <= p_end; i++) {
3838                         len = pgets(true);
3839                         p_input_line++;
3840                         if (len == 0)
3841                                 fatal("unexpected end of file in patch at line %ld\n",
3842                                     p_input_line);
3843                         if (*buf != '>')
3844                                 fatal("> expected at line %ld of patch\n",
3845                                     p_input_line);
3846                         p_line[i] = savestr(buf + 2);
3847                         if (out_of_mem) {
3848                                 p_end = i - 1;
3849                                 return false;
3850                         }
3851                         p_len[i] = strlen(p_line[i]);
3852                         p_char[i] = '+';
3853                 }
3854
3855                 if (remove_special_line()) {
3856                         p_len[i - 1] -= 1;
3857                         (p_line[i - 1])[p_len[i - 1]] = 0;
3858                 }
3859         }
3860         if (reverse)            /* backwards patch? */
3861                 if (!pch_swap())
3862                         say("Not enough memory to swap next hunk!\n");
3863 #ifdef DEBUGGING
3864         if (debug & 2) {
3865                 LINENUM i;
3866                 char    special;
3867
3868                 for (i = 0; i <= p_end; i++) {
3869                         if (i == p_ptrn_lines)
3870                                 special = '^';
3871                         else
3872                                 special = ' ';
3873                         fprintf(stderr, "%3ld %c %c %s", i, p_char[i],
3874                             special, p_line[i]);
3875                         fflush(stderr);
3876                 }
3877         }
3878 #endif
3879         if (p_end + 1 < hunkmax)/* paranoia reigns supreme... */
3880                 p_char[p_end + 1] = '^';        /* add a stopper for apply_hunk */
3881         return true;
3882 }
3883
3884 /*
3885  * Input a line from the patch file.
3886  * Worry about indentation if do_indent is true.
3887  * The line is read directly into the buf global variable which
3888  * is resized if necessary in order to hold the complete line.
3889  * Returns the number of characters read including the terminating
3890  * '\n', if any.
3891  */
3892 size_t
3893 pgets(bool do_indent)
3894 {
3895         char *line;
3896         size_t len;
3897         int indent = 0, skipped = 0;
3898
3899         line = fgetln(pfp, &len);
3900         if (line != NULL) {
3901                 if (len + 1 > buf_size) {
3902                         while (len + 1 > buf_size)
3903                                 buf_size *= 2;
3904                         free(buf);
3905                         buf = malloc(buf_size);
3906                         if (buf == NULL)
3907                                 fatal("out of memory\n");
3908                 }
3909                 if (do_indent == 1 && p_indent) {
3910                         for (;
3911                             indent < p_indent && (*line == ' ' || *line == '\t' || *line == 'X');
3912                             line++, skipped++) {
3913                                 if (*line == '\t')
3914                                         indent += 8 - (indent %7);
3915                                 else
3916                                         indent++;
3917                         }
3918                 }
3919                 memcpy(buf, line, len - skipped);
3920                 buf[len - skipped] = '\0';
3921         }
3922         return len;
3923 }
3924
3925
3926 /*
3927  * Reverse the old and new portions of the current hunk.
3928  */
3929 bool
3930 pch_swap(void)
3931 {
3932         char    **tp_line;      /* the text of the hunk */
3933         unsigned short  *tp_len;/* length of each line */
3934         char    *tp_char;       /* +, -, and ! */
3935         LINENUM i;
3936         LINENUM n;
3937         bool    blankline = false;
3938         char    *s;
3939
3940         i = p_first;
3941         p_first = p_newfirst;
3942         p_newfirst = i;
3943
3944         /* make a scratch copy */
3945
3946         tp_line = p_line;
3947         tp_len = p_len;
3948         tp_char = p_char;
3949         p_line = NULL;  /* force set_hunkmax to allocate again */
3950         p_len = NULL;
3951         p_char = NULL;
3952         set_hunkmax();
3953         if (p_line == NULL || p_len == NULL || p_char == NULL) {
3954
3955                 free(p_line);
3956                 p_line = tp_line;
3957                 free(p_len);
3958                 p_len = tp_len;
3959                 free(p_char);
3960                 p_char = tp_char;
3961                 return false;   /* not enough memory to swap hunk! */
3962         }
3963         /* now turn the new into the old */
3964
3965         i = p_ptrn_lines + 1;
3966         if (tp_char[i] == '\n') {       /* account for possible blank line */
3967                 blankline = true;
3968                 i++;
3969         }
3970         if (p_efake >= 0) {     /* fix non-freeable ptr range */
3971                 if (p_efake <= i)
3972                         n = p_end - i + 1;
3973                 else
3974                         n = -i;
3975                 p_efake += n;
3976                 p_bfake += n;
3977         }
3978         for (n = 0; i <= p_end; i++, n++) {
3979                 p_line[n] = tp_line[i];
3980                 p_char[n] = tp_char[i];
3981                 if (p_char[n] == '+')
3982                         p_char[n] = '-';
3983                 p_len[n] = tp_len[i];
3984         }
3985         if (blankline) {
3986                 i = p_ptrn_lines + 1;
3987                 p_line[n] = tp_line[i];
3988                 p_char[n] = tp_char[i];
3989                 p_len[n] = tp_len[i];
3990                 n++;
3991         }
3992         if (p_char[0] != '=')
3993                 fatal("Malformed patch at line %ld: expected '=' found '%c'\n",
3994                     p_input_line, p_char[0]);
3995         p_char[0] = '*';
3996         for (s = p_line[0]; *s; s++)
3997                 if (*s == '-')
3998                         *s = '*';
3999
4000         /* now turn the old into the new */
4001
4002         if (p_char[0] != '*')
4003                 fatal("Malformed patch at line %ld: expected '*' found '%c'\n",
4004                     p_input_line, p_char[0]);
4005         tp_char[0] = '=';
4006         for (s = tp_line[0]; *s; s++)
4007                 if (*s == '*')
4008                         *s = '-';
4009         for (i = 0; n <= p_end; i++, n++) {
4010                 p_line[n] = tp_line[i];
4011                 p_char[n] = tp_char[i];
4012                 if (p_char[n] == '-')
4013                         p_char[n] = '+';
4014                 p_len[n] = tp_len[i];
4015         }
4016
4017         if (i != p_ptrn_lines + 1)
4018                 fatal("Malformed patch at line %ld: expected %ld lines, "
4019                     "got %ld\n",
4020                     p_input_line, p_ptrn_lines + 1, i);
4021
4022         i = p_ptrn_lines;
4023         p_ptrn_lines = p_repl_lines;
4024         p_repl_lines = i;
4025
4026         free(tp_line);
4027         free(tp_len);
4028         free(tp_char);
4029
4030         return true;
4031 }
4032
4033 /*
4034  * Return the specified line position in the old file of the old context.
4035  */
4036 LINENUM
4037 pch_first(void)
4038 {
4039         return p_first;
4040 }
4041
4042 /*
4043  * Return the number of lines of old context.
4044  */
4045 LINENUM
4046 pch_ptrn_lines(void)
4047 {
4048         return p_ptrn_lines;
4049 }
4050
4051 /*
4052  * Return the probable line position in the new file of the first line.
4053  */
4054 LINENUM
4055 pch_newfirst(void)
4056 {
4057         return p_newfirst;
4058 }
4059
4060 /*
4061  * Return the number of lines in the replacement text including context.
4062  */
4063 LINENUM
4064 pch_repl_lines(void)
4065 {
4066         return p_repl_lines;
4067 }
4068
4069 /*
4070  * Return the number of lines in the whole hunk.
4071  */
4072 LINENUM
4073 pch_end(void)
4074 {
4075         return p_end;
4076 }
4077
4078 /*
4079  * Return the number of context lines before the first changed line.
4080  */
4081 LINENUM
4082 pch_context(void)
4083 {
4084         return p_context;
4085 }
4086
4087 /*
4088  * Return the length of a particular patch line.
4089  */
4090 unsigned short
4091 pch_line_len(LINENUM line)
4092 {
4093         return p_len[line];
4094 }
4095
4096 /*
4097  * Return the control character (+, -, *, !, etc) for a patch line.
4098  */
4099 char
4100 pch_char(LINENUM line)
4101 {
4102         return p_char[line];
4103 }
4104
4105 /*
4106  * Return a pointer to a particular patch line.
4107  */
4108 char *
4109 pfetch(LINENUM line)
4110 {
4111         return p_line[line];
4112 }
4113
4114 /*
4115  * Return where in the patch file this hunk began, for error messages.
4116  */
4117 LINENUM
4118 pch_hunk_beg(void)
4119 {
4120         return p_hunk_beg;
4121 }
4122
4123 /*
4124  * Apply an ed script by feeding ed itself.
4125  */
4126 void
4127 do_ed_script(void)
4128 {
4129         char    *t;
4130         off_t   beginning_of_this_line;
4131         FILE    *pipefp = NULL;
4132         int     continuation;
4133
4134         if (!skip_rest_of_patch) {
4135                 if (copy_file(filearg[0], TMPOUTNAME) < 0) {
4136                         unlink(TMPOUTNAME);
4137                         fatal("can't create temp file %s", TMPOUTNAME);
4138                 }
4139                 snprintf(buf, buf_size, "%s%s%s", _PATH_RED,
4140                     verbosity == VERBOSE ? " " : " -s ", TMPOUTNAME);
4141                 pipefp = popen(buf, "w");
4142         }
4143         for (;;) {
4144                 beginning_of_this_line = ftello(pfp);
4145                 if (pgets(true) == 0) {
4146                         next_intuit_at(beginning_of_this_line, p_input_line);
4147                         break;
4148                 }
4149                 p_input_line++;
4150                 for (t = buf; isdigit((unsigned char)*t) || *t == ','; t++)
4151                         ;
4152                 /* POSIX defines allowed commands as {a,c,d,i,s} */
4153                 if (isdigit((unsigned char)*buf) &&
4154                     (*t == 'a' || *t == 'c' || *t == 'd' || *t == 'i' || *t == 's')) {
4155                         if (pipefp != NULL)
4156                                 fputs(buf, pipefp);
4157                         if (*t == 's') {
4158                                 for (;;) {
4159                                         continuation = 0;
4160                                         t = strchr(buf, '\0') - 1;
4161                                         while (--t >= buf && *t == '\\')
4162                                                 continuation = !continuation;
4163                                         if (!continuation ||
4164                                             pgets(true) == 0)
4165                                                 break;
4166                                         if (pipefp != NULL)
4167                                                 fputs(buf, pipefp);
4168                                 }
4169                         } else if (*t != 'd') {
4170                                 while (pgets(true)) {
4171                                         p_input_line++;
4172                                         if (pipefp != NULL)
4173                                                 fputs(buf, pipefp);
4174                                         if (strEQ(buf, ".\n"))
4175                                                 break;
4176                                 }
4177                         }
4178                 } else {
4179                         next_intuit_at(beginning_of_this_line, p_input_line);
4180                         break;
4181                 }
4182         }
4183         if (pipefp == NULL)
4184                 return;
4185         fprintf(pipefp, "w\n");
4186         fprintf(pipefp, "q\n");
4187         fflush(pipefp);
4188         pclose(pipefp);
4189         ignore_signals();
4190         if (!check_only) {
4191                 if (move_file(TMPOUTNAME, outname) < 0) {
4192                         toutkeep = true;
4193                         chmod(TMPOUTNAME, filemode);
4194                 } else
4195                         chmod(outname, filemode);
4196         }
4197         set_signals(1);
4198 }
4199
4200 /*
4201  * Choose the name of the file to be patched based on POSIX rules.
4202  * NOTE: the POSIX rules are amazingly stupid and we only follow them
4203  *       if the user specified --posix or set POSIXLY_CORRECT.
4204  */
4205 static char *
4206 posix_name(const struct file_name *names, bool assume_exists)
4207 {
4208         char *path = NULL;
4209         int i;
4210
4211         /*
4212          * POSIX states that the filename will be chosen from one
4213          * of the old, new and index names (in that order) if
4214          * the file exists relative to CWD after -p stripping.
4215          */
4216         for (i = 0; i < MAX_FILE; i++) {
4217                 if (names[i].path != NULL && names[i].exists) {
4218                         path = names[i].path;
4219                         break;
4220                 }
4221         }
4222         if (path == NULL && !assume_exists) {
4223                 /*
4224                  * No files found, check to see if the diff could be
4225                  * creating a new file.
4226                  */
4227                 if (path == NULL && ok_to_create_file &&
4228                     names[NEW_FILE].path != NULL)
4229                         path = names[NEW_FILE].path;
4230         }
4231
4232         return path ? xstrdup(path) : NULL;
4233 }
4234
4235 static char *
4236 compare_names(const struct file_name *names, bool assume_exists)
4237 {
4238         size_t min_components, min_baselen, min_len, tmp;
4239         char *best = NULL;
4240         char *path;
4241         int i;
4242
4243         /*
4244          * The "best" name is the one with the fewest number of path
4245          * components, the shortest basename length, and the shortest
4246          * overall length (in that order).  We only use the Index: file
4247          * if neither of the old or new files could be intuited from
4248          * the diff header.
4249          */
4250         min_components = min_baselen = min_len = SIZE_MAX;
4251         for (i = INDEX_FILE; i >= OLD_FILE; i--) {
4252                 path = names[i].path;
4253                 if (path == NULL || (!names[i].exists && !assume_exists))
4254                         continue;
4255                 if ((tmp = num_components(path)) > min_components)
4256                         continue;
4257                 if (tmp < min_components) {
4258                         min_components = tmp;
4259                         best = path;
4260                 }
4261                 if ((tmp = strlen(basename(path))) > min_baselen)
4262                         continue;
4263                 if (tmp < min_baselen) {
4264                         min_baselen = tmp;
4265                         best = path;
4266                 }
4267                 if ((tmp = strlen(path)) > min_len)
4268                         continue;
4269                 min_len = tmp;
4270                 best = path;
4271         }
4272         return best;
4273 }
4274
4275 /*
4276  * Choose the name of the file to be patched based the "best" one
4277  * available.
4278  */
4279 static char *
4280 best_name(const struct file_name *names, bool assume_exists)
4281 {
4282         char *best;
4283
4284         best = compare_names(names, assume_exists);
4285
4286         /* No match?  Check to see if the diff could be creating a new file. */
4287         if (best == NULL && ok_to_create_file)
4288                 best = names[NEW_FILE].path;
4289
4290         return best ? xstrdup(best) : NULL;
4291 }
4292
4293 static size_t
4294 num_components(const char *path)
4295 {
4296         size_t n;
4297         const char *cp;
4298
4299         for (n = 0, cp = path; (cp = strchr(cp, '/')) != NULL; n++, cp++) {
4300                 while (*cp == '/')
4301                         cp++;           /* skip consecutive slashes */
4302         }
4303         return n;
4304 }
4305
4306 /*
4307  * Convert number at NPTR into LINENUM and save address of first
4308  * character that is not a digit in ENDPTR.  If conversion is not
4309  * possible, call fatal.
4310  */
4311 static LINENUM
4312 strtolinenum(char *nptr, char **endptr)
4313 {
4314         LINENUM rv;
4315         char c;
4316         char *p;
4317         const char *errstr;
4318
4319         for (p = nptr; isdigit((unsigned char)*p); p++)
4320                 ;
4321
4322         if (p == nptr)
4323                 malformed();
4324
4325         c = *p;
4326         *p = '\0';
4327
4328         rv = strtonum(nptr, 0, LINENUM_MAX, &errstr);
4329         if (errstr != NULL)
4330                 fatal("invalid line number at line %ld: `%s' is %s\n",
4331                     p_input_line, nptr, errstr);
4332
4333         *p = c;
4334         *endptr = p;
4335
4336         return rv;
4337 }
4338
4339
4340 [FILE:608:files/pch.h]
4341 #define OLD_FILE        0
4342 #define NEW_FILE        1
4343 #define INDEX_FILE      2
4344 #define MAX_FILE        3
4345
4346 struct file_name {
4347         char *path;
4348         bool exists;
4349 };
4350
4351 void            re_patch(void);
4352 void            open_patch_file(const char *);
4353 void            set_hunkmax(void);
4354 bool            there_is_another_patch(void);
4355 bool            another_hunk(void);
4356 bool            pch_swap(void);
4357 char            *pfetch(LINENUM);
4358 unsigned short  pch_line_len(LINENUM);
4359 LINENUM         pch_first(void);
4360 LINENUM         pch_ptrn_lines(void);
4361 LINENUM         pch_newfirst(void);
4362 LINENUM         pch_repl_lines(void);
4363 LINENUM         pch_end(void);
4364 LINENUM         pch_context(void);
4365 LINENUM         pch_hunk_beg(void);
4366 char            pch_char(LINENUM);
4367 void            do_ed_script(void);
4368
4369
4370 [FILE:8191:files/util.c]
4371 #include <sys/stat.h>
4372
4373 #include <ctype.h>
4374 #include <errno.h>
4375 #include <fcntl.h>
4376 #include <libgen.h>
4377 #include <limits.h>
4378 #include <paths.h>
4379 #include <signal.h>
4380 #include <stdarg.h>
4381 #include <stdlib.h>
4382 #include <stdio.h>
4383 #include <string.h>
4384 #include <unistd.h>
4385
4386 #include "common.h"
4387 #include "util.h"
4388 #include "backupfile.h"
4389 #include "pathnames.h"
4390
4391 /* Rename a file, copying it if necessary. */
4392
4393 int
4394 move_file(const char *from, const char *to)
4395 {
4396         int     fromfd;
4397         ssize_t i;
4398
4399         /* to stdout? */
4400
4401         if (strEQ(to, "-")) {
4402 #ifdef DEBUGGING
4403                 if (debug & 4)
4404                         say("Moving %s to stdout.\n", from);
4405 #endif
4406                 fromfd = open(from, O_RDONLY);
4407                 if (fromfd < 0)
4408                         pfatal("internal error, can't reopen %s", from);
4409                 while ((i = read(fromfd, buf, buf_size)) > 0)
4410                         if (write(STDOUT_FILENO, buf, i) != i)
4411                                 pfatal("write failed");
4412                 close(fromfd);
4413                 return 0;
4414         }
4415         if (backup_file(to) < 0) {
4416                 say("Can't backup %s, output is in %s: %s\n", to, from,
4417                     strerror(errno));
4418                 return -1;
4419         }
4420 #ifdef DEBUGGING
4421         if (debug & 4)
4422                 say("Moving %s to %s.\n", from, to);
4423 #endif
4424         if (rename(from, to) < 0) {
4425                 if (errno != EXDEV || copy_file(from, to) < 0) {
4426                         say("Can't create %s, output is in %s: %s\n",
4427                             to, from, strerror(errno));
4428                         return -1;
4429                 }
4430         }
4431         return 0;
4432 }
4433
4434 /* Backup the original file.  */
4435
4436 int
4437 backup_file(const char *orig)
4438 {
4439         struct stat     filestat;
4440         char            bakname[PATH_MAX], *s, *simplename;
4441         dev_t           orig_device;
4442         ino_t           orig_inode;
4443
4444         if (backup_type == none || stat(orig, &filestat) != 0)
4445                 return 0;                       /* nothing to do */
4446         /*
4447          * If the user used zero prefixes or suffixes, then
4448          * he doesn't want backups.  Yet we have to remove
4449          * orig to break possible hardlinks.
4450          */
4451         if ((origprae && *origprae == 0) || *simple_backup_suffix == 0) {
4452                 unlink(orig);
4453                 return 0;
4454         }
4455         orig_device = filestat.st_dev;
4456         orig_inode = filestat.st_ino;
4457
4458         if (origprae) {
4459                 if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
4460                     strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname))
4461                         fatal("filename %s too long for buffer\n", origprae);
4462         } else {
4463                 if ((s = find_backup_file_name(orig)) == NULL)
4464                         fatal("out of memory\n");
4465                 if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname))
4466                         fatal("filename %s too long for buffer\n", s);
4467                 free(s);
4468         }
4469
4470         if ((simplename = strrchr(bakname, '/')) != NULL)
4471                 simplename = simplename + 1;
4472         else
4473                 simplename = bakname;
4474
4475         /*
4476          * Find a backup name that is not the same file. Change the
4477          * first lowercase char into uppercase; if that isn't
4478          * sufficient, chop off the first char and try again.
4479          */
4480         while (stat(bakname, &filestat) == 0 &&
4481             orig_device == filestat.st_dev && orig_inode == filestat.st_ino) {
4482                 /* Skip initial non-lowercase chars.  */
4483                 for (s = simplename; *s && !islower((unsigned char)*s); s++)
4484                         ;
4485                 if (*s)
4486                         *s = toupper((unsigned char)*s);
4487                 else
4488                         memmove(simplename, simplename + 1,
4489                             strlen(simplename + 1) + 1);
4490         }
4491 #ifdef DEBUGGING
4492         if (debug & 4)
4493                 say("Moving %s to %s.\n", orig, bakname);
4494 #endif
4495         if (rename(orig, bakname) < 0) {
4496                 if (errno != EXDEV || copy_file(orig, bakname) < 0)
4497                         return -1;
4498         }
4499         return 0;
4500 }
4501
4502 /*
4503  * Copy a file.
4504  */
4505 int
4506 copy_file(const char *from, const char *to)
4507 {
4508         int     tofd, fromfd;
4509         ssize_t i;
4510
4511         tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666);
4512         if (tofd < 0)
4513                 return -1;
4514         fromfd = open(from, O_RDONLY, 0);
4515         if (fromfd < 0)
4516                 pfatal("internal error, can't reopen %s", from);
4517         while ((i = read(fromfd, buf, buf_size)) > 0)
4518                 if (write(tofd, buf, i) != i)
4519                         pfatal("write to %s failed", to);
4520         close(fromfd);
4521         close(tofd);
4522         return 0;
4523 }
4524
4525 /*
4526  * Allocate a unique area for a string.
4527  */
4528 char *
4529 savestr(const char *s)
4530 {
4531         char    *rv;
4532
4533         if (!s)
4534                 s = "Oops";
4535         rv = strdup(s);
4536         if (rv == NULL) {
4537                 if (using_plan_a)
4538                         out_of_mem = true;
4539                 else
4540                         fatal("out of memory\n");
4541         }
4542         return rv;
4543 }
4544
4545 /*
4546  * Allocate a unique area for a string.  Call fatal if out of memory.
4547  */
4548 char *
4549 xstrdup(const char *s)
4550 {
4551         char    *rv;
4552
4553         if (!s)
4554                 s = "Oops";
4555         rv = strdup(s);
4556         if (rv == NULL)
4557                 fatal("out of memory\n");
4558         return rv;
4559 }
4560
4561 /*
4562  * Vanilla terminal output (buffered).
4563  */
4564 void
4565 say(const char *fmt, ...)
4566 {
4567         va_list ap;
4568
4569         va_start(ap, fmt);
4570         vfprintf(stdout, fmt, ap);
4571         va_end(ap);
4572         fflush(stdout);
4573 }
4574
4575 /*
4576  * Terminal output, pun intended.
4577  */
4578 void
4579 fatal(const char *fmt, ...)
4580 {
4581         va_list ap;
4582
4583         va_start(ap, fmt);
4584         fprintf(stderr, "patch: **** ");
4585         vfprintf(stderr, fmt, ap);
4586         va_end(ap);
4587         my_exit(2);
4588 }
4589
4590 /*
4591  * Say something from patch, something from the system, then silence . . .
4592  */
4593 void
4594 pfatal(const char *fmt, ...)
4595 {
4596         va_list ap;
4597         int     errnum = errno;
4598
4599         fprintf(stderr, "patch: **** ");
4600         va_start(ap, fmt);
4601         vfprintf(stderr, fmt, ap);
4602         va_end(ap);
4603         fprintf(stderr, ": %s\n", strerror(errnum));
4604         my_exit(2);
4605 }
4606
4607 /*
4608  * Get a response from the user via /dev/tty
4609  */
4610 void
4611 ask(const char *fmt, ...)
4612 {
4613         va_list ap;
4614         ssize_t nr = 0;
4615         static  int ttyfd = -1;
4616
4617         va_start(ap, fmt);
4618         vfprintf(stdout, fmt, ap);
4619         va_end(ap);
4620         fflush(stdout);
4621         if (ttyfd < 0)
4622                 ttyfd = open(_PATH_TTY, O_RDONLY);
4623         if (ttyfd >= 0) {
4624                 if ((nr = read(ttyfd, buf, buf_size)) > 0 &&
4625                     buf[nr - 1] == '\n')
4626                         buf[nr - 1] = '\0';
4627         }
4628         if (ttyfd < 0 || nr <= 0) {
4629                 /* no tty or error reading, pretend user entered 'return' */
4630                 putchar('\n');
4631                 buf[0] = '\0';
4632         }
4633 }
4634
4635 /*
4636  * How to handle certain events when not in a critical region.
4637  */
4638 void
4639 set_signals(int reset)
4640 {
4641         static int hup_exit = 0;
4642         static int int_exit = 0;
4643
4644         if (reset) {
4645                 signal (SIGHUP, hup_exit ? my_exit : SIG_IGN);
4646                 signal (SIGINT, int_exit ? my_exit : SIG_IGN);
4647         } else {
4648                 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) {
4649                         hup_exit = 1;
4650                         signal (SIGHUP, my_exit);
4651                 }
4652                 if (signal(SIGINT, SIG_IGN) != SIG_IGN) {
4653                         int_exit = 1;
4654                         signal (SIGINT, my_exit);
4655                 }
4656         }
4657 }
4658
4659 /*
4660  * How to handle certain events when in a critical region.
4661  */
4662 void
4663 ignore_signals(void)
4664 {
4665         signal(SIGHUP, SIG_IGN);
4666         signal(SIGINT, SIG_IGN);
4667 }
4668
4669 /*
4670  * Make sure we'll have the directories to create a file. If `striplast' is
4671  * true, ignore the last element of `filename'.
4672  */
4673
4674 void
4675 makedirs(const char *filename, bool striplast)
4676 {
4677         char    *tmpbuf;
4678
4679         if ((tmpbuf = strdup(filename)) == NULL)
4680                 fatal("out of memory\n");
4681
4682         if (striplast) {
4683                 char    *s = strrchr(tmpbuf, '/');
4684                 if (s == NULL) {
4685                         free(tmpbuf);
4686                         return; /* nothing to be done */
4687                 }
4688                 *s = '\0';
4689         }
4690         if (mkpath(tmpbuf) != 0)
4691                 pfatal("creation of %s failed", tmpbuf);
4692         free(tmpbuf);
4693 }
4694
4695 /*
4696  * Make filenames more reasonable.
4697  */
4698 char *
4699 fetchname(const char *at, bool *exists, int strip_leading)
4700 {
4701         char            *fullname, *name, *t;
4702         int             sleading, tab;
4703         struct stat     filestat;
4704
4705         if (at == NULL || *at == '\0')
4706                 return NULL;
4707         while (isspace((unsigned char)*at))
4708                 at++;
4709 #ifdef DEBUGGING
4710         if (debug & 128)
4711                 say("fetchname %s %d\n", at, strip_leading);
4712 #endif
4713         /* So files can be created by diffing against /dev/null.  */
4714         if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
4715                 return NULL;
4716         name = fullname = t = savestr(at);
4717
4718         tab = strchr(t, '\t') != NULL;
4719         /* Strip off up to `strip_leading' path components and NUL terminate. */
4720         for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
4721             !isspace((unsigned char)*t)); t++) {
4722                 if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
4723                         if (--sleading >= 0)
4724                                 name = t + 1;
4725         }
4726         *t = '\0';
4727
4728         /*
4729          * If no -p option was given (957 is the default value!), we were
4730          * given a relative pathname, and the leading directories that we
4731          * just stripped off all exist, put them back on.
4732          */
4733         if (strip_leading == 957 && name != fullname && *fullname != '/') {
4734                 name[-1] = '\0';
4735                 if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
4736                         name[-1] = '/';
4737                         name = fullname;
4738                 }
4739         }
4740         name = savestr(name);
4741         free(fullname);
4742
4743         *exists = stat(name, &filestat) == 0;
4744         return name;
4745 }
4746
4747 void
4748 version(void)
4749 {
4750         printf("patch 2.0-12u11 Ravenports\n");
4751         my_exit(EXIT_SUCCESS);
4752 }
4753
4754 /*
4755  * Exit with cleanup.
4756  */
4757 void
4758 my_exit(int status)
4759 {
4760         unlink(TMPINNAME);
4761         if (!toutkeep)
4762                 unlink(TMPOUTNAME);
4763         if (!trejkeep)
4764                 unlink(TMPREJNAME);
4765         unlink(TMPPATNAME);
4766         exit(status);
4767 }
4768
4769
4770 [FILE:759:files/util.h]
4771 char            *fetchname(const char *, bool *, int);
4772 int             backup_file(const char *);
4773 int             move_file(const char *, const char *);
4774 int             copy_file(const char *, const char *);
4775 void            say(const char *, ...)
4776                     __attribute__((__format__(__printf__, 1, 2)));
4777 void            fatal(const char *, ...)
4778                     __attribute__((__format__(__printf__, 1, 2)));
4779 void            pfatal(const char *, ...)
4780                     __attribute__((__format__(__printf__, 1, 2)));
4781 void            ask(const char *, ...)
4782                     __attribute__((__format__(__printf__, 1, 2)));
4783 char            *savestr(const char *);
4784 char            *xstrdup(const char *);
4785 void            set_signals(int);
4786 void            ignore_signals(void);
4787 void            makedirs(const char *, bool);
4788 void            version(void);
4789 void            my_exit(int) __attribute__((noreturn));
4790
4791 /* in mkpath.c */
4792 extern int mkpath(char *);
4793