Index: usr.bin/patch/Makefile =================================================================== --- usr.bin/patch/Makefile +++ usr.bin/patch/Makefile @@ -3,6 +3,6 @@ PROG= patch -SRCS= backupfile.c inp.c mkpath.c patch.c pch.c util.c +SRCS= backupfile.c ed.c inp.c mkpath.c patch.c pch.c util.c .include Index: usr.bin/patch/backupfile.c =================================================================== --- usr.bin/patch/backupfile.c +++ usr.bin/patch/backupfile.c @@ -1,3 +1,5 @@ +/* $OpenBSD: backupfile.c,v 1.21 2013/11/26 13:19:07 deraadt Exp $ */ + /*- * Copyright (C) 1990 Free Software Foundation, Inc. * @@ -12,7 +14,6 @@ * * David MacKenzie . Some algorithms adapted from GNU Emacs. * - * $OpenBSD: backupfile.c,v 1.20 2009/10/27 23:59:41 deraadt Exp $ * $FreeBSD$ */ @@ -143,8 +144,9 @@ const char *p; version = 0; - if (!strncmp(base, backup, base_length) && ISDIGIT(backup[base_length])) { - for (p = &backup[base_length]; ISDIGIT(*p); ++p) + if (!strncmp(base, backup, base_length) && + ISDIGIT((unsigned char)backup[base_length])) { + for (p = &backup[base_length]; ISDIGIT((unsigned char)*p); ++p) version = version * 10 + *p - '0'; if (p[0] != '~' || p[1]) version = 0; Index: usr.bin/patch/common.h =================================================================== --- usr.bin/patch/common.h +++ usr.bin/patch/common.h @@ -1,3 +1,5 @@ +/* $OpenBSD: common.h,v 1.29 2015/07/26 14:32:19 millert Exp $ */ + /*- * Copyright 1986, Larry Wall * @@ -23,12 +25,12 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: common.h,v 1.26 2006/03/11 19:41:30 otto Exp $ * $FreeBSD$ */ #include +#include #include #include Index: usr.bin/patch/ed.h =================================================================== --- /dev/null +++ usr.bin/patch/ed.h @@ -0,0 +1,21 @@ +/* $OpenBSD: ed.h,v 1.1 2015/10/16 07:33:47 tobias Exp $ */ + +/* + * Copyright (c) 2015 Tobias Stoeckmann + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +void do_ed_script(void); Index: usr.bin/patch/ed.c =================================================================== --- /dev/null +++ usr.bin/patch/ed.c @@ -0,0 +1,339 @@ +/* $OpenBSD: ed.c,v 1.3 2016/09/02 21:39:51 tobias Exp $ */ + +/* + * Copyright (c) 2015 Tobias Stoeckmann + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + */ + +#include +#include + +#include +#include +#include +#include + +#include "common.h" +#include "ed.h" +#include "util.h" +#include "pch.h" +#include "inp.h" + +/* states of finite state machine */ +#define FSM_CMD 1 +#define FSM_A 2 +#define FSM_C 3 +#define FSM_D 4 +#define FSM_I 5 +#define FSM_S 6 + +#define SRC_INP 1 /* line's origin is input file */ +#define SRC_PCH 2 /* line's origin is patch file */ + +#define S_PATTERN "/.//" + +static void init_lines(void); +static void free_lines(void); +static struct ed_line *get_line(LINENUM); +static struct ed_line *create_line(off_t); +static int valid_addr(LINENUM, LINENUM); +static int get_command(void); +static void write_lines(char *); + +static LIST_HEAD(ed_head, ed_line) head; +struct ed_line { + LIST_ENTRY(ed_line) entries; + int src; + unsigned long subst; + union { + LINENUM lineno; + off_t seek; + } pos; +}; + +static LINENUM first_addr; +static LINENUM second_addr; +static LINENUM line_count; +static struct ed_line *cline; /* current line */ + +void +do_ed_script(void) +{ + off_t linepos; + struct ed_line *nline; + LINENUM i, range; + int fsm; + + init_lines(); + cline = NULL; + fsm = FSM_CMD; + + for (;;) { + linepos = ftello(pfp); + if (pgets(buf, sizeof buf, pfp) == NULL) + break; + p_input_line++; + + if (fsm == FSM_CMD) { + if ((fsm = get_command()) == -1) + break; + + switch (fsm) { + case FSM_C: + case FSM_D: + /* delete lines in specified range */ + if (second_addr == -1) + range = 1; + else + range = second_addr - first_addr + 1; + for (i = 0; i < range; i++) { + nline = LIST_NEXT(cline, entries); + LIST_REMOVE(cline, entries); + free(cline); + cline = nline; + line_count--; + } + cline = get_line(first_addr - 1); + fsm = (fsm == FSM_C) ? FSM_A : FSM_CMD; + break; + case FSM_S: + cline->subst++; + fsm = FSM_CMD; + break; + default: + break; + } + + continue; + } + + if (strcmp(buf, ".\n") == 0) { + fsm = FSM_CMD; + continue; + } + + nline = create_line(linepos); + if (cline == NULL) + LIST_INSERT_HEAD(&head, nline, entries); + else if (fsm == FSM_A) + LIST_INSERT_AFTER(cline, nline, entries); + else + LIST_INSERT_BEFORE(cline, nline, entries); + cline = nline; + line_count++; + fsm = FSM_A; + } + + next_intuit_at(linepos, p_input_line); + + if (skip_rest_of_patch) { + free_lines(); + return; + } + + write_lines(TMPOUTNAME); + free_lines(); + + ignore_signals(); + if (!check_only) { + if (move_file(TMPOUTNAME, outname) < 0) { + toutkeep = true; + chmod(TMPOUTNAME, filemode); + } else + chmod(outname, filemode); + } + set_signals(1); +} + +static int +get_command(void) +{ + char *p; + LINENUM min_addr; + int fsm; + + min_addr = 0; + fsm = -1; + p = buf; + + /* maybe garbage encountered at end of patch */ + if (!isdigit((unsigned char)*p)) + return -1; + + first_addr = strtolinenum(buf, &p); + second_addr = (*p == ',') ? strtolinenum(p + 1, &p) : -1; + + switch (*p++) { + case 'a': + if (second_addr != -1) + fatal("invalid address at line %ld: %s", + p_input_line, buf); + fsm = FSM_A; + break; + case 'c': + fsm = FSM_C; + min_addr = 1; + break; + case 'd': + fsm = FSM_D; + min_addr = 1; + break; + case 'i': + if (second_addr != -1) + fatal("invalid address at line %ld: %s", + p_input_line, buf); + fsm = FSM_I; + break; + case 's': + if (second_addr != -1) + fatal("unsupported address range at line %ld: %s", + p_input_line, buf); + if (strncmp(p, S_PATTERN, sizeof(S_PATTERN) - 1) != 0) + fatal("unsupported substitution at " + "line %ld: %s", p_input_line, buf); + p += sizeof(S_PATTERN) - 1; + fsm = FSM_S; + min_addr = 1; + break; + default: + return -1; + /* NOTREACHED */ + } + + if (*p != '\n') + return -1; + + if (!valid_addr(first_addr, min_addr) || + (second_addr != -1 && !valid_addr(second_addr, first_addr))) + fatal("invalid address at line %ld: %s", p_input_line, buf); + + cline = get_line(first_addr); + + return fsm; +} + +static void +write_lines(char *filename) +{ + FILE *ofp; + char *p; + struct ed_line *line; + off_t linepos; + + linepos = ftello(pfp); + ofp = fopen(filename, "w"); + if (ofp == NULL) + pfatal("can't create %s", filename); + + LIST_FOREACH(line, &head, entries) { + if (line->src == SRC_INP) { + p = ifetch(line->pos.lineno, 0); + /* Note: string is not NUL terminated. */ + for (; *p != '\n'; p++) + if (line->subst != 0) + line->subst--; + else + putc(*p, ofp); + putc('\n', ofp); + } else if (line->src == SRC_PCH) { + fseeko(pfp, line->pos.seek, SEEK_SET); + if (pgets(buf, sizeof buf, pfp) == NULL) + fatal("unexpected end of file"); + p = buf; + if (line->subst != 0) + for (; *p != '\0' && *p != '\n'; p++) + if (line->subst-- == 0) + break; + fputs(p, ofp); + if (strchr(p, '\n') == NULL) + putc('\n', ofp); + } + } + fclose(ofp); + + /* restore patch file position to match p_input_line */ + fseeko(pfp, linepos, SEEK_SET); +} + +/* initialize list with input file */ +static void +init_lines(void) +{ + struct ed_line *line; + LINENUM i; + + LIST_INIT(&head); + for (i = input_lines; i > 0; i--) { + line = malloc(sizeof(*line)); + if (line == NULL) + fatal("cannot allocate memory"); + line->src = SRC_INP; + line->subst = 0; + line->pos.lineno = i; + LIST_INSERT_HEAD(&head, line, entries); + } + line_count = input_lines; +} + +static void +free_lines(void) +{ + struct ed_line *line; + + while (!LIST_EMPTY(&head)) { + line = LIST_FIRST(&head); + LIST_REMOVE(line, entries); + free(line); + } +} + +static struct ed_line * +get_line(LINENUM lineno) +{ + struct ed_line *line; + LINENUM i; + + if (lineno == 0) + return NULL; + + i = 0; + LIST_FOREACH(line, &head, entries) + if (++i == lineno) + return line; + + return NULL; +} + +static struct ed_line * +create_line(off_t seek) +{ + struct ed_line *line; + + line = malloc(sizeof(*line)); + if (line == NULL) + fatal("cannot allocate memory"); + line->src = SRC_PCH; + line->subst = 0; + line->pos.seek = seek; + + return line; +} + +static int +valid_addr(LINENUM lineno, LINENUM min) +{ + return lineno >= min && lineno <= line_count; +} Index: usr.bin/patch/inp.c =================================================================== --- usr.bin/patch/inp.c +++ usr.bin/patch/inp.c @@ -1,3 +1,5 @@ +/* $OpenBSD: inp.c,v 1.47 2017/03/25 23:13:45 deraadt Exp $ */ + /*- * Copyright 1986, Larry Wall * @@ -23,7 +25,6 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: inp.c,v 1.44 2015/07/26 14:32:19 millert Exp $ * $FreeBSD$ */ @@ -112,22 +113,22 @@ } static bool -reallocate_lines(size_t *lines_allocated) +reallocate_lines(size_t *lines_allocatedp) { char **p; size_t new_size; - new_size = *lines_allocated * 3 / 2; + new_size = *lines_allocatedp * 3 / 2; p = reallocarray(i_ptr, new_size + 2, sizeof(char *)); if (p == NULL) { /* shucks, it was a near thing */ munmap(i_womp, i_size); i_womp = NULL; free(i_ptr); i_ptr = NULL; - *lines_allocated = 0; + *lines_allocatedp = 0; return false; } - *lines_allocated = new_size; + *lines_allocatedp = new_size; i_ptr = p; return true; } @@ -154,6 +155,8 @@ statfailed = stat(filename, &filestat); if (statfailed && ok_to_create_file) { + int fd; + if (verbose) say("(Creating file %s...)\n", filename); @@ -165,7 +168,9 @@ if (check_only) return true; makedirs(filename, true); - close(creat(filename, 0666)); + if ((fd = open(filename, O_CREAT | O_TRUNC | O_WRONLY, 0666)) != -1) + close(fd); + statfailed = stat(filename, &filestat); } if (statfailed) Index: usr.bin/patch/mkpath.c =================================================================== --- usr.bin/patch/mkpath.c +++ usr.bin/patch/mkpath.c @@ -1,3 +1,4 @@ +/* $OpenBSD: mkpath.c,v 1.4 2014/05/20 01:25:23 guenther Exp $ */ /*- * Copyright (c) 1983, 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -26,7 +27,6 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * - * $OpenBSD: mkpath.c,v 1.2 2005/06/20 07:14:06 otto Exp $ * $FreeBSD$ */ @@ -36,7 +36,8 @@ #include #include -int mkpath(char *); +#include "common.h" +#include "util.h" /* Code taken directly from mkdir(1). @@ -66,7 +67,7 @@ return (-1); } } else if (!S_ISDIR(sb.st_mode)) { - warnx("%s: %s", path, strerror(ENOTDIR)); + warnc(ENOTDIR, "%s", path); return (-1); } Index: usr.bin/patch/patch.c =================================================================== --- usr.bin/patch/patch.c +++ usr.bin/patch/patch.c @@ -1,3 +1,5 @@ +/* $OpenBSD: patch.c,v 1.63 2016/01/04 14:09:46 gsoares Exp $ */ + /*- * Copyright 1986, Larry Wall * @@ -23,7 +25,6 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: patch.c,v 1.54 2014/12/13 10:31:07 tobias Exp $ * $FreeBSD$ * */ @@ -45,6 +46,7 @@ #include "inp.h" #include "backupfile.h" #include "pathnames.h" +#include "ed.h" mode_t filemode = 0644; @@ -152,6 +154,13 @@ const char *tmpdir; char *v; +#ifdef pledge + if (pledge("stdio rpath wpath cpath tmppath fattr", NULL) == -1) { + perror("pledge"); + my_exit(2); + } +#endif + setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stderr, NULL, _IOLBF, 0); for (i = 0; i < MAXFILEC; i++) @@ -225,11 +234,6 @@ if (outname == NULL) outname = xstrdup(filearg[0]); - /* for ed script just up and do it and exit */ - if (diff_type == ED_DIFF) { - do_ed_script(); - continue; - } /* initialize the patched file */ if (!skip_rest_of_patch) init_output(TMPOUTNAME); @@ -241,8 +245,14 @@ if (!skip_rest_of_patch) scan_input(filearg[0]); + /* for ed script just up and do it and exit */ + if (diff_type == ED_DIFF) { + do_ed_script(); + continue; + } + /* - * from here on, open no standard i/o files, because + * From here on, open no standard I/O files, because * malloc might misfire and we can't catch it easily */ Index: usr.bin/patch/pch.h =================================================================== --- usr.bin/patch/pch.h +++ usr.bin/patch/pch.h @@ -1,3 +1,5 @@ +/* $OpenBSD: pch.h,v 1.10 2015/10/16 07:33:47 tobias Exp $ */ + /*- * Copyright 1986, Larry Wall * @@ -23,7 +25,6 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: pch.h,v 1.9 2003/10/31 20:20:45 millert Exp $ * $FreeBSD$ */ @@ -53,4 +54,11 @@ LINENUM pch_context(void); LINENUM pch_hunk_beg(void); char pch_char(LINENUM); -void do_ed_script(void); + +void next_intuit_at(off_t, LINENUM); +LINENUM strtolinenum(char *, char **); + +extern FILE *pfp; +extern LINENUM p_input_line; +char *pgets(char *, int, FILE *); + Index: usr.bin/patch/pch.c =================================================================== --- usr.bin/patch/pch.c +++ usr.bin/patch/pch.c @@ -1,3 +1,5 @@ +/* $OpenBSD: pch.c,v 1.55 2016/09/02 09:48:03 otto Exp $ */ + /*- * Copyright 1986, Larry Wall * @@ -23,7 +25,6 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: pch.c,v 1.43 2014/11/18 17:03:35 tobias Exp $ * $FreeBSD$ */ @@ -46,6 +47,9 @@ /* Patch (diff listing) abstract type. */ +FILE *pfp = NULL; /* patch file pointer */ +LINENUM p_input_line = 0; /* current line # from patch file */ + static off_t p_filesize; /* size of the patch file */ static LINENUM p_first; /* 1st line number */ static LINENUM p_newfirst; /* 1st line number of replacement */ @@ -54,7 +58,6 @@ static LINENUM p_end = -1; /* last line in hunk */ static LINENUM p_max; /* max allowed value of p_end */ static LINENUM p_context = 3; /* # of context lines */ -static LINENUM p_input_line = 0; /* current line # from patch file */ static char **p_line = NULL;/* the text of the hunk */ static unsigned short *p_len = NULL; /* length of each line */ static char *p_char = NULL; /* +, -, and ! */ @@ -67,18 +70,14 @@ static LINENUM p_hunk_beg; /* line number of current hunk */ static LINENUM p_efake = -1; /* end of faked up lines--don't free */ static LINENUM p_bfake = -1; /* beg of faked up lines */ -static FILE *pfp = NULL; /* patch file pointer */ static char *bestguess = NULL; /* guess at correct filename */ static void grow_hunkmax(void); static int intuit_diff_type(void); -static void next_intuit_at(off_t, LINENUM); static void skip_to(off_t, LINENUM); -static size_t pgets(bool _do_indent); static char *best_name(const struct file_name *, bool); static char *posix_name(const struct file_name *, bool); static size_t num_components(const char *); -static LINENUM strtolinenum(char *, char **); /* * Prepare to look for the next patch in the patch file. @@ -134,11 +133,11 @@ set_hunkmax(void) { if (p_line == NULL) - p_line = malloc(hunkmax * sizeof(char *)); + p_line = calloc((size_t) hunkmax, sizeof(char *)); if (p_len == NULL) - p_len = malloc(hunkmax * sizeof(unsigned short)); + p_len = calloc((size_t) hunkmax, sizeof(short)); if (p_char == NULL) - p_char = malloc(hunkmax * sizeof(char)); + p_char = calloc((size_t) hunkmax, sizeof(char)); } /* @@ -147,15 +146,32 @@ static void grow_hunkmax(void) { - int new_hunkmax = hunkmax * 2; + int new_hunkmax; + char **new_p_line; + short *new_p_len; + char *new_p_char; + new_hunkmax = hunkmax * 2; + if (p_line == NULL || p_len == NULL || p_char == NULL) fatal("Internal memory allocation error\n"); - p_line = reallocf(p_line, new_hunkmax * sizeof(char *)); - p_len = reallocf(p_len, new_hunkmax * sizeof(unsigned short)); - p_char = reallocf(p_char, new_hunkmax * sizeof(char)); + new_p_line = reallocarray(p_line, new_hunkmax, sizeof(char *)); + if (new_p_line == NULL) + free(p_line); + new_p_len = reallocarray(p_len, new_hunkmax, sizeof(short)); + if (new_p_len == NULL) + free(p_len); + + new_p_char = reallocarray(p_char, new_hunkmax, sizeof(char)); + if (new_p_char == NULL) + free(p_char); + + p_char = new_p_char; + p_len = new_p_len; + p_line = new_p_line; + if (p_line != NULL && p_len != NULL && p_char != NULL) { hunkmax = new_hunkmax; return; @@ -216,8 +232,10 @@ filearg[0] = fetchname(buf, &exists, 0); } if (!exists) { - ask("No file found--skip this patch? [n] "); - if (*buf != 'y') + int def_skip = *bestguess == '\0'; + ask("No file found--skip this patch? [%c] ", + def_skip ? 'y' : 'n'); + if (*buf == 'n' || (!def_skip && *buf != 'y')) continue; if (verbose) say("Skipping patch...\n"); @@ -274,7 +292,7 @@ this_line = ftello(pfp); indent = 0; p_input_line++; - if (pgets(false) == 0) { + if (fgets(buf, sizeof buf, pfp) == NULL) { if (first_command_line >= 0) { /* nothing but deletes!? */ p_start = first_command_line; @@ -321,7 +339,7 @@ ; revision = xstrdup(t); for (t = revision; - *t && !isspace((unsigned char)*t); t++) + *t && !isspace((unsigned char)*t); t++) ; *t = '\0'; if (*revision == '\0') { @@ -424,7 +442,7 @@ /* * Remember where this patch ends so we know where to start up again. */ -static void +void next_intuit_at(off_t file_pos, LINENUM file_line) { p_base = file_pos; @@ -437,17 +455,17 @@ static void skip_to(off_t file_pos, LINENUM file_line) { - size_t len; + char *ret; if (p_base > file_pos) fatal("Internal error: seek %lld>%lld\n", - (long long)p_base, (long long)file_pos); + (long long)p_base, (long long)file_pos); if (verbose && p_base < file_pos) { fseeko(pfp, p_base, SEEK_SET); say("The text leading up to this was:\n--------------------------\n"); while (ftello(pfp) < file_pos) { - len = pgets(false); - if (len == 0) + ret = fgets(buf, sizeof buf, pfp); + if (ret == NULL) fatal("Unexpected end of file\n"); say("|%s", buf); } @@ -505,8 +523,7 @@ off_t repl_backtrack_position; /* file pos of first repl line */ LINENUM repl_patch_line; /* input line number for same */ LINENUM ptrn_copiable; /* # of copiable lines in ptrn */ - char *s; - size_t len; + char *s, *ret; int context = 0; while (p_end >= 0) { @@ -532,9 +549,9 @@ repl_patch_line = 0; ptrn_copiable = 0; - len = pgets(true); + ret = pgets(buf, sizeof buf, pfp); p_input_line++; - if (len == 0 || strnNE(buf, "********", 8)) { + if (ret == NULL || strnNE(buf, "********", 8)) { next_intuit_at(line_beginning, p_input_line); return false; } @@ -542,12 +559,12 @@ p_hunk_beg = p_input_line + 1; while (p_end < p_max) { line_beginning = ftello(pfp); - len = pgets(true); + ret = pgets(buf, sizeof buf, pfp); p_input_line++; - if (len == 0) { + if (ret == NULL) { if (p_max - p_end < 4) { /* assume blank lines got chopped */ - strlcpy(buf, " \n", buf_size); + strlcpy(buf, " \n", sizeof buf); } else { if (repl_beginning && repl_could_be_missing) { repl_missing = true; @@ -588,7 +605,7 @@ return false; } for (s = buf; - *s && !isdigit((unsigned char)*s); s++) + *s && !isdigit((unsigned char)*s); s++) ; if (!*s) malformed(); @@ -596,8 +613,7 @@ memmove(s, s + 2, strlen(s + 2) + 1); p_first = strtolinenum(s, &s); if (*s == ',') { - for (; - *s && !isdigit((unsigned char)*s); s++) + for (; *s && !isdigit((unsigned char)*s); s++) ; if (!*s) malformed(); @@ -661,7 +677,8 @@ return false; } p_char[p_end] = '='; - for (s = buf; *s && !isdigit((unsigned char)*s); s++) + for (s = buf; + *s && !isdigit((unsigned char)*s); s++) ; if (!*s) malformed(); @@ -701,7 +718,7 @@ repl_could_be_missing = false; change_line: if (buf[1] == '\n' && canonicalize) - strlcpy(buf + 1, " \n", buf_size - 1); + strlcpy(buf + 1, " \n", sizeof buf - 1); if (!isspace((unsigned char)buf[1]) && buf[1] != '>' && buf[1] != '<' && repl_beginning && repl_could_be_missing) { @@ -720,10 +737,10 @@ } if (p_end == p_ptrn_lines) { if (remove_special_line()) { - int l; + int len; - l = strlen(p_line[p_end]) - 1; - (p_line[p_end])[l] = 0; + len = strlen(p_line[p_end]) - 1; + (p_line[p_end])[len] = 0; } } break; @@ -862,14 +879,12 @@ } } } else if (diff_type == UNI_DIFF) { - LINENUM fillold; /* index of old lines */ - LINENUM fillnew; /* index of new lines */ + line_beginning = ftello(pfp); /* file pos of the current line */ char ch; - line_beginning = ftello(pfp); /* file pos of the current line */ - len = pgets(true); + ret = pgets(buf, sizeof buf, pfp); p_input_line++; - if (len == 0 || strnNE(buf, "@@ -", 4)) { + if (ret == NULL || strnNE(buf, "@@ -", 4)) { next_intuit_at(line_beginning, p_input_line); return false; } @@ -903,10 +918,10 @@ p_max = p_ptrn_lines + p_repl_lines + 1; while (p_max >= hunkmax) grow_hunkmax(); - fillold = 1; - fillnew = fillold + p_ptrn_lines; - p_end = fillnew + p_repl_lines; - snprintf(buf, buf_size, "*** %ld,%ld ****\n", p_first, + fillsrc = 1; + filldst = fillsrc + p_ptrn_lines; + p_end = filldst + p_repl_lines; + snprintf(buf, sizeof buf, "*** %ld,%ld ****\n", p_first, p_first + p_ptrn_lines - 1); p_line[0] = savestr(buf); if (out_of_mem) { @@ -914,25 +929,25 @@ return false; } p_char[0] = '*'; - snprintf(buf, buf_size, "--- %ld,%ld ----\n", p_newfirst, + snprintf(buf, sizeof buf, "--- %ld,%ld ----\n", p_newfirst, p_newfirst + p_repl_lines - 1); - p_line[fillnew] = savestr(buf); + p_line[filldst] = savestr(buf); if (out_of_mem) { p_end = 0; return false; } - p_char[fillnew++] = '='; + p_char[filldst++] = '='; p_context = 100; context = 0; p_hunk_beg = p_input_line + 1; - while (fillold <= p_ptrn_lines || fillnew <= p_end) { + while (fillsrc <= p_ptrn_lines || filldst <= p_end) { line_beginning = ftello(pfp); - len = pgets(true); + ret = pgets(buf, sizeof buf, pfp); p_input_line++; - if (len == 0) { - if (p_max - fillnew < 3) { + if (ret == NULL) { + if (p_max - filldst < 3) { /* assume blank lines got chopped */ - strlcpy(buf, " \n", buf_size); + strlcpy(buf, " \n", sizeof buf); } else { fatal("unexpected end of file in patch\n"); } @@ -945,25 +960,25 @@ s = savestr(buf + 1); } if (out_of_mem) { - while (--fillnew > p_ptrn_lines) - free(p_line[fillnew]); - p_end = fillold - 1; + while (--filldst > p_ptrn_lines) + free(p_line[filldst]); + p_end = fillsrc - 1; return false; } switch (ch) { case '-': - if (fillold > p_ptrn_lines) { + if (fillsrc > p_ptrn_lines) { free(s); - p_end = fillnew - 1; + p_end = filldst - 1; malformed(); } - p_char[fillold] = ch; - p_line[fillold] = s; - p_len[fillold++] = strlen(s); - if (fillold > p_ptrn_lines) { + p_char[fillsrc] = ch; + p_line[fillsrc] = s; + p_len[fillsrc++] = strlen(s); + if (fillsrc > p_ptrn_lines) { if (remove_special_line()) { - p_len[fillold - 1] -= 1; - s[p_len[fillold - 1]] = 0; + p_len[fillsrc - 1] -= 1; + s[p_len[fillsrc - 1]] = 0; } } break; @@ -971,51 +986,51 @@ ch = ' '; /* FALL THROUGH */ case ' ': - if (fillold > p_ptrn_lines) { + if (fillsrc > p_ptrn_lines) { free(s); - while (--fillnew > p_ptrn_lines) - free(p_line[fillnew]); - p_end = fillold - 1; + while (--filldst > p_ptrn_lines) + free(p_line[filldst]); + p_end = fillsrc - 1; malformed(); } context++; - p_char[fillold] = ch; - p_line[fillold] = s; - p_len[fillold++] = strlen(s); + p_char[fillsrc] = ch; + p_line[fillsrc] = s; + p_len[fillsrc++] = strlen(s); s = savestr(s); if (out_of_mem) { - while (--fillnew > p_ptrn_lines) - free(p_line[fillnew]); - p_end = fillold - 1; + while (--filldst > p_ptrn_lines) + free(p_line[filldst]); + p_end = fillsrc - 1; return false; } - if (fillold > p_ptrn_lines) { + if (fillsrc > p_ptrn_lines) { if (remove_special_line()) { - p_len[fillold - 1] -= 1; - s[p_len[fillold - 1]] = 0; + p_len[fillsrc - 1] -= 1; + s[p_len[fillsrc - 1]] = 0; } } /* FALL THROUGH */ case '+': - if (fillnew > p_end) { + if (filldst > p_end) { free(s); - while (--fillnew > p_ptrn_lines) - free(p_line[fillnew]); - p_end = fillold - 1; + while (--filldst > p_ptrn_lines) + free(p_line[filldst]); + p_end = fillsrc - 1; malformed(); } - p_char[fillnew] = ch; - p_line[fillnew] = s; - p_len[fillnew++] = strlen(s); - if (fillold > p_ptrn_lines) { + p_char[filldst] = ch; + p_line[filldst] = s; + p_len[filldst++] = strlen(s); + if (fillsrc > p_ptrn_lines) { if (remove_special_line()) { - p_len[fillnew - 1] -= 1; - s[p_len[fillnew - 1]] = 0; + p_len[filldst - 1] -= 1; + s[p_len[filldst - 1]] = 0; } } break; default: - p_end = fillnew; + p_end = filldst; malformed(); } if (ch != ' ' && context > 0) { @@ -1028,12 +1043,12 @@ char hunk_type; int i; LINENUM min, max; - line_beginning = ftello(pfp); + p_context = 0; - len = pgets(true); + ret = pgets(buf, sizeof buf, pfp); p_input_line++; - if (len == 0 || !isdigit((unsigned char)*buf)) { + if (ret == NULL || !isdigit((unsigned char)*buf)) { next_intuit_at(line_beginning, p_input_line); return false; } @@ -1044,6 +1059,8 @@ malformed(); } else p_ptrn_lines = (*s != 'a'); + if (p_first >= LINENUM_MAX - p_ptrn_lines) + malformed(); hunk_type = *s; if (hunk_type == 'a') p_first++; /* do append rather than insert */ @@ -1067,7 +1084,7 @@ p_end, p_input_line, buf); while (p_end >= hunkmax) grow_hunkmax(); - snprintf(buf, buf_size, "*** %ld,%ld\n", p_first, + snprintf(buf, sizeof buf, "*** %ld,%ld\n", p_first, p_first + p_ptrn_lines - 1); p_line[0] = savestr(buf); if (out_of_mem) { @@ -1076,9 +1093,9 @@ } p_char[0] = '*'; for (i = 1; i <= p_ptrn_lines; i++) { - len = pgets(true); + ret = pgets(buf, sizeof buf, pfp); p_input_line++; - if (len == 0) + if (ret == NULL) fatal("unexpected end of file in patch at line %ld\n", p_input_line); if (*buf != '<') @@ -1098,16 +1115,16 @@ (p_line[i - 1])[p_len[i - 1]] = 0; } if (hunk_type == 'c') { - len = pgets(true); + ret = pgets(buf, sizeof buf, pfp); p_input_line++; - if (len == 0) + if (ret == NULL) fatal("unexpected end of file in patch at line %ld\n", p_input_line); if (*buf != '-') fatal("--- expected at line %ld of patch\n", p_input_line); } - snprintf(buf, buf_size, "--- %ld,%ld\n", min, max); + snprintf(buf, sizeof(buf), "--- %ld,%ld\n", min, max); p_line[i] = savestr(buf); if (out_of_mem) { p_end = i - 1; @@ -1115,9 +1132,9 @@ } p_char[i] = '='; for (i++; i <= p_end; i++) { - len = pgets(true); + ret = pgets(buf, sizeof buf, pfp); p_input_line++; - if (len == 0) + if (ret == NULL) fatal("unexpected end of file in patch at line %ld\n", p_input_line); if (*buf != '>') @@ -1162,47 +1179,29 @@ } /* - * Input a line from the patch file. - * Worry about indentation if do_indent is true. - * The line is read directly into the buf global variable which - * is resized if necessary in order to hold the complete line. - * Returns the number of characters read including the terminating - * '\n', if any. + * Input a line from the patch file, worrying about indentation. */ -size_t -pgets(bool do_indent) +char * +pgets(char *bf, int sz, FILE *fp) { - char *line; - size_t len; - int indent = 0, skipped = 0; + char *s, *ret = fgets(bf, sz, fp); + int indent = 0; - line = fgetln(pfp, &len); - if (line != NULL) { - if (len + 1 > buf_size) { - while (len + 1 > buf_size) - buf_size *= 2; - free(buf); - buf = malloc(buf_size); - if (buf == NULL) - fatal("out of memory\n"); + if (p_indent && ret != NULL) { + for (s = buf; + indent < p_indent && (*s == ' ' || *s == '\t' || *s == 'X'); + s++) { + if (*s == '\t') + indent += 8 - (indent % 7); + else + indent++; } - if (do_indent == 1 && p_indent) { - for (; - indent < p_indent && (*line == ' ' || *line == '\t' || *line == 'X'); - line++, skipped++) { - if (*line == '\t') - indent += 8 - (indent %7); - else - indent++; - } - } - memcpy(buf, line, len - skipped); - buf[len - skipped] = '\0'; + if (buf != s && strlcpy(buf, s, sizeof(buf)) >= sizeof(buf)) + fatal("buffer too small in pgets()\n"); } - return len; + return ret; } - /* * Reverse the old and new portions of the current hunk. */ @@ -1401,83 +1400,6 @@ } /* - * Apply an ed script by feeding ed itself. - */ -void -do_ed_script(void) -{ - char *t; - off_t beginning_of_this_line; - FILE *pipefp = NULL; - int continuation; - - if (!skip_rest_of_patch) { - if (copy_file(filearg[0], TMPOUTNAME) < 0) { - unlink(TMPOUTNAME); - fatal("can't create temp file %s", TMPOUTNAME); - } - snprintf(buf, buf_size, "%s%s%s", _PATH_RED, - verbose ? " " : " -s ", TMPOUTNAME); - pipefp = popen(buf, "w"); - } - for (;;) { - beginning_of_this_line = ftello(pfp); - if (pgets(true) == 0) { - next_intuit_at(beginning_of_this_line, p_input_line); - break; - } - p_input_line++; - for (t = buf; isdigit((unsigned char)*t) || *t == ','; t++) - ; - /* POSIX defines allowed commands as {a,c,d,i,s} */ - if (isdigit((unsigned char)*buf) && - (*t == 'a' || *t == 'c' || *t == 'd' || *t == 'i' || *t == 's')) { - if (pipefp != NULL) - fputs(buf, pipefp); - if (*t == 's') { - for (;;) { - continuation = 0; - t = strchr(buf, '\0') - 1; - while (--t >= buf && *t == '\\') - continuation = !continuation; - if (!continuation || - pgets(true) == 0) - break; - if (pipefp != NULL) - fputs(buf, pipefp); - } - } else if (*t != 'd') { - while (pgets(true)) { - p_input_line++; - if (pipefp != NULL) - fputs(buf, pipefp); - if (strEQ(buf, ".\n")) - break; - } - } - } else { - next_intuit_at(beginning_of_this_line, p_input_line); - break; - } - } - if (pipefp == NULL) - return; - fprintf(pipefp, "w\n"); - fprintf(pipefp, "q\n"); - fflush(pipefp); - pclose(pipefp); - ignore_signals(); - if (!check_only) { - if (move_file(TMPOUTNAME, outname) < 0) { - toutkeep = true; - chmod(TMPOUTNAME, filemode); - } else - chmod(outname, filemode); - } - set_signals(1); -} - -/* * Choose the name of the file to be patched based on POSIX rules. * NOTE: the POSIX rules are amazingly stupid and we only follow them * if the user specified --posix or set POSIXLY_CORRECT. @@ -1588,7 +1510,7 @@ * character that is not a digit in ENDPTR. If conversion is not * possible, call fatal. */ -static LINENUM +LINENUM strtolinenum(char *nptr, char **endptr) { LINENUM rv; Index: usr.bin/patch/util.h =================================================================== --- usr.bin/patch/util.h +++ usr.bin/patch/util.h @@ -1,3 +1,5 @@ +/* $OpenBSD: util.h,v 1.17 2015/07/26 14:32:19 millert Exp $ */ + /*- * Copyright 1986, Larry Wall * @@ -23,7 +25,6 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: util.h,v 1.16 2014/12/13 10:31:07 tobias Exp $ * $FreeBSD$ */ Index: usr.bin/patch/util.c =================================================================== --- usr.bin/patch/util.c +++ usr.bin/patch/util.c @@ -1,3 +1,5 @@ +/* $OpenBSD: util.c,v 1.40 2015/07/26 14:32:19 millert Exp $ */ + /*- * Copyright 1986, Larry Wall * @@ -23,7 +25,6 @@ * -C option added in 1998, original code by Marc Espie, based on FreeBSD * behaviour * - * $OpenBSD: util.c,v 1.35 2010/07/24 01:10:12 ray Exp $ * $FreeBSD$ */