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