165564Sbostic /* $Header: inp.c,v 2.0 86/09/17 15:37:02 lwall Exp $
265564Sbostic *
365564Sbostic * $Log: inp.c,v $
465564Sbostic * Revision 2.0 86/09/17 15:37:02 lwall
565564Sbostic * Baseline for netwide release.
665564Sbostic *
765564Sbostic */
865564Sbostic
965564Sbostic #include "EXTERN.h"
1065564Sbostic #include "common.h"
1165564Sbostic #include "util.h"
1265564Sbostic #include "pch.h"
1365564Sbostic #include "INTERN.h"
1465564Sbostic #include "inp.h"
1565564Sbostic
1665564Sbostic /* Input-file-with-indexable-lines abstract type */
1765564Sbostic
1865564Sbostic static long i_size; /* size of the input file */
1965564Sbostic static char *i_womp; /* plan a buffer for entire file */
2065564Sbostic static char **i_ptr; /* pointers to lines in i_womp */
2165564Sbostic
2265564Sbostic static int tifd = -1; /* plan b virtual string array */
2365564Sbostic static char *tibuf[2]; /* plan b buffers */
2465564Sbostic static LINENUM tiline[2] = {-1, -1}; /* 1st line in each buffer */
2565564Sbostic static LINENUM lines_per_buf; /* how many lines per buffer */
2665564Sbostic static int tireclen; /* length of records in tmp file */
2765564Sbostic
2865564Sbostic /* New patch--prepare to edit another file. */
2965564Sbostic
3065564Sbostic void
re_input()3165564Sbostic re_input()
3265564Sbostic {
3365564Sbostic if (using_plan_a) {
3465564Sbostic i_size = 0;
3565564Sbostic #ifndef lint
3665564Sbostic if (i_ptr != Null(char**))
3765564Sbostic free((char *)i_ptr);
3865564Sbostic #endif
3965564Sbostic if (i_womp != Nullch)
4065564Sbostic free(i_womp);
4165564Sbostic i_womp = Nullch;
4265564Sbostic i_ptr = Null(char **);
4365564Sbostic }
4465564Sbostic else {
4565564Sbostic using_plan_a = TRUE; /* maybe the next one is smaller */
4665564Sbostic Close(tifd);
4765564Sbostic tifd = -1;
4865564Sbostic free(tibuf[0]);
4965564Sbostic free(tibuf[1]);
5065564Sbostic tibuf[0] = tibuf[1] = Nullch;
5165564Sbostic tiline[0] = tiline[1] = -1;
5265564Sbostic tireclen = 0;
5365564Sbostic }
5465564Sbostic }
5565564Sbostic
5665564Sbostic /* Constuct the line index, somehow or other. */
5765564Sbostic
5865564Sbostic void
scan_input(filename)5965564Sbostic scan_input(filename)
6065564Sbostic char *filename;
6165564Sbostic {
6265564Sbostic if (!plan_a(filename))
6365564Sbostic plan_b(filename);
6465564Sbostic if (verbose) {
6565564Sbostic say3("Patching file %s using Plan %s...\n", filename,
6665564Sbostic (using_plan_a ? "A" : "B") );
6765564Sbostic }
6865564Sbostic }
6965564Sbostic
7065564Sbostic /* Try keeping everything in memory. */
7165564Sbostic
7265564Sbostic bool
plan_a(filename)7365564Sbostic plan_a(filename)
7465564Sbostic char *filename;
7565564Sbostic {
7665564Sbostic int ifd;
7765564Sbostic Reg1 char *s;
7865564Sbostic Reg2 LINENUM iline;
7965564Sbostic
8065564Sbostic if (ok_to_create_file && stat(filename, &filestat) < 0) {
8165564Sbostic if (verbose)
8265564Sbostic say2("(Creating file %s...)\n",filename);
8365564Sbostic makedirs(filename, TRUE);
8465564Sbostic close(creat(filename, 0666));
8565564Sbostic }
8665564Sbostic if (stat(filename, &filestat) < 0) {
8765564Sbostic Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX);
8865564Sbostic if (stat(buf, &filestat) >= 0 || stat(buf+4, &filestat) >= 0) {
8965564Sbostic Sprintf(buf, CHECKOUT, filename);
9065564Sbostic if (verbose)
9165564Sbostic say2("Can't find %s--attempting to check it out from RCS.\n",
9265564Sbostic filename);
9365564Sbostic if (system(buf) || stat(filename, &filestat))
9465564Sbostic fatal2("Can't check out %s.\n", filename);
9565564Sbostic }
9665564Sbostic else {
9765564Sbostic Sprintf(buf, "SCCS/%s%s", SCCSPREFIX, filename);
9865564Sbostic if (stat(buf, &filestat) >= 0 || stat(buf+5, &filestat) >= 0) {
9965564Sbostic Sprintf(buf, GET, filename);
10065564Sbostic if (verbose)
10165564Sbostic say2("Can't find %s--attempting to get it from SCCS.\n",
10265564Sbostic filename);
10365564Sbostic if (system(buf) || stat(filename, &filestat))
10465564Sbostic fatal2("Can't get %s.\n", filename);
10565564Sbostic }
10665564Sbostic else
10765564Sbostic fatal2("Can't find %s.\n", filename);
10865564Sbostic }
10965564Sbostic }
11065564Sbostic filemode = filestat.st_mode;
11165564Sbostic if ((filemode & S_IFMT) & ~S_IFREG)
11265564Sbostic fatal2("%s is not a normal file--can't patch.\n", filename);
11365564Sbostic i_size = filestat.st_size;
11465564Sbostic if (out_of_mem) {
11565564Sbostic set_hunkmax(); /* make sure dynamic arrays are allocated */
11665564Sbostic out_of_mem = FALSE;
11765564Sbostic return FALSE; /* force plan b because plan a bombed */
11865564Sbostic }
11965564Sbostic #ifdef lint
12065564Sbostic i_womp = Nullch;
12165564Sbostic #else
12265564Sbostic i_womp = malloc((MEM)(i_size+2)); /* lint says this may alloc less than */
12365564Sbostic /* i_size, but that's okay, I think. */
12465564Sbostic #endif
12565564Sbostic if (i_womp == Nullch)
12665564Sbostic return FALSE;
12765564Sbostic if ((ifd = open(filename, 0)) < 0)
12865564Sbostic fatal2("Can't open file %s\n", filename);
12965564Sbostic #ifndef lint
13065564Sbostic if (read(ifd, i_womp, (int)i_size) != i_size) {
13165564Sbostic Close(ifd); /* probably means i_size > 15 or 16 bits worth */
13265564Sbostic free(i_womp); /* at this point it doesn't matter if i_womp was */
13365564Sbostic return FALSE; /* undersized. */
13465564Sbostic }
13565564Sbostic #endif
13665564Sbostic Close(ifd);
13765564Sbostic if (i_size && i_womp[i_size-1] != '\n')
13865564Sbostic i_womp[i_size++] = '\n';
13965564Sbostic i_womp[i_size] = '\0';
14065564Sbostic
14165564Sbostic /* count the lines in the buffer so we know how many pointers we need */
14265564Sbostic
14365564Sbostic iline = 0;
14465564Sbostic for (s=i_womp; *s; s++) {
14565564Sbostic if (*s == '\n')
14665564Sbostic iline++;
14765564Sbostic }
14865564Sbostic #ifdef lint
14965564Sbostic i_ptr = Null(char**);
15065564Sbostic #else
15165564Sbostic i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
15265564Sbostic #endif
15365564Sbostic if (i_ptr == Null(char **)) { /* shucks, it was a near thing */
15465564Sbostic free((char *)i_womp);
15565564Sbostic return FALSE;
15665564Sbostic }
15765564Sbostic
15865564Sbostic /* now scan the buffer and build pointer array */
15965564Sbostic
16065564Sbostic iline = 1;
16165564Sbostic i_ptr[iline] = i_womp;
16265564Sbostic for (s=i_womp; *s; s++) {
16365564Sbostic if (*s == '\n')
16465564Sbostic i_ptr[++iline] = s+1; /* these are NOT null terminated */
16565564Sbostic }
16665564Sbostic input_lines = iline - 1;
16765564Sbostic
16865564Sbostic /* now check for revision, if any */
16965564Sbostic
17065564Sbostic if (revision != Nullch) {
17165564Sbostic if (!rev_in_string(i_womp)) {
17265564Sbostic if (force) {
17365564Sbostic if (verbose)
17465564Sbostic say2("\
17565564Sbostic Warning: this file doesn't appear to be the %s version--patching anyway.\n",
17665564Sbostic revision);
17765564Sbostic }
17865564Sbostic else {
17965564Sbostic ask2("\
18065564Sbostic This file doesn't appear to be the %s version--patch anyway? [n] ",
18165564Sbostic revision);
18265564Sbostic if (*buf != 'y')
18365564Sbostic fatal1("Aborted.\n");
18465564Sbostic }
18565564Sbostic }
18665564Sbostic else if (verbose)
18765564Sbostic say2("Good. This file appears to be the %s version.\n",
18865564Sbostic revision);
18965564Sbostic }
19065564Sbostic return TRUE; /* plan a will work */
19165564Sbostic }
19265564Sbostic
19365564Sbostic /* Keep (virtually) nothing in memory. */
19465564Sbostic
19565564Sbostic void
plan_b(filename)19665564Sbostic plan_b(filename)
19765564Sbostic char *filename;
19865564Sbostic {
19965564Sbostic Reg3 FILE *ifp;
20065564Sbostic Reg1 int i = 0;
20165564Sbostic Reg2 int maxlen = 1;
20265564Sbostic Reg4 bool found_revision = (revision == Nullch);
20365564Sbostic
20465564Sbostic using_plan_a = FALSE;
20565564Sbostic if ((ifp = fopen(filename, "r")) == Nullfp)
20665564Sbostic fatal2("Can't open file %s\n", filename);
20765564Sbostic if ((tifd = creat(TMPINNAME, 0666)) < 0)
20865564Sbostic fatal2("Can't open file %s\n", TMPINNAME);
20965564Sbostic while (fgets(buf, sizeof buf, ifp) != Nullch) {
21065564Sbostic if (revision != Nullch && !found_revision && rev_in_string(buf))
21165564Sbostic found_revision = TRUE;
21265564Sbostic if ((i = strlen(buf)) > maxlen)
21365564Sbostic maxlen = i; /* find longest line */
21465564Sbostic }
21565564Sbostic if (revision != Nullch) {
21665564Sbostic if (!found_revision) {
21765564Sbostic if (force) {
21865564Sbostic if (verbose)
21965564Sbostic say2("\
22065564Sbostic Warning: this file doesn't appear to be the %s version--patching anyway.\n",
22165564Sbostic revision);
22265564Sbostic }
22365564Sbostic else {
22465564Sbostic ask2("\
22565564Sbostic This file doesn't appear to be the %s version--patch anyway? [n] ",
22665564Sbostic revision);
22765564Sbostic if (*buf != 'y')
22865564Sbostic fatal1("Aborted.\n");
22965564Sbostic }
23065564Sbostic }
23165564Sbostic else if (verbose)
23265564Sbostic say2("Good. This file appears to be the %s version.\n",
23365564Sbostic revision);
23465564Sbostic }
23565564Sbostic Fseek(ifp, 0L, 0); /* rewind file */
23665564Sbostic lines_per_buf = BUFFERSIZE / maxlen;
23765564Sbostic tireclen = maxlen;
23865564Sbostic tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
23965564Sbostic tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
24065564Sbostic if (tibuf[1] == Nullch)
24165564Sbostic fatal1("Can't seem to get enough memory.\n");
24265564Sbostic for (i=1; ; i++) {
24365564Sbostic if (! (i % lines_per_buf)) /* new block */
24465564Sbostic if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
24565564Sbostic fatal1("patch: can't write temp file.\n");
24665564Sbostic if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
24765564Sbostic == Nullch) {
24865564Sbostic input_lines = i - 1;
24965564Sbostic if (i % lines_per_buf)
25065564Sbostic if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
25165564Sbostic fatal1("patch: can't write temp file.\n");
25265564Sbostic break;
25365564Sbostic }
25465564Sbostic }
25565564Sbostic Fclose(ifp);
25665564Sbostic Close(tifd);
25765564Sbostic if ((tifd = open(TMPINNAME, 0)) < 0) {
25865564Sbostic fatal2("Can't reopen file %s\n", TMPINNAME);
25965564Sbostic }
26065564Sbostic }
26165564Sbostic
26265564Sbostic /* Fetch a line from the input file, \n terminated, not necessarily \0. */
26365564Sbostic
26465564Sbostic char *
ifetch(line,whichbuf)26565564Sbostic ifetch(line,whichbuf)
26665564Sbostic Reg1 LINENUM line;
26765564Sbostic int whichbuf; /* ignored when file in memory */
26865564Sbostic {
26965564Sbostic if (line < 1 || line > input_lines)
27065564Sbostic return "";
27165564Sbostic if (using_plan_a)
27265564Sbostic return i_ptr[line];
27365564Sbostic else {
27465564Sbostic LINENUM offline = line % lines_per_buf;
27565564Sbostic LINENUM baseline = line - offline;
27665564Sbostic
27765564Sbostic if (tiline[0] == baseline)
27865564Sbostic whichbuf = 0;
27965564Sbostic else if (tiline[1] == baseline)
28065564Sbostic whichbuf = 1;
28165564Sbostic else {
28265564Sbostic tiline[whichbuf] = baseline;
28365564Sbostic #ifndef lint /* complains of long accuracy */
284*65567Sbostic Lseek(tifd, (off_t)baseline / lines_per_buf * BUFFERSIZE, 0);
28565564Sbostic #endif
28665564Sbostic if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
28765564Sbostic fatal2("Error reading tmp file %s.\n", TMPINNAME);
28865564Sbostic }
28965564Sbostic return tibuf[whichbuf] + (tireclen*offline);
29065564Sbostic }
29165564Sbostic }
29265564Sbostic
29365564Sbostic /* True if the string argument contains the revision number we want. */
29465564Sbostic
29565564Sbostic bool
rev_in_string(string)29665564Sbostic rev_in_string(string)
29765564Sbostic char *string;
29865564Sbostic {
29965564Sbostic Reg1 char *s;
30065564Sbostic Reg2 int patlen;
30165564Sbostic
30265564Sbostic if (revision == Nullch)
30365564Sbostic return TRUE;
30465564Sbostic patlen = strlen(revision);
30565564Sbostic for (s = string; *s; s++) {
30665564Sbostic if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
30765564Sbostic isspace(s[patlen+1] )) {
30865564Sbostic return TRUE;
30965564Sbostic }
31065564Sbostic }
31165564Sbostic return FALSE;
31265564Sbostic }
31365564Sbostic
314