summaryrefslogtreecommitdiffstats
path: root/contrib/less/ch.c
diff options
context:
space:
mode:
authordelphij <delphij@FreeBSD.org>2009-05-08 23:34:35 +0000
committerdelphij <delphij@FreeBSD.org>2009-05-08 23:34:35 +0000
commitd069efd47cacc3156036ed37d5532d6a1d4f55c3 (patch)
tree2526f6b109843b646672c1537476dc51e56c0454 /contrib/less/ch.c
parent6aa3e25391d160482339ee072c010bcd22dfbbd1 (diff)
downloadFreeBSD-src-d069efd47cacc3156036ed37d5532d6a1d4f55c3.zip
FreeBSD-src-d069efd47cacc3156036ed37d5532d6a1d4f55c3.tar.gz
Flatten all tags of the dist tree of less.
Diffstat (limited to 'contrib/less/ch.c')
-rw-r--r--contrib/less/ch.c893
1 files changed, 0 insertions, 893 deletions
diff --git a/contrib/less/ch.c b/contrib/less/ch.c
deleted file mode 100644
index eb607d5..0000000
--- a/contrib/less/ch.c
+++ /dev/null
@@ -1,893 +0,0 @@
-/*
- * Copyright (C) 1984-2007 Mark Nudelman
- *
- * You may distribute under the terms of either the GNU General Public
- * License or the Less License, as specified in the README file.
- *
- * For more information about less, or for information on how to
- * contact the author, see the README file.
- */
-
-
-/*
- * Low level character input from the input file.
- * We use these special purpose routines which optimize moving
- * both forward and backward from the current read pointer.
- */
-
-#include "less.h"
-#if MSDOS_COMPILER==WIN32C
-#include <errno.h>
-#include <windows.h>
-#endif
-
-#if HAVE_STAT_INO
-#include <sys/stat.h>
-extern dev_t curr_dev;
-extern ino_t curr_ino;
-#endif
-
-typedef POSITION BLOCKNUM;
-
-public int ignore_eoi;
-
-/*
- * Pool of buffers holding the most recently used blocks of the input file.
- * The buffer pool is kept as a doubly-linked circular list,
- * in order from most- to least-recently used.
- * The circular list is anchored by the file state "thisfile".
- */
-#define LBUFSIZE 8192
-struct buf {
- struct buf *next, *prev;
- struct buf *hnext, *hprev;
- BLOCKNUM block;
- unsigned int datasize;
- unsigned char data[LBUFSIZE];
-};
-
-struct buflist {
- /* -- Following members must match struct buf */
- struct buf *buf_next, *buf_prev;
- struct buf *buf_hnext, *buf_hprev;
-};
-
-/*
- * The file state is maintained in a filestate structure.
- * A pointer to the filestate is kept in the ifile structure.
- */
-#define BUFHASH_SIZE 64
-struct filestate {
- struct buf *buf_next, *buf_prev;
- struct buflist hashtbl[BUFHASH_SIZE];
- int file;
- int flags;
- POSITION fpos;
- int nbufs;
- BLOCKNUM block;
- unsigned int offset;
- POSITION fsize;
-};
-
-#define ch_bufhead thisfile->buf_next
-#define ch_buftail thisfile->buf_prev
-#define ch_nbufs thisfile->nbufs
-#define ch_block thisfile->block
-#define ch_offset thisfile->offset
-#define ch_fpos thisfile->fpos
-#define ch_fsize thisfile->fsize
-#define ch_flags thisfile->flags
-#define ch_file thisfile->file
-
-#define END_OF_CHAIN ((struct buf *)&thisfile->buf_next)
-#define END_OF_HCHAIN(h) ((struct buf *)&thisfile->hashtbl[h])
-#define BUFHASH(blk) ((blk) & (BUFHASH_SIZE-1))
-
-#define FOR_BUFS_IN_CHAIN(h,bp) \
- for (bp = thisfile->hashtbl[h].buf_hnext; \
- bp != END_OF_HCHAIN(h); bp = bp->hnext)
-
-#define HASH_RM(bp) \
- (bp)->hnext->hprev = (bp)->hprev; \
- (bp)->hprev->hnext = (bp)->hnext;
-
-#define HASH_INS(bp,h) \
- (bp)->hnext = thisfile->hashtbl[h].buf_hnext; \
- (bp)->hprev = END_OF_HCHAIN(h); \
- thisfile->hashtbl[h].buf_hnext->hprev = (bp); \
- thisfile->hashtbl[h].buf_hnext = (bp);
-
-static struct filestate *thisfile;
-static int ch_ungotchar = -1;
-static int maxbufs = -1;
-
-extern int autobuf;
-extern int sigs;
-extern int secure;
-extern int screen_trashed;
-extern int follow_mode;
-extern constant char helpdata[];
-extern constant int size_helpdata;
-extern IFILE curr_ifile;
-#if LOGFILE
-extern int logfile;
-extern char *namelogfile;
-#endif
-
-static int ch_addbuf();
-
-
-/*
- * Get the character pointed to by the read pointer.
- * ch_get() is a macro which is more efficient to call
- * than fch_get (the function), in the usual case
- * that the block desired is at the head of the chain.
- */
-#define ch_get() ((ch_block == ch_bufhead->block && \
- ch_offset < ch_bufhead->datasize) ? \
- ch_bufhead->data[ch_offset] : fch_get())
- int
-fch_get()
-{
- register struct buf *bp;
- register int n;
- register int slept;
- register int h;
- POSITION pos;
- POSITION len;
-
- if (thisfile == NULL)
- return (EOI);
-
- slept = FALSE;
-
- /*
- * Look for a buffer holding the desired block.
- */
- h = BUFHASH(ch_block);
- FOR_BUFS_IN_CHAIN(h, bp)
- {
- if (bp->block == ch_block)
- {
- if (ch_offset >= bp->datasize)
- /*
- * Need more data in this buffer.
- */
- goto read_more;
- goto found;
- }
- }
- /*
- * Block is not in a buffer.
- * Take the least recently used buffer
- * and read the desired block into it.
- * If the LRU buffer has data in it,
- * then maybe allocate a new buffer.
- */
- if (ch_buftail == END_OF_CHAIN || ch_buftail->block != -1)
- {
- /*
- * There is no empty buffer to use.
- * Allocate a new buffer if:
- * 1. We can't seek on this file and -b is not in effect; or
- * 2. We haven't allocated the max buffers for this file yet.
- */
- if ((autobuf && !(ch_flags & CH_CANSEEK)) ||
- (maxbufs < 0 || ch_nbufs < maxbufs))
- if (ch_addbuf())
- /*
- * Allocation failed: turn off autobuf.
- */
- autobuf = OPT_OFF;
- }
- bp = ch_buftail;
- HASH_RM(bp); /* Remove from old hash chain. */
- bp->block = ch_block;
- bp->datasize = 0;
- HASH_INS(bp, h); /* Insert into new hash chain. */
-
- read_more:
- pos = (ch_block * LBUFSIZE) + bp->datasize;
- if ((len = ch_length()) != NULL_POSITION && pos >= len)
- /*
- * At end of file.
- */
- return (EOI);
-
- if (pos != ch_fpos)
- {
- /*
- * Not at the correct position: must seek.
- * If input is a pipe, we're in trouble (can't seek on a pipe).
- * Some data has been lost: just return "?".
- */
- if (!(ch_flags & CH_CANSEEK))
- return ('?');
- if (lseek(ch_file, (off_t)pos, SEEK_SET) == BAD_LSEEK)
- {
- error("seek error", NULL_PARG);
- clear_eol();
- return (EOI);
- }
- ch_fpos = pos;
- }
-
- /*
- * Read the block.
- * If we read less than a full block, that's ok.
- * We use partial block and pick up the rest next time.
- */
- if (ch_ungotchar != -1)
- {
- bp->data[bp->datasize] = ch_ungotchar;
- n = 1;
- ch_ungotchar = -1;
- } else if (ch_flags & CH_HELPFILE)
- {
- bp->data[bp->datasize] = helpdata[ch_fpos];
- n = 1;
- } else
- {
- n = iread(ch_file, &bp->data[bp->datasize],
- (unsigned int)(LBUFSIZE - bp->datasize));
- }
-
- if (n == READ_INTR)
- return (EOI);
- if (n < 0)
- {
-#if MSDOS_COMPILER==WIN32C
- if (errno != EPIPE)
-#endif
- {
- error("read error", NULL_PARG);
- clear_eol();
- }
- n = 0;
- }
-
-#if LOGFILE
- /*
- * If we have a log file, write the new data to it.
- */
- if (!secure && logfile >= 0 && n > 0)
- write(logfile, (char *) &bp->data[bp->datasize], n);
-#endif
-
- ch_fpos += n;
- bp->datasize += n;
-
- /*
- * If we have read to end of file, set ch_fsize to indicate
- * the position of the end of file.
- */
- if (n == 0)
- {
- ch_fsize = pos;
- if (ignore_eoi)
- {
- /*
- * We are ignoring EOF.
- * Wait a while, then try again.
- */
- if (!slept)
- {
- PARG parg;
- parg.p_string = wait_message();
- ierror("%s", &parg);
- }
-#if !MSDOS_COMPILER
- sleep(1);
-#else
-#if MSDOS_COMPILER==WIN32C
- Sleep(1000);
-#endif
-#endif
- slept = TRUE;
-
-#if HAVE_STAT_INO
- if (follow_mode == FOLLOW_NAME)
- {
- /* See whether the file's i-number has changed.
- * If so, force the file to be closed and
- * reopened. */
- struct stat st;
- int r = stat(get_filename(curr_ifile), &st);
- if (r == 0 && (st.st_ino != curr_ino ||
- st.st_dev != curr_dev))
- {
- /* screen_trashed=2 causes
- * make_display to reopen the file. */
- screen_trashed = 2;
- return (EOI);
- }
- }
-#endif
- }
- if (sigs)
- return (EOI);
- }
-
- found:
- if (ch_bufhead != bp)
- {
- /*
- * Move the buffer to the head of the buffer chain.
- * This orders the buffer chain, most- to least-recently used.
- */
- bp->next->prev = bp->prev;
- bp->prev->next = bp->next;
- bp->next = ch_bufhead;
- bp->prev = END_OF_CHAIN;
- ch_bufhead->prev = bp;
- ch_bufhead = bp;
-
- /*
- * Move to head of hash chain too.
- */
- HASH_RM(bp);
- HASH_INS(bp, h);
- }
-
- if (ch_offset >= bp->datasize)
- /*
- * After all that, we still don't have enough data.
- * Go back and try again.
- */
- goto read_more;
-
- return (bp->data[ch_offset]);
-}
-
-/*
- * ch_ungetchar is a rather kludgy and limited way to push
- * a single char onto an input file descriptor.
- */
- public void
-ch_ungetchar(c)
- int c;
-{
- if (c != -1 && ch_ungotchar != -1)
- error("ch_ungetchar overrun", NULL_PARG);
- ch_ungotchar = c;
-}
-
-#if LOGFILE
-/*
- * Close the logfile.
- * If we haven't read all of standard input into it, do that now.
- */
- public void
-end_logfile()
-{
- static int tried = FALSE;
-
- if (logfile < 0)
- return;
- if (!tried && ch_fsize == NULL_POSITION)
- {
- tried = TRUE;
- ierror("Finishing logfile", NULL_PARG);
- while (ch_forw_get() != EOI)
- if (ABORT_SIGS())
- break;
- }
- close(logfile);
- logfile = -1;
- namelogfile = NULL;
-}
-
-/*
- * Start a log file AFTER less has already been running.
- * Invoked from the - command; see toggle_option().
- * Write all the existing buffered data to the log file.
- */
- public void
-sync_logfile()
-{
- register struct buf *bp;
- int warned = FALSE;
- BLOCKNUM block;
- BLOCKNUM nblocks;
-
- nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE;
- for (block = 0; block < nblocks; block++)
- {
- for (bp = ch_bufhead; ; bp = bp->next)
- {
- if (bp == END_OF_CHAIN)
- {
- if (!warned)
- {
- error("Warning: log file is incomplete",
- NULL_PARG);
- warned = TRUE;
- }
- break;
- }
- if (bp->block == block)
- {
- write(logfile, (char *) bp->data, bp->datasize);
- break;
- }
- }
- }
-}
-
-#endif
-
-/*
- * Determine if a specific block is currently in one of the buffers.
- */
- static int
-buffered(block)
- BLOCKNUM block;
-{
- register struct buf *bp;
- register int h;
-
- h = BUFHASH(block);
- FOR_BUFS_IN_CHAIN(h, bp)
- {
- if (bp->block == block)
- return (TRUE);
- }
- return (FALSE);
-}
-
-/*
- * Seek to a specified position in the file.
- * Return 0 if successful, non-zero if can't seek there.
- */
- public int
-ch_seek(pos)
- register POSITION pos;
-{
- BLOCKNUM new_block;
- POSITION len;
-
- if (thisfile == NULL)
- return (0);
-
- len = ch_length();
- if (pos < ch_zero() || (len != NULL_POSITION && pos > len))
- return (1);
-
- new_block = pos / LBUFSIZE;
- if (!(ch_flags & CH_CANSEEK) && pos != ch_fpos && !buffered(new_block))
- {
- if (ch_fpos > pos)
- return (1);
- while (ch_fpos < pos)
- {
- if (ch_forw_get() == EOI)
- return (1);
- if (ABORT_SIGS())
- return (1);
- }
- return (0);
- }
- /*
- * Set read pointer.
- */
- ch_block = new_block;
- ch_offset = pos % LBUFSIZE;
- return (0);
-}
-
-/*
- * Seek to the end of the file.
- */
- public int
-ch_end_seek()
-{
- POSITION len;
-
- if (thisfile == NULL)
- return (0);
-
- if (ch_flags & CH_CANSEEK)
- ch_fsize = filesize(ch_file);
-
- len = ch_length();
- if (len != NULL_POSITION)
- return (ch_seek(len));
-
- /*
- * Do it the slow way: read till end of data.
- */
- while (ch_forw_get() != EOI)
- if (ABORT_SIGS())
- return (1);
- return (0);
-}
-
-/*
- * Seek to the beginning of the file, or as close to it as we can get.
- * We may not be able to seek there if input is a pipe and the
- * beginning of the pipe is no longer buffered.
- */
- public int
-ch_beg_seek()
-{
- register struct buf *bp, *firstbp;
-
- /*
- * Try a plain ch_seek first.
- */
- if (ch_seek(ch_zero()) == 0)
- return (0);
-
- /*
- * Can't get to position 0.
- * Look thru the buffers for the one closest to position 0.
- */
- firstbp = bp = ch_bufhead;
- if (bp == END_OF_CHAIN)
- return (1);
- while ((bp = bp->next) != END_OF_CHAIN)
- if (bp->block < firstbp->block)
- firstbp = bp;
- ch_block = firstbp->block;
- ch_offset = 0;
- return (0);
-}
-
-/*
- * Return the length of the file, if known.
- */
- public POSITION
-ch_length()
-{
- if (thisfile == NULL)
- return (NULL_POSITION);
- if (ignore_eoi)
- return (NULL_POSITION);
- if (ch_flags & CH_HELPFILE)
- return (size_helpdata);
- return (ch_fsize);
-}
-
-/*
- * Return the current position in the file.
- */
- public POSITION
-ch_tell()
-{
- if (thisfile == NULL)
- return (NULL_POSITION);
- return (ch_block * LBUFSIZE) + ch_offset;
-}
-
-/*
- * Get the current char and post-increment the read pointer.
- */
- public int
-ch_forw_get()
-{
- register int c;
-
- if (thisfile == NULL)
- return (EOI);
- c = ch_get();
- if (c == EOI)
- return (EOI);
- if (ch_offset < LBUFSIZE-1)
- ch_offset++;
- else
- {
- ch_block ++;
- ch_offset = 0;
- }
- return (c);
-}
-
-/*
- * Pre-decrement the read pointer and get the new current char.
- */
- public int
-ch_back_get()
-{
- if (thisfile == NULL)
- return (EOI);
- if (ch_offset > 0)
- ch_offset --;
- else
- {
- if (ch_block <= 0)
- return (EOI);
- if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1))
- return (EOI);
- ch_block--;
- ch_offset = LBUFSIZE-1;
- }
- return (ch_get());
-}
-
-/*
- * Set max amount of buffer space.
- * bufspace is in units of 1024 bytes. -1 mean no limit.
- */
- public void
-ch_setbufspace(bufspace)
- int bufspace;
-{
- if (bufspace < 0)
- maxbufs = -1;
- else
- {
- maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE;
- if (maxbufs < 1)
- maxbufs = 1;
- }
-}
-
-/*
- * Flush (discard) any saved file state, including buffer contents.
- */
- public void
-ch_flush()
-{
- register struct buf *bp;
-
- if (thisfile == NULL)
- return;
-
- if (!(ch_flags & CH_CANSEEK))
- {
- /*
- * If input is a pipe, we don't flush buffer contents,
- * since the contents can't be recovered.
- */
- ch_fsize = NULL_POSITION;
- return;
- }
-
- /*
- * Initialize all the buffers.
- */
- for (bp = ch_bufhead; bp != END_OF_CHAIN; bp = bp->next)
- bp->block = -1;
-
- /*
- * Figure out the size of the file, if we can.
- */
- ch_fsize = filesize(ch_file);
-
- /*
- * Seek to a known position: the beginning of the file.
- */
- ch_fpos = 0;
- ch_block = 0; /* ch_fpos / LBUFSIZE; */
- ch_offset = 0; /* ch_fpos % LBUFSIZE; */
-
-#if 1
- /*
- * This is a kludge to workaround a Linux kernel bug: files in
- * /proc have a size of 0 according to fstat() but have readable
- * data. They are sometimes, but not always, seekable.
- * Force them to be non-seekable here.
- */
- if (ch_fsize == 0)
- {
- ch_fsize = NULL_POSITION;
- ch_flags &= ~CH_CANSEEK;
- }
-#endif
-
- if (lseek(ch_file, (off_t)0, SEEK_SET) == BAD_LSEEK)
- {
- /*
- * Warning only; even if the seek fails for some reason,
- * there's a good chance we're at the beginning anyway.
- * {{ I think this is bogus reasoning. }}
- */
- error("seek error to 0", NULL_PARG);
- }
-}
-
-/*
- * Allocate a new buffer.
- * The buffer is added to the tail of the buffer chain.
- */
- static int
-ch_addbuf()
-{
- register struct buf *bp;
-
- /*
- * Allocate and initialize a new buffer and link it
- * onto the tail of the buffer list.
- */
- bp = (struct buf *) calloc(1, sizeof(struct buf));
- if (bp == NULL)
- return (1);
- ch_nbufs++;
- bp->block = -1;
- bp->next = END_OF_CHAIN;
- bp->prev = ch_buftail;
- ch_buftail->next = bp;
- ch_buftail = bp;
- HASH_INS(bp, 0);
- return (0);
-}
-
-/*
- *
- */
- static void
-init_hashtbl()
-{
- register int h;
-
- for (h = 0; h < BUFHASH_SIZE; h++)
- {
- thisfile->hashtbl[h].buf_hnext = END_OF_HCHAIN(h);
- thisfile->hashtbl[h].buf_hprev = END_OF_HCHAIN(h);
- }
-}
-
-/*
- * Delete all buffers for this file.
- */
- static void
-ch_delbufs()
-{
- register struct buf *bp;
-
- while (ch_bufhead != END_OF_CHAIN)
- {
- bp = ch_bufhead;
- bp->next->prev = bp->prev;
- bp->prev->next = bp->next;
- free(bp);
- }
- ch_nbufs = 0;
- init_hashtbl();
-}
-
-/*
- * Is it possible to seek on a file descriptor?
- */
- public int
-seekable(f)
- int f;
-{
-#if MSDOS_COMPILER
- extern int fd0;
- if (f == fd0 && !isatty(fd0))
- {
- /*
- * In MS-DOS, pipes are seekable. Check for
- * standard input, and pretend it is not seekable.
- */
- return (0);
- }
-#endif
- return (lseek(f, (off_t)1, SEEK_SET) != BAD_LSEEK);
-}
-
-/*
- * Initialize file state for a new file.
- */
- public void
-ch_init(f, flags)
- int f;
- int flags;
-{
- /*
- * See if we already have a filestate for this file.
- */
- thisfile = (struct filestate *) get_filestate(curr_ifile);
- if (thisfile == NULL)
- {
- /*
- * Allocate and initialize a new filestate.
- */
- thisfile = (struct filestate *)
- calloc(1, sizeof(struct filestate));
- thisfile->buf_next = thisfile->buf_prev = END_OF_CHAIN;
- thisfile->nbufs = 0;
- thisfile->flags = 0;
- thisfile->fpos = 0;
- thisfile->block = 0;
- thisfile->offset = 0;
- thisfile->file = -1;
- thisfile->fsize = NULL_POSITION;
- ch_flags = flags;
- init_hashtbl();
- /*
- * Try to seek; set CH_CANSEEK if it works.
- */
- if ((flags & CH_CANSEEK) && !seekable(f))
- ch_flags &= ~CH_CANSEEK;
- set_filestate(curr_ifile, (void *) thisfile);
- }
- if (thisfile->file == -1)
- thisfile->file = f;
- ch_flush();
-}
-
-/*
- * Close a filestate.
- */
- public void
-ch_close()
-{
- int keepstate = FALSE;
-
- if (thisfile == NULL)
- return;
-
- if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE))
- {
- /*
- * We can seek or re-open, so we don't need to keep buffers.
- */
- ch_delbufs();
- } else
- keepstate = TRUE;
- if (!(ch_flags & CH_KEEPOPEN))
- {
- /*
- * We don't need to keep the file descriptor open
- * (because we can re-open it.)
- * But don't really close it if it was opened via popen(),
- * because pclose() wants to close it.
- */
- if (!(ch_flags & (CH_POPENED|CH_HELPFILE)))
- close(ch_file);
- ch_file = -1;
- } else
- keepstate = TRUE;
- if (!keepstate)
- {
- /*
- * We don't even need to keep the filestate structure.
- */
- free(thisfile);
- thisfile = NULL;
- set_filestate(curr_ifile, (void *) NULL);
- }
-}
-
-/*
- * Return ch_flags for the current file.
- */
- public int
-ch_getflags()
-{
- if (thisfile == NULL)
- return (0);
- return (ch_flags);
-}
-
-#if 0
- public void
-ch_dump(struct filestate *fs)
-{
- struct buf *bp;
- unsigned char *s;
-
- if (fs == NULL)
- {
- printf(" --no filestate\n");
- return;
- }
- printf(" file %d, flags %x, fpos %x, fsize %x, blk/off %x/%x\n",
- fs->file, fs->flags, fs->fpos,
- fs->fsize, fs->block, fs->offset);
- printf(" %d bufs:\n", fs->nbufs);
- for (bp = fs->buf_next; bp != (struct buf *)fs; bp = bp->next)
- {
- printf("%x: blk %x, size %x \"",
- bp, bp->block, bp->datasize);
- for (s = bp->data; s < bp->data + 30; s++)
- if (*s >= ' ' && *s < 0x7F)
- printf("%c", *s);
- else
- printf(".");
- printf("\"\n");
- }
-}
-#endif
OpenPOWER on IntegriCloud