xref: /minix3/external/bsd/less/dist/ch.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: ch.c,v 1.4 2013/09/04 19:44:21 tron Exp $	*/
2f7cf2976SLionel Sambuc 
3f7cf2976SLionel Sambuc /*
4*84d9c625SLionel Sambuc  * Copyright (C) 1984-2012  Mark Nudelman
5f7cf2976SLionel Sambuc  *
6f7cf2976SLionel Sambuc  * You may distribute under the terms of either the GNU General Public
7f7cf2976SLionel Sambuc  * License or the Less License, as specified in the README file.
8f7cf2976SLionel Sambuc  *
9*84d9c625SLionel Sambuc  * For more information, see the README file.
10f7cf2976SLionel Sambuc  */
11f7cf2976SLionel Sambuc 
12f7cf2976SLionel Sambuc 
13f7cf2976SLionel Sambuc /*
14f7cf2976SLionel Sambuc  * Low level character input from the input file.
15f7cf2976SLionel Sambuc  * We use these special purpose routines which optimize moving
16f7cf2976SLionel Sambuc  * both forward and backward from the current read pointer.
17f7cf2976SLionel Sambuc  */
18f7cf2976SLionel Sambuc 
19f7cf2976SLionel Sambuc #include "less.h"
20f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C
21f7cf2976SLionel Sambuc #include <errno.h>
22f7cf2976SLionel Sambuc #include <windows.h>
23f7cf2976SLionel Sambuc #endif
24f7cf2976SLionel Sambuc 
25f7cf2976SLionel Sambuc #if HAVE_STAT_INO
26f7cf2976SLionel Sambuc #include <sys/stat.h>
27f7cf2976SLionel Sambuc extern dev_t curr_dev;
28f7cf2976SLionel Sambuc extern ino_t curr_ino;
29f7cf2976SLionel Sambuc #endif
30f7cf2976SLionel Sambuc 
31f7cf2976SLionel Sambuc typedef POSITION BLOCKNUM;
32f7cf2976SLionel Sambuc 
33f7cf2976SLionel Sambuc public int ignore_eoi;
34f7cf2976SLionel Sambuc 
35f7cf2976SLionel Sambuc /*
36f7cf2976SLionel Sambuc  * Pool of buffers holding the most recently used blocks of the input file.
37f7cf2976SLionel Sambuc  * The buffer pool is kept as a doubly-linked circular list,
38f7cf2976SLionel Sambuc  * in order from most- to least-recently used.
39f7cf2976SLionel Sambuc  * The circular list is anchored by the file state "thisfile".
40f7cf2976SLionel Sambuc  */
41f7cf2976SLionel Sambuc struct bufnode {
42f7cf2976SLionel Sambuc 	struct bufnode *next, *prev;
43f7cf2976SLionel Sambuc 	struct bufnode *hnext, *hprev;
44f7cf2976SLionel Sambuc };
45f7cf2976SLionel Sambuc 
46f7cf2976SLionel Sambuc #define	LBUFSIZE	8192
47f7cf2976SLionel Sambuc struct buf {
48f7cf2976SLionel Sambuc 	struct bufnode node;
49f7cf2976SLionel Sambuc 	BLOCKNUM block;
50f7cf2976SLionel Sambuc 	unsigned int datasize;
51f7cf2976SLionel Sambuc 	unsigned char data[LBUFSIZE];
52f7cf2976SLionel Sambuc };
53f7cf2976SLionel Sambuc #define bufnode_buf(bn)  ((struct buf *) bn)
54f7cf2976SLionel Sambuc 
55f7cf2976SLionel Sambuc /*
56f7cf2976SLionel Sambuc  * The file state is maintained in a filestate structure.
57f7cf2976SLionel Sambuc  * A pointer to the filestate is kept in the ifile structure.
58f7cf2976SLionel Sambuc  */
59f7cf2976SLionel Sambuc #define	BUFHASH_SIZE	64
60f7cf2976SLionel Sambuc struct filestate {
61f7cf2976SLionel Sambuc 	struct bufnode buflist;
62f7cf2976SLionel Sambuc 	struct bufnode hashtbl[BUFHASH_SIZE];
63f7cf2976SLionel Sambuc 	int file;
64f7cf2976SLionel Sambuc 	int flags;
65f7cf2976SLionel Sambuc 	POSITION fpos;
66f7cf2976SLionel Sambuc 	int nbufs;
67f7cf2976SLionel Sambuc 	BLOCKNUM block;
68f7cf2976SLionel Sambuc 	unsigned int offset;
69f7cf2976SLionel Sambuc 	POSITION fsize;
70f7cf2976SLionel Sambuc };
71f7cf2976SLionel Sambuc 
72f7cf2976SLionel Sambuc #define	ch_bufhead	thisfile->buflist.next
73f7cf2976SLionel Sambuc #define	ch_buftail	thisfile->buflist.prev
74f7cf2976SLionel Sambuc #define	ch_nbufs	thisfile->nbufs
75f7cf2976SLionel Sambuc #define	ch_block	thisfile->block
76f7cf2976SLionel Sambuc #define	ch_offset	thisfile->offset
77f7cf2976SLionel Sambuc #define	ch_fpos		thisfile->fpos
78f7cf2976SLionel Sambuc #define	ch_fsize	thisfile->fsize
79f7cf2976SLionel Sambuc #define	ch_flags	thisfile->flags
80f7cf2976SLionel Sambuc #define	ch_file		thisfile->file
81f7cf2976SLionel Sambuc 
82f7cf2976SLionel Sambuc #define	END_OF_CHAIN	(&thisfile->buflist)
83f7cf2976SLionel Sambuc #define	END_OF_HCHAIN(h) (&thisfile->hashtbl[h])
84f7cf2976SLionel Sambuc #define BUFHASH(blk)	((blk) & (BUFHASH_SIZE-1))
85f7cf2976SLionel Sambuc 
86f7cf2976SLionel Sambuc /*
87f7cf2976SLionel Sambuc  * Macros to manipulate the list of buffers in thisfile->buflist.
88f7cf2976SLionel Sambuc  */
89f7cf2976SLionel Sambuc #define	FOR_BUFS(bn) \
90f7cf2976SLionel Sambuc 	for (bn = ch_bufhead;  bn != END_OF_CHAIN;  bn = bn->next)
91f7cf2976SLionel Sambuc 
92f7cf2976SLionel Sambuc #define BUF_RM(bn) \
93f7cf2976SLionel Sambuc 	(bn)->next->prev = (bn)->prev; \
94f7cf2976SLionel Sambuc 	(bn)->prev->next = (bn)->next;
95f7cf2976SLionel Sambuc 
96f7cf2976SLionel Sambuc #define BUF_INS_HEAD(bn) \
97f7cf2976SLionel Sambuc 	(bn)->next = ch_bufhead; \
98f7cf2976SLionel Sambuc 	(bn)->prev = END_OF_CHAIN; \
99f7cf2976SLionel Sambuc 	ch_bufhead->prev = (bn); \
100f7cf2976SLionel Sambuc 	ch_bufhead = (bn);
101f7cf2976SLionel Sambuc 
102f7cf2976SLionel Sambuc #define BUF_INS_TAIL(bn) \
103f7cf2976SLionel Sambuc 	(bn)->next = END_OF_CHAIN; \
104f7cf2976SLionel Sambuc 	(bn)->prev = ch_buftail; \
105f7cf2976SLionel Sambuc 	ch_buftail->next = (bn); \
106f7cf2976SLionel Sambuc 	ch_buftail = (bn);
107f7cf2976SLionel Sambuc 
108f7cf2976SLionel Sambuc /*
109f7cf2976SLionel Sambuc  * Macros to manipulate the list of buffers in thisfile->hashtbl[n].
110f7cf2976SLionel Sambuc  */
111f7cf2976SLionel Sambuc #define	FOR_BUFS_IN_CHAIN(h,bn) \
112f7cf2976SLionel Sambuc 	for (bn = thisfile->hashtbl[h].hnext;  \
113f7cf2976SLionel Sambuc 	     bn != END_OF_HCHAIN(h);  bn = bn->hnext)
114f7cf2976SLionel Sambuc 
115f7cf2976SLionel Sambuc #define	BUF_HASH_RM(bn) \
116f7cf2976SLionel Sambuc 	(bn)->hnext->hprev = (bn)->hprev; \
117f7cf2976SLionel Sambuc 	(bn)->hprev->hnext = (bn)->hnext;
118f7cf2976SLionel Sambuc 
119f7cf2976SLionel Sambuc #define	BUF_HASH_INS(bn,h) \
120f7cf2976SLionel Sambuc 	(bn)->hnext = thisfile->hashtbl[h].hnext; \
121f7cf2976SLionel Sambuc 	(bn)->hprev = END_OF_HCHAIN(h); \
122f7cf2976SLionel Sambuc 	thisfile->hashtbl[h].hnext->hprev = (bn); \
123f7cf2976SLionel Sambuc 	thisfile->hashtbl[h].hnext = (bn);
124f7cf2976SLionel Sambuc 
125f7cf2976SLionel Sambuc static struct filestate *thisfile;
126f7cf2976SLionel Sambuc static int ch_ungotchar = -1;
127f7cf2976SLionel Sambuc static int maxbufs = -1;
128f7cf2976SLionel Sambuc 
129f7cf2976SLionel Sambuc extern int autobuf;
130f7cf2976SLionel Sambuc extern int sigs;
131f7cf2976SLionel Sambuc extern int secure;
132f7cf2976SLionel Sambuc extern int screen_trashed;
133f7cf2976SLionel Sambuc extern int follow_mode;
134f7cf2976SLionel Sambuc extern constant char helpdata[];
135f7cf2976SLionel Sambuc extern constant int size_helpdata;
136f7cf2976SLionel Sambuc extern IFILE curr_ifile;
137f7cf2976SLionel Sambuc #if LOGFILE
138f7cf2976SLionel Sambuc extern int logfile;
139f7cf2976SLionel Sambuc extern char *namelogfile;
140f7cf2976SLionel Sambuc #endif
141f7cf2976SLionel Sambuc 
142f7cf2976SLionel Sambuc static int ch_addbuf __P((void));
143f7cf2976SLionel Sambuc static int buffered __P((BLOCKNUM));
144f7cf2976SLionel Sambuc static void ch_delbufs __P((void));
145f7cf2976SLionel Sambuc 
146f7cf2976SLionel Sambuc 
147f7cf2976SLionel Sambuc /*
148f7cf2976SLionel Sambuc  * Get the character pointed to by the read pointer.
149f7cf2976SLionel Sambuc  */
150f7cf2976SLionel Sambuc 	int
ch_get()151f7cf2976SLionel Sambuc ch_get()
152f7cf2976SLionel Sambuc {
153f7cf2976SLionel Sambuc 	register struct buf *bp;
154f7cf2976SLionel Sambuc 	register struct bufnode *bn;
155f7cf2976SLionel Sambuc 	register int n;
156f7cf2976SLionel Sambuc 	register int slept;
157f7cf2976SLionel Sambuc 	register int h;
158f7cf2976SLionel Sambuc 	POSITION pos;
159f7cf2976SLionel Sambuc 	POSITION len;
160f7cf2976SLionel Sambuc 
161f7cf2976SLionel Sambuc 	if (thisfile == NULL)
162f7cf2976SLionel Sambuc 		return (EOI);
163f7cf2976SLionel Sambuc 
164f7cf2976SLionel Sambuc 	/*
165f7cf2976SLionel Sambuc 	 * Quick check for the common case where
166f7cf2976SLionel Sambuc 	 * the desired char is in the head buffer.
167f7cf2976SLionel Sambuc 	 */
168f7cf2976SLionel Sambuc 	if (ch_bufhead != END_OF_CHAIN)
169f7cf2976SLionel Sambuc 	{
170f7cf2976SLionel Sambuc 		bp = bufnode_buf(ch_bufhead);
171f7cf2976SLionel Sambuc 		if (ch_block == bp->block && ch_offset < bp->datasize)
172f7cf2976SLionel Sambuc 			return bp->data[ch_offset];
173f7cf2976SLionel Sambuc 	}
174f7cf2976SLionel Sambuc 
175f7cf2976SLionel Sambuc 	slept = FALSE;
176f7cf2976SLionel Sambuc 
177f7cf2976SLionel Sambuc 	/*
178f7cf2976SLionel Sambuc 	 * Look for a buffer holding the desired block.
179f7cf2976SLionel Sambuc 	 */
180f7cf2976SLionel Sambuc 	h = BUFHASH(ch_block);
181f7cf2976SLionel Sambuc 	FOR_BUFS_IN_CHAIN(h, bn)
182f7cf2976SLionel Sambuc 	{
183f7cf2976SLionel Sambuc 		bp = bufnode_buf(bn);
184f7cf2976SLionel Sambuc 		if (bp->block == ch_block)
185f7cf2976SLionel Sambuc 		{
186f7cf2976SLionel Sambuc 			if (ch_offset >= bp->datasize)
187f7cf2976SLionel Sambuc 				/*
188f7cf2976SLionel Sambuc 				 * Need more data in this buffer.
189f7cf2976SLionel Sambuc 				 */
190f7cf2976SLionel Sambuc 				break;
191f7cf2976SLionel Sambuc 			goto found;
192f7cf2976SLionel Sambuc 		}
193f7cf2976SLionel Sambuc 	}
194f7cf2976SLionel Sambuc 	if (bn == END_OF_HCHAIN(h))
195f7cf2976SLionel Sambuc 	{
196f7cf2976SLionel Sambuc 		/*
197f7cf2976SLionel Sambuc 		 * Block is not in a buffer.
198f7cf2976SLionel Sambuc 		 * Take the least recently used buffer
199f7cf2976SLionel Sambuc 		 * and read the desired block into it.
200f7cf2976SLionel Sambuc 		 * If the LRU buffer has data in it,
201f7cf2976SLionel Sambuc 		 * then maybe allocate a new buffer.
202f7cf2976SLionel Sambuc 		 */
203f7cf2976SLionel Sambuc 		if (ch_buftail == END_OF_CHAIN ||
204f7cf2976SLionel Sambuc 			bufnode_buf(ch_buftail)->block != -1)
205f7cf2976SLionel Sambuc 		{
206f7cf2976SLionel Sambuc 			/*
207f7cf2976SLionel Sambuc 			 * There is no empty buffer to use.
208f7cf2976SLionel Sambuc 			 * Allocate a new buffer if:
209f7cf2976SLionel Sambuc 			 * 1. We can't seek on this file and -b is not in effect; or
210f7cf2976SLionel Sambuc 			 * 2. We haven't allocated the max buffers for this file yet.
211f7cf2976SLionel Sambuc 			 */
212f7cf2976SLionel Sambuc 			if ((autobuf && !(ch_flags & CH_CANSEEK)) ||
213f7cf2976SLionel Sambuc 				(maxbufs < 0 || ch_nbufs < maxbufs))
214f7cf2976SLionel Sambuc 				if (ch_addbuf())
215f7cf2976SLionel Sambuc 					/*
216f7cf2976SLionel Sambuc 					 * Allocation failed: turn off autobuf.
217f7cf2976SLionel Sambuc 					 */
218f7cf2976SLionel Sambuc 					autobuf = OPT_OFF;
219f7cf2976SLionel Sambuc 		}
220f7cf2976SLionel Sambuc 		bn = ch_buftail;
221f7cf2976SLionel Sambuc 		bp = bufnode_buf(bn);
222f7cf2976SLionel Sambuc 		BUF_HASH_RM(bn); /* Remove from old hash chain. */
223f7cf2976SLionel Sambuc 		bp->block = ch_block;
224f7cf2976SLionel Sambuc 		bp->datasize = 0;
225f7cf2976SLionel Sambuc 		BUF_HASH_INS(bn, h); /* Insert into new hash chain. */
226f7cf2976SLionel Sambuc 	}
227f7cf2976SLionel Sambuc 
228f7cf2976SLionel Sambuc     read_more:
229f7cf2976SLionel Sambuc 	pos = (ch_block * LBUFSIZE) + bp->datasize;
230f7cf2976SLionel Sambuc 	if ((len = ch_length()) != NULL_POSITION && pos >= len)
231f7cf2976SLionel Sambuc 		/*
232f7cf2976SLionel Sambuc 		 * At end of file.
233f7cf2976SLionel Sambuc 		 */
234f7cf2976SLionel Sambuc 		return (EOI);
235f7cf2976SLionel Sambuc 
236f7cf2976SLionel Sambuc 	if (pos != ch_fpos)
237f7cf2976SLionel Sambuc 	{
238f7cf2976SLionel Sambuc 		/*
239f7cf2976SLionel Sambuc 		 * Not at the correct position: must seek.
240f7cf2976SLionel Sambuc 		 * If input is a pipe, we're in trouble (can't seek on a pipe).
241f7cf2976SLionel Sambuc 		 * Some data has been lost: just return "?".
242f7cf2976SLionel Sambuc 		 */
243f7cf2976SLionel Sambuc 		if (!(ch_flags & CH_CANSEEK))
244f7cf2976SLionel Sambuc 			return ('?');
245f7cf2976SLionel Sambuc 		if (lseek(ch_file, (off_t)pos, SEEK_SET) == BAD_LSEEK)
246f7cf2976SLionel Sambuc 		{
247f7cf2976SLionel Sambuc  			error("seek error", NULL_PARG);
248f7cf2976SLionel Sambuc 			clear_eol();
249f7cf2976SLionel Sambuc 			return (EOI);
250f7cf2976SLionel Sambuc  		}
251f7cf2976SLionel Sambuc  		ch_fpos = pos;
252f7cf2976SLionel Sambuc  	}
253f7cf2976SLionel Sambuc 
254f7cf2976SLionel Sambuc 	/*
255f7cf2976SLionel Sambuc 	 * Read the block.
256f7cf2976SLionel Sambuc 	 * If we read less than a full block, that's ok.
257f7cf2976SLionel Sambuc 	 * We use partial block and pick up the rest next time.
258f7cf2976SLionel Sambuc 	 */
259f7cf2976SLionel Sambuc 	if (ch_ungotchar != -1)
260f7cf2976SLionel Sambuc 	{
261f7cf2976SLionel Sambuc 		bp->data[bp->datasize] = ch_ungotchar;
262f7cf2976SLionel Sambuc 		n = 1;
263f7cf2976SLionel Sambuc 		ch_ungotchar = -1;
264f7cf2976SLionel Sambuc 	} else if (ch_flags & CH_HELPFILE)
265f7cf2976SLionel Sambuc 	{
266f7cf2976SLionel Sambuc 		bp->data[bp->datasize] = helpdata[ch_fpos];
267f7cf2976SLionel Sambuc 		n = 1;
268f7cf2976SLionel Sambuc 	} else
269f7cf2976SLionel Sambuc 	{
270f7cf2976SLionel Sambuc 		n = iread(ch_file, &bp->data[bp->datasize],
271f7cf2976SLionel Sambuc 			(unsigned int)(LBUFSIZE - bp->datasize));
272f7cf2976SLionel Sambuc 	}
273f7cf2976SLionel Sambuc 
274f7cf2976SLionel Sambuc 	if (n == READ_INTR)
275f7cf2976SLionel Sambuc 		return (EOI);
276f7cf2976SLionel Sambuc 	if (n < 0)
277f7cf2976SLionel Sambuc 	{
278f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C
279f7cf2976SLionel Sambuc 		if (errno != EPIPE)
280f7cf2976SLionel Sambuc #endif
281f7cf2976SLionel Sambuc 		{
282f7cf2976SLionel Sambuc 			error("read error", NULL_PARG);
283f7cf2976SLionel Sambuc 			clear_eol();
284f7cf2976SLionel Sambuc 		}
285f7cf2976SLionel Sambuc 		n = 0;
286f7cf2976SLionel Sambuc 	}
287f7cf2976SLionel Sambuc 
288f7cf2976SLionel Sambuc #if LOGFILE
289f7cf2976SLionel Sambuc 	/*
290f7cf2976SLionel Sambuc 	 * If we have a log file, write the new data to it.
291f7cf2976SLionel Sambuc 	 */
292f7cf2976SLionel Sambuc 	if (!secure && logfile >= 0 && n > 0)
293f7cf2976SLionel Sambuc 		write(logfile, (char *) &bp->data[bp->datasize], n);
294f7cf2976SLionel Sambuc #endif
295f7cf2976SLionel Sambuc 
296f7cf2976SLionel Sambuc 	ch_fpos += n;
297f7cf2976SLionel Sambuc 	bp->datasize += n;
298f7cf2976SLionel Sambuc 
299f7cf2976SLionel Sambuc 	/*
300f7cf2976SLionel Sambuc 	 * If we have read to end of file, set ch_fsize to indicate
301f7cf2976SLionel Sambuc 	 * the position of the end of file.
302f7cf2976SLionel Sambuc 	 */
303f7cf2976SLionel Sambuc 	if (n == 0)
304f7cf2976SLionel Sambuc 	{
305f7cf2976SLionel Sambuc 		ch_fsize = pos;
306f7cf2976SLionel Sambuc 		if (ignore_eoi)
307f7cf2976SLionel Sambuc 		{
308f7cf2976SLionel Sambuc 			/*
309f7cf2976SLionel Sambuc 			 * We are ignoring EOF.
310f7cf2976SLionel Sambuc 			 * Wait a while, then try again.
311f7cf2976SLionel Sambuc 			 */
312f7cf2976SLionel Sambuc 			if (!slept)
313f7cf2976SLionel Sambuc 			{
314f7cf2976SLionel Sambuc 				PARG parg;
315f7cf2976SLionel Sambuc 				parg.p_string = wait_message();
316f7cf2976SLionel Sambuc 				ierror("%s", &parg);
317f7cf2976SLionel Sambuc 			}
318f7cf2976SLionel Sambuc #if !MSDOS_COMPILER
319f7cf2976SLionel Sambuc 	 		sleep(1);
320f7cf2976SLionel Sambuc #else
321f7cf2976SLionel Sambuc #if MSDOS_COMPILER==WIN32C
322f7cf2976SLionel Sambuc 			Sleep(1000);
323f7cf2976SLionel Sambuc #endif
324f7cf2976SLionel Sambuc #endif
325f7cf2976SLionel Sambuc 			slept = TRUE;
326f7cf2976SLionel Sambuc 
327f7cf2976SLionel Sambuc #if HAVE_STAT_INO
328f7cf2976SLionel Sambuc 			if (follow_mode == FOLLOW_NAME)
329f7cf2976SLionel Sambuc 			{
330f7cf2976SLionel Sambuc 				/* See whether the file's i-number has changed.
331f7cf2976SLionel Sambuc 				 * If so, force the file to be closed and
332f7cf2976SLionel Sambuc 				 * reopened. */
333f7cf2976SLionel Sambuc 				struct stat st;
334f7cf2976SLionel Sambuc 				int r = stat(get_filename(curr_ifile), &st);
335f7cf2976SLionel Sambuc 				if (r == 0 && (st.st_ino != curr_ino ||
336f7cf2976SLionel Sambuc 					st.st_dev != curr_dev))
337f7cf2976SLionel Sambuc 				{
338f7cf2976SLionel Sambuc 					/* screen_trashed=2 causes
339f7cf2976SLionel Sambuc 					 * make_display to reopen the file. */
340f7cf2976SLionel Sambuc 					screen_trashed = 2;
341f7cf2976SLionel Sambuc 					return (EOI);
342f7cf2976SLionel Sambuc 				}
343f7cf2976SLionel Sambuc 			}
344f7cf2976SLionel Sambuc #endif
345f7cf2976SLionel Sambuc 		}
346f7cf2976SLionel Sambuc 		if (sigs)
347f7cf2976SLionel Sambuc 			return (EOI);
348f7cf2976SLionel Sambuc 	}
349f7cf2976SLionel Sambuc 
350f7cf2976SLionel Sambuc     found:
351f7cf2976SLionel Sambuc 	if (ch_bufhead != bn)
352f7cf2976SLionel Sambuc 	{
353f7cf2976SLionel Sambuc 		/*
354f7cf2976SLionel Sambuc 		 * Move the buffer to the head of the buffer chain.
355f7cf2976SLionel Sambuc 		 * This orders the buffer chain, most- to least-recently used.
356f7cf2976SLionel Sambuc 		 */
357f7cf2976SLionel Sambuc 		BUF_RM(bn);
358f7cf2976SLionel Sambuc 		BUF_INS_HEAD(bn);
359f7cf2976SLionel Sambuc 
360f7cf2976SLionel Sambuc 		/*
361f7cf2976SLionel Sambuc 		 * Move to head of hash chain too.
362f7cf2976SLionel Sambuc 		 */
363f7cf2976SLionel Sambuc 		BUF_HASH_RM(bn);
364f7cf2976SLionel Sambuc 		BUF_HASH_INS(bn, h);
365f7cf2976SLionel Sambuc 	}
366f7cf2976SLionel Sambuc 
367f7cf2976SLionel Sambuc 	if (ch_offset >= bp->datasize)
368f7cf2976SLionel Sambuc 		/*
369f7cf2976SLionel Sambuc 		 * After all that, we still don't have enough data.
370f7cf2976SLionel Sambuc 		 * Go back and try again.
371f7cf2976SLionel Sambuc 		 */
372f7cf2976SLionel Sambuc 		goto read_more;
373f7cf2976SLionel Sambuc 
374f7cf2976SLionel Sambuc 	return (bp->data[ch_offset]);
375f7cf2976SLionel Sambuc }
376f7cf2976SLionel Sambuc 
377f7cf2976SLionel Sambuc /*
378f7cf2976SLionel Sambuc  * ch_ungetchar is a rather kludgy and limited way to push
379f7cf2976SLionel Sambuc  * a single char onto an input file descriptor.
380f7cf2976SLionel Sambuc  */
381f7cf2976SLionel Sambuc 	public void
ch_ungetchar(c)382f7cf2976SLionel Sambuc ch_ungetchar(c)
383f7cf2976SLionel Sambuc 	int c;
384f7cf2976SLionel Sambuc {
385f7cf2976SLionel Sambuc 	if (c != -1 && ch_ungotchar != -1)
386f7cf2976SLionel Sambuc 		error("ch_ungetchar overrun", NULL_PARG);
387f7cf2976SLionel Sambuc 	ch_ungotchar = c;
388f7cf2976SLionel Sambuc }
389f7cf2976SLionel Sambuc 
390f7cf2976SLionel Sambuc #if LOGFILE
391f7cf2976SLionel Sambuc /*
392f7cf2976SLionel Sambuc  * Close the logfile.
393f7cf2976SLionel Sambuc  * If we haven't read all of standard input into it, do that now.
394f7cf2976SLionel Sambuc  */
395f7cf2976SLionel Sambuc 	public void
end_logfile()396f7cf2976SLionel Sambuc end_logfile()
397f7cf2976SLionel Sambuc {
398f7cf2976SLionel Sambuc 	static int tried = FALSE;
399f7cf2976SLionel Sambuc 
400f7cf2976SLionel Sambuc 	if (logfile < 0)
401f7cf2976SLionel Sambuc 		return;
402f7cf2976SLionel Sambuc 	if (!tried && ch_fsize == NULL_POSITION)
403f7cf2976SLionel Sambuc 	{
404f7cf2976SLionel Sambuc 		tried = TRUE;
405f7cf2976SLionel Sambuc 		ierror("Finishing logfile", NULL_PARG);
406f7cf2976SLionel Sambuc 		while (ch_forw_get() != EOI)
407f7cf2976SLionel Sambuc 			if (ABORT_SIGS())
408f7cf2976SLionel Sambuc 				break;
409f7cf2976SLionel Sambuc 	}
410f7cf2976SLionel Sambuc 	close(logfile);
411f7cf2976SLionel Sambuc 	logfile = -1;
412f7cf2976SLionel Sambuc 	namelogfile = NULL;
413f7cf2976SLionel Sambuc }
414f7cf2976SLionel Sambuc 
415f7cf2976SLionel Sambuc /*
416f7cf2976SLionel Sambuc  * Start a log file AFTER less has already been running.
417f7cf2976SLionel Sambuc  * Invoked from the - command; see toggle_option().
418f7cf2976SLionel Sambuc  * Write all the existing buffered data to the log file.
419f7cf2976SLionel Sambuc  */
420f7cf2976SLionel Sambuc 	public void
sync_logfile()421f7cf2976SLionel Sambuc sync_logfile()
422f7cf2976SLionel Sambuc {
423f7cf2976SLionel Sambuc 	register struct buf *bp;
424f7cf2976SLionel Sambuc 	register struct bufnode *bn;
425f7cf2976SLionel Sambuc 	int warned = FALSE;
426f7cf2976SLionel Sambuc 	BLOCKNUM block;
427f7cf2976SLionel Sambuc 	BLOCKNUM nblocks;
428f7cf2976SLionel Sambuc 
429f7cf2976SLionel Sambuc 	nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;
430f7cf2976SLionel Sambuc 	for (block = 0;  block < nblocks;  block++)
431f7cf2976SLionel Sambuc 	{
432f7cf2976SLionel Sambuc 		int wrote = FALSE;
433f7cf2976SLionel Sambuc 		FOR_BUFS(bn)
434f7cf2976SLionel Sambuc 		{
435f7cf2976SLionel Sambuc 			bp = bufnode_buf(bn);
436f7cf2976SLionel Sambuc 			if (bp->block == block)
437f7cf2976SLionel Sambuc 			{
438f7cf2976SLionel Sambuc 				write(logfile, (char *) bp->data, bp->datasize);
439f7cf2976SLionel Sambuc 				wrote = TRUE;
440f7cf2976SLionel Sambuc 				break;
441f7cf2976SLionel Sambuc 			}
442f7cf2976SLionel Sambuc 		}
443f7cf2976SLionel Sambuc 		if (!wrote && !warned)
444f7cf2976SLionel Sambuc 		{
445f7cf2976SLionel Sambuc 			error("Warning: log file is incomplete",
446f7cf2976SLionel Sambuc 				NULL_PARG);
447f7cf2976SLionel Sambuc 			warned = TRUE;
448f7cf2976SLionel Sambuc 		}
449f7cf2976SLionel Sambuc 	}
450f7cf2976SLionel Sambuc }
451f7cf2976SLionel Sambuc 
452f7cf2976SLionel Sambuc #endif
453f7cf2976SLionel Sambuc 
454f7cf2976SLionel Sambuc /*
455f7cf2976SLionel Sambuc  * Determine if a specific block is currently in one of the buffers.
456f7cf2976SLionel Sambuc  */
457f7cf2976SLionel Sambuc 	static int
buffered(block)458f7cf2976SLionel Sambuc buffered(block)
459f7cf2976SLionel Sambuc 	BLOCKNUM block;
460f7cf2976SLionel Sambuc {
461f7cf2976SLionel Sambuc 	register struct buf *bp;
462f7cf2976SLionel Sambuc 	register struct bufnode *bn;
463f7cf2976SLionel Sambuc 	register int h;
464f7cf2976SLionel Sambuc 
465f7cf2976SLionel Sambuc 	h = BUFHASH(block);
466f7cf2976SLionel Sambuc 	FOR_BUFS_IN_CHAIN(h, bn)
467f7cf2976SLionel Sambuc 	{
468f7cf2976SLionel Sambuc 		bp = bufnode_buf(bn);
469f7cf2976SLionel Sambuc 		if (bp->block == block)
470f7cf2976SLionel Sambuc 			return (TRUE);
471f7cf2976SLionel Sambuc 	}
472f7cf2976SLionel Sambuc 	return (FALSE);
473f7cf2976SLionel Sambuc }
474f7cf2976SLionel Sambuc 
475f7cf2976SLionel Sambuc /*
476f7cf2976SLionel Sambuc  * Seek to a specified position in the file.
477f7cf2976SLionel Sambuc  * Return 0 if successful, non-zero if can't seek there.
478f7cf2976SLionel Sambuc  */
479f7cf2976SLionel Sambuc 	public int
ch_seek(pos)480f7cf2976SLionel Sambuc ch_seek(pos)
481f7cf2976SLionel Sambuc 	register POSITION pos;
482f7cf2976SLionel Sambuc {
483f7cf2976SLionel Sambuc 	BLOCKNUM new_block;
484f7cf2976SLionel Sambuc 	POSITION len;
485f7cf2976SLionel Sambuc 
486f7cf2976SLionel Sambuc 	if (thisfile == NULL)
487f7cf2976SLionel Sambuc 		return (0);
488f7cf2976SLionel Sambuc 
489f7cf2976SLionel Sambuc 	len = ch_length();
490f7cf2976SLionel Sambuc 	if (pos < ch_zero() || (len != NULL_POSITION && pos > len))
491f7cf2976SLionel Sambuc 		return (1);
492f7cf2976SLionel Sambuc 
493f7cf2976SLionel Sambuc 	new_block = pos / LBUFSIZE;
494f7cf2976SLionel Sambuc 	if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos && !buffered(new_block))
495f7cf2976SLionel Sambuc 	{
496f7cf2976SLionel Sambuc 		if (ch_fpos > pos)
497f7cf2976SLionel Sambuc 			return (1);
498f7cf2976SLionel Sambuc 		while (ch_fpos < pos)
499f7cf2976SLionel Sambuc 		{
500f7cf2976SLionel Sambuc 			if (ch_forw_get() == EOI)
501f7cf2976SLionel Sambuc 				return (1);
502f7cf2976SLionel Sambuc 			if (ABORT_SIGS())
503f7cf2976SLionel Sambuc 				return (1);
504f7cf2976SLionel Sambuc 		}
505f7cf2976SLionel Sambuc 		return (0);
506f7cf2976SLionel Sambuc 	}
507f7cf2976SLionel Sambuc 	/*
508f7cf2976SLionel Sambuc 	 * Set read pointer.
509f7cf2976SLionel Sambuc 	 */
510f7cf2976SLionel Sambuc 	ch_block = new_block;
511f7cf2976SLionel Sambuc 	ch_offset = pos % LBUFSIZE;
512f7cf2976SLionel Sambuc 	return (0);
513f7cf2976SLionel Sambuc }
514f7cf2976SLionel Sambuc 
515f7cf2976SLionel Sambuc /*
516f7cf2976SLionel Sambuc  * Seek to the end of the file.
517f7cf2976SLionel Sambuc  */
518f7cf2976SLionel Sambuc 	public int
ch_end_seek()519f7cf2976SLionel Sambuc ch_end_seek()
520f7cf2976SLionel Sambuc {
521f7cf2976SLionel Sambuc 	POSITION len;
522f7cf2976SLionel Sambuc 
523f7cf2976SLionel Sambuc 	if (thisfile == NULL)
524f7cf2976SLionel Sambuc 		return (0);
525f7cf2976SLionel Sambuc 
526f7cf2976SLionel Sambuc 	if (ch_flags & CH_CANSEEK)
527f7cf2976SLionel Sambuc 		ch_fsize = filesize(ch_file);
528f7cf2976SLionel Sambuc 
529f7cf2976SLionel Sambuc 	len = ch_length();
530f7cf2976SLionel Sambuc 	if (len != NULL_POSITION)
531f7cf2976SLionel Sambuc 		return (ch_seek(len));
532f7cf2976SLionel Sambuc 
533f7cf2976SLionel Sambuc 	/*
534f7cf2976SLionel Sambuc 	 * Do it the slow way: read till end of data.
535f7cf2976SLionel Sambuc 	 */
536f7cf2976SLionel Sambuc 	while (ch_forw_get() != EOI)
537f7cf2976SLionel Sambuc 		if (ABORT_SIGS())
538f7cf2976SLionel Sambuc 			return (1);
539f7cf2976SLionel Sambuc 	return (0);
540f7cf2976SLionel Sambuc }
541f7cf2976SLionel Sambuc 
542f7cf2976SLionel Sambuc /*
543f7cf2976SLionel Sambuc  * Seek to the beginning of the file, or as close to it as we can get.
544f7cf2976SLionel Sambuc  * We may not be able to seek there if input is a pipe and the
545f7cf2976SLionel Sambuc  * beginning of the pipe is no longer buffered.
546f7cf2976SLionel Sambuc  */
547f7cf2976SLionel Sambuc 	public int
ch_beg_seek()548f7cf2976SLionel Sambuc ch_beg_seek()
549f7cf2976SLionel Sambuc {
550f7cf2976SLionel Sambuc 	register struct bufnode *bn;
551f7cf2976SLionel Sambuc 	register struct bufnode *firstbn;
552f7cf2976SLionel Sambuc 
553f7cf2976SLionel Sambuc 	/*
554f7cf2976SLionel Sambuc 	 * Try a plain ch_seek first.
555f7cf2976SLionel Sambuc 	 */
556f7cf2976SLionel Sambuc 	if (ch_seek(ch_zero()) == 0)
557f7cf2976SLionel Sambuc 		return (0);
558f7cf2976SLionel Sambuc 
559f7cf2976SLionel Sambuc 	/*
560f7cf2976SLionel Sambuc 	 * Can't get to position 0.
561f7cf2976SLionel Sambuc 	 * Look thru the buffers for the one closest to position 0.
562f7cf2976SLionel Sambuc 	 */
563f7cf2976SLionel Sambuc 	firstbn = ch_bufhead;
564f7cf2976SLionel Sambuc 	if (firstbn == END_OF_CHAIN)
565f7cf2976SLionel Sambuc 		return (1);
566f7cf2976SLionel Sambuc 	FOR_BUFS(bn)
567f7cf2976SLionel Sambuc 	{
568f7cf2976SLionel Sambuc 		if (bufnode_buf(bn)->block < bufnode_buf(firstbn)->block)
569f7cf2976SLionel Sambuc 			firstbn = bn;
570f7cf2976SLionel Sambuc 	}
571f7cf2976SLionel Sambuc 	ch_block = bufnode_buf(firstbn)->block;
572f7cf2976SLionel Sambuc 	ch_offset = 0;
573f7cf2976SLionel Sambuc 	return (0);
574f7cf2976SLionel Sambuc }
575f7cf2976SLionel Sambuc 
576f7cf2976SLionel Sambuc /*
577f7cf2976SLionel Sambuc  * Return the length of the file, if known.
578f7cf2976SLionel Sambuc  */
579f7cf2976SLionel Sambuc 	public POSITION
ch_length()580f7cf2976SLionel Sambuc ch_length()
581f7cf2976SLionel Sambuc {
582f7cf2976SLionel Sambuc 	if (thisfile == NULL)
583f7cf2976SLionel Sambuc 		return (NULL_POSITION);
584f7cf2976SLionel Sambuc 	if (ignore_eoi)
585f7cf2976SLionel Sambuc 		return (NULL_POSITION);
586f7cf2976SLionel Sambuc 	if (ch_flags & CH_HELPFILE)
587f7cf2976SLionel Sambuc 		return (size_helpdata);
588*84d9c625SLionel Sambuc 	if (ch_flags & CH_NODATA)
589*84d9c625SLionel Sambuc 		return (0);
590f7cf2976SLionel Sambuc 	return (ch_fsize);
591f7cf2976SLionel Sambuc }
592f7cf2976SLionel Sambuc 
593f7cf2976SLionel Sambuc /*
594f7cf2976SLionel Sambuc  * Return the current position in the file.
595f7cf2976SLionel Sambuc  */
596f7cf2976SLionel Sambuc 	public POSITION
ch_tell()597f7cf2976SLionel Sambuc ch_tell()
598f7cf2976SLionel Sambuc {
599f7cf2976SLionel Sambuc 	if (thisfile == NULL)
600f7cf2976SLionel Sambuc 		return (NULL_POSITION);
601f7cf2976SLionel Sambuc 	return (ch_block * LBUFSIZE) + ch_offset;
602f7cf2976SLionel Sambuc }
603f7cf2976SLionel Sambuc 
604f7cf2976SLionel Sambuc /*
605f7cf2976SLionel Sambuc  * Get the current char and post-increment the read pointer.
606f7cf2976SLionel Sambuc  */
607f7cf2976SLionel Sambuc 	public int
ch_forw_get()608f7cf2976SLionel Sambuc ch_forw_get()
609f7cf2976SLionel Sambuc {
610f7cf2976SLionel Sambuc 	register int c;
611f7cf2976SLionel Sambuc 
612f7cf2976SLionel Sambuc 	if (thisfile == NULL)
613f7cf2976SLionel Sambuc 		return (EOI);
614f7cf2976SLionel Sambuc 	c = ch_get();
615f7cf2976SLionel Sambuc 	if (c == EOI)
616f7cf2976SLionel Sambuc 		return (EOI);
617f7cf2976SLionel Sambuc 	if (ch_offset < LBUFSIZE-1)
618f7cf2976SLionel Sambuc 		ch_offset++;
619f7cf2976SLionel Sambuc 	else
620f7cf2976SLionel Sambuc 	{
621f7cf2976SLionel Sambuc 		ch_block ++;
622f7cf2976SLionel Sambuc 		ch_offset = 0;
623f7cf2976SLionel Sambuc 	}
624f7cf2976SLionel Sambuc 	return (c);
625f7cf2976SLionel Sambuc }
626f7cf2976SLionel Sambuc 
627f7cf2976SLionel Sambuc /*
628f7cf2976SLionel Sambuc  * Pre-decrement the read pointer and get the new current char.
629f7cf2976SLionel Sambuc  */
630f7cf2976SLionel Sambuc 	public int
ch_back_get()631f7cf2976SLionel Sambuc ch_back_get()
632f7cf2976SLionel Sambuc {
633f7cf2976SLionel Sambuc 	if (thisfile == NULL)
634f7cf2976SLionel Sambuc 		return (EOI);
635f7cf2976SLionel Sambuc 	if (ch_offset > 0)
636f7cf2976SLionel Sambuc 		ch_offset --;
637f7cf2976SLionel Sambuc 	else
638f7cf2976SLionel Sambuc 	{
639f7cf2976SLionel Sambuc 		if (ch_block <= 0)
640f7cf2976SLionel Sambuc 			return (EOI);
641f7cf2976SLionel Sambuc 		if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1))
642f7cf2976SLionel Sambuc 			return (EOI);
643f7cf2976SLionel Sambuc 		ch_block--;
644f7cf2976SLionel Sambuc 		ch_offset = LBUFSIZE-1;
645f7cf2976SLionel Sambuc 	}
646f7cf2976SLionel Sambuc 	return (ch_get());
647f7cf2976SLionel Sambuc }
648f7cf2976SLionel Sambuc 
649f7cf2976SLionel Sambuc /*
650f7cf2976SLionel Sambuc  * Set max amount of buffer space.
651f7cf2976SLionel Sambuc  * bufspace is in units of 1024 bytes.  -1 mean no limit.
652f7cf2976SLionel Sambuc  */
653f7cf2976SLionel Sambuc 	public void
ch_setbufspace(bufspace)654f7cf2976SLionel Sambuc ch_setbufspace(bufspace)
655f7cf2976SLionel Sambuc 	int bufspace;
656f7cf2976SLionel Sambuc {
657f7cf2976SLionel Sambuc 	if (bufspace < 0)
658f7cf2976SLionel Sambuc 		maxbufs = -1;
659f7cf2976SLionel Sambuc 	else
660f7cf2976SLionel Sambuc 	{
661f7cf2976SLionel Sambuc 		maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE;
662f7cf2976SLionel Sambuc 		if (maxbufs < 1)
663f7cf2976SLionel Sambuc 			maxbufs = 1;
664f7cf2976SLionel Sambuc 	}
665f7cf2976SLionel Sambuc }
666f7cf2976SLionel Sambuc 
667f7cf2976SLionel Sambuc /*
668f7cf2976SLionel Sambuc  * Flush (discard) any saved file state, including buffer contents.
669f7cf2976SLionel Sambuc  */
670f7cf2976SLionel Sambuc 	public void
ch_flush()671f7cf2976SLionel Sambuc ch_flush()
672f7cf2976SLionel Sambuc {
673f7cf2976SLionel Sambuc 	register struct bufnode *bn;
674f7cf2976SLionel Sambuc 
675f7cf2976SLionel Sambuc 	if (thisfile == NULL)
676f7cf2976SLionel Sambuc 		return;
677f7cf2976SLionel Sambuc 
678f7cf2976SLionel Sambuc 	if (!(ch_flags & CH_CANSEEK))
679f7cf2976SLionel Sambuc 	{
680f7cf2976SLionel Sambuc 		/*
681f7cf2976SLionel Sambuc 		 * If input is a pipe, we don't flush buffer contents,
682f7cf2976SLionel Sambuc 		 * since the contents can't be recovered.
683f7cf2976SLionel Sambuc 		 */
684f7cf2976SLionel Sambuc 		ch_fsize = NULL_POSITION;
685f7cf2976SLionel Sambuc 		return;
686f7cf2976SLionel Sambuc 	}
687f7cf2976SLionel Sambuc 
688f7cf2976SLionel Sambuc 	/*
689f7cf2976SLionel Sambuc 	 * Initialize all the buffers.
690f7cf2976SLionel Sambuc 	 */
691f7cf2976SLionel Sambuc 	FOR_BUFS(bn)
692f7cf2976SLionel Sambuc 	{
693f7cf2976SLionel Sambuc 		bufnode_buf(bn)->block = -1;
694f7cf2976SLionel Sambuc 	}
695f7cf2976SLionel Sambuc 
696f7cf2976SLionel Sambuc 	/*
697f7cf2976SLionel Sambuc 	 * Figure out the size of the file, if we can.
698f7cf2976SLionel Sambuc 	 */
699f7cf2976SLionel Sambuc 	ch_fsize = filesize(ch_file);
700f7cf2976SLionel Sambuc 
701f7cf2976SLionel Sambuc 	/*
702f7cf2976SLionel Sambuc 	 * Seek to a known position: the beginning of the file.
703f7cf2976SLionel Sambuc 	 */
704f7cf2976SLionel Sambuc 	ch_fpos = 0;
705f7cf2976SLionel Sambuc 	ch_block = 0; /* ch_fpos / LBUFSIZE; */
706f7cf2976SLionel Sambuc 	ch_offset = 0; /* ch_fpos % LBUFSIZE; */
707f7cf2976SLionel Sambuc 
708f7cf2976SLionel Sambuc #if 1
709f7cf2976SLionel Sambuc 	/*
710f7cf2976SLionel Sambuc 	 * This is a kludge to workaround a Linux kernel bug: files in
711f7cf2976SLionel Sambuc 	 * /proc have a size of 0 according to fstat() but have readable
712f7cf2976SLionel Sambuc 	 * data.  They are sometimes, but not always, seekable.
713f7cf2976SLionel Sambuc 	 * Force them to be non-seekable here.
714f7cf2976SLionel Sambuc 	 */
715f7cf2976SLionel Sambuc 	if (ch_fsize == 0)
716f7cf2976SLionel Sambuc 	{
717f7cf2976SLionel Sambuc 		ch_fsize = NULL_POSITION;
718f7cf2976SLionel Sambuc 		ch_flags &= ~CH_CANSEEK;
719f7cf2976SLionel Sambuc 	}
720f7cf2976SLionel Sambuc #endif
721f7cf2976SLionel Sambuc 
722f7cf2976SLionel Sambuc 	if (lseek(ch_file, (off_t)0, SEEK_SET) == BAD_LSEEK)
723f7cf2976SLionel Sambuc 	{
724f7cf2976SLionel Sambuc 		/*
725f7cf2976SLionel Sambuc 		 * Warning only; even if the seek fails for some reason,
726f7cf2976SLionel Sambuc 		 * there's a good chance we're at the beginning anyway.
727f7cf2976SLionel Sambuc 		 * {{ I think this is bogus reasoning. }}
728f7cf2976SLionel Sambuc 		 */
729f7cf2976SLionel Sambuc 		error("seek error to 0", NULL_PARG);
730f7cf2976SLionel Sambuc 	}
731f7cf2976SLionel Sambuc }
732f7cf2976SLionel Sambuc 
733f7cf2976SLionel Sambuc /*
734f7cf2976SLionel Sambuc  * Allocate a new buffer.
735f7cf2976SLionel Sambuc  * The buffer is added to the tail of the buffer chain.
736f7cf2976SLionel Sambuc  */
737f7cf2976SLionel Sambuc 	static int
ch_addbuf()738f7cf2976SLionel Sambuc ch_addbuf()
739f7cf2976SLionel Sambuc {
740f7cf2976SLionel Sambuc 	register struct buf *bp;
741f7cf2976SLionel Sambuc 	register struct bufnode *bn;
742f7cf2976SLionel Sambuc 
743f7cf2976SLionel Sambuc 	/*
744f7cf2976SLionel Sambuc 	 * Allocate and initialize a new buffer and link it
745f7cf2976SLionel Sambuc 	 * onto the tail of the buffer list.
746f7cf2976SLionel Sambuc 	 */
747f7cf2976SLionel Sambuc 	bp = (struct buf *) calloc(1, sizeof(struct buf));
748f7cf2976SLionel Sambuc 	if (bp == NULL)
749f7cf2976SLionel Sambuc 		return (1);
750f7cf2976SLionel Sambuc 	ch_nbufs++;
751f7cf2976SLionel Sambuc 	bp->block = -1;
752f7cf2976SLionel Sambuc 	bn = &bp->node;
753f7cf2976SLionel Sambuc 
754f7cf2976SLionel Sambuc 	BUF_INS_TAIL(bn);
755f7cf2976SLionel Sambuc 	BUF_HASH_INS(bn, 0);
756f7cf2976SLionel Sambuc 	return (0);
757f7cf2976SLionel Sambuc }
758f7cf2976SLionel Sambuc 
759f7cf2976SLionel Sambuc /*
760f7cf2976SLionel Sambuc  *
761f7cf2976SLionel Sambuc  */
762f7cf2976SLionel Sambuc 	static void
init_hashtbl()763f7cf2976SLionel Sambuc init_hashtbl()
764f7cf2976SLionel Sambuc {
765f7cf2976SLionel Sambuc 	register int h;
766f7cf2976SLionel Sambuc 
767f7cf2976SLionel Sambuc 	for (h = 0;  h < BUFHASH_SIZE;  h++)
768f7cf2976SLionel Sambuc 	{
769f7cf2976SLionel Sambuc 		thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h);
770f7cf2976SLionel Sambuc 		thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h);
771f7cf2976SLionel Sambuc 	}
772f7cf2976SLionel Sambuc }
773f7cf2976SLionel Sambuc 
774f7cf2976SLionel Sambuc /*
775f7cf2976SLionel Sambuc  * Delete all buffers for this file.
776f7cf2976SLionel Sambuc  */
777f7cf2976SLionel Sambuc 	static void
ch_delbufs()778f7cf2976SLionel Sambuc ch_delbufs()
779f7cf2976SLionel Sambuc {
780f7cf2976SLionel Sambuc 	register struct bufnode *bn;
781f7cf2976SLionel Sambuc 
782f7cf2976SLionel Sambuc 	while (ch_bufhead != END_OF_CHAIN)
783f7cf2976SLionel Sambuc 	{
784f7cf2976SLionel Sambuc 		bn = ch_bufhead;
785f7cf2976SLionel Sambuc 		BUF_RM(bn);
786f7cf2976SLionel Sambuc 		free(bufnode_buf(bn));
787f7cf2976SLionel Sambuc 	}
788f7cf2976SLionel Sambuc 	ch_nbufs = 0;
789f7cf2976SLionel Sambuc 	init_hashtbl();
790f7cf2976SLionel Sambuc }
791f7cf2976SLionel Sambuc 
792f7cf2976SLionel Sambuc /*
793f7cf2976SLionel Sambuc  * Is it possible to seek on a file descriptor?
794f7cf2976SLionel Sambuc  */
795f7cf2976SLionel Sambuc 	public int
seekable(f)796f7cf2976SLionel Sambuc seekable(f)
797f7cf2976SLionel Sambuc 	int f;
798f7cf2976SLionel Sambuc {
799f7cf2976SLionel Sambuc #if MSDOS_COMPILER
800f7cf2976SLionel Sambuc 	extern int fd0;
801f7cf2976SLionel Sambuc 	if (f == fd0 && !isatty(fd0))
802f7cf2976SLionel Sambuc 	{
803f7cf2976SLionel Sambuc 		/*
804f7cf2976SLionel Sambuc 		 * In MS-DOS, pipes are seekable.  Check for
805f7cf2976SLionel Sambuc 		 * standard input, and pretend it is not seekable.
806f7cf2976SLionel Sambuc 		 */
807f7cf2976SLionel Sambuc 		return (0);
808f7cf2976SLionel Sambuc 	}
809f7cf2976SLionel Sambuc #endif
810f7cf2976SLionel Sambuc 	return (lseek(f, (off_t)1, SEEK_SET) != BAD_LSEEK);
811f7cf2976SLionel Sambuc }
812f7cf2976SLionel Sambuc 
813f7cf2976SLionel Sambuc /*
814*84d9c625SLionel Sambuc  * Force EOF to be at the current read position.
815*84d9c625SLionel Sambuc  * This is used after an ignore_eof read, during which the EOF may change.
816*84d9c625SLionel Sambuc  */
817*84d9c625SLionel Sambuc 	public void
ch_set_eof()818*84d9c625SLionel Sambuc ch_set_eof()
819*84d9c625SLionel Sambuc {
820*84d9c625SLionel Sambuc 	ch_fsize = ch_fpos;
821*84d9c625SLionel Sambuc }
822*84d9c625SLionel Sambuc 
823*84d9c625SLionel Sambuc 
824*84d9c625SLionel Sambuc /*
825f7cf2976SLionel Sambuc  * Initialize file state for a new file.
826f7cf2976SLionel Sambuc  */
827f7cf2976SLionel Sambuc 	public void
ch_init(f,flags)828f7cf2976SLionel Sambuc ch_init(f, flags)
829f7cf2976SLionel Sambuc 	int f;
830f7cf2976SLionel Sambuc 	int flags;
831f7cf2976SLionel Sambuc {
832f7cf2976SLionel Sambuc 	/*
833f7cf2976SLionel Sambuc 	 * See if we already have a filestate for this file.
834f7cf2976SLionel Sambuc 	 */
835f7cf2976SLionel Sambuc 	thisfile = (struct filestate *) get_filestate(curr_ifile);
836f7cf2976SLionel Sambuc 	if (thisfile == NULL)
837f7cf2976SLionel Sambuc 	{
838f7cf2976SLionel Sambuc 		/*
839f7cf2976SLionel Sambuc 		 * Allocate and initialize a new filestate.
840f7cf2976SLionel Sambuc 		 */
841f7cf2976SLionel Sambuc 		thisfile = (struct filestate *)
842f7cf2976SLionel Sambuc 				calloc(1, sizeof(struct filestate));
843f7cf2976SLionel Sambuc 		thisfile->buflist.next = thisfile->buflist.prev = END_OF_CHAIN;
844f7cf2976SLionel Sambuc 		thisfile->nbufs = 0;
845f7cf2976SLionel Sambuc 		thisfile->flags = 0;
846f7cf2976SLionel Sambuc 		thisfile->fpos = 0;
847f7cf2976SLionel Sambuc 		thisfile->block = 0;
848f7cf2976SLionel Sambuc 		thisfile->offset = 0;
849f7cf2976SLionel Sambuc 		thisfile->file = -1;
850f7cf2976SLionel Sambuc 		thisfile->fsize = NULL_POSITION;
851f7cf2976SLionel Sambuc 		ch_flags = flags;
852f7cf2976SLionel Sambuc 		init_hashtbl();
853f7cf2976SLionel Sambuc 		/*
854f7cf2976SLionel Sambuc 		 * Try to seek; set CH_CANSEEK if it works.
855f7cf2976SLionel Sambuc 		 */
856f7cf2976SLionel Sambuc 		if ((flags & CH_CANSEEK) && !seekable(f))
857f7cf2976SLionel Sambuc 			ch_flags &= ~CH_CANSEEK;
858f7cf2976SLionel Sambuc 		set_filestate(curr_ifile, (void *) thisfile);
859f7cf2976SLionel Sambuc 	}
860f7cf2976SLionel Sambuc 	if (thisfile->file == -1)
861f7cf2976SLionel Sambuc 		thisfile->file = f;
862f7cf2976SLionel Sambuc 	ch_flush();
863f7cf2976SLionel Sambuc }
864f7cf2976SLionel Sambuc 
865f7cf2976SLionel Sambuc /*
866f7cf2976SLionel Sambuc  * Close a filestate.
867f7cf2976SLionel Sambuc  */
868f7cf2976SLionel Sambuc 	public void
ch_close()869f7cf2976SLionel Sambuc ch_close()
870f7cf2976SLionel Sambuc {
871f7cf2976SLionel Sambuc 	int keepstate = FALSE;
872f7cf2976SLionel Sambuc 
873f7cf2976SLionel Sambuc 	if (thisfile == NULL)
874f7cf2976SLionel Sambuc 		return;
875f7cf2976SLionel Sambuc 
876f7cf2976SLionel Sambuc 	if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE))
877f7cf2976SLionel Sambuc 	{
878f7cf2976SLionel Sambuc 		/*
879f7cf2976SLionel Sambuc 		 * We can seek or re-open, so we don't need to keep buffers.
880f7cf2976SLionel Sambuc 		 */
881f7cf2976SLionel Sambuc 		ch_delbufs();
882f7cf2976SLionel Sambuc 	} else
883f7cf2976SLionel Sambuc 		keepstate = TRUE;
884f7cf2976SLionel Sambuc 	if (!(ch_flags & CH_KEEPOPEN))
885f7cf2976SLionel Sambuc 	{
886f7cf2976SLionel Sambuc 		/*
887f7cf2976SLionel Sambuc 		 * We don't need to keep the file descriptor open
888f7cf2976SLionel Sambuc 		 * (because we can re-open it.)
889f7cf2976SLionel Sambuc 		 * But don't really close it if it was opened via popen(),
890f7cf2976SLionel Sambuc 		 * because pclose() wants to close it.
891f7cf2976SLionel Sambuc 		 */
892f7cf2976SLionel Sambuc 		if (!(ch_flags & (CH_POPENED|CH_HELPFILE)))
893f7cf2976SLionel Sambuc 			close(ch_file);
894f7cf2976SLionel Sambuc 		ch_file = -1;
895f7cf2976SLionel Sambuc 	} else
896f7cf2976SLionel Sambuc 		keepstate = TRUE;
897f7cf2976SLionel Sambuc 	if (!keepstate)
898f7cf2976SLionel Sambuc 	{
899f7cf2976SLionel Sambuc 		/*
900f7cf2976SLionel Sambuc 		 * We don't even need to keep the filestate structure.
901f7cf2976SLionel Sambuc 		 */
902f7cf2976SLionel Sambuc 		free(thisfile);
903f7cf2976SLionel Sambuc 		thisfile = NULL;
904f7cf2976SLionel Sambuc 		set_filestate(curr_ifile, (void *) NULL);
905f7cf2976SLionel Sambuc 	}
906f7cf2976SLionel Sambuc }
907f7cf2976SLionel Sambuc 
908f7cf2976SLionel Sambuc /*
909f7cf2976SLionel Sambuc  * Return ch_flags for the current file.
910f7cf2976SLionel Sambuc  */
911f7cf2976SLionel Sambuc 	public int
ch_getflags()912f7cf2976SLionel Sambuc ch_getflags()
913f7cf2976SLionel Sambuc {
914f7cf2976SLionel Sambuc 	if (thisfile == NULL)
915f7cf2976SLionel Sambuc 		return (0);
916f7cf2976SLionel Sambuc 	return (ch_flags);
917f7cf2976SLionel Sambuc }
918f7cf2976SLionel Sambuc 
919f7cf2976SLionel Sambuc #if 0
920f7cf2976SLionel Sambuc 	public void
921f7cf2976SLionel Sambuc ch_dump(struct filestate *fs)
922f7cf2976SLionel Sambuc {
923f7cf2976SLionel Sambuc 	struct buf *bp;
924f7cf2976SLionel Sambuc 	struct bufnode *bn;
925f7cf2976SLionel Sambuc 	unsigned char *s;
926f7cf2976SLionel Sambuc 
927f7cf2976SLionel Sambuc 	if (fs == NULL)
928f7cf2976SLionel Sambuc 	{
929f7cf2976SLionel Sambuc 		printf(" --no filestate\n");
930f7cf2976SLionel Sambuc 		return;
931f7cf2976SLionel Sambuc 	}
932f7cf2976SLionel Sambuc 	printf(" file %d, flags %x, fpos %x, fsize %x, blk/off %x/%x\n",
933f7cf2976SLionel Sambuc 		fs->file, fs->flags, fs->fpos,
934f7cf2976SLionel Sambuc 		fs->fsize, fs->block, fs->offset);
935f7cf2976SLionel Sambuc 	printf(" %d bufs:\n", fs->nbufs);
936f7cf2976SLionel Sambuc 	for (bn = fs->next; bn != &fs->buflist;  bn = bn->next)
937f7cf2976SLionel Sambuc 	{
938f7cf2976SLionel Sambuc 		bp = bufnode_buf(bn);
939f7cf2976SLionel Sambuc 		printf("%x: blk %x, size %x \"",
940f7cf2976SLionel Sambuc 			bp, bp->block, bp->datasize);
941f7cf2976SLionel Sambuc 		for (s = bp->data;  s < bp->data + 30;  s++)
942f7cf2976SLionel Sambuc 			if (*s >= ' ' && *s < 0x7F)
943f7cf2976SLionel Sambuc 				printf("%c", *s);
944f7cf2976SLionel Sambuc 			else
945f7cf2976SLionel Sambuc 				printf(".");
946f7cf2976SLionel Sambuc 		printf("\"\n");
947f7cf2976SLionel Sambuc 	}
948f7cf2976SLionel Sambuc }
949f7cf2976SLionel Sambuc #endif
950