11133e27eSPeter Avalos /*
2*320d7c8aSAaron LI * Copyright (C) 1984-2023 Mark Nudelman
31133e27eSPeter Avalos *
41133e27eSPeter Avalos * You may distribute under the terms of either the GNU General Public
51133e27eSPeter Avalos * License or the Less License, as specified in the README file.
61133e27eSPeter Avalos *
7e639dc31SJohn Marino * For more information, see the README file.
81133e27eSPeter Avalos */
91133e27eSPeter Avalos
101133e27eSPeter Avalos
111133e27eSPeter Avalos /*
121133e27eSPeter Avalos * Low level character input from the input file.
131133e27eSPeter Avalos * We use these special purpose routines which optimize moving
141133e27eSPeter Avalos * both forward and backward from the current read pointer.
151133e27eSPeter Avalos */
161133e27eSPeter Avalos
171133e27eSPeter Avalos #include "less.h"
181133e27eSPeter Avalos #if MSDOS_COMPILER==WIN32C
191133e27eSPeter Avalos #include <errno.h>
201133e27eSPeter Avalos #include <windows.h>
211133e27eSPeter Avalos #endif
221133e27eSPeter Avalos
230c7ad07eSAntonio Huete Jimenez #if HAVE_PROCFS
240c7ad07eSAntonio Huete Jimenez #include <sys/statfs.h>
25*320d7c8aSAaron LI #if HAVE_LINUX_MAGIC_H
26*320d7c8aSAaron LI #include <linux/magic.h>
27*320d7c8aSAaron LI #endif
280c7ad07eSAntonio Huete Jimenez #endif
290c7ad07eSAntonio Huete Jimenez
301133e27eSPeter Avalos typedef POSITION BLOCKNUM;
311133e27eSPeter Avalos
321133e27eSPeter Avalos public int ignore_eoi;
331133e27eSPeter Avalos
341133e27eSPeter Avalos /*
351133e27eSPeter Avalos * Pool of buffers holding the most recently used blocks of the input file.
361133e27eSPeter Avalos * The buffer pool is kept as a doubly-linked circular list,
371133e27eSPeter Avalos * in order from most- to least-recently used.
381133e27eSPeter Avalos * The circular list is anchored by the file state "thisfile".
391133e27eSPeter Avalos */
408be36e5bSPeter Avalos struct bufnode {
418be36e5bSPeter Avalos struct bufnode *next, *prev;
428be36e5bSPeter Avalos struct bufnode *hnext, *hprev;
438be36e5bSPeter Avalos };
448be36e5bSPeter Avalos
451133e27eSPeter Avalos #define LBUFSIZE 8192
461133e27eSPeter Avalos struct buf {
478be36e5bSPeter Avalos struct bufnode node;
481133e27eSPeter Avalos BLOCKNUM block;
491133e27eSPeter Avalos unsigned int datasize;
501133e27eSPeter Avalos unsigned char data[LBUFSIZE];
511133e27eSPeter Avalos };
528be36e5bSPeter Avalos #define bufnode_buf(bn) ((struct buf *) bn)
531133e27eSPeter Avalos
541133e27eSPeter Avalos /*
551133e27eSPeter Avalos * The file state is maintained in a filestate structure.
561133e27eSPeter Avalos * A pointer to the filestate is kept in the ifile structure.
571133e27eSPeter Avalos */
58fa0be7c5SJohn Marino #define BUFHASH_SIZE 1024
591133e27eSPeter Avalos struct filestate {
608be36e5bSPeter Avalos struct bufnode buflist;
618be36e5bSPeter Avalos struct bufnode hashtbl[BUFHASH_SIZE];
621133e27eSPeter Avalos int file;
631133e27eSPeter Avalos int flags;
641133e27eSPeter Avalos POSITION fpos;
651133e27eSPeter Avalos int nbufs;
661133e27eSPeter Avalos BLOCKNUM block;
671133e27eSPeter Avalos unsigned int offset;
681133e27eSPeter Avalos POSITION fsize;
691133e27eSPeter Avalos };
701133e27eSPeter Avalos
718be36e5bSPeter Avalos #define ch_bufhead thisfile->buflist.next
728be36e5bSPeter Avalos #define ch_buftail thisfile->buflist.prev
731133e27eSPeter Avalos #define ch_nbufs thisfile->nbufs
741133e27eSPeter Avalos #define ch_block thisfile->block
751133e27eSPeter Avalos #define ch_offset thisfile->offset
761133e27eSPeter Avalos #define ch_fpos thisfile->fpos
771133e27eSPeter Avalos #define ch_fsize thisfile->fsize
781133e27eSPeter Avalos #define ch_flags thisfile->flags
791133e27eSPeter Avalos #define ch_file thisfile->file
801133e27eSPeter Avalos
818be36e5bSPeter Avalos #define END_OF_CHAIN (&thisfile->buflist)
828be36e5bSPeter Avalos #define END_OF_HCHAIN(h) (&thisfile->hashtbl[h])
831133e27eSPeter Avalos #define BUFHASH(blk) ((blk) & (BUFHASH_SIZE-1))
841133e27eSPeter Avalos
858be36e5bSPeter Avalos /*
868be36e5bSPeter Avalos * Macros to manipulate the list of buffers in thisfile->buflist.
878be36e5bSPeter Avalos */
888be36e5bSPeter Avalos #define FOR_BUFS(bn) \
898be36e5bSPeter Avalos for (bn = ch_bufhead; bn != END_OF_CHAIN; bn = bn->next)
901133e27eSPeter Avalos
918be36e5bSPeter Avalos #define BUF_RM(bn) \
928be36e5bSPeter Avalos (bn)->next->prev = (bn)->prev; \
938be36e5bSPeter Avalos (bn)->prev->next = (bn)->next;
941133e27eSPeter Avalos
958be36e5bSPeter Avalos #define BUF_INS_HEAD(bn) \
968be36e5bSPeter Avalos (bn)->next = ch_bufhead; \
978be36e5bSPeter Avalos (bn)->prev = END_OF_CHAIN; \
988be36e5bSPeter Avalos ch_bufhead->prev = (bn); \
998be36e5bSPeter Avalos ch_bufhead = (bn);
1008be36e5bSPeter Avalos
1018be36e5bSPeter Avalos #define BUF_INS_TAIL(bn) \
1028be36e5bSPeter Avalos (bn)->next = END_OF_CHAIN; \
1038be36e5bSPeter Avalos (bn)->prev = ch_buftail; \
1048be36e5bSPeter Avalos ch_buftail->next = (bn); \
1058be36e5bSPeter Avalos ch_buftail = (bn);
1068be36e5bSPeter Avalos
1078be36e5bSPeter Avalos /*
1088be36e5bSPeter Avalos * Macros to manipulate the list of buffers in thisfile->hashtbl[n].
1098be36e5bSPeter Avalos */
1108be36e5bSPeter Avalos #define FOR_BUFS_IN_CHAIN(h,bn) \
1118be36e5bSPeter Avalos for (bn = thisfile->hashtbl[h].hnext; \
1128be36e5bSPeter Avalos bn != END_OF_HCHAIN(h); bn = bn->hnext)
1138be36e5bSPeter Avalos
1148be36e5bSPeter Avalos #define BUF_HASH_RM(bn) \
1158be36e5bSPeter Avalos (bn)->hnext->hprev = (bn)->hprev; \
1168be36e5bSPeter Avalos (bn)->hprev->hnext = (bn)->hnext;
1178be36e5bSPeter Avalos
1188be36e5bSPeter Avalos #define BUF_HASH_INS(bn,h) \
1198be36e5bSPeter Avalos (bn)->hnext = thisfile->hashtbl[h].hnext; \
1208be36e5bSPeter Avalos (bn)->hprev = END_OF_HCHAIN(h); \
1218be36e5bSPeter Avalos thisfile->hashtbl[h].hnext->hprev = (bn); \
1228be36e5bSPeter Avalos thisfile->hashtbl[h].hnext = (bn);
1231133e27eSPeter Avalos
1241133e27eSPeter Avalos static struct filestate *thisfile;
1251133e27eSPeter Avalos static int ch_ungotchar = -1;
1261133e27eSPeter Avalos static int maxbufs = -1;
1271133e27eSPeter Avalos
1281133e27eSPeter Avalos extern int autobuf;
1291133e27eSPeter Avalos extern int sigs;
1301133e27eSPeter Avalos extern int secure;
1311133e27eSPeter Avalos extern int screen_trashed;
1321133e27eSPeter Avalos extern int follow_mode;
133*320d7c8aSAaron LI extern int waiting_for_data;
1341133e27eSPeter Avalos extern constant char helpdata[];
1351133e27eSPeter Avalos extern constant int size_helpdata;
1361133e27eSPeter Avalos extern IFILE curr_ifile;
1371133e27eSPeter Avalos #if LOGFILE
1381133e27eSPeter Avalos extern int logfile;
1391133e27eSPeter Avalos extern char *namelogfile;
1401133e27eSPeter Avalos #endif
1411133e27eSPeter Avalos
1421133e27eSPeter Avalos static int ch_addbuf();
1431133e27eSPeter Avalos
1441133e27eSPeter Avalos
1451133e27eSPeter Avalos /*
1461133e27eSPeter Avalos * Get the character pointed to by the read pointer.
1471133e27eSPeter Avalos */
ch_get(void)148*320d7c8aSAaron LI static int ch_get(void)
1491133e27eSPeter Avalos {
15002d62a0fSDaniel Fojt struct buf *bp;
15102d62a0fSDaniel Fojt struct bufnode *bn;
15202d62a0fSDaniel Fojt int n;
153*320d7c8aSAaron LI int read_again;
15402d62a0fSDaniel Fojt int h;
1551133e27eSPeter Avalos POSITION pos;
1561133e27eSPeter Avalos POSITION len;
1571133e27eSPeter Avalos
1581133e27eSPeter Avalos if (thisfile == NULL)
1591133e27eSPeter Avalos return (EOI);
1601133e27eSPeter Avalos
1618be36e5bSPeter Avalos /*
1628be36e5bSPeter Avalos * Quick check for the common case where
1638be36e5bSPeter Avalos * the desired char is in the head buffer.
1648be36e5bSPeter Avalos */
1658be36e5bSPeter Avalos if (ch_bufhead != END_OF_CHAIN)
1668be36e5bSPeter Avalos {
1678be36e5bSPeter Avalos bp = bufnode_buf(ch_bufhead);
1688be36e5bSPeter Avalos if (ch_block == bp->block && ch_offset < bp->datasize)
1698be36e5bSPeter Avalos return bp->data[ch_offset];
1708be36e5bSPeter Avalos }
1718be36e5bSPeter Avalos
1721133e27eSPeter Avalos /*
1731133e27eSPeter Avalos * Look for a buffer holding the desired block.
1741133e27eSPeter Avalos */
175*320d7c8aSAaron LI waiting_for_data = FALSE;
1761133e27eSPeter Avalos h = BUFHASH(ch_block);
1778be36e5bSPeter Avalos FOR_BUFS_IN_CHAIN(h, bn)
1781133e27eSPeter Avalos {
1798be36e5bSPeter Avalos bp = bufnode_buf(bn);
1801133e27eSPeter Avalos if (bp->block == ch_block)
1811133e27eSPeter Avalos {
1821133e27eSPeter Avalos if (ch_offset >= bp->datasize)
1831133e27eSPeter Avalos /*
1841133e27eSPeter Avalos * Need more data in this buffer.
1851133e27eSPeter Avalos */
1868be36e5bSPeter Avalos break;
1871133e27eSPeter Avalos goto found;
1881133e27eSPeter Avalos }
1891133e27eSPeter Avalos }
1908be36e5bSPeter Avalos if (bn == END_OF_HCHAIN(h))
1918be36e5bSPeter Avalos {
1921133e27eSPeter Avalos /*
1931133e27eSPeter Avalos * Block is not in a buffer.
1941133e27eSPeter Avalos * Take the least recently used buffer
1951133e27eSPeter Avalos * and read the desired block into it.
1961133e27eSPeter Avalos * If the LRU buffer has data in it,
1971133e27eSPeter Avalos * then maybe allocate a new buffer.
1981133e27eSPeter Avalos */
1998be36e5bSPeter Avalos if (ch_buftail == END_OF_CHAIN ||
2008be36e5bSPeter Avalos bufnode_buf(ch_buftail)->block != -1)
2011133e27eSPeter Avalos {
2021133e27eSPeter Avalos /*
2031133e27eSPeter Avalos * There is no empty buffer to use.
2041133e27eSPeter Avalos * Allocate a new buffer if:
2051133e27eSPeter Avalos * 1. We can't seek on this file and -b is not in effect; or
2061133e27eSPeter Avalos * 2. We haven't allocated the max buffers for this file yet.
2071133e27eSPeter Avalos */
2081133e27eSPeter Avalos if ((autobuf && !(ch_flags & CH_CANSEEK)) ||
2091133e27eSPeter Avalos (maxbufs < 0 || ch_nbufs < maxbufs))
2101133e27eSPeter Avalos if (ch_addbuf())
2111133e27eSPeter Avalos /*
2121133e27eSPeter Avalos * Allocation failed: turn off autobuf.
2131133e27eSPeter Avalos */
2141133e27eSPeter Avalos autobuf = OPT_OFF;
2151133e27eSPeter Avalos }
2168be36e5bSPeter Avalos bn = ch_buftail;
2178be36e5bSPeter Avalos bp = bufnode_buf(bn);
2188be36e5bSPeter Avalos BUF_HASH_RM(bn); /* Remove from old hash chain. */
2191133e27eSPeter Avalos bp->block = ch_block;
2201133e27eSPeter Avalos bp->datasize = 0;
2218be36e5bSPeter Avalos BUF_HASH_INS(bn, h); /* Insert into new hash chain. */
2228be36e5bSPeter Avalos }
2231133e27eSPeter Avalos
224*320d7c8aSAaron LI for (;;)
225*320d7c8aSAaron LI {
2261133e27eSPeter Avalos pos = (ch_block * LBUFSIZE) + bp->datasize;
2271133e27eSPeter Avalos if ((len = ch_length()) != NULL_POSITION && pos >= len)
2281133e27eSPeter Avalos /*
2291133e27eSPeter Avalos * At end of file.
2301133e27eSPeter Avalos */
2311133e27eSPeter Avalos return (EOI);
2321133e27eSPeter Avalos
2331133e27eSPeter Avalos if (pos != ch_fpos)
2341133e27eSPeter Avalos {
2351133e27eSPeter Avalos /*
2361133e27eSPeter Avalos * Not at the correct position: must seek.
2371133e27eSPeter Avalos * If input is a pipe, we're in trouble (can't seek on a pipe).
2381133e27eSPeter Avalos * Some data has been lost: just return "?".
2391133e27eSPeter Avalos */
2401133e27eSPeter Avalos if (!(ch_flags & CH_CANSEEK))
2411133e27eSPeter Avalos return ('?');
2421133e27eSPeter Avalos if (lseek(ch_file, (off_t)pos, SEEK_SET) == BAD_LSEEK)
2431133e27eSPeter Avalos {
2441133e27eSPeter Avalos error("seek error", NULL_PARG);
2451133e27eSPeter Avalos clear_eol();
2461133e27eSPeter Avalos return (EOI);
2471133e27eSPeter Avalos }
2481133e27eSPeter Avalos ch_fpos = pos;
2491133e27eSPeter Avalos }
2501133e27eSPeter Avalos
2511133e27eSPeter Avalos /*
2521133e27eSPeter Avalos * Read the block.
2531133e27eSPeter Avalos * If we read less than a full block, that's ok.
2541133e27eSPeter Avalos * We use partial block and pick up the rest next time.
2551133e27eSPeter Avalos */
2561133e27eSPeter Avalos if (ch_ungotchar != -1)
2571133e27eSPeter Avalos {
2581133e27eSPeter Avalos bp->data[bp->datasize] = ch_ungotchar;
2591133e27eSPeter Avalos n = 1;
2601133e27eSPeter Avalos ch_ungotchar = -1;
2611133e27eSPeter Avalos } else if (ch_flags & CH_HELPFILE)
2621133e27eSPeter Avalos {
2631133e27eSPeter Avalos bp->data[bp->datasize] = helpdata[ch_fpos];
2641133e27eSPeter Avalos n = 1;
2651133e27eSPeter Avalos } else
2661133e27eSPeter Avalos {
2671133e27eSPeter Avalos n = iread(ch_file, &bp->data[bp->datasize],
2681133e27eSPeter Avalos (unsigned int)(LBUFSIZE - bp->datasize));
2691133e27eSPeter Avalos }
2701133e27eSPeter Avalos
271*320d7c8aSAaron LI read_again = FALSE;
2721133e27eSPeter Avalos if (n == READ_INTR)
273*320d7c8aSAaron LI {
274*320d7c8aSAaron LI ch_fsize = pos;
2751133e27eSPeter Avalos return (EOI);
276*320d7c8aSAaron LI }
277*320d7c8aSAaron LI if (n == READ_AGAIN)
278*320d7c8aSAaron LI {
279*320d7c8aSAaron LI read_again = TRUE;
280*320d7c8aSAaron LI n = 0;
281*320d7c8aSAaron LI }
2821133e27eSPeter Avalos if (n < 0)
2831133e27eSPeter Avalos {
2841133e27eSPeter Avalos #if MSDOS_COMPILER==WIN32C
2851133e27eSPeter Avalos if (errno != EPIPE)
2861133e27eSPeter Avalos #endif
2871133e27eSPeter Avalos {
2881133e27eSPeter Avalos error("read error", NULL_PARG);
2891133e27eSPeter Avalos clear_eol();
2901133e27eSPeter Avalos }
2911133e27eSPeter Avalos n = 0;
2921133e27eSPeter Avalos }
2931133e27eSPeter Avalos
2941133e27eSPeter Avalos #if LOGFILE
2951133e27eSPeter Avalos /*
2961133e27eSPeter Avalos * If we have a log file, write the new data to it.
2971133e27eSPeter Avalos */
2981133e27eSPeter Avalos if (!secure && logfile >= 0 && n > 0)
2991133e27eSPeter Avalos write(logfile, (char *) &bp->data[bp->datasize], n);
3001133e27eSPeter Avalos #endif
3011133e27eSPeter Avalos
3021133e27eSPeter Avalos ch_fpos += n;
3031133e27eSPeter Avalos bp->datasize += n;
3041133e27eSPeter Avalos
3051133e27eSPeter Avalos if (n == 0)
3061133e27eSPeter Avalos {
307*320d7c8aSAaron LI /* Either end of file or no data available.
308*320d7c8aSAaron LI * read_again indicates the latter. */
309*320d7c8aSAaron LI if (!read_again)
3101133e27eSPeter Avalos ch_fsize = pos;
311*320d7c8aSAaron LI if (ignore_eoi || read_again)
3121133e27eSPeter Avalos {
313*320d7c8aSAaron LI /* Wait a while, then try again. */
314*320d7c8aSAaron LI if (!waiting_for_data)
3151133e27eSPeter Avalos {
3161133e27eSPeter Avalos PARG parg;
3171133e27eSPeter Avalos parg.p_string = wait_message();
318*320d7c8aSAaron LI ixerror("%s", &parg);
319*320d7c8aSAaron LI waiting_for_data = TRUE;
3201133e27eSPeter Avalos }
321*320d7c8aSAaron LI sleep_ms(50); /* Reduce system load */
322*320d7c8aSAaron LI }
323*320d7c8aSAaron LI if (ignore_eoi && follow_mode == FOLLOW_NAME && curr_ifile_changed())
3241133e27eSPeter Avalos {
325*320d7c8aSAaron LI /* screen_trashed=2 causes make_display to reopen the file. */
3261133e27eSPeter Avalos screen_trashed = 2;
3271133e27eSPeter Avalos return (EOI);
3281133e27eSPeter Avalos }
3291133e27eSPeter Avalos if (sigs)
3301133e27eSPeter Avalos return (EOI);
3311133e27eSPeter Avalos }
3321133e27eSPeter Avalos
3331133e27eSPeter Avalos found:
3348be36e5bSPeter Avalos if (ch_bufhead != bn)
3351133e27eSPeter Avalos {
3361133e27eSPeter Avalos /*
3371133e27eSPeter Avalos * Move the buffer to the head of the buffer chain.
3381133e27eSPeter Avalos * This orders the buffer chain, most- to least-recently used.
3391133e27eSPeter Avalos */
3408be36e5bSPeter Avalos BUF_RM(bn);
3418be36e5bSPeter Avalos BUF_INS_HEAD(bn);
3421133e27eSPeter Avalos
3431133e27eSPeter Avalos /*
3441133e27eSPeter Avalos * Move to head of hash chain too.
3451133e27eSPeter Avalos */
3468be36e5bSPeter Avalos BUF_HASH_RM(bn);
3478be36e5bSPeter Avalos BUF_HASH_INS(bn, h);
3481133e27eSPeter Avalos }
3491133e27eSPeter Avalos
350*320d7c8aSAaron LI if (ch_offset < bp->datasize)
351*320d7c8aSAaron LI break;
3521133e27eSPeter Avalos /*
3531133e27eSPeter Avalos * After all that, we still don't have enough data.
3541133e27eSPeter Avalos * Go back and try again.
3551133e27eSPeter Avalos */
356*320d7c8aSAaron LI }
3571133e27eSPeter Avalos return (bp->data[ch_offset]);
3581133e27eSPeter Avalos }
3591133e27eSPeter Avalos
3601133e27eSPeter Avalos /*
3611133e27eSPeter Avalos * ch_ungetchar is a rather kludgy and limited way to push
3621133e27eSPeter Avalos * a single char onto an input file descriptor.
3631133e27eSPeter Avalos */
ch_ungetchar(int c)364*320d7c8aSAaron LI public void ch_ungetchar(int c)
3651133e27eSPeter Avalos {
3661133e27eSPeter Avalos if (c != -1 && ch_ungotchar != -1)
3671133e27eSPeter Avalos error("ch_ungetchar overrun", NULL_PARG);
3681133e27eSPeter Avalos ch_ungotchar = c;
3691133e27eSPeter Avalos }
3701133e27eSPeter Avalos
3711133e27eSPeter Avalos #if LOGFILE
3721133e27eSPeter Avalos /*
3731133e27eSPeter Avalos * Close the logfile.
3741133e27eSPeter Avalos * If we haven't read all of standard input into it, do that now.
3751133e27eSPeter Avalos */
end_logfile(void)376*320d7c8aSAaron LI public void end_logfile(void)
3771133e27eSPeter Avalos {
3781133e27eSPeter Avalos static int tried = FALSE;
3791133e27eSPeter Avalos
3801133e27eSPeter Avalos if (logfile < 0)
3811133e27eSPeter Avalos return;
3821133e27eSPeter Avalos if (!tried && ch_fsize == NULL_POSITION)
3831133e27eSPeter Avalos {
3841133e27eSPeter Avalos tried = TRUE;
3851133e27eSPeter Avalos ierror("Finishing logfile", NULL_PARG);
3861133e27eSPeter Avalos while (ch_forw_get() != EOI)
3871133e27eSPeter Avalos if (ABORT_SIGS())
3881133e27eSPeter Avalos break;
3891133e27eSPeter Avalos }
3901133e27eSPeter Avalos close(logfile);
3911133e27eSPeter Avalos logfile = -1;
3920c7ad07eSAntonio Huete Jimenez free(namelogfile);
3931133e27eSPeter Avalos namelogfile = NULL;
3941133e27eSPeter Avalos }
3951133e27eSPeter Avalos
3961133e27eSPeter Avalos /*
3971133e27eSPeter Avalos * Start a log file AFTER less has already been running.
3981133e27eSPeter Avalos * Invoked from the - command; see toggle_option().
3991133e27eSPeter Avalos * Write all the existing buffered data to the log file.
4001133e27eSPeter Avalos */
sync_logfile(void)401*320d7c8aSAaron LI public void sync_logfile(void)
4021133e27eSPeter Avalos {
40302d62a0fSDaniel Fojt struct buf *bp;
40402d62a0fSDaniel Fojt struct bufnode *bn;
4051133e27eSPeter Avalos int warned = FALSE;
4061133e27eSPeter Avalos BLOCKNUM block;
4071133e27eSPeter Avalos BLOCKNUM nblocks;
4081133e27eSPeter Avalos
409*320d7c8aSAaron LI if (logfile < 0)
410*320d7c8aSAaron LI return;
4111133e27eSPeter Avalos nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;
4121133e27eSPeter Avalos for (block = 0; block < nblocks; block++)
4131133e27eSPeter Avalos {
4148be36e5bSPeter Avalos int wrote = FALSE;
4158be36e5bSPeter Avalos FOR_BUFS(bn)
4161133e27eSPeter Avalos {
4178be36e5bSPeter Avalos bp = bufnode_buf(bn);
4188be36e5bSPeter Avalos if (bp->block == block)
4191133e27eSPeter Avalos {
4208be36e5bSPeter Avalos write(logfile, (char *) bp->data, bp->datasize);
4218be36e5bSPeter Avalos wrote = TRUE;
4228be36e5bSPeter Avalos break;
4238be36e5bSPeter Avalos }
4248be36e5bSPeter Avalos }
4258be36e5bSPeter Avalos if (!wrote && !warned)
4261133e27eSPeter Avalos {
4271133e27eSPeter Avalos error("Warning: log file is incomplete",
4281133e27eSPeter Avalos NULL_PARG);
4291133e27eSPeter Avalos warned = TRUE;
4301133e27eSPeter Avalos }
4311133e27eSPeter Avalos }
4321133e27eSPeter Avalos }
4331133e27eSPeter Avalos
4341133e27eSPeter Avalos #endif
4351133e27eSPeter Avalos
4361133e27eSPeter Avalos /*
4371133e27eSPeter Avalos * Determine if a specific block is currently in one of the buffers.
4381133e27eSPeter Avalos */
buffered(BLOCKNUM block)439*320d7c8aSAaron LI static int buffered(BLOCKNUM block)
4401133e27eSPeter Avalos {
44102d62a0fSDaniel Fojt struct buf *bp;
44202d62a0fSDaniel Fojt struct bufnode *bn;
44302d62a0fSDaniel Fojt int h;
4441133e27eSPeter Avalos
4451133e27eSPeter Avalos h = BUFHASH(block);
4468be36e5bSPeter Avalos FOR_BUFS_IN_CHAIN(h, bn)
4471133e27eSPeter Avalos {
4488be36e5bSPeter Avalos bp = bufnode_buf(bn);
4491133e27eSPeter Avalos if (bp->block == block)
4501133e27eSPeter Avalos return (TRUE);
4511133e27eSPeter Avalos }
4521133e27eSPeter Avalos return (FALSE);
4531133e27eSPeter Avalos }
4541133e27eSPeter Avalos
4551133e27eSPeter Avalos /*
4561133e27eSPeter Avalos * Seek to a specified position in the file.
4571133e27eSPeter Avalos * Return 0 if successful, non-zero if can't seek there.
4581133e27eSPeter Avalos */
ch_seek(POSITION pos)459*320d7c8aSAaron LI public int ch_seek(POSITION pos)
4601133e27eSPeter Avalos {
4611133e27eSPeter Avalos BLOCKNUM new_block;
4621133e27eSPeter Avalos POSITION len;
4631133e27eSPeter Avalos
4641133e27eSPeter Avalos if (thisfile == NULL)
4651133e27eSPeter Avalos return (0);
4661133e27eSPeter Avalos
4671133e27eSPeter Avalos len = ch_length();
4681133e27eSPeter Avalos if (pos < ch_zero() || (len != NULL_POSITION && pos > len))
4691133e27eSPeter Avalos return (1);
4701133e27eSPeter Avalos
4711133e27eSPeter Avalos new_block = pos / LBUFSIZE;
4721133e27eSPeter Avalos if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos && !buffered(new_block))
4731133e27eSPeter Avalos {
4741133e27eSPeter Avalos if (ch_fpos > pos)
4751133e27eSPeter Avalos return (1);
4761133e27eSPeter Avalos while (ch_fpos < pos)
4771133e27eSPeter Avalos {
4781133e27eSPeter Avalos if (ch_forw_get() == EOI)
4791133e27eSPeter Avalos return (1);
4801133e27eSPeter Avalos if (ABORT_SIGS())
4811133e27eSPeter Avalos return (1);
4821133e27eSPeter Avalos }
4831133e27eSPeter Avalos return (0);
4841133e27eSPeter Avalos }
4851133e27eSPeter Avalos /*
4861133e27eSPeter Avalos * Set read pointer.
4871133e27eSPeter Avalos */
4881133e27eSPeter Avalos ch_block = new_block;
4891133e27eSPeter Avalos ch_offset = pos % LBUFSIZE;
4901133e27eSPeter Avalos return (0);
4911133e27eSPeter Avalos }
4921133e27eSPeter Avalos
4931133e27eSPeter Avalos /*
4941133e27eSPeter Avalos * Seek to the end of the file.
4951133e27eSPeter Avalos */
ch_end_seek(void)496*320d7c8aSAaron LI public int ch_end_seek(void)
4971133e27eSPeter Avalos {
4981133e27eSPeter Avalos POSITION len;
4991133e27eSPeter Avalos
5001133e27eSPeter Avalos if (thisfile == NULL)
5011133e27eSPeter Avalos return (0);
5021133e27eSPeter Avalos
5031133e27eSPeter Avalos if (ch_flags & CH_CANSEEK)
5041133e27eSPeter Avalos ch_fsize = filesize(ch_file);
5051133e27eSPeter Avalos
5061133e27eSPeter Avalos len = ch_length();
5071133e27eSPeter Avalos if (len != NULL_POSITION)
5081133e27eSPeter Avalos return (ch_seek(len));
5091133e27eSPeter Avalos
5101133e27eSPeter Avalos /*
5111133e27eSPeter Avalos * Do it the slow way: read till end of data.
5121133e27eSPeter Avalos */
5131133e27eSPeter Avalos while (ch_forw_get() != EOI)
5141133e27eSPeter Avalos if (ABORT_SIGS())
5151133e27eSPeter Avalos return (1);
5161133e27eSPeter Avalos return (0);
5171133e27eSPeter Avalos }
5181133e27eSPeter Avalos
5191133e27eSPeter Avalos /*
520fa0be7c5SJohn Marino * Seek to the last position in the file that is currently buffered.
521fa0be7c5SJohn Marino */
ch_end_buffer_seek(void)522*320d7c8aSAaron LI public int ch_end_buffer_seek(void)
523fa0be7c5SJohn Marino {
52402d62a0fSDaniel Fojt struct buf *bp;
52502d62a0fSDaniel Fojt struct bufnode *bn;
526fa0be7c5SJohn Marino POSITION buf_pos;
527fa0be7c5SJohn Marino POSITION end_pos;
528fa0be7c5SJohn Marino
529fa0be7c5SJohn Marino if (thisfile == NULL || (ch_flags & CH_CANSEEK))
530fa0be7c5SJohn Marino return (ch_end_seek());
531fa0be7c5SJohn Marino
532fa0be7c5SJohn Marino end_pos = 0;
533fa0be7c5SJohn Marino FOR_BUFS(bn)
534fa0be7c5SJohn Marino {
535fa0be7c5SJohn Marino bp = bufnode_buf(bn);
536fa0be7c5SJohn Marino buf_pos = (bp->block * LBUFSIZE) + bp->datasize;
537fa0be7c5SJohn Marino if (buf_pos > end_pos)
538fa0be7c5SJohn Marino end_pos = buf_pos;
539fa0be7c5SJohn Marino }
540fa0be7c5SJohn Marino
541fa0be7c5SJohn Marino return (ch_seek(end_pos));
542fa0be7c5SJohn Marino }
543fa0be7c5SJohn Marino
544fa0be7c5SJohn Marino /*
5451133e27eSPeter Avalos * Seek to the beginning of the file, or as close to it as we can get.
5461133e27eSPeter Avalos * We may not be able to seek there if input is a pipe and the
5471133e27eSPeter Avalos * beginning of the pipe is no longer buffered.
5481133e27eSPeter Avalos */
ch_beg_seek(void)549*320d7c8aSAaron LI public int ch_beg_seek(void)
5501133e27eSPeter Avalos {
55102d62a0fSDaniel Fojt struct bufnode *bn;
55202d62a0fSDaniel Fojt struct bufnode *firstbn;
5531133e27eSPeter Avalos
5541133e27eSPeter Avalos /*
5551133e27eSPeter Avalos * Try a plain ch_seek first.
5561133e27eSPeter Avalos */
5571133e27eSPeter Avalos if (ch_seek(ch_zero()) == 0)
5581133e27eSPeter Avalos return (0);
5591133e27eSPeter Avalos
5601133e27eSPeter Avalos /*
5611133e27eSPeter Avalos * Can't get to position 0.
5621133e27eSPeter Avalos * Look thru the buffers for the one closest to position 0.
5631133e27eSPeter Avalos */
5648be36e5bSPeter Avalos firstbn = ch_bufhead;
5658be36e5bSPeter Avalos if (firstbn == END_OF_CHAIN)
5661133e27eSPeter Avalos return (1);
5678be36e5bSPeter Avalos FOR_BUFS(bn)
5688be36e5bSPeter Avalos {
5698be36e5bSPeter Avalos if (bufnode_buf(bn)->block < bufnode_buf(firstbn)->block)
5708be36e5bSPeter Avalos firstbn = bn;
5718be36e5bSPeter Avalos }
5728be36e5bSPeter Avalos ch_block = bufnode_buf(firstbn)->block;
5731133e27eSPeter Avalos ch_offset = 0;
5741133e27eSPeter Avalos return (0);
5751133e27eSPeter Avalos }
5761133e27eSPeter Avalos
5771133e27eSPeter Avalos /*
5781133e27eSPeter Avalos * Return the length of the file, if known.
5791133e27eSPeter Avalos */
ch_length(void)580*320d7c8aSAaron LI public POSITION ch_length(void)
5811133e27eSPeter Avalos {
5821133e27eSPeter Avalos if (thisfile == NULL)
5831133e27eSPeter Avalos return (NULL_POSITION);
5841133e27eSPeter Avalos if (ignore_eoi)
5851133e27eSPeter Avalos return (NULL_POSITION);
5861133e27eSPeter Avalos if (ch_flags & CH_HELPFILE)
5871133e27eSPeter Avalos return (size_helpdata);
588e639dc31SJohn Marino if (ch_flags & CH_NODATA)
589e639dc31SJohn Marino return (0);
5901133e27eSPeter Avalos return (ch_fsize);
5911133e27eSPeter Avalos }
5921133e27eSPeter Avalos
5931133e27eSPeter Avalos /*
5941133e27eSPeter Avalos * Return the current position in the file.
5951133e27eSPeter Avalos */
ch_tell(void)596*320d7c8aSAaron LI public POSITION ch_tell(void)
5971133e27eSPeter Avalos {
5981133e27eSPeter Avalos if (thisfile == NULL)
5991133e27eSPeter Avalos return (NULL_POSITION);
6001133e27eSPeter Avalos return (ch_block * LBUFSIZE) + ch_offset;
6011133e27eSPeter Avalos }
6021133e27eSPeter Avalos
6031133e27eSPeter Avalos /*
6041133e27eSPeter Avalos * Get the current char and post-increment the read pointer.
6051133e27eSPeter Avalos */
ch_forw_get(void)606*320d7c8aSAaron LI public int ch_forw_get(void)
6071133e27eSPeter Avalos {
60802d62a0fSDaniel Fojt int c;
6091133e27eSPeter Avalos
6101133e27eSPeter Avalos if (thisfile == NULL)
6111133e27eSPeter Avalos return (EOI);
6121133e27eSPeter Avalos c = ch_get();
6131133e27eSPeter Avalos if (c == EOI)
6141133e27eSPeter Avalos return (EOI);
6151133e27eSPeter Avalos if (ch_offset < LBUFSIZE-1)
6161133e27eSPeter Avalos ch_offset++;
6171133e27eSPeter Avalos else
6181133e27eSPeter Avalos {
6191133e27eSPeter Avalos ch_block ++;
6201133e27eSPeter Avalos ch_offset = 0;
6211133e27eSPeter Avalos }
6221133e27eSPeter Avalos return (c);
6231133e27eSPeter Avalos }
6241133e27eSPeter Avalos
6251133e27eSPeter Avalos /*
6261133e27eSPeter Avalos * Pre-decrement the read pointer and get the new current char.
6271133e27eSPeter Avalos */
ch_back_get(void)628*320d7c8aSAaron LI public int ch_back_get(void)
6291133e27eSPeter Avalos {
6301133e27eSPeter Avalos if (thisfile == NULL)
6311133e27eSPeter Avalos return (EOI);
6321133e27eSPeter Avalos if (ch_offset > 0)
6331133e27eSPeter Avalos ch_offset --;
6341133e27eSPeter Avalos else
6351133e27eSPeter Avalos {
6361133e27eSPeter Avalos if (ch_block <= 0)
6371133e27eSPeter Avalos return (EOI);
6381133e27eSPeter Avalos if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1))
6391133e27eSPeter Avalos return (EOI);
6401133e27eSPeter Avalos ch_block--;
6411133e27eSPeter Avalos ch_offset = LBUFSIZE-1;
6421133e27eSPeter Avalos }
6431133e27eSPeter Avalos return (ch_get());
6441133e27eSPeter Avalos }
6451133e27eSPeter Avalos
6461133e27eSPeter Avalos /*
6471133e27eSPeter Avalos * Set max amount of buffer space.
6481133e27eSPeter Avalos * bufspace is in units of 1024 bytes. -1 mean no limit.
6491133e27eSPeter Avalos */
ch_setbufspace(int bufspace)650*320d7c8aSAaron LI public void ch_setbufspace(int bufspace)
6511133e27eSPeter Avalos {
6521133e27eSPeter Avalos if (bufspace < 0)
6531133e27eSPeter Avalos maxbufs = -1;
6541133e27eSPeter Avalos else
6551133e27eSPeter Avalos {
656*320d7c8aSAaron LI int lbufk = LBUFSIZE / 1024;
657*320d7c8aSAaron LI maxbufs = bufspace / lbufk + (bufspace % lbufk != 0);
6581133e27eSPeter Avalos if (maxbufs < 1)
6591133e27eSPeter Avalos maxbufs = 1;
6601133e27eSPeter Avalos }
6611133e27eSPeter Avalos }
6621133e27eSPeter Avalos
6631133e27eSPeter Avalos /*
6641133e27eSPeter Avalos * Flush (discard) any saved file state, including buffer contents.
6651133e27eSPeter Avalos */
ch_flush(void)666*320d7c8aSAaron LI public void ch_flush(void)
6671133e27eSPeter Avalos {
66802d62a0fSDaniel Fojt struct bufnode *bn;
6691133e27eSPeter Avalos
6701133e27eSPeter Avalos if (thisfile == NULL)
6711133e27eSPeter Avalos return;
6721133e27eSPeter Avalos
6731133e27eSPeter Avalos if (!(ch_flags & CH_CANSEEK))
6741133e27eSPeter Avalos {
6751133e27eSPeter Avalos /*
6761133e27eSPeter Avalos * If input is a pipe, we don't flush buffer contents,
6771133e27eSPeter Avalos * since the contents can't be recovered.
6781133e27eSPeter Avalos */
6791133e27eSPeter Avalos ch_fsize = NULL_POSITION;
6801133e27eSPeter Avalos return;
6811133e27eSPeter Avalos }
6821133e27eSPeter Avalos
6831133e27eSPeter Avalos /*
6841133e27eSPeter Avalos * Initialize all the buffers.
6851133e27eSPeter Avalos */
6868be36e5bSPeter Avalos FOR_BUFS(bn)
6878be36e5bSPeter Avalos {
6888be36e5bSPeter Avalos bufnode_buf(bn)->block = -1;
6898be36e5bSPeter Avalos }
6901133e27eSPeter Avalos
6911133e27eSPeter Avalos /*
6921133e27eSPeter Avalos * Figure out the size of the file, if we can.
6931133e27eSPeter Avalos */
6941133e27eSPeter Avalos ch_fsize = filesize(ch_file);
6951133e27eSPeter Avalos
6961133e27eSPeter Avalos /*
6971133e27eSPeter Avalos * Seek to a known position: the beginning of the file.
6981133e27eSPeter Avalos */
6991133e27eSPeter Avalos ch_fpos = 0;
7001133e27eSPeter Avalos ch_block = 0; /* ch_fpos / LBUFSIZE; */
7011133e27eSPeter Avalos ch_offset = 0; /* ch_fpos % LBUFSIZE; */
7021133e27eSPeter Avalos
7030c7ad07eSAntonio Huete Jimenez #if HAVE_PROCFS
7041133e27eSPeter Avalos /*
7051133e27eSPeter Avalos * This is a kludge to workaround a Linux kernel bug: files in
7061133e27eSPeter Avalos * /proc have a size of 0 according to fstat() but have readable
7071133e27eSPeter Avalos * data. They are sometimes, but not always, seekable.
7081133e27eSPeter Avalos * Force them to be non-seekable here.
7091133e27eSPeter Avalos */
7101133e27eSPeter Avalos if (ch_fsize == 0)
7111133e27eSPeter Avalos {
7120c7ad07eSAntonio Huete Jimenez struct statfs st;
7130c7ad07eSAntonio Huete Jimenez if (fstatfs(ch_file, &st) == 0)
7140c7ad07eSAntonio Huete Jimenez {
7150c7ad07eSAntonio Huete Jimenez if (st.f_type == PROC_SUPER_MAGIC)
7160c7ad07eSAntonio Huete Jimenez {
7171133e27eSPeter Avalos ch_fsize = NULL_POSITION;
7181133e27eSPeter Avalos ch_flags &= ~CH_CANSEEK;
7191133e27eSPeter Avalos }
7200c7ad07eSAntonio Huete Jimenez }
7210c7ad07eSAntonio Huete Jimenez }
7221133e27eSPeter Avalos #endif
7231133e27eSPeter Avalos
7241133e27eSPeter Avalos if (lseek(ch_file, (off_t)0, SEEK_SET) == BAD_LSEEK)
7251133e27eSPeter Avalos {
7261133e27eSPeter Avalos /*
7271133e27eSPeter Avalos * Warning only; even if the seek fails for some reason,
7281133e27eSPeter Avalos * there's a good chance we're at the beginning anyway.
7291133e27eSPeter Avalos * {{ I think this is bogus reasoning. }}
7301133e27eSPeter Avalos */
7311133e27eSPeter Avalos error("seek error to 0", NULL_PARG);
7321133e27eSPeter Avalos }
7331133e27eSPeter Avalos }
7341133e27eSPeter Avalos
7351133e27eSPeter Avalos /*
7361133e27eSPeter Avalos * Allocate a new buffer.
7371133e27eSPeter Avalos * The buffer is added to the tail of the buffer chain.
7381133e27eSPeter Avalos */
ch_addbuf(void)739*320d7c8aSAaron LI static int ch_addbuf(void)
7401133e27eSPeter Avalos {
74102d62a0fSDaniel Fojt struct buf *bp;
74202d62a0fSDaniel Fojt struct bufnode *bn;
7431133e27eSPeter Avalos
7441133e27eSPeter Avalos /*
7451133e27eSPeter Avalos * Allocate and initialize a new buffer and link it
7461133e27eSPeter Avalos * onto the tail of the buffer list.
7471133e27eSPeter Avalos */
7481133e27eSPeter Avalos bp = (struct buf *) calloc(1, sizeof(struct buf));
7491133e27eSPeter Avalos if (bp == NULL)
7501133e27eSPeter Avalos return (1);
7511133e27eSPeter Avalos ch_nbufs++;
7521133e27eSPeter Avalos bp->block = -1;
7538be36e5bSPeter Avalos bn = &bp->node;
7548be36e5bSPeter Avalos
7558be36e5bSPeter Avalos BUF_INS_TAIL(bn);
7568be36e5bSPeter Avalos BUF_HASH_INS(bn, 0);
7571133e27eSPeter Avalos return (0);
7581133e27eSPeter Avalos }
7591133e27eSPeter Avalos
7601133e27eSPeter Avalos /*
7611133e27eSPeter Avalos *
7621133e27eSPeter Avalos */
init_hashtbl(void)763*320d7c8aSAaron LI static void init_hashtbl(void)
7641133e27eSPeter Avalos {
76502d62a0fSDaniel Fojt int h;
7661133e27eSPeter Avalos
7671133e27eSPeter Avalos for (h = 0; h < BUFHASH_SIZE; h++)
7681133e27eSPeter Avalos {
7698be36e5bSPeter Avalos thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h);
7708be36e5bSPeter Avalos thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h);
7711133e27eSPeter Avalos }
7721133e27eSPeter Avalos }
7731133e27eSPeter Avalos
7741133e27eSPeter Avalos /*
7751133e27eSPeter Avalos * Delete all buffers for this file.
7761133e27eSPeter Avalos */
ch_delbufs(void)777*320d7c8aSAaron LI static void ch_delbufs(void)
7781133e27eSPeter Avalos {
77902d62a0fSDaniel Fojt struct bufnode *bn;
7801133e27eSPeter Avalos
7811133e27eSPeter Avalos while (ch_bufhead != END_OF_CHAIN)
7821133e27eSPeter Avalos {
7838be36e5bSPeter Avalos bn = ch_bufhead;
7848be36e5bSPeter Avalos BUF_RM(bn);
7858be36e5bSPeter Avalos free(bufnode_buf(bn));
7861133e27eSPeter Avalos }
7871133e27eSPeter Avalos ch_nbufs = 0;
7881133e27eSPeter Avalos init_hashtbl();
7891133e27eSPeter Avalos }
7901133e27eSPeter Avalos
7911133e27eSPeter Avalos /*
7921133e27eSPeter Avalos * Is it possible to seek on a file descriptor?
7931133e27eSPeter Avalos */
seekable(int f)794*320d7c8aSAaron LI public int seekable(int f)
7951133e27eSPeter Avalos {
7961133e27eSPeter Avalos #if MSDOS_COMPILER
7971133e27eSPeter Avalos extern int fd0;
7981133e27eSPeter Avalos if (f == fd0 && !isatty(fd0))
7991133e27eSPeter Avalos {
8001133e27eSPeter Avalos /*
8011133e27eSPeter Avalos * In MS-DOS, pipes are seekable. Check for
8021133e27eSPeter Avalos * standard input, and pretend it is not seekable.
8031133e27eSPeter Avalos */
8041133e27eSPeter Avalos return (0);
8051133e27eSPeter Avalos }
8061133e27eSPeter Avalos #endif
8071133e27eSPeter Avalos return (lseek(f, (off_t)1, SEEK_SET) != BAD_LSEEK);
8081133e27eSPeter Avalos }
8091133e27eSPeter Avalos
8101133e27eSPeter Avalos /*
811e639dc31SJohn Marino * Force EOF to be at the current read position.
812e639dc31SJohn Marino * This is used after an ignore_eof read, during which the EOF may change.
813e639dc31SJohn Marino */
ch_set_eof(void)814*320d7c8aSAaron LI public void ch_set_eof(void)
815e639dc31SJohn Marino {
8160c7ad07eSAntonio Huete Jimenez if (ch_fsize != NULL_POSITION && ch_fsize < ch_fpos)
817e639dc31SJohn Marino ch_fsize = ch_fpos;
818e639dc31SJohn Marino }
819e639dc31SJohn Marino
820e639dc31SJohn Marino
821e639dc31SJohn Marino /*
8221133e27eSPeter Avalos * Initialize file state for a new file.
8231133e27eSPeter Avalos */
ch_init(int f,int flags)824*320d7c8aSAaron LI public void ch_init(int f, int flags)
8251133e27eSPeter Avalos {
8261133e27eSPeter Avalos /*
8271133e27eSPeter Avalos * See if we already have a filestate for this file.
8281133e27eSPeter Avalos */
8291133e27eSPeter Avalos thisfile = (struct filestate *) get_filestate(curr_ifile);
8301133e27eSPeter Avalos if (thisfile == NULL)
8311133e27eSPeter Avalos {
8321133e27eSPeter Avalos /*
8331133e27eSPeter Avalos * Allocate and initialize a new filestate.
8341133e27eSPeter Avalos */
8351133e27eSPeter Avalos thisfile = (struct filestate *)
8360c7ad07eSAntonio Huete Jimenez ecalloc(1, sizeof(struct filestate));
8378be36e5bSPeter Avalos thisfile->buflist.next = thisfile->buflist.prev = END_OF_CHAIN;
8381133e27eSPeter Avalos thisfile->nbufs = 0;
83902d62a0fSDaniel Fojt thisfile->flags = flags;
8401133e27eSPeter Avalos thisfile->fpos = 0;
8411133e27eSPeter Avalos thisfile->block = 0;
8421133e27eSPeter Avalos thisfile->offset = 0;
8431133e27eSPeter Avalos thisfile->file = -1;
8441133e27eSPeter Avalos thisfile->fsize = NULL_POSITION;
8451133e27eSPeter Avalos init_hashtbl();
8461133e27eSPeter Avalos /*
8471133e27eSPeter Avalos * Try to seek; set CH_CANSEEK if it works.
8481133e27eSPeter Avalos */
8491133e27eSPeter Avalos if ((flags & CH_CANSEEK) && !seekable(f))
8501133e27eSPeter Avalos ch_flags &= ~CH_CANSEEK;
8511133e27eSPeter Avalos set_filestate(curr_ifile, (void *) thisfile);
8521133e27eSPeter Avalos }
8531133e27eSPeter Avalos if (thisfile->file == -1)
8541133e27eSPeter Avalos thisfile->file = f;
8551133e27eSPeter Avalos ch_flush();
8561133e27eSPeter Avalos }
8571133e27eSPeter Avalos
8581133e27eSPeter Avalos /*
8591133e27eSPeter Avalos * Close a filestate.
8601133e27eSPeter Avalos */
ch_close(void)861*320d7c8aSAaron LI public void ch_close(void)
8621133e27eSPeter Avalos {
8631133e27eSPeter Avalos int keepstate = FALSE;
8641133e27eSPeter Avalos
8651133e27eSPeter Avalos if (thisfile == NULL)
8661133e27eSPeter Avalos return;
8671133e27eSPeter Avalos
86802d62a0fSDaniel Fojt if ((ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE)) && !(ch_flags & CH_KEEPOPEN))
8691133e27eSPeter Avalos {
8701133e27eSPeter Avalos /*
8711133e27eSPeter Avalos * We can seek or re-open, so we don't need to keep buffers.
8721133e27eSPeter Avalos */
8731133e27eSPeter Avalos ch_delbufs();
8741133e27eSPeter Avalos } else
8751133e27eSPeter Avalos keepstate = TRUE;
8761133e27eSPeter Avalos if (!(ch_flags & CH_KEEPOPEN))
8771133e27eSPeter Avalos {
8781133e27eSPeter Avalos /*
8791133e27eSPeter Avalos * We don't need to keep the file descriptor open
8801133e27eSPeter Avalos * (because we can re-open it.)
8811133e27eSPeter Avalos * But don't really close it if it was opened via popen(),
8821133e27eSPeter Avalos * because pclose() wants to close it.
8831133e27eSPeter Avalos */
8841133e27eSPeter Avalos if (!(ch_flags & (CH_POPENED|CH_HELPFILE)))
8851133e27eSPeter Avalos close(ch_file);
8861133e27eSPeter Avalos ch_file = -1;
8871133e27eSPeter Avalos } else
8881133e27eSPeter Avalos keepstate = TRUE;
8891133e27eSPeter Avalos if (!keepstate)
8901133e27eSPeter Avalos {
8911133e27eSPeter Avalos /*
8921133e27eSPeter Avalos * We don't even need to keep the filestate structure.
8931133e27eSPeter Avalos */
8941133e27eSPeter Avalos free(thisfile);
8951133e27eSPeter Avalos thisfile = NULL;
8961133e27eSPeter Avalos set_filestate(curr_ifile, (void *) NULL);
8971133e27eSPeter Avalos }
8981133e27eSPeter Avalos }
8991133e27eSPeter Avalos
9001133e27eSPeter Avalos /*
9011133e27eSPeter Avalos * Return ch_flags for the current file.
9021133e27eSPeter Avalos */
ch_getflags(void)903*320d7c8aSAaron LI public int ch_getflags(void)
9041133e27eSPeter Avalos {
9051133e27eSPeter Avalos if (thisfile == NULL)
9061133e27eSPeter Avalos return (0);
9071133e27eSPeter Avalos return (ch_flags);
9081133e27eSPeter Avalos }
9091133e27eSPeter Avalos
9101133e27eSPeter Avalos #if 0
911*320d7c8aSAaron LI static void ch_dump(struct filestate *fs)
9121133e27eSPeter Avalos {
9131133e27eSPeter Avalos struct buf *bp;
9148be36e5bSPeter Avalos struct bufnode *bn;
9151133e27eSPeter Avalos unsigned char *s;
9161133e27eSPeter Avalos
9171133e27eSPeter Avalos if (fs == NULL)
9181133e27eSPeter Avalos {
9191133e27eSPeter Avalos printf(" --no filestate\n");
9201133e27eSPeter Avalos return;
9211133e27eSPeter Avalos }
9221133e27eSPeter Avalos printf(" file %d, flags %x, fpos %x, fsize %x, blk/off %x/%x\n",
9231133e27eSPeter Avalos fs->file, fs->flags, fs->fpos,
9241133e27eSPeter Avalos fs->fsize, fs->block, fs->offset);
9251133e27eSPeter Avalos printf(" %d bufs:\n", fs->nbufs);
9268be36e5bSPeter Avalos for (bn = fs->next; bn != &fs->buflist; bn = bn->next)
9271133e27eSPeter Avalos {
9288be36e5bSPeter Avalos bp = bufnode_buf(bn);
9291133e27eSPeter Avalos printf("%x: blk %x, size %x \"",
9301133e27eSPeter Avalos bp, bp->block, bp->datasize);
9311133e27eSPeter Avalos for (s = bp->data; s < bp->data + 30; s++)
9321133e27eSPeter Avalos if (*s >= ' ' && *s < 0x7F)
9331133e27eSPeter Avalos printf("%c", *s);
9341133e27eSPeter Avalos else
9351133e27eSPeter Avalos printf(".");
9361133e27eSPeter Avalos printf("\"\n");
9371133e27eSPeter Avalos }
9381133e27eSPeter Avalos }
9391133e27eSPeter Avalos #endif
940