xref: /csrg-svn/usr.bin/patch/inp.c (revision 65567)
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