Annotation of src/usr.bin/patch/inp.c, Revision 1.15
1.15 ! itojun 1: /* $NetBSD: inp.c,v 1.14 2003/07/08 01:55:35 kristerw Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 1988, Larry Wall
! 5: *
! 6: * Redistribution and use in source and binary forms, with or without
! 7: * modification, are permitted provided that the following condition
! 8: * is met:
! 9: * 1. Redistributions of source code must retain the above copyright
! 10: * notice, this condition and the following disclaimer.
! 11: *
! 12: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
! 13: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 14: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 15: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
! 16: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 17: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 18: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 19: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 20: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 21: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 22: * SUCH DAMAGE.
! 23: */
! 24:
1.4 christos 25: #include <sys/cdefs.h>
1.2 mycroft 26: #ifndef lint
1.15 ! itojun 27: __RCSID("$NetBSD: inp.c,v 1.14 2003/07/08 01:55:35 kristerw Exp $");
1.2 mycroft 28: #endif /* not lint */
1.1 cgd 29:
30: #include "EXTERN.h"
1.7 kristerw 31: #include "backupfile.h"
1.1 cgd 32: #include "common.h"
33: #include "util.h"
34: #include "pch.h"
35: #include "INTERN.h"
36: #include "inp.h"
37:
1.4 christos 38: #include <stdlib.h>
39: #include <unistd.h>
40: #include <fcntl.h>
41:
1.13 kristerw 42: static void plan_a(char *);
1.10 kristerw 43: static bool rev_in_string(char *);
44:
1.9 kristerw 45: /* Input-file-with-indexable-lines abstract type. */
1.1 cgd 46:
1.11 kristerw 47: static size_t i_size; /* Size of the input file */
1.9 kristerw 48: static char *i_womp; /* Plan a buffer for entire file */
49: static char **i_ptr; /* Pointers to lines in i_womp */
1.1 cgd 50:
1.9 kristerw 51: /*
1.13 kristerw 52: * New patch -- prepare to edit another file.
1.9 kristerw 53: */
1.1 cgd 54: void
1.7 kristerw 55: re_input(void)
1.1 cgd 56: {
1.13 kristerw 57: i_size = 0;
1.7 kristerw 58:
1.13 kristerw 59: if (i_ptr != NULL)
60: free(i_ptr);
61: if (i_womp != NULL)
62: free(i_womp);
63: i_womp = NULL;
64: i_ptr = NULL;
1.1 cgd 65: }
66:
1.9 kristerw 67: /*
1.13 kristerw 68: * Construct the line index, somehow or other.
1.9 kristerw 69: */
1.1 cgd 70: void
1.7 kristerw 71: scan_input(char *filename)
1.1 cgd 72: {
1.13 kristerw 73: plan_a(filename);
74: if (verbose)
75: say("Patching file %s using Plan A...\n", filename);
1.1 cgd 76: }
77:
1.9 kristerw 78: /*
79: * Try keeping everything in memory.
80: */
1.13 kristerw 81: static void
1.7 kristerw 82: plan_a(char *filename)
1.1 cgd 83: {
1.9 kristerw 84: int ifd, statfailed;
85: char *s;
86: LINENUM iline;
87: char lbuf[MAXLINELEN];
88:
1.1 cgd 89: statfailed = stat(filename, &filestat);
1.9 kristerw 90: if (statfailed && ok_to_create_file) {
91: if (verbose)
92: say("(Creating file %s...)\n",filename);
93: makedirs(filename, TRUE);
94: close(creat(filename, 0666));
95: statfailed = stat(filename, &filestat);
96: }
97: /*
98: * For nonexistent or read-only files, look for RCS or SCCS
99: * versions.
100: */
101: if (statfailed ||
102: /* No one can write to it. */
103: (filestat.st_mode & 0222) == 0 ||
104: /* I can't write to it. */
105: ((filestat.st_mode & 0022) == 0 && filestat.st_uid != myuid)) {
106: struct stat cstat;
1.14 kristerw 107: const char *cs = NULL;
1.9 kristerw 108: char *filebase;
1.11 kristerw 109: size_t pathlen;
1.9 kristerw 110:
111: filebase = basename(filename);
112: pathlen = filebase - filename;
113:
114: /*
115: * Put any leading path into `s'.
116: * Leave room in lbuf for the diff command.
117: */
118: s = lbuf + 20;
119: strncpy(s, filename, pathlen);
1.1 cgd 120:
121: #define try(f, a1, a2) (Sprintf(s + pathlen, f, a1, a2), stat(s, &cstat) == 0)
1.4 christos 122: #define try1(f, a1) (Sprintf(s + pathlen, f, a1), stat(s, &cstat) == 0)
1.9 kristerw 123: if (try("RCS/%s%s", filebase, RCSSUFFIX) ||
124: try1("RCS/%s" , filebase) ||
125: try("%s%s", filebase, RCSSUFFIX)) {
126: Sprintf(buf, CHECKOUT, filename);
127: Sprintf(lbuf, RCSDIFF, filename);
128: cs = "RCS";
129: } else if (try("SCCS/%s%s", SCCSPREFIX, filebase) ||
130: try("%s%s", SCCSPREFIX, filebase)) {
131: Sprintf(buf, GET, s);
132: Sprintf(lbuf, SCCSDIFF, s, filename);
133: cs = "SCCS";
134: } else if (statfailed)
135: fatal("can't find %s\n", filename);
136: /*
137: * else we can't write to it but it's not under a version
138: * control system, so just proceed.
139: */
140: if (cs) {
141: if (!statfailed) {
142: if ((filestat.st_mode & 0222) != 0)
143: /* The owner can write to it. */
144: fatal(
145: "file %s seems to be locked by somebody else under %s\n",
146: filename, cs);
147: /*
148: * It might be checked out unlocked. See if
149: * it's safe to check out the default version
150: * locked.
151: */
152: if (verbose)
153: say(
154: "Comparing file %s to default %s version...\n",
155: filename, cs);
156: if (system(lbuf))
157: fatal(
158: "can't check out file %s: differs from default %s version\n",
159: filename, cs);
160: }
161: if (verbose)
162: say("Checking out file %s from %s...\n",
163: filename, cs);
164: if (system(buf) || stat(filename, &filestat))
165: fatal("can't check out file %s from %s\n",
166: filename, cs);
167: }
168: }
169: if (old_file_is_dev_null &&
170: ok_to_create_file &&
171: (filestat.st_size != 0)) {
172: fatal(
173: "patch creates new file but existing file %s not empty\n",
174: filename);
1.1 cgd 175: }
1.6 sommerfe 176:
1.9 kristerw 177: filemode = filestat.st_mode;
178: if (!S_ISREG(filemode))
179: fatal("%s is not a normal file--can't patch\n", filename);
180: i_size = filestat.st_size;
181:
1.12 kristerw 182: i_womp = xmalloc(i_size + 2);
1.9 kristerw 183: if ((ifd = open(filename, 0)) < 0)
184: pfatal("can't open file %s", filename);
1.13 kristerw 185: if (read(ifd, i_womp, i_size) != i_size)
186: pfatal("read error");
1.9 kristerw 187: Close(ifd);
188: if (i_size && i_womp[i_size - 1] != '\n')
189: i_womp[i_size++] = '\n';
190: i_womp[i_size] = '\0';
191:
192: /*
193: * Count the lines in the buffer so we know how many pointers we
194: * need.
195: */
196: iline = 0;
197: for (s = i_womp; *s; s++) {
198: if (*s == '\n')
199: iline++;
200: }
1.12 kristerw 201: i_ptr = xmalloc((iline + 2) * sizeof(char *));
1.1 cgd 202:
1.9 kristerw 203: /* Now scan the buffer and build pointer array. */
204: iline = 1;
205: i_ptr[iline] = i_womp;
206: for (s = i_womp; *s; s++) {
207: if (*s == '\n') {
208: /* These are NOT null terminated. */
209: i_ptr[++iline] = s + 1;
210: }
211: }
212: input_lines = iline - 1;
1.1 cgd 213:
1.9 kristerw 214: /* Now check for revision, if any. */
215: if (revision != NULL) {
216: if (!rev_in_string(i_womp)) {
217: if (force) {
218: if (verbose)
219: say(
1.1 cgd 220: "Warning: this file doesn't appear to be the %s version--patching anyway.\n",
221: revision);
1.9 kristerw 222: } else if (batch) {
223: fatal(
1.1 cgd 224: "this file doesn't appear to be the %s version--aborting.\n", revision);
1.9 kristerw 225: } else {
226: ask(
1.1 cgd 227: "This file doesn't appear to be the %s version--patch anyway? [n] ",
228: revision);
1.9 kristerw 229: if (*buf != 'y')
230: fatal("aborted\n");
231: }
232: } else if (verbose)
233: say("Good. This file appears to be the %s version.\n",
234: revision);
235: }
1.1 cgd 236: }
237:
1.9 kristerw 238: /*
239: * Fetch a line from the input file, \n terminated, not necessarily \0.
240: */
1.14 kristerw 241: const char *
1.13 kristerw 242: ifetch(LINENUM line)
1.1 cgd 243: {
1.9 kristerw 244: if (line < 1 || line > input_lines)
245: return "";
1.13 kristerw 246:
247: return i_ptr[line];
1.1 cgd 248: }
249:
1.9 kristerw 250: /*
251: * True if the string argument contains the revision number we want.
252: */
1.10 kristerw 253: static bool
1.7 kristerw 254: rev_in_string(char *string)
1.1 cgd 255: {
1.9 kristerw 256: char *s;
1.11 kristerw 257: size_t patlen;
1.1 cgd 258:
1.9 kristerw 259: if (revision == NULL)
260: return TRUE;
261: patlen = strlen(revision);
262: if (strnEQ(string,revision,patlen) &&
263: isspace((unsigned char)string[patlen]))
264: return TRUE;
265: for (s = string; *s; s++) {
266: if (isspace((unsigned char)*s) &&
267: strnEQ(s + 1, revision, patlen) &&
268: isspace((unsigned char)s[patlen + 1] )) {
269: return TRUE;
270: }
1.1 cgd 271: }
1.13 kristerw 272: return FALSE;
1.1 cgd 273: }
CVSweb <webmaster@jp.NetBSD.org>