Changeset View
Changeset View
Standalone View
Standalone View
contrib/less/ch.c
Show First 20 Lines • Show All 138 Lines • ▼ Show 20 Lines | |||||
static int ch_addbuf(); | static int ch_addbuf(); | ||||
/* | /* | ||||
* Get the character pointed to by the read pointer. | * Get the character pointed to by the read pointer. | ||||
*/ | */ | ||||
int | int | ||||
ch_get() | ch_get(void) | ||||
{ | { | ||||
register struct buf *bp; | struct buf *bp; | ||||
register struct bufnode *bn; | struct bufnode *bn; | ||||
register int n; | int n; | ||||
register int slept; | int slept; | ||||
register int h; | int h; | ||||
POSITION pos; | POSITION pos; | ||||
POSITION len; | POSITION len; | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return (EOI); | return (EOI); | ||||
/* | /* | ||||
* Quick check for the common case where | * Quick check for the common case where | ||||
▲ Show 20 Lines • Show All 211 Lines • ▼ Show 20 Lines | #endif | ||||
return (bp->data[ch_offset]); | return (bp->data[ch_offset]); | ||||
} | } | ||||
/* | /* | ||||
* ch_ungetchar is a rather kludgy and limited way to push | * ch_ungetchar is a rather kludgy and limited way to push | ||||
* a single char onto an input file descriptor. | * a single char onto an input file descriptor. | ||||
*/ | */ | ||||
public void | public void | ||||
ch_ungetchar(c) | ch_ungetchar(int c) | ||||
int c; | |||||
{ | { | ||||
if (c != -1 && ch_ungotchar != -1) | if (c != -1 && ch_ungotchar != -1) | ||||
error("ch_ungetchar overrun", NULL_PARG); | error("ch_ungetchar overrun", NULL_PARG); | ||||
ch_ungotchar = c; | ch_ungotchar = c; | ||||
} | } | ||||
#if LOGFILE | #if LOGFILE | ||||
/* | /* | ||||
* Close the logfile. | * Close the logfile. | ||||
* If we haven't read all of standard input into it, do that now. | * If we haven't read all of standard input into it, do that now. | ||||
*/ | */ | ||||
public void | public void | ||||
end_logfile() | end_logfile(void) | ||||
{ | { | ||||
static int tried = FALSE; | static int tried = FALSE; | ||||
if (logfile < 0) | if (logfile < 0) | ||||
return; | return; | ||||
if (!tried && ch_fsize == NULL_POSITION) | if (!tried && ch_fsize == NULL_POSITION) | ||||
{ | { | ||||
tried = TRUE; | tried = TRUE; | ||||
ierror("Finishing logfile", NULL_PARG); | ierror("Finishing logfile", NULL_PARG); | ||||
while (ch_forw_get() != EOI) | while (ch_forw_get() != EOI) | ||||
if (ABORT_SIGS()) | if (ABORT_SIGS()) | ||||
break; | break; | ||||
} | } | ||||
close(logfile); | close(logfile); | ||||
logfile = -1; | logfile = -1; | ||||
namelogfile = NULL; | namelogfile = NULL; | ||||
} | } | ||||
/* | /* | ||||
* Start a log file AFTER less has already been running. | * Start a log file AFTER less has already been running. | ||||
* Invoked from the - command; see toggle_option(). | * Invoked from the - command; see toggle_option(). | ||||
* Write all the existing buffered data to the log file. | * Write all the existing buffered data to the log file. | ||||
*/ | */ | ||||
public void | public void | ||||
sync_logfile() | sync_logfile(void) | ||||
{ | { | ||||
register struct buf *bp; | struct buf *bp; | ||||
register struct bufnode *bn; | struct bufnode *bn; | ||||
int warned = FALSE; | int warned = FALSE; | ||||
BLOCKNUM block; | BLOCKNUM block; | ||||
BLOCKNUM nblocks; | BLOCKNUM nblocks; | ||||
nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE; | nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE; | ||||
for (block = 0; block < nblocks; block++) | for (block = 0; block < nblocks; block++) | ||||
{ | { | ||||
int wrote = FALSE; | int wrote = FALSE; | ||||
Show All 17 Lines | |||||
} | } | ||||
#endif | #endif | ||||
/* | /* | ||||
* Determine if a specific block is currently in one of the buffers. | * Determine if a specific block is currently in one of the buffers. | ||||
*/ | */ | ||||
static int | static int | ||||
buffered(block) | buffered(BLOCKNUM block) | ||||
BLOCKNUM block; | |||||
{ | { | ||||
register struct buf *bp; | struct buf *bp; | ||||
register struct bufnode *bn; | struct bufnode *bn; | ||||
register int h; | int h; | ||||
h = BUFHASH(block); | h = BUFHASH(block); | ||||
FOR_BUFS_IN_CHAIN(h, bn) | FOR_BUFS_IN_CHAIN(h, bn) | ||||
{ | { | ||||
bp = bufnode_buf(bn); | bp = bufnode_buf(bn); | ||||
if (bp->block == block) | if (bp->block == block) | ||||
return (TRUE); | return (TRUE); | ||||
} | } | ||||
return (FALSE); | return (FALSE); | ||||
} | } | ||||
/* | /* | ||||
* Seek to a specified position in the file. | * Seek to a specified position in the file. | ||||
* Return 0 if successful, non-zero if can't seek there. | * Return 0 if successful, non-zero if can't seek there. | ||||
*/ | */ | ||||
public int | public int | ||||
ch_seek(pos) | ch_seek(POSITION pos) | ||||
register POSITION pos; | |||||
{ | { | ||||
BLOCKNUM new_block; | BLOCKNUM new_block; | ||||
POSITION len; | POSITION len; | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return (0); | return (0); | ||||
len = ch_length(); | len = ch_length(); | ||||
Show All 21 Lines | ch_seek(POSITION pos) | ||||
ch_offset = pos % LBUFSIZE; | ch_offset = pos % LBUFSIZE; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Seek to the end of the file. | * Seek to the end of the file. | ||||
*/ | */ | ||||
public int | public int | ||||
ch_end_seek() | ch_end_seek(void) | ||||
{ | { | ||||
POSITION len; | POSITION len; | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return (0); | return (0); | ||||
if (ch_flags & CH_CANSEEK) | if (ch_flags & CH_CANSEEK) | ||||
ch_fsize = filesize(ch_file); | ch_fsize = filesize(ch_file); | ||||
Show All 10 Lines | if (ABORT_SIGS()) | ||||
return (1); | return (1); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Seek to the last position in the file that is currently buffered. | * Seek to the last position in the file that is currently buffered. | ||||
*/ | */ | ||||
public int | public int | ||||
ch_end_buffer_seek() | ch_end_buffer_seek(void) | ||||
{ | { | ||||
register struct buf *bp; | struct buf *bp; | ||||
register struct bufnode *bn; | struct bufnode *bn; | ||||
POSITION buf_pos; | POSITION buf_pos; | ||||
POSITION end_pos; | POSITION end_pos; | ||||
if (thisfile == NULL || (ch_flags & CH_CANSEEK)) | if (thisfile == NULL || (ch_flags & CH_CANSEEK)) | ||||
return (ch_end_seek()); | return (ch_end_seek()); | ||||
end_pos = 0; | end_pos = 0; | ||||
FOR_BUFS(bn) | FOR_BUFS(bn) | ||||
{ | { | ||||
bp = bufnode_buf(bn); | bp = bufnode_buf(bn); | ||||
buf_pos = (bp->block * LBUFSIZE) + bp->datasize; | buf_pos = (bp->block * LBUFSIZE) + bp->datasize; | ||||
if (buf_pos > end_pos) | if (buf_pos > end_pos) | ||||
end_pos = buf_pos; | end_pos = buf_pos; | ||||
} | } | ||||
return (ch_seek(end_pos)); | return (ch_seek(end_pos)); | ||||
} | } | ||||
/* | /* | ||||
* Seek to the beginning of the file, or as close to it as we can get. | * 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 | * We may not be able to seek there if input is a pipe and the | ||||
* beginning of the pipe is no longer buffered. | * beginning of the pipe is no longer buffered. | ||||
*/ | */ | ||||
public int | public int | ||||
ch_beg_seek() | ch_beg_seek(void) | ||||
{ | { | ||||
register struct bufnode *bn; | struct bufnode *bn; | ||||
register struct bufnode *firstbn; | struct bufnode *firstbn; | ||||
/* | /* | ||||
* Try a plain ch_seek first. | * Try a plain ch_seek first. | ||||
*/ | */ | ||||
if (ch_seek(ch_zero()) == 0) | if (ch_seek(ch_zero()) == 0) | ||||
return (0); | return (0); | ||||
/* | /* | ||||
Show All 12 Lines | ch_beg_seek(void) | ||||
ch_offset = 0; | ch_offset = 0; | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Return the length of the file, if known. | * Return the length of the file, if known. | ||||
*/ | */ | ||||
public POSITION | public POSITION | ||||
ch_length() | ch_length(void) | ||||
{ | { | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return (NULL_POSITION); | return (NULL_POSITION); | ||||
if (ignore_eoi) | if (ignore_eoi) | ||||
return (NULL_POSITION); | return (NULL_POSITION); | ||||
if (ch_flags & CH_HELPFILE) | if (ch_flags & CH_HELPFILE) | ||||
return (size_helpdata); | return (size_helpdata); | ||||
if (ch_flags & CH_NODATA) | if (ch_flags & CH_NODATA) | ||||
return (0); | return (0); | ||||
return (ch_fsize); | return (ch_fsize); | ||||
} | } | ||||
/* | /* | ||||
* Return the current position in the file. | * Return the current position in the file. | ||||
*/ | */ | ||||
public POSITION | public POSITION | ||||
ch_tell() | ch_tell(void) | ||||
{ | { | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return (NULL_POSITION); | return (NULL_POSITION); | ||||
return (ch_block * LBUFSIZE) + ch_offset; | return (ch_block * LBUFSIZE) + ch_offset; | ||||
} | } | ||||
/* | /* | ||||
* Get the current char and post-increment the read pointer. | * Get the current char and post-increment the read pointer. | ||||
*/ | */ | ||||
public int | public int | ||||
ch_forw_get() | ch_forw_get(void) | ||||
{ | { | ||||
register int c; | int c; | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return (EOI); | return (EOI); | ||||
c = ch_get(); | c = ch_get(); | ||||
if (c == EOI) | if (c == EOI) | ||||
return (EOI); | return (EOI); | ||||
if (ch_offset < LBUFSIZE-1) | if (ch_offset < LBUFSIZE-1) | ||||
ch_offset++; | ch_offset++; | ||||
else | else | ||||
{ | { | ||||
ch_block ++; | ch_block ++; | ||||
ch_offset = 0; | ch_offset = 0; | ||||
} | } | ||||
return (c); | return (c); | ||||
} | } | ||||
/* | /* | ||||
* Pre-decrement the read pointer and get the new current char. | * Pre-decrement the read pointer and get the new current char. | ||||
*/ | */ | ||||
public int | public int | ||||
ch_back_get() | ch_back_get(void) | ||||
{ | { | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return (EOI); | return (EOI); | ||||
if (ch_offset > 0) | if (ch_offset > 0) | ||||
ch_offset --; | ch_offset --; | ||||
else | else | ||||
{ | { | ||||
if (ch_block <= 0) | if (ch_block <= 0) | ||||
return (EOI); | return (EOI); | ||||
if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1)) | if (!(ch_flags & CH_CANSEEK) && !buffered(ch_block-1)) | ||||
return (EOI); | return (EOI); | ||||
ch_block--; | ch_block--; | ||||
ch_offset = LBUFSIZE-1; | ch_offset = LBUFSIZE-1; | ||||
} | } | ||||
return (ch_get()); | return (ch_get()); | ||||
} | } | ||||
/* | /* | ||||
* Set max amount of buffer space. | * Set max amount of buffer space. | ||||
* bufspace is in units of 1024 bytes. -1 mean no limit. | * bufspace is in units of 1024 bytes. -1 mean no limit. | ||||
*/ | */ | ||||
public void | public void | ||||
ch_setbufspace(bufspace) | ch_setbufspace(int bufspace) | ||||
int bufspace; | |||||
{ | { | ||||
if (bufspace < 0) | if (bufspace < 0) | ||||
maxbufs = -1; | maxbufs = -1; | ||||
else | else | ||||
{ | { | ||||
maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE; | maxbufs = ((bufspace * 1024) + LBUFSIZE-1) / LBUFSIZE; | ||||
if (maxbufs < 1) | if (maxbufs < 1) | ||||
maxbufs = 1; | maxbufs = 1; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Flush (discard) any saved file state, including buffer contents. | * Flush (discard) any saved file state, including buffer contents. | ||||
*/ | */ | ||||
public void | public void | ||||
ch_flush() | ch_flush(void) | ||||
{ | { | ||||
register struct bufnode *bn; | struct bufnode *bn; | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return; | return; | ||||
if (!(ch_flags & CH_CANSEEK)) | if (!(ch_flags & CH_CANSEEK)) | ||||
{ | { | ||||
/* | /* | ||||
* If input is a pipe, we don't flush buffer contents, | * If input is a pipe, we don't flush buffer contents, | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Allocate a new buffer. | * Allocate a new buffer. | ||||
* The buffer is added to the tail of the buffer chain. | * The buffer is added to the tail of the buffer chain. | ||||
*/ | */ | ||||
static int | static int | ||||
ch_addbuf() | ch_addbuf(void) | ||||
{ | { | ||||
register struct buf *bp; | struct buf *bp; | ||||
register struct bufnode *bn; | struct bufnode *bn; | ||||
/* | /* | ||||
* Allocate and initialize a new buffer and link it | * Allocate and initialize a new buffer and link it | ||||
* onto the tail of the buffer list. | * onto the tail of the buffer list. | ||||
*/ | */ | ||||
bp = (struct buf *) calloc(1, sizeof(struct buf)); | bp = (struct buf *) calloc(1, sizeof(struct buf)); | ||||
if (bp == NULL) | if (bp == NULL) | ||||
return (1); | return (1); | ||||
ch_nbufs++; | ch_nbufs++; | ||||
bp->block = -1; | bp->block = -1; | ||||
bn = &bp->node; | bn = &bp->node; | ||||
BUF_INS_TAIL(bn); | BUF_INS_TAIL(bn); | ||||
BUF_HASH_INS(bn, 0); | BUF_HASH_INS(bn, 0); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* | * | ||||
*/ | */ | ||||
static void | static void | ||||
init_hashtbl() | init_hashtbl(void) | ||||
{ | { | ||||
register int h; | int h; | ||||
for (h = 0; h < BUFHASH_SIZE; h++) | for (h = 0; h < BUFHASH_SIZE; h++) | ||||
{ | { | ||||
thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h); | thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h); | ||||
thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h); | thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Delete all buffers for this file. | * Delete all buffers for this file. | ||||
*/ | */ | ||||
static void | static void | ||||
ch_delbufs() | ch_delbufs(void) | ||||
{ | { | ||||
register struct bufnode *bn; | struct bufnode *bn; | ||||
while (ch_bufhead != END_OF_CHAIN) | while (ch_bufhead != END_OF_CHAIN) | ||||
{ | { | ||||
bn = ch_bufhead; | bn = ch_bufhead; | ||||
BUF_RM(bn); | BUF_RM(bn); | ||||
free(bufnode_buf(bn)); | free(bufnode_buf(bn)); | ||||
} | } | ||||
ch_nbufs = 0; | ch_nbufs = 0; | ||||
init_hashtbl(); | init_hashtbl(); | ||||
} | } | ||||
/* | /* | ||||
* Is it possible to seek on a file descriptor? | * Is it possible to seek on a file descriptor? | ||||
*/ | */ | ||||
public int | public int | ||||
seekable(f) | seekable(int f) | ||||
int f; | |||||
{ | { | ||||
#if MSDOS_COMPILER | #if MSDOS_COMPILER | ||||
extern int fd0; | extern int fd0; | ||||
if (f == fd0 && !isatty(fd0)) | if (f == fd0 && !isatty(fd0)) | ||||
{ | { | ||||
/* | /* | ||||
* In MS-DOS, pipes are seekable. Check for | * In MS-DOS, pipes are seekable. Check for | ||||
* standard input, and pretend it is not seekable. | * standard input, and pretend it is not seekable. | ||||
*/ | */ | ||||
return (0); | return (0); | ||||
} | } | ||||
#endif | #endif | ||||
return (lseek(f, (off_t)1, SEEK_SET) != BAD_LSEEK); | return (lseek(f, (off_t)1, SEEK_SET) != BAD_LSEEK); | ||||
} | } | ||||
/* | /* | ||||
* Force EOF to be at the current read position. | * Force EOF to be at the current read position. | ||||
* This is used after an ignore_eof read, during which the EOF may change. | * This is used after an ignore_eof read, during which the EOF may change. | ||||
*/ | */ | ||||
public void | public void | ||||
ch_set_eof() | ch_set_eof(void) | ||||
{ | { | ||||
ch_fsize = ch_fpos; | ch_fsize = ch_fpos; | ||||
} | } | ||||
/* | /* | ||||
* Initialize file state for a new file. | * Initialize file state for a new file. | ||||
*/ | */ | ||||
public void | public void | ||||
ch_init(f, flags) | ch_init(int f, int flags) | ||||
int f; | |||||
int flags; | |||||
{ | { | ||||
/* | /* | ||||
* See if we already have a filestate for this file. | * See if we already have a filestate for this file. | ||||
*/ | */ | ||||
thisfile = (struct filestate *) get_filestate(curr_ifile); | thisfile = (struct filestate *) get_filestate(curr_ifile); | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
{ | { | ||||
/* | /* | ||||
Show All 22 Lines | if (thisfile->file == -1) | ||||
thisfile->file = f; | thisfile->file = f; | ||||
ch_flush(); | ch_flush(); | ||||
} | } | ||||
/* | /* | ||||
* Close a filestate. | * Close a filestate. | ||||
*/ | */ | ||||
public void | public void | ||||
ch_close() | ch_close(void) | ||||
{ | { | ||||
int keepstate = FALSE; | int keepstate = FALSE; | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return; | return; | ||||
if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE)) | if (ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE)) | ||||
{ | { | ||||
Show All 26 Lines | if (!keepstate) | ||||
set_filestate(curr_ifile, (void *) NULL); | set_filestate(curr_ifile, (void *) NULL); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Return ch_flags for the current file. | * Return ch_flags for the current file. | ||||
*/ | */ | ||||
public int | public int | ||||
ch_getflags() | ch_getflags(void) | ||||
{ | { | ||||
if (thisfile == NULL) | if (thisfile == NULL) | ||||
return (0); | return (0); | ||||
return (ch_flags); | return (ch_flags); | ||||
} | } | ||||
#if 0 | #if 0 | ||||
public void | public void | ||||
Show All 29 Lines |