xref: /plan9/sys/src/ape/cmd/patch/inp.c (revision 0b459c2cb92b7c9d88818e9a2f72e678e5bc4553)
1*0b459c2cSDavid du Colombier /* inputting files to be patched */
2*0b459c2cSDavid du Colombier 
3*0b459c2cSDavid du Colombier /* $Id: inp.c,v 1.18 1997/07/21 17:59:46 eggert Exp $ */
4*0b459c2cSDavid du Colombier 
5*0b459c2cSDavid du Colombier /*
6*0b459c2cSDavid du Colombier Copyright 1986, 1988 Larry Wall
7*0b459c2cSDavid du Colombier Copyright 1991, 1992, 1993, 1997 Free Software Foundation, Inc.
8*0b459c2cSDavid du Colombier 
9*0b459c2cSDavid du Colombier This program is free software; you can redistribute it and/or modify
10*0b459c2cSDavid du Colombier it under the terms of the GNU General Public License as published by
11*0b459c2cSDavid du Colombier the Free Software Foundation; either version 2, or (at your option)
12*0b459c2cSDavid du Colombier any later version.
13*0b459c2cSDavid du Colombier 
14*0b459c2cSDavid du Colombier This program is distributed in the hope that it will be useful,
15*0b459c2cSDavid du Colombier but WITHOUT ANY WARRANTY; without even the implied warranty of
16*0b459c2cSDavid du Colombier MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17*0b459c2cSDavid du Colombier GNU General Public License for more details.
18*0b459c2cSDavid du Colombier 
19*0b459c2cSDavid du Colombier You should have received a copy of the GNU General Public License
20*0b459c2cSDavid du Colombier along with this program; see the file COPYING.
21*0b459c2cSDavid du Colombier If not, write to the Free Software Foundation,
22*0b459c2cSDavid du Colombier 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23*0b459c2cSDavid du Colombier */
24*0b459c2cSDavid du Colombier 
25*0b459c2cSDavid du Colombier #define XTERN extern
26*0b459c2cSDavid du Colombier #include <common.h>
27*0b459c2cSDavid du Colombier #include <backupfile.h>
28*0b459c2cSDavid du Colombier #include <pch.h>
29*0b459c2cSDavid du Colombier #include <util.h>
30*0b459c2cSDavid du Colombier #undef XTERN
31*0b459c2cSDavid du Colombier #define XTERN
32*0b459c2cSDavid du Colombier #include <inp.h>
33*0b459c2cSDavid du Colombier 
34*0b459c2cSDavid du Colombier /* Input-file-with-indexable-lines abstract type */
35*0b459c2cSDavid du Colombier 
36*0b459c2cSDavid du Colombier static char *i_buffer;			/* plan A buffer */
37*0b459c2cSDavid du Colombier static char const **i_ptr;		/* pointers to lines in plan A buffer */
38*0b459c2cSDavid du Colombier 
39*0b459c2cSDavid du Colombier static size_t tibufsize;		/* size of plan b buffers */
40*0b459c2cSDavid du Colombier #ifndef TIBUFSIZE_MINIMUM
41*0b459c2cSDavid du Colombier #define TIBUFSIZE_MINIMUM (8 * 1024)	/* minimum value for tibufsize */
42*0b459c2cSDavid du Colombier #endif
43*0b459c2cSDavid du Colombier static int tifd = -1;			/* plan b virtual string array */
44*0b459c2cSDavid du Colombier static char *tibuf[2];			/* plan b buffers */
45*0b459c2cSDavid du Colombier static LINENUM tiline[2] = {-1, -1};	/* 1st line in each buffer */
46*0b459c2cSDavid du Colombier static LINENUM lines_per_buf;		/* how many lines per buffer */
47*0b459c2cSDavid du Colombier static size_t tireclen;			/* length of records in tmp file */
48*0b459c2cSDavid du Colombier static size_t last_line_size;		/* size of last input line */
49*0b459c2cSDavid du Colombier 
50*0b459c2cSDavid du Colombier static bool plan_a PARAMS ((char const *));/* yield FALSE if memory runs out */
51*0b459c2cSDavid du Colombier static void plan_b PARAMS ((char const *));
52*0b459c2cSDavid du Colombier static void report_revision PARAMS ((int));
53*0b459c2cSDavid du Colombier static void too_many_lines PARAMS ((char const *)) __attribute__((noreturn));
54*0b459c2cSDavid du Colombier 
55*0b459c2cSDavid du Colombier /* New patch--prepare to edit another file. */
56*0b459c2cSDavid du Colombier 
57*0b459c2cSDavid du Colombier void
re_input()58*0b459c2cSDavid du Colombier re_input()
59*0b459c2cSDavid du Colombier {
60*0b459c2cSDavid du Colombier     if (using_plan_a) {
61*0b459c2cSDavid du Colombier 	free (i_buffer);
62*0b459c2cSDavid du Colombier 	free (i_ptr);
63*0b459c2cSDavid du Colombier     }
64*0b459c2cSDavid du Colombier     else {
65*0b459c2cSDavid du Colombier 	close (tifd);
66*0b459c2cSDavid du Colombier 	tifd = -1;
67*0b459c2cSDavid du Colombier 	free(tibuf[0]);
68*0b459c2cSDavid du Colombier 	tibuf[0] = 0;
69*0b459c2cSDavid du Colombier 	tiline[0] = tiline[1] = -1;
70*0b459c2cSDavid du Colombier 	tireclen = 0;
71*0b459c2cSDavid du Colombier     }
72*0b459c2cSDavid du Colombier }
73*0b459c2cSDavid du Colombier 
74*0b459c2cSDavid du Colombier /* Construct the line index, somehow or other. */
75*0b459c2cSDavid du Colombier 
76*0b459c2cSDavid du Colombier void
scan_input(filename)77*0b459c2cSDavid du Colombier scan_input(filename)
78*0b459c2cSDavid du Colombier char *filename;
79*0b459c2cSDavid du Colombier {
80*0b459c2cSDavid du Colombier     using_plan_a = ! (debug & 16) && plan_a (filename);
81*0b459c2cSDavid du Colombier     if (!using_plan_a)
82*0b459c2cSDavid du Colombier 	plan_b(filename);
83*0b459c2cSDavid du Colombier     switch (verbosity)
84*0b459c2cSDavid du Colombier       {
85*0b459c2cSDavid du Colombier       case SILENT:
86*0b459c2cSDavid du Colombier 	break;
87*0b459c2cSDavid du Colombier 
88*0b459c2cSDavid du Colombier       case VERBOSE:
89*0b459c2cSDavid du Colombier 	say ("Patching file `%s' using Plan %s...\n",
90*0b459c2cSDavid du Colombier 	     filename, using_plan_a ? "A" : "B");
91*0b459c2cSDavid du Colombier 	break;
92*0b459c2cSDavid du Colombier 
93*0b459c2cSDavid du Colombier       case DEFAULT_VERBOSITY:
94*0b459c2cSDavid du Colombier 	say ("patching file `%s'\n", filename);
95*0b459c2cSDavid du Colombier 	break;
96*0b459c2cSDavid du Colombier       }
97*0b459c2cSDavid du Colombier }
98*0b459c2cSDavid du Colombier 
99*0b459c2cSDavid du Colombier /* Report whether a desired revision was found.  */
100*0b459c2cSDavid du Colombier 
101*0b459c2cSDavid du Colombier static void
report_revision(found_revision)102*0b459c2cSDavid du Colombier report_revision (found_revision)
103*0b459c2cSDavid du Colombier      int found_revision;
104*0b459c2cSDavid du Colombier {
105*0b459c2cSDavid du Colombier   if (found_revision)
106*0b459c2cSDavid du Colombier     {
107*0b459c2cSDavid du Colombier       if (verbosity == VERBOSE)
108*0b459c2cSDavid du Colombier 	say ("Good.  This file appears to be the %s version.\n", revision);
109*0b459c2cSDavid du Colombier     }
110*0b459c2cSDavid du Colombier   else if (force)
111*0b459c2cSDavid du Colombier     {
112*0b459c2cSDavid du Colombier       if (verbosity != SILENT)
113*0b459c2cSDavid du Colombier 	say ("Warning: this file doesn't appear to be the %s version -- patching anyway.\n",
114*0b459c2cSDavid du Colombier 	     revision);
115*0b459c2cSDavid du Colombier     }
116*0b459c2cSDavid du Colombier   else if (batch)
117*0b459c2cSDavid du Colombier     {
118*0b459c2cSDavid du Colombier       fatal ("This file doesn't appear to be the %s version -- aborting.",
119*0b459c2cSDavid du Colombier 	     revision);
120*0b459c2cSDavid du Colombier     }
121*0b459c2cSDavid du Colombier   else
122*0b459c2cSDavid du Colombier     {
123*0b459c2cSDavid du Colombier       ask ("This file doesn't appear to be the %s version -- patch anyway? [n] ",
124*0b459c2cSDavid du Colombier 	   revision);
125*0b459c2cSDavid du Colombier       if (*buf != 'y')
126*0b459c2cSDavid du Colombier 	fatal ("aborted");
127*0b459c2cSDavid du Colombier     }
128*0b459c2cSDavid du Colombier }
129*0b459c2cSDavid du Colombier 
130*0b459c2cSDavid du Colombier 
131*0b459c2cSDavid du Colombier static void
too_many_lines(filename)132*0b459c2cSDavid du Colombier too_many_lines (filename)
133*0b459c2cSDavid du Colombier      char const *filename;
134*0b459c2cSDavid du Colombier {
135*0b459c2cSDavid du Colombier   fatal ("File `%s' has too many lines.", filename);
136*0b459c2cSDavid du Colombier }
137*0b459c2cSDavid du Colombier 
138*0b459c2cSDavid du Colombier 
139*0b459c2cSDavid du Colombier void
get_input_file(filename,outname)140*0b459c2cSDavid du Colombier get_input_file (filename, outname)
141*0b459c2cSDavid du Colombier      char const *filename;
142*0b459c2cSDavid du Colombier      char const *outname;
143*0b459c2cSDavid du Colombier {
144*0b459c2cSDavid du Colombier     int elsewhere = strcmp (filename, outname);
145*0b459c2cSDavid du Colombier     char const *cs;
146*0b459c2cSDavid du Colombier     char *diffbuf;
147*0b459c2cSDavid du Colombier     char *getbuf;
148*0b459c2cSDavid du Colombier 
149*0b459c2cSDavid du Colombier     if (inerrno == -1)
150*0b459c2cSDavid du Colombier       inerrno = stat (inname, &instat) == 0 ? 0 : errno;
151*0b459c2cSDavid du Colombier 
152*0b459c2cSDavid du Colombier     /* Perhaps look for RCS or SCCS versions.  */
153*0b459c2cSDavid du Colombier     if (patch_get
154*0b459c2cSDavid du Colombier 	&& invc != 0
155*0b459c2cSDavid du Colombier 	&& (inerrno
156*0b459c2cSDavid du Colombier 	    || (! elsewhere
157*0b459c2cSDavid du Colombier 		&& (/* No one can write to it.  */
158*0b459c2cSDavid du Colombier 		    (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) == 0
159*0b459c2cSDavid du Colombier 		    /* Only the owner (who's not me) can write to it.  */
160*0b459c2cSDavid du Colombier 		    || ((instat.st_mode & (S_IWGRP|S_IWOTH)) == 0
161*0b459c2cSDavid du Colombier 			&& instat.st_uid != geteuid ()))))
162*0b459c2cSDavid du Colombier 	&& (invc = !! (cs = (version_controller
163*0b459c2cSDavid du Colombier 			     (filename, elsewhere,
164*0b459c2cSDavid du Colombier 			      inerrno ? (struct stat *) 0 : &instat,
165*0b459c2cSDavid du Colombier 			      &getbuf, &diffbuf))))) {
166*0b459c2cSDavid du Colombier 
167*0b459c2cSDavid du Colombier 	    if (!inerrno) {
168*0b459c2cSDavid du Colombier 		if (!elsewhere
169*0b459c2cSDavid du Colombier 		    && (instat.st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)) != 0)
170*0b459c2cSDavid du Colombier 		    /* Somebody can write to it.  */
171*0b459c2cSDavid du Colombier 		    fatal ("file `%s' seems to be locked by somebody else under %s",
172*0b459c2cSDavid du Colombier 			   filename, cs);
173*0b459c2cSDavid du Colombier 		/* It might be checked out unlocked.  See if it's safe to
174*0b459c2cSDavid du Colombier 		   check out the default version locked.  */
175*0b459c2cSDavid du Colombier 		if (verbosity == VERBOSE)
176*0b459c2cSDavid du Colombier 		    say ("Comparing file `%s' to default %s version...\n",
177*0b459c2cSDavid du Colombier 			 filename, cs);
178*0b459c2cSDavid du Colombier 		if (systemic (diffbuf) != 0)
179*0b459c2cSDavid du Colombier 		  {
180*0b459c2cSDavid du Colombier 		    say ("warning: patching file `%s', which does not match default %s version\n",
181*0b459c2cSDavid du Colombier 			 filename, cs);
182*0b459c2cSDavid du Colombier 		    cs = 0;
183*0b459c2cSDavid du Colombier 		  }
184*0b459c2cSDavid du Colombier 	    }
185*0b459c2cSDavid du Colombier 
186*0b459c2cSDavid du Colombier 	    if (cs && version_get (filename, cs, ! inerrno, elsewhere, getbuf,
187*0b459c2cSDavid du Colombier 				   &instat))
188*0b459c2cSDavid du Colombier 	      inerrno = 0;
189*0b459c2cSDavid du Colombier 
190*0b459c2cSDavid du Colombier 	    free (getbuf);
191*0b459c2cSDavid du Colombier 	    free (diffbuf);
192*0b459c2cSDavid du Colombier 
193*0b459c2cSDavid du Colombier     } else if (inerrno && !pch_says_nonexistent (reverse))
194*0b459c2cSDavid du Colombier       {
195*0b459c2cSDavid du Colombier 	errno = inerrno;
196*0b459c2cSDavid du Colombier 	pfatal ("can't find file `%s'", filename);
197*0b459c2cSDavid du Colombier       }
198*0b459c2cSDavid du Colombier 
199*0b459c2cSDavid du Colombier     if (inerrno)
200*0b459c2cSDavid du Colombier       {
201*0b459c2cSDavid du Colombier 	instat.st_mode = S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH;
202*0b459c2cSDavid du Colombier 	instat.st_size = 0;
203*0b459c2cSDavid du Colombier       }
204*0b459c2cSDavid du Colombier     else if (! S_ISREG (instat.st_mode))
205*0b459c2cSDavid du Colombier       fatal ("`%s' is not a regular file -- can't patch", filename);
206*0b459c2cSDavid du Colombier }
207*0b459c2cSDavid du Colombier 
208*0b459c2cSDavid du Colombier 
209*0b459c2cSDavid du Colombier /* Try keeping everything in memory. */
210*0b459c2cSDavid du Colombier 
211*0b459c2cSDavid du Colombier static bool
plan_a(filename)212*0b459c2cSDavid du Colombier plan_a(filename)
213*0b459c2cSDavid du Colombier      char const *filename;
214*0b459c2cSDavid du Colombier {
215*0b459c2cSDavid du Colombier   register char const *s;
216*0b459c2cSDavid du Colombier   register char const *lim;
217*0b459c2cSDavid du Colombier   register char const **ptr;
218*0b459c2cSDavid du Colombier   register char *buffer;
219*0b459c2cSDavid du Colombier   register LINENUM iline;
220*0b459c2cSDavid du Colombier   size_t size = instat.st_size;
221*0b459c2cSDavid du Colombier 
222*0b459c2cSDavid du Colombier   /* Fail if the file size doesn't fit in a size_t,
223*0b459c2cSDavid du Colombier      or if storage isn't available.  */
224*0b459c2cSDavid du Colombier   if (! (size == instat.st_size
225*0b459c2cSDavid du Colombier 	 && (buffer = malloc (size ? size : (size_t) 1))))
226*0b459c2cSDavid du Colombier     return FALSE;
227*0b459c2cSDavid du Colombier 
228*0b459c2cSDavid du Colombier   /* Read the input file, but don't bother reading it if it's empty.
229*0b459c2cSDavid du Colombier      When creating files, the files do not actually exist.  */
230*0b459c2cSDavid du Colombier   if (size)
231*0b459c2cSDavid du Colombier     {
232*0b459c2cSDavid du Colombier       int ifd = open (filename, O_RDONLY|binary_transput);
233*0b459c2cSDavid du Colombier       size_t buffered = 0, n;
234*0b459c2cSDavid du Colombier       if (ifd < 0)
235*0b459c2cSDavid du Colombier 	pfatal ("can't open file `%s'", filename);
236*0b459c2cSDavid du Colombier 
237*0b459c2cSDavid du Colombier       while (size - buffered != 0)
238*0b459c2cSDavid du Colombier 	{
239*0b459c2cSDavid du Colombier 	  n = read (ifd, buffer + buffered, size - buffered);
240*0b459c2cSDavid du Colombier 	  if (n == 0)
241*0b459c2cSDavid du Colombier 	    {
242*0b459c2cSDavid du Colombier 	      /* Some non-POSIX hosts exaggerate st_size in text mode;
243*0b459c2cSDavid du Colombier 		 or the file may have shrunk!  */
244*0b459c2cSDavid du Colombier 	      size = buffered;
245*0b459c2cSDavid du Colombier 	      break;
246*0b459c2cSDavid du Colombier 	    }
247*0b459c2cSDavid du Colombier 	  if (n == (size_t) -1)
248*0b459c2cSDavid du Colombier 	    {
249*0b459c2cSDavid du Colombier 	      /* Perhaps size is too large for this host.  */
250*0b459c2cSDavid du Colombier 	      close (ifd);
251*0b459c2cSDavid du Colombier 	      free (buffer);
252*0b459c2cSDavid du Colombier 	      return FALSE;
253*0b459c2cSDavid du Colombier 	    }
254*0b459c2cSDavid du Colombier 	  buffered += n;
255*0b459c2cSDavid du Colombier 	}
256*0b459c2cSDavid du Colombier 
257*0b459c2cSDavid du Colombier       if (close (ifd) != 0)
258*0b459c2cSDavid du Colombier 	read_fatal ();
259*0b459c2cSDavid du Colombier     }
260*0b459c2cSDavid du Colombier 
261*0b459c2cSDavid du Colombier   /* Scan the buffer and build array of pointers to lines.  */
262*0b459c2cSDavid du Colombier   lim = buffer + size;
263*0b459c2cSDavid du Colombier   iline = 3; /* 1 unused, 1 for SOF, 1 for EOF if last line is incomplete */
264*0b459c2cSDavid du Colombier   for (s = buffer;  (s = (char *) memchr (s, '\n', lim - s));  s++)
265*0b459c2cSDavid du Colombier     if (++iline < 0)
266*0b459c2cSDavid du Colombier       too_many_lines (filename);
267*0b459c2cSDavid du Colombier   if (! (iline == (size_t) iline
268*0b459c2cSDavid du Colombier 	 && (size_t) iline * sizeof *ptr / sizeof *ptr == (size_t) iline
269*0b459c2cSDavid du Colombier 	 && (ptr = (char const **) malloc ((size_t) iline * sizeof *ptr))))
270*0b459c2cSDavid du Colombier     {
271*0b459c2cSDavid du Colombier       free (buffer);
272*0b459c2cSDavid du Colombier       return FALSE;
273*0b459c2cSDavid du Colombier     }
274*0b459c2cSDavid du Colombier   iline = 0;
275*0b459c2cSDavid du Colombier   for (s = buffer;  ;  s++)
276*0b459c2cSDavid du Colombier     {
277*0b459c2cSDavid du Colombier       ptr[++iline] = s;
278*0b459c2cSDavid du Colombier       if (! (s = (char *) memchr (s, '\n', lim - s)))
279*0b459c2cSDavid du Colombier 	break;
280*0b459c2cSDavid du Colombier     }
281*0b459c2cSDavid du Colombier   if (size && lim[-1] != '\n')
282*0b459c2cSDavid du Colombier     ptr[++iline] = lim;
283*0b459c2cSDavid du Colombier   input_lines = iline - 1;
284*0b459c2cSDavid du Colombier 
285*0b459c2cSDavid du Colombier   if (revision)
286*0b459c2cSDavid du Colombier     {
287*0b459c2cSDavid du Colombier       char const *rev = revision;
288*0b459c2cSDavid du Colombier       int rev0 = rev[0];
289*0b459c2cSDavid du Colombier       int found_revision = 0;
290*0b459c2cSDavid du Colombier       size_t revlen = strlen (rev);
291*0b459c2cSDavid du Colombier 
292*0b459c2cSDavid du Colombier       if (revlen <= size)
293*0b459c2cSDavid du Colombier 	{
294*0b459c2cSDavid du Colombier 	  char const *limrev = lim - revlen;
295*0b459c2cSDavid du Colombier 
296*0b459c2cSDavid du Colombier 	  for (s = buffer;  (s = (char *) memchr (s, rev0, limrev - s));  s++)
297*0b459c2cSDavid du Colombier 	    if (memcmp (s, rev, revlen) == 0
298*0b459c2cSDavid du Colombier 		&& (s == buffer || ISSPACE ((unsigned char) s[-1]))
299*0b459c2cSDavid du Colombier 		&& (s + 1 == limrev || ISSPACE ((unsigned char) s[revlen])))
300*0b459c2cSDavid du Colombier 	      {
301*0b459c2cSDavid du Colombier 		found_revision = 1;
302*0b459c2cSDavid du Colombier 		break;
303*0b459c2cSDavid du Colombier 	      }
304*0b459c2cSDavid du Colombier 	}
305*0b459c2cSDavid du Colombier 
306*0b459c2cSDavid du Colombier       report_revision (found_revision);
307*0b459c2cSDavid du Colombier     }
308*0b459c2cSDavid du Colombier 
309*0b459c2cSDavid du Colombier   /* Plan A will work.  */
310*0b459c2cSDavid du Colombier   i_buffer = buffer;
311*0b459c2cSDavid du Colombier   i_ptr = ptr;
312*0b459c2cSDavid du Colombier   return TRUE;
313*0b459c2cSDavid du Colombier }
314*0b459c2cSDavid du Colombier 
315*0b459c2cSDavid du Colombier /* Keep (virtually) nothing in memory. */
316*0b459c2cSDavid du Colombier 
317*0b459c2cSDavid du Colombier static void
plan_b(filename)318*0b459c2cSDavid du Colombier plan_b(filename)
319*0b459c2cSDavid du Colombier      char const *filename;
320*0b459c2cSDavid du Colombier {
321*0b459c2cSDavid du Colombier   register FILE *ifp;
322*0b459c2cSDavid du Colombier   register int c;
323*0b459c2cSDavid du Colombier   register size_t len;
324*0b459c2cSDavid du Colombier   register size_t maxlen;
325*0b459c2cSDavid du Colombier   register int found_revision;
326*0b459c2cSDavid du Colombier   register size_t i;
327*0b459c2cSDavid du Colombier   register char const *rev;
328*0b459c2cSDavid du Colombier   register size_t revlen;
329*0b459c2cSDavid du Colombier   register LINENUM line = 1;
330*0b459c2cSDavid du Colombier 
331*0b459c2cSDavid du Colombier   if (instat.st_size == 0)
332*0b459c2cSDavid du Colombier     filename = NULL_DEVICE;
333*0b459c2cSDavid du Colombier   if (! (ifp = fopen (filename, binary_transput ? "rb" : "r")))
334*0b459c2cSDavid du Colombier     pfatal ("can't open file `%s'", filename);
335*0b459c2cSDavid du Colombier   tifd = create_file (TMPINNAME, O_RDWR | O_BINARY, (mode_t) 0);
336*0b459c2cSDavid du Colombier   i = 0;
337*0b459c2cSDavid du Colombier   len = 0;
338*0b459c2cSDavid du Colombier   maxlen = 1;
339*0b459c2cSDavid du Colombier   rev = revision;
340*0b459c2cSDavid du Colombier   found_revision = !rev;
341*0b459c2cSDavid du Colombier   revlen = rev ? strlen (rev) : 0;
342*0b459c2cSDavid du Colombier 
343*0b459c2cSDavid du Colombier   while ((c = getc (ifp)) != EOF)
344*0b459c2cSDavid du Colombier     {
345*0b459c2cSDavid du Colombier       len++;
346*0b459c2cSDavid du Colombier 
347*0b459c2cSDavid du Colombier       if (c == '\n')
348*0b459c2cSDavid du Colombier 	{
349*0b459c2cSDavid du Colombier 	  if (++line < 0)
350*0b459c2cSDavid du Colombier 	    too_many_lines (filename);
351*0b459c2cSDavid du Colombier 	  if (maxlen < len)
352*0b459c2cSDavid du Colombier 	      maxlen = len;
353*0b459c2cSDavid du Colombier 	  len = 0;
354*0b459c2cSDavid du Colombier 	}
355*0b459c2cSDavid du Colombier 
356*0b459c2cSDavid du Colombier       if (!found_revision)
357*0b459c2cSDavid du Colombier 	{
358*0b459c2cSDavid du Colombier 	  if (i == revlen)
359*0b459c2cSDavid du Colombier 	    {
360*0b459c2cSDavid du Colombier 	      found_revision = ISSPACE ((unsigned char) c);
361*0b459c2cSDavid du Colombier 	      i = (size_t) -1;
362*0b459c2cSDavid du Colombier 	    }
363*0b459c2cSDavid du Colombier 	  else if (i != (size_t) -1)
364*0b459c2cSDavid du Colombier 	    i = rev[i]==c ? i + 1 : (size_t) -1;
365*0b459c2cSDavid du Colombier 
366*0b459c2cSDavid du Colombier 	  if (i == (size_t) -1  &&  ISSPACE ((unsigned char) c))
367*0b459c2cSDavid du Colombier 	    i = 0;
368*0b459c2cSDavid du Colombier 	}
369*0b459c2cSDavid du Colombier     }
370*0b459c2cSDavid du Colombier 
371*0b459c2cSDavid du Colombier   if (revision)
372*0b459c2cSDavid du Colombier     report_revision (found_revision);
373*0b459c2cSDavid du Colombier   Fseek (ifp, (off_t) 0, SEEK_SET);		/* rewind file */
374*0b459c2cSDavid du Colombier   for (tibufsize = TIBUFSIZE_MINIMUM;  tibufsize < maxlen;  tibufsize <<= 1)
375*0b459c2cSDavid du Colombier     continue;
376*0b459c2cSDavid du Colombier   lines_per_buf = tibufsize / maxlen;
377*0b459c2cSDavid du Colombier   tireclen = maxlen;
378*0b459c2cSDavid du Colombier   tibuf[0] = xmalloc (2 * tibufsize);
379*0b459c2cSDavid du Colombier   tibuf[1] = tibuf[0] + tibufsize;
380*0b459c2cSDavid du Colombier 
381*0b459c2cSDavid du Colombier   for (line = 1; ; line++)
382*0b459c2cSDavid du Colombier     {
383*0b459c2cSDavid du Colombier       char *p = tibuf[0] + maxlen * (line % lines_per_buf);
384*0b459c2cSDavid du Colombier       char const *p0 = p;
385*0b459c2cSDavid du Colombier       if (! (line % lines_per_buf))	/* new block */
386*0b459c2cSDavid du Colombier 	if (write (tifd, tibuf[0], tibufsize) != tibufsize)
387*0b459c2cSDavid du Colombier 	  write_fatal ();
388*0b459c2cSDavid du Colombier       if ((c = getc (ifp)) == EOF)
389*0b459c2cSDavid du Colombier 	break;
390*0b459c2cSDavid du Colombier 
391*0b459c2cSDavid du Colombier       for (;;)
392*0b459c2cSDavid du Colombier 	{
393*0b459c2cSDavid du Colombier 	  *p++ = c;
394*0b459c2cSDavid du Colombier 	  if (c == '\n')
395*0b459c2cSDavid du Colombier 	    {
396*0b459c2cSDavid du Colombier 	      last_line_size = p - p0;
397*0b459c2cSDavid du Colombier 	      break;
398*0b459c2cSDavid du Colombier 	    }
399*0b459c2cSDavid du Colombier 
400*0b459c2cSDavid du Colombier 	  if ((c = getc (ifp)) == EOF)
401*0b459c2cSDavid du Colombier 	    {
402*0b459c2cSDavid du Colombier 	      last_line_size = p - p0;
403*0b459c2cSDavid du Colombier 	      line++;
404*0b459c2cSDavid du Colombier 	      goto EOF_reached;
405*0b459c2cSDavid du Colombier 	    }
406*0b459c2cSDavid du Colombier 	}
407*0b459c2cSDavid du Colombier     }
408*0b459c2cSDavid du Colombier  EOF_reached:
409*0b459c2cSDavid du Colombier   if (ferror (ifp)  ||  fclose (ifp) != 0)
410*0b459c2cSDavid du Colombier     read_fatal ();
411*0b459c2cSDavid du Colombier 
412*0b459c2cSDavid du Colombier   if (line % lines_per_buf  !=  0)
413*0b459c2cSDavid du Colombier     if (write (tifd, tibuf[0], tibufsize) != tibufsize)
414*0b459c2cSDavid du Colombier       write_fatal ();
415*0b459c2cSDavid du Colombier   input_lines = line - 1;
416*0b459c2cSDavid du Colombier }
417*0b459c2cSDavid du Colombier 
418*0b459c2cSDavid du Colombier /* Fetch a line from the input file. */
419*0b459c2cSDavid du Colombier 
420*0b459c2cSDavid du Colombier char const *
ifetch(line,whichbuf,psize)421*0b459c2cSDavid du Colombier ifetch (line, whichbuf, psize)
422*0b459c2cSDavid du Colombier register LINENUM line;
423*0b459c2cSDavid du Colombier int whichbuf;				/* ignored when file in memory */
424*0b459c2cSDavid du Colombier size_t *psize;
425*0b459c2cSDavid du Colombier {
426*0b459c2cSDavid du Colombier     register char const *q;
427*0b459c2cSDavid du Colombier     register char const *p;
428*0b459c2cSDavid du Colombier 
429*0b459c2cSDavid du Colombier     if (line < 1 || line > input_lines) {
430*0b459c2cSDavid du Colombier 	*psize = 0;
431*0b459c2cSDavid du Colombier 	return "";
432*0b459c2cSDavid du Colombier     }
433*0b459c2cSDavid du Colombier     if (using_plan_a) {
434*0b459c2cSDavid du Colombier 	p = i_ptr[line];
435*0b459c2cSDavid du Colombier 	*psize = i_ptr[line + 1] - p;
436*0b459c2cSDavid du Colombier 	return p;
437*0b459c2cSDavid du Colombier     } else {
438*0b459c2cSDavid du Colombier 	LINENUM offline = line % lines_per_buf;
439*0b459c2cSDavid du Colombier 	LINENUM baseline = line - offline;
440*0b459c2cSDavid du Colombier 
441*0b459c2cSDavid du Colombier 	if (tiline[0] == baseline)
442*0b459c2cSDavid du Colombier 	    whichbuf = 0;
443*0b459c2cSDavid du Colombier 	else if (tiline[1] == baseline)
444*0b459c2cSDavid du Colombier 	    whichbuf = 1;
445*0b459c2cSDavid du Colombier 	else {
446*0b459c2cSDavid du Colombier 	    tiline[whichbuf] = baseline;
447*0b459c2cSDavid du Colombier 	    if (lseek (tifd, (off_t) (baseline/lines_per_buf * tibufsize),
448*0b459c2cSDavid du Colombier 		       SEEK_SET) == -1
449*0b459c2cSDavid du Colombier 		|| read (tifd, tibuf[whichbuf], tibufsize) < 0)
450*0b459c2cSDavid du Colombier 	      read_fatal ();
451*0b459c2cSDavid du Colombier 	}
452*0b459c2cSDavid du Colombier 	p = tibuf[whichbuf] + (tireclen*offline);
453*0b459c2cSDavid du Colombier 	if (line == input_lines)
454*0b459c2cSDavid du Colombier 	    *psize = last_line_size;
455*0b459c2cSDavid du Colombier 	else {
456*0b459c2cSDavid du Colombier 	    for (q = p;  *q++ != '\n';  )
457*0b459c2cSDavid du Colombier 		continue;
458*0b459c2cSDavid du Colombier 	    *psize = q - p;
459*0b459c2cSDavid du Colombier 	}
460*0b459c2cSDavid du Colombier 	return p;
461*0b459c2cSDavid du Colombier     }
462*0b459c2cSDavid du Colombier }
463