xref: /original-bsd/usr.bin/patch/inp.c (revision 5d045ae7)
13297ae0bSbostic /* $Header: inp.c,v 2.0 86/09/17 15:37:02 lwall Exp $
23297ae0bSbostic  *
33297ae0bSbostic  * $Log:	inp.c,v $
43297ae0bSbostic  * Revision 2.0  86/09/17  15:37:02  lwall
53297ae0bSbostic  * Baseline for netwide release.
63297ae0bSbostic  *
73297ae0bSbostic  */
83297ae0bSbostic 
93297ae0bSbostic #include "EXTERN.h"
103297ae0bSbostic #include "common.h"
113297ae0bSbostic #include "util.h"
123297ae0bSbostic #include "pch.h"
133297ae0bSbostic #include "INTERN.h"
143297ae0bSbostic #include "inp.h"
153297ae0bSbostic 
163297ae0bSbostic /* Input-file-with-indexable-lines abstract type */
173297ae0bSbostic 
183297ae0bSbostic static long i_size;			/* size of the input file */
193297ae0bSbostic static char *i_womp;			/* plan a buffer for entire file */
203297ae0bSbostic static char **i_ptr;			/* pointers to lines in i_womp */
213297ae0bSbostic 
223297ae0bSbostic static int tifd = -1;			/* plan b virtual string array */
233297ae0bSbostic static char *tibuf[2];			/* plan b buffers */
243297ae0bSbostic static LINENUM tiline[2] = {-1, -1};	/* 1st line in each buffer */
253297ae0bSbostic static LINENUM lines_per_buf;		/* how many lines per buffer */
263297ae0bSbostic static int tireclen;			/* length of records in tmp file */
273297ae0bSbostic 
283297ae0bSbostic /* New patch--prepare to edit another file. */
293297ae0bSbostic 
303297ae0bSbostic void
re_input()313297ae0bSbostic re_input()
323297ae0bSbostic {
333297ae0bSbostic     if (using_plan_a) {
343297ae0bSbostic 	i_size = 0;
353297ae0bSbostic #ifndef lint
363297ae0bSbostic 	if (i_ptr != Null(char**))
373297ae0bSbostic 	    free((char *)i_ptr);
383297ae0bSbostic #endif
393297ae0bSbostic 	if (i_womp != Nullch)
403297ae0bSbostic 	    free(i_womp);
413297ae0bSbostic 	i_womp = Nullch;
423297ae0bSbostic 	i_ptr = Null(char **);
433297ae0bSbostic     }
443297ae0bSbostic     else {
453297ae0bSbostic 	using_plan_a = TRUE;		/* maybe the next one is smaller */
463297ae0bSbostic 	Close(tifd);
473297ae0bSbostic 	tifd = -1;
483297ae0bSbostic 	free(tibuf[0]);
493297ae0bSbostic 	free(tibuf[1]);
503297ae0bSbostic 	tibuf[0] = tibuf[1] = Nullch;
513297ae0bSbostic 	tiline[0] = tiline[1] = -1;
523297ae0bSbostic 	tireclen = 0;
533297ae0bSbostic     }
543297ae0bSbostic }
553297ae0bSbostic 
563297ae0bSbostic /* Constuct the line index, somehow or other. */
573297ae0bSbostic 
583297ae0bSbostic void
scan_input(filename)593297ae0bSbostic scan_input(filename)
603297ae0bSbostic char *filename;
613297ae0bSbostic {
623297ae0bSbostic     if (!plan_a(filename))
633297ae0bSbostic 	plan_b(filename);
643297ae0bSbostic     if (verbose) {
653297ae0bSbostic 	say3("Patching file %s using Plan %s...\n", filename,
663297ae0bSbostic 	  (using_plan_a ? "A" : "B") );
673297ae0bSbostic     }
683297ae0bSbostic }
693297ae0bSbostic 
703297ae0bSbostic /* Try keeping everything in memory. */
713297ae0bSbostic 
723297ae0bSbostic bool
plan_a(filename)733297ae0bSbostic plan_a(filename)
743297ae0bSbostic char *filename;
753297ae0bSbostic {
763297ae0bSbostic     int ifd;
773297ae0bSbostic     Reg1 char *s;
783297ae0bSbostic     Reg2 LINENUM iline;
793297ae0bSbostic 
803297ae0bSbostic     if (ok_to_create_file && stat(filename, &filestat) < 0) {
813297ae0bSbostic 	if (verbose)
823297ae0bSbostic 	    say2("(Creating file %s...)\n",filename);
833297ae0bSbostic 	makedirs(filename, TRUE);
843297ae0bSbostic 	close(creat(filename, 0666));
853297ae0bSbostic     }
863297ae0bSbostic     if (stat(filename, &filestat) < 0) {
873297ae0bSbostic 	Sprintf(buf, "RCS/%s%s", filename, RCSSUFFIX);
883297ae0bSbostic 	if (stat(buf, &filestat) >= 0 || stat(buf+4, &filestat) >= 0) {
893297ae0bSbostic 	    Sprintf(buf, CHECKOUT, filename);
903297ae0bSbostic 	    if (verbose)
913297ae0bSbostic 		say2("Can't find %s--attempting to check it out from RCS.\n",
923297ae0bSbostic 		    filename);
933297ae0bSbostic 	    if (system(buf) || stat(filename, &filestat))
943297ae0bSbostic 		fatal2("Can't check out %s.\n", filename);
953297ae0bSbostic 	}
963297ae0bSbostic 	else {
973297ae0bSbostic 	    Sprintf(buf, "SCCS/%s%s", SCCSPREFIX, filename);
983297ae0bSbostic 	    if (stat(buf, &filestat) >= 0 || stat(buf+5, &filestat) >= 0) {
993297ae0bSbostic 		Sprintf(buf, GET, filename);
1003297ae0bSbostic 		if (verbose)
1013297ae0bSbostic 		    say2("Can't find %s--attempting to get it from SCCS.\n",
1023297ae0bSbostic 			filename);
1033297ae0bSbostic 		if (system(buf) || stat(filename, &filestat))
1043297ae0bSbostic 		    fatal2("Can't get %s.\n", filename);
1053297ae0bSbostic 	    }
1063297ae0bSbostic 	    else
1073297ae0bSbostic 		fatal2("Can't find %s.\n", filename);
1083297ae0bSbostic 	}
1093297ae0bSbostic     }
1103297ae0bSbostic     filemode = filestat.st_mode;
1113297ae0bSbostic     if ((filemode & S_IFMT) & ~S_IFREG)
1123297ae0bSbostic 	fatal2("%s is not a normal file--can't patch.\n", filename);
1133297ae0bSbostic     i_size = filestat.st_size;
1143297ae0bSbostic     if (out_of_mem) {
1153297ae0bSbostic 	set_hunkmax();		/* make sure dynamic arrays are allocated */
1163297ae0bSbostic 	out_of_mem = FALSE;
1173297ae0bSbostic 	return FALSE;			/* force plan b because plan a bombed */
1183297ae0bSbostic     }
1193297ae0bSbostic #ifdef lint
1203297ae0bSbostic     i_womp = Nullch;
1213297ae0bSbostic #else
1223297ae0bSbostic     i_womp = malloc((MEM)(i_size+2));	/* lint says this may alloc less than */
1233297ae0bSbostic 					/* i_size, but that's okay, I think. */
1243297ae0bSbostic #endif
1253297ae0bSbostic     if (i_womp == Nullch)
1263297ae0bSbostic 	return FALSE;
1273297ae0bSbostic     if ((ifd = open(filename, 0)) < 0)
1283297ae0bSbostic 	fatal2("Can't open file %s\n", filename);
1293297ae0bSbostic #ifndef lint
1303297ae0bSbostic     if (read(ifd, i_womp, (int)i_size) != i_size) {
1313297ae0bSbostic 	Close(ifd);	/* probably means i_size > 15 or 16 bits worth */
1323297ae0bSbostic 	free(i_womp);	/* at this point it doesn't matter if i_womp was */
1333297ae0bSbostic 	return FALSE;	/*   undersized. */
1343297ae0bSbostic     }
1353297ae0bSbostic #endif
1363297ae0bSbostic     Close(ifd);
1373297ae0bSbostic     if (i_size && i_womp[i_size-1] != '\n')
1383297ae0bSbostic 	i_womp[i_size++] = '\n';
1393297ae0bSbostic     i_womp[i_size] = '\0';
1403297ae0bSbostic 
1413297ae0bSbostic     /* count the lines in the buffer so we know how many pointers we need */
1423297ae0bSbostic 
1433297ae0bSbostic     iline = 0;
1443297ae0bSbostic     for (s=i_womp; *s; s++) {
1453297ae0bSbostic 	if (*s == '\n')
1463297ae0bSbostic 	    iline++;
1473297ae0bSbostic     }
1483297ae0bSbostic #ifdef lint
1493297ae0bSbostic     i_ptr = Null(char**);
1503297ae0bSbostic #else
1513297ae0bSbostic     i_ptr = (char **)malloc((MEM)((iline + 2) * sizeof(char *)));
1523297ae0bSbostic #endif
1533297ae0bSbostic     if (i_ptr == Null(char **)) {	/* shucks, it was a near thing */
1543297ae0bSbostic 	free((char *)i_womp);
1553297ae0bSbostic 	return FALSE;
1563297ae0bSbostic     }
1573297ae0bSbostic 
1583297ae0bSbostic     /* now scan the buffer and build pointer array */
1593297ae0bSbostic 
1603297ae0bSbostic     iline = 1;
1613297ae0bSbostic     i_ptr[iline] = i_womp;
1623297ae0bSbostic     for (s=i_womp; *s; s++) {
1633297ae0bSbostic 	if (*s == '\n')
1643297ae0bSbostic 	    i_ptr[++iline] = s+1;	/* these are NOT null terminated */
1653297ae0bSbostic     }
1663297ae0bSbostic     input_lines = iline - 1;
1673297ae0bSbostic 
1683297ae0bSbostic     /* now check for revision, if any */
1693297ae0bSbostic 
1703297ae0bSbostic     if (revision != Nullch) {
1713297ae0bSbostic 	if (!rev_in_string(i_womp)) {
1723297ae0bSbostic 	    if (force) {
1733297ae0bSbostic 		if (verbose)
1743297ae0bSbostic 		    say2("\
1753297ae0bSbostic Warning: this file doesn't appear to be the %s version--patching anyway.\n",
1763297ae0bSbostic 			revision);
1773297ae0bSbostic 	    }
1783297ae0bSbostic 	    else {
1793297ae0bSbostic 		ask2("\
1803297ae0bSbostic This file doesn't appear to be the %s version--patch anyway? [n] ",
1813297ae0bSbostic 		    revision);
1823297ae0bSbostic 	    if (*buf != 'y')
1833297ae0bSbostic 		fatal1("Aborted.\n");
1843297ae0bSbostic 	    }
1853297ae0bSbostic 	}
1863297ae0bSbostic 	else if (verbose)
1873297ae0bSbostic 	    say2("Good.  This file appears to be the %s version.\n",
1883297ae0bSbostic 		revision);
1893297ae0bSbostic     }
1903297ae0bSbostic     return TRUE;			/* plan a will work */
1913297ae0bSbostic }
1923297ae0bSbostic 
1933297ae0bSbostic /* Keep (virtually) nothing in memory. */
1943297ae0bSbostic 
1953297ae0bSbostic void
plan_b(filename)1963297ae0bSbostic plan_b(filename)
1973297ae0bSbostic char *filename;
1983297ae0bSbostic {
1993297ae0bSbostic     Reg3 FILE *ifp;
2003297ae0bSbostic     Reg1 int i = 0;
2013297ae0bSbostic     Reg2 int maxlen = 1;
2023297ae0bSbostic     Reg4 bool found_revision = (revision == Nullch);
2033297ae0bSbostic 
2043297ae0bSbostic     using_plan_a = FALSE;
2053297ae0bSbostic     if ((ifp = fopen(filename, "r")) == Nullfp)
2063297ae0bSbostic 	fatal2("Can't open file %s\n", filename);
2073297ae0bSbostic     if ((tifd = creat(TMPINNAME, 0666)) < 0)
2083297ae0bSbostic 	fatal2("Can't open file %s\n", TMPINNAME);
2093297ae0bSbostic     while (fgets(buf, sizeof buf, ifp) != Nullch) {
2103297ae0bSbostic 	if (revision != Nullch && !found_revision && rev_in_string(buf))
2113297ae0bSbostic 	    found_revision = TRUE;
2123297ae0bSbostic 	if ((i = strlen(buf)) > maxlen)
2133297ae0bSbostic 	    maxlen = i;			/* find longest line */
2143297ae0bSbostic     }
2153297ae0bSbostic     if (revision != Nullch) {
2163297ae0bSbostic 	if (!found_revision) {
2173297ae0bSbostic 	    if (force) {
2183297ae0bSbostic 		if (verbose)
2193297ae0bSbostic 		    say2("\
2203297ae0bSbostic Warning: this file doesn't appear to be the %s version--patching anyway.\n",
2213297ae0bSbostic 			revision);
2223297ae0bSbostic 	    }
2233297ae0bSbostic 	    else {
2243297ae0bSbostic 		ask2("\
2253297ae0bSbostic This file doesn't appear to be the %s version--patch anyway? [n] ",
2263297ae0bSbostic 		    revision);
2273297ae0bSbostic 		if (*buf != 'y')
2283297ae0bSbostic 		    fatal1("Aborted.\n");
2293297ae0bSbostic 	    }
2303297ae0bSbostic 	}
2313297ae0bSbostic 	else if (verbose)
2323297ae0bSbostic 	    say2("Good.  This file appears to be the %s version.\n",
2333297ae0bSbostic 		revision);
2343297ae0bSbostic     }
2353297ae0bSbostic     Fseek(ifp, 0L, 0);		/* rewind file */
2363297ae0bSbostic     lines_per_buf = BUFFERSIZE / maxlen;
2373297ae0bSbostic     tireclen = maxlen;
2383297ae0bSbostic     tibuf[0] = malloc((MEM)(BUFFERSIZE + 1));
2393297ae0bSbostic     tibuf[1] = malloc((MEM)(BUFFERSIZE + 1));
2403297ae0bSbostic     if (tibuf[1] == Nullch)
2413297ae0bSbostic 	fatal1("Can't seem to get enough memory.\n");
2423297ae0bSbostic     for (i=1; ; i++) {
2433297ae0bSbostic 	if (! (i % lines_per_buf))	/* new block */
2443297ae0bSbostic 	    if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
2453297ae0bSbostic 		fatal1("patch: can't write temp file.\n");
2463297ae0bSbostic 	if (fgets(tibuf[0] + maxlen * (i%lines_per_buf), maxlen + 1, ifp)
2473297ae0bSbostic 	  == Nullch) {
2483297ae0bSbostic 	    input_lines = i - 1;
2493297ae0bSbostic 	    if (i % lines_per_buf)
2503297ae0bSbostic 		if (write(tifd, tibuf[0], BUFFERSIZE) < BUFFERSIZE)
2513297ae0bSbostic 		    fatal1("patch: can't write temp file.\n");
2523297ae0bSbostic 	    break;
2533297ae0bSbostic 	}
2543297ae0bSbostic     }
2553297ae0bSbostic     Fclose(ifp);
2563297ae0bSbostic     Close(tifd);
2573297ae0bSbostic     if ((tifd = open(TMPINNAME, 0)) < 0) {
2583297ae0bSbostic 	fatal2("Can't reopen file %s\n", TMPINNAME);
2593297ae0bSbostic     }
2603297ae0bSbostic }
2613297ae0bSbostic 
2623297ae0bSbostic /* Fetch a line from the input file, \n terminated, not necessarily \0. */
2633297ae0bSbostic 
2643297ae0bSbostic char *
ifetch(line,whichbuf)2653297ae0bSbostic ifetch(line,whichbuf)
2663297ae0bSbostic Reg1 LINENUM line;
2673297ae0bSbostic int whichbuf;				/* ignored when file in memory */
2683297ae0bSbostic {
2693297ae0bSbostic     if (line < 1 || line > input_lines)
2703297ae0bSbostic 	return "";
2713297ae0bSbostic     if (using_plan_a)
2723297ae0bSbostic 	return i_ptr[line];
2733297ae0bSbostic     else {
2743297ae0bSbostic 	LINENUM offline = line % lines_per_buf;
2753297ae0bSbostic 	LINENUM baseline = line - offline;
2763297ae0bSbostic 
2773297ae0bSbostic 	if (tiline[0] == baseline)
2783297ae0bSbostic 	    whichbuf = 0;
2793297ae0bSbostic 	else if (tiline[1] == baseline)
2803297ae0bSbostic 	    whichbuf = 1;
2813297ae0bSbostic 	else {
2823297ae0bSbostic 	    tiline[whichbuf] = baseline;
2833297ae0bSbostic #ifndef lint		/* complains of long accuracy */
284*5d045ae7Sbostic 	    Lseek(tifd, (off_t)baseline / lines_per_buf * BUFFERSIZE, 0);
2853297ae0bSbostic #endif
2863297ae0bSbostic 	    if (read(tifd, tibuf[whichbuf], BUFFERSIZE) < 0)
2873297ae0bSbostic 		fatal2("Error reading tmp file %s.\n", TMPINNAME);
2883297ae0bSbostic 	}
2893297ae0bSbostic 	return tibuf[whichbuf] + (tireclen*offline);
2903297ae0bSbostic     }
2913297ae0bSbostic }
2923297ae0bSbostic 
2933297ae0bSbostic /* True if the string argument contains the revision number we want. */
2943297ae0bSbostic 
2953297ae0bSbostic bool
rev_in_string(string)2963297ae0bSbostic rev_in_string(string)
2973297ae0bSbostic char *string;
2983297ae0bSbostic {
2993297ae0bSbostic     Reg1 char *s;
3003297ae0bSbostic     Reg2 int patlen;
3013297ae0bSbostic 
3023297ae0bSbostic     if (revision == Nullch)
3033297ae0bSbostic 	return TRUE;
3043297ae0bSbostic     patlen = strlen(revision);
3053297ae0bSbostic     for (s = string; *s; s++) {
3063297ae0bSbostic 	if (isspace(*s) && strnEQ(s+1, revision, patlen) &&
3073297ae0bSbostic 		isspace(s[patlen+1] )) {
3083297ae0bSbostic 	    return TRUE;
3093297ae0bSbostic 	}
3103297ae0bSbostic     }
3113297ae0bSbostic     return FALSE;
3123297ae0bSbostic }
3133297ae0bSbostic 
314