("" < 3.4) always evaluates to true, which unconditionally
[dragonfly.git] / contrib / less-381 / ch.c
blob0446a2c2292a6b42f37ead06966137bec3967bf7
1 /*
2 * Copyright (C) 1984-2002 Mark Nudelman
4 * You may distribute under the terms of either the GNU General Public
5 * License or the Less License, as specified in the README file.
7 * For more information about less, or for information on how to
8 * contact the author, see the README file.
9 */
13 * Low level character input from the input file.
14 * We use these special purpose routines which optimize moving
15 * both forward and backward from the current read pointer.
18 #include "less.h"
19 #if MSDOS_COMPILER==WIN32C
20 #include <errno.h>
21 #include <windows.h>
22 #endif
24 typedef POSITION BLOCKNUM;
26 public int ignore_eoi;
29 * Pool of buffers holding the most recently used blocks of the input file.
30 * The buffer pool is kept as a doubly-linked circular list,
31 * in order from most- to least-recently used.
32 * The circular list is anchored by the file state "thisfile".
34 #define LBUFSIZE 8192
35 struct buf {
36 struct buf *next, *prev;
37 struct buf *hnext, *hprev;
38 BLOCKNUM block;
39 unsigned int datasize;
40 unsigned char data[LBUFSIZE];
43 struct buflist {
44 /* -- Following members must match struct buf */
45 struct buf *buf_next, *buf_prev;
46 struct buf *buf_hnext, *buf_hprev;
50 * The file state is maintained in a filestate structure.
51 * A pointer to the filestate is kept in the ifile structure.
53 #define BUFHASH_SIZE 64
54 struct filestate {
55 struct buf *buf_next, *buf_prev;
56 struct buflist hashtbl[BUFHASH_SIZE];
57 int file;
58 int flags;
59 POSITION fpos;
60 int nbufs;
61 BLOCKNUM block;
62 unsigned int offset;
63 POSITION fsize;
66 #define ch_bufhead thisfile->buf_next
67 #define ch_buftail thisfile->buf_prev
68 #define ch_nbufs thisfile->nbufs
69 #define ch_block thisfile->block
70 #define ch_offset thisfile->offset
71 #define ch_fpos thisfile->fpos
72 #define ch_fsize thisfile->fsize
73 #define ch_flags thisfile->flags
74 #define ch_file thisfile->file
76 #define END_OF_CHAIN ((struct buf *)&thisfile->buf_next)
77 #define END_OF_HCHAIN(h) ((struct buf *)&thisfile->hashtbl[h])
78 #define BUFHASH(blk) ((blk) & (BUFHASH_SIZE-1))
80 #define FOR_BUFS_IN_CHAIN(h,bp) \
81 for (bp = thisfile->hashtbl[h].buf_hnext; \
82 bp != END_OF_HCHAIN(h); bp = bp->hnext)
84 #define HASH_RM(bp) \
85 (bp)->hnext->hprev = (bp)->hprev; \
86 (bp)->hprev->hnext = (bp)->hnext;
88 #define HASH_INS(bp,h) \
89 (bp)->hnext = thisfile->hashtbl[h].buf_hnext; \
90 (bp)->hprev = END_OF_HCHAIN(h); \
91 thisfile->hashtbl[h].buf_hnext->hprev = (bp); \
92 thisfile->hashtbl[h].buf_hnext = (bp);
94 static struct filestate *thisfile;
95 static int ch_ungotchar = -1;
96 static int maxbufs = -1;
98 extern int autobuf;
99 extern int sigs;
100 extern int secure;
101 extern constant char helpdata[];
102 extern constant int size_helpdata;
103 extern IFILE curr_ifile;
104 #if LOGFILE
105 extern int logfile;
106 extern char *namelogfile;
107 #endif
109 static int ch_addbuf();
113 * Get the character pointed to by the read pointer.
114 * ch_get() is a macro which is more efficient to call
115 * than fch_get (the function), in the usual case
116 * that the block desired is at the head of the chain.
118 #define ch_get() ((ch_block == ch_bufhead->block && \
119 ch_offset < ch_bufhead->datasize) ? \
120 ch_bufhead->data[ch_offset] : fch_get())
122 fch_get()
124 register struct buf *bp;
125 register int n;
126 register int slept;
127 register int h;
128 POSITION pos;
129 POSITION len;
131 slept = FALSE;
134 * Look for a buffer holding the desired block.
136 h = BUFHASH(ch_block);
137 FOR_BUFS_IN_CHAIN(h, bp)
139 if (bp->block == ch_block)
141 if (ch_offset >= bp->datasize)
143 * Need more data in this buffer.
145 goto read_more;
146 goto found;
150 * Block is not in a buffer.
151 * Take the least recently used buffer
152 * and read the desired block into it.
153 * If the LRU buffer has data in it,
154 * then maybe allocate a new buffer.
156 if (ch_buftail == END_OF_CHAIN || ch_buftail->block != -1)
159 * There is no empty buffer to use.
160 * Allocate a new buffer if:
161 * 1. We can't seek on this file and -b is not in effect; or
162 * 2. We haven't allocated the max buffers for this file yet.
164 if ((autobuf && !(ch_flags & CH_CANSEEK)) ||
165 (maxbufs < 0 || ch_nbufs < maxbufs))
166 if (ch_addbuf())
168 * Allocation failed: turn off autobuf.
170 autobuf = OPT_OFF;
172 bp = ch_buftail;
173 HASH_RM(bp); /* Remove from old hash chain. */
174 bp->block = ch_block;
175 bp->datasize = 0;
176 HASH_INS(bp, h); /* Insert into new hash chain. */
178 read_more:
179 pos = (ch_block * LBUFSIZE) + bp->datasize;
180 if ((len = ch_length()) != NULL_POSITION && pos >= len)
182 * At end of file.
184 return (EOI);
186 if (pos != ch_fpos)
189 * Not at the correct position: must seek.
190 * If input is a pipe, we're in trouble (can't seek on a pipe).
191 * Some data has been lost: just return "?".
193 if (!(ch_flags & CH_CANSEEK))
194 return ('?');
195 if (lseek(ch_file, (off_t)pos, 0) == BAD_LSEEK)
197 error("seek error", NULL_PARG);
198 clear_eol();
199 return (EOI);
201 ch_fpos = pos;
205 * Read the block.
206 * If we read less than a full block, that's ok.
207 * We use partial block and pick up the rest next time.
209 if (ch_ungotchar != -1)
211 bp->data[bp->datasize] = ch_ungotchar;
212 n = 1;
213 ch_ungotchar = -1;
214 } else if (ch_flags & CH_HELPFILE)
216 bp->data[bp->datasize] = helpdata[ch_fpos];
217 n = 1;
218 } else
220 n = iread(ch_file, &bp->data[bp->datasize],
221 (unsigned int)(LBUFSIZE - bp->datasize));
224 if (n == READ_INTR)
225 return (EOI);
226 if (n < 0)
228 #if MSDOS_COMPILER==WIN32C
229 if (errno != EPIPE)
230 #endif
232 error("read error", NULL_PARG);
233 clear_eol();
235 n = 0;
238 #if LOGFILE
240 * If we have a log file, write the new data to it.
242 if (!secure && logfile >= 0 && n > 0)
243 write(logfile, (char *) &bp->data[bp->datasize], n);
244 #endif
246 ch_fpos += n;
247 bp->datasize += n;
250 * If we have read to end of file, set ch_fsize to indicate
251 * the position of the end of file.
253 if (n == 0)
255 ch_fsize = pos;
256 if (ignore_eoi)
259 * We are ignoring EOF.
260 * Wait a while, then try again.
262 if (!slept)
264 PARG parg;
265 parg.p_string = wait_message();
266 ierror("%s", &parg);
268 #if !MSDOS_COMPILER
269 sleep(1);
270 #else
271 #if MSDOS_COMPILER==WIN32C
272 Sleep(1000);
273 #endif
274 #endif
275 slept = TRUE;
277 if (sigs)
278 return (EOI);
281 found:
282 if (ch_bufhead != bp)
285 * Move the buffer to the head of the buffer chain.
286 * This orders the buffer chain, most- to least-recently used.
288 bp->next->prev = bp->prev;
289 bp->prev->next = bp->next;
290 bp->next = ch_bufhead;
291 bp->prev = END_OF_CHAIN;
292 ch_bufhead->prev = bp;
293 ch_bufhead = bp;
296 * Move to head of hash chain too.
298 HASH_RM(bp);
299 HASH_INS(bp, h);
302 if (ch_offset >= bp->datasize)
304 * After all that, we still don't have enough data.
305 * Go back and try again.
307 goto read_more;
309 return (bp->data[ch_offset]);
313 * ch_ungetchar is a rather kludgy and limited way to push
314 * a single char onto an input file descriptor.
316 public void
317 ch_ungetchar(c)
318 int c;
320 if (c != -1 && ch_ungotchar != -1)
321 error("ch_ungetchar overrun", NULL_PARG);
322 ch_ungotchar = c;
325 #if LOGFILE
327 * Close the logfile.
328 * If we haven't read all of standard input into it, do that now.
330 public void
331 end_logfile()
333 static int tried = FALSE;
335 if (logfile < 0)
336 return;
337 if (!tried && ch_fsize == NULL_POSITION)
339 tried = TRUE;
340 ierror("Finishing logfile", NULL_PARG);
341 while (ch_forw_get() != EOI)
342 if (ABORT_SIGS())
343 break;
345 close(logfile);
346 logfile = -1;
347 namelogfile = NULL;
351 * Start a log file AFTER less has already been running.
352 * Invoked from the - command; see toggle_option().
353 * Write all the existing buffered data to the log file.
355 public void
356 sync_logfile()
358 register struct buf *bp;
359 int warned = FALSE;
360 BLOCKNUM block;
361 BLOCKNUM nblocks;
363 nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;
364 for (block = 0; block < nblocks; block++)
366 for (bp = ch_bufhead; ; bp = bp->next)
368 if (bp == END_OF_CHAIN)
370 if (!warned)
372 error("Warning: log file is incomplete",
373 NULL_PARG);
374 warned = TRUE;
376 break;
378 if (bp->block == block)
380 write(logfile, (char *) bp->data, bp->datasize);
381 break;
387 #endif
390 * Determine if a specific block is currently in one of the buffers.
392 static int
393 buffered(block)
394 BLOCKNUM block;
396 register struct buf *bp;
397 register int h;
399 h = BUFHASH(block);
400 FOR_BUFS_IN_CHAIN(h, bp)
402 if (bp->block == block)
403 return (TRUE);
405 return (FALSE);
409 * Seek to a specified position in the file.
410 * Return 0 if successful, non-zero if can't seek there.
412 public int
413 ch_seek(pos)
414 register POSITION pos;
416 BLOCKNUM new_block;
417 POSITION len;
419 len = ch_length();
420 if (pos < ch_zero() || (len != NULL_POSITION && pos > len))
421 return (1);
423 new_block = pos / LBUFSIZE;
424 if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos && !buffered(new_block))
426 if (ch_fpos > pos)
427 return (1);
428 while (ch_fpos < pos)
430 if (ch_forw_get() == EOI)
431 return (1);
432 if (ABORT_SIGS())
433 return (1);
435 return (0);
438 * Set read pointer.
440 ch_block = new_block;
441 ch_offset = pos % LBUFSIZE;
442 return (0);
446 * Seek to the end of the file.
448 public int
449 ch_end_seek()
451 POSITION len;
453 if (ch_flags & CH_CANSEEK)
454 ch_fsize = filesize(ch_file);
456 len = ch_length();
457 if (len != NULL_POSITION)
458 return (ch_seek(len));
461 * Do it the slow way: read till end of data.
463 while (ch_forw_get() != EOI)
464 if (ABORT_SIGS())
465 return (1);
466 return (0);
470 * Seek to the beginning of the file, or as close to it as we can get.
471 * We may not be able to seek there if input is a pipe and the
472 * beginning of the pipe is no longer buffered.
474 public int
475 ch_beg_seek()
477 register struct buf *bp, *firstbp;
480 * Try a plain ch_seek first.
482 if (ch_seek(ch_zero()) == 0)
483 return (0);
486 * Can't get to position 0.
487 * Look thru the buffers for the one closest to position 0.
489 firstbp = bp = ch_bufhead;
490 if (bp == END_OF_CHAIN)
491 return (1);
492 while ((bp = bp->next) != END_OF_CHAIN)
493 if (bp->block < firstbp->block)
494 firstbp = bp;
495 ch_block = firstbp->block;
496 ch_offset = 0;
497 return (0);
501 * Return the length of the file, if known.
503 public POSITION
504 ch_length()
506 if (ignore_eoi)
507 return (NULL_POSITION);
508 if (ch_flags & CH_HELPFILE)
509 return (size_helpdata);
510 return (ch_fsize);
514 * Return the current position in the file.
516 public POSITION
517 ch_tell()
519 return (ch_block * LBUFSIZE) + ch_offset;
523 * Get the current char and post-increment the read pointer.
525 public int
526 ch_forw_get()
528 register int c;
530 c = ch_get();
531 if (c == EOI)
532 return (EOI);
533 if (ch_offset < LBUFSIZE-1)
534 ch_offset++;
535 else
537 ch_block ++;
538 ch_offset = 0;
540 return (c);
544 * Pre-decrement the read pointer and get the new current char.
546 public int
547 ch_back_get()
549 if (ch_offset > 0)
550 ch_offset --;
551 else
553 if (ch_block <= 0)
554 return (EOI);
555 if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1))
556 return (EOI);
557 ch_block--;
558 ch_offset = LBUFSIZE-1;
560 return (ch_get());
564 * Set max amount of buffer space.
565 * bufspace is in units of 1024 bytes. -1 mean no limit.
567 public void
568 ch_setbufspace(bufspace)
569 int bufspace;
571 if (bufspace < 0)
572 maxbufs = -1;
573 else
575 maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE;
576 if (maxbufs < 1)
577 maxbufs = 1;
582 * Flush (discard) any saved file state, including buffer contents.
584 public void
585 ch_flush()
587 register struct buf *bp;
589 if (!(ch_flags & CH_CANSEEK))
592 * If input is a pipe, we don't flush buffer contents,
593 * since the contents can't be recovered.
595 ch_fsize = NULL_POSITION;
596 return;
600 * Initialize all the buffers.
602 for (bp = ch_bufhead; bp != END_OF_CHAIN; bp = bp->next)
603 bp->block = -1;
606 * Figure out the size of the file, if we can.
608 ch_fsize = filesize(ch_file);
611 * Seek to a known position: the beginning of the file.
613 ch_fpos = 0;
614 ch_block = 0; /* ch_fpos / LBUFSIZE; */
615 ch_offset = 0; /* ch_fpos % LBUFSIZE; */
617 #if 1
619 * This is a kludge to workaround a Linux kernel bug: files in
620 * /proc have a size of 0 according to fstat() but have readable
621 * data. They are sometimes, but not always, seekable.
622 * Force them to be non-seekable here.
624 if (ch_fsize == 0)
626 ch_fsize = NULL_POSITION;
627 ch_flags &= ~CH_CANSEEK;
629 #endif
631 if (lseek(ch_file, (off_t)0, 0) == BAD_LSEEK)
634 * Warning only; even if the seek fails for some reason,
635 * there's a good chance we're at the beginning anyway.
636 * {{ I think this is bogus reasoning. }}
638 error("seek error to 0", NULL_PARG);
643 * Allocate a new buffer.
644 * The buffer is added to the tail of the buffer chain.
646 static int
647 ch_addbuf()
649 register struct buf *bp;
652 * Allocate and initialize a new buffer and link it
653 * onto the tail of the buffer list.
655 bp = (struct buf *) calloc(1, sizeof(struct buf));
656 if (bp == NULL)
657 return (1);
658 ch_nbufs++;
659 bp->block = -1;
660 bp->next = END_OF_CHAIN;
661 bp->prev = ch_buftail;
662 ch_buftail->next = bp;
663 ch_buftail = bp;
664 HASH_INS(bp, 0);
665 return (0);
671 static void
672 init_hashtbl()
674 register int h;
676 for (h = 0; h < BUFHASH_SIZE; h++)
678 thisfile->hashtbl[h].buf_hnext = END_OF_HCHAIN(h);
679 thisfile->hashtbl[h].buf_hprev = END_OF_HCHAIN(h);
684 * Delete all buffers for this file.
686 static void
687 ch_delbufs()
689 register struct buf *bp;
691 while (ch_bufhead != END_OF_CHAIN)
693 bp = ch_bufhead;
694 bp->next->prev = bp->prev;;
695 bp->prev->next = bp->next;
696 free(bp);
698 ch_nbufs = 0;
699 init_hashtbl();
703 * Is it possible to seek on a file descriptor?
705 public int
706 seekable(f)
707 int f;
709 #if MSDOS_COMPILER
710 extern int fd0;
711 if (f == fd0 && !isatty(fd0))
714 * In MS-DOS, pipes are seekable. Check for
715 * standard input, and pretend it is not seekable.
717 return (0);
719 #endif
720 return (lseek(f, (off_t)1, 0) != BAD_LSEEK);
724 * Initialize file state for a new file.
726 public void
727 ch_init(f, flags)
728 int f;
729 int flags;
732 * See if we already have a filestate for this file.
734 thisfile = (struct filestate *) get_filestate(curr_ifile);
735 if (thisfile == NULL)
738 * Allocate and initialize a new filestate.
740 thisfile = (struct filestate *)
741 calloc(1, sizeof(struct filestate));
742 thisfile->buf_next = thisfile->buf_prev = END_OF_CHAIN;
743 thisfile->nbufs = 0;
744 thisfile->flags = 0;
745 thisfile->fpos = 0;
746 thisfile->block = 0;
747 thisfile->offset = 0;
748 thisfile->file = -1;
749 thisfile->fsize = NULL_POSITION;
750 ch_flags = flags;
751 init_hashtbl();
753 * Try to seek; set CH_CANSEEK if it works.
755 if ((flags & CH_CANSEEK) && !seekable(f))
756 ch_flags &= ~CH_CANSEEK;
757 set_filestate(curr_ifile, (void *) thisfile);
759 if (thisfile->file == -1)
760 thisfile->file = f;
761 ch_flush();
765 * Close a filestate.
767 public void
768 ch_close()
770 int keepstate = FALSE;
772 if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE))
775 * We can seek or re-open, so we don't need to keep buffers.
777 ch_delbufs();
778 } else
779 keepstate = TRUE;
780 if (!(ch_flags & CH_KEEPOPEN))
783 * We don't need to keep the file descriptor open
784 * (because we can re-open it.)
785 * But don't really close it if it was opened via popen(),
786 * because pclose() wants to close it.
788 if (!(ch_flags & (CH_POPENED|CH_HELPFILE)))
789 close(ch_file);
790 ch_file = -1;
791 } else
792 keepstate = TRUE;
793 if (!keepstate)
796 * We don't even need to keep the filestate structure.
798 free(thisfile);
799 thisfile = NULL;
800 set_filestate(curr_ifile, (void *) NULL);
805 * Return ch_flags for the current file.
807 public int
808 ch_getflags()
810 return (ch_flags);
813 #if 0
814 public void
815 ch_dump(struct filestate *fs)
817 struct buf *bp;
818 unsigned char *s;
820 if (fs == NULL)
822 printf(" --no filestate\n");
823 return;
825 printf(" file %d, flags %x, fpos %x, fsize %x, blk/off %x/%x\n",
826 fs->file, fs->flags, fs->fpos,
827 fs->fsize, fs->block, fs->offset);
828 printf(" %d bufs:\n", fs->nbufs);
829 for (bp = fs->buf_next; bp != (struct buf *)fs; bp = bp->next)
831 printf("%x: blk %x, size %x \"",
832 bp, bp->block, bp->datasize);
833 for (s = bp->data; s < bp->data + 30; s++)
834 if (*s >= ' ' && *s < 0x7F)
835 printf("%c", *s);
836 else
837 printf(".");
838 printf("\"\n");
841 #endif