148d201a5SJoerg Sonnenberger /* 2573bac56SSascha Wildner * $OpenBSD: patch.c,v 1.43 2004/11/19 20:08:11 otto Exp $ 3*41871674SJoerg Sonnenberger * $DragonFly: src/usr.bin/patch/patch.c,v 1.5 2006/04/10 08:11:43 joerg Exp $ 448d201a5SJoerg Sonnenberger */ 548d201a5SJoerg Sonnenberger 648d201a5SJoerg Sonnenberger /* 748d201a5SJoerg Sonnenberger * patch - a program to apply diffs to original files 848d201a5SJoerg Sonnenberger * 948d201a5SJoerg Sonnenberger * Copyright 1986, Larry Wall 1048d201a5SJoerg Sonnenberger * 1148d201a5SJoerg Sonnenberger * Redistribution and use in source and binary forms, with or without 1248d201a5SJoerg Sonnenberger * modification, are permitted provided that the following condition is met: 1348d201a5SJoerg Sonnenberger * 1. Redistributions of source code must retain the above copyright notice, 1448d201a5SJoerg Sonnenberger * this condition and the following disclaimer. 1548d201a5SJoerg Sonnenberger * 1648d201a5SJoerg Sonnenberger * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY 1748d201a5SJoerg Sonnenberger * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1848d201a5SJoerg Sonnenberger * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 1948d201a5SJoerg Sonnenberger * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR 2048d201a5SJoerg Sonnenberger * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2148d201a5SJoerg Sonnenberger * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2248d201a5SJoerg Sonnenberger * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 2348d201a5SJoerg Sonnenberger * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2448d201a5SJoerg Sonnenberger * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2548d201a5SJoerg Sonnenberger * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2648d201a5SJoerg Sonnenberger * SUCH DAMAGE. 2748d201a5SJoerg Sonnenberger * 2848d201a5SJoerg Sonnenberger * -C option added in 1998, original code by Marc Espie, based on FreeBSD 2948d201a5SJoerg Sonnenberger * behaviour 3048d201a5SJoerg Sonnenberger */ 3148d201a5SJoerg Sonnenberger 3248d201a5SJoerg Sonnenberger #include <sys/types.h> 3348d201a5SJoerg Sonnenberger #include <sys/stat.h> 3448d201a5SJoerg Sonnenberger 3548d201a5SJoerg Sonnenberger #include <ctype.h> 3648d201a5SJoerg Sonnenberger #include <getopt.h> 3748d201a5SJoerg Sonnenberger #include <limits.h> 3848d201a5SJoerg Sonnenberger #include <stdio.h> 3948d201a5SJoerg Sonnenberger #include <string.h> 4048d201a5SJoerg Sonnenberger #include <stdlib.h> 41f7e25d55SSascha Wildner #include <unistd.h> 4248d201a5SJoerg Sonnenberger 4348d201a5SJoerg Sonnenberger #include "common.h" 4448d201a5SJoerg Sonnenberger #include "util.h" 4548d201a5SJoerg Sonnenberger #include "pch.h" 4648d201a5SJoerg Sonnenberger #include "inp.h" 4748d201a5SJoerg Sonnenberger #include "backupfile.h" 4848d201a5SJoerg Sonnenberger #include "pathnames.h" 4948d201a5SJoerg Sonnenberger 5048d201a5SJoerg Sonnenberger int filemode = 0644; 5148d201a5SJoerg Sonnenberger 5248d201a5SJoerg Sonnenberger char buf[MAXLINELEN]; /* general purpose buffer */ 5348d201a5SJoerg Sonnenberger 5448d201a5SJoerg Sonnenberger bool using_plan_a = true; /* try to keep everything in memory */ 5548d201a5SJoerg Sonnenberger bool out_of_mem = false; /* ran out of memory in plan a */ 5648d201a5SJoerg Sonnenberger 5748d201a5SJoerg Sonnenberger #define MAXFILEC 2 5848d201a5SJoerg Sonnenberger 5948d201a5SJoerg Sonnenberger char *filearg[MAXFILEC]; 6048d201a5SJoerg Sonnenberger bool ok_to_create_file = false; 6148d201a5SJoerg Sonnenberger char *outname = NULL; 6248d201a5SJoerg Sonnenberger char *origprae = NULL; 6348d201a5SJoerg Sonnenberger char *TMPOUTNAME; 6448d201a5SJoerg Sonnenberger char *TMPINNAME; 6548d201a5SJoerg Sonnenberger char *TMPREJNAME; 6648d201a5SJoerg Sonnenberger char *TMPPATNAME; 6748d201a5SJoerg Sonnenberger bool toutkeep = false; 6848d201a5SJoerg Sonnenberger bool trejkeep = false; 6948d201a5SJoerg Sonnenberger bool warn_on_invalid_line; 7048d201a5SJoerg Sonnenberger bool last_line_missing_eol; 7148d201a5SJoerg Sonnenberger 7248d201a5SJoerg Sonnenberger #ifdef DEBUGGING 7348d201a5SJoerg Sonnenberger int debug = 0; 7448d201a5SJoerg Sonnenberger #endif 7548d201a5SJoerg Sonnenberger 7648d201a5SJoerg Sonnenberger bool force = false; 7748d201a5SJoerg Sonnenberger bool batch = false; 7848d201a5SJoerg Sonnenberger bool verbose = true; 7948d201a5SJoerg Sonnenberger bool reverse = false; 8048d201a5SJoerg Sonnenberger bool noreverse = false; 8148d201a5SJoerg Sonnenberger bool skip_rest_of_patch = false; 8248d201a5SJoerg Sonnenberger int strippath = 957; 8348d201a5SJoerg Sonnenberger bool canonicalize = false; 8448d201a5SJoerg Sonnenberger bool check_only = false; 8548d201a5SJoerg Sonnenberger int diff_type = 0; 8648d201a5SJoerg Sonnenberger char *revision = NULL; /* prerequisite revision, if any */ 8748d201a5SJoerg Sonnenberger LINENUM input_lines = 0; /* how long is input file in lines */ 8848d201a5SJoerg Sonnenberger int posix = 0; /* strict POSIX mode? */ 8948d201a5SJoerg Sonnenberger 9048d201a5SJoerg Sonnenberger static void reinitialize_almost_everything(void); 9148d201a5SJoerg Sonnenberger static void get_some_switches(void); 9248d201a5SJoerg Sonnenberger static LINENUM locate_hunk(LINENUM); 93f7e25d55SSascha Wildner static void abort_context_hunk(void); 94f7e25d55SSascha Wildner static void rej_line(int, LINENUM); 9548d201a5SJoerg Sonnenberger static void abort_hunk(void); 9648d201a5SJoerg Sonnenberger static void apply_hunk(LINENUM); 9748d201a5SJoerg Sonnenberger static void init_output(const char *); 9848d201a5SJoerg Sonnenberger static void init_reject(const char *); 9948d201a5SJoerg Sonnenberger static void copy_till(LINENUM, bool); 10048d201a5SJoerg Sonnenberger static void spew_output(void); 10148d201a5SJoerg Sonnenberger static void dump_line(LINENUM, bool); 10248d201a5SJoerg Sonnenberger static bool patch_match(LINENUM, LINENUM, LINENUM); 10348d201a5SJoerg Sonnenberger static bool similar(const char *, const char *, int); 10448d201a5SJoerg Sonnenberger static void usage(void); 10548d201a5SJoerg Sonnenberger 10648d201a5SJoerg Sonnenberger /* true if -E was specified on command line. */ 10748d201a5SJoerg Sonnenberger static bool remove_empty_files = false; 10848d201a5SJoerg Sonnenberger 10948d201a5SJoerg Sonnenberger /* true if -R was specified on command line. */ 11048d201a5SJoerg Sonnenberger static bool reverse_flag_specified = false; 11148d201a5SJoerg Sonnenberger 11248d201a5SJoerg Sonnenberger /* buffer holding the name of the rejected patch file. */ 11348d201a5SJoerg Sonnenberger static char rejname[NAME_MAX + 1]; 11448d201a5SJoerg Sonnenberger 11548d201a5SJoerg Sonnenberger /* buffer for stderr */ 11648d201a5SJoerg Sonnenberger static char serrbuf[BUFSIZ]; 11748d201a5SJoerg Sonnenberger 11848d201a5SJoerg Sonnenberger /* how many input lines have been irretractibly output */ 11948d201a5SJoerg Sonnenberger static LINENUM last_frozen_line = 0; 12048d201a5SJoerg Sonnenberger 12148d201a5SJoerg Sonnenberger static int Argc; /* guess */ 12248d201a5SJoerg Sonnenberger static char **Argv; 12348d201a5SJoerg Sonnenberger static int Argc_last; /* for restarting plan_b */ 12448d201a5SJoerg Sonnenberger static char **Argv_last; 12548d201a5SJoerg Sonnenberger 12648d201a5SJoerg Sonnenberger static FILE *ofp = NULL; /* output file pointer */ 12748d201a5SJoerg Sonnenberger static FILE *rejfp = NULL; /* reject file pointer */ 12848d201a5SJoerg Sonnenberger 12948d201a5SJoerg Sonnenberger static int filec = 0; /* how many file arguments? */ 13048d201a5SJoerg Sonnenberger static LINENUM last_offset = 0; 13148d201a5SJoerg Sonnenberger static LINENUM maxfuzz = 2; 13248d201a5SJoerg Sonnenberger 13348d201a5SJoerg Sonnenberger /* patch using ifdef, ifndef, etc. */ 13448d201a5SJoerg Sonnenberger static bool do_defines = false; 13548d201a5SJoerg Sonnenberger /* #ifdef xyzzy */ 13648d201a5SJoerg Sonnenberger static char if_defined[128]; 13748d201a5SJoerg Sonnenberger /* #ifndef xyzzy */ 13848d201a5SJoerg Sonnenberger static char not_defined[128]; 13948d201a5SJoerg Sonnenberger /* #else */ 14048d201a5SJoerg Sonnenberger static const char else_defined[] = "#else\n"; 14148d201a5SJoerg Sonnenberger /* #endif xyzzy */ 14248d201a5SJoerg Sonnenberger static char end_defined[128]; 14348d201a5SJoerg Sonnenberger 14448d201a5SJoerg Sonnenberger 14548d201a5SJoerg Sonnenberger /* Apply a set of diffs as appropriate. */ 14648d201a5SJoerg Sonnenberger 14748d201a5SJoerg Sonnenberger int 14848d201a5SJoerg Sonnenberger main(int argc, char *argv[]) 14948d201a5SJoerg Sonnenberger { 150f7e25d55SSascha Wildner int error = 0, hunk, failed, i, fd; 15148d201a5SJoerg Sonnenberger LINENUM where = 0, newwhere, fuzz, mymaxfuzz; 15248d201a5SJoerg Sonnenberger const char *tmpdir; 15348d201a5SJoerg Sonnenberger char *v; 15448d201a5SJoerg Sonnenberger 15548d201a5SJoerg Sonnenberger setbuf(stderr, serrbuf); 15648d201a5SJoerg Sonnenberger for (i = 0; i < MAXFILEC; i++) 15748d201a5SJoerg Sonnenberger filearg[i] = NULL; 15848d201a5SJoerg Sonnenberger 15948d201a5SJoerg Sonnenberger /* Cons up the names of the temporary files. */ 16048d201a5SJoerg Sonnenberger if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0') 16148d201a5SJoerg Sonnenberger tmpdir = _PATH_TMP; 16248d201a5SJoerg Sonnenberger for (i = strlen(tmpdir) - 1; i > 0 && tmpdir[i] == '/'; i--) 16348d201a5SJoerg Sonnenberger ; 16448d201a5SJoerg Sonnenberger i++; 16548d201a5SJoerg Sonnenberger if (asprintf(&TMPOUTNAME, "%.*s/patchoXXXXXXXXXX", i, tmpdir) == -1) 16648d201a5SJoerg Sonnenberger fatal("cannot allocate memory"); 16748d201a5SJoerg Sonnenberger if ((fd = mkstemp(TMPOUTNAME)) < 0) 16848d201a5SJoerg Sonnenberger pfatal("can't create %s", TMPOUTNAME); 16948d201a5SJoerg Sonnenberger close(fd); 17048d201a5SJoerg Sonnenberger 17148d201a5SJoerg Sonnenberger if (asprintf(&TMPINNAME, "%.*s/patchiXXXXXXXXXX", i, tmpdir) == -1) 17248d201a5SJoerg Sonnenberger fatal("cannot allocate memory"); 17348d201a5SJoerg Sonnenberger if ((fd = mkstemp(TMPINNAME)) < 0) 17448d201a5SJoerg Sonnenberger pfatal("can't create %s", TMPINNAME); 17548d201a5SJoerg Sonnenberger close(fd); 17648d201a5SJoerg Sonnenberger 17748d201a5SJoerg Sonnenberger if (asprintf(&TMPREJNAME, "%.*s/patchrXXXXXXXXXX", i, tmpdir) == -1) 17848d201a5SJoerg Sonnenberger fatal("cannot allocate memory"); 17948d201a5SJoerg Sonnenberger if ((fd = mkstemp(TMPREJNAME)) < 0) 18048d201a5SJoerg Sonnenberger pfatal("can't create %s", TMPREJNAME); 18148d201a5SJoerg Sonnenberger close(fd); 18248d201a5SJoerg Sonnenberger 18348d201a5SJoerg Sonnenberger if (asprintf(&TMPPATNAME, "%.*s/patchpXXXXXXXXXX", i, tmpdir) == -1) 18448d201a5SJoerg Sonnenberger fatal("cannot allocate memory"); 18548d201a5SJoerg Sonnenberger if ((fd = mkstemp(TMPPATNAME)) < 0) 18648d201a5SJoerg Sonnenberger pfatal("can't create %s", TMPPATNAME); 18748d201a5SJoerg Sonnenberger close(fd); 18848d201a5SJoerg Sonnenberger 18948d201a5SJoerg Sonnenberger v = getenv("SIMPLE_BACKUP_SUFFIX"); 19048d201a5SJoerg Sonnenberger if (v) 19148d201a5SJoerg Sonnenberger simple_backup_suffix = v; 19248d201a5SJoerg Sonnenberger else 19348d201a5SJoerg Sonnenberger simple_backup_suffix = ORIGEXT; 19448d201a5SJoerg Sonnenberger 19548d201a5SJoerg Sonnenberger /* parse switches */ 19648d201a5SJoerg Sonnenberger Argc = argc; 19748d201a5SJoerg Sonnenberger Argv = argv; 19848d201a5SJoerg Sonnenberger get_some_switches(); 19948d201a5SJoerg Sonnenberger 20048d201a5SJoerg Sonnenberger if (backup_type == none) { 20148d201a5SJoerg Sonnenberger if ((v = getenv("PATCH_VERSION_CONTROL")) == NULL) 20248d201a5SJoerg Sonnenberger v = getenv("VERSION_CONTROL"); 20348d201a5SJoerg Sonnenberger if (v != NULL || !posix) 20448d201a5SJoerg Sonnenberger backup_type = get_version(v); /* OK to pass NULL. */ 20548d201a5SJoerg Sonnenberger } 20648d201a5SJoerg Sonnenberger 20748d201a5SJoerg Sonnenberger /* make sure we clean up /tmp in case of disaster */ 20848d201a5SJoerg Sonnenberger set_signals(0); 20948d201a5SJoerg Sonnenberger 21048d201a5SJoerg Sonnenberger for (open_patch_file(filearg[1]); there_is_another_patch(); 21148d201a5SJoerg Sonnenberger reinitialize_almost_everything()) { 21248d201a5SJoerg Sonnenberger /* for each patch in patch file */ 21348d201a5SJoerg Sonnenberger 21448d201a5SJoerg Sonnenberger warn_on_invalid_line = true; 21548d201a5SJoerg Sonnenberger 21648d201a5SJoerg Sonnenberger if (outname == NULL) 21748d201a5SJoerg Sonnenberger outname = savestr(filearg[0]); 21848d201a5SJoerg Sonnenberger 21948d201a5SJoerg Sonnenberger /* for ed script just up and do it and exit */ 22048d201a5SJoerg Sonnenberger if (diff_type == ED_DIFF) { 22148d201a5SJoerg Sonnenberger do_ed_script(); 22248d201a5SJoerg Sonnenberger continue; 22348d201a5SJoerg Sonnenberger } 22448d201a5SJoerg Sonnenberger /* initialize the patched file */ 22548d201a5SJoerg Sonnenberger if (!skip_rest_of_patch) 22648d201a5SJoerg Sonnenberger init_output(TMPOUTNAME); 22748d201a5SJoerg Sonnenberger 22848d201a5SJoerg Sonnenberger /* initialize reject file */ 22948d201a5SJoerg Sonnenberger init_reject(TMPREJNAME); 23048d201a5SJoerg Sonnenberger 23148d201a5SJoerg Sonnenberger /* find out where all the lines are */ 23248d201a5SJoerg Sonnenberger if (!skip_rest_of_patch) 23348d201a5SJoerg Sonnenberger scan_input(filearg[0]); 23448d201a5SJoerg Sonnenberger 23548d201a5SJoerg Sonnenberger /* from here on, open no standard i/o files, because malloc */ 23648d201a5SJoerg Sonnenberger /* might misfire and we can't catch it easily */ 23748d201a5SJoerg Sonnenberger 23848d201a5SJoerg Sonnenberger /* apply each hunk of patch */ 23948d201a5SJoerg Sonnenberger hunk = 0; 24048d201a5SJoerg Sonnenberger failed = 0; 24148d201a5SJoerg Sonnenberger out_of_mem = false; 24248d201a5SJoerg Sonnenberger while (another_hunk()) { 24348d201a5SJoerg Sonnenberger hunk++; 24448d201a5SJoerg Sonnenberger fuzz = 0; 24548d201a5SJoerg Sonnenberger mymaxfuzz = pch_context(); 24648d201a5SJoerg Sonnenberger if (maxfuzz < mymaxfuzz) 24748d201a5SJoerg Sonnenberger mymaxfuzz = maxfuzz; 24848d201a5SJoerg Sonnenberger if (!skip_rest_of_patch) { 24948d201a5SJoerg Sonnenberger do { 25048d201a5SJoerg Sonnenberger where = locate_hunk(fuzz); 25148d201a5SJoerg Sonnenberger if (hunk == 1 && where == 0 && !force) { 25248d201a5SJoerg Sonnenberger /* dwim for reversed patch? */ 25348d201a5SJoerg Sonnenberger if (!pch_swap()) { 25448d201a5SJoerg Sonnenberger if (fuzz == 0) 25548d201a5SJoerg Sonnenberger say("Not enough memory to try swapped hunk! Assuming unswapped.\n"); 25648d201a5SJoerg Sonnenberger continue; 25748d201a5SJoerg Sonnenberger } 25848d201a5SJoerg Sonnenberger reverse = !reverse; 25948d201a5SJoerg Sonnenberger /* try again */ 26048d201a5SJoerg Sonnenberger where = locate_hunk(fuzz); 26148d201a5SJoerg Sonnenberger if (where == 0) { 26248d201a5SJoerg Sonnenberger /* didn't find it swapped */ 26348d201a5SJoerg Sonnenberger if (!pch_swap()) 26448d201a5SJoerg Sonnenberger /* put it back to normal */ 26548d201a5SJoerg Sonnenberger fatal("lost hunk on alloc error!\n"); 26648d201a5SJoerg Sonnenberger reverse = !reverse; 26748d201a5SJoerg Sonnenberger } else if (noreverse) { 26848d201a5SJoerg Sonnenberger if (!pch_swap()) 26948d201a5SJoerg Sonnenberger /* put it back to normal */ 27048d201a5SJoerg Sonnenberger fatal("lost hunk on alloc error!\n"); 27148d201a5SJoerg Sonnenberger reverse = !reverse; 27248d201a5SJoerg Sonnenberger say("Ignoring previously applied (or reversed) patch.\n"); 27348d201a5SJoerg Sonnenberger skip_rest_of_patch = true; 27448d201a5SJoerg Sonnenberger } else if (batch) { 27548d201a5SJoerg Sonnenberger if (verbose) 27648d201a5SJoerg Sonnenberger say("%seversed (or previously applied) patch detected! %s -R.", 27748d201a5SJoerg Sonnenberger reverse ? "R" : "Unr", 27848d201a5SJoerg Sonnenberger reverse ? "Assuming" : "Ignoring"); 27948d201a5SJoerg Sonnenberger } else { 28048d201a5SJoerg Sonnenberger ask("%seversed (or previously applied) patch detected! %s -R? [y] ", 28148d201a5SJoerg Sonnenberger reverse ? "R" : "Unr", 28248d201a5SJoerg Sonnenberger reverse ? "Assume" : "Ignore"); 28348d201a5SJoerg Sonnenberger if (*buf == 'n') { 28448d201a5SJoerg Sonnenberger ask("Apply anyway? [n] "); 28548d201a5SJoerg Sonnenberger if (*buf != 'y') 28648d201a5SJoerg Sonnenberger skip_rest_of_patch = true; 28748d201a5SJoerg Sonnenberger where = 0; 28848d201a5SJoerg Sonnenberger reverse = !reverse; 28948d201a5SJoerg Sonnenberger if (!pch_swap()) 29048d201a5SJoerg Sonnenberger /* put it back to normal */ 29148d201a5SJoerg Sonnenberger fatal("lost hunk on alloc error!\n"); 29248d201a5SJoerg Sonnenberger } 29348d201a5SJoerg Sonnenberger } 29448d201a5SJoerg Sonnenberger } 29548d201a5SJoerg Sonnenberger } while (!skip_rest_of_patch && where == 0 && 29648d201a5SJoerg Sonnenberger ++fuzz <= mymaxfuzz); 29748d201a5SJoerg Sonnenberger 29848d201a5SJoerg Sonnenberger if (skip_rest_of_patch) { /* just got decided */ 29948d201a5SJoerg Sonnenberger fclose(ofp); 30048d201a5SJoerg Sonnenberger ofp = NULL; 30148d201a5SJoerg Sonnenberger } 30248d201a5SJoerg Sonnenberger } 30348d201a5SJoerg Sonnenberger newwhere = pch_newfirst() + last_offset; 30448d201a5SJoerg Sonnenberger if (skip_rest_of_patch) { 30548d201a5SJoerg Sonnenberger abort_hunk(); 30648d201a5SJoerg Sonnenberger failed++; 30748d201a5SJoerg Sonnenberger if (verbose) 30848d201a5SJoerg Sonnenberger say("Hunk #%d ignored at %ld.\n", 30948d201a5SJoerg Sonnenberger hunk, newwhere); 31048d201a5SJoerg Sonnenberger } else if (where == 0) { 31148d201a5SJoerg Sonnenberger abort_hunk(); 31248d201a5SJoerg Sonnenberger failed++; 31348d201a5SJoerg Sonnenberger if (verbose) 31448d201a5SJoerg Sonnenberger say("Hunk #%d failed at %ld.\n", 31548d201a5SJoerg Sonnenberger hunk, newwhere); 31648d201a5SJoerg Sonnenberger } else { 31748d201a5SJoerg Sonnenberger apply_hunk(where); 31848d201a5SJoerg Sonnenberger if (verbose) { 31948d201a5SJoerg Sonnenberger say("Hunk #%d succeeded at %ld", 32048d201a5SJoerg Sonnenberger hunk, newwhere); 32148d201a5SJoerg Sonnenberger if (fuzz != 0) 32248d201a5SJoerg Sonnenberger say(" with fuzz %ld", fuzz); 32348d201a5SJoerg Sonnenberger if (last_offset) 32448d201a5SJoerg Sonnenberger say(" (offset %ld line%s)", 32548d201a5SJoerg Sonnenberger last_offset, 32648d201a5SJoerg Sonnenberger last_offset == 1L ? "" : "s"); 32748d201a5SJoerg Sonnenberger say(".\n"); 32848d201a5SJoerg Sonnenberger } 32948d201a5SJoerg Sonnenberger } 33048d201a5SJoerg Sonnenberger } 33148d201a5SJoerg Sonnenberger 33248d201a5SJoerg Sonnenberger if (out_of_mem && using_plan_a) { 33348d201a5SJoerg Sonnenberger Argc = Argc_last; 33448d201a5SJoerg Sonnenberger Argv = Argv_last; 33548d201a5SJoerg Sonnenberger say("\n\nRan out of memory using Plan A--trying again...\n\n"); 33648d201a5SJoerg Sonnenberger if (ofp) 33748d201a5SJoerg Sonnenberger fclose(ofp); 33848d201a5SJoerg Sonnenberger ofp = NULL; 33948d201a5SJoerg Sonnenberger if (rejfp) 34048d201a5SJoerg Sonnenberger fclose(rejfp); 34148d201a5SJoerg Sonnenberger rejfp = NULL; 34248d201a5SJoerg Sonnenberger continue; 34348d201a5SJoerg Sonnenberger } 34448d201a5SJoerg Sonnenberger if (hunk == 0) 34548d201a5SJoerg Sonnenberger fatal("Internal error: hunk should not be 0\n"); 34648d201a5SJoerg Sonnenberger 34748d201a5SJoerg Sonnenberger /* finish spewing out the new file */ 34848d201a5SJoerg Sonnenberger if (!skip_rest_of_patch) 34948d201a5SJoerg Sonnenberger spew_output(); 35048d201a5SJoerg Sonnenberger 35148d201a5SJoerg Sonnenberger /* and put the output where desired */ 35248d201a5SJoerg Sonnenberger ignore_signals(); 35348d201a5SJoerg Sonnenberger if (!skip_rest_of_patch) { 35448d201a5SJoerg Sonnenberger struct stat statbuf; 35548d201a5SJoerg Sonnenberger char *realout = outname; 35648d201a5SJoerg Sonnenberger 35748d201a5SJoerg Sonnenberger if (!check_only) { 35848d201a5SJoerg Sonnenberger if (move_file(TMPOUTNAME, outname) < 0) { 35948d201a5SJoerg Sonnenberger toutkeep = true; 36048d201a5SJoerg Sonnenberger realout = TMPOUTNAME; 36148d201a5SJoerg Sonnenberger chmod(TMPOUTNAME, filemode); 36248d201a5SJoerg Sonnenberger } else 36348d201a5SJoerg Sonnenberger chmod(outname, filemode); 36448d201a5SJoerg Sonnenberger 36548d201a5SJoerg Sonnenberger if (remove_empty_files && 36648d201a5SJoerg Sonnenberger stat(realout, &statbuf) == 0 && 36748d201a5SJoerg Sonnenberger statbuf.st_size == 0) { 36848d201a5SJoerg Sonnenberger if (verbose) 36948d201a5SJoerg Sonnenberger say("Removing %s (empty after patching).\n", 37048d201a5SJoerg Sonnenberger realout); 37148d201a5SJoerg Sonnenberger unlink(realout); 37248d201a5SJoerg Sonnenberger } 37348d201a5SJoerg Sonnenberger } 37448d201a5SJoerg Sonnenberger } 37548d201a5SJoerg Sonnenberger fclose(rejfp); 37648d201a5SJoerg Sonnenberger rejfp = NULL; 37748d201a5SJoerg Sonnenberger if (failed) { 37848d201a5SJoerg Sonnenberger error = 1; 37948d201a5SJoerg Sonnenberger if (*rejname == '\0') { 38048d201a5SJoerg Sonnenberger if (strlcpy(rejname, outname, 38148d201a5SJoerg Sonnenberger sizeof(rejname)) >= sizeof(rejname)) 38248d201a5SJoerg Sonnenberger fatal("filename %s is too long\n", outname); 38348d201a5SJoerg Sonnenberger if (strlcat(rejname, REJEXT, 38448d201a5SJoerg Sonnenberger sizeof(rejname)) >= sizeof(rejname)) 38548d201a5SJoerg Sonnenberger fatal("filename %s is too long\n", outname); 38648d201a5SJoerg Sonnenberger } 38748d201a5SJoerg Sonnenberger if (skip_rest_of_patch) { 38848d201a5SJoerg Sonnenberger say("%d out of %d hunks ignored--saving rejects to %s\n", 38948d201a5SJoerg Sonnenberger failed, hunk, rejname); 39048d201a5SJoerg Sonnenberger } else { 39148d201a5SJoerg Sonnenberger say("%d out of %d hunks failed--saving rejects to %s\n", 39248d201a5SJoerg Sonnenberger failed, hunk, rejname); 39348d201a5SJoerg Sonnenberger } 39448d201a5SJoerg Sonnenberger if (!check_only && move_file(TMPREJNAME, rejname) < 0) 39548d201a5SJoerg Sonnenberger trejkeep = true; 39648d201a5SJoerg Sonnenberger } 39748d201a5SJoerg Sonnenberger set_signals(1); 39848d201a5SJoerg Sonnenberger } 39948d201a5SJoerg Sonnenberger my_exit(error); 40048d201a5SJoerg Sonnenberger /* NOTREACHED */ 40148d201a5SJoerg Sonnenberger } 40248d201a5SJoerg Sonnenberger 40348d201a5SJoerg Sonnenberger /* Prepare to find the next patch to do in the patch file. */ 40448d201a5SJoerg Sonnenberger 40548d201a5SJoerg Sonnenberger static void 40648d201a5SJoerg Sonnenberger reinitialize_almost_everything(void) 40748d201a5SJoerg Sonnenberger { 40848d201a5SJoerg Sonnenberger re_patch(); 40948d201a5SJoerg Sonnenberger re_input(); 41048d201a5SJoerg Sonnenberger 41148d201a5SJoerg Sonnenberger input_lines = 0; 41248d201a5SJoerg Sonnenberger last_frozen_line = 0; 41348d201a5SJoerg Sonnenberger 41448d201a5SJoerg Sonnenberger filec = 0; 41548d201a5SJoerg Sonnenberger if (!out_of_mem) { 41648d201a5SJoerg Sonnenberger free(filearg[0]); 41748d201a5SJoerg Sonnenberger filearg[0] = NULL; 41848d201a5SJoerg Sonnenberger } 41948d201a5SJoerg Sonnenberger 42048d201a5SJoerg Sonnenberger free(outname); 42148d201a5SJoerg Sonnenberger outname = NULL; 42248d201a5SJoerg Sonnenberger 42348d201a5SJoerg Sonnenberger last_offset = 0; 42448d201a5SJoerg Sonnenberger diff_type = 0; 42548d201a5SJoerg Sonnenberger 42648d201a5SJoerg Sonnenberger free(revision); 42748d201a5SJoerg Sonnenberger revision = NULL; 42848d201a5SJoerg Sonnenberger 42948d201a5SJoerg Sonnenberger reverse = reverse_flag_specified; 43048d201a5SJoerg Sonnenberger skip_rest_of_patch = false; 43148d201a5SJoerg Sonnenberger 43248d201a5SJoerg Sonnenberger get_some_switches(); 43348d201a5SJoerg Sonnenberger } 43448d201a5SJoerg Sonnenberger 43548d201a5SJoerg Sonnenberger /* Process switches and filenames. */ 43648d201a5SJoerg Sonnenberger 43748d201a5SJoerg Sonnenberger static void 43848d201a5SJoerg Sonnenberger get_some_switches(void) 43948d201a5SJoerg Sonnenberger { 440f7e25d55SSascha Wildner const char *options = "b::B:cCd:D:eEfF:i:lnNo:p:r:RstuvV:x:z:"; 44148d201a5SJoerg Sonnenberger static struct option longopts[] = { 44248d201a5SJoerg Sonnenberger {"backup", no_argument, 0, 'b'}, 44348d201a5SJoerg Sonnenberger {"batch", no_argument, 0, 't'}, 44448d201a5SJoerg Sonnenberger {"check", no_argument, 0, 'C'}, 44548d201a5SJoerg Sonnenberger {"context", no_argument, 0, 'c'}, 44648d201a5SJoerg Sonnenberger {"debug", required_argument, 0, 'x'}, 44748d201a5SJoerg Sonnenberger {"directory", required_argument, 0, 'd'}, 44848d201a5SJoerg Sonnenberger {"ed", no_argument, 0, 'e'}, 44948d201a5SJoerg Sonnenberger {"force", no_argument, 0, 'f'}, 45048d201a5SJoerg Sonnenberger {"forward", no_argument, 0, 'N'}, 45148d201a5SJoerg Sonnenberger {"fuzz", required_argument, 0, 'F'}, 45248d201a5SJoerg Sonnenberger {"ifdef", required_argument, 0, 'D'}, 45348d201a5SJoerg Sonnenberger {"input", required_argument, 0, 'i'}, 45448d201a5SJoerg Sonnenberger {"ignore-whitespace", no_argument, 0, 'l'}, 45548d201a5SJoerg Sonnenberger {"normal", no_argument, 0, 'n'}, 45648d201a5SJoerg Sonnenberger {"output", required_argument, 0, 'o'}, 45748d201a5SJoerg Sonnenberger {"prefix", required_argument, 0, 'B'}, 45848d201a5SJoerg Sonnenberger {"quiet", no_argument, 0, 's'}, 45948d201a5SJoerg Sonnenberger {"reject-file", required_argument, 0, 'r'}, 46048d201a5SJoerg Sonnenberger {"remove-empty-files", no_argument, 0, 'E'}, 46148d201a5SJoerg Sonnenberger {"reverse", no_argument, 0, 'R'}, 46248d201a5SJoerg Sonnenberger {"silent", no_argument, 0, 's'}, 46348d201a5SJoerg Sonnenberger {"strip", required_argument, 0, 'p'}, 46448d201a5SJoerg Sonnenberger {"suffix", required_argument, 0, 'z'}, 46548d201a5SJoerg Sonnenberger {"unified", no_argument, 0, 'u'}, 46648d201a5SJoerg Sonnenberger {"version", no_argument, 0, 'v'}, 46748d201a5SJoerg Sonnenberger {"version-control", required_argument, 0, 'V'}, 46848d201a5SJoerg Sonnenberger {"posix", no_argument, &posix, 1}, 46948d201a5SJoerg Sonnenberger {NULL, 0, 0, 0} 47048d201a5SJoerg Sonnenberger }; 47148d201a5SJoerg Sonnenberger int ch; 47248d201a5SJoerg Sonnenberger 47348d201a5SJoerg Sonnenberger rejname[0] = '\0'; 47448d201a5SJoerg Sonnenberger Argc_last = Argc; 47548d201a5SJoerg Sonnenberger Argv_last = Argv; 47648d201a5SJoerg Sonnenberger if (!Argc) 47748d201a5SJoerg Sonnenberger return; 47848d201a5SJoerg Sonnenberger optreset = optind = 1; 47948d201a5SJoerg Sonnenberger while ((ch = getopt_long(Argc, Argv, options, longopts, NULL)) != -1) { 48048d201a5SJoerg Sonnenberger switch (ch) { 48148d201a5SJoerg Sonnenberger case 'b': 48248d201a5SJoerg Sonnenberger if (backup_type == none) 48348d201a5SJoerg Sonnenberger backup_type = numbered_existing; 48448d201a5SJoerg Sonnenberger if (optarg == NULL) 48548d201a5SJoerg Sonnenberger break; 48648d201a5SJoerg Sonnenberger if (verbose) 48748d201a5SJoerg Sonnenberger say("Warning, the ``-b suffix'' option has been" 48848d201a5SJoerg Sonnenberger " obsoleted by the -z option.\n"); 48948d201a5SJoerg Sonnenberger /* FALLTHROUGH */ 49048d201a5SJoerg Sonnenberger case 'z': 49148d201a5SJoerg Sonnenberger /* must directly follow 'b' case for backwards compat */ 49248d201a5SJoerg Sonnenberger simple_backup_suffix = savestr(optarg); 49348d201a5SJoerg Sonnenberger break; 49448d201a5SJoerg Sonnenberger case 'B': 49548d201a5SJoerg Sonnenberger origprae = savestr(optarg); 49648d201a5SJoerg Sonnenberger break; 49748d201a5SJoerg Sonnenberger case 'c': 49848d201a5SJoerg Sonnenberger diff_type = CONTEXT_DIFF; 49948d201a5SJoerg Sonnenberger break; 50048d201a5SJoerg Sonnenberger case 'C': 50148d201a5SJoerg Sonnenberger check_only = true; 50248d201a5SJoerg Sonnenberger break; 50348d201a5SJoerg Sonnenberger case 'd': 50448d201a5SJoerg Sonnenberger if (chdir(optarg) < 0) 50548d201a5SJoerg Sonnenberger pfatal("can't cd to %s", optarg); 50648d201a5SJoerg Sonnenberger break; 50748d201a5SJoerg Sonnenberger case 'D': 50848d201a5SJoerg Sonnenberger do_defines = true; 509*41871674SJoerg Sonnenberger if (!isalpha((unsigned char)*optarg) && *optarg != '_') 51048d201a5SJoerg Sonnenberger fatal("argument to -D is not an identifier\n"); 51148d201a5SJoerg Sonnenberger snprintf(if_defined, sizeof if_defined, 51248d201a5SJoerg Sonnenberger "#ifdef %s\n", optarg); 51348d201a5SJoerg Sonnenberger snprintf(not_defined, sizeof not_defined, 51448d201a5SJoerg Sonnenberger "#ifndef %s\n", optarg); 51548d201a5SJoerg Sonnenberger snprintf(end_defined, sizeof end_defined, 51648d201a5SJoerg Sonnenberger "#endif /* %s */\n", optarg); 51748d201a5SJoerg Sonnenberger break; 51848d201a5SJoerg Sonnenberger case 'e': 51948d201a5SJoerg Sonnenberger diff_type = ED_DIFF; 52048d201a5SJoerg Sonnenberger break; 52148d201a5SJoerg Sonnenberger case 'E': 52248d201a5SJoerg Sonnenberger remove_empty_files = true; 52348d201a5SJoerg Sonnenberger break; 52448d201a5SJoerg Sonnenberger case 'f': 52548d201a5SJoerg Sonnenberger force = true; 52648d201a5SJoerg Sonnenberger break; 52748d201a5SJoerg Sonnenberger case 'F': 52848d201a5SJoerg Sonnenberger maxfuzz = atoi(optarg); 52948d201a5SJoerg Sonnenberger break; 53048d201a5SJoerg Sonnenberger case 'i': 53148d201a5SJoerg Sonnenberger if (++filec == MAXFILEC) 53248d201a5SJoerg Sonnenberger fatal("too many file arguments\n"); 53348d201a5SJoerg Sonnenberger filearg[filec] = savestr(optarg); 53448d201a5SJoerg Sonnenberger break; 53548d201a5SJoerg Sonnenberger case 'l': 53648d201a5SJoerg Sonnenberger canonicalize = true; 53748d201a5SJoerg Sonnenberger break; 53848d201a5SJoerg Sonnenberger case 'n': 53948d201a5SJoerg Sonnenberger diff_type = NORMAL_DIFF; 54048d201a5SJoerg Sonnenberger break; 54148d201a5SJoerg Sonnenberger case 'N': 54248d201a5SJoerg Sonnenberger noreverse = true; 54348d201a5SJoerg Sonnenberger break; 54448d201a5SJoerg Sonnenberger case 'o': 54548d201a5SJoerg Sonnenberger outname = savestr(optarg); 54648d201a5SJoerg Sonnenberger break; 54748d201a5SJoerg Sonnenberger case 'p': 54848d201a5SJoerg Sonnenberger strippath = atoi(optarg); 54948d201a5SJoerg Sonnenberger break; 55048d201a5SJoerg Sonnenberger case 'r': 55148d201a5SJoerg Sonnenberger if (strlcpy(rejname, optarg, 55248d201a5SJoerg Sonnenberger sizeof(rejname)) >= sizeof(rejname)) 55348d201a5SJoerg Sonnenberger fatal("argument for -r is too long\n"); 55448d201a5SJoerg Sonnenberger break; 55548d201a5SJoerg Sonnenberger case 'R': 55648d201a5SJoerg Sonnenberger reverse = true; 55748d201a5SJoerg Sonnenberger reverse_flag_specified = true; 55848d201a5SJoerg Sonnenberger break; 55948d201a5SJoerg Sonnenberger case 's': 56048d201a5SJoerg Sonnenberger verbose = false; 56148d201a5SJoerg Sonnenberger break; 56248d201a5SJoerg Sonnenberger case 't': 56348d201a5SJoerg Sonnenberger batch = true; 56448d201a5SJoerg Sonnenberger break; 56548d201a5SJoerg Sonnenberger case 'u': 56648d201a5SJoerg Sonnenberger diff_type = UNI_DIFF; 56748d201a5SJoerg Sonnenberger break; 56848d201a5SJoerg Sonnenberger case 'v': 56948d201a5SJoerg Sonnenberger version(); 57048d201a5SJoerg Sonnenberger break; 57148d201a5SJoerg Sonnenberger case 'V': 57248d201a5SJoerg Sonnenberger backup_type = get_version(optarg); 57348d201a5SJoerg Sonnenberger break; 57448d201a5SJoerg Sonnenberger #ifdef DEBUGGING 57548d201a5SJoerg Sonnenberger case 'x': 57648d201a5SJoerg Sonnenberger debug = atoi(optarg); 57748d201a5SJoerg Sonnenberger break; 57848d201a5SJoerg Sonnenberger #endif 57948d201a5SJoerg Sonnenberger default: 58048d201a5SJoerg Sonnenberger if (ch != '\0') 58148d201a5SJoerg Sonnenberger usage(); 58248d201a5SJoerg Sonnenberger break; 58348d201a5SJoerg Sonnenberger } 58448d201a5SJoerg Sonnenberger } 58548d201a5SJoerg Sonnenberger Argc -= optind; 58648d201a5SJoerg Sonnenberger Argv += optind; 58748d201a5SJoerg Sonnenberger 58848d201a5SJoerg Sonnenberger if (Argc > 0) { 58948d201a5SJoerg Sonnenberger filearg[0] = savestr(*Argv++); 59048d201a5SJoerg Sonnenberger Argc--; 59148d201a5SJoerg Sonnenberger while (Argc > 0) { 59248d201a5SJoerg Sonnenberger if (++filec == MAXFILEC) 59348d201a5SJoerg Sonnenberger fatal("too many file arguments\n"); 59448d201a5SJoerg Sonnenberger filearg[filec] = savestr(*Argv++); 59548d201a5SJoerg Sonnenberger Argc--; 59648d201a5SJoerg Sonnenberger } 59748d201a5SJoerg Sonnenberger } 59848d201a5SJoerg Sonnenberger 59948d201a5SJoerg Sonnenberger if (getenv("POSIXLY_CORRECT") != NULL) 60048d201a5SJoerg Sonnenberger posix = 1; 60148d201a5SJoerg Sonnenberger } 60248d201a5SJoerg Sonnenberger 60348d201a5SJoerg Sonnenberger static void 60448d201a5SJoerg Sonnenberger usage(void) 60548d201a5SJoerg Sonnenberger { 60648d201a5SJoerg Sonnenberger fprintf(stderr, 60748d201a5SJoerg Sonnenberger "usage: patch [-bcCeEflnNRstuv] [-B backup-prefix] [-d directory] [-D symbol]\n" 60848d201a5SJoerg Sonnenberger " [-F max-fuzz] [-i patchfile] [-o out-file] [-p strip-count]\n" 60948d201a5SJoerg Sonnenberger " [-r rej-name] [-V {numbered,existing,simple}] [-z backup-ext]\n" 61048d201a5SJoerg Sonnenberger " [origfile [patchfile]]\n"); 61148d201a5SJoerg Sonnenberger my_exit(EXIT_SUCCESS); 61248d201a5SJoerg Sonnenberger } 61348d201a5SJoerg Sonnenberger 61448d201a5SJoerg Sonnenberger /* 61548d201a5SJoerg Sonnenberger * Attempt to find the right place to apply this hunk of patch. 61648d201a5SJoerg Sonnenberger */ 61748d201a5SJoerg Sonnenberger static LINENUM 61848d201a5SJoerg Sonnenberger locate_hunk(LINENUM fuzz) 61948d201a5SJoerg Sonnenberger { 62048d201a5SJoerg Sonnenberger LINENUM first_guess = pch_first() + last_offset; 62148d201a5SJoerg Sonnenberger LINENUM offset; 62248d201a5SJoerg Sonnenberger LINENUM pat_lines = pch_ptrn_lines(); 62348d201a5SJoerg Sonnenberger LINENUM max_pos_offset = input_lines - first_guess - pat_lines + 1; 62448d201a5SJoerg Sonnenberger LINENUM max_neg_offset = first_guess - last_frozen_line - 1 + pch_context(); 62548d201a5SJoerg Sonnenberger 62648d201a5SJoerg Sonnenberger if (pat_lines == 0) { /* null range matches always */ 62748d201a5SJoerg Sonnenberger if (verbose && fuzz == 0 && (diff_type == CONTEXT_DIFF 62848d201a5SJoerg Sonnenberger || diff_type == NEW_CONTEXT_DIFF 62948d201a5SJoerg Sonnenberger || diff_type == UNI_DIFF)) { 63048d201a5SJoerg Sonnenberger say("Empty context always matches.\n"); 63148d201a5SJoerg Sonnenberger } 63248d201a5SJoerg Sonnenberger if (diff_type == CONTEXT_DIFF 63348d201a5SJoerg Sonnenberger || diff_type == NEW_CONTEXT_DIFF 63448d201a5SJoerg Sonnenberger || diff_type == UNI_DIFF) { 63548d201a5SJoerg Sonnenberger if (fuzz == 0) 63648d201a5SJoerg Sonnenberger return (input_lines == 0 ? first_guess : 0); 63748d201a5SJoerg Sonnenberger } else 63848d201a5SJoerg Sonnenberger return (first_guess); 63948d201a5SJoerg Sonnenberger } 64048d201a5SJoerg Sonnenberger if (max_neg_offset >= first_guess) /* do not try lines < 0 */ 64148d201a5SJoerg Sonnenberger max_neg_offset = first_guess - 1; 64248d201a5SJoerg Sonnenberger if (first_guess <= input_lines && patch_match(first_guess, 0, fuzz)) 64348d201a5SJoerg Sonnenberger return first_guess; 64448d201a5SJoerg Sonnenberger for (offset = 1; ; offset++) { 64548d201a5SJoerg Sonnenberger bool check_after = (offset <= max_pos_offset); 64648d201a5SJoerg Sonnenberger bool check_before = (offset <= max_neg_offset); 64748d201a5SJoerg Sonnenberger 64848d201a5SJoerg Sonnenberger if (check_after && patch_match(first_guess, offset, fuzz)) { 64948d201a5SJoerg Sonnenberger #ifdef DEBUGGING 65048d201a5SJoerg Sonnenberger if (debug & 1) 65148d201a5SJoerg Sonnenberger say("Offset changing from %ld to %ld\n", 65248d201a5SJoerg Sonnenberger last_offset, offset); 65348d201a5SJoerg Sonnenberger #endif 65448d201a5SJoerg Sonnenberger last_offset = offset; 65548d201a5SJoerg Sonnenberger return first_guess + offset; 65648d201a5SJoerg Sonnenberger } else if (check_before && patch_match(first_guess, -offset, fuzz)) { 65748d201a5SJoerg Sonnenberger #ifdef DEBUGGING 65848d201a5SJoerg Sonnenberger if (debug & 1) 65948d201a5SJoerg Sonnenberger say("Offset changing from %ld to %ld\n", 66048d201a5SJoerg Sonnenberger last_offset, -offset); 66148d201a5SJoerg Sonnenberger #endif 66248d201a5SJoerg Sonnenberger last_offset = -offset; 66348d201a5SJoerg Sonnenberger return first_guess - offset; 66448d201a5SJoerg Sonnenberger } else if (!check_before && !check_after) 66548d201a5SJoerg Sonnenberger return 0; 66648d201a5SJoerg Sonnenberger } 66748d201a5SJoerg Sonnenberger } 66848d201a5SJoerg Sonnenberger 66948d201a5SJoerg Sonnenberger /* We did not find the pattern, dump out the hunk so they can handle it. */ 67048d201a5SJoerg Sonnenberger 67148d201a5SJoerg Sonnenberger static void 672f7e25d55SSascha Wildner abort_context_hunk(void) 67348d201a5SJoerg Sonnenberger { 67448d201a5SJoerg Sonnenberger LINENUM i; 67548d201a5SJoerg Sonnenberger const LINENUM pat_end = pch_end(); 67648d201a5SJoerg Sonnenberger /* 67748d201a5SJoerg Sonnenberger * add in last_offset to guess the same as the previous successful 67848d201a5SJoerg Sonnenberger * hunk 67948d201a5SJoerg Sonnenberger */ 68048d201a5SJoerg Sonnenberger const LINENUM oldfirst = pch_first() + last_offset; 68148d201a5SJoerg Sonnenberger const LINENUM newfirst = pch_newfirst() + last_offset; 68248d201a5SJoerg Sonnenberger const LINENUM oldlast = oldfirst + pch_ptrn_lines() - 1; 68348d201a5SJoerg Sonnenberger const LINENUM newlast = newfirst + pch_repl_lines() - 1; 68448d201a5SJoerg Sonnenberger const char *stars = (diff_type >= NEW_CONTEXT_DIFF ? " ****" : ""); 68548d201a5SJoerg Sonnenberger const char *minuses = (diff_type >= NEW_CONTEXT_DIFF ? " ----" : " -----"); 68648d201a5SJoerg Sonnenberger 68748d201a5SJoerg Sonnenberger fprintf(rejfp, "***************\n"); 68848d201a5SJoerg Sonnenberger for (i = 0; i <= pat_end; i++) { 68948d201a5SJoerg Sonnenberger switch (pch_char(i)) { 69048d201a5SJoerg Sonnenberger case '*': 69148d201a5SJoerg Sonnenberger if (oldlast < oldfirst) 69248d201a5SJoerg Sonnenberger fprintf(rejfp, "*** 0%s\n", stars); 69348d201a5SJoerg Sonnenberger else if (oldlast == oldfirst) 69448d201a5SJoerg Sonnenberger fprintf(rejfp, "*** %ld%s\n", oldfirst, stars); 69548d201a5SJoerg Sonnenberger else 69648d201a5SJoerg Sonnenberger fprintf(rejfp, "*** %ld,%ld%s\n", oldfirst, 69748d201a5SJoerg Sonnenberger oldlast, stars); 69848d201a5SJoerg Sonnenberger break; 69948d201a5SJoerg Sonnenberger case '=': 70048d201a5SJoerg Sonnenberger if (newlast < newfirst) 70148d201a5SJoerg Sonnenberger fprintf(rejfp, "--- 0%s\n", minuses); 70248d201a5SJoerg Sonnenberger else if (newlast == newfirst) 70348d201a5SJoerg Sonnenberger fprintf(rejfp, "--- %ld%s\n", newfirst, minuses); 70448d201a5SJoerg Sonnenberger else 70548d201a5SJoerg Sonnenberger fprintf(rejfp, "--- %ld,%ld%s\n", newfirst, 70648d201a5SJoerg Sonnenberger newlast, minuses); 70748d201a5SJoerg Sonnenberger break; 70848d201a5SJoerg Sonnenberger case '\n': 70948d201a5SJoerg Sonnenberger fprintf(rejfp, "%s", pfetch(i)); 71048d201a5SJoerg Sonnenberger break; 71148d201a5SJoerg Sonnenberger case ' ': 71248d201a5SJoerg Sonnenberger case '-': 71348d201a5SJoerg Sonnenberger case '+': 71448d201a5SJoerg Sonnenberger case '!': 71548d201a5SJoerg Sonnenberger fprintf(rejfp, "%c %s", pch_char(i), pfetch(i)); 71648d201a5SJoerg Sonnenberger break; 71748d201a5SJoerg Sonnenberger default: 718f7e25d55SSascha Wildner fatal("fatal internal error in abort_context_hunk\n"); 719f7e25d55SSascha Wildner } 720f7e25d55SSascha Wildner } 721f7e25d55SSascha Wildner } 722f7e25d55SSascha Wildner 723f7e25d55SSascha Wildner static void 724f7e25d55SSascha Wildner rej_line(int ch, LINENUM i) 725f7e25d55SSascha Wildner { 726f7e25d55SSascha Wildner size_t len; 727f7e25d55SSascha Wildner const char *line = pfetch(i); 728f7e25d55SSascha Wildner 729f7e25d55SSascha Wildner len = strlen(line); 730f7e25d55SSascha Wildner 731f7e25d55SSascha Wildner fprintf(rejfp, "%c%s", ch, line); 732f7e25d55SSascha Wildner if (len == 0 || line[len-1] != '\n') 733f7e25d55SSascha Wildner fprintf(rejfp, "\n\\ No newline at end of file\n"); 734f7e25d55SSascha Wildner } 735f7e25d55SSascha Wildner 736f7e25d55SSascha Wildner static void 737f7e25d55SSascha Wildner abort_hunk(void) 738f7e25d55SSascha Wildner { 739f7e25d55SSascha Wildner LINENUM i, j, split; 740f7e25d55SSascha Wildner int ch1, ch2; 741f7e25d55SSascha Wildner const LINENUM pat_end = pch_end(); 742f7e25d55SSascha Wildner const LINENUM oldfirst = pch_first() + last_offset; 743f7e25d55SSascha Wildner const LINENUM newfirst = pch_newfirst() + last_offset; 744f7e25d55SSascha Wildner 745f7e25d55SSascha Wildner if (diff_type != UNI_DIFF) { 746f7e25d55SSascha Wildner abort_context_hunk(); 747f7e25d55SSascha Wildner return; 748f7e25d55SSascha Wildner } 749f7e25d55SSascha Wildner split = -1; 750f7e25d55SSascha Wildner for (i = 0; i <= pat_end; i++) { 751f7e25d55SSascha Wildner if (pch_char(i) == '=') { 752f7e25d55SSascha Wildner split = i; 753f7e25d55SSascha Wildner break; 754f7e25d55SSascha Wildner } 755f7e25d55SSascha Wildner } 756f7e25d55SSascha Wildner if (split == -1) { 757f7e25d55SSascha Wildner fprintf(rejfp, "malformed hunk: no split found\n"); 758f7e25d55SSascha Wildner return; 759f7e25d55SSascha Wildner } 760f7e25d55SSascha Wildner i = 0; 761f7e25d55SSascha Wildner j = split + 1; 762f7e25d55SSascha Wildner fprintf(rejfp, "@@ -%ld,%ld +%ld,%ld @@\n", 763f7e25d55SSascha Wildner pch_ptrn_lines() ? oldfirst : 0, 764f7e25d55SSascha Wildner pch_ptrn_lines(), newfirst, pch_repl_lines()); 765f7e25d55SSascha Wildner while (i < split || j <= pat_end) { 766f7e25d55SSascha Wildner ch1 = i < split ? pch_char(i) : -1; 767f7e25d55SSascha Wildner ch2 = j <= pat_end ? pch_char(j) : -1; 768f7e25d55SSascha Wildner if (ch1 == '-') { 769f7e25d55SSascha Wildner rej_line('-', i); 770f7e25d55SSascha Wildner i++; 771f7e25d55SSascha Wildner } else if (ch1 == ' ' && ch2 == ' ') { 772f7e25d55SSascha Wildner rej_line(' ', i); 773f7e25d55SSascha Wildner i++; 774f7e25d55SSascha Wildner j++; 775f7e25d55SSascha Wildner } else if (ch1 == '!' && ch2 == '!') { 776f7e25d55SSascha Wildner while (i < split && ch1 == '!') { 777f7e25d55SSascha Wildner rej_line('-', i); 778f7e25d55SSascha Wildner i++; 779f7e25d55SSascha Wildner ch1 = i < split ? pch_char(i) : -1; 780f7e25d55SSascha Wildner } 781f7e25d55SSascha Wildner while (j <= pat_end && ch2 == '!') { 782f7e25d55SSascha Wildner rej_line('+', j); 783f7e25d55SSascha Wildner j++; 784f7e25d55SSascha Wildner ch2 = j <= pat_end ? pch_char(j) : -1; 785f7e25d55SSascha Wildner } 786f7e25d55SSascha Wildner } else if (ch1 == '*') { 787f7e25d55SSascha Wildner i++; 788f7e25d55SSascha Wildner } else if (ch2 == '+' || ch2 == ' ') { 789f7e25d55SSascha Wildner rej_line(ch2, j); 790f7e25d55SSascha Wildner j++; 791f7e25d55SSascha Wildner } else { 792f7e25d55SSascha Wildner fprintf(rejfp, "internal error on (%ld %ld %ld)\n", 793f7e25d55SSascha Wildner i, split, j); 794f7e25d55SSascha Wildner rej_line(ch1, i); 795f7e25d55SSascha Wildner rej_line(ch2, j); 796f7e25d55SSascha Wildner return; 79748d201a5SJoerg Sonnenberger } 79848d201a5SJoerg Sonnenberger } 79948d201a5SJoerg Sonnenberger } 80048d201a5SJoerg Sonnenberger 80148d201a5SJoerg Sonnenberger /* We found where to apply it (we hope), so do it. */ 80248d201a5SJoerg Sonnenberger 80348d201a5SJoerg Sonnenberger static void 80448d201a5SJoerg Sonnenberger apply_hunk(LINENUM where) 80548d201a5SJoerg Sonnenberger { 80648d201a5SJoerg Sonnenberger LINENUM old = 1; 80748d201a5SJoerg Sonnenberger const LINENUM lastline = pch_ptrn_lines(); 80848d201a5SJoerg Sonnenberger LINENUM new = lastline + 1; 80948d201a5SJoerg Sonnenberger #define OUTSIDE 0 81048d201a5SJoerg Sonnenberger #define IN_IFNDEF 1 81148d201a5SJoerg Sonnenberger #define IN_IFDEF 2 81248d201a5SJoerg Sonnenberger #define IN_ELSE 3 81348d201a5SJoerg Sonnenberger int def_state = OUTSIDE; 81448d201a5SJoerg Sonnenberger const LINENUM pat_end = pch_end(); 81548d201a5SJoerg Sonnenberger 81648d201a5SJoerg Sonnenberger where--; 81748d201a5SJoerg Sonnenberger while (pch_char(new) == '=' || pch_char(new) == '\n') 81848d201a5SJoerg Sonnenberger new++; 81948d201a5SJoerg Sonnenberger 82048d201a5SJoerg Sonnenberger while (old <= lastline) { 82148d201a5SJoerg Sonnenberger if (pch_char(old) == '-') { 82248d201a5SJoerg Sonnenberger copy_till(where + old - 1, false); 82348d201a5SJoerg Sonnenberger if (do_defines) { 82448d201a5SJoerg Sonnenberger if (def_state == OUTSIDE) { 82548d201a5SJoerg Sonnenberger fputs(not_defined, ofp); 82648d201a5SJoerg Sonnenberger def_state = IN_IFNDEF; 82748d201a5SJoerg Sonnenberger } else if (def_state == IN_IFDEF) { 82848d201a5SJoerg Sonnenberger fputs(else_defined, ofp); 82948d201a5SJoerg Sonnenberger def_state = IN_ELSE; 83048d201a5SJoerg Sonnenberger } 83148d201a5SJoerg Sonnenberger fputs(pfetch(old), ofp); 83248d201a5SJoerg Sonnenberger } 83348d201a5SJoerg Sonnenberger last_frozen_line++; 83448d201a5SJoerg Sonnenberger old++; 83548d201a5SJoerg Sonnenberger } else if (new > pat_end) { 83648d201a5SJoerg Sonnenberger break; 83748d201a5SJoerg Sonnenberger } else if (pch_char(new) == '+') { 83848d201a5SJoerg Sonnenberger copy_till(where + old - 1, false); 83948d201a5SJoerg Sonnenberger if (do_defines) { 84048d201a5SJoerg Sonnenberger if (def_state == IN_IFNDEF) { 84148d201a5SJoerg Sonnenberger fputs(else_defined, ofp); 84248d201a5SJoerg Sonnenberger def_state = IN_ELSE; 84348d201a5SJoerg Sonnenberger } else if (def_state == OUTSIDE) { 84448d201a5SJoerg Sonnenberger fputs(if_defined, ofp); 84548d201a5SJoerg Sonnenberger def_state = IN_IFDEF; 84648d201a5SJoerg Sonnenberger } 84748d201a5SJoerg Sonnenberger } 84848d201a5SJoerg Sonnenberger fputs(pfetch(new), ofp); 84948d201a5SJoerg Sonnenberger new++; 85048d201a5SJoerg Sonnenberger } else if (pch_char(new) != pch_char(old)) { 85148d201a5SJoerg Sonnenberger say("Out-of-sync patch, lines %ld,%ld--mangled text or line numbers, maybe?\n", 85248d201a5SJoerg Sonnenberger pch_hunk_beg() + old, 85348d201a5SJoerg Sonnenberger pch_hunk_beg() + new); 85448d201a5SJoerg Sonnenberger #ifdef DEBUGGING 85548d201a5SJoerg Sonnenberger say("oldchar = '%c', newchar = '%c'\n", 85648d201a5SJoerg Sonnenberger pch_char(old), pch_char(new)); 85748d201a5SJoerg Sonnenberger #endif 85848d201a5SJoerg Sonnenberger my_exit(2); 85948d201a5SJoerg Sonnenberger } else if (pch_char(new) == '!') { 86048d201a5SJoerg Sonnenberger copy_till(where + old - 1, false); 86148d201a5SJoerg Sonnenberger if (do_defines) { 86248d201a5SJoerg Sonnenberger fputs(not_defined, ofp); 86348d201a5SJoerg Sonnenberger def_state = IN_IFNDEF; 86448d201a5SJoerg Sonnenberger } 86548d201a5SJoerg Sonnenberger while (pch_char(old) == '!') { 86648d201a5SJoerg Sonnenberger if (do_defines) { 86748d201a5SJoerg Sonnenberger fputs(pfetch(old), ofp); 86848d201a5SJoerg Sonnenberger } 86948d201a5SJoerg Sonnenberger last_frozen_line++; 87048d201a5SJoerg Sonnenberger old++; 87148d201a5SJoerg Sonnenberger } 87248d201a5SJoerg Sonnenberger if (do_defines) { 87348d201a5SJoerg Sonnenberger fputs(else_defined, ofp); 87448d201a5SJoerg Sonnenberger def_state = IN_ELSE; 87548d201a5SJoerg Sonnenberger } 87648d201a5SJoerg Sonnenberger while (pch_char(new) == '!') { 87748d201a5SJoerg Sonnenberger fputs(pfetch(new), ofp); 87848d201a5SJoerg Sonnenberger new++; 87948d201a5SJoerg Sonnenberger } 88048d201a5SJoerg Sonnenberger } else { 88148d201a5SJoerg Sonnenberger if (pch_char(new) != ' ') 88248d201a5SJoerg Sonnenberger fatal("Internal error: expected ' '\n"); 88348d201a5SJoerg Sonnenberger old++; 88448d201a5SJoerg Sonnenberger new++; 88548d201a5SJoerg Sonnenberger if (do_defines && def_state != OUTSIDE) { 88648d201a5SJoerg Sonnenberger fputs(end_defined, ofp); 88748d201a5SJoerg Sonnenberger def_state = OUTSIDE; 88848d201a5SJoerg Sonnenberger } 88948d201a5SJoerg Sonnenberger } 89048d201a5SJoerg Sonnenberger } 89148d201a5SJoerg Sonnenberger if (new <= pat_end && pch_char(new) == '+') { 89248d201a5SJoerg Sonnenberger copy_till(where + old - 1, false); 89348d201a5SJoerg Sonnenberger if (do_defines) { 89448d201a5SJoerg Sonnenberger if (def_state == OUTSIDE) { 89548d201a5SJoerg Sonnenberger fputs(if_defined, ofp); 89648d201a5SJoerg Sonnenberger def_state = IN_IFDEF; 89748d201a5SJoerg Sonnenberger } else if (def_state == IN_IFNDEF) { 89848d201a5SJoerg Sonnenberger fputs(else_defined, ofp); 89948d201a5SJoerg Sonnenberger def_state = IN_ELSE; 90048d201a5SJoerg Sonnenberger } 90148d201a5SJoerg Sonnenberger } 90248d201a5SJoerg Sonnenberger while (new <= pat_end && pch_char(new) == '+') { 90348d201a5SJoerg Sonnenberger fputs(pfetch(new), ofp); 90448d201a5SJoerg Sonnenberger new++; 90548d201a5SJoerg Sonnenberger } 90648d201a5SJoerg Sonnenberger } 90748d201a5SJoerg Sonnenberger if (do_defines && def_state != OUTSIDE) { 90848d201a5SJoerg Sonnenberger fputs(end_defined, ofp); 90948d201a5SJoerg Sonnenberger } 91048d201a5SJoerg Sonnenberger } 91148d201a5SJoerg Sonnenberger 91248d201a5SJoerg Sonnenberger /* 91348d201a5SJoerg Sonnenberger * Open the new file. 91448d201a5SJoerg Sonnenberger */ 91548d201a5SJoerg Sonnenberger static void 91648d201a5SJoerg Sonnenberger init_output(const char *name) 91748d201a5SJoerg Sonnenberger { 91848d201a5SJoerg Sonnenberger ofp = fopen(name, "w"); 91948d201a5SJoerg Sonnenberger if (ofp == NULL) 92048d201a5SJoerg Sonnenberger pfatal("can't create %s", name); 92148d201a5SJoerg Sonnenberger } 92248d201a5SJoerg Sonnenberger 92348d201a5SJoerg Sonnenberger /* 92448d201a5SJoerg Sonnenberger * Open a file to put hunks we can't locate. 92548d201a5SJoerg Sonnenberger */ 92648d201a5SJoerg Sonnenberger static void 92748d201a5SJoerg Sonnenberger init_reject(const char *name) 92848d201a5SJoerg Sonnenberger { 92948d201a5SJoerg Sonnenberger rejfp = fopen(name, "w"); 93048d201a5SJoerg Sonnenberger if (rejfp == NULL) 93148d201a5SJoerg Sonnenberger pfatal("can't create %s", name); 93248d201a5SJoerg Sonnenberger } 93348d201a5SJoerg Sonnenberger 93448d201a5SJoerg Sonnenberger /* 93548d201a5SJoerg Sonnenberger * Copy input file to output, up to wherever hunk is to be applied. 93648d201a5SJoerg Sonnenberger * If endoffile is true, treat the last line specially since it may 93748d201a5SJoerg Sonnenberger * lack a newline. 93848d201a5SJoerg Sonnenberger */ 93948d201a5SJoerg Sonnenberger static void 94048d201a5SJoerg Sonnenberger copy_till(LINENUM lastline, bool endoffile) 94148d201a5SJoerg Sonnenberger { 94248d201a5SJoerg Sonnenberger if (last_frozen_line > lastline) 94348d201a5SJoerg Sonnenberger fatal("misordered hunks! output would be garbled\n"); 94448d201a5SJoerg Sonnenberger while (last_frozen_line < lastline) { 94548d201a5SJoerg Sonnenberger if (++last_frozen_line == lastline && endoffile) 94648d201a5SJoerg Sonnenberger dump_line(last_frozen_line, !last_line_missing_eol); 94748d201a5SJoerg Sonnenberger else 94848d201a5SJoerg Sonnenberger dump_line(last_frozen_line, true); 94948d201a5SJoerg Sonnenberger } 95048d201a5SJoerg Sonnenberger } 95148d201a5SJoerg Sonnenberger 95248d201a5SJoerg Sonnenberger /* 95348d201a5SJoerg Sonnenberger * Finish copying the input file to the output file. 95448d201a5SJoerg Sonnenberger */ 95548d201a5SJoerg Sonnenberger static void 95648d201a5SJoerg Sonnenberger spew_output(void) 95748d201a5SJoerg Sonnenberger { 95848d201a5SJoerg Sonnenberger #ifdef DEBUGGING 95948d201a5SJoerg Sonnenberger if (debug & 256) 96048d201a5SJoerg Sonnenberger say("il=%ld lfl=%ld\n", input_lines, last_frozen_line); 96148d201a5SJoerg Sonnenberger #endif 96248d201a5SJoerg Sonnenberger if (input_lines) 96348d201a5SJoerg Sonnenberger copy_till(input_lines, true); /* dump remainder of file */ 96448d201a5SJoerg Sonnenberger fclose(ofp); 96548d201a5SJoerg Sonnenberger ofp = NULL; 96648d201a5SJoerg Sonnenberger } 96748d201a5SJoerg Sonnenberger 96848d201a5SJoerg Sonnenberger /* 96948d201a5SJoerg Sonnenberger * Copy one line from input to output. 97048d201a5SJoerg Sonnenberger */ 97148d201a5SJoerg Sonnenberger static void 97248d201a5SJoerg Sonnenberger dump_line(LINENUM line, bool write_newline) 97348d201a5SJoerg Sonnenberger { 97448d201a5SJoerg Sonnenberger char *s; 97548d201a5SJoerg Sonnenberger 97648d201a5SJoerg Sonnenberger s = ifetch(line, 0); 97748d201a5SJoerg Sonnenberger if (s == NULL) 97848d201a5SJoerg Sonnenberger return; 97948d201a5SJoerg Sonnenberger /* Note: string is not NUL terminated. */ 98048d201a5SJoerg Sonnenberger for (; *s != '\n'; s++) 98148d201a5SJoerg Sonnenberger putc(*s, ofp); 98248d201a5SJoerg Sonnenberger if (write_newline) 98348d201a5SJoerg Sonnenberger putc('\n', ofp); 98448d201a5SJoerg Sonnenberger } 98548d201a5SJoerg Sonnenberger 98648d201a5SJoerg Sonnenberger /* 98748d201a5SJoerg Sonnenberger * Does the patch pattern match at line base+offset? 98848d201a5SJoerg Sonnenberger */ 98948d201a5SJoerg Sonnenberger static bool 99048d201a5SJoerg Sonnenberger patch_match(LINENUM base, LINENUM offset, LINENUM fuzz) 99148d201a5SJoerg Sonnenberger { 99248d201a5SJoerg Sonnenberger LINENUM pline = 1 + fuzz; 99348d201a5SJoerg Sonnenberger LINENUM iline; 99448d201a5SJoerg Sonnenberger LINENUM pat_lines = pch_ptrn_lines() - fuzz; 99548d201a5SJoerg Sonnenberger const char *ilineptr; 99648d201a5SJoerg Sonnenberger const char *plineptr; 99748d201a5SJoerg Sonnenberger short plinelen; 99848d201a5SJoerg Sonnenberger 99948d201a5SJoerg Sonnenberger for (iline = base + offset + fuzz; pline <= pat_lines; pline++, iline++) { 100048d201a5SJoerg Sonnenberger ilineptr = ifetch(iline, offset >= 0); 100148d201a5SJoerg Sonnenberger if (ilineptr == NULL) 100248d201a5SJoerg Sonnenberger return false; 100348d201a5SJoerg Sonnenberger plineptr = pfetch(pline); 100448d201a5SJoerg Sonnenberger plinelen = pch_line_len(pline); 100548d201a5SJoerg Sonnenberger if (canonicalize) { 100648d201a5SJoerg Sonnenberger if (!similar(ilineptr, plineptr, plinelen)) 100748d201a5SJoerg Sonnenberger return false; 100848d201a5SJoerg Sonnenberger } else if (strnNE(ilineptr, plineptr, plinelen)) 100948d201a5SJoerg Sonnenberger return false; 101048d201a5SJoerg Sonnenberger if (iline == input_lines) { 101148d201a5SJoerg Sonnenberger /* 101248d201a5SJoerg Sonnenberger * We are looking at the last line of the file. 101348d201a5SJoerg Sonnenberger * If the file has no eol, the patch line should 101448d201a5SJoerg Sonnenberger * not have one either and vice-versa. Note that 101548d201a5SJoerg Sonnenberger * plinelen > 0. 101648d201a5SJoerg Sonnenberger */ 101748d201a5SJoerg Sonnenberger if (last_line_missing_eol) { 101848d201a5SJoerg Sonnenberger if (plineptr[plinelen - 1] == '\n') 101948d201a5SJoerg Sonnenberger return false; 102048d201a5SJoerg Sonnenberger } else { 102148d201a5SJoerg Sonnenberger if (plineptr[plinelen - 1] != '\n') 102248d201a5SJoerg Sonnenberger return false; 102348d201a5SJoerg Sonnenberger } 102448d201a5SJoerg Sonnenberger } 102548d201a5SJoerg Sonnenberger } 102648d201a5SJoerg Sonnenberger return true; 102748d201a5SJoerg Sonnenberger } 102848d201a5SJoerg Sonnenberger 102948d201a5SJoerg Sonnenberger /* 103048d201a5SJoerg Sonnenberger * Do two lines match with canonicalized white space? 103148d201a5SJoerg Sonnenberger */ 103248d201a5SJoerg Sonnenberger static bool 103348d201a5SJoerg Sonnenberger similar(const char *a, const char *b, int len) 103448d201a5SJoerg Sonnenberger { 103548d201a5SJoerg Sonnenberger while (len) { 1036*41871674SJoerg Sonnenberger if (isspace((unsigned char)*b)) { /* whitespace (or \n) to match? */ 1037*41871674SJoerg Sonnenberger if (!isspace((unsigned char)*a)) /* no corresponding whitespace? */ 103848d201a5SJoerg Sonnenberger return false; 1039*41871674SJoerg Sonnenberger while (len && isspace((unsigned char)*b) && *b != '\n') 104048d201a5SJoerg Sonnenberger b++, len--; /* skip pattern whitespace */ 1041*41871674SJoerg Sonnenberger while (isspace((unsigned char)*a) && *a != '\n') 104248d201a5SJoerg Sonnenberger a++; /* skip target whitespace */ 104348d201a5SJoerg Sonnenberger if (*a == '\n' || *b == '\n') 104448d201a5SJoerg Sonnenberger return (*a == *b); /* should end in sync */ 104548d201a5SJoerg Sonnenberger } else if (*a++ != *b++) /* match non-whitespace chars */ 104648d201a5SJoerg Sonnenberger return false; 104748d201a5SJoerg Sonnenberger else 104848d201a5SJoerg Sonnenberger len--; /* probably not necessary */ 104948d201a5SJoerg Sonnenberger } 105048d201a5SJoerg Sonnenberger return true; /* actually, this is not reached */ 105148d201a5SJoerg Sonnenberger /* since there is always a \n */ 105248d201a5SJoerg Sonnenberger } 1053