12dd076b8SGabor Kovesdan /*- 22dd076b8SGabor Kovesdan * Copyright 1986, Larry Wall 32dd076b8SGabor Kovesdan * 42dd076b8SGabor Kovesdan * Redistribution and use in source and binary forms, with or without 52dd076b8SGabor Kovesdan * modification, are permitted provided that the following condition is met: 62dd076b8SGabor Kovesdan * 1. Redistributions of source code must retain the above copyright notice, 72dd076b8SGabor Kovesdan * this condition and the following disclaimer. 82dd076b8SGabor Kovesdan * 92dd076b8SGabor Kovesdan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 102dd076b8SGabor Kovesdan * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 112dd076b8SGabor Kovesdan * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 122dd076b8SGabor Kovesdan * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 132dd076b8SGabor Kovesdan * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 142dd076b8SGabor Kovesdan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 152dd076b8SGabor Kovesdan * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 162dd076b8SGabor Kovesdan * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 172dd076b8SGabor Kovesdan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 182dd076b8SGabor Kovesdan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 192dd076b8SGabor Kovesdan * SUCH DAMAGE. 202dd076b8SGabor Kovesdan * 212dd076b8SGabor Kovesdan * patch - a program to apply diffs to original files 222dd076b8SGabor Kovesdan * 232dd076b8SGabor Kovesdan * -C option added in 1998, original code by Marc Espie, based on FreeBSD 242dd076b8SGabor Kovesdan * behaviour 252dd076b8SGabor Kovesdan * 2663433bc9SPedro F. Giffuni * $OpenBSD: inp.c,v 1.44 2015/07/26 14:32:19 millert Exp $ 272dd076b8SGabor Kovesdan */ 282dd076b8SGabor Kovesdan 292dd076b8SGabor Kovesdan #include <sys/types.h> 302dd076b8SGabor Kovesdan #include <sys/file.h> 312dd076b8SGabor Kovesdan #include <sys/stat.h> 322dd076b8SGabor Kovesdan #include <sys/mman.h> 331e3e5815SXin LI #include <sys/wait.h> 342dd076b8SGabor Kovesdan 352dd076b8SGabor Kovesdan #include <ctype.h> 361e3e5815SXin LI #include <errno.h> 372dd076b8SGabor Kovesdan #include <libgen.h> 382cf624f6SXin LI #include <paths.h> 392cf624f6SXin LI #include <spawn.h> 402dd076b8SGabor Kovesdan #include <stddef.h> 41df6e4074SPedro F. Giffuni #include <stdint.h> 422dd076b8SGabor Kovesdan #include <stdio.h> 432dd076b8SGabor Kovesdan #include <stdlib.h> 442dd076b8SGabor Kovesdan #include <string.h> 452dd076b8SGabor Kovesdan #include <unistd.h> 462dd076b8SGabor Kovesdan 472dd076b8SGabor Kovesdan #include "common.h" 482dd076b8SGabor Kovesdan #include "util.h" 492dd076b8SGabor Kovesdan #include "pch.h" 502dd076b8SGabor Kovesdan #include "inp.h" 512dd076b8SGabor Kovesdan 522dd076b8SGabor Kovesdan 532dd076b8SGabor Kovesdan /* Input-file-with-indexable-lines abstract type */ 542dd076b8SGabor Kovesdan 552dd076b8SGabor Kovesdan static size_t i_size; /* size of the input file */ 562dd076b8SGabor Kovesdan static char *i_womp; /* plan a buffer for entire file */ 572dd076b8SGabor Kovesdan static char **i_ptr; /* pointers to lines in i_womp */ 582dd076b8SGabor Kovesdan static char empty_line[] = { '\0' }; 592dd076b8SGabor Kovesdan 602dd076b8SGabor Kovesdan static int tifd = -1; /* plan b virtual string array */ 612dd076b8SGabor Kovesdan static char *tibuf[2]; /* plan b buffers */ 622dd076b8SGabor Kovesdan static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */ 63a45060f0SPedro F. Giffuni static size_t lines_per_buf; /* how many lines per buffer */ 64a45060f0SPedro F. Giffuni static size_t tibuflen; /* plan b buffer length */ 65a45060f0SPedro F. Giffuni static size_t tireclen; /* length of records in tmp file */ 662dd076b8SGabor Kovesdan 672dd076b8SGabor Kovesdan static bool rev_in_string(const char *); 682dd076b8SGabor Kovesdan static bool reallocate_lines(size_t *); 692dd076b8SGabor Kovesdan 702dd076b8SGabor Kovesdan /* returns false if insufficient memory */ 712dd076b8SGabor Kovesdan static bool plan_a(const char *); 722dd076b8SGabor Kovesdan 732dd076b8SGabor Kovesdan static void plan_b(const char *); 742dd076b8SGabor Kovesdan 752dd076b8SGabor Kovesdan /* New patch--prepare to edit another file. */ 762dd076b8SGabor Kovesdan 772dd076b8SGabor Kovesdan void 782dd076b8SGabor Kovesdan re_input(void) 792dd076b8SGabor Kovesdan { 802dd076b8SGabor Kovesdan if (using_plan_a) { 812dd076b8SGabor Kovesdan free(i_ptr); 822dd076b8SGabor Kovesdan i_ptr = NULL; 832dd076b8SGabor Kovesdan if (i_womp != NULL) { 842dd076b8SGabor Kovesdan munmap(i_womp, i_size); 852dd076b8SGabor Kovesdan i_womp = NULL; 862dd076b8SGabor Kovesdan } 872dd076b8SGabor Kovesdan i_size = 0; 882dd076b8SGabor Kovesdan } else { 892dd076b8SGabor Kovesdan using_plan_a = true; /* maybe the next one is smaller */ 902dd076b8SGabor Kovesdan close(tifd); 912dd076b8SGabor Kovesdan tifd = -1; 922dd076b8SGabor Kovesdan free(tibuf[0]); 932dd076b8SGabor Kovesdan free(tibuf[1]); 942dd076b8SGabor Kovesdan tibuf[0] = tibuf[1] = NULL; 952dd076b8SGabor Kovesdan tiline[0] = tiline[1] = -1; 962dd076b8SGabor Kovesdan tireclen = 0; 972dd076b8SGabor Kovesdan } 982dd076b8SGabor Kovesdan } 992dd076b8SGabor Kovesdan 1002dd076b8SGabor Kovesdan /* Construct the line index, somehow or other. */ 1012dd076b8SGabor Kovesdan 1022dd076b8SGabor Kovesdan void 1032dd076b8SGabor Kovesdan scan_input(const char *filename) 1042dd076b8SGabor Kovesdan { 1052dd076b8SGabor Kovesdan if (!plan_a(filename)) 1062dd076b8SGabor Kovesdan plan_b(filename); 1072dd076b8SGabor Kovesdan if (verbose) { 1082dd076b8SGabor Kovesdan say("Patching file %s using Plan %s...\n", filename, 1092dd076b8SGabor Kovesdan (using_plan_a ? "A" : "B")); 1102dd076b8SGabor Kovesdan } 1112dd076b8SGabor Kovesdan } 1122dd076b8SGabor Kovesdan 1132dd076b8SGabor Kovesdan static bool 1142dd076b8SGabor Kovesdan reallocate_lines(size_t *lines_allocated) 1152dd076b8SGabor Kovesdan { 1162dd076b8SGabor Kovesdan char **p; 1172dd076b8SGabor Kovesdan size_t new_size; 1182dd076b8SGabor Kovesdan 1192dd076b8SGabor Kovesdan new_size = *lines_allocated * 3 / 2; 12063433bc9SPedro F. Giffuni p = reallocarray(i_ptr, new_size + 2, sizeof(char *)); 1212dd076b8SGabor Kovesdan if (p == NULL) { /* shucks, it was a near thing */ 1222dd076b8SGabor Kovesdan munmap(i_womp, i_size); 1232dd076b8SGabor Kovesdan i_womp = NULL; 1242dd076b8SGabor Kovesdan free(i_ptr); 1252dd076b8SGabor Kovesdan i_ptr = NULL; 1262dd076b8SGabor Kovesdan *lines_allocated = 0; 1272dd076b8SGabor Kovesdan return false; 1282dd076b8SGabor Kovesdan } 1292dd076b8SGabor Kovesdan *lines_allocated = new_size; 1302dd076b8SGabor Kovesdan i_ptr = p; 1312dd076b8SGabor Kovesdan return true; 1322dd076b8SGabor Kovesdan } 1332dd076b8SGabor Kovesdan 1342dd076b8SGabor Kovesdan /* Try keeping everything in memory. */ 1352dd076b8SGabor Kovesdan 1362dd076b8SGabor Kovesdan static bool 1372dd076b8SGabor Kovesdan plan_a(const char *filename) 1382dd076b8SGabor Kovesdan { 139e678759cSXin LI int ifd, statfailed; 140e678759cSXin LI char *p, *s; 1412dd076b8SGabor Kovesdan struct stat filestat; 1422dd076b8SGabor Kovesdan ptrdiff_t sz; 1432dd076b8SGabor Kovesdan size_t i; 1442dd076b8SGabor Kovesdan size_t iline, lines_allocated; 1452dd076b8SGabor Kovesdan 1462dd076b8SGabor Kovesdan #ifdef DEBUGGING 1472dd076b8SGabor Kovesdan if (debug & 8) 1482dd076b8SGabor Kovesdan return false; 1492dd076b8SGabor Kovesdan #endif 1502dd076b8SGabor Kovesdan 1512dd076b8SGabor Kovesdan if (filename == NULL || *filename == '\0') 1522dd076b8SGabor Kovesdan return false; 1532dd076b8SGabor Kovesdan 1542dd076b8SGabor Kovesdan statfailed = stat(filename, &filestat); 1552dd076b8SGabor Kovesdan if (statfailed && ok_to_create_file) { 1562dd076b8SGabor Kovesdan if (verbose) 1572dd076b8SGabor Kovesdan say("(Creating file %s...)\n", filename); 1582dd076b8SGabor Kovesdan 1592dd076b8SGabor Kovesdan /* 1602dd076b8SGabor Kovesdan * in check_patch case, we still display `Creating file' even 1612dd076b8SGabor Kovesdan * though we're not. The rule is that -C should be as similar 1622dd076b8SGabor Kovesdan * to normal patch behavior as possible 1632dd076b8SGabor Kovesdan */ 1642dd076b8SGabor Kovesdan if (check_only) 1652dd076b8SGabor Kovesdan return true; 1662dd076b8SGabor Kovesdan makedirs(filename, true); 1672dd076b8SGabor Kovesdan close(creat(filename, 0666)); 1682dd076b8SGabor Kovesdan statfailed = stat(filename, &filestat); 1692dd076b8SGabor Kovesdan } 170e678759cSXin LI if (statfailed) 1711e3e5815SXin LI fatal("can't find %s\n", filename); 1722dd076b8SGabor Kovesdan filemode = filestat.st_mode; 1732dd076b8SGabor Kovesdan if (!S_ISREG(filemode)) 1742dd076b8SGabor Kovesdan fatal("%s is not a normal file--can't patch\n", filename); 1752dd076b8SGabor Kovesdan if ((uint64_t)filestat.st_size > SIZE_MAX) { 1762dd076b8SGabor Kovesdan say("block too large to mmap\n"); 1772dd076b8SGabor Kovesdan return false; 1782dd076b8SGabor Kovesdan } 1792dd076b8SGabor Kovesdan i_size = (size_t)filestat.st_size; 1802dd076b8SGabor Kovesdan if (out_of_mem) { 1812dd076b8SGabor Kovesdan set_hunkmax(); /* make sure dynamic arrays are allocated */ 1822dd076b8SGabor Kovesdan out_of_mem = false; 1832dd076b8SGabor Kovesdan return false; /* force plan b because plan a bombed */ 1842dd076b8SGabor Kovesdan } 1852dd076b8SGabor Kovesdan if ((ifd = open(filename, O_RDONLY)) < 0) 1862dd076b8SGabor Kovesdan pfatal("can't open file %s", filename); 1872dd076b8SGabor Kovesdan 1882dd076b8SGabor Kovesdan if (i_size) { 1892dd076b8SGabor Kovesdan i_womp = mmap(NULL, i_size, PROT_READ, MAP_PRIVATE, ifd, 0); 1902dd076b8SGabor Kovesdan if (i_womp == MAP_FAILED) { 1912dd076b8SGabor Kovesdan perror("mmap failed"); 1922dd076b8SGabor Kovesdan i_womp = NULL; 1932dd076b8SGabor Kovesdan close(ifd); 1942dd076b8SGabor Kovesdan return false; 1952dd076b8SGabor Kovesdan } 1962dd076b8SGabor Kovesdan } else { 1972dd076b8SGabor Kovesdan i_womp = NULL; 1982dd076b8SGabor Kovesdan } 1992dd076b8SGabor Kovesdan 2002dd076b8SGabor Kovesdan close(ifd); 2012dd076b8SGabor Kovesdan if (i_size) 2022dd076b8SGabor Kovesdan madvise(i_womp, i_size, MADV_SEQUENTIAL); 2032dd076b8SGabor Kovesdan 2042dd076b8SGabor Kovesdan /* estimate the number of lines */ 2052dd076b8SGabor Kovesdan lines_allocated = i_size / 25; 2062dd076b8SGabor Kovesdan if (lines_allocated < 100) 2072dd076b8SGabor Kovesdan lines_allocated = 100; 2082dd076b8SGabor Kovesdan 2092dd076b8SGabor Kovesdan if (!reallocate_lines(&lines_allocated)) 2102dd076b8SGabor Kovesdan return false; 2112dd076b8SGabor Kovesdan 2122dd076b8SGabor Kovesdan /* now scan the buffer and build pointer array */ 2132dd076b8SGabor Kovesdan iline = 1; 2142dd076b8SGabor Kovesdan i_ptr[iline] = i_womp; 21521ab148dSKyle Evans /* 21621ab148dSKyle Evans * Testing for NUL here actively breaks files that innocently use NUL 21721ab148dSKyle Evans * for other reasons. mmap(2) succeeded, just scan the whole buffer. 21821ab148dSKyle Evans */ 21921ab148dSKyle Evans for (s = i_womp, i = 0; i < i_size; s++, i++) { 2202dd076b8SGabor Kovesdan if (*s == '\n') { 2212dd076b8SGabor Kovesdan if (iline == lines_allocated) { 2222dd076b8SGabor Kovesdan if (!reallocate_lines(&lines_allocated)) 2232dd076b8SGabor Kovesdan return false; 2242dd076b8SGabor Kovesdan } 2252dd076b8SGabor Kovesdan /* these are NOT NUL terminated */ 2262dd076b8SGabor Kovesdan i_ptr[++iline] = s + 1; 2272dd076b8SGabor Kovesdan } 2282dd076b8SGabor Kovesdan } 2292dd076b8SGabor Kovesdan /* if the last line contains no EOL, append one */ 2302dd076b8SGabor Kovesdan if (i_size > 0 && i_womp[i_size - 1] != '\n') { 2312dd076b8SGabor Kovesdan last_line_missing_eol = true; 2322dd076b8SGabor Kovesdan /* fix last line */ 2332dd076b8SGabor Kovesdan sz = s - i_ptr[iline]; 2342dd076b8SGabor Kovesdan p = malloc(sz + 1); 2352dd076b8SGabor Kovesdan if (p == NULL) { 2362dd076b8SGabor Kovesdan free(i_ptr); 2372dd076b8SGabor Kovesdan i_ptr = NULL; 2382dd076b8SGabor Kovesdan munmap(i_womp, i_size); 2392dd076b8SGabor Kovesdan i_womp = NULL; 2402dd076b8SGabor Kovesdan return false; 2412dd076b8SGabor Kovesdan } 2422dd076b8SGabor Kovesdan 2432dd076b8SGabor Kovesdan memcpy(p, i_ptr[iline], sz); 2442dd076b8SGabor Kovesdan p[sz] = '\n'; 2452dd076b8SGabor Kovesdan i_ptr[iline] = p; 2462dd076b8SGabor Kovesdan /* count the extra line and make it point to some valid mem */ 2472dd076b8SGabor Kovesdan i_ptr[++iline] = empty_line; 2482dd076b8SGabor Kovesdan } else 2492dd076b8SGabor Kovesdan last_line_missing_eol = false; 2502dd076b8SGabor Kovesdan 2512dd076b8SGabor Kovesdan input_lines = iline - 1; 2522dd076b8SGabor Kovesdan 2532dd076b8SGabor Kovesdan /* now check for revision, if any */ 2542dd076b8SGabor Kovesdan 2552dd076b8SGabor Kovesdan if (revision != NULL) { 256a45060f0SPedro F. Giffuni if (i_womp == NULL || !rev_in_string(i_womp)) { 2572dd076b8SGabor Kovesdan if (force) { 2582dd076b8SGabor Kovesdan if (verbose) 2592dd076b8SGabor Kovesdan say("Warning: this file doesn't appear " 2602dd076b8SGabor Kovesdan "to be the %s version--patching anyway.\n", 2612dd076b8SGabor Kovesdan revision); 2622dd076b8SGabor Kovesdan } else if (batch) { 2632dd076b8SGabor Kovesdan fatal("this file doesn't appear to be the " 2642dd076b8SGabor Kovesdan "%s version--aborting.\n", 2652dd076b8SGabor Kovesdan revision); 2662dd076b8SGabor Kovesdan } else { 2672dd076b8SGabor Kovesdan ask("This file doesn't appear to be the " 2682dd076b8SGabor Kovesdan "%s version--patch anyway? [n] ", 2692dd076b8SGabor Kovesdan revision); 2702dd076b8SGabor Kovesdan if (*buf != 'y') 2712dd076b8SGabor Kovesdan fatal("aborted\n"); 2722dd076b8SGabor Kovesdan } 2732dd076b8SGabor Kovesdan } else if (verbose) 2742dd076b8SGabor Kovesdan say("Good. This file appears to be the %s version.\n", 2752dd076b8SGabor Kovesdan revision); 2762dd076b8SGabor Kovesdan } 2772dd076b8SGabor Kovesdan return true; /* plan a will work */ 2782dd076b8SGabor Kovesdan } 2792dd076b8SGabor Kovesdan 2802dd076b8SGabor Kovesdan /* Keep (virtually) nothing in memory. */ 2812dd076b8SGabor Kovesdan 2822dd076b8SGabor Kovesdan static void 2832dd076b8SGabor Kovesdan plan_b(const char *filename) 2842dd076b8SGabor Kovesdan { 2852dd076b8SGabor Kovesdan FILE *ifp; 286*25696725SMartin Tournoij size_t i = 0, j, blen = 0, maxlen = 1; 287*25696725SMartin Tournoij ssize_t len; 288*25696725SMartin Tournoij char *p = NULL; 2892dd076b8SGabor Kovesdan bool found_revision = (revision == NULL); 2902dd076b8SGabor Kovesdan 2912dd076b8SGabor Kovesdan using_plan_a = false; 2922dd076b8SGabor Kovesdan if ((ifp = fopen(filename, "r")) == NULL) 2932dd076b8SGabor Kovesdan pfatal("can't open file %s", filename); 2942dd076b8SGabor Kovesdan unlink(TMPINNAME); 2952dd076b8SGabor Kovesdan if ((tifd = open(TMPINNAME, O_EXCL | O_CREAT | O_WRONLY, 0666)) < 0) 2962dd076b8SGabor Kovesdan pfatal("can't open file %s", TMPINNAME); 297c384a278SPedro F. Giffuni len = 0; 298c384a278SPedro F. Giffuni maxlen = 1; 299*25696725SMartin Tournoij while ((len = getline(&p, &blen, ifp)) >= 0) { 300a45060f0SPedro F. Giffuni if (p[len - 1] == '\n') 301a45060f0SPedro F. Giffuni p[len - 1] = '\0'; 302a45060f0SPedro F. Giffuni else { 303*25696725SMartin Tournoij /* EOF without EOL */ 304a45060f0SPedro F. Giffuni last_line_missing_eol = true; 305a45060f0SPedro F. Giffuni len++; 3062dd076b8SGabor Kovesdan } 307a45060f0SPedro F. Giffuni if (revision != NULL && !found_revision && rev_in_string(p)) 308a45060f0SPedro F. Giffuni found_revision = true; 309*25696725SMartin Tournoij if ((size_t)len > maxlen) 310a45060f0SPedro F. Giffuni maxlen = len; /* find longest line */ 311a45060f0SPedro F. Giffuni } 312*25696725SMartin Tournoij free(p); 313a45060f0SPedro F. Giffuni if (ferror(ifp)) 314a45060f0SPedro F. Giffuni pfatal("can't read file %s", filename); 3152dd076b8SGabor Kovesdan 3162dd076b8SGabor Kovesdan if (revision != NULL) { 3172dd076b8SGabor Kovesdan if (!found_revision) { 3182dd076b8SGabor Kovesdan if (force) { 3192dd076b8SGabor Kovesdan if (verbose) 3202dd076b8SGabor Kovesdan say("Warning: this file doesn't appear " 3212dd076b8SGabor Kovesdan "to be the %s version--patching anyway.\n", 3222dd076b8SGabor Kovesdan revision); 3232dd076b8SGabor Kovesdan } else if (batch) { 3242dd076b8SGabor Kovesdan fatal("this file doesn't appear to be the " 3252dd076b8SGabor Kovesdan "%s version--aborting.\n", 3262dd076b8SGabor Kovesdan revision); 3272dd076b8SGabor Kovesdan } else { 3282dd076b8SGabor Kovesdan ask("This file doesn't appear to be the %s " 3292dd076b8SGabor Kovesdan "version--patch anyway? [n] ", 3302dd076b8SGabor Kovesdan revision); 3312dd076b8SGabor Kovesdan if (*buf != 'y') 3322dd076b8SGabor Kovesdan fatal("aborted\n"); 3332dd076b8SGabor Kovesdan } 3342dd076b8SGabor Kovesdan } else if (verbose) 3352dd076b8SGabor Kovesdan say("Good. This file appears to be the %s version.\n", 3362dd076b8SGabor Kovesdan revision); 3372dd076b8SGabor Kovesdan } 3382dd076b8SGabor Kovesdan fseek(ifp, 0L, SEEK_SET); /* rewind file */ 3392dd076b8SGabor Kovesdan tireclen = maxlen; 340a45060f0SPedro F. Giffuni tibuflen = maxlen > BUFFERSIZE ? maxlen : BUFFERSIZE; 341a45060f0SPedro F. Giffuni lines_per_buf = tibuflen / maxlen; 342a45060f0SPedro F. Giffuni tibuf[0] = malloc(tibuflen + 1); 3432dd076b8SGabor Kovesdan if (tibuf[0] == NULL) 3442dd076b8SGabor Kovesdan fatal("out of memory\n"); 345a45060f0SPedro F. Giffuni tibuf[1] = malloc(tibuflen + 1); 3462dd076b8SGabor Kovesdan if (tibuf[1] == NULL) 3472dd076b8SGabor Kovesdan fatal("out of memory\n"); 3482dd076b8SGabor Kovesdan for (i = 1;; i++) { 3492dd076b8SGabor Kovesdan p = tibuf[0] + maxlen * (i % lines_per_buf); 3502dd076b8SGabor Kovesdan if (i % lines_per_buf == 0) /* new block */ 351a45060f0SPedro F. Giffuni if (write(tifd, tibuf[0], tibuflen) != 352a45060f0SPedro F. Giffuni (ssize_t) tibuflen) 3532dd076b8SGabor Kovesdan pfatal("can't write temp file"); 3542dd076b8SGabor Kovesdan if (fgets(p, maxlen + 1, ifp) == NULL) { 3552dd076b8SGabor Kovesdan input_lines = i - 1; 3562dd076b8SGabor Kovesdan if (i % lines_per_buf != 0) 357a45060f0SPedro F. Giffuni if (write(tifd, tibuf[0], tibuflen) != 358a45060f0SPedro F. Giffuni (ssize_t) tibuflen) 3592dd076b8SGabor Kovesdan pfatal("can't write temp file"); 3602dd076b8SGabor Kovesdan break; 3612dd076b8SGabor Kovesdan } 3622dd076b8SGabor Kovesdan j = strlen(p); 3632dd076b8SGabor Kovesdan /* These are '\n' terminated strings, so no need to add a NUL */ 3642dd076b8SGabor Kovesdan if (j == 0 || p[j - 1] != '\n') 3652dd076b8SGabor Kovesdan p[j] = '\n'; 3662dd076b8SGabor Kovesdan } 3672dd076b8SGabor Kovesdan fclose(ifp); 3682dd076b8SGabor Kovesdan close(tifd); 3692dd076b8SGabor Kovesdan if ((tifd = open(TMPINNAME, O_RDONLY)) < 0) 3702dd076b8SGabor Kovesdan pfatal("can't reopen file %s", TMPINNAME); 3712dd076b8SGabor Kovesdan } 3722dd076b8SGabor Kovesdan 3732dd076b8SGabor Kovesdan /* 3742dd076b8SGabor Kovesdan * Fetch a line from the input file, \n terminated, not necessarily \0. 3752dd076b8SGabor Kovesdan */ 3762dd076b8SGabor Kovesdan char * 3772dd076b8SGabor Kovesdan ifetch(LINENUM line, int whichbuf) 3782dd076b8SGabor Kovesdan { 3792dd076b8SGabor Kovesdan if (line < 1 || line > input_lines) { 3802dd076b8SGabor Kovesdan if (warn_on_invalid_line) { 3812dd076b8SGabor Kovesdan say("No such line %ld in input file, ignoring\n", line); 3822dd076b8SGabor Kovesdan warn_on_invalid_line = false; 3832dd076b8SGabor Kovesdan } 3842dd076b8SGabor Kovesdan return NULL; 3852dd076b8SGabor Kovesdan } 3862dd076b8SGabor Kovesdan if (using_plan_a) 3872dd076b8SGabor Kovesdan return i_ptr[line]; 3882dd076b8SGabor Kovesdan else { 3892dd076b8SGabor Kovesdan LINENUM offline = line % lines_per_buf; 3902dd076b8SGabor Kovesdan LINENUM baseline = line - offline; 3912dd076b8SGabor Kovesdan 3922dd076b8SGabor Kovesdan if (tiline[0] == baseline) 3932dd076b8SGabor Kovesdan whichbuf = 0; 3942dd076b8SGabor Kovesdan else if (tiline[1] == baseline) 3952dd076b8SGabor Kovesdan whichbuf = 1; 3962dd076b8SGabor Kovesdan else { 3972dd076b8SGabor Kovesdan tiline[whichbuf] = baseline; 3982dd076b8SGabor Kovesdan 3992dd076b8SGabor Kovesdan if (lseek(tifd, (off_t) (baseline / lines_per_buf * 400a45060f0SPedro F. Giffuni tibuflen), SEEK_SET) < 0) 4012dd076b8SGabor Kovesdan pfatal("cannot seek in the temporary input file"); 4022dd076b8SGabor Kovesdan 403a45060f0SPedro F. Giffuni if (read(tifd, tibuf[whichbuf], tibuflen) != 404a45060f0SPedro F. Giffuni (ssize_t) tibuflen) 4052dd076b8SGabor Kovesdan pfatal("error reading tmp file %s", TMPINNAME); 4062dd076b8SGabor Kovesdan } 4072dd076b8SGabor Kovesdan return tibuf[whichbuf] + (tireclen * offline); 4082dd076b8SGabor Kovesdan } 4092dd076b8SGabor Kovesdan } 4102dd076b8SGabor Kovesdan 4112dd076b8SGabor Kovesdan /* 4122dd076b8SGabor Kovesdan * True if the string argument contains the revision number we want. 4132dd076b8SGabor Kovesdan */ 4142dd076b8SGabor Kovesdan static bool 4152dd076b8SGabor Kovesdan rev_in_string(const char *string) 4162dd076b8SGabor Kovesdan { 4172dd076b8SGabor Kovesdan const char *s; 4182dd076b8SGabor Kovesdan size_t patlen; 4192dd076b8SGabor Kovesdan 4202dd076b8SGabor Kovesdan if (revision == NULL) 4212dd076b8SGabor Kovesdan return true; 4222dd076b8SGabor Kovesdan patlen = strlen(revision); 4232dd076b8SGabor Kovesdan if (strnEQ(string, revision, patlen) && isspace((unsigned char)string[patlen])) 4242dd076b8SGabor Kovesdan return true; 4252dd076b8SGabor Kovesdan for (s = string; *s; s++) { 4262dd076b8SGabor Kovesdan if (isspace((unsigned char)*s) && strnEQ(s + 1, revision, patlen) && 4272dd076b8SGabor Kovesdan isspace((unsigned char)s[patlen + 1])) { 4282dd076b8SGabor Kovesdan return true; 4292dd076b8SGabor Kovesdan } 4302dd076b8SGabor Kovesdan } 4312dd076b8SGabor Kovesdan return false; 4322dd076b8SGabor Kovesdan } 433