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