Index: head/contrib/less/brac.c =================================================================== --- head/contrib/less/brac.c (revision 316338) +++ head/contrib/less/brac.c (revision 316339) @@ -1,100 +1,96 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines to perform bracket matching functions. */ #include "less.h" #include "position.h" /* * Try to match the n-th open bracket * which appears in the top displayed line (forwdir), * or the n-th close bracket * which appears in the bottom displayed line (!forwdir). * The characters which serve as "open bracket" and * "close bracket" are given. */ public void -match_brac(obrac, cbrac, forwdir, n) - register int obrac; - register int cbrac; - int forwdir; - int n; +match_brac(int obrac, int cbrac, int forwdir, int n) { - register int c; - register int nest; + int c; + int nest; POSITION pos; - int (*chget)(); + int (*chget)(void); - extern int ch_forw_get(), ch_back_get(); + extern int ch_forw_get(void), ch_back_get(void); /* * Seek to the line containing the open bracket. * This is either the top or bottom line on the screen, * depending on the type of bracket. */ pos = position((forwdir) ? TOP : BOTTOM); if (pos == NULL_POSITION || ch_seek(pos)) { if (forwdir) error("Nothing in top line", NULL_PARG); else error("Nothing in bottom line", NULL_PARG); return; } /* * Look thru the line to find the open bracket to match. */ do { if ((c = ch_forw_get()) == '\n' || c == EOI) { if (forwdir) error("No bracket in top line", NULL_PARG); else error("No bracket in bottom line", NULL_PARG); return; } } while (c != obrac || --n > 0); /* * Position the file just "after" the open bracket * (in the direction in which we will be searching). * If searching forward, we are already after the bracket. * If searching backward, skip back over the open bracket. */ if (!forwdir) (void) ch_back_get(); /* * Search the file for the matching bracket. */ chget = (forwdir) ? ch_forw_get : ch_back_get; nest = 0; while ((c = (*chget)()) != EOI) { if (c == obrac) nest++; else if (c == cbrac && --nest < 0) { /* * Found the matching bracket. * If searching backward, put it on the top line. * If searching forward, put it on the bottom line. */ jump_line_loc(ch_tell(), forwdir ? -1 : 1); return; } } error("No matching bracket", NULL_PARG); } Index: head/contrib/less/ch.c =================================================================== --- head/contrib/less/ch.c (revision 316338) +++ head/contrib/less/ch.c (revision 316339) @@ -1,974 +1,967 @@ /* * Copyright (C) 1984-2015 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, 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 #include #endif #if HAVE_STAT_INO #include 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". */ struct bufnode { struct bufnode *next, *prev; struct bufnode *hnext, *hprev; }; #define LBUFSIZE 8192 struct buf { struct bufnode node; BLOCKNUM block; unsigned int datasize; unsigned char data[LBUFSIZE]; }; #define bufnode_buf(bn) ((struct buf *) bn) /* * The file state is maintained in a filestate structure. * A pointer to the filestate is kept in the ifile structure. */ #define BUFHASH_SIZE 1024 struct filestate { struct bufnode buflist; struct bufnode hashtbl[BUFHASH_SIZE]; int file; int flags; POSITION fpos; int nbufs; BLOCKNUM block; unsigned int offset; POSITION fsize; }; #define ch_bufhead thisfile->buflist.next #define ch_buftail thisfile->buflist.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 (&thisfile->buflist) #define END_OF_HCHAIN(h) (&thisfile->hashtbl[h]) #define BUFHASH(blk) ((blk) & (BUFHASH_SIZE-1)) /* * Macros to manipulate the list of buffers in thisfile->buflist. */ #define FOR_BUFS(bn) \ for (bn = ch_bufhead; bn != END_OF_CHAIN; bn = bn->next) #define BUF_RM(bn) \ (bn)->next->prev = (bn)->prev; \ (bn)->prev->next = (bn)->next; #define BUF_INS_HEAD(bn) \ (bn)->next = ch_bufhead; \ (bn)->prev = END_OF_CHAIN; \ ch_bufhead->prev = (bn); \ ch_bufhead = (bn); #define BUF_INS_TAIL(bn) \ (bn)->next = END_OF_CHAIN; \ (bn)->prev = ch_buftail; \ ch_buftail->next = (bn); \ ch_buftail = (bn); /* * Macros to manipulate the list of buffers in thisfile->hashtbl[n]. */ #define FOR_BUFS_IN_CHAIN(h,bn) \ for (bn = thisfile->hashtbl[h].hnext; \ bn != END_OF_HCHAIN(h); bn = bn->hnext) #define BUF_HASH_RM(bn) \ (bn)->hnext->hprev = (bn)->hprev; \ (bn)->hprev->hnext = (bn)->hnext; #define BUF_HASH_INS(bn,h) \ (bn)->hnext = thisfile->hashtbl[h].hnext; \ (bn)->hprev = END_OF_HCHAIN(h); \ thisfile->hashtbl[h].hnext->hprev = (bn); \ thisfile->hashtbl[h].hnext = (bn); 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. */ int -ch_get() +ch_get(void) { - register struct buf *bp; - register struct bufnode *bn; - register int n; - register int slept; - register int h; + struct buf *bp; + struct bufnode *bn; + int n; + int slept; + int h; POSITION pos; POSITION len; if (thisfile == NULL) return (EOI); /* * Quick check for the common case where * the desired char is in the head buffer. */ if (ch_bufhead != END_OF_CHAIN) { bp = bufnode_buf(ch_bufhead); if (ch_block == bp->block && ch_offset < bp->datasize) return bp->data[ch_offset]; } slept = FALSE; /* * Look for a buffer holding the desired block. */ h = BUFHASH(ch_block); FOR_BUFS_IN_CHAIN(h, bn) { bp = bufnode_buf(bn); if (bp->block == ch_block) { if (ch_offset >= bp->datasize) /* * Need more data in this buffer. */ break; goto found; } } if (bn == END_OF_HCHAIN(h)) { /* * 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 || bufnode_buf(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; } bn = ch_buftail; bp = bufnode_buf(bn); BUF_HASH_RM(bn); /* Remove from old hash chain. */ bp->block = ch_block; bp->datasize = 0; BUF_HASH_INS(bn, 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, * or the file has shrunk. * If so, force the file to be closed and * reopened. */ struct stat st; POSITION curr_pos = ch_tell(); int r = stat(get_filename(curr_ifile), &st); if (r == 0 && (st.st_ino != curr_ino || st.st_dev != curr_dev || (curr_pos != NULL_POSITION && st.st_size < curr_pos))) { /* screen_trashed=2 causes * make_display to reopen the file. */ screen_trashed = 2; return (EOI); } } #endif } if (sigs) return (EOI); } found: if (ch_bufhead != bn) { /* * Move the buffer to the head of the buffer chain. * This orders the buffer chain, most- to least-recently used. */ BUF_RM(bn); BUF_INS_HEAD(bn); /* * Move to head of hash chain too. */ BUF_HASH_RM(bn); BUF_HASH_INS(bn, 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; +ch_ungetchar(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() +end_logfile(void) { 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() +sync_logfile(void) { - register struct buf *bp; - register struct bufnode *bn; + struct buf *bp; + struct bufnode *bn; int warned = FALSE; BLOCKNUM block; BLOCKNUM nblocks; nblocks = (ch_fpos + LBUFSIZE - 1) / LBUFSIZE; for (block = 0; block < nblocks; block++) { int wrote = FALSE; FOR_BUFS(bn) { bp = bufnode_buf(bn); if (bp->block == block) { write(logfile, (char *) bp->data, bp->datasize); wrote = TRUE; break; } } if (!wrote && !warned) { error("Warning: log file is incomplete", NULL_PARG); warned = TRUE; } } } #endif /* * Determine if a specific block is currently in one of the buffers. */ static int -buffered(block) - BLOCKNUM block; +buffered(BLOCKNUM block) { - register struct buf *bp; - register struct bufnode *bn; - register int h; + struct buf *bp; + struct bufnode *bn; + int h; h = BUFHASH(block); FOR_BUFS_IN_CHAIN(h, bn) { bp = bufnode_buf(bn); 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; +ch_seek(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() +ch_end_seek(void) { 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 last position in the file that is currently buffered. */ public int -ch_end_buffer_seek() +ch_end_buffer_seek(void) { - register struct buf *bp; - register struct bufnode *bn; + struct buf *bp; + struct bufnode *bn; POSITION buf_pos; POSITION end_pos; if (thisfile == NULL || (ch_flags & CH_CANSEEK)) return (ch_end_seek()); end_pos = 0; FOR_BUFS(bn) { bp = bufnode_buf(bn); buf_pos = (bp->block * LBUFSIZE) + bp->datasize; if (buf_pos > end_pos) end_pos = buf_pos; } return (ch_seek(end_pos)); } /* * 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() +ch_beg_seek(void) { - register struct bufnode *bn; - register struct bufnode *firstbn; + struct bufnode *bn; + struct bufnode *firstbn; /* * 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. */ firstbn = ch_bufhead; if (firstbn == END_OF_CHAIN) return (1); FOR_BUFS(bn) { if (bufnode_buf(bn)->block < bufnode_buf(firstbn)->block) firstbn = bn; } ch_block = bufnode_buf(firstbn)->block; ch_offset = 0; return (0); } /* * Return the length of the file, if known. */ public POSITION -ch_length() +ch_length(void) { if (thisfile == NULL) return (NULL_POSITION); if (ignore_eoi) return (NULL_POSITION); if (ch_flags & CH_HELPFILE) return (size_helpdata); if (ch_flags & CH_NODATA) return (0); return (ch_fsize); } /* * Return the current position in the file. */ public POSITION -ch_tell() +ch_tell(void) { 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() +ch_forw_get(void) { - register int c; + 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() +ch_back_get(void) { 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; +ch_setbufspace(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() +ch_flush(void) { - register struct bufnode *bn; + struct bufnode *bn; 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_BUFS(bn) { bufnode_buf(bn)->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() +ch_addbuf(void) { - register struct buf *bp; - register struct bufnode *bn; + struct buf *bp; + struct bufnode *bn; /* * 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; bn = &bp->node; BUF_INS_TAIL(bn); BUF_HASH_INS(bn, 0); return (0); } /* * */ static void -init_hashtbl() +init_hashtbl(void) { - register int h; + int h; for (h = 0; h < BUFHASH_SIZE; h++) { thisfile->hashtbl[h].hnext = END_OF_HCHAIN(h); thisfile->hashtbl[h].hprev = END_OF_HCHAIN(h); } } /* * Delete all buffers for this file. */ static void -ch_delbufs() +ch_delbufs(void) { - register struct bufnode *bn; + struct bufnode *bn; while (ch_bufhead != END_OF_CHAIN) { bn = ch_bufhead; BUF_RM(bn); free(bufnode_buf(bn)); } ch_nbufs = 0; init_hashtbl(); } /* * Is it possible to seek on a file descriptor? */ public int -seekable(f) - int f; +seekable(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); } /* * Force EOF to be at the current read position. * This is used after an ignore_eof read, during which the EOF may change. */ public void -ch_set_eof() +ch_set_eof(void) { ch_fsize = ch_fpos; } /* * Initialize file state for a new file. */ public void -ch_init(f, flags) - int f; - int flags; +ch_init(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->buflist.next = thisfile->buflist.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() +ch_close(void) { 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() +ch_getflags(void) { if (thisfile == NULL) return (0); return (ch_flags); } #if 0 public void ch_dump(struct filestate *fs) { struct buf *bp; struct bufnode *bn; 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 (bn = fs->next; bn != &fs->buflist; bn = bn->next) { bp = bufnode_buf(bn); 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 Index: head/contrib/less/charset.c =================================================================== --- head/contrib/less/charset.c (revision 316338) +++ head/contrib/less/charset.c (revision 316339) @@ -1,823 +1,795 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Functions to define the character set * and do things specific to the character set. */ #include "less.h" #if HAVE_LOCALE #include #include #include #endif #include "charset.h" public int utf_mode = 0; /* * Predefined character sets, * selected by the LESSCHARSET environment variable. */ struct charset { char *name; int *p_flag; char *desc; } charsets[] = { { "ascii", NULL, "8bcccbcc18b95.b" }, { "utf-8", &utf_mode, "8bcccbcc18b95.b126.bb" }, { "iso8859", NULL, "8bcccbcc18b95.33b." }, { "latin3", NULL, "8bcccbcc18b95.33b5.b8.b15.b4.b12.b18.b12.b." }, { "arabic", NULL, "8bcccbcc18b95.33b.3b.7b2.13b.3b.b26.5b19.b" }, { "greek", NULL, "8bcccbcc18b95.33b4.2b4.b3.b35.b44.b" }, { "greek2005", NULL, "8bcccbcc18b95.33b14.b35.b44.b" }, { "hebrew", NULL, "8bcccbcc18b95.33b.b29.32b28.2b2.b" }, { "koi8-r", NULL, "8bcccbcc18b95.b." }, { "KOI8-T", NULL, "8bcccbcc18b95.b8.b6.b8.b.b.5b7.3b4.b4.b3.b.b.3b." }, { "georgianps", NULL, "8bcccbcc18b95.3b11.4b12.2b." }, { "tcvn", NULL, "b..b...bcccbccbbb7.8b95.b48.5b." }, { "TIS-620", NULL, "8bcccbcc18b95.b.4b.11b7.8b." }, { "next", NULL, "8bcccbcc18b95.bb125.bb" }, { "dos", NULL, "8bcccbcc12bc5b95.b." }, { "windows-1251", NULL, "8bcccbcc12bc5b95.b24.b." }, { "windows-1252", NULL, "8bcccbcc12bc5b95.b.b11.b.2b12.b." }, { "windows-1255", NULL, "8bcccbcc12bc5b95.b.b8.b.5b9.b.4b." }, { "ebcdic", NULL, "5bc6bcc7bcc41b.9b7.9b5.b..8b6.10b6.b9.7b9.8b8.17b3.3b9.7b9.8b8.6b10.b.b.b." }, { "IBM-1047", NULL, "4cbcbc3b9cbccbccbb4c6bcc5b3cbbc4bc4bccbc191.b" }, { NULL, NULL, NULL } }; /* * Support "locale charmap"/nl_langinfo(CODESET) values, as well as others. */ struct cs_alias { char *name; char *oname; } cs_aliases[] = { { "UTF-8", "utf-8" }, { "ANSI_X3.4-1968", "ascii" }, { "US-ASCII", "ascii" }, { "latin1", "iso8859" }, { "ISO-8859-1", "iso8859" }, { "latin9", "iso8859" }, { "ISO-8859-15", "iso8859" }, { "latin2", "iso8859" }, { "ISO-8859-2", "iso8859" }, { "ISO-8859-3", "latin3" }, { "latin4", "iso8859" }, { "ISO-8859-4", "iso8859" }, { "cyrillic", "iso8859" }, { "ISO-8859-5", "iso8859" }, { "ISO-8859-6", "arabic" }, { "ISO-8859-7", "greek" }, { "IBM9005", "greek2005" }, { "ISO-8859-8", "hebrew" }, { "latin5", "iso8859" }, { "ISO-8859-9", "iso8859" }, { "latin6", "iso8859" }, { "ISO-8859-10", "iso8859" }, { "latin7", "iso8859" }, { "ISO-8859-13", "iso8859" }, { "latin8", "iso8859" }, { "ISO-8859-14", "iso8859" }, { "latin10", "iso8859" }, { "ISO-8859-16", "iso8859" }, { "IBM437", "dos" }, { "EBCDIC-US", "ebcdic" }, { "IBM1047", "IBM-1047" }, { "KOI8-R", "koi8-r" }, { "KOI8-U", "koi8-r" }, { "GEORGIAN-PS", "georgianps" }, { "TCVN5712-1", "tcvn" }, { "NEXTSTEP", "next" }, { "windows", "windows-1252" }, /* backward compatibility */ { "CP1251", "windows-1251" }, { "CP1252", "windows-1252" }, { "CP1255", "windows-1255" }, { NULL, NULL } }; #define IS_BINARY_CHAR 01 #define IS_CONTROL_CHAR 02 static char chardef[256]; static char *binfmt = NULL; static char *utfbinfmt = NULL; public int binattr = AT_STANDOUT; /* * Define a charset, given a description string. * The string consists of 256 letters, * one for each character in the charset. * If the string is shorter than 256 letters, missing letters * are taken to be identical to the last one. * A decimal number followed by a letter is taken to be a * repetition of the letter. * * Each letter is one of: * . normal character * b binary character * c control character */ static void -ichardef(s) - char *s; +ichardef(char *s) { - register char *cp; - register int n; - register char v; + char *cp; + int n; + char v; n = 0; v = 0; cp = chardef; while (*s != '\0') { switch (*s++) { case '.': v = 0; break; case 'c': v = IS_CONTROL_CHAR; break; case 'b': v = IS_BINARY_CHAR|IS_CONTROL_CHAR; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = (10 * n) + (s[-1] - '0'); continue; default: error("invalid chardef", NULL_PARG); quit(QUIT_ERROR); /*NOTREACHED*/ } do { if (cp >= chardef + sizeof(chardef)) { error("chardef longer than 256", NULL_PARG); quit(QUIT_ERROR); /*NOTREACHED*/ } *cp++ = v; } while (--n > 0); n = 0; } while (cp < chardef + sizeof(chardef)) *cp++ = v; } /* * Define a charset, given a charset name. * The valid charset names are listed in the "charsets" array. */ static int -icharset(name, no_error) - register char *name; - int no_error; +icharset(char *name, int no_error) { - register struct charset *p; - register struct cs_alias *a; + struct charset *p; + struct cs_alias *a; if (name == NULL || *name == '\0') return (0); /* First see if the name is an alias. */ for (a = cs_aliases; a->name != NULL; a++) { if (strcmp(name, a->name) == 0) { name = a->oname; break; } } for (p = charsets; p->name != NULL; p++) { if (strcmp(name, p->name) == 0) { ichardef(p->desc); if (p->p_flag != NULL) *(p->p_flag) = 1; return (1); } } if (!no_error) { error("invalid charset name", NULL_PARG); quit(QUIT_ERROR); } return (0); } #if HAVE_LOCALE /* * Define a charset, given a locale name. */ static void -ilocale() +ilocale(void) { - register int c; + int c; for (c = 0; c < (int) sizeof(chardef); c++) { if (isprint(c)) chardef[c] = 0; else if (iscntrl(c)) chardef[c] = IS_CONTROL_CHAR; else chardef[c] = IS_BINARY_CHAR|IS_CONTROL_CHAR; } } #endif /* * Define the printing format for control (or binary utf) chars. */ static void -setbinfmt(s, fmtvarptr, default_fmt) - char *s; - char **fmtvarptr; - char *default_fmt; +setbinfmt(char *s, char **fmtvarptr, char *default_fmt) { if (s && utf_mode) { /* It would be too hard to account for width otherwise. */ char *t = s; while (*t) { if (*t < ' ' || *t > '~') { s = default_fmt; goto attr; } t++; } } /* %n is evil */ if (s == NULL || *s == '\0' || (*s == '*' && (s[1] == '\0' || s[2] == '\0' || strchr(s + 2, 'n'))) || (*s != '*' && strchr(s, 'n'))) s = default_fmt; /* * Select the attributes if it starts with "*". */ attr: if (*s == '*') { switch (s[1]) { case 'd': binattr = AT_BOLD; break; case 'k': binattr = AT_BLINK; break; case 's': binattr = AT_STANDOUT; break; case 'u': binattr = AT_UNDERLINE; break; default: binattr = AT_NORMAL; break; } s += 2; } *fmtvarptr = s; } /* * */ static void -set_charset() +set_charset(void) { char *s; /* * See if environment variable LESSCHARSET is defined. */ s = lgetenv("LESSCHARSET"); if (icharset(s, 0)) return; /* * LESSCHARSET is not defined: try LESSCHARDEF. */ s = lgetenv("LESSCHARDEF"); if (s != NULL && *s != '\0') { ichardef(s); return; } #if HAVE_LOCALE #ifdef CODESET /* * Try using the codeset name as the charset name. */ s = nl_langinfo(CODESET); if (icharset(s, 1)) return; #endif #endif #if HAVE_STRSTR /* * Check whether LC_ALL, LC_CTYPE or LANG look like UTF-8 is used. */ if ((s = lgetenv("LC_ALL")) != NULL || (s = lgetenv("LC_CTYPE")) != NULL || (s = lgetenv("LANG")) != NULL) { if ( strstr(s, "UTF-8") != NULL || strstr(s, "utf-8") != NULL || strstr(s, "UTF8") != NULL || strstr(s, "utf8") != NULL) if (icharset("utf-8", 1)) return; } #endif #if HAVE_LOCALE /* * Get character definitions from locale functions, * rather than from predefined charset entry. */ ilocale(); #if MSDOS_COMPILER /* * Default to "dos". */ (void) icharset("dos", 1); #else /* * Default to "latin1". */ (void) icharset("latin1", 1); #endif #endif } /* * Initialize charset data structures. */ public void -init_charset() +init_charset(void) { char *s; #if HAVE_LOCALE setlocale(LC_ALL, ""); #endif set_charset(); s = lgetenv("LESSBINFMT"); setbinfmt(s, &binfmt, "*s<%02X>"); s = lgetenv("LESSUTFBINFMT"); setbinfmt(s, &utfbinfmt, ""); } /* * Is a given character a "binary" character? */ public int -binary_char(c) - LWCHAR c; +binary_char(LWCHAR c) { if (utf_mode) return (is_ubin_char(c)); c &= 0377; return (chardef[c] & IS_BINARY_CHAR); } /* * Is a given character a "control" character? */ public int -control_char(c) - LWCHAR c; +control_char(LWCHAR c) { c &= 0377; return (chardef[c] & IS_CONTROL_CHAR); } /* * Return the printable form of a character. * For example, in the "ascii" charset '\3' is printed as "^C". */ public char * -prchar(c) - LWCHAR c; +prchar(LWCHAR c) { /* {{ This buffer can be overrun if LESSBINFMT is a long string. }} */ static char buf[32]; c &= 0377; if ((c < 128 || !utf_mode) && !control_char(c)) SNPRINTF1(buf, sizeof(buf), "%c", (int) c); else if (c == ESC) strcpy(buf, "ESC"); #if IS_EBCDIC_HOST else if (!binary_char(c) && c < 64) SNPRINTF1(buf, sizeof(buf), "^%c", /* * This array roughly inverts CONTROL() #defined in less.h, * and should be kept in sync with CONTROL() and IBM-1047. */ "@ABC.I.?...KLMNO" "PQRS.JH.XY.." "\\]^_" "......W[.....EFG" "..V....D....TU.Z"[c]); #else else if (c < 128 && !control_char(c ^ 0100)) SNPRINTF1(buf, sizeof(buf), "^%c", (int) (c ^ 0100)); #endif else SNPRINTF1(buf, sizeof(buf), binfmt, c); return (buf); } /* * Return the printable form of a UTF-8 character. */ public char * -prutfchar(ch) - LWCHAR ch; +prutfchar(LWCHAR ch) { static char buf[32]; if (ch == ESC) strcpy(buf, "ESC"); else if (ch < 128 && control_char(ch)) { if (!control_char(ch ^ 0100)) SNPRINTF1(buf, sizeof(buf), "^%c", ((char) ch) ^ 0100); else SNPRINTF1(buf, sizeof(buf), binfmt, (char) ch); } else if (is_ubin_char(ch)) { SNPRINTF1(buf, sizeof(buf), utfbinfmt, ch); } else { char *p = buf; if (ch >= 0x80000000) ch = 0xFFFD; /* REPLACEMENT CHARACTER */ put_wchar(&p, ch); *p = '\0'; } return (buf); } /* * Get the length of a UTF-8 character in bytes. */ public int -utf_len(ch) - char ch; +utf_len(char ch) { if ((ch & 0x80) == 0) return 1; if ((ch & 0xE0) == 0xC0) return 2; if ((ch & 0xF0) == 0xE0) return 3; if ((ch & 0xF8) == 0xF0) return 4; if ((ch & 0xFC) == 0xF8) return 5; if ((ch & 0xFE) == 0xFC) return 6; /* Invalid UTF-8 encoding. */ return 1; } /* * Does the parameter point to the lead byte of a well-formed UTF-8 character? */ public int -is_utf8_well_formed(s, slen) - unsigned char *s; - int slen; +is_utf8_well_formed(unsigned char *s, int slen) { int i; int len; if (IS_UTF8_INVALID(s[0])) return (0); len = utf_len((char) s[0]); if (len > slen) return (0); if (len == 1) return (1); if (len == 2) { if (s[0] < 0xC2) return (0); } else { unsigned char mask; mask = (~((1 << (8-len)) - 1)) & 0xFF; if (s[0] == mask && (s[1] & mask) == 0x80) return (0); } for (i = 1; i < len; i++) if (!IS_UTF8_TRAIL(s[i])) return (0); return (1); } /* * Return number of invalid UTF-8 sequences found in a buffer. */ public int -utf_bin_count(data, len) - unsigned char *data; - int len; +utf_bin_count(unsigned char *data, int len) { int bin_count = 0; while (len > 0) { if (is_utf8_well_formed(data, len)) { int clen = utf_len(*data); data += clen; len -= clen; } else { /* Skip to next lead byte. */ bin_count++; do { ++data; --len; } while (len > 0 && !IS_UTF8_LEAD(*data)); } } return (bin_count); } /* * Get the value of a UTF-8 character. */ public LWCHAR -get_wchar(p) - char *p; +get_wchar(constant char *p) { switch (utf_len(p[0])) { case 1: default: /* 0xxxxxxx */ return (LWCHAR) (p[0] & 0xFF); case 2: /* 110xxxxx 10xxxxxx */ return (LWCHAR) ( ((p[0] & 0x1F) << 6) | (p[1] & 0x3F)); case 3: /* 1110xxxx 10xxxxxx 10xxxxxx */ return (LWCHAR) ( ((p[0] & 0x0F) << 12) | ((p[1] & 0x3F) << 6) | (p[2] & 0x3F)); case 4: /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ return (LWCHAR) ( ((p[0] & 0x07) << 18) | ((p[1] & 0x3F) << 12) | ((p[2] & 0x3F) << 6) | (p[3] & 0x3F)); case 5: /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ return (LWCHAR) ( ((p[0] & 0x03) << 24) | ((p[1] & 0x3F) << 18) | ((p[2] & 0x3F) << 12) | ((p[3] & 0x3F) << 6) | (p[4] & 0x3F)); case 6: /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ return (LWCHAR) ( ((p[0] & 0x01) << 30) | ((p[1] & 0x3F) << 24) | ((p[2] & 0x3F) << 18) | ((p[3] & 0x3F) << 12) | ((p[4] & 0x3F) << 6) | (p[5] & 0x3F)); } } /* * Store a character into a UTF-8 string. */ public void -put_wchar(pp, ch) - char **pp; - LWCHAR ch; +put_wchar(char **pp, LWCHAR ch) { if (!utf_mode || ch < 0x80) { /* 0xxxxxxx */ *(*pp)++ = (char) ch; } else if (ch < 0x800) { /* 110xxxxx 10xxxxxx */ *(*pp)++ = (char) (0xC0 | ((ch >> 6) & 0x1F)); *(*pp)++ = (char) (0x80 | (ch & 0x3F)); } else if (ch < 0x10000) { /* 1110xxxx 10xxxxxx 10xxxxxx */ *(*pp)++ = (char) (0xE0 | ((ch >> 12) & 0x0F)); *(*pp)++ = (char) (0x80 | ((ch >> 6) & 0x3F)); *(*pp)++ = (char) (0x80 | (ch & 0x3F)); } else if (ch < 0x200000) { /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ *(*pp)++ = (char) (0xF0 | ((ch >> 18) & 0x07)); *(*pp)++ = (char) (0x80 | ((ch >> 12) & 0x3F)); *(*pp)++ = (char) (0x80 | ((ch >> 6) & 0x3F)); *(*pp)++ = (char) (0x80 | (ch & 0x3F)); } else if (ch < 0x4000000) { /* 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ *(*pp)++ = (char) (0xF0 | ((ch >> 24) & 0x03)); *(*pp)++ = (char) (0x80 | ((ch >> 18) & 0x3F)); *(*pp)++ = (char) (0x80 | ((ch >> 12) & 0x3F)); *(*pp)++ = (char) (0x80 | ((ch >> 6) & 0x3F)); *(*pp)++ = (char) (0x80 | (ch & 0x3F)); } else { /* 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx */ *(*pp)++ = (char) (0xF0 | ((ch >> 30) & 0x01)); *(*pp)++ = (char) (0x80 | ((ch >> 24) & 0x3F)); *(*pp)++ = (char) (0x80 | ((ch >> 18) & 0x3F)); *(*pp)++ = (char) (0x80 | ((ch >> 12) & 0x3F)); *(*pp)++ = (char) (0x80 | ((ch >> 6) & 0x3F)); *(*pp)++ = (char) (0x80 | (ch & 0x3F)); } } /* * Step forward or backward one character in a string. */ public LWCHAR -step_char(pp, dir, limit) - char **pp; - signed int dir; - char *limit; +step_char(constant char **pp, signed int dir, constant char *limit) { LWCHAR ch; int len; - char *p = *pp; + constant char *p = *pp; if (!utf_mode) { /* It's easy if chars are one byte. */ if (dir > 0) ch = (LWCHAR) ((p < limit) ? *p++ : 0); else ch = (LWCHAR) ((p > limit) ? *--p : 0); } else if (dir > 0) { len = utf_len(*p); if (p + len > limit) { ch = 0; p = limit; } else { ch = get_wchar(p); p += len; } } else { while (p > limit && IS_UTF8_TRAIL(p[-1])) p--; if (p > limit) ch = get_wchar(--p); else ch = 0; } *pp = p; return ch; } /* * Unicode characters data * Actual data is in the generated *.uni files. */ #define DECLARE_RANGE_TABLE_START(name) \ static struct wchar_range name##_array[] = { #define DECLARE_RANGE_TABLE_END(name) \ }; struct wchar_range_table name##_table = { name##_array, sizeof(name##_array)/sizeof(*name##_array) }; DECLARE_RANGE_TABLE_START(compose) #include "compose.uni" DECLARE_RANGE_TABLE_END(compose) DECLARE_RANGE_TABLE_START(ubin) #include "ubin.uni" DECLARE_RANGE_TABLE_END(ubin) DECLARE_RANGE_TABLE_START(wide) #include "wide.uni" DECLARE_RANGE_TABLE_END(wide) /* comb_table is special pairs, not ranges. */ static struct wchar_range comb_table[] = { {0x0644,0x0622}, {0x0644,0x0623}, {0x0644,0x0625}, {0x0644,0x0627}, }; static int -is_in_table(ch, table) - LWCHAR ch; - struct wchar_range_table *table; +is_in_table(LWCHAR ch, struct wchar_range_table *table) { int hi; int lo; /* Binary search in the table. */ if (ch < table->table[0].first) return 0; lo = 0; hi = table->count - 1; while (lo <= hi) { int mid = (lo + hi) / 2; if (ch > table->table[mid].last) lo = mid + 1; else if (ch < table->table[mid].first) hi = mid - 1; else return 1; } return 0; } /* * Is a character a UTF-8 composing character? * If a composing character follows any char, the two combine into one glyph. */ public int -is_composing_char(ch) - LWCHAR ch; +is_composing_char(LWCHAR ch) { return is_in_table(ch, &compose_table); } /* * Should this UTF-8 character be treated as binary? */ public int -is_ubin_char(ch) - LWCHAR ch; +is_ubin_char(LWCHAR ch) { return is_in_table(ch, &ubin_table); } /* * Is this a double width UTF-8 character? */ public int -is_wide_char(ch) - LWCHAR ch; +is_wide_char(LWCHAR ch) { return is_in_table(ch, &wide_table); } /* * Is a character a UTF-8 combining character? * A combining char acts like an ordinary char, but if it follows * a specific char (not any char), the two combine into one glyph. */ public int -is_combining_char(ch1, ch2) - LWCHAR ch1; - LWCHAR ch2; +is_combining_char(LWCHAR ch1, LWCHAR ch2) { /* The table is small; use linear search. */ int i; for (i = 0; i < sizeof(comb_table)/sizeof(*comb_table); i++) { if (ch1 == comb_table[i].first && ch2 == comb_table[i].last) return 1; } return 0; } Index: head/contrib/less/cmdbuf.c =================================================================== --- head/contrib/less/cmdbuf.c (revision 316338) +++ head/contrib/less/cmdbuf.c (revision 316339) @@ -1,1700 +1,1659 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Functions which manipulate the command buffer. * Used only by command() and related functions. */ #include "less.h" #include "cmd.h" #include "charset.h" #if HAVE_STAT #include #endif extern int sc_width; extern int utf_mode; static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */ static int cmd_col; /* Current column of the cursor */ static int prompt_col; /* Column of cursor just after prompt */ static char *cp; /* Pointer into cmdbuf */ static int cmd_offset; /* Index into cmdbuf of first displayed char */ static int literal; /* Next input char should not be interpreted */ static int updown_match = -1; /* Prefix length in up/down movement */ #if TAB_COMPLETE_FILENAME -static int cmd_complete(); +static int cmd_complete(int action); /* * These variables are statics used by cmd_complete. */ static int in_completion = 0; static char *tk_text; static char *tk_original; static char *tk_ipoint; static char *tk_trial; static struct textlist tk_tlist; #endif static int cmd_left(); static int cmd_right(); #if SPACES_IN_FILENAMES public char openquote = '"'; public char closequote = '"'; #endif #if CMD_HISTORY /* History file */ #define HISTFILE_FIRST_LINE ".less-history-file:" #define HISTFILE_SEARCH_SECTION ".search" #define HISTFILE_SHELL_SECTION ".shell" /* * A mlist structure represents a command history. */ struct mlist { struct mlist *next; struct mlist *prev; struct mlist *curr_mp; char *string; int modified; }; /* * These are the various command histories that exist. */ struct mlist mlist_search = { &mlist_search, &mlist_search, &mlist_search, NULL, 0 }; public void * constant ml_search = (void *) &mlist_search; struct mlist mlist_examine = { &mlist_examine, &mlist_examine, &mlist_examine, NULL, 0 }; public void * constant ml_examine = (void *) &mlist_examine; #if SHELL_ESCAPE || PIPEC struct mlist mlist_shell = { &mlist_shell, &mlist_shell, &mlist_shell, NULL, 0 }; public void * constant ml_shell = (void *) &mlist_shell; #endif #else /* CMD_HISTORY */ /* If CMD_HISTORY is off, these are just flags. */ public void * constant ml_search = (void *)1; public void * constant ml_examine = (void *)2; #if SHELL_ESCAPE || PIPEC public void * constant ml_shell = (void *)3; #endif #endif /* CMD_HISTORY */ /* * History for the current command. */ static struct mlist *curr_mlist = NULL; static int curr_cmdflags; static char cmd_mbc_buf[MAX_UTF_CHAR_LEN]; static int cmd_mbc_buf_len; static int cmd_mbc_buf_index; /* * Reset command buffer (to empty). */ public void -cmd_reset() +cmd_reset(void) { cp = cmdbuf; *cp = '\0'; cmd_col = 0; cmd_offset = 0; literal = 0; cmd_mbc_buf_len = 0; updown_match = -1; } /* * Clear command line. */ public void -clear_cmd() +clear_cmd(void) { cmd_col = prompt_col = 0; cmd_mbc_buf_len = 0; updown_match = -1; } /* * Display a string, usually as a prompt for input into the command buffer. */ public void -cmd_putstr(s) - char *s; +cmd_putstr(constant char *s) { LWCHAR prev_ch = 0; LWCHAR ch; - char *endline = s + strlen(s); + constant char *endline = s + strlen(s); while (*s != '\0') { - char *ns = s; + constant char *ns = s; ch = step_char(&ns, +1, endline); while (s < ns) putchr(*s++); if (!utf_mode) { cmd_col++; prompt_col++; } else if (!is_composing_char(ch) && !is_combining_char(prev_ch, ch)) { int width = is_wide_char(ch) ? 2 : 1; cmd_col += width; prompt_col += width; } prev_ch = ch; } } /* * How many characters are in the command buffer? */ public int -len_cmdbuf() +len_cmdbuf(void) { - char *s = cmdbuf; - char *endline = s + strlen(s); + constant char *s = cmdbuf; + constant char *endline = s + strlen(s); int len = 0; while (*s != '\0') { step_char(&s, +1, endline); len++; } return (len); } /* * Common part of cmd_step_right() and cmd_step_left(). */ static char * -cmd_step_common(p, ch, len, pwidth, bswidth) - char *p; - LWCHAR ch; - int len; - int *pwidth; - int *bswidth; +cmd_step_common(constant char *p, LWCHAR ch, int len, int *pwidth, int *bswidth) { char *pr; if (len == 1) { pr = prchar((int) ch); if (pwidth != NULL || bswidth != NULL) { int len = (int) strlen(pr); if (pwidth != NULL) *pwidth = len; if (bswidth != NULL) *bswidth = len; } } else { pr = prutfchar(ch); if (pwidth != NULL || bswidth != NULL) { if (is_composing_char(ch)) { if (pwidth != NULL) *pwidth = 0; if (bswidth != NULL) *bswidth = 0; } else if (is_ubin_char(ch)) { int len = (int) strlen(pr); if (pwidth != NULL) *pwidth = len; if (bswidth != NULL) *bswidth = len; } else { LWCHAR prev_ch = step_char(&p, -1, cmdbuf); if (is_combining_char(prev_ch, ch)) { if (pwidth != NULL) *pwidth = 0; if (bswidth != NULL) *bswidth = 0; } else { if (pwidth != NULL) *pwidth = is_wide_char(ch) ? 2 : 1; if (bswidth != NULL) *bswidth = 1; } } } } return (pr); } /* * Step a pointer one character right in the command buffer. */ static char * -cmd_step_right(pp, pwidth, bswidth) - char **pp; - int *pwidth; - int *bswidth; +cmd_step_right(char **pp, int *pwidth, int *bswidth) { char *p = *pp; - LWCHAR ch = step_char(pp, +1, p + strlen(p)); + LWCHAR ch = step_char((constant char **)pp, +1, p + strlen(p)); return cmd_step_common(p, ch, *pp - p, pwidth, bswidth); } /* * Step a pointer one character left in the command buffer. */ static char * -cmd_step_left(pp, pwidth, bswidth) - char **pp; - int *pwidth; - int *bswidth; +cmd_step_left(char **pp, int *pwidth, int *bswidth) { char *p = *pp; - LWCHAR ch = step_char(pp, -1, cmdbuf); + LWCHAR ch = step_char((constant char **)pp, -1, cmdbuf); return cmd_step_common(*pp, ch, p - *pp, pwidth, bswidth); } /* * Repaint the line from cp onwards. * Then position the cursor just after the char old_cp (a pointer into cmdbuf). */ static void -cmd_repaint(old_cp) - char *old_cp; +cmd_repaint(char *old_cp) { /* * Repaint the line from the current position. */ clear_eol(); while (*cp != '\0') { char *np = cp; int width; - char *pr = cmd_step_right(&np, &width, NULL); + constant char *pr = cmd_step_right(&np, &width, NULL); if (cmd_col + width >= sc_width) break; cp = np; putstr(pr); cmd_col += width; } while (*cp != '\0') { char *np = cp; int width; char *pr = cmd_step_right(&np, &width, NULL); if (width > 0) break; cp = np; putstr(pr); } /* * Back up the cursor to the correct position. */ while (cp > old_cp) cmd_left(); } /* * Put the cursor at "home" (just after the prompt), * and set cp to the corresponding char in cmdbuf. */ static void -cmd_home() +cmd_home(void) { while (cmd_col > prompt_col) { int width, bswidth; cmd_step_left(&cp, &width, &bswidth); while (bswidth-- > 0) putbs(); cmd_col -= width; } cp = &cmdbuf[cmd_offset]; } /* * Shift the cmdbuf display left a half-screen. */ static void -cmd_lshift() +cmd_lshift(void) { char *s; char *save_cp; int cols; /* * Start at the first displayed char, count how far to the * right we'd have to move to reach the center of the screen. */ s = cmdbuf + cmd_offset; cols = 0; while (cols < (sc_width - prompt_col) / 2 && *s != '\0') { int width; cmd_step_right(&s, &width, NULL); cols += width; } while (*s != '\0') { int width; char *ns = s; cmd_step_right(&ns, &width, NULL); if (width > 0) break; s = ns; } cmd_offset = (int) (s - cmdbuf); save_cp = cp; cmd_home(); cmd_repaint(save_cp); } /* * Shift the cmdbuf display right a half-screen. */ static void -cmd_rshift() +cmd_rshift(void) { char *s; char *save_cp; int cols; /* * Start at the first displayed char, count how far to the * left we'd have to move to traverse a half-screen width * of displayed characters. */ s = cmdbuf + cmd_offset; cols = 0; while (cols < (sc_width - prompt_col) / 2 && s > cmdbuf) { int width; cmd_step_left(&s, &width, NULL); cols += width; } cmd_offset = (int) (s - cmdbuf); save_cp = cp; cmd_home(); cmd_repaint(save_cp); } /* * Move cursor right one character. */ static int -cmd_right() +cmd_right(void) { char *pr; char *ncp; int width; if (*cp == '\0') { /* Already at the end of the line. */ return (CC_OK); } ncp = cp; pr = cmd_step_right(&ncp, &width, NULL); if (cmd_col + width >= sc_width) cmd_lshift(); else if (cmd_col + width == sc_width - 1 && cp[1] != '\0') cmd_lshift(); cp = ncp; cmd_col += width; putstr(pr); while (*cp != '\0') { pr = cmd_step_right(&ncp, &width, NULL); if (width > 0) break; putstr(pr); cp = ncp; } return (CC_OK); } /* * Move cursor left one character. */ static int -cmd_left() +cmd_left(void) { char *ncp; int width, bswidth; if (cp <= cmdbuf) { /* Already at the beginning of the line */ return (CC_OK); } ncp = cp; while (ncp > cmdbuf) { cmd_step_left(&ncp, &width, &bswidth); if (width > 0) break; } if (cmd_col < prompt_col + width) cmd_rshift(); cp = ncp; cmd_col -= width; while (bswidth-- > 0) putbs(); return (CC_OK); } /* * Insert a char into the command buffer, at the current position. */ static int -cmd_ichar(cs, clen) - char *cs; - int clen; +cmd_ichar(char *cs, int clen) { char *s; if (strlen(cmdbuf) + clen >= sizeof(cmdbuf)-1) { /* No room in the command buffer for another char. */ bell(); return (CC_ERROR); } /* * Make room for the new character (shift the tail of the buffer right). */ for (s = &cmdbuf[strlen(cmdbuf)]; s >= cp; s--) s[clen] = s[0]; /* * Insert the character into the buffer. */ for (s = cp; s < cp + clen; s++) *s = *cs++; /* * Reprint the tail of the line from the inserted char. */ updown_match = -1; cmd_repaint(cp); cmd_right(); return (CC_OK); } /* * Backspace in the command buffer. * Delete the char to the left of the cursor. */ static int -cmd_erase() +cmd_erase(void) { - register char *s; + char *s; int clen; if (cp == cmdbuf) { /* * Backspace past beginning of the buffer: * this usually means abort the command. */ return (CC_QUIT); } /* * Move cursor left (to the char being erased). */ s = cp; cmd_left(); clen = (int) (s - cp); /* * Remove the char from the buffer (shift the buffer left). */ for (s = cp; ; s++) { s[0] = s[clen]; if (s[0] == '\0') break; } /* * Repaint the buffer after the erased char. */ updown_match = -1; cmd_repaint(cp); /* * We say that erasing the entire command string causes us * to abort the current command, if CF_QUIT_ON_ERASE is set. */ if ((curr_cmdflags & CF_QUIT_ON_ERASE) && cp == cmdbuf && *cp == '\0') return (CC_QUIT); return (CC_OK); } /* * Delete the char under the cursor. */ static int -cmd_delete() +cmd_delete(void) { if (*cp == '\0') { /* At end of string; there is no char under the cursor. */ return (CC_OK); } /* * Move right, then use cmd_erase. */ cmd_right(); cmd_erase(); return (CC_OK); } /* * Delete the "word" to the left of the cursor. */ static int -cmd_werase() +cmd_werase(void) { if (cp > cmdbuf && cp[-1] == ' ') { /* * If the char left of cursor is a space, * erase all the spaces left of cursor (to the first non-space). */ while (cp > cmdbuf && cp[-1] == ' ') (void) cmd_erase(); } else { /* * If the char left of cursor is not a space, * erase all the nonspaces left of cursor (the whole "word"). */ while (cp > cmdbuf && cp[-1] != ' ') (void) cmd_erase(); } return (CC_OK); } /* * Delete the "word" under the cursor. */ static int -cmd_wdelete() +cmd_wdelete(void) { if (*cp == ' ') { /* * If the char under the cursor is a space, * delete it and all the spaces right of cursor. */ while (*cp == ' ') (void) cmd_delete(); } else { /* * If the char under the cursor is not a space, * delete it and all nonspaces right of cursor (the whole word). */ while (*cp != ' ' && *cp != '\0') (void) cmd_delete(); } return (CC_OK); } /* * Delete all chars in the command buffer. */ static int -cmd_kill() +cmd_kill(void) { if (cmdbuf[0] == '\0') { /* Buffer is already empty; abort the current command. */ return (CC_QUIT); } cmd_offset = 0; cmd_home(); *cp = '\0'; updown_match = -1; cmd_repaint(cp); /* * We say that erasing the entire command string causes us * to abort the current command, if CF_QUIT_ON_ERASE is set. */ if (curr_cmdflags & CF_QUIT_ON_ERASE) return (CC_QUIT); return (CC_OK); } /* * Select an mlist structure to be the current command history. */ public void -set_mlist(mlist, cmdflags) - void *mlist; - int cmdflags; +set_mlist(constant void *mlist, int cmdflags) { #if CMD_HISTORY curr_mlist = (struct mlist *) mlist; curr_cmdflags = cmdflags; /* Make sure the next up-arrow moves to the last string in the mlist. */ if (curr_mlist != NULL) curr_mlist->curr_mp = curr_mlist; #endif } #if CMD_HISTORY /* * Move up or down in the currently selected command history list. * Only consider entries whose first updown_match chars are equal to * cmdbuf's corresponding chars. */ static int -cmd_updown(action) - int action; +cmd_updown(int action) { char *s; struct mlist *ml; if (curr_mlist == NULL) { /* * The current command has no history list. */ bell(); return (CC_OK); } if (updown_match < 0) { updown_match = (int) (cp - cmdbuf); } /* * Find the next history entry which matches. */ for (ml = curr_mlist->curr_mp;;) { ml = (action == EC_UP) ? ml->prev : ml->next; if (ml == curr_mlist) { /* * We reached the end (or beginning) of the list. */ break; } if (strncmp(cmdbuf, ml->string, updown_match) == 0) { /* * This entry matches; stop here. * Copy the entry into cmdbuf and echo it on the screen. */ curr_mlist->curr_mp = ml; s = ml->string; if (s == NULL) s = ""; cmd_home(); clear_eol(); strcpy(cmdbuf, s); for (cp = cmdbuf; *cp != '\0'; ) cmd_right(); return (CC_OK); } } /* * We didn't find a history entry that matches. */ bell(); return (CC_OK); } #endif /* * Add a string to an mlist. */ public void -cmd_addhist(mlist, cmd, modified) - struct mlist *mlist; - char *cmd; - int modified; +cmd_addhist(struct mlist *constant mlist, char *cmd, int modified) { #if CMD_HISTORY struct mlist *ml; /* * Don't save a trivial command. */ if (strlen(cmd) == 0) return; /* * Save the command unless it's a duplicate of the * last command in the history. */ ml = mlist->prev; if (ml == mlist || strcmp(ml->string, cmd) != 0) { /* * Did not find command in history. * Save the command and put it at the end of the history list. */ ml = (struct mlist *) ecalloc(1, sizeof(struct mlist)); ml->string = save(cmd); ml->modified = modified; ml->next = mlist; ml->prev = mlist->prev; mlist->prev->next = ml; mlist->prev = ml; } /* * Point to the cmd just after the just-accepted command. * Thus, an UPARROW will always retrieve the previous command. */ mlist->curr_mp = ml->next; #endif } /* * Accept the command in the command buffer. * Add it to the currently selected history list. */ public void -cmd_accept() +cmd_accept(void) { #if CMD_HISTORY /* * Nothing to do if there is no currently selected history list. */ if (curr_mlist == NULL) return; cmd_addhist(curr_mlist, cmdbuf, 1); curr_mlist->modified = 1; #endif } /* * Try to perform a line-edit function on the command buffer, * using a specified char as a line-editing command. * Returns: * CC_PASS The char does not invoke a line edit function. * CC_OK Line edit function done. * CC_QUIT The char requests the current command to be aborted. */ static int -cmd_edit(c) - int c; +cmd_edit(int c) { int action; int flags; #if TAB_COMPLETE_FILENAME #define not_in_completion() in_completion = 0 #else #define not_in_completion() #endif /* * See if the char is indeed a line-editing command. */ flags = 0; #if CMD_HISTORY if (curr_mlist == NULL) /* * No current history; don't accept history manipulation cmds. */ flags |= EC_NOHISTORY; #endif #if TAB_COMPLETE_FILENAME if (curr_mlist == ml_search) /* * In a search command; don't accept file-completion cmds. */ flags |= EC_NOCOMPLETE; #endif action = editchar(c, flags); switch (action) { case EC_RIGHT: not_in_completion(); return (cmd_right()); case EC_LEFT: not_in_completion(); return (cmd_left()); case EC_W_RIGHT: not_in_completion(); while (*cp != '\0' && *cp != ' ') cmd_right(); while (*cp == ' ') cmd_right(); return (CC_OK); case EC_W_LEFT: not_in_completion(); while (cp > cmdbuf && cp[-1] == ' ') cmd_left(); while (cp > cmdbuf && cp[-1] != ' ') cmd_left(); return (CC_OK); case EC_HOME: not_in_completion(); cmd_offset = 0; cmd_home(); cmd_repaint(cp); return (CC_OK); case EC_END: not_in_completion(); while (*cp != '\0') cmd_right(); return (CC_OK); case EC_INSERT: not_in_completion(); return (CC_OK); case EC_BACKSPACE: not_in_completion(); return (cmd_erase()); case EC_LINEKILL: not_in_completion(); return (cmd_kill()); case EC_ABORT: not_in_completion(); (void) cmd_kill(); return (CC_QUIT); case EC_W_BACKSPACE: not_in_completion(); return (cmd_werase()); case EC_DELETE: not_in_completion(); return (cmd_delete()); case EC_W_DELETE: not_in_completion(); return (cmd_wdelete()); case EC_LITERAL: literal = 1; return (CC_OK); #if CMD_HISTORY case EC_UP: case EC_DOWN: not_in_completion(); return (cmd_updown(action)); #endif #if TAB_COMPLETE_FILENAME case EC_F_COMPLETE: case EC_B_COMPLETE: case EC_EXPAND: return (cmd_complete(action)); #endif case EC_NOACTION: return (CC_OK); default: not_in_completion(); return (CC_PASS); } } #if TAB_COMPLETE_FILENAME /* * Insert a string into the command buffer, at the current position. */ static int -cmd_istr(str) - char *str; +cmd_istr(char *str) { char *s; int action; char *endline = str + strlen(str); for (s = str; *s != '\0'; ) { char *os = s; - step_char(&s, +1, endline); + step_char((constant char **)&s, +1, endline); action = cmd_ichar(os, s - os); if (action != CC_OK) { bell(); return (action); } } return (CC_OK); } /* * Find the beginning and end of the "current" word. * This is the word which the cursor (cp) is inside or at the end of. * Return pointer to the beginning of the word and put the * cursor at the end of the word. */ static char * -delimit_word() +delimit_word(void) { char *word; #if SPACES_IN_FILENAMES char *p; int delim_quoted = 0; int meta_quoted = 0; char *esc = get_meta_escape(); int esclen = (int) strlen(esc); #endif /* * Move cursor to end of word. */ if (*cp != ' ' && *cp != '\0') { /* * Cursor is on a nonspace. * Move cursor right to the next space. */ while (*cp != ' ' && *cp != '\0') cmd_right(); } else if (cp > cmdbuf && cp[-1] != ' ') { /* * Cursor is on a space, and char to the left is a nonspace. * We're already at the end of the word. */ ; #if 0 } else { /* * Cursor is on a space and char to the left is a space. * Huh? There's no word here. */ return (NULL); #endif } /* * Find the beginning of the word which the cursor is in. */ if (cp == cmdbuf) return (NULL); #if SPACES_IN_FILENAMES /* * If we have an unbalanced quote (that is, an open quote * without a corresponding close quote), we return everything * from the open quote, including spaces. */ for (word = cmdbuf; word < cp; word++) if (*word != ' ') break; if (word >= cp) return (cp); for (p = cmdbuf; p < cp; p++) { if (meta_quoted) { meta_quoted = 0; } else if (esclen > 0 && p + esclen < cp && strncmp(p, esc, esclen) == 0) { meta_quoted = 1; p += esclen - 1; } else if (delim_quoted) { if (*p == closequote) delim_quoted = 0; } else /* (!delim_quoted) */ { if (*p == openquote) delim_quoted = 1; else if (*p == ' ') word = p+1; } } #endif return (word); } /* * Set things up to enter completion mode. * Expand the word under the cursor into a list of filenames * which start with that word, and set tk_text to that list. */ static void -init_compl() +init_compl(void) { char *word; char c; /* * Get rid of any previous tk_text. */ if (tk_text != NULL) { free(tk_text); tk_text = NULL; } /* * Find the original (uncompleted) word in the command buffer. */ word = delimit_word(); if (word == NULL) return; /* * Set the insertion point to the point in the command buffer * where the original (uncompleted) word now sits. */ tk_ipoint = word; /* * Save the original (uncompleted) word */ if (tk_original != NULL) free(tk_original); tk_original = (char *) ecalloc(cp-word+1, sizeof(char)); strncpy(tk_original, word, cp-word); /* * Get the expanded filename. * This may result in a single filename, or * a blank-separated list of filenames. */ c = *cp; *cp = '\0'; if (*word != openquote) { tk_text = fcomplete(word); } else { #if MSDOS_COMPILER char *qword = NULL; #else char *qword = shell_quote(word+1); #endif if (qword == NULL) tk_text = fcomplete(word+1); else { tk_text = fcomplete(qword); free(qword); } } *cp = c; } /* * Return the next word in the current completion list. */ static char * -next_compl(action, prev) - int action; - char *prev; +next_compl(int action, char *prev) { switch (action) { case EC_F_COMPLETE: return (forw_textlist(&tk_tlist, prev)); case EC_B_COMPLETE: return (back_textlist(&tk_tlist, prev)); } /* Cannot happen */ return ("?"); } /* * Complete the filename before (or under) the cursor. * cmd_complete may be called multiple times. The global in_completion * remembers whether this call is the first time (create the list), * or a subsequent time (step thru the list). */ static int -cmd_complete(action) - int action; +cmd_complete(int action) { char *s; if (!in_completion || action == EC_EXPAND) { /* * Expand the word under the cursor and * use the first word in the expansion * (or the entire expansion if we're doing EC_EXPAND). */ init_compl(); if (tk_text == NULL) { bell(); return (CC_OK); } if (action == EC_EXPAND) { /* * Use the whole list. */ tk_trial = tk_text; } else { /* * Use the first filename in the list. */ in_completion = 1; init_textlist(&tk_tlist, tk_text); tk_trial = next_compl(action, (char*)NULL); } } else { /* * We already have a completion list. * Use the next/previous filename from the list. */ tk_trial = next_compl(action, tk_trial); } /* * Remove the original word, or the previous trial completion. */ while (cp > tk_ipoint) (void) cmd_erase(); if (tk_trial == NULL) { /* * There are no more trial completions. * Insert the original (uncompleted) filename. */ in_completion = 0; if (cmd_istr(tk_original) != CC_OK) goto fail; } else { /* * Insert trial completion. */ if (cmd_istr(tk_trial) != CC_OK) goto fail; /* * If it is a directory, append a slash. */ if (is_dir(tk_trial)) { if (cp > cmdbuf && cp[-1] == closequote) (void) cmd_erase(); s = lgetenv("LESSSEPARATOR"); if (s == NULL) s = PATHNAME_SEP; if (cmd_istr(s) != CC_OK) goto fail; } } return (CC_OK); fail: in_completion = 0; bell(); return (CC_OK); } #endif /* TAB_COMPLETE_FILENAME */ /* * Process a single character of a multi-character command, such as * a number, or the pattern of a search command. * Returns: * CC_OK The char was accepted. * CC_QUIT The char requests the command to be aborted. * CC_ERROR The char could not be accepted due to an error. */ public int -cmd_char(c) - int c; +cmd_char(int c) { int action; int len; if (!utf_mode) { cmd_mbc_buf[0] = c; len = 1; } else { /* Perform strict validation in all possible cases. */ if (cmd_mbc_buf_len == 0) { retry: cmd_mbc_buf_index = 1; *cmd_mbc_buf = c; if (IS_ASCII_OCTET(c)) cmd_mbc_buf_len = 1; else if (IS_UTF8_LEAD(c)) { cmd_mbc_buf_len = utf_len(c); return (CC_OK); } else { /* UTF8_INVALID or stray UTF8_TRAIL */ bell(); return (CC_ERROR); } } else if (IS_UTF8_TRAIL(c)) { cmd_mbc_buf[cmd_mbc_buf_index++] = c; if (cmd_mbc_buf_index < cmd_mbc_buf_len) return (CC_OK); if (!is_utf8_well_formed(cmd_mbc_buf, cmd_mbc_buf_index)) { /* complete, but not well formed (non-shortest form), sequence */ cmd_mbc_buf_len = 0; bell(); return (CC_ERROR); } } else { /* Flush incomplete (truncated) sequence. */ cmd_mbc_buf_len = 0; bell(); /* Handle new char. */ goto retry; } len = cmd_mbc_buf_len; cmd_mbc_buf_len = 0; } if (literal) { /* * Insert the char, even if it is a line-editing char. */ literal = 0; return (cmd_ichar(cmd_mbc_buf, len)); } /* * See if it is a line-editing character. */ if (in_mca() && len == 1) { action = cmd_edit(c); switch (action) { case CC_OK: case CC_QUIT: return (action); case CC_PASS: break; } } /* * Insert the char into the command buffer. */ return (cmd_ichar(cmd_mbc_buf, len)); } /* * Return the number currently in the command buffer. */ public LINENUM -cmd_int(frac) - long *frac; +cmd_int(long *frac) { char *p; LINENUM n = 0; int err; for (p = cmdbuf; *p >= '0' && *p <= '9'; p++) n = (n * 10) + (*p - '0'); *frac = 0; if (*p++ == '.') { *frac = getfraction(&p, NULL, &err); /* {{ do something if err is set? }} */ } return (n); } /* * Return a pointer to the command buffer. */ public char * -get_cmdbuf() +get_cmdbuf(void) { return (cmdbuf); } #if CMD_HISTORY /* * Return the last (most recent) string in the current command history. */ public char * -cmd_lastpattern() +cmd_lastpattern(void) { if (curr_mlist == NULL) return (NULL); return (curr_mlist->curr_mp->prev->string); } #endif #if CMD_HISTORY /* */ static int -mlist_size(ml) - struct mlist *ml; +mlist_size(struct mlist *ml) { int size = 0; for (ml = ml->next; ml->string != NULL; ml = ml->next) ++size; return size; } /* * Get the name of the history file. */ static char * -histfile_name() +histfile_name(void) { char *home; char *name; int len; /* See if filename is explicitly specified by $LESSHISTFILE. */ name = lgetenv("LESSHISTFILE"); if (name != NULL && *name != '\0') { if (strcmp(name, "-") == 0 || strcmp(name, "/dev/null") == 0) /* $LESSHISTFILE == "-" means don't use a history file. */ return (NULL); return (save(name)); } /* See if history file is disabled in the build. */ if (strcmp(LESSHISTFILE, "") == 0 || strcmp(LESSHISTFILE, "-") == 0) return (NULL); /* Otherwise, file is in $HOME. */ home = lgetenv("HOME"); if (home == NULL || *home == '\0') { #if OS2 home = lgetenv("INIT"); if (home == NULL || *home == '\0') #endif return (NULL); } len = (int) (strlen(home) + strlen(LESSHISTFILE) + 2); name = (char *) ecalloc(len, sizeof(char)); SNPRINTF2(name, len, "%s/%s", home, LESSHISTFILE); return (name); } /* * Read a .lesshst file and call a callback for each line in the file. */ static void -read_cmdhist2(action, uparam, skip_search, skip_shell) - void (*action)(void*,struct mlist*,char*); - void *uparam; - int skip_search; - int skip_shell; +read_cmdhist2(void (*action)(void*,struct mlist*,char*), void *uparam, + int skip_search, int skip_shell) { struct mlist *ml = NULL; char line[CMDBUF_SIZE]; char *filename; FILE *f; char *p; int *skip = NULL; filename = histfile_name(); if (filename == NULL) return; f = fopen(filename, "r"); free(filename); if (f == NULL) return; if (fgets(line, sizeof(line), f) == NULL || strncmp(line, HISTFILE_FIRST_LINE, strlen(HISTFILE_FIRST_LINE)) != 0) { fclose(f); return; } while (fgets(line, sizeof(line), f) != NULL) { for (p = line; *p != '\0'; p++) { if (*p == '\n' || *p == '\r') { *p = '\0'; break; } } if (strcmp(line, HISTFILE_SEARCH_SECTION) == 0) { ml = &mlist_search; skip = &skip_search; } else if (strcmp(line, HISTFILE_SHELL_SECTION) == 0) { #if SHELL_ESCAPE || PIPEC ml = &mlist_shell; skip = &skip_shell; #else ml = NULL; skip = NULL; #endif } else if (*line == '"') { if (ml != NULL) { if (skip != NULL && *skip > 0) --(*skip); else (*action)(uparam, ml, line+1); } } } fclose(f); } static void -read_cmdhist(action, uparam, skip_search, skip_shell) - void (*action)(void*,struct mlist*,char*); - void *uparam; - int skip_search; - int skip_shell; +read_cmdhist(void (*action)(void*,struct mlist*,char*), void *uparam, + int skip_search, int skip_shell) { read_cmdhist2(action, uparam, skip_search, skip_shell); (*action)(uparam, NULL, NULL); /* signal end of file */ } static void addhist_init(void *uparam, struct mlist *ml, char *string) { if (ml == NULL || string == NULL) return; cmd_addhist(ml, string, 0); } #endif /* CMD_HISTORY */ /* * Initialize history from a .lesshist file. */ public void -init_cmdhist() +init_cmdhist(void) { #if CMD_HISTORY read_cmdhist(&addhist_init, NULL, 0, 0); #endif /* CMD_HISTORY */ } /* * Write the header for a section of the history file. */ #if CMD_HISTORY static void -write_mlist_header(ml, f) - struct mlist *ml; - FILE *f; +write_mlist_header(struct mlist *ml, FILE *f) { if (ml == &mlist_search) fprintf(f, "%s\n", HISTFILE_SEARCH_SECTION); #if SHELL_ESCAPE || PIPEC else if (ml == &mlist_shell) fprintf(f, "%s\n", HISTFILE_SHELL_SECTION); #endif } /* * Write all modified entries in an mlist to the history file. */ static void -write_mlist(ml, f) - struct mlist *ml; - FILE *f; +write_mlist(struct mlist *ml, FILE *f) { for (ml = ml->next; ml->string != NULL; ml = ml->next) { if (!ml->modified) continue; fprintf(f, "\"%s\n", ml->string); ml->modified = 0; } ml->modified = 0; /* entire mlist is now unmodified */ } /* * Make a temp name in the same directory as filename. */ static char * -make_tempname(filename) - char *filename; +make_tempname(char *filename) { char lastch; char *tempname = ecalloc(1, strlen(filename)+1); strcpy(tempname, filename); lastch = tempname[strlen(tempname)-1]; tempname[strlen(tempname)-1] = (lastch == 'Q') ? 'Z' : 'Q'; return tempname; } struct save_ctx { struct mlist *mlist; FILE *fout; }; /* * Copy entries from the saved history file to a new file. * At the end of each mlist, append any new entries * created during this session. */ static void copy_hist(void *uparam, struct mlist *ml, char *string) { struct save_ctx *ctx = (struct save_ctx *) uparam; if (ml != ctx->mlist) { /* We're changing mlists. */ if (ctx->mlist) /* Append any new entries to the end of the current mlist. */ write_mlist(ctx->mlist, ctx->fout); /* Write the header for the new mlist. */ ctx->mlist = ml; write_mlist_header(ctx->mlist, ctx->fout); } if (string != NULL) { /* Copy the entry. */ fprintf(ctx->fout, "\"%s\n", string); } if (ml == NULL) /* End of file */ { /* Write any sections that were not in the original file. */ if (mlist_search.modified) { write_mlist_header(&mlist_search, ctx->fout); write_mlist(&mlist_search, ctx->fout); } #if SHELL_ESCAPE || PIPEC if (mlist_shell.modified) { write_mlist_header(&mlist_shell, ctx->fout); write_mlist(&mlist_shell, ctx->fout); } #endif } } #endif /* CMD_HISTORY */ /* * Make a file readable only by its owner. */ static void -make_file_private(f) - FILE *f; +make_file_private(FILE *f) { #if HAVE_FCHMOD int do_chmod = 1; #if HAVE_STAT struct stat statbuf; int r = fstat(fileno(f), &statbuf); if (r < 0 || !S_ISREG(statbuf.st_mode)) /* Don't chmod if not a regular file. */ do_chmod = 0; #endif if (do_chmod) fchmod(fileno(f), 0600); #endif } /* * Does the history file need to be updated? */ static int -histfile_modified() +histfile_modified(void) { if (mlist_search.modified) return 1; #if SHELL_ESCAPE || PIPEC if (mlist_shell.modified) return 1; #endif return 0; } /* * Update the .lesshst file. */ public void -save_cmdhist() +save_cmdhist(void) { #if CMD_HISTORY char *histname; char *tempname; int skip_search; int skip_shell; struct save_ctx ctx; char *s; FILE *fout = NULL; int histsize = 0; if (!histfile_modified()) return; histname = histfile_name(); if (histname == NULL) return; tempname = make_tempname(histname); fout = fopen(tempname, "w"); if (fout != NULL) { make_file_private(fout); s = lgetenv("LESSHISTSIZE"); if (s != NULL) histsize = atoi(s); if (histsize <= 0) histsize = 100; skip_search = mlist_size(&mlist_search) - histsize; #if SHELL_ESCAPE || PIPEC skip_shell = mlist_size(&mlist_shell) - histsize; #endif fprintf(fout, "%s\n", HISTFILE_FIRST_LINE); ctx.fout = fout; ctx.mlist = NULL; read_cmdhist(copy_hist, &ctx, skip_search, skip_shell); fclose(fout); #if MSDOS_COMPILER==WIN32C /* * Windows rename doesn't remove an existing file, * making it useless for atomic operations. Sigh. */ remove(histname); #endif rename(tempname, histname); } free(tempname); free(histname); #endif /* CMD_HISTORY */ } Index: head/contrib/less/command.c =================================================================== --- head/contrib/less/command.c (revision 316338) +++ head/contrib/less/command.c (revision 316339) @@ -1,1812 +1,1796 @@ /* $FreeBSD$ */ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * User-level command processor. */ #include "less.h" #if MSDOS_COMPILER==WIN32C #include #endif #include "position.h" #include "option.h" #include "cmd.h" extern int erase_char, erase2_char, kill_char; extern int sigs; extern int quit_if_one_screen; extern int squished; extern int sc_width; extern int sc_height; extern int swindow; extern int jump_sline; extern int quitting; extern int wscroll; extern int top_scroll; extern int ignore_eoi; extern int secure; extern int hshift; extern int bs_mode; extern int show_attn; extern int less_is_more; extern POSITION highest_hilite; extern char *every_first_cmd; extern char *curr_altfilename; extern char version[]; extern struct scrpos initial_scrpos; extern IFILE curr_ifile; extern void constant *ml_search; extern void constant *ml_examine; #if SHELL_ESCAPE || PIPEC extern void constant *ml_shell; #endif #if EDITOR extern char *editor; extern char *editproto; #endif extern int screen_trashed; /* The screen has been overwritten */ extern int shift_count; extern int oldbot; extern int forw_prompt; extern int same_pos_bell; #if SHELL_ESCAPE static char *shellcmd = NULL; /* For holding last shell command for "!!" */ #endif static int mca; /* The multicharacter command (action) */ static int search_type; /* The previous type of search */ static LINENUM number; /* The number typed by the user */ static long fraction; /* The fractional part of the number */ static struct loption *curropt; static int opt_lower; static int optflag; static int optgetname; static POSITION bottompos; static int save_hshift; static int save_bs_mode; #if PIPEC static char pipec; #endif struct ungot { struct ungot *ug_next; char ug_char; char ug_end_command; }; static struct ungot* ungot = NULL; -static void multi_search(); +static void multi_search(char *pattern, int n, int silent); /* * Move the cursor to start of prompt line before executing a command. * This looks nicer if the command takes a long time before * updating the screen. */ static void -cmd_exec() +cmd_exec(void) { #if HILITE_SEARCH clear_attn(); #endif clear_bot(); flush(); } /* * Set up the display to start a new multi-character command. */ static void -start_mca(action, prompt, mlist, cmdflags) - int action; - constant char *prompt; - constant void *mlist; - int cmdflags; +start_mca(int action, constant char *prompt, constant void *mlist, int cmdflags) { mca = action; clear_bot(); clear_cmd(); cmd_putstr(prompt); set_mlist(mlist, cmdflags); } public int -in_mca() +in_mca(void) { return (mca != 0 && mca != A_PREFIX); } /* * Set up the display to start a new search command. */ static void -mca_search() +mca_search(void) { #if HILITE_SEARCH if (search_type & SRCH_FILTER) mca = A_FILTER; else #endif if (search_type & SRCH_FORW) mca = A_F_SEARCH; else mca = A_B_SEARCH; clear_bot(); clear_cmd(); if (search_type & SRCH_NO_MATCH) cmd_putstr("Non-match "); if (search_type & SRCH_FIRST_FILE) cmd_putstr("First-file "); if (search_type & SRCH_PAST_EOF) cmd_putstr("EOF-ignore "); if (search_type & SRCH_NO_MOVE) cmd_putstr("Keep-pos "); if (search_type & SRCH_NO_REGEX) cmd_putstr("Regex-off "); #if HILITE_SEARCH if (search_type & SRCH_FILTER) cmd_putstr("&/"); else #endif if (search_type & SRCH_FORW) cmd_putstr("/"); else cmd_putstr("?"); forw_prompt = 0; set_mlist(ml_search, 0); } /* * Set up the display to start a new toggle-option command. */ static void -mca_opt_toggle() +mca_opt_toggle(void) { int no_prompt; int flag; char *dash; no_prompt = (optflag & OPT_NO_PROMPT); flag = (optflag & ~OPT_NO_PROMPT); dash = (flag == OPT_NO_TOGGLE) ? "_" : "-"; mca = A_OPT_TOGGLE; clear_bot(); clear_cmd(); cmd_putstr(dash); if (optgetname) cmd_putstr(dash); if (no_prompt) cmd_putstr("(P)"); switch (flag) { case OPT_UNSET: cmd_putstr("+"); break; case OPT_SET: cmd_putstr("!"); break; } forw_prompt = 0; set_mlist(NULL, 0); } /* * Execute a multicharacter command. */ static void -exec_mca() +exec_mca(void) { - register char *cbuf; + char *cbuf; cmd_exec(); cbuf = get_cmdbuf(); switch (mca) { case A_F_SEARCH: case A_B_SEARCH: multi_search(cbuf, (int) number, 0); break; #if HILITE_SEARCH case A_FILTER: search_type ^= SRCH_NO_MATCH; set_filter_pattern(cbuf, search_type); break; #endif case A_FIRSTCMD: /* * Skip leading spaces or + signs in the string. */ while (*cbuf == '+' || *cbuf == ' ') cbuf++; if (every_first_cmd != NULL) free(every_first_cmd); if (*cbuf == '\0') every_first_cmd = NULL; else every_first_cmd = save(cbuf); break; case A_OPT_TOGGLE: toggle_option(curropt, opt_lower, cbuf, optflag); curropt = NULL; break; case A_F_BRACKET: match_brac(cbuf[0], cbuf[1], 1, (int) number); break; case A_B_BRACKET: match_brac(cbuf[1], cbuf[0], 0, (int) number); break; #if EXAMINE case A_EXAMINE: if (secure) break; edit_list(cbuf); #if TAGS /* If tag structure is loaded then clean it up. */ cleantags(); #endif break; #endif #if SHELL_ESCAPE case A_SHELL: /* * !! just uses whatever is in shellcmd. * Otherwise, copy cmdbuf to shellcmd, * expanding any special characters ("%" or "#"). */ if (*cbuf != '!') { if (shellcmd != NULL) free(shellcmd); shellcmd = fexpand(cbuf); } if (secure) break; if (shellcmd == NULL) lsystem("", "!done"); else lsystem(shellcmd, "!done"); break; #endif #if PIPEC case A_PIPE: if (secure) break; (void) pipe_mark(pipec, cbuf); error("|done", NULL_PARG); break; #endif } } /* * Is a character an erase or kill char? */ static int -is_erase_char(c) - int c; +is_erase_char(int c) { return (c == erase_char || c == erase2_char || c == kill_char); } /* * Handle the first char of an option (after the initial dash). */ static int -mca_opt_first_char(c) - int c; +mca_opt_first_char(int c) { int flag = (optflag & ~OPT_NO_PROMPT); if (flag == OPT_NO_TOGGLE) { switch (c) { case '_': /* "__" = long option name. */ optgetname = TRUE; mca_opt_toggle(); return (MCA_MORE); } } else { switch (c) { case '+': /* "-+" = UNSET. */ optflag = (flag == OPT_UNSET) ? OPT_TOGGLE : OPT_UNSET; mca_opt_toggle(); return (MCA_MORE); case '!': /* "-!" = SET */ optflag = (flag == OPT_SET) ? OPT_TOGGLE : OPT_SET; mca_opt_toggle(); return (MCA_MORE); case CONTROL('P'): optflag ^= OPT_NO_PROMPT; mca_opt_toggle(); return (MCA_MORE); case '-': /* "--" = long option name. */ optgetname = TRUE; mca_opt_toggle(); return (MCA_MORE); } } /* Char was not handled here. */ return (NO_MCA); } /* * Add a char to a long option name. * See if we've got a match for an option name yet. * If so, display the complete name and stop * accepting chars until user hits RETURN. */ static int -mca_opt_nonfirst_char(c) - int c; +mca_opt_nonfirst_char(int c) { char *p; char *oname; if (curropt != NULL) { /* * Already have a match for the name. * Don't accept anything but erase/kill. */ if (is_erase_char(c)) return (MCA_DONE); return (MCA_MORE); } /* * Add char to cmd buffer and try to match * the option name. */ if (cmd_char(c) == CC_QUIT) return (MCA_DONE); p = get_cmdbuf(); opt_lower = ASCII_IS_LOWER(p[0]); curropt = findopt_name(&p, &oname, NULL); if (curropt != NULL) { /* * Got a match. * Remember the option and * display the full option name. */ cmd_reset(); mca_opt_toggle(); for (p = oname; *p != '\0'; p++) { c = *p; if (!opt_lower && ASCII_IS_LOWER(c)) c = ASCII_TO_UPPER(c); if (cmd_char(c) != CC_OK) return (MCA_DONE); } } return (MCA_MORE); } /* * Handle a char of an option toggle command. */ static int -mca_opt_char(c) - int c; +mca_opt_char(int c) { PARG parg; /* * This may be a short option (single char), * or one char of a long option name, * or one char of the option parameter. */ if (curropt == NULL && len_cmdbuf() == 0) { int ret = mca_opt_first_char(c); if (ret != NO_MCA) return (ret); } if (optgetname) { /* We're getting a long option name. */ if (c != '\n' && c != '\r') return (mca_opt_nonfirst_char(c)); if (curropt == NULL) { parg.p_string = get_cmdbuf(); error("There is no --%s option", &parg); return (MCA_DONE); } optgetname = FALSE; cmd_reset(); } else { if (is_erase_char(c)) return (NO_MCA); if (curropt != NULL) /* We're getting the option parameter. */ return (NO_MCA); curropt = findopt(c); if (curropt == NULL) { parg.p_string = propt(c); error("There is no %s option", &parg); return (MCA_DONE); } } /* * If the option which was entered does not take a * parameter, toggle the option immediately, * so user doesn't have to hit RETURN. */ if ((optflag & ~OPT_NO_PROMPT) != OPT_TOGGLE || !opt_has_param(curropt)) { toggle_option(curropt, ASCII_IS_LOWER(c), "", optflag); return (MCA_DONE); } /* * Display a prompt appropriate for the option parameter. */ start_mca(A_OPT_TOGGLE, opt_prompt(curropt), (void*)NULL, 0); return (MCA_MORE); } /* * Handle a char of a search command. */ static int -mca_search_char(c) - int c; +mca_search_char(int c) { int flag = 0; /* * Certain characters as the first char of * the pattern have special meaning: * ! Toggle the NO_MATCH flag * * Toggle the PAST_EOF flag * @ Toggle the FIRST_FILE flag */ if (len_cmdbuf() > 0) return (NO_MCA); switch (c) { case '*': if (less_is_more) break; case CONTROL('E'): /* ignore END of file */ if (mca != A_FILTER) flag = SRCH_PAST_EOF; break; case '@': if (less_is_more) break; case CONTROL('F'): /* FIRST file */ if (mca != A_FILTER) flag = SRCH_FIRST_FILE; break; case CONTROL('K'): /* KEEP position */ if (mca != A_FILTER) flag = SRCH_NO_MOVE; break; case CONTROL('R'): /* Don't use REGULAR EXPRESSIONS */ flag = SRCH_NO_REGEX; break; case CONTROL('N'): /* NOT match */ case '!': flag = SRCH_NO_MATCH; break; } if (flag != 0) { search_type ^= flag; mca_search(); return (MCA_MORE); } return (NO_MCA); } /* * Handle a character of a multi-character command. */ static int -mca_char(c) - int c; +mca_char(int c) { int ret; switch (mca) { case 0: /* * We're not in a multicharacter command. */ return (NO_MCA); case A_PREFIX: /* * In the prefix of a command. * This not considered a multichar command * (even tho it uses cmdbuf, etc.). * It is handled in the commands() switch. */ return (NO_MCA); case A_DIGIT: /* * Entering digits of a number. * Terminated by a non-digit. */ if (!((c >= '0' && c <= '9') || c == '.') && editchar(c, EC_PEEK|EC_NOHISTORY|EC_NOCOMPLETE|EC_NORIGHTLEFT) == A_INVALID) { /* * Not part of the number. * End the number and treat this char * as a normal command character. */ number = cmd_int(&fraction); mca = 0; cmd_accept(); return (NO_MCA); } break; case A_OPT_TOGGLE: ret = mca_opt_char(c); if (ret != NO_MCA) return (ret); break; case A_F_SEARCH: case A_B_SEARCH: case A_FILTER: ret = mca_search_char(c); if (ret != NO_MCA) return (ret); break; default: /* Other multicharacter command. */ break; } /* * The multichar command is terminated by a newline. */ if (c == '\n' || c == '\r') { /* * Execute the command. */ exec_mca(); return (MCA_DONE); } /* * Append the char to the command buffer. */ if (cmd_char(c) == CC_QUIT) /* * Abort the multi-char command. */ return (MCA_DONE); if ((mca == A_F_BRACKET || mca == A_B_BRACKET) && len_cmdbuf() >= 2) { /* * Special case for the bracket-matching commands. * Execute the command after getting exactly two * characters from the user. */ exec_mca(); return (MCA_DONE); } /* * Need another character. */ return (MCA_MORE); } /* * Discard any buffered file data. */ static void -clear_buffers() +clear_buffers(void) { if (!(ch_getflags() & CH_CANSEEK)) return; ch_flush(); clr_linenum(); #if HILITE_SEARCH clr_hilite(); #endif } /* * Make sure the screen is displayed. */ static void -make_display() +make_display(void) { /* * If nothing is displayed yet, display starting from initial_scrpos. */ if (empty_screen()) { if (initial_scrpos.pos == NULL_POSITION) /* * {{ Maybe this should be: * jump_loc(ch_zero(), jump_sline); * but this behavior seems rather unexpected * on the first screen. }} */ jump_loc(ch_zero(), 1); else jump_loc(initial_scrpos.pos, initial_scrpos.ln); } else if (screen_trashed) { int save_top_scroll = top_scroll; int save_ignore_eoi = ignore_eoi; top_scroll = 1; ignore_eoi = 0; if (screen_trashed == 2) { /* Special case used by ignore_eoi: re-open the input file * and jump to the end of the file. */ reopen_curr_ifile(); jump_forw(); } repaint(); top_scroll = save_top_scroll; ignore_eoi = save_ignore_eoi; } } /* * Display the appropriate prompt. */ static void -prompt() +prompt(void) { - register constant char *p; + constant char *p; if (ungot != NULL && !ungot->ug_end_command) { /* * No prompt necessary if commands are from * ungotten chars rather than from the user. */ return; } /* * Make sure the screen is displayed. */ make_display(); bottompos = position(BOTTOM_PLUS_ONE); /* * If we've hit EOF on the last file and the -E flag is set, quit. */ if (get_quit_at_eof() == OPT_ONPLUS && eof_displayed() && !(ch_getflags() & CH_HELPFILE) && next_ifile(curr_ifile) == NULL_IFILE) quit(QUIT_OK); /* * If the entire file is displayed and the -F flag is set, quit. */ if (quit_if_one_screen && entire_file_displayed() && !(ch_getflags() & CH_HELPFILE) && next_ifile(curr_ifile) == NULL_IFILE) quit(QUIT_OK); #if MSDOS_COMPILER==WIN32C /* * In Win32, display the file name in the window title. */ if (!(ch_getflags() & CH_HELPFILE)) SetConsoleTitle(pr_expand("Less?f - %f.", 0)); #endif /* * Select the proper prompt and display it. */ /* * If the previous action was a forward movement, * don't clear the bottom line of the display; * just print the prompt since the forward movement guarantees * that we're in the right position to display the prompt. * Clearing the line could cause a problem: for example, if the last * line displayed ended at the right screen edge without a newline, * then clearing would clear the last displayed line rather than * the prompt line. */ if (!forw_prompt) clear_bot(); clear_cmd(); forw_prompt = 0; p = pr_string(); if (is_filtering()) putstr("& "); if (p == NULL || *p == '\0') putchr(':'); else { at_enter(AT_STANDOUT); putstr(p); at_exit(); } clear_eol(); } /* * Display the less version message. */ public void -dispversion() +dispversion(void) { PARG parg; parg.p_string = version; error("less %s", &parg); } /* * Get command character. * The character normally comes from the keyboard, * but may come from ungotten characters * (characters previously given to ungetcc or ungetsc). */ public int -getcc() +getcc(void) { if (ungot == NULL) { /* * Normal case: no ungotten chars, so get one from the user. */ return (getchr()); } /* * Return the next ungotten char. */ { struct ungot *ug = ungot; char c = ug->ug_char; int end_command = ug->ug_end_command; ungot = ug->ug_next; free(ug); if (end_command) { /* * Command is incomplete, so try to complete it. */ switch (mca) { case A_DIGIT: /* * We have a number but no command. Treat as #g. */ return ('g'); case A_F_SEARCH: case A_B_SEARCH: /* * We have "/string" but no newline. Add the \n. */ return ('\n'); default: /* * Some other incomplete command. Let user complete it. */ return (getchr()); } } return (c); } } /* * "Unget" a command character. * The next getcc() will return this character. */ public void -ungetcc(c) - int c; +ungetcc(int c) { struct ungot *ug = (struct ungot *) ecalloc(1, sizeof(struct ungot)); ug->ug_char = (char) c; ug->ug_end_command = (c == CHAR_END_COMMAND); ug->ug_next = ungot; ungot = ug; } /* * Unget a whole string of command characters. * The next sequence of getcc()'s will return this string. */ public void -ungetsc(s) - char *s; +ungetsc(char *s) { - register char *p; + char *p; for (p = s + strlen(s) - 1; p >= s; p--) ungetcc(*p); } /* * Search for a pattern, possibly in multiple files. * If SRCH_FIRST_FILE is set, begin searching at the first file. * If SRCH_PAST_EOF is set, continue the search thru multiple files. */ static void -multi_search(pattern, n, silent) - char *pattern; - int n; - int silent; +multi_search(char *pattern, int n, int silent) { - register int nomore; + int nomore; IFILE save_ifile; int changed_file; changed_file = 0; save_ifile = save_curr_ifile(); if (search_type & SRCH_FIRST_FILE) { /* * Start at the first (or last) file * in the command line list. */ if (search_type & SRCH_FORW) nomore = edit_first(); else nomore = edit_last(); if (nomore) { unsave_ifile(save_ifile); return; } changed_file = 1; search_type &= ~SRCH_FIRST_FILE; } for (;;) { n = search(search_type, pattern, n); /* * The SRCH_NO_MOVE flag doesn't "stick": it gets cleared * after being used once. This allows "n" to work after * using a /@@ search. */ search_type &= ~SRCH_NO_MOVE; if (n == 0) { /* * Found it. */ unsave_ifile(save_ifile); return; } if (n < 0) /* * Some kind of error in the search. * Error message has been printed by search(). */ break; if ((search_type & SRCH_PAST_EOF) == 0) /* * We didn't find a match, but we're * supposed to search only one file. */ break; /* * Move on to the next file. */ if (search_type & SRCH_FORW) nomore = edit_next(1); else nomore = edit_prev(1); if (nomore) break; changed_file = 1; } /* * Didn't find it. * Print an error message if we haven't already. */ if (n > 0 && !silent) error("Pattern not found", NULL_PARG); if (changed_file) { /* * Restore the file we were originally viewing. */ reedit_ifile(save_ifile); } else { unsave_ifile(save_ifile); } } /* * Forward forever, or until a highlighted line appears. */ static int -forw_loop(until_hilite) - int until_hilite; +forw_loop(int until_hilite) { POSITION curr_len; if (ch_getflags() & CH_HELPFILE) return (A_NOACTION); cmd_exec(); jump_forw_buffered(); curr_len = ch_length(); highest_hilite = until_hilite ? curr_len : NULL_POSITION; ignore_eoi = 1; while (!sigs) { if (until_hilite && highest_hilite > curr_len) { bell(); break; } make_display(); forward(1, 0, 0); } ignore_eoi = 0; ch_set_eof(); /* * This gets us back in "F mode" after processing * a non-abort signal (e.g. window-change). */ if (sigs && !ABORT_SIGS()) return (until_hilite ? A_F_UNTIL_HILITE : A_F_FOREVER); return (A_NOACTION); } /* * Main command processor. * Accept and execute commands until a quit command. */ public void -commands() +commands(void) { - register int c; - register int action; - register char *cbuf; + int c; + int action; + char *cbuf; int newaction; int save_search_type; char *extra; char tbuf[2]; PARG parg; IFILE old_ifile; IFILE new_ifile; char *tagfile; search_type = SRCH_FORW; wscroll = (sc_height + 1) / 2; newaction = A_NOACTION; for (;;) { mca = 0; cmd_accept(); number = 0; curropt = NULL; /* * See if any signals need processing. */ if (sigs) { psignals(); if (quitting) quit(QUIT_SAVED_STATUS); } /* * See if window size changed, for systems that don't * generate SIGWINCH. */ check_winch(); /* * Display prompt and accept a character. */ cmd_reset(); prompt(); if (sigs) continue; if (newaction == A_NOACTION) c = getcc(); again: if (sigs) continue; if (newaction != A_NOACTION) { action = newaction; newaction = A_NOACTION; } else { /* * If we are in a multicharacter command, call mca_char. * Otherwise we call fcmd_decode to determine the * action to be performed. */ if (mca) switch (mca_char(c)) { case MCA_MORE: /* * Need another character. */ c = getcc(); goto again; case MCA_DONE: /* * Command has been handled by mca_char. * Start clean with a prompt. */ continue; case NO_MCA: /* * Not a multi-char command * (at least, not anymore). */ break; } /* * Decode the command character and decide what to do. */ if (mca) { /* * We're in a multichar command. * Add the character to the command buffer * and display it on the screen. * If the user backspaces past the start * of the line, abort the command. */ if (cmd_char(c) == CC_QUIT || len_cmdbuf() == 0) continue; cbuf = get_cmdbuf(); } else { /* * Don't use cmd_char if we're starting fresh * at the beginning of a command, because we * don't want to echo the command until we know * it is a multichar command. We also don't * want erase_char/kill_char to be treated * as line editing characters. */ tbuf[0] = c; tbuf[1] = '\0'; cbuf = tbuf; } extra = NULL; action = fcmd_decode(cbuf, &extra); /* * If an "extra" string was returned, * process it as a string of command characters. */ if (extra != NULL) ungetsc(extra); } /* * Clear the cmdbuf string. * (But not if we're in the prefix of a command, * because the partial command string is kept there.) */ if (action != A_PREFIX) cmd_reset(); switch (action) { case A_DIGIT: /* * First digit of a number. */ start_mca(A_DIGIT, ":", (void*)NULL, CF_QUIT_ON_ERASE); goto again; case A_F_WINDOW: /* * Forward one window (and set the window size). */ if (number > 0) swindow = (int) number; /* FALLTHRU */ case A_F_SCREEN: /* * Forward one screen. */ if (number <= 0) number = get_swindow(); cmd_exec(); if (show_attn) set_attnpos(bottompos); forward((int) number, 0, 1); break; case A_B_WINDOW: /* * Backward one window (and set the window size). */ if (number > 0) swindow = (int) number; /* FALLTHRU */ case A_B_SCREEN: /* * Backward one screen. */ if (number <= 0) number = get_swindow(); cmd_exec(); backward((int) number, 0, 1); break; case A_F_LINE: /* * Forward N (default 1) line. */ if (number <= 0) number = 1; cmd_exec(); if (show_attn == OPT_ONPLUS && number > 1) set_attnpos(bottompos); forward((int) number, 0, 0); break; case A_B_LINE: /* * Backward N (default 1) line. */ if (number <= 0) number = 1; cmd_exec(); backward((int) number, 0, 0); break; case A_FF_LINE: /* * Force forward N (default 1) line. */ if (number <= 0) number = 1; cmd_exec(); if (show_attn == OPT_ONPLUS && number > 1) set_attnpos(bottompos); forward((int) number, 1, 0); break; case A_BF_LINE: /* * Force backward N (default 1) line. */ if (number <= 0) number = 1; cmd_exec(); backward((int) number, 1, 0); break; case A_FF_SCREEN: /* * Force forward one screen. */ if (number <= 0) number = get_swindow(); cmd_exec(); if (show_attn == OPT_ONPLUS) set_attnpos(bottompos); forward((int) number, 1, 0); break; case A_F_FOREVER: /* * Forward forever, ignoring EOF. */ if (show_attn) set_attnpos(bottompos); newaction = forw_loop(0); break; case A_F_UNTIL_HILITE: newaction = forw_loop(1); break; case A_F_SCROLL: /* * Forward N lines * (default same as last 'd' or 'u' command). */ if (number > 0) wscroll = (int) number; cmd_exec(); if (show_attn == OPT_ONPLUS) set_attnpos(bottompos); forward(wscroll, 0, 0); break; case A_B_SCROLL: /* * Forward N lines * (default same as last 'd' or 'u' command). */ if (number > 0) wscroll = (int) number; cmd_exec(); backward(wscroll, 0, 0); break; case A_FREPAINT: /* * Flush buffers, then repaint screen. * Don't flush the buffers on a pipe! */ clear_buffers(); /* FALLTHRU */ case A_REPAINT: /* * Repaint screen. */ cmd_exec(); repaint(); break; case A_GOLINE: /* * Go to line N, default beginning of file. */ if (number <= 0) number = 1; cmd_exec(); jump_back(number); break; case A_PERCENT: /* * Go to a specified percentage into the file. */ if (number < 0) { number = 0; fraction = 0; } if (number > 100) { number = 100; fraction = 0; } cmd_exec(); jump_percent((int) number, fraction); break; case A_GOEND: /* * Go to line N, default end of file. */ cmd_exec(); if (number <= 0) jump_forw(); else jump_back(number); break; case A_GOEND_BUF: /* * Go to line N, default last buffered byte. */ cmd_exec(); if (number <= 0) jump_forw_buffered(); else jump_back(number); break; case A_GOPOS: /* * Go to a specified byte position in the file. */ cmd_exec(); if (number < 0) number = 0; jump_line_loc((POSITION) number, jump_sline); break; case A_STAT: /* * Print file name, etc. */ if (ch_getflags() & CH_HELPFILE) break; cmd_exec(); parg.p_string = eq_message(); error("%s", &parg); break; case A_VERSION: /* * Print version number, without the "@(#)". */ cmd_exec(); dispversion(); break; case A_QUIT: /* * Exit. */ if (curr_ifile != NULL_IFILE && ch_getflags() & CH_HELPFILE) { /* * Quit while viewing the help file * just means return to viewing the * previous file. */ hshift = save_hshift; bs_mode = save_bs_mode; if (edit_prev(1) == 0) break; } if (extra != NULL) quit(*extra); quit(QUIT_OK); break; /* * Define abbreviation for a commonly used sequence below. */ #define DO_SEARCH() \ if (number <= 0) number = 1; \ mca_search(); \ cmd_exec(); \ multi_search((char *)NULL, (int) number, 0); case A_F_SEARCH: /* * Search forward for a pattern. * Get the first char of the pattern. */ search_type = SRCH_FORW; if (number <= 0) number = 1; mca_search(); c = getcc(); goto again; case A_B_SEARCH: /* * Search backward for a pattern. * Get the first char of the pattern. */ search_type = SRCH_BACK; if (number <= 0) number = 1; mca_search(); c = getcc(); goto again; case A_FILTER: #if HILITE_SEARCH search_type = SRCH_FORW | SRCH_FILTER; mca_search(); c = getcc(); goto again; #else error("Command not available", NULL_PARG); break; #endif case A_AGAIN_SEARCH: /* * Repeat previous search. */ DO_SEARCH(); break; case A_T_AGAIN_SEARCH: /* * Repeat previous search, multiple files. */ search_type |= SRCH_PAST_EOF; DO_SEARCH(); break; case A_REVERSE_SEARCH: /* * Repeat previous search, in reverse direction. */ save_search_type = search_type; search_type = SRCH_REVERSE(search_type); DO_SEARCH(); search_type = save_search_type; break; case A_T_REVERSE_SEARCH: /* * Repeat previous search, * multiple files in reverse direction. */ save_search_type = search_type; search_type = SRCH_REVERSE(search_type); search_type |= SRCH_PAST_EOF; DO_SEARCH(); search_type = save_search_type; break; case A_UNDO_SEARCH: undo_search(); break; case A_HELP: /* * Help. */ if (ch_getflags() & CH_HELPFILE) break; cmd_exec(); save_hshift = hshift; hshift = 0; save_bs_mode = bs_mode; bs_mode = BS_SPECIAL; (void) edit(FAKE_HELPFILE); break; case A_EXAMINE: #if EXAMINE /* * Edit a new file. Get the filename. */ if (secure) { error("Command not available", NULL_PARG); break; } start_mca(A_EXAMINE, "Examine: ", ml_examine, 0); c = getcc(); goto again; #else error("Command not available", NULL_PARG); break; #endif case A_VISUAL: /* * Invoke an editor on the input file. */ #if EDITOR if (secure) { error("Command not available", NULL_PARG); break; } if (ch_getflags() & CH_HELPFILE) break; if (strcmp(get_filename(curr_ifile), "-") == 0) { error("Cannot edit standard input", NULL_PARG); break; } if (curr_altfilename != NULL) { error("WARNING: This file was viewed via LESSOPEN", NULL_PARG); } start_mca(A_SHELL, "!", ml_shell, 0); /* * Expand the editor prototype string * and pass it to the system to execute. * (Make sure the screen is displayed so the * expansion of "+%lm" works.) */ make_display(); cmd_exec(); lsystem(pr_expand(editproto, 0), (char*)NULL); break; #else error("Command not available", NULL_PARG); break; #endif case A_NEXT_FILE: /* * Examine next file. */ #if TAGS if (ntags()) { error("No next file", NULL_PARG); break; } #endif if (number <= 0) number = 1; if (edit_next((int) number)) { if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE)) quit(QUIT_OK); parg.p_string = (number > 1) ? "(N-th) " : ""; error("No %snext file", &parg); } break; case A_PREV_FILE: /* * Examine previous file. */ #if TAGS if (ntags()) { error("No previous file", NULL_PARG); break; } #endif if (number <= 0) number = 1; if (edit_prev((int) number)) { parg.p_string = (number > 1) ? "(N-th) " : ""; error("No %sprevious file", &parg); } break; case A_NEXT_TAG: #if TAGS if (number <= 0) number = 1; tagfile = nexttag((int) number); if (tagfile == NULL) { error("No next tag", NULL_PARG); break; } if (edit(tagfile) == 0) { POSITION pos = tagsearch(); if (pos != NULL_POSITION) jump_loc(pos, jump_sline); } #else error("Command not available", NULL_PARG); #endif break; case A_PREV_TAG: #if TAGS if (number <= 0) number = 1; tagfile = prevtag((int) number); if (tagfile == NULL) { error("No previous tag", NULL_PARG); break; } if (edit(tagfile) == 0) { POSITION pos = tagsearch(); if (pos != NULL_POSITION) jump_loc(pos, jump_sline); } #else error("Command not available", NULL_PARG); #endif break; case A_INDEX_FILE: /* * Examine a particular file. */ if (number <= 0) number = 1; if (edit_index((int) number)) error("No such file", NULL_PARG); break; case A_REMOVE_FILE: if (ch_getflags() & CH_HELPFILE) break; old_ifile = curr_ifile; new_ifile = getoff_ifile(curr_ifile); if (new_ifile == NULL_IFILE) { bell(); break; } if (edit_ifile(new_ifile) != 0) { reedit_ifile(old_ifile); break; } del_ifile(old_ifile); break; case A_OPT_TOGGLE: optflag = OPT_TOGGLE; optgetname = FALSE; mca_opt_toggle(); c = getcc(); goto again; case A_DISP_OPTION: /* * Report a flag setting. */ optflag = OPT_NO_TOGGLE; optgetname = FALSE; mca_opt_toggle(); c = getcc(); goto again; case A_FIRSTCMD: /* * Set an initial command for new files. */ start_mca(A_FIRSTCMD, "+", (void*)NULL, 0); c = getcc(); goto again; case A_SHELL: /* * Shell escape. */ #if SHELL_ESCAPE if (secure) { error("Command not available", NULL_PARG); break; } start_mca(A_SHELL, "!", ml_shell, 0); c = getcc(); goto again; #else error("Command not available", NULL_PARG); break; #endif case A_SETMARK: /* * Set a mark. */ if (ch_getflags() & CH_HELPFILE) break; start_mca(A_SETMARK, "mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == erase2_char || c == kill_char || c == '\n' || c == '\r') break; setmark(c); break; case A_GOMARK: /* * Go to a mark. */ start_mca(A_GOMARK, "goto mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == erase2_char || c == kill_char || c == '\n' || c == '\r') break; cmd_exec(); gomark(c); break; case A_PIPE: #if PIPEC if (secure) { error("Command not available", NULL_PARG); break; } start_mca(A_PIPE, "|mark: ", (void*)NULL, 0); c = getcc(); if (c == erase_char || c == erase2_char || c == kill_char) break; if (c == '\n' || c == '\r') c = '.'; if (badmark(c)) break; pipec = c; start_mca(A_PIPE, "!", ml_shell, 0); c = getcc(); goto again; #else error("Command not available", NULL_PARG); break; #endif case A_B_BRACKET: case A_F_BRACKET: start_mca(action, "Brackets: ", (void*)NULL, 0); c = getcc(); goto again; case A_LSHIFT: if (number > 0) shift_count = number; else number = (shift_count > 0) ? shift_count : sc_width / 2; if (number > hshift) number = hshift; hshift -= number; screen_trashed = 1; break; case A_RSHIFT: if (number > 0) shift_count = number; else number = (shift_count > 0) ? shift_count : sc_width / 2; hshift += number; screen_trashed = 1; break; case A_PREFIX: /* * The command is incomplete (more chars are needed). * Display the current char, so the user knows * what's going on, and get another character. */ if (mca != A_PREFIX) { cmd_reset(); start_mca(A_PREFIX, " ", (void*)NULL, CF_QUIT_ON_ERASE); (void) cmd_char(c); } c = getcc(); goto again; case A_NOACTION: break; default: bell(); break; } } } Index: head/contrib/less/cvt.c =================================================================== --- head/contrib/less/cvt.c (revision 316338) +++ head/contrib/less/cvt.c (revision 316339) @@ -1,114 +1,106 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines to convert text in various ways. Used by search. */ #include "less.h" #include "charset.h" extern int utf_mode; /* * Get the length of a buffer needed to convert a string. */ public int -cvt_length(len, ops) - int len; - int ops; +cvt_length(int len, int ops) { if (utf_mode) /* * Just copying a string in UTF-8 mode can cause it to grow * in length. * Four output bytes for one input byte is the worst case. */ len *= 4; return (len + 1); } /* * Allocate a chpos array for use by cvt_text. */ public int * -cvt_alloc_chpos(len) - int len; +cvt_alloc_chpos(int len) { int i; int *chpos = (int *) ecalloc(sizeof(int), len); /* Initialize all entries to an invalid position. */ for (i = 0; i < len; i++) chpos[i] = -1; return (chpos); } /* * Convert text. Perform the transformations specified by ops. * Returns converted text in odst. The original offset of each * odst character (when it was in osrc) is returned in the chpos array. */ public void -cvt_text(odst, osrc, chpos, lenp, ops) - char *odst; - char *osrc; - int *chpos; - int *lenp; - int ops; +cvt_text(char *odst, char *osrc, int *chpos, int *lenp, int ops) { char *dst; char *edst = odst; char *src; - register char *src_end; + char *src_end; LWCHAR ch; if (lenp != NULL) src_end = osrc + *lenp; else src_end = osrc + strlen(osrc); for (src = osrc, dst = odst; src < src_end; ) { int src_pos = (int) (src - osrc); int dst_pos = (int) (dst - odst); - ch = step_char(&src, +1, src_end); + ch = step_char((constant char **)&src, +1, src_end); if ((ops & CVT_BS) && ch == '\b' && dst > odst) { /* Delete backspace and preceding char. */ do { dst--; } while (dst > odst && !IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst)); } else if ((ops & CVT_ANSI) && IS_CSI_START(ch)) { /* Skip to end of ANSI escape sequence. */ src++; /* skip the CSI start char */ while (src < src_end) if (!is_ansi_middle(*src++)) break; } else { /* Just copy the char to the destination buffer. */ if ((ops & CVT_TO_LC) && IS_UPPER(ch)) ch = TO_LOWER(ch); put_wchar(&dst, ch); /* Record the original position of the char. */ if (chpos != NULL) chpos[dst_pos] = src_pos; } if (dst > edst) edst = dst; } if ((ops & CVT_CRLF) && edst > odst && edst[-1] == '\r') edst--; *edst = '\0'; if (lenp != NULL) *lenp = (int) (edst - odst); /* FIXME: why was this here? if (chpos != NULL) chpos[dst - odst] = src - osrc; */ } Index: head/contrib/less/decode.c =================================================================== --- head/contrib/less/decode.c (revision 316338) +++ head/contrib/less/decode.c (revision 316339) @@ -1,842 +1,805 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines to decode user commands. * * This is all table driven. * A command table is a sequence of command descriptors. * Each command descriptor is a sequence of bytes with the following format: * ...<0> * The characters c1,c2,...,cN are the command string; that is, * the characters which the user must type. * It is terminated by a null <0> byte. * The byte after the null byte is the action code associated * with the command string. * If an action byte is OR-ed with A_EXTRA, this indicates * that the option byte is followed by an extra string. * * There may be many command tables. * The first (default) table is built-in. * Other tables are read in from "lesskey" files. * All the tables are linked together and are searched in order. */ #include "less.h" #include "cmd.h" #include "lesskey.h" extern int erase_char, erase2_char, kill_char; extern int secure; #define SK(k) \ SK_SPECIAL_KEY, (k), 6, 1, 1, 1 /* * Command table is ordered roughly according to expected * frequency of use, so the common commands are near the beginning. */ static unsigned char cmdtable[] = { '\r',0, A_F_LINE, '\n',0, A_F_LINE, 'e',0, A_F_LINE, 'j',0, A_F_LINE, SK(SK_DOWN_ARROW),0, A_F_LINE, CONTROL('E'),0, A_F_LINE, CONTROL('N'),0, A_F_LINE, 'k',0, A_B_LINE, 'y',0, A_B_LINE, CONTROL('Y'),0, A_B_LINE, SK(SK_CONTROL_K),0, A_B_LINE, CONTROL('P'),0, A_B_LINE, SK(SK_UP_ARROW),0, A_B_LINE, 'J',0, A_FF_LINE, 'K',0, A_BF_LINE, 'Y',0, A_BF_LINE, 'd',0, A_F_SCROLL, CONTROL('D'),0, A_F_SCROLL, 'u',0, A_B_SCROLL, CONTROL('U'),0, A_B_SCROLL, ' ',0, A_F_SCREEN, 'f',0, A_F_SCREEN, CONTROL('F'),0, A_F_SCREEN, CONTROL('V'),0, A_F_SCREEN, SK(SK_PAGE_DOWN),0, A_F_SCREEN, 'b',0, A_B_SCREEN, CONTROL('B'),0, A_B_SCREEN, ESC,'v',0, A_B_SCREEN, SK(SK_PAGE_UP),0, A_B_SCREEN, 'z',0, A_F_WINDOW, 'w',0, A_B_WINDOW, ESC,' ',0, A_FF_SCREEN, 'F',0, A_F_FOREVER, ESC,'F',0, A_F_UNTIL_HILITE, 'R',0, A_FREPAINT, 'r',0, A_REPAINT, CONTROL('R'),0, A_REPAINT, CONTROL('L'),0, A_REPAINT, ESC,'u',0, A_UNDO_SEARCH, 'g',0, A_GOLINE, SK(SK_HOME),0, A_GOLINE, '<',0, A_GOLINE, ESC,'<',0, A_GOLINE, 'p',0, A_PERCENT, '%',0, A_PERCENT, ESC,'[',0, A_LSHIFT, ESC,']',0, A_RSHIFT, ESC,'(',0, A_LSHIFT, ESC,')',0, A_RSHIFT, SK(SK_RIGHT_ARROW),0, A_RSHIFT, SK(SK_LEFT_ARROW),0, A_LSHIFT, '{',0, A_F_BRACKET|A_EXTRA, '{','}',0, '}',0, A_B_BRACKET|A_EXTRA, '{','}',0, '(',0, A_F_BRACKET|A_EXTRA, '(',')',0, ')',0, A_B_BRACKET|A_EXTRA, '(',')',0, '[',0, A_F_BRACKET|A_EXTRA, '[',']',0, ']',0, A_B_BRACKET|A_EXTRA, '[',']',0, ESC,CONTROL('F'),0, A_F_BRACKET, ESC,CONTROL('B'),0, A_B_BRACKET, 'G',0, A_GOEND, ESC,'G',0, A_GOEND_BUF, ESC,'>',0, A_GOEND, '>',0, A_GOEND, SK(SK_END),0, A_GOEND, 'P',0, A_GOPOS, '0',0, A_DIGIT, '1',0, A_DIGIT, '2',0, A_DIGIT, '3',0, A_DIGIT, '4',0, A_DIGIT, '5',0, A_DIGIT, '6',0, A_DIGIT, '7',0, A_DIGIT, '8',0, A_DIGIT, '9',0, A_DIGIT, '.',0, A_DIGIT, '=',0, A_STAT, CONTROL('G'),0, A_STAT, ':','f',0, A_STAT, '/',0, A_F_SEARCH, '?',0, A_B_SEARCH, ESC,'/',0, A_F_SEARCH|A_EXTRA, '*',0, ESC,'?',0, A_B_SEARCH|A_EXTRA, '*',0, 'n',0, A_AGAIN_SEARCH, ESC,'n',0, A_T_AGAIN_SEARCH, 'N',0, A_REVERSE_SEARCH, ESC,'N',0, A_T_REVERSE_SEARCH, '&',0, A_FILTER, 'm',0, A_SETMARK, '\'',0, A_GOMARK, CONTROL('X'),CONTROL('X'),0, A_GOMARK, 'E',0, A_EXAMINE, ':','e',0, A_EXAMINE, CONTROL('X'),CONTROL('V'),0, A_EXAMINE, ':','n',0, A_NEXT_FILE, ':','p',0, A_PREV_FILE, 't',0, A_NEXT_TAG, 'T',0, A_PREV_TAG, ':','x',0, A_INDEX_FILE, ':','d',0, A_REMOVE_FILE, '-',0, A_OPT_TOGGLE, ':','t',0, A_OPT_TOGGLE|A_EXTRA, 't',0, 's',0, A_OPT_TOGGLE|A_EXTRA, 'o',0, '_',0, A_DISP_OPTION, '|',0, A_PIPE, 'v',0, A_VISUAL, '!',0, A_SHELL, '+',0, A_FIRSTCMD, 'H',0, A_HELP, 'h',0, A_HELP, SK(SK_F1),0, A_HELP, 'V',0, A_VERSION, 'q',0, A_QUIT, 'Q',0, A_QUIT, ':','q',0, A_QUIT, ':','Q',0, A_QUIT, 'Z','Z',0, A_QUIT }; static unsigned char edittable[] = { '\t',0, EC_F_COMPLETE, /* TAB */ '\17',0, EC_B_COMPLETE, /* BACKTAB */ SK(SK_BACKTAB),0, EC_B_COMPLETE, /* BACKTAB */ ESC,'\t',0, EC_B_COMPLETE, /* ESC TAB */ CONTROL('L'),0, EC_EXPAND, /* CTRL-L */ CONTROL('V'),0, EC_LITERAL, /* BACKSLASH */ CONTROL('A'),0, EC_LITERAL, /* BACKSLASH */ ESC,'l',0, EC_RIGHT, /* ESC l */ SK(SK_RIGHT_ARROW),0, EC_RIGHT, /* RIGHTARROW */ ESC,'h',0, EC_LEFT, /* ESC h */ SK(SK_LEFT_ARROW),0, EC_LEFT, /* LEFTARROW */ ESC,'b',0, EC_W_LEFT, /* ESC b */ ESC,SK(SK_LEFT_ARROW),0, EC_W_LEFT, /* ESC LEFTARROW */ SK(SK_CTL_LEFT_ARROW),0, EC_W_LEFT, /* CTRL-LEFTARROW */ ESC,'w',0, EC_W_RIGHT, /* ESC w */ ESC,SK(SK_RIGHT_ARROW),0, EC_W_RIGHT, /* ESC RIGHTARROW */ SK(SK_CTL_RIGHT_ARROW),0, EC_W_RIGHT, /* CTRL-RIGHTARROW */ ESC,'i',0, EC_INSERT, /* ESC i */ SK(SK_INSERT),0, EC_INSERT, /* INSERT */ ESC,'x',0, EC_DELETE, /* ESC x */ SK(SK_DELETE),0, EC_DELETE, /* DELETE */ ESC,'X',0, EC_W_DELETE, /* ESC X */ ESC,SK(SK_DELETE),0, EC_W_DELETE, /* ESC DELETE */ SK(SK_CTL_DELETE),0, EC_W_DELETE, /* CTRL-DELETE */ SK(SK_CTL_BACKSPACE),0, EC_W_BACKSPACE, /* CTRL-BACKSPACE */ ESC,'\b',0, EC_W_BACKSPACE, /* ESC BACKSPACE */ ESC,'0',0, EC_HOME, /* ESC 0 */ SK(SK_HOME),0, EC_HOME, /* HOME */ ESC,'$',0, EC_END, /* ESC $ */ SK(SK_END),0, EC_END, /* END */ ESC,'k',0, EC_UP, /* ESC k */ SK(SK_UP_ARROW),0, EC_UP, /* UPARROW */ ESC,'j',0, EC_DOWN, /* ESC j */ SK(SK_DOWN_ARROW),0, EC_DOWN, /* DOWNARROW */ CONTROL('G'),0, EC_ABORT, /* CTRL-G */ }; /* * Structure to support a list of command tables. */ struct tablelist { struct tablelist *t_next; char *t_start; char *t_end; }; /* * List of command tables and list of line-edit tables. */ static struct tablelist *list_fcmd_tables = NULL; static struct tablelist *list_ecmd_tables = NULL; static struct tablelist *list_var_tables = NULL; static struct tablelist *list_sysvar_tables = NULL; /* * Expand special key abbreviations in a command table. */ static void -expand_special_keys(table, len) - char *table; - int len; +expand_special_keys(char *table, int len) { - register char *fm; - register char *to; - register int a; + char *fm; + char *to; + int a; char *repl; int klen; for (fm = table; fm < table + len; ) { /* * Rewrite each command in the table with any * special key abbreviations expanded. */ for (to = fm; *fm != '\0'; ) { if (*fm != SK_SPECIAL_KEY) { *to++ = *fm++; continue; } /* * After SK_SPECIAL_KEY, next byte is the type * of special key (one of the SK_* contants), * and the byte after that is the number of bytes, * N, reserved by the abbreviation (including the * SK_SPECIAL_KEY and key type bytes). * Replace all N bytes with the actual bytes * output by the special key on this terminal. */ repl = special_key_str(fm[1]); klen = fm[2] & 0377; fm += klen; if (repl == NULL || (int) strlen(repl) > klen) repl = "\377"; while (*repl != '\0') *to++ = *repl++; } *to++ = '\0'; /* * Fill any unused bytes between end of command and * the action byte with A_SKIP. */ while (to <= fm) *to++ = A_SKIP; fm++; a = *fm++ & 0377; if (a & A_EXTRA) { while (*fm++ != '\0') continue; } } } /* * Initialize the command lists. */ public void -init_cmds() +init_cmds(void) { /* * Add the default command tables. */ add_fcmd_table((char*)cmdtable, sizeof(cmdtable)); add_ecmd_table((char*)edittable, sizeof(edittable)); #if USERFILE /* * For backwards compatibility, * try to add tables in the OLD system lesskey file. */ #ifdef BINDIR add_hometable(NULL, BINDIR "/.sysless", 1); #endif /* * Try to add the tables in the system lesskey file. */ add_hometable("LESSKEY_SYSTEM", LESSKEYFILE_SYS, 1); /* * Try to add the tables in the standard lesskey file "$HOME/.less". */ add_hometable("LESSKEY", LESSKEYFILE, 0); #endif } /* * Add a command table. */ static int -add_cmd_table(tlist, buf, len) - struct tablelist **tlist; - char *buf; - int len; +add_cmd_table(struct tablelist **tlist, char *buf, int len) { - register struct tablelist *t; + struct tablelist *t; if (len == 0) return (0); /* * Allocate a tablelist structure, initialize it, * and link it into the list of tables. */ if ((t = (struct tablelist *) calloc(1, sizeof(struct tablelist))) == NULL) { return (-1); } expand_special_keys(buf, len); t->t_start = buf; t->t_end = buf + len; t->t_next = *tlist; *tlist = t; return (0); } /* * Add a command table. */ public void -add_fcmd_table(buf, len) - char *buf; - int len; +add_fcmd_table(char *buf, int len) { if (add_cmd_table(&list_fcmd_tables, buf, len) < 0) error("Warning: some commands disabled", NULL_PARG); } /* * Add an editing command table. */ public void -add_ecmd_table(buf, len) - char *buf; - int len; +add_ecmd_table(char *buf, int len) { if (add_cmd_table(&list_ecmd_tables, buf, len) < 0) error("Warning: some edit commands disabled", NULL_PARG); } /* * Add an environment variable table. */ static void -add_var_table(tlist, buf, len) - struct tablelist **tlist; - char *buf; - int len; +add_var_table(struct tablelist **tlist, char *buf, int len) { if (add_cmd_table(tlist, buf, len) < 0) error("Warning: environment variables from lesskey file unavailable", NULL_PARG); } /* * Search a single command table for the command string in cmd. */ static int -cmd_search(cmd, table, endtable, sp) - char *cmd; - char *table; - char *endtable; - char **sp; +cmd_search(char *cmd, char *table, char *endtable, char **sp) { - register char *p; - register char *q; - register int a; + char *p; + char *q; + int a; *sp = NULL; for (p = table, q = cmd; p < endtable; p++, q++) { if (*p == *q) { /* * Current characters match. * If we're at the end of the string, we've found it. * Return the action code, which is the character * after the null at the end of the string * in the command table. */ if (*p == '\0') { a = *++p & 0377; while (a == A_SKIP) a = *++p & 0377; if (a == A_END_LIST) { /* * We get here only if the original * cmd string passed in was empty (""). * I don't think that can happen, * but just in case ... */ return (A_UINVALID); } /* * Check for an "extra" string. */ if (a & A_EXTRA) { *sp = ++p; a &= ~A_EXTRA; } return (a); } } else if (*q == '\0') { /* * Hit the end of the user's command, * but not the end of the string in the command table. * The user's command is incomplete. */ return (A_PREFIX); } else { /* * Not a match. * Skip ahead to the next command in the * command table, and reset the pointer * to the beginning of the user's command. */ if (*p == '\0' && p[1] == A_END_LIST) { /* * A_END_LIST is a special marker that tells * us to abort the cmd search. */ return (A_UINVALID); } while (*p++ != '\0') continue; while (*p == A_SKIP) p++; if (*p & A_EXTRA) while (*++p != '\0') continue; q = cmd-1; } } /* * No match found in the entire command table. */ return (A_INVALID); } /* * Decode a command character and return the associated action. * The "extra" string, if any, is returned in sp. */ static int -cmd_decode(tlist, cmd, sp) - struct tablelist *tlist; - char *cmd; - char **sp; +cmd_decode(struct tablelist *tlist, char *cmd, char **sp) { - register struct tablelist *t; - register int action = A_INVALID; + struct tablelist *t; + int action = A_INVALID; /* * Search thru all the command tables. * Stop when we find an action which is not A_INVALID. */ for (t = tlist; t != NULL; t = t->t_next) { action = cmd_search(cmd, t->t_start, t->t_end, sp); if (action != A_INVALID) break; } if (action == A_UINVALID) action = A_INVALID; return (action); } /* * Decode a command from the cmdtables list. */ public int -fcmd_decode(cmd, sp) - char *cmd; - char **sp; +fcmd_decode(char *cmd, char **sp) { return (cmd_decode(list_fcmd_tables, cmd, sp)); } /* * Decode a command from the edittables list. */ public int -ecmd_decode(cmd, sp) - char *cmd; - char **sp; +ecmd_decode(char *cmd, char **sp) { return (cmd_decode(list_ecmd_tables, cmd, sp)); } /* * Get the value of an environment variable. * Looks first in the lesskey file, then in the real environment. */ public char * -lgetenv(var) - char *var; +lgetenv(char *var) { int a; char *s; a = cmd_decode(list_var_tables, var, &s); if (a == EV_OK) return (s); s = getenv(var); if (s != NULL && *s != '\0') return (s); a = cmd_decode(list_sysvar_tables, var, &s); if (a == EV_OK) return (s); return (NULL); } #if USERFILE /* * Get an "integer" from a lesskey file. * Integers are stored in a funny format: * two bytes, low order first, in radix KRADIX. */ static int -gint(sp) - char **sp; +gint(char **sp) { int n; n = *(*sp)++; n += *(*sp)++ * KRADIX; return (n); } /* * Process an old (pre-v241) lesskey file. */ static int -old_lesskey(buf, len) - char *buf; - int len; +old_lesskey(char *buf, int len) { /* * Old-style lesskey file. * The file must end with either * ...,cmd,0,action * or ...,cmd,0,action|A_EXTRA,string,0 * So the last byte or the second to last byte must be zero. */ if (buf[len-1] != '\0' && buf[len-2] != '\0') return (-1); add_fcmd_table(buf, len); return (0); } /* * Process a new (post-v241) lesskey file. */ static int -new_lesskey(buf, len, sysvar) - char *buf; - int len; - int sysvar; +new_lesskey(char *buf, int len, int sysvar) { char *p; - register int c; - register int n; + int c; + int n; /* * New-style lesskey file. * Extract the pieces. */ if (buf[len-3] != C0_END_LESSKEY_MAGIC || buf[len-2] != C1_END_LESSKEY_MAGIC || buf[len-1] != C2_END_LESSKEY_MAGIC) return (-1); p = buf + 4; for (;;) { c = *p++; switch (c) { case CMD_SECTION: n = gint(&p); add_fcmd_table(p, n); p += n; break; case EDIT_SECTION: n = gint(&p); add_ecmd_table(p, n); p += n; break; case VAR_SECTION: n = gint(&p); add_var_table((sysvar) ? &list_sysvar_tables : &list_var_tables, p, n); p += n; break; case END_SECTION: return (0); default: /* * Unrecognized section type. */ return (-1); } } } /* * Set up a user command table, based on a "lesskey" file. */ public int -lesskey(filename, sysvar) - char *filename; - int sysvar; +lesskey(char *filename, int sysvar) { - register char *buf; - register POSITION len; - register long n; - register int f; + char *buf; + POSITION len; + long n; + int f; if (secure) return (1); /* * Try to open the lesskey file. */ filename = shell_unquote(filename); f = open(filename, OPEN_READ); free(filename); if (f < 0) return (1); /* * Read the file into a buffer. * We first figure out the size of the file and allocate space for it. * {{ Minimal error checking is done here. * A garbage .less file will produce strange results. * To avoid a large amount of error checking code here, we * rely on the lesskey program to generate a good .less file. }} */ len = filesize(f); if (len == NULL_POSITION || len < 3) { /* * Bad file (valid file must have at least 3 chars). */ close(f); return (-1); } if ((buf = (char *) calloc((int)len, sizeof(char))) == NULL) { close(f); return (-1); } if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK) { free(buf); close(f); return (-1); } n = read(f, buf, (unsigned int) len); close(f); if (n != len) { free(buf); return (-1); } /* * Figure out if this is an old-style (before version 241) * or new-style lesskey file format. */ if (buf[0] != C0_LESSKEY_MAGIC || buf[1] != C1_LESSKEY_MAGIC || buf[2] != C2_LESSKEY_MAGIC || buf[3] != C3_LESSKEY_MAGIC) return (old_lesskey(buf, (int)len)); return (new_lesskey(buf, (int)len, sysvar)); } /* * Add the standard lesskey file "$HOME/.less" */ public void -add_hometable(envname, def_filename, sysvar) - char *envname; - char *def_filename; - int sysvar; +add_hometable(char *envname, char *def_filename, int sysvar) { char *filename; PARG parg; if (envname != NULL && (filename = lgetenv(envname)) != NULL) filename = save(filename); else if (sysvar) filename = save(def_filename); else filename = homefile(def_filename); if (filename == NULL) return; if (lesskey(filename, sysvar) < 0) { parg.p_string = filename; error("Cannot use lesskey file \"%s\"", &parg); } free(filename); } #endif /* * See if a char is a special line-editing command. */ public int -editchar(c, flags) - int c; - int flags; +editchar(int c, int flags) { int action; int nch; char *s; char usercmd[MAX_CMDLEN+1]; /* * An editing character could actually be a sequence of characters; * for example, an escape sequence sent by pressing the uparrow key. * To match the editing string, we use the command decoder * but give it the edit-commands command table * This table is constructed to match the user's keyboard. */ if (c == erase_char || c == erase2_char) return (EC_BACKSPACE); if (c == kill_char) return (EC_LINEKILL); /* * Collect characters in a buffer. * Start with the one we have, and get more if we need them. */ nch = 0; do { if (nch > 0) c = getcc(); usercmd[nch] = c; usercmd[nch+1] = '\0'; nch++; action = ecmd_decode(usercmd, &s); } while (action == A_PREFIX); if (flags & EC_NORIGHTLEFT) { switch (action) { case EC_RIGHT: case EC_LEFT: action = A_INVALID; break; } } #if CMD_HISTORY if (flags & EC_NOHISTORY) { /* * The caller says there is no history list. * Reject any history-manipulation action. */ switch (action) { case EC_UP: case EC_DOWN: action = A_INVALID; break; } } #endif #if TAB_COMPLETE_FILENAME if (flags & EC_NOCOMPLETE) { /* * The caller says we don't want any filename completion cmds. * Reject them. */ switch (action) { case EC_F_COMPLETE: case EC_B_COMPLETE: case EC_EXPAND: action = A_INVALID; break; } } #endif if ((flags & EC_PEEK) || action == A_INVALID) { /* * We're just peeking, or we didn't understand the command. * Unget all the characters we read in the loop above. * This does NOT include the original character that was * passed in as a parameter. */ while (nch > 1) { ungetcc(usercmd[--nch]); } } else { if (s != NULL) ungetsc(s); } return action; } Index: head/contrib/less/edit.c =================================================================== --- head/contrib/less/edit.c (revision 316338) +++ head/contrib/less/edit.c (revision 316339) @@ -1,826 +1,804 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ #include "less.h" #if HAVE_STAT #include #endif public int fd0 = 0; extern int new_file; extern int errmsgs; extern int cbufs; extern char *every_first_cmd; extern int any_display; extern int force_open; extern int is_tty; extern int sigs; extern IFILE curr_ifile; extern IFILE old_ifile; extern struct scrpos initial_scrpos; -extern void constant *ml_examine; +extern void * constant ml_examine; #if SPACES_IN_FILENAMES extern char openquote; extern char closequote; #endif #if LOGFILE extern int logfile; extern int force_logfile; extern char *namelogfile; #endif #if HAVE_STAT_INO public dev_t curr_dev; public ino_t curr_ino; #endif char *curr_altfilename = NULL; static void *curr_altpipe; /* * Textlist functions deal with a list of words separated by spaces. * init_textlist sets up a textlist structure. * forw_textlist uses that structure to iterate thru the list of * words, returning each one as a standard null-terminated string. * back_textlist does the same, but runs thru the list backwards. */ public void -init_textlist(tlist, str) - struct textlist *tlist; - char *str; +init_textlist(struct textlist *tlist, char *str) { char *s; #if SPACES_IN_FILENAMES int meta_quoted = 0; int delim_quoted = 0; char *esc = get_meta_escape(); int esclen = (int) strlen(esc); #endif tlist->string = skipsp(str); tlist->endstring = tlist->string + strlen(tlist->string); for (s = str; s < tlist->endstring; s++) { #if SPACES_IN_FILENAMES if (meta_quoted) { meta_quoted = 0; } else if (esclen > 0 && s + esclen < tlist->endstring && strncmp(s, esc, esclen) == 0) { meta_quoted = 1; s += esclen - 1; } else if (delim_quoted) { if (*s == closequote) delim_quoted = 0; } else /* (!delim_quoted) */ { if (*s == openquote) delim_quoted = 1; else if (*s == ' ') *s = '\0'; } #else if (*s == ' ') *s = '\0'; #endif } } public char * -forw_textlist(tlist, prev) - struct textlist *tlist; - char *prev; +forw_textlist(struct textlist *tlist, char *prev) { char *s; /* * prev == NULL means return the first word in the list. * Otherwise, return the word after "prev". */ if (prev == NULL) s = tlist->string; else s = prev + strlen(prev); if (s >= tlist->endstring) return (NULL); while (*s == '\0') s++; if (s >= tlist->endstring) return (NULL); return (s); } public char * -back_textlist(tlist, prev) - struct textlist *tlist; - char *prev; +back_textlist(struct textlist *tlist, char *prev) { char *s; /* * prev == NULL means return the last word in the list. * Otherwise, return the word before "prev". */ if (prev == NULL) s = tlist->endstring; else if (prev <= tlist->string) return (NULL); else s = prev - 1; while (*s == '\0') s--; if (s <= tlist->string) return (NULL); while (s[-1] != '\0' && s > tlist->string) s--; return (s); } /* * Close the current input file. */ static void -close_file() +close_file(void) { struct scrpos scrpos; if (curr_ifile == NULL_IFILE) return; /* * Save the current position so that we can return to * the same position if we edit this file again. */ get_scrpos(&scrpos); if (scrpos.pos != NULL_POSITION) { store_pos(curr_ifile, &scrpos); lastmark(); } /* * Close the file descriptor, unless it is a pipe. */ ch_close(); /* * If we opened a file using an alternate name, * do special stuff to close it. */ if (curr_altfilename != NULL) { close_altfile(curr_altfilename, get_filename(curr_ifile), curr_altpipe); free(curr_altfilename); curr_altfilename = NULL; } curr_ifile = NULL_IFILE; #if HAVE_STAT_INO curr_ino = curr_dev = 0; #endif } /* * Edit a new file (given its name). * Filename == "-" means standard input. * Filename == NULL means just close the current file. */ public int -edit(filename) - char *filename; +edit(char *filename) { if (filename == NULL) return (edit_ifile(NULL_IFILE)); return (edit_ifile(get_ifile(filename, curr_ifile))); } /* * Edit a new file (given its IFILE). * ifile == NULL means just close the current file. */ public int -edit_ifile(ifile) - IFILE ifile; +edit_ifile(IFILE ifile) { int f; int answer; int no_display; int chflags; char *filename; char *open_filename; char *qopen_filename; char *alt_filename; void *alt_pipe; IFILE was_curr_ifile; PARG parg; if (ifile == curr_ifile) { /* * Already have the correct file open. */ return (0); } /* * We must close the currently open file now. * This is necessary to make the open_altfile/close_altfile pairs * nest properly (or rather to avoid nesting at all). * {{ Some stupid implementations of popen() mess up if you do: * fA = popen("A"); fB = popen("B"); pclose(fA); pclose(fB); }} */ #if LOGFILE end_logfile(); #endif was_curr_ifile = save_curr_ifile(); if (curr_ifile != NULL_IFILE) { chflags = ch_getflags(); close_file(); if ((chflags & CH_HELPFILE) && held_ifile(was_curr_ifile) <= 1) { /* * Don't keep the help file in the ifile list. */ del_ifile(was_curr_ifile); was_curr_ifile = old_ifile; } } if (ifile == NULL_IFILE) { /* * No new file to open. * (Don't set old_ifile, because if you call edit_ifile(NULL), * you're supposed to have saved curr_ifile yourself, * and you'll restore it if necessary.) */ unsave_ifile(was_curr_ifile); return (0); } filename = save(get_filename(ifile)); /* * See if LESSOPEN specifies an "alternate" file to open. */ alt_pipe = NULL; alt_filename = open_altfile(filename, &f, &alt_pipe); open_filename = (alt_filename != NULL) ? alt_filename : filename; qopen_filename = shell_unquote(open_filename); chflags = 0; if (alt_pipe != NULL) { /* * The alternate "file" is actually a pipe. * f has already been set to the file descriptor of the pipe * in the call to open_altfile above. * Keep the file descriptor open because it was opened * via popen(), and pclose() wants to close it. */ chflags |= CH_POPENED; } else if (strcmp(open_filename, "-") == 0) { /* * Use standard input. * Keep the file descriptor open because we can't reopen it. */ f = fd0; chflags |= CH_KEEPOPEN; /* * Must switch stdin to BINARY mode. */ SET_BINARY(f); #if MSDOS_COMPILER==DJGPPC /* * Setting stdin to binary by default causes * Ctrl-C to not raise SIGINT. We must undo * that side-effect. */ __djgpp_set_ctrl_c(1); #endif } else if (strcmp(open_filename, FAKE_EMPTYFILE) == 0) { f = -1; chflags |= CH_NODATA; } else if (strcmp(open_filename, FAKE_HELPFILE) == 0) { f = -1; chflags |= CH_HELPFILE; } else if ((parg.p_string = bad_file(open_filename)) != NULL) { /* * It looks like a bad file. Don't try to open it. */ error("%s", &parg); free(parg.p_string); err1: if (alt_filename != NULL) { close_altfile(alt_filename, filename, alt_pipe); free(alt_filename); } del_ifile(ifile); free(qopen_filename); free(filename); /* * Re-open the current file. */ if (was_curr_ifile == ifile) { /* * Whoops. The "current" ifile is the one we just deleted. * Just give up. */ quit(QUIT_ERROR); } reedit_ifile(was_curr_ifile); return (1); } else if ((f = open(qopen_filename, OPEN_READ)) < 0) { /* * Got an error trying to open it. */ parg.p_string = errno_message(filename); error("%s", &parg); free(parg.p_string); goto err1; } else { chflags |= CH_CANSEEK; if (!force_open && !opened(ifile) && bin_file(f)) { /* * Looks like a binary file. * Ask user if we should proceed. */ parg.p_string = filename; answer = query("\"%s\" may be a binary file. See it anyway? ", &parg); if (answer != 'y' && answer != 'Y') { close(f); goto err1; } } } /* * Get the new ifile. * Get the saved position for the file. */ if (was_curr_ifile != NULL_IFILE) { old_ifile = was_curr_ifile; unsave_ifile(was_curr_ifile); } curr_ifile = ifile; curr_altfilename = alt_filename; curr_altpipe = alt_pipe; set_open(curr_ifile); /* File has been opened */ get_pos(curr_ifile, &initial_scrpos); new_file = TRUE; ch_init(f, chflags); if (!(chflags & CH_HELPFILE)) { #if LOGFILE if (namelogfile != NULL && is_tty) use_logfile(namelogfile); #endif #if HAVE_STAT_INO /* Remember the i-number and device of the opened file. */ { struct stat statbuf; int r = stat(qopen_filename, &statbuf); if (r == 0) { curr_ino = statbuf.st_ino; curr_dev = statbuf.st_dev; } } #endif if (every_first_cmd != NULL) { ungetcc(CHAR_END_COMMAND); ungetsc(every_first_cmd); } } free(qopen_filename); no_display = !any_display; flush(); any_display = TRUE; if (is_tty) { /* * Output is to a real tty. */ /* * Indicate there is nothing displayed yet. */ pos_clear(); clr_linenum(); #if HILITE_SEARCH clr_hilite(); #endif if (strcmp(filename, FAKE_HELPFILE) && strcmp(filename, FAKE_EMPTYFILE)) cmd_addhist(ml_examine, filename, 1); if (no_display && errmsgs > 0) { /* * We displayed some messages on error output * (file descriptor 2; see error() function). * Before erasing the screen contents, * display the file name and wait for a keystroke. */ parg.p_string = filename; error("%s", &parg); } } free(filename); return (0); } /* * Edit a space-separated list of files. * For each filename in the list, enter it into the ifile list. * Then edit the first one. */ public int -edit_list(filelist) - char *filelist; +edit_list(char *filelist) { IFILE save_ifile; char *good_filename; char *filename; char *gfilelist; char *gfilename; struct textlist tl_files; struct textlist tl_gfiles; save_ifile = save_curr_ifile(); good_filename = NULL; /* * Run thru each filename in the list. * Try to glob the filename. * If it doesn't expand, just try to open the filename. * If it does expand, try to open each name in that list. */ init_textlist(&tl_files, filelist); filename = NULL; while ((filename = forw_textlist(&tl_files, filename)) != NULL) { gfilelist = lglob(filename); init_textlist(&tl_gfiles, gfilelist); gfilename = NULL; while ((gfilename = forw_textlist(&tl_gfiles, gfilename)) != NULL) { if (edit(gfilename) == 0 && good_filename == NULL) good_filename = get_filename(curr_ifile); } free(gfilelist); } /* * Edit the first valid filename in the list. */ if (good_filename == NULL) { unsave_ifile(save_ifile); return (1); } if (get_ifile(good_filename, curr_ifile) == curr_ifile) { /* * Trying to edit the current file; don't reopen it. */ unsave_ifile(save_ifile); return (0); } reedit_ifile(save_ifile); return (edit(good_filename)); } /* * Edit the first file in the command line (ifile) list. */ public int -edit_first() +edit_first(void) { curr_ifile = NULL_IFILE; return (edit_next(1)); } /* * Edit the last file in the command line (ifile) list. */ public int -edit_last() +edit_last(void) { curr_ifile = NULL_IFILE; return (edit_prev(1)); } /* * Edit the n-th next or previous file in the command line (ifile) list. */ static int -edit_istep(h, n, dir) - IFILE h; - int n; - int dir; +edit_istep(IFILE h, int n, int dir) { IFILE next; /* * Skip n filenames, then try to edit each filename. */ for (;;) { next = (dir > 0) ? next_ifile(h) : prev_ifile(h); if (--n < 0) { if (edit_ifile(h) == 0) break; } if (next == NULL_IFILE) { /* * Reached end of the ifile list. */ return (1); } if (ABORT_SIGS()) { /* * Interrupt breaks out, if we're in a long * list of files that can't be opened. */ return (1); } h = next; } /* * Found a file that we can edit. */ return (0); } static int -edit_inext(h, n) - IFILE h; - int n; +edit_inext(IFILE h, int n) { return (edit_istep(h, n, +1)); } public int -edit_next(n) - int n; +edit_next(int n) { return edit_istep(curr_ifile, n, +1); } static int -edit_iprev(h, n) - IFILE h; - int n; +edit_iprev(IFILE h, int n) { return (edit_istep(h, n, -1)); } public int -edit_prev(n) - int n; +edit_prev(int n) { return edit_istep(curr_ifile, n, -1); } /* * Edit a specific file in the command line (ifile) list. */ public int -edit_index(n) - int n; +edit_index(int n) { IFILE h; h = NULL_IFILE; do { if ((h = next_ifile(h)) == NULL_IFILE) { /* * Reached end of the list without finding it. */ return (1); } } while (get_index(h) != n); return (edit_ifile(h)); } public IFILE -save_curr_ifile() +save_curr_ifile(void) { if (curr_ifile != NULL_IFILE) hold_ifile(curr_ifile, 1); return (curr_ifile); } public void -unsave_ifile(save_ifile) - IFILE save_ifile; +unsave_ifile(IFILE save_ifile) { if (save_ifile != NULL_IFILE) hold_ifile(save_ifile, -1); } /* * Reedit the ifile which was previously open. */ public void -reedit_ifile(save_ifile) - IFILE save_ifile; +reedit_ifile(IFILE save_ifile) { IFILE next; IFILE prev; /* * Try to reopen the ifile. * Note that opening it may fail (maybe the file was removed), * in which case the ifile will be deleted from the list. * So save the next and prev ifiles first. */ unsave_ifile(save_ifile); next = next_ifile(save_ifile); prev = prev_ifile(save_ifile); if (edit_ifile(save_ifile) == 0) return; /* * If can't reopen it, open the next input file in the list. */ if (next != NULL_IFILE && edit_inext(next, 0) == 0) return; /* * If can't open THAT one, open the previous input file in the list. */ if (prev != NULL_IFILE && edit_iprev(prev, 0) == 0) return; /* * If can't even open that, we're stuck. Just quit. */ quit(QUIT_ERROR); } public void -reopen_curr_ifile() +reopen_curr_ifile(void) { IFILE save_ifile = save_curr_ifile(); close_file(); reedit_ifile(save_ifile); } /* * Edit standard input. */ public int -edit_stdin() +edit_stdin(void) { if (isatty(fd0)) { error("Missing filename (\"less --help\" for help)", NULL_PARG); quit(QUIT_OK); } return (edit("-")); } /* * Copy a file directly to standard output. * Used if standard output is not a tty. */ public void -cat_file() +cat_file(void) { - register int c; + int c; while ((c = ch_forw_get()) != EOI) putchr(c); flush(); } #if LOGFILE /* * If the user asked for a log file and our input file * is standard input, create the log file. * We take care not to blindly overwrite an existing file. */ public void -use_logfile(filename) - char *filename; +use_logfile(char *filename) { - register int exists; - register int answer; + int exists; + int answer; PARG parg; if (ch_getflags() & CH_CANSEEK) /* * Can't currently use a log file on a file that can seek. */ return; /* * {{ We could use access() here. }} */ filename = shell_unquote(filename); exists = open(filename, OPEN_READ); if (exists >= 0) close(exists); exists = (exists >= 0); /* * Decide whether to overwrite the log file or append to it. * If it doesn't exist we "overwrite" it. */ if (!exists || force_logfile) { /* * Overwrite (or create) the log file. */ answer = 'O'; } else { /* * Ask user what to do. */ parg.p_string = filename; answer = query("Warning: \"%s\" exists; Overwrite, Append or Don't log? ", &parg); } loop: switch (answer) { case 'O': case 'o': /* * Overwrite: create the file. */ logfile = creat(filename, 0644); break; case 'A': case 'a': /* * Append: open the file and seek to the end. */ logfile = open(filename, OPEN_APPEND); if (lseek(logfile, (off_t)0, SEEK_END) == BAD_LSEEK) { close(logfile); logfile = -1; } break; case 'D': case 'd': /* * Don't do anything. */ free(filename); return; case 'q': quit(QUIT_OK); /*NOTREACHED*/ default: /* * Eh? */ answer = query("Overwrite, Append, or Don't log? (Type \"O\", \"A\", \"D\" or \"q\") ", NULL_PARG); goto loop; } if (logfile < 0) { /* * Error in opening logfile. */ parg.p_string = filename; error("Cannot write to \"%s\"", &parg); free(filename); return; } free(filename); SET_BINARY(logfile); } #endif Index: head/contrib/less/filename.c =================================================================== --- head/contrib/less/filename.c (revision 316338) +++ head/contrib/less/filename.c (revision 316339) @@ -1,1131 +1,1107 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines to mess around with filenames (and files). * Much of this is very OS dependent. */ #include "less.h" #include "lglob.h" #if MSDOS_COMPILER #include #if MSDOS_COMPILER==WIN32C && !defined(_MSC_VER) #include #endif #if MSDOS_COMPILER==DJGPPC #include #include #define _MAX_PATH PATH_MAX #endif #endif #ifdef _OSK #include #ifndef _OSK_MWC32 #include #endif #endif #if OS2 #include #endif #if HAVE_STAT #include #ifndef S_ISDIR #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) #endif #ifndef S_ISREG #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #endif #endif extern int force_open; extern int secure; extern int use_lessopen; extern int ctldisp; extern int utf_mode; extern IFILE curr_ifile; extern IFILE old_ifile; #if SPACES_IN_FILENAMES extern char openquote; extern char closequote; #endif /* * Remove quotes around a filename. */ public char * -shell_unquote(str) - char *str; +shell_unquote(char *str) { char *name; char *p; name = p = (char *) ecalloc(strlen(str)+1, sizeof(char)); if (*str == openquote) { str++; while (*str != '\0') { if (*str == closequote) { if (str[1] != closequote) break; str++; } *p++ = *str++; } } else { char *esc = get_meta_escape(); int esclen = (int) strlen(esc); while (*str != '\0') { if (esclen > 0 && strncmp(str, esc, esclen) == 0) str += esclen; *p++ = *str++; } } *p = '\0'; return (name); } /* * Get the shell's escape character. */ public char * -get_meta_escape() +get_meta_escape(void) { char *s; s = lgetenv("LESSMETAESCAPE"); if (s == NULL) s = DEF_METAESCAPE; return (s); } /* * Get the characters which the shell considers to be "metacharacters". */ static char * -metachars() +metachars(void) { static char *mchars = NULL; if (mchars == NULL) { mchars = lgetenv("LESSMETACHARS"); if (mchars == NULL) mchars = DEF_METACHARS; } return (mchars); } /* * Is this a shell metacharacter? */ static int -metachar(c) - char c; +metachar(char c) { return (strchr(metachars(), c) != NULL); } /* * Insert a backslash before each metacharacter in a string. */ public char * -shell_quote(s) - char *s; +shell_quote(char *s) { char *p; char *newstr; int len; char *esc = get_meta_escape(); int esclen = (int) strlen(esc); int use_quotes = 0; int have_quotes = 0; /* * Determine how big a string we need to allocate. */ len = 1; /* Trailing null byte */ for (p = s; *p != '\0'; p++) { len++; if (*p == openquote || *p == closequote) have_quotes = 1; if (metachar(*p)) { if (esclen == 0) { /* * We've got a metachar, but this shell * doesn't support escape chars. Use quotes. */ use_quotes = 1; } else { /* * Allow space for the escape char. */ len += esclen; } } } if (use_quotes) { if (have_quotes) /* * We can't quote a string that contains quotes. */ return (NULL); len = (int) strlen(s) + 3; } /* * Allocate and construct the new string. */ newstr = p = (char *) ecalloc(len, sizeof(char)); if (use_quotes) { SNPRINTF3(newstr, len, "%c%s%c", openquote, s, closequote); } else { while (*s != '\0') { if (metachar(*s)) { /* * Add the escape char. */ strcpy(p, esc); p += esclen; } *p++ = *s++; } *p = '\0'; } return (newstr); } /* * Return a pathname that points to a specified file in a specified directory. * Return NULL if the file does not exist in the directory. */ static char * -dirfile(dirname, filename) - char *dirname; - char *filename; +dirfile(char *dirname, char *filename) { char *pathname; char *qpathname; int len; int f; if (dirname == NULL || *dirname == '\0') return (NULL); /* * Construct the full pathname. */ len = (int) (strlen(dirname) + strlen(filename) + 2); pathname = (char *) calloc(len, sizeof(char)); if (pathname == NULL) return (NULL); SNPRINTF3(pathname, len, "%s%s%s", dirname, PATHNAME_SEP, filename); /* * Make sure the file exists. */ qpathname = shell_unquote(pathname); f = open(qpathname, OPEN_READ); if (f < 0) { free(pathname); pathname = NULL; } else { close(f); } free(qpathname); return (pathname); } /* * Return the full pathname of the given file in the "home directory". */ public char * -homefile(filename) - char *filename; +homefile(char *filename) { - register char *pathname; + char *pathname; /* * Try $HOME/filename. */ pathname = dirfile(lgetenv("HOME"), filename); if (pathname != NULL) return (pathname); #if OS2 /* * Try $INIT/filename. */ pathname = dirfile(lgetenv("INIT"), filename); if (pathname != NULL) return (pathname); #endif #if MSDOS_COMPILER || OS2 /* * Look for the file anywhere on search path. */ pathname = (char *) calloc(_MAX_PATH, sizeof(char)); #if MSDOS_COMPILER==DJGPPC { char *res = searchpath(filename); if (res == 0) *pathname = '\0'; else strcpy(pathname, res); } #else _searchenv(filename, "PATH", pathname); #endif if (*pathname != '\0') return (pathname); free(pathname); #endif return (NULL); } /* * Expand a string, substituting any "%" with the current filename, * and any "#" with the previous filename. * But a string of N "%"s is just replaced with N-1 "%"s. * Likewise for a string of N "#"s. * {{ This is a lot of work just to support % and #. }} */ public char * -fexpand(s) - char *s; +fexpand(char *s) { - register char *fr, *to; - register int n; - register char *e; + char *fr, *to; + int n; + char *e; IFILE ifile; #define fchar_ifile(c) \ ((c) == '%' ? curr_ifile : \ (c) == '#' ? old_ifile : NULL_IFILE) /* * Make one pass to see how big a buffer we * need to allocate for the expanded string. */ n = 0; for (fr = s; *fr != '\0'; fr++) { switch (*fr) { case '%': case '#': if (fr > s && fr[-1] == *fr) { /* * Second (or later) char in a string * of identical chars. Treat as normal. */ n++; } else if (fr[1] != *fr) { /* * Single char (not repeated). Treat specially. */ ifile = fchar_ifile(*fr); if (ifile == NULL_IFILE) n++; else n += (int) strlen(get_filename(ifile)); } /* * Else it is the first char in a string of * identical chars. Just discard it. */ break; default: n++; break; } } e = (char *) ecalloc(n+1, sizeof(char)); /* * Now copy the string, expanding any "%" or "#". */ to = e; for (fr = s; *fr != '\0'; fr++) { switch (*fr) { case '%': case '#': if (fr > s && fr[-1] == *fr) { *to++ = *fr; } else if (fr[1] != *fr) { ifile = fchar_ifile(*fr); if (ifile == NULL_IFILE) *to++ = *fr; else { strcpy(to, get_filename(ifile)); to += strlen(to); } } break; default: *to++ = *fr; break; } } *to = '\0'; return (e); } #if TAB_COMPLETE_FILENAME /* * Return a blank-separated list of filenames which "complete" * the given string. */ public char * -fcomplete(s) - char *s; +fcomplete(char *s) { char *fpat; char *qs; if (secure) return (NULL); /* * Complete the filename "s" by globbing "s*". */ #if MSDOS_COMPILER && (MSDOS_COMPILER == MSOFTC || MSDOS_COMPILER == BORLANDC) /* * But in DOS, we have to glob "s*.*". * But if the final component of the filename already has * a dot in it, just do "s*". * (Thus, "FILE" is globbed as "FILE*.*", * but "FILE.A" is globbed as "FILE.A*"). */ { char *slash; int len; for (slash = s+strlen(s)-1; slash > s; slash--) if (*slash == *PATHNAME_SEP || *slash == '/') break; len = (int) strlen(s) + 4; fpat = (char *) ecalloc(len, sizeof(char)); if (strchr(slash, '.') == NULL) SNPRINTF1(fpat, len, "%s*.*", s); else SNPRINTF1(fpat, len, "%s*", s); } #else { int len = (int) strlen(s) + 2; fpat = (char *) ecalloc(len, sizeof(char)); SNPRINTF1(fpat, len, "%s*", s); } #endif qs = lglob(fpat); s = shell_unquote(qs); if (strcmp(s,fpat) == 0) { /* * The filename didn't expand. */ free(qs); qs = NULL; } free(s); free(fpat); return (qs); } #endif /* * Try to determine if a file is "binary". * This is just a guess, and we need not try too hard to make it accurate. */ public int -bin_file(f) - int f; +bin_file(int f) { int n; int bin_count = 0; char data[256]; - char* p; + constant char* p; char* pend; if (!seekable(f)) return (0); if (lseek(f, (off_t)0, SEEK_SET) == BAD_LSEEK) return (0); n = read(f, data, sizeof(data)); if (n <= 0) return (0); if (utf_mode) { bin_count = utf_bin_count(data, n); } else { pend = &data[n]; for (p = data; p < pend; ) { LWCHAR c = step_char(&p, +1, pend); if (ctldisp == OPT_ONPLUS && IS_CSI_START(c)) { do { c = step_char(&p, +1, pend); } while (p < pend && is_ansi_middle(c)); } else if (binary_char(c)) bin_count++; } } /* * Call it a binary file if there are more than 5 binary characters * in the first 256 bytes of the file. */ return (bin_count > 5); } /* * Try to determine the size of a file by seeking to the end. */ static POSITION -seek_filesize(f) - int f; +seek_filesize(int f) { off_t spos; spos = lseek(f, (off_t)0, SEEK_END); if (spos == BAD_LSEEK) return (NULL_POSITION); return ((POSITION) spos); } /* * Read a string from a file. * Return a pointer to the string in memory. */ static char * -readfd(fd) - FILE *fd; +readfd(FILE *fd) { int len; int ch; char *buf; char *p; /* * Make a guess about how many chars in the string * and allocate a buffer to hold it. */ len = 100; buf = (char *) ecalloc(len, sizeof(char)); for (p = buf; ; p++) { if ((ch = getc(fd)) == '\n' || ch == EOF) break; if (p - buf >= len-1) { /* * The string is too big to fit in the buffer we have. * Allocate a new buffer, twice as big. */ len *= 2; *p = '\0'; p = (char *) ecalloc(len, sizeof(char)); strcpy(p, buf); free(buf); buf = p; p = buf + strlen(buf); } *p = ch; } *p = '\0'; return (buf); } #if HAVE_POPEN FILE *popen(); /* * Execute a shell command. * Return a pointer to a pipe connected to the shell command's standard output. */ static FILE * -shellcmd(cmd) - char *cmd; +shellcmd(char *cmd) { FILE *fd; #if HAVE_SHELL char *shell; shell = lgetenv("SHELL"); if (shell != NULL && *shell != '\0') { char *scmd; char *esccmd; /* * Read the output of <$SHELL -c cmd>. * Escape any metacharacters in the command. */ esccmd = shell_quote(cmd); if (esccmd == NULL) { fd = popen(cmd, "r"); } else { int len = (int) (strlen(shell) + strlen(esccmd) + 5); scmd = (char *) ecalloc(len, sizeof(char)); SNPRINTF3(scmd, len, "%s %s %s", shell, shell_coption(), esccmd); free(esccmd); fd = popen(scmd, "r"); free(scmd); } } else #endif { fd = popen(cmd, "r"); } /* * Redirection in `popen' might have messed with the * standard devices. Restore binary input mode. */ SET_BINARY(0); return (fd); } #endif /* HAVE_POPEN */ /* * Expand a filename, doing any system-specific metacharacter substitutions. */ public char * -lglob(filename) - char *filename; +lglob(char *filename) { char *gfilename; char *ofilename; ofilename = fexpand(filename); if (secure) return (ofilename); filename = shell_unquote(ofilename); #ifdef DECL_GLOB_LIST { /* * The globbing function returns a list of names. */ int length; char *p; char *qfilename; DECL_GLOB_LIST(list) GLOB_LIST(filename, list); if (GLOB_LIST_FAILED(list)) { free(filename); return (ofilename); } length = 1; /* Room for trailing null byte */ for (SCAN_GLOB_LIST(list, p)) { INIT_GLOB_LIST(list, p); qfilename = shell_quote(p); if (qfilename != NULL) { length += strlen(qfilename) + 1; free(qfilename); } } gfilename = (char *) ecalloc(length, sizeof(char)); for (SCAN_GLOB_LIST(list, p)) { INIT_GLOB_LIST(list, p); qfilename = shell_quote(p); if (qfilename != NULL) { sprintf(gfilename + strlen(gfilename), "%s ", qfilename); free(qfilename); } } /* * Overwrite the final trailing space with a null terminator. */ *--p = '\0'; GLOB_LIST_DONE(list); } #else #ifdef DECL_GLOB_NAME { /* * The globbing function returns a single name, and * is called multiple times to walk thru all names. */ - register char *p; - register int len; - register int n; + char *p; + int len; + int n; char *pathname; char *qpathname; DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) GLOB_FIRST_NAME(filename, &fnd, handle); if (GLOB_FIRST_FAILED(handle)) { free(filename); return (ofilename); } _splitpath(filename, drive, dir, fname, ext); len = 100; gfilename = (char *) ecalloc(len, sizeof(char)); p = gfilename; do { n = (int) (strlen(drive) + strlen(dir) + strlen(fnd.GLOB_NAME) + 1); pathname = (char *) ecalloc(n, sizeof(char)); SNPRINTF3(pathname, n, "%s%s%s", drive, dir, fnd.GLOB_NAME); qpathname = shell_quote(pathname); free(pathname); if (qpathname != NULL) { n = (int) strlen(qpathname); while (p - gfilename + n + 2 >= len) { /* * No room in current buffer. * Allocate a bigger one. */ len *= 2; *p = '\0'; p = (char *) ecalloc(len, sizeof(char)); strcpy(p, gfilename); free(gfilename); gfilename = p; p = gfilename + strlen(gfilename); } strcpy(p, qpathname); free(qpathname); p += n; *p++ = ' '; } } while (GLOB_NEXT_NAME(handle, &fnd) == 0); /* * Overwrite the final trailing space with a null terminator. */ *--p = '\0'; GLOB_NAME_DONE(handle); } #else #if HAVE_POPEN { /* * We get the shell to glob the filename for us by passing * an "echo" command to the shell and reading its output. */ FILE *fd; char *s; char *lessecho; char *cmd; char *esc; int len; esc = get_meta_escape(); if (strlen(esc) == 0) esc = "-"; esc = shell_quote(esc); if (esc == NULL) { free(filename); return (ofilename); } lessecho = lgetenv("LESSECHO"); if (lessecho == NULL || *lessecho == '\0') lessecho = "lessecho"; /* * Invoke lessecho, and read its output (a globbed list of filenames). */ len = (int) (strlen(lessecho) + strlen(ofilename) + (7*strlen(metachars())) + 24); cmd = (char *) ecalloc(len, sizeof(char)); SNPRINTF4(cmd, len, "%s -p0x%x -d0x%x -e%s ", lessecho, openquote, closequote, esc); free(esc); for (s = metachars(); *s != '\0'; s++) sprintf(cmd + strlen(cmd), "-n0x%x ", *s); sprintf(cmd + strlen(cmd), "-- %s", ofilename); fd = shellcmd(cmd); free(cmd); if (fd == NULL) { /* * Cannot create the pipe. * Just return the original (fexpanded) filename. */ free(filename); return (ofilename); } gfilename = readfd(fd); pclose(fd); if (*gfilename == '\0') { free(gfilename); free(filename); return (ofilename); } } #else /* * No globbing functions at all. Just use the fexpanded filename. */ gfilename = save(filename); #endif #endif #endif free(filename); free(ofilename); return (gfilename); } /* * Return number of %s escapes in a string. * Return a large number if there are any other % escapes besides %s. */ static int -num_pct_s(lessopen) - char *lessopen; +num_pct_s(char *lessopen) { int num = 0; while (*lessopen != '\0') { if (*lessopen == '%') { if (lessopen[1] == '%') ++lessopen; else if (lessopen[1] == 's') ++num; else return (999); } ++lessopen; } return (num); } /* * See if we should open a "replacement file" * instead of the file we're about to open. */ public char * -open_altfile(filename, pf, pfd) - char *filename; - int *pf; - void **pfd; +open_altfile(char *filename, int *pf, void **pfd) { #if !HAVE_POPEN return (NULL); #else char *lessopen; char *cmd; int len; FILE *fd; #if HAVE_FILENO int returnfd = 0; #endif if (!use_lessopen || secure) return (NULL); ch_ungetchar(-1); if ((lessopen = lgetenv("LESSOPEN")) == NULL) return (NULL); while (*lessopen == '|') { /* * If LESSOPEN starts with a |, it indicates * a "pipe preprocessor". */ #if !HAVE_FILENO error("LESSOPEN pipe is not supported", NULL_PARG); return (NULL); #else lessopen++; returnfd++; #endif } if (*lessopen == '-') { /* * Lessopen preprocessor will accept "-" as a filename. */ lessopen++; } else { if (strcmp(filename, "-") == 0) return (NULL); } if (num_pct_s(lessopen) > 1) { error("Invalid LESSOPEN variable", NULL_PARG); return (NULL); } len = (int) (strlen(lessopen) + strlen(filename) + 2); cmd = (char *) ecalloc(len, sizeof(char)); SNPRINTF1(cmd, len, lessopen, filename); fd = shellcmd(cmd); free(cmd); if (fd == NULL) { /* * Cannot create the pipe. */ return (NULL); } #if HAVE_FILENO if (returnfd) { int f; char c; /* * Read one char to see if the pipe will produce any data. * If it does, push the char back on the pipe. */ f = fileno(fd); SET_BINARY(f); if (read(f, &c, 1) != 1) { /* * Pipe is empty. * If more than 1 pipe char was specified, * the exit status tells whether the file itself * is empty, or if there is no alt file. * If only one pipe char, just assume no alt file. */ int status = pclose(fd); if (returnfd > 1 && status == 0) { *pfd = NULL; *pf = -1; return (save(FAKE_EMPTYFILE)); } return (NULL); } ch_ungetchar(c); *pfd = (void *) fd; *pf = f; return (save("-")); } #endif cmd = readfd(fd); pclose(fd); if (*cmd == '\0') /* * Pipe is empty. This means there is no alt file. */ return (NULL); return (cmd); #endif /* HAVE_POPEN */ } /* * Close a replacement file. */ public void -close_altfile(altfilename, filename, pipefd) - char *altfilename; - char *filename; - void *pipefd; +close_altfile(char *altfilename, char *filename, void *pipefd) { #if HAVE_POPEN char *lessclose; FILE *fd; char *cmd; int len; if (secure) return; if (pipefd != NULL) { #if OS2 /* * The pclose function of OS/2 emx sometimes fails. * Send SIGINT to the piped process before closing it. */ kill(((FILE*)pipefd)->_pid, SIGINT); #endif pclose((FILE*) pipefd); } if ((lessclose = lgetenv("LESSCLOSE")) == NULL) return; if (num_pct_s(lessclose) > 2) { error("Invalid LESSCLOSE variable", NULL_PARG); return; } len = (int) (strlen(lessclose) + strlen(filename) + strlen(altfilename) + 2); cmd = (char *) ecalloc(len, sizeof(char)); SNPRINTF2(cmd, len, lessclose, filename, altfilename); fd = shellcmd(cmd); free(cmd); if (fd != NULL) pclose(fd); #endif } /* * Is the specified file a directory? */ public int -is_dir(filename) - char *filename; +is_dir(char *filename) { int isdir = 0; filename = shell_unquote(filename); #if HAVE_STAT { int r; struct stat statbuf; r = stat(filename, &statbuf); isdir = (r >= 0 && S_ISDIR(statbuf.st_mode)); } #else #ifdef _OSK { - register int f; + int f; f = open(filename, S_IREAD | S_IFDIR); if (f >= 0) close(f); isdir = (f >= 0); } #endif #endif free(filename); return (isdir); } /* * Returns NULL if the file can be opened and * is an ordinary file, otherwise an error message * (if it cannot be opened or is a directory, etc.) */ public char * -bad_file(filename) - char *filename; +bad_file(char *filename) { - register char *m = NULL; + char *m = NULL; filename = shell_unquote(filename); if (!force_open && is_dir(filename)) { static char is_a_dir[] = " is a directory"; m = (char *) ecalloc(strlen(filename) + sizeof(is_a_dir), sizeof(char)); strcpy(m, filename); strcat(m, is_a_dir); } else { #if HAVE_STAT int r; struct stat statbuf; r = stat(filename, &statbuf); if (r < 0) { m = errno_message(filename); } else if (force_open) { m = NULL; } else if (!S_ISREG(statbuf.st_mode)) { static char not_reg[] = " is not a regular file (use -f to see it)"; m = (char *) ecalloc(strlen(filename) + sizeof(not_reg), sizeof(char)); strcpy(m, filename); strcat(m, not_reg); } #endif } free(filename); return (m); } /* * Return the size of a file, as cheaply as possible. * In Unix, we can stat the file. */ public POSITION -filesize(f) - int f; +filesize(int f) { #if HAVE_STAT struct stat statbuf; if (fstat(f, &statbuf) >= 0) return ((POSITION) statbuf.st_size); #else #ifdef _OSK long size; if ((size = (long) _gs_size(f)) >= 0) return ((POSITION) size); #endif #endif return (seek_filesize(f)); } /* * */ public char * -shell_coption() +shell_coption(void) { return ("-c"); } /* * Return last component of a pathname. */ public char * -last_component(name) - char *name; +last_component(char *name) { char *slash; for (slash = name + strlen(name); slash > name; ) { --slash; if (*slash == *PATHNAME_SEP || *slash == '/') return (slash + 1); } return (name); } Index: head/contrib/less/forwback.c =================================================================== --- head/contrib/less/forwback.c (revision 316338) +++ head/contrib/less/forwback.c (revision 316339) @@ -1,451 +1,436 @@ /* $FreeBSD$ */ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Primitives for displaying the file on the screen, * scrolling either forward or backward. */ #include "less.h" #include "position.h" public int screen_trashed; public int squished; public int no_back_scroll = 0; public int forw_prompt; public int same_pos_bell = 1; extern int sigs; extern int top_scroll; extern int quiet; extern int sc_width, sc_height; extern int less_is_more; extern int plusoption; extern int forw_scroll; extern int back_scroll; extern int ignore_eoi; extern int clear_bg; extern int final_attr; extern int oldbot; #if HILITE_SEARCH extern int size_linebuf; extern int hilite_search; extern int status_col; #endif #if TAGS extern char *tagoption; #endif /* * Sound the bell to indicate user is trying to move past end of file. */ static void -eof_bell() +eof_bell(void) { if (quiet == NOT_QUIET) bell(); else vbell(); } /* * Check to see if the end of file is currently displayed. */ public int -eof_displayed() +eof_displayed(void) { POSITION pos; if (ignore_eoi) return (0); if (ch_length() == NULL_POSITION) /* * If the file length is not known, * we can't possibly be displaying EOF. */ return (0); /* * If the bottom line is empty, we are at EOF. * If the bottom line ends at the file length, * we must be just at EOF. */ pos = position(BOTTOM_PLUS_ONE); return (pos == NULL_POSITION || pos == ch_length()); } /* * Check to see if the entire file is currently displayed. */ public int -entire_file_displayed() +entire_file_displayed(void) { POSITION pos; /* Make sure last line of file is displayed. */ if (!eof_displayed()) return (0); /* Make sure first line of file is displayed. */ pos = position(0); return (pos == NULL_POSITION || pos == 0); } /* * If the screen is "squished", repaint it. * "Squished" means the first displayed line is not at the top * of the screen; this can happen when we display a short file * for the first time. */ public void -squish_check() +squish_check(void) { if (!squished) return; squished = 0; repaint(); } /* * Display n lines, scrolling forward, * starting at position pos in the input file. * "force" means display the n lines even if we hit end of file. * "only_last" means display only the last screenful if n > screen size. * "nblank" is the number of blank lines to draw before the first * real line. If nblank > 0, the pos must be NULL_POSITION. * The first real line after the blanks will start at ch_zero(). */ public void -forw(n, pos, force, only_last, nblank) - register int n; - POSITION pos; - int force; - int only_last; - int nblank; +forw(int n, POSITION pos, int force, int only_last, int nblank) { int nlines = 0; int do_repaint; static int first_time = 1; squish_check(); /* * do_repaint tells us not to display anything till the end, * then just repaint the entire screen. * We repaint if we are supposed to display only the last * screenful and the request is for more than a screenful. * Also if the request exceeds the forward scroll limit * (but not if the request is for exactly a screenful, since * repainting itself involves scrolling forward a screenful). */ do_repaint = (only_last && n > sc_height-1) || (forw_scroll >= 0 && n > forw_scroll && n != sc_height-1); #if HILITE_SEARCH if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) { prep_hilite(pos, pos + 4*size_linebuf, ignore_eoi ? 1 : -1); pos = next_unfiltered(pos); } #endif if (!do_repaint) { if (top_scroll && n >= sc_height - 1 && pos != ch_length()) { /* * Start a new screen. * {{ This is not really desirable if we happen * to hit eof in the middle of this screen, * but we don't yet know if that will happen. }} */ pos_clear(); add_forw_pos(pos); force = 1; if (less_is_more == 0) { clear(); home(); } } if (pos != position(BOTTOM_PLUS_ONE) || empty_screen()) { /* * This is not contiguous with what is * currently displayed. Clear the screen image * (position table) and start a new screen. */ pos_clear(); add_forw_pos(pos); force = 1; if (top_scroll) { clear(); home(); } else if (!first_time) { putstr("...skipping...\n"); } } } while (--n >= 0) { /* * Read the next line of input. */ if (nblank > 0) { /* * Still drawing blanks; don't get a line * from the file yet. * If this is the last blank line, get ready to * read a line starting at ch_zero() next time. */ if (--nblank == 0) pos = ch_zero(); } else { /* * Get the next line from the file. */ pos = forw_line(pos); #if HILITE_SEARCH pos = next_unfiltered(pos); #endif if (pos == NULL_POSITION) { /* * End of file: stop here unless the top line * is still empty, or "force" is true. * Even if force is true, stop when the last * line in the file reaches the top of screen. */ if (!force && position(TOP) != NULL_POSITION) break; if (!empty_lines(0, 0) && !empty_lines(1, 1) && empty_lines(2, sc_height-1)) break; } } /* * Add the position of the next line to the position table. * Display the current line on the screen. */ add_forw_pos(pos); nlines++; if (do_repaint) continue; /* * If this is the first screen displayed and * we hit an early EOF (i.e. before the requested * number of lines), we "squish" the display down * at the bottom of the screen. * But don't do this if a + option or a -t option * was given. These options can cause us to * start the display after the beginning of the file, * and it is not appropriate to squish in that case. */ if ((first_time || less_is_more) && pos == NULL_POSITION && !top_scroll && #if TAGS tagoption == NULL && #endif !plusoption) { squished = 1; continue; } put_line(); #if 0 /* {{ * Can't call clear_eol here. The cursor might be at end of line * on an ignaw terminal, so clear_eol would clear the last char * of the current line instead of all of the next line. * If we really need to do this on clear_bg terminals, we need * to find a better way. * }} */ if (clear_bg && apply_at_specials(final_attr) != AT_NORMAL) { /* * Writing the last character on the last line * of the display may have scrolled the screen. * If we were in standout mode, clear_bg terminals * will fill the new line with the standout color. * Now we're in normal mode again, so clear the line. */ clear_eol(); } #endif forw_prompt = 1; } if (nlines == 0 && same_pos_bell) eof_bell(); else if (do_repaint) repaint(); first_time = 0; (void) currline(BOTTOM); } /* * Display n lines, scrolling backward. */ public void -back(n, pos, force, only_last) - register int n; - POSITION pos; - int force; - int only_last; +back(int n, POSITION pos, int force, int only_last) { int nlines = 0; int do_repaint; squish_check(); do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); #if HILITE_SEARCH if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) { prep_hilite((pos < 3*size_linebuf) ? 0 : pos - 3*size_linebuf, pos, -1); } #endif while (--n >= 0) { /* * Get the previous line of input. */ #if HILITE_SEARCH pos = prev_unfiltered(pos); #endif pos = back_line(pos); if (pos == NULL_POSITION) { /* * Beginning of file: stop here unless "force" is true. */ if (!force) break; } /* * Add the position of the previous line to the position table. * Display the line on the screen. */ add_back_pos(pos); nlines++; if (!do_repaint) { home(); add_line(); put_line(); } } if (nlines == 0 && same_pos_bell) eof_bell(); else if (do_repaint) repaint(); else if (!oldbot) lower_left(); (void) currline(BOTTOM); } /* * Display n more lines, forward. * Start just after the line currently displayed at the bottom of the screen. */ public void -forward(n, force, only_last) - int n; - int force; - int only_last; +forward(int n, int force, int only_last) { POSITION pos; if (get_quit_at_eof() && eof_displayed() && !(ch_getflags() & CH_HELPFILE)) { /* * If the -e flag is set and we're trying to go * forward from end-of-file, go on to the next file. */ if (edit_next(1)) quit(QUIT_OK); return; } pos = position(BOTTOM_PLUS_ONE); if (pos == NULL_POSITION && (!force || empty_lines(2, sc_height-1))) { if (ignore_eoi) { /* * ignore_eoi is to support A_F_FOREVER. * Back up until there is a line at the bottom * of the screen. */ if (empty_screen()) pos = ch_zero(); else { do { back(1, position(TOP), 1, 0); pos = position(BOTTOM_PLUS_ONE); } while (pos == NULL_POSITION); } } else { eof_bell(); return; } } forw(n, pos, force, only_last, 0); } /* * Display n more lines, backward. * Start just before the line currently displayed at the top of the screen. */ public void -backward(n, force, only_last) - int n; - int force; - int only_last; +backward(int n, int force, int only_last) { POSITION pos; pos = position(TOP); if (pos == NULL_POSITION && (!force || position(BOTTOM) == 0)) { eof_bell(); return; } back(n, pos, force, only_last); } /* * Get the backwards scroll limit. * Must call this function instead of just using the value of * back_scroll, because the default case depends on sc_height and * top_scroll, as well as back_scroll. */ public int -get_back_scroll() +get_back_scroll(void) { if (no_back_scroll) return (0); if (back_scroll >= 0) return (back_scroll); if (top_scroll) return (sc_height - 2); return (10000); /* infinity */ } Index: head/contrib/less/funcs.h =================================================================== --- head/contrib/less/funcs.h (revision 316338) +++ head/contrib/less/funcs.h (revision 316339) @@ -1,298 +1,302 @@ - public char * save (); - public VOID_POINTER ecalloc (); - public char * skipsp (); - public int sprefix (); - public void quit (); - public void raw_mode (); - public void scrsize (); - public char * special_key_str (); - public void get_term (); - public void init (); - public void deinit (); - public void home (); - public void add_line (); - public void remove_top (); - public void win32_scroll_up (); - public void lower_left (); - public void line_left (); - public void check_winch (); - public void goto_line (); - public void vbell (); - public void bell (); - public void clear (); - public void clear_eol (); - public void clear_bot (); - public void at_enter (); - public void at_exit (); - public void at_switch (); - public int is_at_equiv (); - public int apply_at_specials (); - public void backspace (); - public void putbs (); - public char WIN32getch (); - public void WIN32setcolors (); - public void WIN32textout (); - public void match_brac (); - public void ch_ungetchar (); - public void end_logfile (); - public void sync_logfile (); - public int ch_seek (); - public int ch_end_seek (); - public int ch_end_buffer_seek (); - public int ch_beg_seek (); - public POSITION ch_length (); - public POSITION ch_tell (); - public int ch_forw_get (); - public int ch_back_get (); - public void ch_setbufspace (); - public void ch_flush (); - public int seekable (); - public void ch_set_eof (); - public void ch_init (); - public void ch_close (); - public int ch_getflags (); - public void ch_dump (); - public void init_charset (); - public int binary_char (); - public int control_char (); - public char * prchar (); - public char * prutfchar (); - public int utf_len (); - public int is_utf8_well_formed (); - public int utf_bin_count (); - public LWCHAR get_wchar (); - public void put_wchar (); - public LWCHAR step_char (); - public int is_composing_char (); - public int is_ubin_char (); - public int is_wide_char (); - public int is_combining_char (); - public void cmd_reset (); - public void clear_cmd (); - public void cmd_putstr (); - public int len_cmdbuf (); - public void set_mlist (); - public void cmd_addhist (); - public void cmd_accept (); - public int cmd_char (); - public LINENUM cmd_int (); - public char * get_cmdbuf (); - public char * cmd_lastpattern (); - public void init_cmdhist (); - public void save_cmdhist (); - public int in_mca (); - public void dispversion (); - public int getcc (); - public void ungetcc (); - public void ungetsc (); - public void commands (); - public int cvt_length (); - public int * cvt_alloc_chpos (); - public void cvt_text (); - public void init_cmds (); - public void add_fcmd_table (); - public void add_ecmd_table (); - public int fcmd_decode (); - public int ecmd_decode (); - public char * lgetenv (); - public int lesskey (); - public void add_hometable (); - public int editchar (); - public void init_textlist (); - public char * forw_textlist (); - public char * back_textlist (); - public int edit (); - public int edit_ifile (); - public int edit_list (); - public int edit_first (); - public int edit_last (); - public int edit_next (); - public int edit_prev (); - public int edit_index (); - public IFILE save_curr_ifile (); - public void unsave_ifile (); - public void reedit_ifile (); - public void reopen_curr_ifile (); - public int edit_stdin (); - public void cat_file (); - public void use_logfile (); - public char * shell_unquote (); - public char * get_meta_escape (); - public char * shell_quote (); - public char * homefile (); - public char * fexpand (); - public char * fcomplete (); - public int bin_file (); - public char * lglob (); - public char * open_altfile (); - public void close_altfile (); - public int is_dir (); - public char * bad_file (); - public POSITION filesize (); - public char * shell_coption (); - public char * last_component (); - public int eof_displayed (); - public int entire_file_displayed (); - public void squish_check (); - public void forw (); - public void back (); - public void forward (); - public void backward (); - public int get_back_scroll (); - public void del_ifile (); - public IFILE next_ifile (); - public IFILE prev_ifile (); - public IFILE getoff_ifile (); - public int nifile (); - public IFILE get_ifile (); - public char * get_filename (); - public int get_index (); - public void store_pos (); - public void get_pos (); - public void set_open (); - public int opened (); - public void hold_ifile (); - public int held_ifile (); - public void * get_filestate (); - public void set_filestate (); - public void if_dump (); - public POSITION forw_line (); - public POSITION back_line (); - public void set_attnpos (); - public void jump_forw (); - public void jump_forw_buffered (); - public void jump_back (); - public void repaint (); - public void jump_percent (); - public void jump_line_loc (); - public void jump_loc (); - public void init_line (); - public int is_ascii_char (); - public void prewind (); - public void plinenum (); - public void pshift_all (); - public int is_ansi_end (); - public int is_ansi_middle (); - public int pappend (); - public int pflushmbc (); - public void pdone (); - public void set_status_col (); - public int gline (); - public void null_line (); - public POSITION forw_raw_line (); - public POSITION back_raw_line (); - public void clr_linenum (); - public void add_lnum (); - public LINENUM find_linenum (); - public POSITION find_pos (); - public LINENUM currline (); - public void lsystem (); - public int pipe_mark (); - public int pipe_data (); - public void init_mark (); - public int badmark (); - public void setmark (); - public void lastmark (); - public void gomark (); - public POSITION markpos (); - public void unmark (); - public void opt_o (); - public void opt__O (); - public void opt_j (); - public void calc_jump_sline (); - public void opt_shift (); - public void calc_shift_count (); - public void opt_k (); - public void opt_t (); - public void opt__T (); - public void opt_p (); - public void opt__P (); - public void opt_b (); - public void opt_i (); - public void opt__V (); - public void opt_D (); - public void opt_x (); - public void opt_quote (); - public void opt_query (); - public int get_swindow (); - public char * propt (); - public void scan_option (); - public void toggle_option (); - public int opt_has_param (); - public char * opt_prompt (); - public int isoptpending (); - public void nopendopt (); - public int getnum (); - public long getfraction (); - public int get_quit_at_eof (); - public void init_option (); - public struct loption * findopt (); - public struct loption * findopt_name (); - public int iread (); - public void intread (); - public time_type get_time (); - public char * errno_message (); - public int percentage (); - public POSITION percent_pos (); - public int os9_signal (); - public void put_line (); - public void flush (); - public int putchr (); - public void putstr (); - public void get_return (); - public void error (); - public void ierror (); - public int query (); - public int compile_pattern (); - public void uncompile_pattern (); - public int valid_pattern (); - public int is_null_pattern (); - public int match_pattern (); - public POSITION position (); - public void add_forw_pos (); - public void add_back_pos (); - public void pos_clear (); - public void pos_init (); - public int onscreen (); - public int empty_screen (); - public int empty_lines (); - public void get_scrpos (); - public int adjsline (); - public void init_prompt (); - public char * pr_expand (); - public char * eq_message (); - public char * pr_string (); - public char * wait_message (); - public void init_search (); - public void repaint_hilite (); - public void clear_attn (); - public void undo_search (); - public void clr_hlist (); - public void clr_hilite (); - public void clr_filter (); - public int is_filtered (); - public POSITION next_unfiltered (); - public POSITION prev_unfiltered (); - public int is_hilited (); - public void chg_caseless (); - public void chg_hilite (); - public int search (); - public void prep_hilite (); - public void set_filter_pattern (); - public int is_filtering (); - public RETSIGTYPE winch (); - public RETSIGTYPE winch (); - public void init_signals (); - public void psignals (); - public void cleantags (); - public int gettagtype (); - public void findtag (); - public POSITION tagsearch (); - public char * nexttag (); - public char * prevtag (); - public int ntags (); - public int curr_tag (); - public int edit_tagfile (); - public void open_getchr (); - public void close_getchr (); - public int getchr (); + public char * save (constant char *s); + public VOID_POINTER ecalloc (int count, unsigned int size); + public char * skipsp (char *s); + public char * skipnsp(char *s); + public int sprefix (char *ps, char *s, int uppercase); + public void quit (int status); + public void raw_mode (int on); + public void scrsize (void); + public char * special_key_str (int key); + public void get_term (void); + public void init (void); + public void deinit (void); + public void home (void); + public void add_line (void); + public void remove_top (int n); + public void win32_scroll_up (int n); + public void lower_left (void); + public void line_left (void); + public void check_winch (void); + public void goto_line (int slinenum); + public void vbell (void); + public void bell (void); + public void clear (void); + public void clear_eol (void); + public void clear_bot (void); + public void at_enter (int attr); + public void at_exit (void); + public void at_switch (int attr); + public int is_at_equiv (int attr1, int attr2); + public int apply_at_specials (int attr); + public void backspace (void); + public void putbs (void); + public char WIN32getch (int tty); + public void WIN32setcolors (int fg, int bg); + public void WIN32textout (char *text, int len); + public void match_brac(int obrac, int cbrac, int forwdir, int n); + public void ch_ungetchar (int c); + public void end_logfile (void); + public void sync_logfile (void); + public int ch_seek (POSITION pos); + public int ch_end_seek (void); + public int ch_end_buffer_seek (void); + public int ch_beg_seek (void); + public POSITION ch_length (void); + public POSITION ch_tell (void); + public int ch_forw_get (void); + public int ch_back_get (void); + public void ch_setbufspace (int bufspace); + public void ch_flush (void); + public int seekable (int f); + public void ch_set_eof (void); + public void ch_init (int f, int flags); + public void ch_close (void); + public int ch_getflags (void); +struct filestate; + public void ch_dump (struct filestate *fs); + public void init_charset (void); + public int binary_char (LWCHAR c); + public int control_char (LWCHAR c); + public char * prchar (LWCHAR c); + public char * prutfchar (LWCHAR ch); + public int utf_len (char ch); + public int is_utf8_well_formed (unsigned char *s, int slen); + public int utf_bin_count (unsigned char *data, int len); + public LWCHAR get_wchar (constant char *p); + public void put_wchar (char **pp, LWCHAR ch); + public LWCHAR step_char (constant char **pp, signed int dir, constant char *limit); + public int is_composing_char (LWCHAR ch); + public int is_ubin_char (LWCHAR ch); + public int is_wide_char (LWCHAR ch); + public int is_combining_char (LWCHAR ch1, LWCHAR ch2); + public void cmd_reset (void); + public void clear_cmd (void); + public void cmd_putstr (constant char *s); + public int len_cmdbuf (void); + public void set_mlist (constant void *mlist, int cmdflags); +struct mlist; + public void cmd_addhist (struct mlist *constant mlist, char *cmd, int modified); + public void cmd_accept (void); + public int cmd_char (int c); + public LINENUM cmd_int (long *frac); + public char * get_cmdbuf (void); + public char * cmd_lastpattern (void); + public void init_cmdhist (void); + public void save_cmdhist (void); + public int in_mca (void); + public void dispversion (void); + public int getcc (void); + public void ungetcc (int c); + public void ungetsc (char *s); + public void commands (void); + public int cvt_length (int len, int ops); + public int * cvt_alloc_chpos (int len); + public void cvt_text (char *odst, char *osrc, int *chpos, int *lenp, int ops); + public void init_cmds (void); + public void add_fcmd_table (char *buf, int len); + public void add_ecmd_table (char *buf, int len); + public int fcmd_decode (char *cmd, char **sp); + public int ecmd_decode (char *cmd, char **sp); + public char * lgetenv (char *var); + public int lesskey (char *filename, int sysvar); + public void add_hometable (char *envname, char *def_filename, int sysvar); + public int editchar (int c, int flags); + public void init_textlist (struct textlist *tlist, char *str); + public char * forw_textlist (struct textlist *tlist, char *prev); + public char * back_textlist (struct textlist *tlist, char *prev); + public int edit (char *filename); + public int edit_ifile (IFILE ifile); + public int edit_list (char *filelist); + public int edit_first (void); + public int edit_last (void); + public int edit_next (int n); + public int edit_prev (int n); + public int edit_index (int n); + public IFILE save_curr_ifile (void); + public void unsave_ifile (IFILE save_ifile); + public void reedit_ifile (IFILE save_ifiler); + public void reopen_curr_ifile (void); + public int edit_stdin (void); + public void cat_file (void); + public void use_logfile (char *filename); + public char * shell_unquote (char *str); + public char * get_meta_escape (void); + public char * shell_quote (char *s); + public char * homefile (char *filename); + public char * fexpand (char *s); + public char * fcomplete (char *s); + public int bin_file (int f); + public char * lglob (char *filename); + public char * open_altfile (char *filename, int *pf, void **pfd); + public void close_altfile (char *altfilename, char *filename, void *pipefd); + public int is_dir (char *filename); + public char * bad_file (char *filename); + public POSITION filesize (int f); + public char * shell_coption (void); + public char * last_component (char *name); + public int eof_displayed (void); + public int entire_file_displayed (void); + public void squish_check (void); + public void forw (int n, POSITION pos, int force, int only_last, int nblank); + public void back (int n, POSITION pos, int force, int only_last); + public void forward (int n, int force, int only_last); + public void backward (int n, int force, int only_last); + public int get_back_scroll (void); + public void del_ifile (IFILE h); + public IFILE next_ifile (IFILE h); + public IFILE prev_ifile (IFILE h); + public IFILE getoff_ifile (IFILE ifile); + public int nifile (void); + public IFILE get_ifile (char *filename, IFILE prev); + public char * get_filename (IFILE ifile); + public int get_index (IFILE ifile); + public void store_pos (IFILE ifile, struct scrpos *scrpos); + public void get_pos (IFILE ifile, struct scrpos *scrpos); + public void set_open (IFILE ifile); + public int opened (IFILE ifile); + public void hold_ifile (IFILE ifile, int incr); + public int held_ifile (IFILE ifile); + public void * get_filestate (IFILE ifile); + public void set_filestate (IFILE ifile, void *filestate); + public void if_dump (void); + public POSITION forw_line (POSITION curr_pos); + public POSITION back_line (POSITION curr_pos); + public void set_attnpos (POSITION pos); + public void jump_forw (void); + public void jump_forw_buffered (void); + public void jump_back (LINENUM linenum); + public void repaint (void); + public void jump_percent (int percent, long fraction); + public void jump_line_loc (POSITION pos, int sline); + public void jump_loc (POSITION pos, int sline); + public void init_line (void); + public int is_ascii_char (LWCHAR ch); + public void prewind (void); + public void plinenum (POSITION pos); + public void pshift_all (void); + public int is_ansi_end (LWCHAR ch); + public int is_ansi_middle (LWCHAR ch); + public int pappend (unsigned char c, POSITION pos); + public int pflushmbc (void); + public void pdone (int endline, int forw); + public void set_status_col (char c); + public int gline (int i, int *ap); + public void null_line (void); + public POSITION forw_raw_line (POSITION curr_pos, char **linep, int *line_lenp); + public POSITION back_raw_line (POSITION curr_pos, char **linep, int *line_lenp); + public void clr_linenum (void); + public void add_lnum (LINENUM linenum, POSITION pos); + public LINENUM find_linenum (POSITION pos); + public POSITION find_pos (LINENUM linenum); + public LINENUM currline (int where); + public void lsystem (char *cmd, char *donemsg); + public int pipe_mark (int c, char *cmd); + public int pipe_data (char *cmd, POSITION spos, POSITION epos); + public void init_mark (void); + public int badmark (int c); + public void setmark (int c); + public void lastmark (void); + public void gomark (int c); + public POSITION markpos (int c); + public void unmark (IFILE ifile); + public void opt_o (int type, char *s); + public void opt__O (int type, char *s); + public void opt_j (int type, char *s); + public void calc_jump_sline (void); + public void opt_shift (int type, char *s); + public void calc_shift_count (void); + public void opt_k (int type, char *s); + public void opt_t (int type, char *s); + public void opt__T (int type, char *s); + public void opt_p (int type, char *s); + public void opt__P (int type, char *s); + public void opt_b (int type, char *s); + public void opt_i (int type, char *s); + public void opt__V (int type, char *s); + public void opt_D (int type, char *s); + public void opt_x (int type, char *s); + public void opt_quote (int type, char *s); + public void opt_query (int type, char *s); + public int get_swindow (void); + public char * propt (int c); + public void scan_option (char *s); +struct loption; + public void toggle_option (struct loption *o, int lower, char *s, int how_toggle); + public int opt_has_param (struct loption *o); + public char * opt_prompt (struct loption *o); + public int isoptpending (void); + public void nopendopt (void); + public int getnum (char **sp, char *printopt, int *errp); + public long getfraction (char **sp, char *printopt, int *errp); + public int get_quit_at_eof (void); + public void init_option (void); + public struct loption * findopt (int c); + public struct loption * findopt_name (char **p_optname, char **p_oname, int *p_err); + public int iread (int fd, char *buf, unsigned int len); + public void intread (void); + public time_type get_time (void); + public char * errno_message (char *filename); + public int percentage (POSITION num, POSITION den); + public POSITION percent_pos (POSITION pos, int percent, long fraction); + public int os9_signal (int type, RETSIGTYPE (*handler)()); + public void put_line (void); + public void flush (void); + public int putchr (int c); + public void putstr (constant char *s); + public void get_return (void); + public void error (char *fmt, PARG *parg); + public void ierror (char *fmt, PARG *parg); + public int query (char *fmt, PARG *parg); + public int compile_pattern (char *pattern, int search_type, void **comp_pattern); + public void uncompile_pattern (void **pattern); + public int valid_pattern (char *pattern); + public int is_null_pattern (void *pattern); + public int match_pattern (void *pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int notbol, int search_type); + public POSITION position (int where); + public void add_forw_pos (POSITION pos); + public void add_back_pos (POSITION pos); + public void pos_clear (void); + public void pos_init (void); + public int onscreen (POSITION pos); + public int empty_screen (void); + public int empty_lines (int s, int e); + public void get_scrpos (struct scrpos *scrpos); + public int adjsline (int sline); + public void init_prompt (void); + public char * pr_expand (constant char *proto, int maxwidth); + public char * eq_message (void); + public char * pr_string (void); + public char * wait_message (void); + public void init_search (void); + public void repaint_hilite (int on); + public void clear_attn (void); + public void undo_search (void); +struct hilite_tree; + public void clr_hlist (struct hilite_tree *anchor); + public void clr_hilite (void); + public void clr_filter (void); + public int is_filtered (POSITION pos); + public POSITION next_unfiltered (POSITION pos); + public POSITION prev_unfiltered (POSITION pos); + public int is_hilited (POSITION pos, POSITION epos, int nohide, int *p_matches); + public void chg_caseless (void); + public void chg_hilite (void); + public int search (int search_type, char *pattern, int n); + public void prep_hilite (POSITION spos, POSITION epos, int maxlines); + public void set_filter_pattern (char *pattern, int search_type); + public int is_filtering (void); + public RETSIGTYPE winch (int type); + public void init_signals (int on); + public void psignals (void); + public void cleantags (void); + public int gettagtype (void); + public void findtag (char *tag); + public POSITION tagsearch (void); + public char * nexttag (int n); + public char * prevtag (int n); + public int ntags (void); + public int curr_tag (void); + public int edit_tagfile (void); + public void open_getchr (void); + public void close_getchr (void); + public int getchr (void); Index: head/contrib/less/ifile.c =================================================================== --- head/contrib/less/ifile.c (revision 316338) +++ head/contrib/less/ifile.c (revision 316339) @@ -1,345 +1,317 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * An IFILE represents an input file. * * It is actually a pointer to an ifile structure, * but is opaque outside this module. * Ifile structures are kept in a linked list in the order they * appear on the command line. * Any new file which does not already appear in the list is * inserted after the current file. */ #include "less.h" extern IFILE curr_ifile; struct ifile { struct ifile *h_next; /* Links for command line list */ struct ifile *h_prev; char *h_filename; /* Name of the file */ void *h_filestate; /* File state (used in ch.c) */ int h_index; /* Index within command line list */ int h_hold; /* Hold count */ char h_opened; /* Has this ifile been opened? */ struct scrpos h_scrpos; /* Saved position within the file */ }; /* * Convert an IFILE (external representation) * to a struct file (internal representation), and vice versa. */ #define int_ifile(h) ((struct ifile *)(h)) #define ext_ifile(h) ((IFILE)(h)) /* * Anchor for linked list. */ static struct ifile anchor = { &anchor, &anchor, NULL, NULL, 0, 0, '\0', { NULL_POSITION, 0 } }; static int ifiles = 0; static void -incr_index(p, incr) - register struct ifile *p; - int incr; +incr_index(struct ifile *p, int incr) { for (; p != &anchor; p = p->h_next) p->h_index += incr; } /* * Link an ifile into the ifile list. */ static void -link_ifile(p, prev) - struct ifile *p; - struct ifile *prev; +link_ifile(struct ifile *p, struct ifile *prev) { /* * Link into list. */ if (prev == NULL) prev = &anchor; p->h_next = prev->h_next; p->h_prev = prev; prev->h_next->h_prev = p; prev->h_next = p; /* * Calculate index for the new one, * and adjust the indexes for subsequent ifiles in the list. */ p->h_index = prev->h_index + 1; incr_index(p->h_next, 1); ifiles++; } /* * Unlink an ifile from the ifile list. */ static void -unlink_ifile(p) - struct ifile *p; +unlink_ifile(struct ifile *p) { p->h_next->h_prev = p->h_prev; p->h_prev->h_next = p->h_next; incr_index(p->h_next, -1); ifiles--; } /* * Allocate a new ifile structure and stick a filename in it. * It should go after "prev" in the list * (or at the beginning of the list if "prev" is NULL). * Return a pointer to the new ifile structure. */ static struct ifile * -new_ifile(filename, prev) - char *filename; - struct ifile *prev; +new_ifile(char *filename, struct ifile *prev) { - register struct ifile *p; + struct ifile *p; /* * Allocate and initialize structure. */ p = (struct ifile *) ecalloc(1, sizeof(struct ifile)); p->h_filename = save(filename); p->h_scrpos.pos = NULL_POSITION; p->h_opened = 0; p->h_hold = 0; p->h_filestate = NULL; link_ifile(p, prev); return (p); } /* * Delete an existing ifile structure. */ public void -del_ifile(h) - IFILE h; +del_ifile(IFILE h) { - register struct ifile *p; + struct ifile *p; if (h == NULL_IFILE) return; /* * If the ifile we're deleting is the currently open ifile, * move off it. */ unmark(h); if (h == curr_ifile) curr_ifile = getoff_ifile(curr_ifile); p = int_ifile(h); unlink_ifile(p); free(p->h_filename); free(p); } /* * Get the ifile after a given one in the list. */ public IFILE -next_ifile(h) - IFILE h; +next_ifile(IFILE h) { - register struct ifile *p; + struct ifile *p; p = (h == NULL_IFILE) ? &anchor : int_ifile(h); if (p->h_next == &anchor) return (NULL_IFILE); return (ext_ifile(p->h_next)); } /* * Get the ifile before a given one in the list. */ public IFILE -prev_ifile(h) - IFILE h; +prev_ifile(IFILE h) { - register struct ifile *p; + struct ifile *p; p = (h == NULL_IFILE) ? &anchor : int_ifile(h); if (p->h_prev == &anchor) return (NULL_IFILE); return (ext_ifile(p->h_prev)); } /* * Return a different ifile from the given one. */ public IFILE -getoff_ifile(ifile) - IFILE ifile; +getoff_ifile(IFILE ifile) { IFILE newifile; if ((newifile = prev_ifile(ifile)) != NULL_IFILE) return (newifile); if ((newifile = next_ifile(ifile)) != NULL_IFILE) return (newifile); return (NULL_IFILE); } /* * Return the number of ifiles. */ public int -nifile() +nifile(void) { return (ifiles); } /* * Find an ifile structure, given a filename. */ static struct ifile * -find_ifile(filename) - char *filename; +find_ifile(char *filename) { - register struct ifile *p; + struct ifile *p; for (p = anchor.h_next; p != &anchor; p = p->h_next) if (strcmp(filename, p->h_filename) == 0) return (p); return (NULL); } /* * Get the ifile associated with a filename. * If the filename has not been seen before, * insert the new ifile after "prev" in the list. */ public IFILE -get_ifile(filename, prev) - char *filename; - IFILE prev; +get_ifile(char *filename, IFILE prev) { - register struct ifile *p; + struct ifile *p; if ((p = find_ifile(filename)) == NULL) p = new_ifile(filename, int_ifile(prev)); return (ext_ifile(p)); } /* * Get the filename associated with a ifile. */ public char * -get_filename(ifile) - IFILE ifile; +get_filename(IFILE ifile) { if (ifile == NULL) return (NULL); return (int_ifile(ifile)->h_filename); } /* * Get the index of the file associated with a ifile. */ public int -get_index(ifile) - IFILE ifile; +get_index(IFILE ifile) { return (int_ifile(ifile)->h_index); } /* * Save the file position to be associated with a given file. */ public void -store_pos(ifile, scrpos) - IFILE ifile; - struct scrpos *scrpos; +store_pos(IFILE ifile, struct scrpos *scrpos) { int_ifile(ifile)->h_scrpos = *scrpos; } /* * Recall the file position associated with a file. * If no position has been associated with the file, return NULL_POSITION. */ public void -get_pos(ifile, scrpos) - IFILE ifile; - struct scrpos *scrpos; +get_pos(IFILE ifile, struct scrpos *scrpos) { *scrpos = int_ifile(ifile)->h_scrpos; } /* * Mark the ifile as "opened". */ public void -set_open(ifile) - IFILE ifile; +set_open(IFILE ifile) { int_ifile(ifile)->h_opened = 1; } /* * Return whether the ifile has been opened previously. */ public int -opened(ifile) - IFILE ifile; +opened(IFILE ifile) { return (int_ifile(ifile)->h_opened); } public void -hold_ifile(ifile, incr) - IFILE ifile; - int incr; +hold_ifile(IFILE ifile, int incr) { int_ifile(ifile)->h_hold += incr; } public int -held_ifile(ifile) - IFILE ifile; +held_ifile(IFILE ifile) { return (int_ifile(ifile)->h_hold); } public void * -get_filestate(ifile) - IFILE ifile; +get_filestate(IFILE ifile) { return (int_ifile(ifile)->h_filestate); } public void -set_filestate(ifile, filestate) - IFILE ifile; - void *filestate; +set_filestate(IFILE ifile, void *filestate) { int_ifile(ifile)->h_filestate = filestate; } #if 0 public void -if_dump() +if_dump(void) { - register struct ifile *p; + struct ifile *p; for (p = anchor.h_next; p != &anchor; p = p->h_next) { printf("%x: %d. <%s> pos %d,%x\n", p, p->h_index, p->h_filename, p->h_scrpos.ln, p->h_scrpos.pos); ch_dump(p->h_filestate); } } #endif Index: head/contrib/less/input.c =================================================================== --- head/contrib/less/input.c (revision 316338) +++ head/contrib/less/input.c (revision 316339) @@ -1,463 +1,460 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * High level routines dealing with getting lines of input * from the file being viewed. * * When we speak of "lines" here, we mean PRINTABLE lines; * lines processed with respect to the screen width. * We use the term "raw line" to refer to lines simply * delimited by newlines; not processed with respect to screen width. */ #include "less.h" extern int squeeze; extern int chopline; extern int hshift; extern int quit_if_one_screen; extern int sigs; extern int ignore_eoi; extern int status_col; extern POSITION start_attnpos; extern POSITION end_attnpos; #if HILITE_SEARCH extern int hilite_search; extern int size_linebuf; #endif /* * Get the next line. * A "current" position is passed and a "new" position is returned. * The current position is the position of the first character of * a line. The new position is the position of the first character * of the NEXT line. The line obtained is the line starting at curr_pos. */ public POSITION -forw_line(curr_pos) - POSITION curr_pos; +forw_line(POSITION curr_pos) { POSITION base_pos; POSITION new_pos; - register int c; + int c; int blankline; int endline; int backchars; get_forw_line: if (curr_pos == NULL_POSITION) { null_line(); return (NULL_POSITION); } #if HILITE_SEARCH if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) { /* * If we are ignoring EOI (command F), only prepare * one line ahead, to avoid getting stuck waiting for * slow data without displaying the data we already have. * If we're not ignoring EOI, we *could* do the same, but * for efficiency we prepare several lines ahead at once. */ prep_hilite(curr_pos, curr_pos + 3*size_linebuf, ignore_eoi ? 1 : -1); curr_pos = next_unfiltered(curr_pos); } #endif if (ch_seek(curr_pos)) { null_line(); return (NULL_POSITION); } /* * Step back to the beginning of the line. */ base_pos = curr_pos; for (;;) { if (ABORT_SIGS()) { null_line(); return (NULL_POSITION); } c = ch_back_get(); if (c == EOI) break; if (c == '\n') { (void) ch_forw_get(); break; } --base_pos; } /* * Read forward again to the position we should start at. */ prewind(); plinenum(base_pos); (void) ch_seek(base_pos); new_pos = base_pos; while (new_pos < curr_pos) { if (ABORT_SIGS()) { null_line(); return (NULL_POSITION); } c = ch_forw_get(); backchars = pappend(c, new_pos); new_pos++; if (backchars > 0) { pshift_all(); new_pos -= backchars; while (--backchars >= 0) (void) ch_back_get(); } } (void) pflushmbc(); pshift_all(); /* * Read the first character to display. */ c = ch_forw_get(); if (c == EOI) { null_line(); return (NULL_POSITION); } blankline = (c == '\n' || c == '\r'); /* * Read each character in the line and append to the line buffer. */ for (;;) { if (ABORT_SIGS()) { null_line(); return (NULL_POSITION); } if (c == '\n' || c == EOI) { /* * End of the line. */ backchars = pflushmbc(); new_pos = ch_tell(); if (backchars > 0 && !chopline && hshift == 0) { new_pos -= backchars + 1; endline = FALSE; } else endline = TRUE; break; } if (c != '\r') blankline = 0; /* * Append the char to the line and get the next char. */ backchars = pappend(c, ch_tell()-1); if (backchars > 0) { /* * The char won't fit in the line; the line * is too long to print in the screen width. * End the line here. */ if (chopline || hshift > 0) { do { if (ABORT_SIGS()) { null_line(); return (NULL_POSITION); } c = ch_forw_get(); } while (c != '\n' && c != EOI); new_pos = ch_tell(); endline = TRUE; quit_if_one_screen = FALSE; } else { new_pos = ch_tell() - backchars; endline = FALSE; } break; } c = ch_forw_get(); } pdone(endline, 1); #if HILITE_SEARCH if (is_filtered(base_pos)) { /* * We don't want to display this line. * Get the next line. */ curr_pos = new_pos; goto get_forw_line; } if (status_col && is_hilited(base_pos, ch_tell()-1, 1, NULL)) set_status_col('*'); #endif if (squeeze && blankline) { /* * This line is blank. * Skip down to the last contiguous blank line * and pretend it is the one which we are returning. */ while ((c = ch_forw_get()) == '\n' || c == '\r') if (ABORT_SIGS()) { null_line(); return (NULL_POSITION); } if (c != EOI) (void) ch_back_get(); new_pos = ch_tell(); } return (new_pos); } /* * Get the previous line. * A "current" position is passed and a "new" position is returned. * The current position is the position of the first character of * a line. The new position is the position of the first character * of the PREVIOUS line. The line obtained is the one starting at new_pos. */ public POSITION -back_line(curr_pos) - POSITION curr_pos; +back_line(POSITION curr_pos) { POSITION new_pos, begin_new_pos, base_pos; int c; int endline; int backchars; get_back_line: if (curr_pos == NULL_POSITION || curr_pos <= ch_zero()) { null_line(); return (NULL_POSITION); } #if HILITE_SEARCH if (hilite_search == OPT_ONPLUS || is_filtering() || status_col) prep_hilite((curr_pos < 3*size_linebuf) ? 0 : curr_pos - 3*size_linebuf, curr_pos, -1); #endif if (ch_seek(curr_pos-1)) { null_line(); return (NULL_POSITION); } if (squeeze) { /* * Find out if the "current" line was blank. */ (void) ch_forw_get(); /* Skip the newline */ c = ch_forw_get(); /* First char of "current" line */ (void) ch_back_get(); /* Restore our position */ (void) ch_back_get(); if (c == '\n' || c == '\r') { /* * The "current" line was blank. * Skip over any preceding blank lines, * since we skipped them in forw_line(). */ while ((c = ch_back_get()) == '\n' || c == '\r') if (ABORT_SIGS()) { null_line(); return (NULL_POSITION); } if (c == EOI) { null_line(); return (NULL_POSITION); } (void) ch_forw_get(); } } /* * Scan backwards until we hit the beginning of the line. */ for (;;) { if (ABORT_SIGS()) { null_line(); return (NULL_POSITION); } c = ch_back_get(); if (c == '\n') { /* * This is the newline ending the previous line. * We have hit the beginning of the line. */ base_pos = ch_tell() + 1; break; } if (c == EOI) { /* * We have hit the beginning of the file. * This must be the first line in the file. * This must, of course, be the beginning of the line. */ base_pos = ch_tell(); break; } } /* * Now scan forwards from the beginning of this line. * We keep discarding "printable lines" (based on screen width) * until we reach the curr_pos. * * {{ This algorithm is pretty inefficient if the lines * are much longer than the screen width, * but I don't know of any better way. }} */ new_pos = base_pos; if (ch_seek(new_pos)) { null_line(); return (NULL_POSITION); } endline = FALSE; prewind(); plinenum(new_pos); loop: begin_new_pos = new_pos; (void) ch_seek(new_pos); do { c = ch_forw_get(); if (c == EOI || ABORT_SIGS()) { null_line(); return (NULL_POSITION); } new_pos++; if (c == '\n') { backchars = pflushmbc(); if (backchars > 0 && !chopline && hshift == 0) { backchars++; goto shift; } endline = TRUE; break; } backchars = pappend(c, ch_tell()-1); if (backchars > 0) { /* * Got a full printable line, but we haven't * reached our curr_pos yet. Discard the line * and start a new one. */ if (chopline || hshift > 0) { endline = TRUE; quit_if_one_screen = FALSE; break; } shift: pshift_all(); while (backchars-- > 0) { (void) ch_back_get(); new_pos--; } goto loop; } } while (new_pos < curr_pos); pdone(endline, 0); #if HILITE_SEARCH if (is_filtered(base_pos)) { /* * We don't want to display this line. * Get the previous line. */ curr_pos = begin_new_pos; goto get_back_line; } if (status_col && curr_pos > 0 && is_hilited(base_pos, curr_pos-1, 1, NULL)) set_status_col('*'); #endif return (begin_new_pos); } /* * Set attnpos. */ public void -set_attnpos(pos) - POSITION pos; +set_attnpos(POSITION pos) { int c; if (pos != NULL_POSITION) { if (ch_seek(pos)) return; for (;;) { c = ch_forw_get(); if (c == EOI) break; if (c == '\n' || c == '\r') { (void) ch_back_get(); break; } pos++; } end_attnpos = pos; for (;;) { c = ch_back_get(); if (c == EOI || c == '\n' || c == '\r') break; pos--; } } start_attnpos = pos; } Index: head/contrib/less/jump.c =================================================================== --- head/contrib/less/jump.c (revision 316338) +++ head/contrib/less/jump.c (revision 316339) @@ -1,329 +1,322 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines which jump to a new location in the file. */ #include "less.h" #include "position.h" extern int jump_sline; extern int squished; extern int screen_trashed; extern int sc_width, sc_height; extern int show_attn; extern int top_scroll; /* * Jump to the end of the file. */ public void -jump_forw() +jump_forw(void) { POSITION pos; POSITION end_pos; if (ch_end_seek()) { error("Cannot seek to end of file", NULL_PARG); return; } /* * Note; lastmark will be called later by jump_loc, but it fails * because the position table has been cleared by pos_clear below. * So call it here before calling pos_clear. */ lastmark(); /* * Position the last line in the file at the last screen line. * Go back one line from the end of the file * to get to the beginning of the last line. */ pos_clear(); end_pos = ch_tell(); pos = back_line(end_pos); if (pos == NULL_POSITION) jump_loc((POSITION)0, sc_height-1); else { jump_loc(pos, sc_height-1); if (position(sc_height-1) != end_pos) repaint(); } } /* * Jump to the last buffered line in the file. */ public void -jump_forw_buffered() +jump_forw_buffered(void) { POSITION end; if (ch_end_buffer_seek()) { error("Cannot seek to end of buffers", NULL_PARG); return; } end = ch_tell(); if (end != NULL_POSITION && end > 0) jump_line_loc(end-1, sc_height-1); } /* * Jump to line n in the file. */ public void -jump_back(linenum) - LINENUM linenum; +jump_back(LINENUM linenum) { POSITION pos; PARG parg; /* * Find the position of the specified line. * If we can seek there, just jump to it. * If we can't seek, but we're trying to go to line number 1, * use ch_beg_seek() to get as close as we can. */ pos = find_pos(linenum); if (pos != NULL_POSITION && ch_seek(pos) == 0) { if (show_attn) set_attnpos(pos); jump_loc(pos, jump_sline); } else if (linenum <= 1 && ch_beg_seek() == 0) { jump_loc(ch_tell(), jump_sline); error("Cannot seek to beginning of file", NULL_PARG); } else { parg.p_linenum = linenum; error("Cannot seek to line number %n", &parg); } } /* * Repaint the screen. */ public void -repaint() +repaint(void) { struct scrpos scrpos; /* * Start at the line currently at the top of the screen * and redisplay the screen. */ get_scrpos(&scrpos); pos_clear(); jump_loc(scrpos.pos, scrpos.ln); } /* * Jump to a specified percentage into the file. */ public void -jump_percent(percent, fraction) - int percent; - long fraction; +jump_percent(int percent, long fraction) { POSITION pos, len; /* * Determine the position in the file * (the specified percentage of the file's length). */ if ((len = ch_length()) == NULL_POSITION) { ierror("Determining length of file", NULL_PARG); ch_end_seek(); } if ((len = ch_length()) == NULL_POSITION) { error("Don't know length of file", NULL_PARG); return; } pos = percent_pos(len, percent, fraction); if (pos >= len) pos = len-1; jump_line_loc(pos, jump_sline); } /* * Jump to a specified position in the file. * Like jump_loc, but the position need not be * the first character in a line. */ public void -jump_line_loc(pos, sline) - POSITION pos; - int sline; +jump_line_loc(POSITION pos, int sline) { int c; if (ch_seek(pos) == 0) { /* * Back up to the beginning of the line. */ while ((c = ch_back_get()) != '\n' && c != EOI) ; if (c == '\n') (void) ch_forw_get(); pos = ch_tell(); } if (show_attn) set_attnpos(pos); jump_loc(pos, sline); } /* * Jump to a specified position in the file. * The position must be the first character in a line. * Place the target line on a specified line on the screen. */ public void -jump_loc(pos, sline) - POSITION pos; - int sline; +jump_loc(POSITION pos, int sline) { - register int nline; + int nline; POSITION tpos; POSITION bpos; /* * Normalize sline. */ sline = adjsline(sline); if ((nline = onscreen(pos)) >= 0) { /* * The line is currently displayed. * Just scroll there. */ nline -= sline; if (nline > 0) forw(nline, position(BOTTOM_PLUS_ONE), 1, 0, 0); else back(-nline, position(TOP), 1, 0); #if HILITE_SEARCH if (show_attn) repaint_hilite(1); #endif return; } /* * Line is not on screen. * Seek to the desired location. */ if (ch_seek(pos)) { error("Cannot seek to that file position", NULL_PARG); return; } /* * See if the desired line is before or after * the currently displayed screen. */ tpos = position(TOP); bpos = position(BOTTOM_PLUS_ONE); if (tpos == NULL_POSITION || pos >= tpos) { /* * The desired line is after the current screen. * Move back in the file far enough so that we can * call forw() and put the desired line at the * sline-th line on the screen. */ for (nline = 0; nline < sline; nline++) { if (bpos != NULL_POSITION && pos <= bpos) { /* * Surprise! The desired line is * close enough to the current screen * that we can just scroll there after all. */ forw(sc_height-sline+nline-1, bpos, 1, 0, 0); #if HILITE_SEARCH if (show_attn) repaint_hilite(1); #endif return; } pos = back_line(pos); if (pos == NULL_POSITION) { /* * Oops. Ran into the beginning of the file. * Exit the loop here and rely on forw() * below to draw the required number of * blank lines at the top of the screen. */ break; } } lastmark(); squished = 0; screen_trashed = 0; forw(sc_height-1, pos, 1, 0, sline-nline); } else { /* * The desired line is before the current screen. * Move forward in the file far enough so that we * can call back() and put the desired line at the * sline-th line on the screen. */ for (nline = sline; nline < sc_height - 1; nline++) { pos = forw_line(pos); if (pos == NULL_POSITION) { /* * Ran into end of file. * This shouldn't normally happen, * but may if there is some kind of read error. */ break; } #if HILITE_SEARCH pos = next_unfiltered(pos); #endif if (pos >= tpos) { /* * Surprise! The desired line is * close enough to the current screen * that we can just scroll there after all. */ back(nline+1, tpos, 1, 0); #if HILITE_SEARCH if (show_attn) repaint_hilite(1); #endif return; } } lastmark(); if (!top_scroll) clear(); else home(); screen_trashed = 0; add_back_pos(pos); back(sc_height-1, pos, 1, 0); } } Index: head/contrib/less/less.h =================================================================== --- head/contrib/less/less.h (revision 316338) +++ head/contrib/less/less.h (revision 316339) @@ -1,533 +1,533 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ #define NEWBOT 1 /* * Standard include file for "less". */ /* * Defines for MSDOS_COMPILER. */ #define MSOFTC 1 /* Microsoft C */ #define BORLANDC 2 /* Borland C */ #define WIN32C 3 /* Windows (Borland C or Microsoft C) */ #define DJGPPC 4 /* DJGPP C */ /* * Include the file of compile-time options. * The <> make cc search for it in -I., not srcdir. */ #include #ifdef _SEQUENT_ /* * Kludge for Sequent Dynix systems that have sigsetmask, but * it's not compatible with the way less calls it. * {{ Do other systems need this? }} */ #undef HAVE_SIGSETMASK #endif /* * Language details. */ #if HAVE_VOID #define VOID_POINTER void * #else #define VOID_POINTER char * #define void int #endif #if HAVE_CONST #define constant const #else #define constant #endif #define public /* PUBLIC FUNCTION */ /* Library function declarations */ #if HAVE_SYS_TYPES_H #include #endif #if HAVE_STDIO_H #include #endif #if HAVE_FCNTL_H #include #endif #if HAVE_UNISTD_H #include #endif #if HAVE_CTYPE_H #include #endif #if HAVE_WCTYPE_H #include #endif #if HAVE_LIMITS_H #include #endif #if HAVE_STDLIB_H #include #endif #if HAVE_STRING_H #include #endif /* OS-specific includes */ #ifdef _OSK #include #include #endif #ifdef __TANDEM #include #endif #if MSDOS_COMPILER==WIN32C || OS2 #include #endif #if MSDOS_COMPILER==DJGPPC #include #include #include #include #endif #if !HAVE_STDLIB_H char *getenv(); off_t lseek(); VOID_POINTER calloc(); void free(); #endif /* * Simple lowercase test which can be used during option processing * (before options are parsed which might tell us what charset to use). */ #define ASCII_IS_UPPER(c) ((c) >= 'A' && (c) <= 'Z') #define ASCII_IS_LOWER(c) ((c) >= 'a' && (c) <= 'z') #define ASCII_TO_UPPER(c) ((c) - 'a' + 'A') #define ASCII_TO_LOWER(c) ((c) - 'A' + 'a') #undef IS_UPPER #undef IS_LOWER #undef TO_UPPER #undef TO_LOWER #undef IS_SPACE #undef IS_DIGIT #if HAVE_WCTYPE #define IS_UPPER(c) iswupper(c) #define IS_LOWER(c) iswlower(c) #define TO_UPPER(c) towupper(c) #define TO_LOWER(c) towlower(c) #else #if HAVE_UPPER_LOWER #define IS_UPPER(c) isupper((unsigned char) (c)) #define IS_LOWER(c) islower((unsigned char) (c)) #define TO_UPPER(c) toupper((unsigned char) (c)) #define TO_LOWER(c) tolower((unsigned char) (c)) #else #define IS_UPPER(c) ASCII_IS_UPPER(c) #define IS_LOWER(c) ASCII_IS_LOWER(c) #define TO_UPPER(c) ASCII_TO_UPPER(c) #define TO_LOWER(c) ASCII_TO_LOWER(c) #endif #endif #ifdef isspace #define IS_SPACE(c) isspace((unsigned char)(c)) #else #define IS_SPACE(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r' || (c) == '\f') #endif #ifdef isdigit #define IS_DIGIT(c) isdigit((unsigned char)(c)) #else #define IS_DIGIT(c) ((c) >= '0' && (c) <= '9') #endif #define IS_CSI_START(c) (((LWCHAR)(c)) == ESC || (((LWCHAR)(c)) == CSI)) #ifndef NULL #define NULL 0 #endif #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #define OPT_OFF 0 #define OPT_ON 1 #define OPT_ONPLUS 2 #if !HAVE_MEMCPY #ifndef memcpy #define memcpy(to,from,len) bcopy((from),(to),(len)) #endif #endif #if HAVE_SNPRINTF #define SNPRINTF1(str, size, fmt, v1) snprintf((str), (size), (fmt), (v1)) #define SNPRINTF2(str, size, fmt, v1, v2) snprintf((str), (size), (fmt), (v1), (v2)) #define SNPRINTF3(str, size, fmt, v1, v2, v3) snprintf((str), (size), (fmt), (v1), (v2), (v3)) #define SNPRINTF4(str, size, fmt, v1, v2, v3, v4) snprintf((str), (size), (fmt), (v1), (v2), (v3), (v4)) #else /* Use unsafe sprintf if we don't have snprintf. */ #define SNPRINTF1(str, size, fmt, v1) sprintf((str), (fmt), (v1)) #define SNPRINTF2(str, size, fmt, v1, v2) sprintf((str), (fmt), (v1), (v2)) #define SNPRINTF3(str, size, fmt, v1, v2, v3) sprintf((str), (fmt), (v1), (v2), (v3)) #define SNPRINTF4(str, size, fmt, v1, v2, v3, v4) sprintf((str), (fmt), (v1), (v2), (v3), (v4)) #endif #define BAD_LSEEK ((off_t)-1) #ifndef SEEK_SET #define SEEK_SET 0 #endif #ifndef SEEK_END #define SEEK_END 2 #endif #ifndef CHAR_BIT #define CHAR_BIT 8 #endif /* * Upper bound on the string length of an integer converted to string. * 302 / 1000 is ceil (log10 (2.0)). Subtract 1 for the sign bit; * add 1 for integer division truncation; add 1 more for a minus sign. */ #define INT_STRLEN_BOUND(t) ((sizeof(t) * CHAR_BIT - 1) * 302 / 1000 + 1 + 1) /* * Special types and constants. */ typedef unsigned long LWCHAR; typedef off_t POSITION; typedef off_t LINENUM; #define MIN_LINENUM_WIDTH 7 /* Min printing width of a line number */ #define MAX_UTF_CHAR_LEN 6 /* Max bytes in one UTF-8 char */ #define NULL_POSITION ((POSITION)(-1)) /* * Flags for open() */ #if MSDOS_COMPILER || OS2 #define OPEN_READ (O_RDONLY|O_BINARY) #else #ifdef _OSK #define OPEN_READ (S_IREAD) #else #ifdef O_RDONLY #define OPEN_READ (O_RDONLY) #else #define OPEN_READ (0) #endif #endif #endif #if defined(O_WRONLY) && defined(O_APPEND) #define OPEN_APPEND (O_APPEND|O_WRONLY) #else #ifdef _OSK #define OPEN_APPEND (S_IWRITE) #else #define OPEN_APPEND (1) #endif #endif /* * Set a file descriptor to binary mode. */ #if MSDOS_COMPILER==MSOFTC #define SET_BINARY(f) _setmode(f, _O_BINARY); #else #if MSDOS_COMPILER || OS2 #define SET_BINARY(f) setmode(f, O_BINARY) #else #define SET_BINARY(f) #endif #endif /* * Does the shell treat "?" as a metacharacter? */ #if MSDOS_COMPILER || OS2 || _OSK #define SHELL_META_QUEST 0 #else #define SHELL_META_QUEST 1 #endif #define SPACES_IN_FILENAMES 1 /* * An IFILE represents an input file. */ #define IFILE VOID_POINTER #define NULL_IFILE ((IFILE)NULL) /* * The structure used to represent a "screen position". * This consists of a file position, and a screen line number. * The meaning is that the line starting at the given file * position is displayed on the ln-th line of the screen. * (Screen lines before ln are empty.) */ struct scrpos { POSITION pos; int ln; }; /* * A mark is an ifile (input file) plus a position within the file. */ struct mark { IFILE m_ifile; struct scrpos m_scrpos; }; typedef union parg { char *p_string; int p_int; LINENUM p_linenum; } PARG; #define NULL_PARG ((PARG *)NULL) struct textlist { char *string; char *endstring; }; struct wchar_range { LWCHAR first, last; }; struct wchar_range_table { struct wchar_range *table; int count; }; #define EOI (-1) #define READ_INTR (-2) /* A fraction is represented by an int n; the fraction is n/NUM_FRAC_DENOM */ #define NUM_FRAC_DENOM 1000000 #define NUM_LOG_FRAC_DENOM 6 /* How quiet should we be? */ #define NOT_QUIET 0 /* Ring bell at eof and for errors */ #define LITTLE_QUIET 1 /* Ring bell only for errors */ #define VERY_QUIET 2 /* Never ring bell */ /* How should we prompt? */ #define PR_SHORT 0 /* Prompt with colon */ #define PR_MEDIUM 1 /* Prompt with message */ #define PR_LONG 2 /* Prompt with longer message */ /* How should we handle backspaces? */ #define BS_SPECIAL 0 /* Do special things for underlining and bold */ #define BS_NORMAL 1 /* \b treated as normal char; actually output */ #define BS_CONTROL 2 /* \b treated as control char; prints as ^H */ /* How should we search? */ #define SRCH_FORW (1 << 0) /* Search forward from current position */ #define SRCH_BACK (1 << 1) /* Search backward from current position */ #define SRCH_NO_MOVE (1 << 2) /* Highlight, but don't move */ #define SRCH_FIND_ALL (1 << 4) /* Find and highlight all matches */ #define SRCH_NO_MATCH (1 << 8) /* Search for non-matching lines */ #define SRCH_PAST_EOF (1 << 9) /* Search past end-of-file, into next file */ #define SRCH_FIRST_FILE (1 << 10) /* Search starting at the first file */ #define SRCH_NO_REGEX (1 << 12) /* Don't use regular expressions */ #define SRCH_FILTER (1 << 13) /* Search is for '&' (filter) command */ #define SRCH_AFTER_TARGET (1 << 14) /* Start search after the target line */ #define SRCH_REVERSE(t) (((t) & SRCH_FORW) ? \ (((t) & ~SRCH_FORW) | SRCH_BACK) : \ (((t) & ~SRCH_BACK) | SRCH_FORW)) /* */ #define NO_MCA 0 #define MCA_DONE 1 #define MCA_MORE 2 #define CC_OK 0 /* Char was accepted & processed */ #define CC_QUIT 1 /* Char was a request to abort current cmd */ #define CC_ERROR 2 /* Char could not be accepted due to error */ #define CC_PASS 3 /* Char was rejected (internal) */ #define CF_QUIT_ON_ERASE 0001 /* Abort cmd if its entirely erased */ /* Special char bit-flags used to tell put_line() to do something special */ #define AT_NORMAL (0) #define AT_UNDERLINE (1 << 0) #define AT_BOLD (1 << 1) #define AT_BLINK (1 << 2) #define AT_STANDOUT (1 << 3) #define AT_ANSI (1 << 4) /* Content-supplied "ANSI" escape sequence */ #define AT_BINARY (1 << 5) /* LESS*BINFMT representation */ #define AT_HILITE (1 << 6) /* Internal highlights (e.g., for search) */ #if '0' == 240 #define IS_EBCDIC_HOST 1 #endif #if IS_EBCDIC_HOST /* * Long definition for EBCDIC. * Since the argument is usually a constant, this macro normally compiles * into a constant. */ #define CONTROL(c) ( \ (c)=='[' ? '\047' : \ (c)=='a' ? '\001' : \ (c)=='b' ? '\002' : \ (c)=='c' ? '\003' : \ (c)=='d' ? '\067' : \ (c)=='e' ? '\055' : \ (c)=='f' ? '\056' : \ (c)=='g' ? '\057' : \ (c)=='h' ? '\026' : \ (c)=='i' ? '\005' : \ (c)=='j' ? '\025' : \ (c)=='k' ? '\013' : \ (c)=='l' ? '\014' : \ (c)=='m' ? '\015' : \ (c)=='n' ? '\016' : \ (c)=='o' ? '\017' : \ (c)=='p' ? '\020' : \ (c)=='q' ? '\021' : \ (c)=='r' ? '\022' : \ (c)=='s' ? '\023' : \ (c)=='t' ? '\074' : \ (c)=='u' ? '\075' : \ (c)=='v' ? '\062' : \ (c)=='w' ? '\046' : \ (c)=='x' ? '\030' : \ (c)=='y' ? '\031' : \ (c)=='z' ? '\077' : \ (c)=='A' ? '\001' : \ (c)=='B' ? '\002' : \ (c)=='C' ? '\003' : \ (c)=='D' ? '\067' : \ (c)=='E' ? '\055' : \ (c)=='F' ? '\056' : \ (c)=='G' ? '\057' : \ (c)=='H' ? '\026' : \ (c)=='I' ? '\005' : \ (c)=='J' ? '\025' : \ (c)=='K' ? '\013' : \ (c)=='L' ? '\014' : \ (c)=='M' ? '\015' : \ (c)=='N' ? '\016' : \ (c)=='O' ? '\017' : \ (c)=='P' ? '\020' : \ (c)=='Q' ? '\021' : \ (c)=='R' ? '\022' : \ (c)=='S' ? '\023' : \ (c)=='T' ? '\074' : \ (c)=='U' ? '\075' : \ (c)=='V' ? '\062' : \ (c)=='W' ? '\046' : \ (c)=='X' ? '\030' : \ (c)=='Y' ? '\031' : \ (c)=='Z' ? '\077' : \ (c)=='|' ? '\031' : \ (c)=='\\' ? '\034' : \ (c)=='^' ? '\036' : \ (c)&077) #else #define CONTROL(c) ((c)&037) #endif /* IS_EBCDIC_HOST */ #define ESC CONTROL('[') #define CSI ((unsigned char)'\233') #define CHAR_END_COMMAND 0x40000000 #if _OSK_MWC32 #define LSIGNAL(sig,func) os9_signal(sig,func) #else #define LSIGNAL(sig,func) signal(sig,func) #endif #if HAVE_SIGPROCMASK #if HAVE_SIGSET_T #else #undef HAVE_SIGPROCMASK #endif #endif #if HAVE_SIGPROCMASK #if HAVE_SIGEMPTYSET #else #undef sigemptyset #define sigemptyset(mp) *(mp) = 0 #endif #endif #define S_INTERRUPT 01 #define S_STOP 02 #define S_WINCH 04 #define ABORT_SIGS() (sigs & (S_INTERRUPT|S_STOP)) #define QUIT_OK 0 #define QUIT_ERROR 1 #define QUIT_INTERRUPT 2 #define QUIT_SAVED_STATUS (-1) #define FOLLOW_DESC 0 #define FOLLOW_NAME 1 /* filestate flags */ #define CH_CANSEEK 001 #define CH_KEEPOPEN 002 #define CH_POPENED 004 #define CH_HELPFILE 010 #define CH_NODATA 020 /* Special case for zero length files */ #define ch_zero() ((POSITION)0) #define FAKE_HELPFILE "@/\\less/\\help/\\file/\\@" #define FAKE_EMPTYFILE "@/\\less/\\empty/\\file/\\@" /* Flags for cvt_text */ #define CVT_TO_LC 01 /* Convert upper-case to lower-case */ #define CVT_BS 02 /* Do backspace processing */ #define CVT_CRLF 04 /* Remove CR after LF */ #define CVT_ANSI 010 /* Remove ANSI escape sequences */ #if HAVE_TIME_T #define time_type time_t #else #define time_type long #endif #include "funcs.h" /* Functions not included in funcs.h */ -void postoa(); -void linenumtoa(); -void inttoa(); +void postoa(POSITION num, char *buf); +void linenumtoa(LINENUM num, char *buf); +void inttoa(int num, char *buf); Index: head/contrib/less/lessecho.c =================================================================== --- head/contrib/less/lessecho.c (revision 316338) +++ head/contrib/less/lessecho.c (revision 316339) @@ -1,271 +1,267 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * lessecho [-ox] [-cx] [-pn] [-dn] [-a] file ... * Simply echos its filename arguments on standard output. * But any argument containing spaces is enclosed in quotes. * * -ox Specifies "x" to be the open quote character. * -cx Specifies "x" to be the close quote character. * -pn Specifies "n" to be the open quote character, as an integer. * -dn Specifies "n" to be the close quote character, as an integer. * -mx Specifies "x" to be a metachar. * -nn Specifies "n" to be a metachar, as an integer. * -ex Specifies "x" to be the escape char for metachars. * -fn Specifies "x" to be the escape char for metachars, as an integer. * -a Specifies that all arguments are to be quoted. * The default is that only arguments containing spaces are quoted. */ #include "less.h" static char *version = "$Revision: 1.15 $"; static int quote_all = 0; static char openquote = '"'; static char closequote = '"'; static char *meta_escape = "\\"; static char meta_escape_buf[2]; static char metachars[64] = ""; static int num_metachars = 0; static void -pr_usage() +pr_usage(void) { fprintf(stderr, "usage: lessecho [-ox] [-cx] [-pn] [-dn] [-mx] [-nn] [-ex] [-fn] [-a] file ...\n"); } static void -pr_version() +pr_version(void) { char *p; char buf[10]; char *pbuf = buf; for (p = version; *p != ' '; p++) if (*p == '\0') return; for (p++; *p != '$' && *p != ' ' && *p != '\0'; p++) *pbuf++ = *p; *pbuf = '\0'; printf("%s\n", buf); } static void -pr_error(s) - char *s; +pr_error(char *s) { fprintf(stderr, "%s\n", s); exit(1); } static long -lstrtol(s, radix, pend) - char *s; - int radix; - char **pend; +lstrtol(char *s, int radix, char **pend) { int v; int neg = 0; long n = 0; /* Skip leading white space. */ while (*s == ' ' || *s == '\t') s++; /* Check for a leading + or -. */ if (*s == '-') { neg = 1; s++; } else if (*s == '+') { s++; } /* Determine radix if caller does not specify. */ if (radix == 0) { radix = 10; if (*s == '0') { switch (*++s) { case 'x': radix = 16; s++; break; default: radix = 8; break; } } } /* Parse the digits of the number. */ for (;;) { if (*s >= '0' && *s <= '9') v = *s - '0'; else if (*s >= 'a' && *s <= 'f') v = *s - 'a' + 10; else if (*s >= 'A' && *s <= 'F') v = *s - 'A' + 10; else break; if (v >= radix) break; n = n * radix + v; s++; } if (pend != NULL) { /* Skip trailing white space. */ while (*s == ' ' || *s == '\t') s++; *pend = s; } if (neg) return (-n); return (n); } #if !HAVE_STRCHR char * strchr(s, c) char *s; int c; { for ( ; *s != '\0'; s++) if (*s == c) return (s); if (c == '\0') return (s); return (NULL); } #endif int main(argc, argv) int argc; char *argv[]; { char *arg; char *s; int no_more_options; no_more_options = 0; while (--argc > 0) { arg = *++argv; if (*arg != '-' || no_more_options) break; switch (*++arg) { case 'a': quote_all = 1; break; case 'c': closequote = *++arg; break; case 'd': closequote = lstrtol(++arg, 0, &s); if (s == arg) pr_error("Missing number after -d"); break; case 'e': if (strcmp(++arg, "-") == 0) meta_escape = ""; else meta_escape = arg; break; case 'f': meta_escape_buf[0] = lstrtol(++arg, 0, &s); meta_escape = meta_escape_buf; if (s == arg) pr_error("Missing number after -f"); break; case 'o': openquote = *++arg; break; case 'p': openquote = lstrtol(++arg, 0, &s); if (s == arg) pr_error("Missing number after -p"); break; case 'm': metachars[num_metachars++] = *++arg; metachars[num_metachars] = '\0'; break; case 'n': metachars[num_metachars++] = lstrtol(++arg, 0, &s); if (s == arg) pr_error("Missing number after -n"); metachars[num_metachars] = '\0'; break; case '?': pr_usage(); return (0); case '-': if (*++arg == '\0') { no_more_options = 1; break; } if (strcmp(arg, "version") == 0) { pr_version(); return (0); } if (strcmp(arg, "help") == 0) { pr_usage(); return (0); } pr_error("Invalid option after --"); default: pr_error("Invalid option letter"); } } while (argc-- > 0) { int has_meta = 0; arg = *argv++; for (s = arg; *s != '\0'; s++) { if (strchr(metachars, *s) != NULL) { has_meta = 1; break; } } if (quote_all || (has_meta && strlen(meta_escape) == 0)) printf("%c%s%c", openquote, arg, closequote); else { for (s = arg; *s != '\0'; s++) { if (strchr(metachars, *s) != NULL) printf("%s", meta_escape); printf("%c", *s); } } if (argc > 0) printf(" "); else printf("\n"); } return (0); } Index: head/contrib/less/lesskey.c =================================================================== --- head/contrib/less/lesskey.c (revision 316338) +++ head/contrib/less/lesskey.c (revision 316339) @@ -1,874 +1,851 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * lesskey [-o output] [input] * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * Make a .less file. * If no input file is specified, standard input is used. * If no output file is specified, $HOME/.less is used. * * The .less file is used to specify (to "less") user-defined * key bindings. Basically any sequence of 1 to MAX_CMDLEN * keystrokes may be bound to an existing less function. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The input file is an ascii file consisting of a * sequence of lines of the form: * string action [chars] * * "string" is a sequence of command characters which form * the new user-defined command. The command * characters may be: * 1. The actual character itself. * 2. A character preceded by ^ to specify a * control character (e.g. ^X means control-X). * 3. A backslash followed by one to three octal digits * to specify a character by its octal value. * 4. A backslash followed by b, e, n, r or t * to specify \b, ESC, \n, \r or \t, respectively. * 5. Any character (other than those mentioned above) preceded * by a \ to specify the character itself (characters which * must be preceded by \ include ^, \, and whitespace. * "action" is the name of a "less" action, from the table below. * "chars" is an optional sequence of characters which is treated * as keyboard input after the command is executed. * * Blank lines and lines which start with # are ignored, * except for the special control lines: * #command Signals the beginning of the command * keys section. * #line-edit Signals the beginning of the line-editing * keys section. * #env Signals the beginning of the environment * variable section. * #stop Stops command parsing in less; * causes all default keys to be disabled. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * The output file is a non-ascii file, consisting of a header, * one or more sections, and a trailer. * Each section begins with a section header, a section length word * and the section data. Normally there are three sections: * CMD_SECTION Definition of command keys. * EDIT_SECTION Definition of editing keys. * END_SECTION A special section header, with no * length word or section data. * * Section data consists of zero or more byte sequences of the form: * string <0> * or * string <0> chars <0> * * "string" is the command string. * "<0>" is one null byte. * "" is one byte containing the action code (the A_xxx value). * If action is ORed with A_EXTRA, the action byte is followed * by the null-terminated "chars" string. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "less.h" #include "lesskey.h" #include "cmd.h" struct cmdname { char *cn_name; int cn_action; }; struct cmdname cmdnames[] = { { "back-bracket", A_B_BRACKET }, { "back-line", A_B_LINE }, { "back-line-force", A_BF_LINE }, { "back-screen", A_B_SCREEN }, { "back-scroll", A_B_SCROLL }, { "back-search", A_B_SEARCH }, { "back-window", A_B_WINDOW }, { "debug", A_DEBUG }, { "digit", A_DIGIT }, { "display-flag", A_DISP_OPTION }, { "display-option", A_DISP_OPTION }, { "end", A_GOEND }, { "examine", A_EXAMINE }, { "filter", A_FILTER }, { "first-cmd", A_FIRSTCMD }, { "firstcmd", A_FIRSTCMD }, { "flush-repaint", A_FREPAINT }, { "forw-bracket", A_F_BRACKET }, { "forw-forever", A_F_FOREVER }, { "forw-until-hilite", A_F_UNTIL_HILITE }, { "forw-line", A_F_LINE }, { "forw-line-force", A_FF_LINE }, { "forw-screen", A_F_SCREEN }, { "forw-screen-force", A_FF_SCREEN }, { "forw-scroll", A_F_SCROLL }, { "forw-search", A_F_SEARCH }, { "forw-window", A_F_WINDOW }, { "goto-end", A_GOEND }, { "goto-end-buffered", A_GOEND_BUF }, { "goto-line", A_GOLINE }, { "goto-mark", A_GOMARK }, { "help", A_HELP }, { "index-file", A_INDEX_FILE }, { "invalid", A_UINVALID }, { "left-scroll", A_LSHIFT }, { "next-file", A_NEXT_FILE }, { "next-tag", A_NEXT_TAG }, { "noaction", A_NOACTION }, { "percent", A_PERCENT }, { "pipe", A_PIPE }, { "prev-file", A_PREV_FILE }, { "prev-tag", A_PREV_TAG }, { "quit", A_QUIT }, { "remove-file", A_REMOVE_FILE }, { "repaint", A_REPAINT }, { "repaint-flush", A_FREPAINT }, { "repeat-search", A_AGAIN_SEARCH }, { "repeat-search-all", A_T_AGAIN_SEARCH }, { "reverse-search", A_REVERSE_SEARCH }, { "reverse-search-all", A_T_REVERSE_SEARCH }, { "right-scroll", A_RSHIFT }, { "set-mark", A_SETMARK }, { "shell", A_SHELL }, { "status", A_STAT }, { "toggle-flag", A_OPT_TOGGLE }, { "toggle-option", A_OPT_TOGGLE }, { "undo-hilite", A_UNDO_SEARCH }, { "version", A_VERSION }, { "visual", A_VISUAL }, { NULL, 0 } }; struct cmdname editnames[] = { { "back-complete", EC_B_COMPLETE }, { "backspace", EC_BACKSPACE }, { "delete", EC_DELETE }, { "down", EC_DOWN }, { "end", EC_END }, { "expand", EC_EXPAND }, { "forw-complete", EC_F_COMPLETE }, { "home", EC_HOME }, { "insert", EC_INSERT }, { "invalid", EC_UINVALID }, { "kill-line", EC_LINEKILL }, { "abort", EC_ABORT }, { "left", EC_LEFT }, { "literal", EC_LITERAL }, { "right", EC_RIGHT }, { "up", EC_UP }, { "word-backspace", EC_W_BACKSPACE }, { "word-delete", EC_W_DELETE }, { "word-left", EC_W_LEFT }, { "word-right", EC_W_RIGHT }, { NULL, 0 } }; struct table { struct cmdname *names; char *pbuffer; char buffer[MAX_USERCMD]; }; struct table cmdtable; struct table edittable; struct table vartable; struct table *currtable = &cmdtable; char fileheader[] = { C0_LESSKEY_MAGIC, C1_LESSKEY_MAGIC, C2_LESSKEY_MAGIC, C3_LESSKEY_MAGIC }; char filetrailer[] = { C0_END_LESSKEY_MAGIC, C1_END_LESSKEY_MAGIC, C2_END_LESSKEY_MAGIC }; char cmdsection[1] = { CMD_SECTION }; char editsection[1] = { EDIT_SECTION }; char varsection[1] = { VAR_SECTION }; char endsection[1] = { END_SECTION }; char *infile = NULL; char *outfile = NULL ; int linenum; int errors; +static void lk_error(char *s); + extern char version[]; void -usage() +usage(void) { fprintf(stderr, "usage: lesskey [-o output] [input]\n"); exit(1); } char * -mkpathname(dirname, filename) - char *dirname; - char *filename; +mkpathname(char *dirname, char *filename) { char *pathname; pathname = calloc(strlen(dirname) + strlen(filename) + 2, sizeof(char)); strcpy(pathname, dirname); strcat(pathname, PATHNAME_SEP); strcat(pathname, filename); return (pathname); } /* * Figure out the name of a default file (in the user's HOME directory). */ char * -homefile(filename) - char *filename; +homefile(char *filename) { char *p; char *pathname; if ((p = getenv("HOME")) != NULL && *p != '\0') pathname = mkpathname(p, filename); #if OS2 else if ((p = getenv("INIT")) != NULL && *p != '\0') pathname = mkpathname(p, filename); #endif else { fprintf(stderr, "cannot find $HOME - using current directory\n"); pathname = mkpathname(".", filename); } return (pathname); } /* * Parse command line arguments. */ void -parse_args(argc, argv) - int argc; - char **argv; +parse_args(int argc, char **argv) { char *arg; outfile = NULL; while (--argc > 0) { arg = *++argv; if (arg[0] != '-') /* Arg does not start with "-"; it's not an option. */ break; if (arg[1] == '\0') /* "-" means standard input. */ break; if (arg[1] == '-' && arg[2] == '\0') { /* "--" means end of options. */ argc--; argv++; break; } switch (arg[1]) { case '-': if (strncmp(arg, "--output", 8) == 0) { if (arg[8] == '\0') outfile = &arg[8]; else if (arg[8] == '=') outfile = &arg[9]; else usage(); goto opt_o; } if (strcmp(arg, "--version") == 0) { goto opt_V; } usage(); break; case 'o': outfile = &argv[0][2]; opt_o: if (*outfile == '\0') { if (--argc <= 0) usage(); outfile = *(++argv); } break; case 'V': opt_V: printf("lesskey version %s\n", version); exit(0); default: usage(); } } if (argc > 1) usage(); /* * Open the input file, or use DEF_LESSKEYINFILE if none specified. */ if (argc > 0) infile = *argv; else infile = homefile(DEF_LESSKEYINFILE); } /* * Initialize data structures. */ void -init_tables() +init_tables(void) { cmdtable.names = cmdnames; cmdtable.pbuffer = cmdtable.buffer; edittable.names = editnames; edittable.pbuffer = edittable.buffer; vartable.names = NULL; vartable.pbuffer = vartable.buffer; } /* * Parse one character of a string. */ char * -tstr(pp, xlate) - char **pp; - int xlate; +tstr(char **pp, int xlate) { - register char *p; - register char ch; - register int i; + char *p; + char ch; + int i; static char buf[10]; static char tstr_control_k[] = { SK_SPECIAL_KEY, SK_CONTROL_K, 6, 1, 1, 1, '\0' }; p = *pp; switch (*p) { case '\\': ++p; switch (*p) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': /* * Parse an octal number. */ ch = 0; i = 0; do ch = 8*ch + (*p - '0'); while (*++p >= '0' && *p <= '7' && ++i < 3); *pp = p; if (xlate && ch == CONTROL('K')) return tstr_control_k; buf[0] = ch; buf[1] = '\0'; return (buf); case 'b': *pp = p+1; return ("\b"); case 'e': *pp = p+1; buf[0] = ESC; buf[1] = '\0'; return (buf); case 'n': *pp = p+1; return ("\n"); case 'r': *pp = p+1; return ("\r"); case 't': *pp = p+1; return ("\t"); case 'k': if (xlate) { switch (*++p) { case 'u': ch = SK_UP_ARROW; break; case 'd': ch = SK_DOWN_ARROW; break; case 'r': ch = SK_RIGHT_ARROW; break; case 'l': ch = SK_LEFT_ARROW; break; case 'U': ch = SK_PAGE_UP; break; case 'D': ch = SK_PAGE_DOWN; break; case 'h': ch = SK_HOME; break; case 'e': ch = SK_END; break; case 'x': ch = SK_DELETE; break; default: - error("illegal char after \\k"); + lk_error("illegal char after \\k"); *pp = p+1; return (""); } *pp = p+1; buf[0] = SK_SPECIAL_KEY; buf[1] = ch; buf[2] = 6; buf[3] = 1; buf[4] = 1; buf[5] = 1; buf[6] = '\0'; return (buf); } /* FALLTHRU */ default: /* * Backslash followed by any other char * just means that char. */ *pp = p+1; buf[0] = *p; buf[1] = '\0'; if (xlate && buf[0] == CONTROL('K')) return tstr_control_k; return (buf); } case '^': /* * Caret means CONTROL. */ *pp = p+2; buf[0] = CONTROL(p[1]); buf[1] = '\0'; if (buf[0] == CONTROL('K')) return tstr_control_k; return (buf); } *pp = p+1; buf[0] = *p; buf[1] = '\0'; if (xlate && buf[0] == CONTROL('K')) return tstr_control_k; return (buf); } /* * Skip leading spaces in a string. */ public char * -skipsp(s) - register char *s; +skipsp(char *s) { while (*s == ' ' || *s == '\t') s++; return (s); } /* * Skip non-space characters in a string. */ public char * -skipnsp(s) - register char *s; +skipnsp(char *s) { while (*s != '\0' && *s != ' ' && *s != '\t') s++; return (s); } /* * Clean up an input line: * strip off the trailing newline & any trailing # comment. */ char * -clean_line(s) - char *s; +clean_line(char *s) { - register int i; + int i; s = skipsp(s); for (i = 0; s[i] != '\n' && s[i] != '\r' && s[i] != '\0'; i++) if (s[i] == '#' && (i == 0 || s[i-1] != '\\')) break; s[i] = '\0'; return (s); } /* * Add a byte to the output command table. */ void -add_cmd_char(c) - int c; +add_cmd_char(int c) { if (currtable->pbuffer >= currtable->buffer + MAX_USERCMD) { - error("too many commands"); + lk_error("too many commands"); exit(1); } *(currtable->pbuffer)++ = c; } /* * Add a string to the output command table. */ void -add_cmd_str(s) - char *s; +add_cmd_str(char *s) { for ( ; *s != '\0'; s++) add_cmd_char(*s); } /* * See if we have a special "control" line. */ int -control_line(s) - char *s; +control_line(char *s) { #define PREFIX(str,pat) (strncmp(str,pat,strlen(pat)) == 0) if (PREFIX(s, "#line-edit")) { currtable = &edittable; return (1); } if (PREFIX(s, "#command")) { currtable = &cmdtable; return (1); } if (PREFIX(s, "#env")) { currtable = &vartable; return (1); } if (PREFIX(s, "#stop")) { add_cmd_char('\0'); add_cmd_char(A_END_LIST); return (1); } return (0); } /* * Output some bytes. */ void -fputbytes(fd, buf, len) - FILE *fd; - char *buf; - int len; +fputbytes(FILE *fd, char *buf, int len) { while (len-- > 0) { fwrite(buf, sizeof(char), 1, fd); buf++; } } /* * Output an integer, in special KRADIX form. */ void -fputint(fd, val) - FILE *fd; - unsigned int val; +fputint(FILE *fd, unsigned int val) { char c; if (val >= KRADIX*KRADIX) { fprintf(stderr, "error: integer too big (%d > %d)\n", val, KRADIX*KRADIX); exit(1); } c = val % KRADIX; fwrite(&c, sizeof(char), 1, fd); c = val / KRADIX; fwrite(&c, sizeof(char), 1, fd); } /* * Find an action, given the name of the action. */ int -findaction(actname) - char *actname; +findaction(char *actname) { int i; for (i = 0; currtable->names[i].cn_name != NULL; i++) if (strcmp(currtable->names[i].cn_name, actname) == 0) return (currtable->names[i].cn_action); - error("unknown action"); + lk_error("unknown action"); return (A_INVALID); } - void -error(s) - char *s; + static void +lk_error(char *s) { fprintf(stderr, "line %d: %s\n", linenum, s); errors++; } void -parse_cmdline(p) - char *p; +parse_cmdline(char *p) { int cmdlen; char *actname; int action; char *s; char c; /* * Parse the command string and store it in the current table. */ cmdlen = 0; do { s = tstr(&p, 1); cmdlen += (int) strlen(s); if (cmdlen > MAX_CMDLEN) - error("command too long"); + lk_error("command too long"); else add_cmd_str(s); } while (*p != ' ' && *p != '\t' && *p != '\0'); /* * Terminate the command string with a null byte. */ add_cmd_char('\0'); /* * Skip white space between the command string * and the action name. * Terminate the action name with a null byte. */ p = skipsp(p); if (*p == '\0') { - error("missing action"); + lk_error("missing action"); return; } actname = p; p = skipnsp(p); c = *p; *p = '\0'; /* * Parse the action name and store it in the current table. */ action = findaction(actname); /* * See if an extra string follows the action name. */ *p = c; p = skipsp(p); if (*p == '\0') { add_cmd_char(action); } else { /* * OR the special value A_EXTRA into the action byte. * Put the extra string after the action byte. */ add_cmd_char(action | A_EXTRA); while (*p != '\0') add_cmd_str(tstr(&p, 0)); add_cmd_char('\0'); } } void -parse_varline(p) - char *p; +parse_varline(char *p) { char *s; do { s = tstr(&p, 0); add_cmd_str(s); } while (*p != ' ' && *p != '\t' && *p != '=' && *p != '\0'); /* * Terminate the variable name with a null byte. */ add_cmd_char('\0'); p = skipsp(p); if (*p++ != '=') { - error("missing ="); + lk_error("missing ="); return; } add_cmd_char(EV_OK|A_EXTRA); p = skipsp(p); while (*p != '\0') { s = tstr(&p, 0); add_cmd_str(s); } add_cmd_char('\0'); } /* * Parse a line from the lesskey file. */ void -parse_line(line) - char *line; +parse_line(char *line) { char *p; /* * See if it is a control line. */ if (control_line(line)) return; /* * Skip leading white space. * Replace the final newline with a null byte. * Ignore blank lines and comments. */ p = clean_line(line); if (*p == '\0') return; if (currtable == &vartable) parse_varline(p); else parse_cmdline(p); } int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { FILE *desc; FILE *out; char line[1024]; #ifdef WIN32 if (getenv("HOME") == NULL) { /* * If there is no HOME environment variable, * try the concatenation of HOMEDRIVE + HOMEPATH. */ char *drive = getenv("HOMEDRIVE"); char *path = getenv("HOMEPATH"); if (drive != NULL && path != NULL) { char *env = (char *) calloc(strlen(drive) + strlen(path) + 6, sizeof(char)); strcpy(env, "HOME="); strcat(env, drive); strcat(env, path); putenv(env); } } #endif /* WIN32 */ /* * Process command line arguments. */ parse_args(argc, argv); init_tables(); /* * Open the input file. */ if (strcmp(infile, "-") == 0) desc = stdin; else if ((desc = fopen(infile, "r")) == NULL) { #if HAVE_PERROR perror(infile); #else fprintf(stderr, "Cannot open %s\n", infile); #endif usage(); } /* * Read and parse the input file, one line at a time. */ errors = 0; linenum = 0; while (fgets(line, sizeof(line), desc) != NULL) { ++linenum; parse_line(line); } /* * Write the output file. * If no output file was specified, use "$HOME/.less" */ if (errors > 0) { fprintf(stderr, "%d errors; no output produced\n", errors); exit(1); } if (outfile == NULL) outfile = getenv("LESSKEY"); if (outfile == NULL) outfile = homefile(LESSKEYFILE); if ((out = fopen(outfile, "wb")) == NULL) { #if HAVE_PERROR perror(outfile); #else fprintf(stderr, "Cannot open %s\n", outfile); #endif exit(1); } /* File header */ fputbytes(out, fileheader, sizeof(fileheader)); /* Command key section */ fputbytes(out, cmdsection, sizeof(cmdsection)); fputint(out, cmdtable.pbuffer - cmdtable.buffer); fputbytes(out, (char *)cmdtable.buffer, cmdtable.pbuffer-cmdtable.buffer); /* Edit key section */ fputbytes(out, editsection, sizeof(editsection)); fputint(out, edittable.pbuffer - edittable.buffer); fputbytes(out, (char *)edittable.buffer, edittable.pbuffer-edittable.buffer); /* Environment variable section */ fputbytes(out, varsection, sizeof(varsection)); fputint(out, vartable.pbuffer - vartable.buffer); fputbytes(out, (char *)vartable.buffer, vartable.pbuffer-vartable.buffer); /* File trailer */ fputbytes(out, endsection, sizeof(endsection)); fputbytes(out, filetrailer, sizeof(filetrailer)); return (0); } Index: head/contrib/less/line.c =================================================================== --- head/contrib/less/line.c (revision 316338) +++ head/contrib/less/line.c (revision 316339) @@ -1,1257 +1,1222 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines to manipulate the "line buffer". * The line buffer holds a line of output as it is being built * in preparation for output to the screen. */ #include "less.h" #include "charset.h" static char *linebuf = NULL; /* Buffer which holds the current output line */ static char *attr = NULL; /* Extension of linebuf to hold attributes */ public int size_linebuf = 0; /* Size of line buffer (and attr buffer) */ static int cshift; /* Current left-shift of output line buffer */ public int hshift; /* Desired left-shift of output line buffer */ public int tabstops[TABSTOP_MAX] = { 0 }; /* Custom tabstops */ public int ntabstops = 1; /* Number of tabstops */ public int tabdefault = 8; /* Default repeated tabstops */ public POSITION highest_hilite; /* Pos of last hilite in file found so far */ static int curr; /* Index into linebuf */ static int column; /* Printable length, accounting for backspaces, etc. */ static int overstrike; /* Next char should overstrike previous char */ static int last_overstrike = AT_NORMAL; static int is_null_line; /* There is no current line */ static int lmargin; /* Left margin */ static LWCHAR pendc; static POSITION pendpos; static char *end_ansi_chars; static char *mid_ansi_chars; -static int attr_swidth(); -static int attr_ewidth(); -static int do_append(); +static int attr_swidth(int); +static int attr_ewidth(int); +static int do_append(LWCHAR, char *, POSITION); extern int sigs; extern int bs_mode; extern int linenums; extern int ctldisp; extern int twiddle; extern int binattr; extern int status_col; extern int auto_wrap, ignaw; extern int bo_s_width, bo_e_width; extern int ul_s_width, ul_e_width; extern int bl_s_width, bl_e_width; extern int so_s_width, so_e_width; extern int sc_width, sc_height; extern int utf_mode; extern POSITION start_attnpos; extern POSITION end_attnpos; static char mbc_buf[MAX_UTF_CHAR_LEN]; static int mbc_buf_len = 0; static int mbc_buf_index = 0; static POSITION mbc_pos; /* * Initialize from environment variables. */ public void -init_line() +init_line(void) { end_ansi_chars = lgetenv("LESSANSIENDCHARS"); if (end_ansi_chars == NULL || *end_ansi_chars == '\0') end_ansi_chars = "m"; mid_ansi_chars = lgetenv("LESSANSIMIDCHARS"); if (mid_ansi_chars == NULL || *mid_ansi_chars == '\0') mid_ansi_chars = "0123456789:;[?!\"'#%()*+ "; linebuf = (char *) ecalloc(LINEBUF_SIZE, sizeof(char)); attr = (char *) ecalloc(LINEBUF_SIZE, sizeof(char)); size_linebuf = LINEBUF_SIZE; } /* * Expand the line buffer. */ static int -expand_linebuf() +expand_linebuf(void) { /* Double the size of the line buffer. */ int new_size = size_linebuf * 2; /* Just realloc to expand the buffer, if we can. */ #if HAVE_REALLOC char *new_buf = (char *) realloc(linebuf, new_size); char *new_attr = (char *) realloc(attr, new_size); #else char *new_buf = (char *) calloc(new_size, sizeof(char)); char *new_attr = (char *) calloc(new_size, sizeof(char)); #endif if (new_buf == NULL || new_attr == NULL) { if (new_attr != NULL) free(new_attr); if (new_buf != NULL) free(new_buf); return 1; } #if HAVE_REALLOC /* * We realloc'd the buffers; they already have the old contents. */ #if 0 memset(new_buf + size_linebuf, 0, new_size - size_linebuf); memset(new_attr + size_linebuf, 0, new_size - size_linebuf); #endif #else /* * We just calloc'd the buffers; copy the old contents. */ memcpy(new_buf, linebuf, size_linebuf * sizeof(char)); memcpy(new_attr, attr, size_linebuf * sizeof(char)); free(attr); free(linebuf); #endif linebuf = new_buf; attr = new_attr; size_linebuf = new_size; return 0; } /* * Is a character ASCII? */ public int -is_ascii_char(ch) - LWCHAR ch; +is_ascii_char(LWCHAR ch) { return (ch <= 0x7F); } /* * Rewind the line buffer. */ public void -prewind() +prewind(void) { curr = 0; column = 0; cshift = 0; overstrike = 0; last_overstrike = AT_NORMAL; mbc_buf_len = 0; is_null_line = 0; pendc = '\0'; lmargin = 0; if (status_col) lmargin += 1; } /* * Insert the line number (of the given position) into the line buffer. */ public void -plinenum(pos) - POSITION pos; +plinenum(POSITION pos) { - register LINENUM linenum = 0; - register int i; + LINENUM linenum = 0; + int i; if (linenums == OPT_ONPLUS) { /* * Get the line number and put it in the current line. * {{ Note: since find_linenum calls forw_raw_line, * it may seek in the input file, requiring the caller * of plinenum to re-seek if necessary. }} * {{ Since forw_raw_line modifies linebuf, we must * do this first, before storing anything in linebuf. }} */ linenum = find_linenum(pos); } /* * Display a status column if the -J option is set. */ if (status_col) { linebuf[curr] = ' '; if (start_attnpos != NULL_POSITION && pos >= start_attnpos && pos < end_attnpos) attr[curr] = AT_NORMAL|AT_HILITE; else attr[curr] = AT_NORMAL; curr++; column++; } /* * Display the line number at the start of each line * if the -N option is set. */ if (linenums == OPT_ONPLUS) { char buf[INT_STRLEN_BOUND(pos) + 2]; int n; linenumtoa(linenum, buf); n = (int) strlen(buf); if (n < MIN_LINENUM_WIDTH) n = MIN_LINENUM_WIDTH; sprintf(linebuf+curr, "%*s ", n, buf); n++; /* One space after the line number. */ for (i = 0; i < n; i++) attr[curr+i] = AT_NORMAL; curr += n; column += n; lmargin += n; } /* * Append enough spaces to bring us to the lmargin. */ while (column < lmargin) { linebuf[curr] = ' '; attr[curr++] = AT_NORMAL; column++; } } /* * Shift the input line left. * This means discarding N printable chars at the start of the buffer. */ static void -pshift(shift) - int shift; +pshift(int shift) { LWCHAR prev_ch = 0; unsigned char c; int shifted = 0; int to; int from; int len; int width; int prev_attr; int next_attr; if (shift > column - lmargin) shift = column - lmargin; if (shift > curr - lmargin) shift = curr - lmargin; to = from = lmargin; /* * We keep on going when shifted == shift * to get all combining chars. */ while (shifted <= shift && from < curr) { c = linebuf[from]; if (ctldisp == OPT_ONPLUS && IS_CSI_START(c)) { /* Keep cumulative effect. */ linebuf[to] = c; attr[to++] = attr[from++]; while (from < curr && linebuf[from]) { linebuf[to] = linebuf[from]; attr[to++] = attr[from]; if (!is_ansi_middle(linebuf[from++])) break; } continue; } width = 0; if (!IS_ASCII_OCTET(c) && utf_mode) { /* Assumes well-formedness validation already done. */ LWCHAR ch; len = utf_len(c); if (from + len > curr) break; ch = get_wchar(linebuf + from); if (!is_composing_char(ch) && !is_combining_char(prev_ch, ch)) width = is_wide_char(ch) ? 2 : 1; prev_ch = ch; } else { len = 1; if (c == '\b') /* XXX - Incorrect if several '\b' in a row. */ width = (utf_mode && is_wide_char(prev_ch)) ? -2 : -1; else if (!control_char(c)) width = 1; prev_ch = 0; } if (width == 2 && shift - shifted == 1) { /* Should never happen when called by pshift_all(). */ attr[to] = attr[from]; /* * Assume a wide_char will never be the first half of a * combining_char pair, so reset prev_ch in case we're * followed by a '\b'. */ prev_ch = linebuf[to++] = ' '; from += len; shifted++; continue; } /* Adjust width for magic cookies. */ prev_attr = (to > 0) ? attr[to-1] : AT_NORMAL; next_attr = (from + len < curr) ? attr[from + len] : prev_attr; if (!is_at_equiv(attr[from], prev_attr) && !is_at_equiv(attr[from], next_attr)) { width += attr_swidth(attr[from]); if (from + len < curr) width += attr_ewidth(attr[from]); if (is_at_equiv(prev_attr, next_attr)) { width += attr_ewidth(prev_attr); if (from + len < curr) width += attr_swidth(next_attr); } } if (shift - shifted < width) break; from += len; shifted += width; if (shifted < 0) shifted = 0; } while (from < curr) { linebuf[to] = linebuf[from]; attr[to++] = attr[from++]; } curr = to; column -= shifted; cshift += shifted; } /* * */ public void -pshift_all() +pshift_all(void) { pshift(column); } /* * Return the printing width of the start (enter) sequence * for a given character attribute. */ static int -attr_swidth(a) - int a; +attr_swidth(int a) { int w = 0; a = apply_at_specials(a); if (a & AT_UNDERLINE) w += ul_s_width; if (a & AT_BOLD) w += bo_s_width; if (a & AT_BLINK) w += bl_s_width; if (a & AT_STANDOUT) w += so_s_width; return w; } /* * Return the printing width of the end (exit) sequence * for a given character attribute. */ static int -attr_ewidth(a) - int a; +attr_ewidth(int a) { int w = 0; a = apply_at_specials(a); if (a & AT_UNDERLINE) w += ul_e_width; if (a & AT_BOLD) w += bo_e_width; if (a & AT_BLINK) w += bl_e_width; if (a & AT_STANDOUT) w += so_e_width; return w; } /* * Return the printing width of a given character and attribute, * if the character were added to the current position in the line buffer. * Adding a character with a given attribute may cause an enter or exit * attribute sequence to be inserted, so this must be taken into account. */ static int -pwidth(ch, a, prev_ch) - LWCHAR ch; - int a; - LWCHAR prev_ch; +pwidth(LWCHAR ch, int a, LWCHAR prev_ch) { int w; if (ch == '\b') /* * Backspace moves backwards one or two positions. * XXX - Incorrect if several '\b' in a row. */ return (utf_mode && is_wide_char(prev_ch)) ? -2 : -1; if (!utf_mode || is_ascii_char(ch)) { if (control_char((char)ch)) { /* * Control characters do unpredictable things, * so we don't even try to guess; say it doesn't move. * This can only happen if the -r flag is in effect. */ return (0); } } else { if (is_composing_char(ch) || is_combining_char(prev_ch, ch)) { /* * Composing and combining chars take up no space. * * Some terminals, upon failure to compose a * composing character with the character(s) that * precede(s) it will actually take up one column * for the composing character; there isn't much * we could do short of testing the (complex) * composition process ourselves and printing * a binary representation when it fails. */ return (0); } } /* * Other characters take one or two columns, * plus the width of any attribute enter/exit sequence. */ w = 1; if (is_wide_char(ch)) w++; if (curr > 0 && !is_at_equiv(attr[curr-1], a)) w += attr_ewidth(attr[curr-1]); if ((apply_at_specials(a) != AT_NORMAL) && (curr == 0 || !is_at_equiv(attr[curr-1], a))) w += attr_swidth(a); return (w); } /* * Delete to the previous base character in the line buffer. * Return 1 if one is found. */ static int -backc() +backc(void) { LWCHAR prev_ch; - char *p = linebuf + curr; + constant char *p = linebuf + curr; LWCHAR ch = step_char(&p, -1, linebuf + lmargin); int width; /* This assumes that there is no '\b' in linebuf. */ while ( curr > lmargin && column > lmargin && (!(attr[curr - 1] & (AT_ANSI|AT_BINARY)))) { curr = (int) (p - linebuf); prev_ch = step_char(&p, -1, linebuf + lmargin); width = pwidth(ch, attr[curr], prev_ch); column -= width; if (width > 0) return 1; ch = prev_ch; } return 0; } /* * Are we currently within a recognized ANSI escape sequence? */ static int -in_ansi_esc_seq() +in_ansi_esc_seq(void) { - char *p; + constant char *p; /* * Search backwards for either an ESC (which means we ARE in a seq); * or an end char (which means we're NOT in a seq). */ for (p = &linebuf[curr]; p > linebuf; ) { LWCHAR ch = step_char(&p, -1, linebuf); if (IS_CSI_START(ch)) return (1); if (!is_ansi_middle(ch)) return (0); } return (0); } /* * Is a character the end of an ANSI escape sequence? */ public int -is_ansi_end(ch) - LWCHAR ch; +is_ansi_end(LWCHAR ch) { if (!is_ascii_char(ch)) return (0); return (strchr(end_ansi_chars, (char) ch) != NULL); } /* * */ public int -is_ansi_middle(ch) - LWCHAR ch; +is_ansi_middle(LWCHAR ch) { if (!is_ascii_char(ch)) return (0); if (is_ansi_end(ch)) return (0); return (strchr(mid_ansi_chars, (char) ch) != NULL); } /* * Append a character and attribute to the line buffer. */ #define STORE_CHAR(ch,a,rep,pos) \ do { \ if (store_char((ch),(a),(rep),(pos))) return (1); \ } while (0) static int -store_char(ch, a, rep, pos) - LWCHAR ch; - int a; - char *rep; - POSITION pos; +store_char(LWCHAR ch, int a, char *rep, POSITION pos) { int w; int replen; char cs; w = (a & (AT_UNDERLINE|AT_BOLD)); /* Pre-use w. */ if (w != AT_NORMAL) last_overstrike = w; #if HILITE_SEARCH { int matches; if (is_hilited(pos, pos+1, 0, &matches)) { /* * This character should be highlighted. * Override the attribute passed in. */ if (a != AT_ANSI) { if (highest_hilite != NULL_POSITION && pos > highest_hilite) highest_hilite = pos; a |= AT_HILITE; } } } #endif if (ctldisp == OPT_ONPLUS && in_ansi_esc_seq()) { if (!is_ansi_end(ch) && !is_ansi_middle(ch)) { /* Remove whole unrecognized sequence. */ - char *p = &linebuf[curr]; + constant char *p = &linebuf[curr]; LWCHAR bch; do { bch = step_char(&p, -1, linebuf); } while (p > linebuf && !IS_CSI_START(bch)); curr = (int) (p - linebuf); return 0; } a = AT_ANSI; /* Will force re-AT_'ing around it. */ w = 0; } else if (ctldisp == OPT_ONPLUS && IS_CSI_START(ch)) { a = AT_ANSI; /* Will force re-AT_'ing around it. */ w = 0; } else { - char *p = &linebuf[curr]; + constant char *p = &linebuf[curr]; LWCHAR prev_ch = step_char(&p, -1, linebuf); w = pwidth(ch, a, prev_ch); } if (ctldisp != OPT_ON && column + w + attr_ewidth(a) > sc_width) /* * Won't fit on screen. */ return (1); if (rep == NULL) { cs = (char) ch; rep = &cs; replen = 1; } else { replen = utf_len(rep[0]); } if (curr + replen >= size_linebuf-6) { /* * Won't fit in line buffer. * Try to expand it. */ if (expand_linebuf()) return (1); } while (replen-- > 0) { linebuf[curr] = *rep++; attr[curr] = a; curr++; } column += w; return (0); } /* * Append a tab to the line buffer. * Store spaces to represent the tab. */ #define STORE_TAB(a,pos) \ do { if (store_tab((a),(pos))) return (1); } while (0) static int -store_tab(attr, pos) - int attr; - POSITION pos; +store_tab(int attr, POSITION pos) { int to_tab = column + cshift - lmargin; int i; if (ntabstops < 2 || to_tab >= tabstops[ntabstops-1]) to_tab = tabdefault - ((to_tab - tabstops[ntabstops-1]) % tabdefault); else { for (i = ntabstops - 2; i >= 0; i--) if (to_tab >= tabstops[i]) break; to_tab = tabstops[i+1] - to_tab; } if (column + to_tab - 1 + pwidth(' ', attr, 0) + attr_ewidth(attr) > sc_width) return 1; do { STORE_CHAR(' ', attr, " ", pos); } while (--to_tab > 0); return 0; } #define STORE_PRCHAR(c, pos) \ do { if (store_prchar((c), (pos))) return 1; } while (0) static int -store_prchar(c, pos) - LWCHAR c; - POSITION pos; +store_prchar(LWCHAR c, POSITION pos) { char *s; /* * Convert to printable representation. */ s = prchar(c); /* * Make sure we can get the entire representation * of the character on this line. */ if (column + (int) strlen(s) - 1 + pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width) return 1; for ( ; *s != 0; s++) STORE_CHAR(*s, AT_BINARY, NULL, pos); return 0; } static int -flush_mbc_buf(pos) - POSITION pos; +flush_mbc_buf(POSITION pos) { int i; for (i = 0; i < mbc_buf_index; i++) if (store_prchar(mbc_buf[i], pos)) return mbc_buf_index - i; return 0; } /* * Append a character to the line buffer. * Expand tabs into spaces, handle underlining, boldfacing, etc. * Returns 0 if ok, 1 if couldn't fit in buffer. */ public int -pappend(c, pos) - unsigned char c; - POSITION pos; +pappend(unsigned char c, POSITION pos) { int r; if (pendc) { if (c == '\r' && pendc == '\r') return (0); if (do_append(pendc, NULL, pendpos)) /* * Oops. We've probably lost the char which * was in pendc, since caller won't back up. */ return (1); pendc = '\0'; } if (c == '\r' && bs_mode == BS_SPECIAL) { if (mbc_buf_len > 0) /* utf_mode must be on. */ { /* Flush incomplete (truncated) sequence. */ r = flush_mbc_buf(mbc_pos); mbc_buf_index = r + 1; mbc_buf_len = 0; if (r) return (mbc_buf_index); } /* * Don't put the CR into the buffer until we see * the next char. If the next char is a newline, * discard the CR. */ pendc = c; pendpos = pos; return (0); } if (!utf_mode) { r = do_append(c, NULL, pos); } else { /* Perform strict validation in all possible cases. */ if (mbc_buf_len == 0) { retry: mbc_buf_index = 1; *mbc_buf = c; if (IS_ASCII_OCTET(c)) r = do_append(c, NULL, pos); else if (IS_UTF8_LEAD(c)) { mbc_buf_len = utf_len(c); mbc_pos = pos; return (0); } else /* UTF8_INVALID or stray UTF8_TRAIL */ r = flush_mbc_buf(pos); } else if (IS_UTF8_TRAIL(c)) { mbc_buf[mbc_buf_index++] = c; if (mbc_buf_index < mbc_buf_len) return (0); if (is_utf8_well_formed(mbc_buf, mbc_buf_index)) r = do_append(get_wchar(mbc_buf), mbc_buf, mbc_pos); else /* Complete, but not shortest form, sequence. */ mbc_buf_index = r = flush_mbc_buf(mbc_pos); mbc_buf_len = 0; } else { /* Flush incomplete (truncated) sequence. */ r = flush_mbc_buf(mbc_pos); mbc_buf_index = r + 1; mbc_buf_len = 0; /* Handle new char. */ if (!r) goto retry; } } /* * If we need to shift the line, do it. * But wait until we get to at least the middle of the screen, * so shifting it doesn't affect the chars we're currently * pappending. (Bold & underline can get messed up otherwise.) */ if (cshift < hshift && column > sc_width / 2) { linebuf[curr] = '\0'; pshift(hshift - cshift); } if (r) { /* How many chars should caller back up? */ r = (!utf_mode) ? 1 : mbc_buf_index; } return (r); } static int -do_append(ch, rep, pos) - LWCHAR ch; - char *rep; - POSITION pos; +do_append(LWCHAR ch, char *rep, POSITION pos) { - register int a; + int a; LWCHAR prev_ch; a = AT_NORMAL; if (ch == '\b') { if (bs_mode == BS_CONTROL) goto do_control_char; /* * A better test is needed here so we don't * backspace over part of the printed * representation of a binary character. */ if ( curr <= lmargin || column <= lmargin || (attr[curr - 1] & (AT_ANSI|AT_BINARY))) STORE_PRCHAR('\b', pos); else if (bs_mode == BS_NORMAL) STORE_CHAR(ch, AT_NORMAL, NULL, pos); else if (bs_mode == BS_SPECIAL) overstrike = backc(); return 0; } if (overstrike > 0) { /* * Overstrike the character at the current position * in the line buffer. This will cause either * underline (if a "_" is overstruck), * bold (if an identical character is overstruck), * or just deletion of the character in the buffer. */ overstrike = utf_mode ? -1 : 0; if (utf_mode) { /* To be correct, this must be a base character. */ prev_ch = get_wchar(linebuf + curr); } else { prev_ch = (unsigned char) linebuf[curr]; } a = attr[curr]; if (ch == prev_ch) { /* * Overstriking a char with itself means make it bold. * But overstriking an underscore with itself is * ambiguous. It could mean make it bold, or * it could mean make it underlined. * Use the previous overstrike to resolve it. */ if (ch == '_') { if ((a & (AT_BOLD|AT_UNDERLINE)) != AT_NORMAL) a |= (AT_BOLD|AT_UNDERLINE); else if (last_overstrike != AT_NORMAL) a |= last_overstrike; else a |= AT_BOLD; } else a |= AT_BOLD; } else if (ch == '_') { a |= AT_UNDERLINE; ch = prev_ch; rep = linebuf + curr; } else if (prev_ch == '_') { a |= AT_UNDERLINE; } /* Else we replace prev_ch, but we keep its attributes. */ } else if (overstrike < 0) { if ( is_composing_char(ch) || is_combining_char(get_wchar(linebuf + curr), ch)) /* Continuation of the same overstrike. */ a = last_overstrike; else overstrike = 0; } if (ch == '\t') { /* * Expand a tab into spaces. */ switch (bs_mode) { case BS_CONTROL: goto do_control_char; case BS_NORMAL: case BS_SPECIAL: STORE_TAB(a, pos); break; } } else if ((!utf_mode || is_ascii_char(ch)) && control_char((char)ch)) { do_control_char: if (ctldisp == OPT_ON || (ctldisp == OPT_ONPLUS && IS_CSI_START(ch))) { /* * Output as a normal character. */ STORE_CHAR(ch, AT_NORMAL, rep, pos); } else { STORE_PRCHAR((char) ch, pos); } } else if (utf_mode && ctldisp != OPT_ON && is_ubin_char(ch)) { char *s; s = prutfchar(ch); if (column + (int) strlen(s) - 1 + pwidth(' ', binattr, 0) + attr_ewidth(binattr) > sc_width) return (1); for ( ; *s != 0; s++) STORE_CHAR(*s, AT_BINARY, NULL, pos); } else { STORE_CHAR(ch, a, rep, pos); } return (0); } /* * */ public int -pflushmbc() +pflushmbc(void) { int r = 0; if (mbc_buf_len > 0) { /* Flush incomplete (truncated) sequence. */ r = flush_mbc_buf(mbc_pos); mbc_buf_len = 0; } return r; } /* * Terminate the line in the line buffer. */ public void -pdone(endline, forw) - int endline; - int forw; +pdone(int endline, int forw) { (void) pflushmbc(); if (pendc && (pendc != '\r' || !endline)) /* * If we had a pending character, put it in the buffer. * But discard a pending CR if we are at end of line * (that is, discard the CR in a CR/LF sequence). */ (void) do_append(pendc, NULL, pendpos); /* * Make sure we've shifted the line, if we need to. */ if (cshift < hshift) pshift(hshift - cshift); if (ctldisp == OPT_ONPLUS && is_ansi_end('m')) { /* Switch to normal attribute at end of line. */ char *p = "\033[m"; for ( ; *p != '\0'; p++) { linebuf[curr] = *p; attr[curr++] = AT_ANSI; } } /* * Add a newline if necessary, * and append a '\0' to the end of the line. * We output a newline if we're not at the right edge of the screen, * or if the terminal doesn't auto wrap, * or if this is really the end of the line AND the terminal ignores * a newline at the right edge. * (In the last case we don't want to output a newline if the terminal * doesn't ignore it since that would produce an extra blank line. * But we do want to output a newline if the terminal ignores it in case * the next line is blank. In that case the single newline output for * that blank line would be ignored!) */ if (column < sc_width || !auto_wrap || (endline && ignaw) || ctldisp == OPT_ON) { linebuf[curr] = '\n'; attr[curr] = AT_NORMAL; curr++; } else if (ignaw && column >= sc_width && forw) { /* * Terminals with "ignaw" don't wrap until they *really* need * to, i.e. when the character *after* the last one to fit on a * line is output. But they are too hard to deal with when they * get in the state where a full screen width of characters * have been output but the cursor is sitting on the right edge * instead of at the start of the next line. * So we nudge them into wrapping by outputting a space * character plus a backspace. But do this only if moving * forward; if we're moving backward and drawing this line at * the top of the screen, the space would overwrite the first * char on the next line. We don't need to do this "nudge" * at the top of the screen anyway. */ linebuf[curr] = ' '; attr[curr++] = AT_NORMAL; linebuf[curr] = '\b'; attr[curr++] = AT_NORMAL; } linebuf[curr] = '\0'; attr[curr] = AT_NORMAL; } /* * */ public void -set_status_col(c) - char c; +set_status_col(char c) { linebuf[0] = c; attr[0] = AT_NORMAL|AT_HILITE; } /* * Get a character from the current line. * Return the character as the function return value, * and the character attribute in *ap. */ public int -gline(i, ap) - register int i; - register int *ap; +gline(int i, int *ap) { if (is_null_line) { /* * If there is no current line, we pretend the line is * either "~" or "", depending on the "twiddle" flag. */ if (twiddle) { if (i == 0) { *ap = AT_BOLD; return '~'; } --i; } /* Make sure we're back to AT_NORMAL before the '\n'. */ *ap = AT_NORMAL; return i ? '\0' : '\n'; } *ap = attr[i]; return (linebuf[i] & 0xFF); } /* * Indicate that there is no current line. */ public void -null_line() +null_line(void) { is_null_line = 1; cshift = 0; } /* * Analogous to forw_line(), but deals with "raw lines": * lines which are not split for screen width. * {{ This is supposed to be more efficient than forw_line(). }} */ public POSITION -forw_raw_line(curr_pos, linep, line_lenp) - POSITION curr_pos; - char **linep; - int *line_lenp; +forw_raw_line(POSITION curr_pos, char **linep, int *line_lenp) { - register int n; - register int c; + int n; + int c; POSITION new_pos; if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || (c = ch_forw_get()) == EOI) return (NULL_POSITION); n = 0; for (;;) { if (c == '\n' || c == EOI || ABORT_SIGS()) { new_pos = ch_tell(); break; } if (n >= size_linebuf-1) { if (expand_linebuf()) { /* * Overflowed the input buffer. * Pretend the line ended here. */ new_pos = ch_tell() - 1; break; } } linebuf[n++] = c; c = ch_forw_get(); } linebuf[n] = '\0'; if (linep != NULL) *linep = linebuf; if (line_lenp != NULL) *line_lenp = n; return (new_pos); } /* * Analogous to back_line(), but deals with "raw lines". * {{ This is supposed to be more efficient than back_line(). }} */ public POSITION -back_raw_line(curr_pos, linep, line_lenp) - POSITION curr_pos; - char **linep; - int *line_lenp; +back_raw_line(POSITION curr_pos, char **linep, int *line_lenp) { - register int n; - register int c; + int n; + int c; POSITION new_pos; if (curr_pos == NULL_POSITION || curr_pos <= ch_zero() || ch_seek(curr_pos-1)) return (NULL_POSITION); n = size_linebuf; linebuf[--n] = '\0'; for (;;) { c = ch_back_get(); if (c == '\n' || ABORT_SIGS()) { /* * This is the newline ending the previous line. * We have hit the beginning of the line. */ new_pos = ch_tell() + 1; break; } if (c == EOI) { /* * We have hit the beginning of the file. * This must be the first line in the file. * This must, of course, be the beginning of the line. */ new_pos = ch_zero(); break; } if (n <= 0) { int old_size_linebuf = size_linebuf; char *fm; char *to; if (expand_linebuf()) { /* * Overflowed the input buffer. * Pretend the line ended here. */ new_pos = ch_tell() + 1; break; } /* * Shift the data to the end of the new linebuf. */ for (fm = linebuf + old_size_linebuf - 1, to = linebuf + size_linebuf - 1; fm >= linebuf; fm--, to--) *to = *fm; n = size_linebuf - old_size_linebuf; } linebuf[--n] = c; } if (linep != NULL) *linep = &linebuf[n]; if (line_lenp != NULL) *line_lenp = size_linebuf - 1 - n; return (new_pos); } Index: head/contrib/less/linenum.c =================================================================== --- head/contrib/less/linenum.c (revision 316338) +++ head/contrib/less/linenum.c (revision 316339) @@ -1,470 +1,464 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Code to handle displaying line numbers. * * Finding the line number of a given file position is rather tricky. * We don't want to just start at the beginning of the file and * count newlines, because that is slow for large files (and also * wouldn't work if we couldn't get to the start of the file; e.g. * if input is a long pipe). * * So we use the function add_lnum to cache line numbers. * We try to be very clever and keep only the more interesting * line numbers when we run out of space in our table. A line * number is more interesting than another when it is far from * other line numbers. For example, we'd rather keep lines * 100,200,300 than 100,101,300. 200 is more interesting than * 101 because 101 can be derived very cheaply from 100, while * 200 is more expensive to derive from 100. * * The function currline() returns the line number of a given * position in the file. As a side effect, it calls add_lnum * to cache the line number. Therefore currline is occasionally * called to make sure we cache line numbers often enough. */ #include "less.h" /* * Structure to keep track of a line number and the associated file position. * A doubly-linked circular list of line numbers is kept ordered by line number. */ struct linenum_info { struct linenum_info *next; /* Link to next in the list */ struct linenum_info *prev; /* Line to previous in the list */ POSITION pos; /* File position */ POSITION gap; /* Gap between prev and next */ LINENUM line; /* Line number */ }; /* * "gap" needs some explanation: the gap of any particular line number * is the distance between the previous one and the next one in the list. * ("Distance" means difference in file position.) In other words, the * gap of a line number is the gap which would be introduced if this * line number were deleted. It is used to decide which one to replace * when we have a new one to insert and the table is full. */ #define NPOOL 200 /* Size of line number pool */ #define LONGTIME (2) /* In seconds */ static struct linenum_info anchor; /* Anchor of the list */ static struct linenum_info *freelist; /* Anchor of the unused entries */ static struct linenum_info pool[NPOOL]; /* The pool itself */ static struct linenum_info *spare; /* We always keep one spare entry */ extern int linenums; extern int sigs; extern int sc_height; extern int screen_trashed; /* * Initialize the line number structures. */ public void -clr_linenum() +clr_linenum(void) { - register struct linenum_info *p; + struct linenum_info *p; /* * Put all the entries on the free list. * Leave one for the "spare". */ for (p = pool; p < &pool[NPOOL-2]; p++) p->next = p+1; pool[NPOOL-2].next = NULL; freelist = pool; spare = &pool[NPOOL-1]; /* * Initialize the anchor. */ anchor.next = anchor.prev = &anchor; anchor.gap = 0; anchor.pos = (POSITION)0; anchor.line = 1; } /* * Calculate the gap for an entry. */ static void -calcgap(p) - register struct linenum_info *p; +calcgap(struct linenum_info *p) { /* * Don't bother to compute a gap for the anchor. * Also don't compute a gap for the last one in the list. * The gap for that last one should be considered infinite, * but we never look at it anyway. */ if (p == &anchor || p->next == &anchor) return; p->gap = p->next->pos - p->prev->pos; } /* * Add a new line number to the cache. * The specified position (pos) should be the file position of the * FIRST character in the specified line. */ public void -add_lnum(linenum, pos) - LINENUM linenum; - POSITION pos; +add_lnum(LINENUM linenum, POSITION pos) { - register struct linenum_info *p; - register struct linenum_info *new; - register struct linenum_info *nextp; - register struct linenum_info *prevp; - register POSITION mingap; + struct linenum_info *p; + struct linenum_info *new; + struct linenum_info *nextp; + struct linenum_info *prevp; + POSITION mingap; /* * Find the proper place in the list for the new one. * The entries are sorted by position. */ for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next) if (p->line == linenum) /* We already have this one. */ return; nextp = p; prevp = p->prev; if (freelist != NULL) { /* * We still have free (unused) entries. * Use one of them. */ new = freelist; freelist = freelist->next; } else { /* * No free entries. * Use the "spare" entry. */ new = spare; spare = NULL; } /* * Fill in the fields of the new entry, * and insert it into the proper place in the list. */ new->next = nextp; new->prev = prevp; new->pos = pos; new->line = linenum; nextp->prev = new; prevp->next = new; /* * Recalculate gaps for the new entry and the neighboring entries. */ calcgap(new); calcgap(nextp); calcgap(prevp); if (spare == NULL) { /* * We have used the spare entry. * Scan the list to find the one with the smallest * gap, take it out and make it the spare. * We should never remove the last one, so stop when * we get to p->next == &anchor. This also avoids * looking at the gap of the last one, which is * not computed by calcgap. */ mingap = anchor.next->gap; for (p = anchor.next; p->next != &anchor; p = p->next) { if (p->gap <= mingap) { spare = p; mingap = p->gap; } } spare->next->prev = spare->prev; spare->prev->next = spare->next; } } /* * If we get stuck in a long loop trying to figure out the * line number, print a message to tell the user what we're doing. */ static void -longloopmessage() +longloopmessage(void) { ierror("Calculating line numbers", NULL_PARG); } static int loopcount; #if HAVE_TIME static time_type startime; #endif static void -longish() +longish(void) { #if HAVE_TIME if (loopcount >= 0 && ++loopcount > 100) { loopcount = 0; if (get_time() >= startime + LONGTIME) { longloopmessage(); loopcount = -1; } } #else if (loopcount >= 0 && ++loopcount > LONGLOOP) { longloopmessage(); loopcount = -1; } #endif } /* * Turn off line numbers because the user has interrupted * a lengthy line number calculation. */ static void -abort_long() +abort_long(void) { if (linenums == OPT_ONPLUS) /* * We were displaying line numbers, so need to repaint. */ screen_trashed = 1; linenums = 0; error("Line numbers turned off", NULL_PARG); } /* * Find the line number associated with a given position. * Return 0 if we can't figure it out. */ public LINENUM -find_linenum(pos) - POSITION pos; +find_linenum(POSITION pos) { - register struct linenum_info *p; - register LINENUM linenum; + struct linenum_info *p; + LINENUM linenum; POSITION cpos; if (!linenums) /* * We're not using line numbers. */ return (0); if (pos == NULL_POSITION) /* * Caller doesn't know what he's talking about. */ return (0); if (pos <= ch_zero()) /* * Beginning of file is always line number 1. */ return (1); /* * Find the entry nearest to the position we want. */ for (p = anchor.next; p != &anchor && p->pos < pos; p = p->next) continue; if (p->pos == pos) /* Found it exactly. */ return (p->line); /* * This is the (possibly) time-consuming part. * We start at the line we just found and start * reading the file forward or backward till we * get to the place we want. * * First decide whether we should go forward from the * previous one or backwards from the next one. * The decision is based on which way involves * traversing fewer bytes in the file. */ #if HAVE_TIME startime = get_time(); #endif if (p == &anchor || pos - p->prev->pos < p->pos - pos) { /* * Go forward. */ p = p->prev; if (ch_seek(p->pos)) return (0); loopcount = 0; for (linenum = p->line, cpos = p->pos; cpos < pos; linenum++) { /* * Allow a signal to abort this loop. */ cpos = forw_raw_line(cpos, (char **)NULL, (int *)NULL); if (ABORT_SIGS()) { abort_long(); return (0); } if (cpos == NULL_POSITION) return (0); longish(); } /* * We might as well cache it. */ add_lnum(linenum, cpos); /* * If the given position is not at the start of a line, * make sure we return the correct line number. */ if (cpos > pos) linenum--; } else { /* * Go backward. */ if (ch_seek(p->pos)) return (0); loopcount = 0; for (linenum = p->line, cpos = p->pos; cpos > pos; linenum--) { /* * Allow a signal to abort this loop. */ cpos = back_raw_line(cpos, (char **)NULL, (int *)NULL); if (ABORT_SIGS()) { abort_long(); return (0); } if (cpos == NULL_POSITION) return (0); longish(); } /* * We might as well cache it. */ add_lnum(linenum, cpos); } return (linenum); } /* * Find the position of a given line number. * Return NULL_POSITION if we can't figure it out. */ public POSITION -find_pos(linenum) - LINENUM linenum; +find_pos(LINENUM linenum) { - register struct linenum_info *p; + struct linenum_info *p; POSITION cpos; LINENUM clinenum; if (linenum <= 1) /* * Line number 1 is beginning of file. */ return (ch_zero()); /* * Find the entry nearest to the line number we want. */ for (p = anchor.next; p != &anchor && p->line < linenum; p = p->next) continue; if (p->line == linenum) /* Found it exactly. */ return (p->pos); if (p == &anchor || linenum - p->prev->line < p->line - linenum) { /* * Go forward. */ p = p->prev; if (ch_seek(p->pos)) return (NULL_POSITION); for (clinenum = p->line, cpos = p->pos; clinenum < linenum; clinenum++) { /* * Allow a signal to abort this loop. */ cpos = forw_raw_line(cpos, (char **)NULL, (int *)NULL); if (ABORT_SIGS()) return (NULL_POSITION); if (cpos == NULL_POSITION) return (NULL_POSITION); } } else { /* * Go backward. */ if (ch_seek(p->pos)) return (NULL_POSITION); for (clinenum = p->line, cpos = p->pos; clinenum > linenum; clinenum--) { /* * Allow a signal to abort this loop. */ cpos = back_raw_line(cpos, (char **)NULL, (int *)NULL); if (ABORT_SIGS()) return (NULL_POSITION); if (cpos == NULL_POSITION) return (NULL_POSITION); } } /* * We might as well cache it. */ add_lnum(clinenum, cpos); return (cpos); } /* * Return the line number of the "current" line. * The argument "where" tells which line is to be considered * the "current" line (e.g. TOP, BOTTOM, MIDDLE, etc). */ public LINENUM -currline(where) - int where; +currline(int where) { POSITION pos; POSITION len; LINENUM linenum; pos = position(where); len = ch_length(); while (pos == NULL_POSITION && where >= 0 && where < sc_height) pos = position(++where); if (pos == NULL_POSITION) pos = len; linenum = find_linenum(pos); if (pos == len) linenum--; return (linenum); } Index: head/contrib/less/lsystem.c =================================================================== --- head/contrib/less/lsystem.c (revision 316338) +++ head/contrib/less/lsystem.c (revision 316339) @@ -1,373 +1,366 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines to execute other programs. * Necessarily very OS dependent. */ #include "less.h" #include #include "position.h" #if MSDOS_COMPILER #include #ifdef _MSC_VER #include #define setdisk(n) _chdrive((n)+1) #else #include #endif #endif extern int screen_trashed; extern IFILE curr_ifile; #if HAVE_SYSTEM /* * Pass the specified command to a shell to be executed. * Like plain "system()", but handles resetting terminal modes, etc. */ public void -lsystem(cmd, donemsg) - char *cmd; - char *donemsg; +lsystem(char *cmd, char *donemsg) { - register int inp; + int inp; #if HAVE_SHELL - register char *shell; - register char *p; + char *shell; + char *p; #endif IFILE save_ifile; #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C char cwd[FILENAME_MAX+1]; #endif /* * Print the command which is to be executed, * unless the command starts with a "-". */ if (cmd[0] == '-') cmd++; else { clear_bot(); putstr("!"); putstr(cmd); putstr("\n"); } #if MSDOS_COMPILER #if MSDOS_COMPILER==WIN32C if (*cmd == '\0') cmd = getenv("COMSPEC"); #else /* * Working directory is global on MSDOS. * The child might change the working directory, so we * must save and restore CWD across calls to "system", * or else we won't find our file when we return and * try to "reedit_ifile" it. */ getcwd(cwd, FILENAME_MAX); #endif #endif /* * Close the current input file. */ save_ifile = save_curr_ifile(); (void) edit_ifile(NULL_IFILE); /* * De-initialize the terminal and take out of raw mode. */ deinit(); flush(); /* Make sure the deinit chars get out */ raw_mode(0); #if MSDOS_COMPILER==WIN32C close_getchr(); #endif /* * Restore signals to their defaults. */ init_signals(0); #if HAVE_DUP /* * Force standard input to be the user's terminal * (the normal standard input), even if less's standard input * is coming from a pipe. */ inp = dup(0); close(0); #if OS2 /* The __open() system call translates "/dev/tty" to "con". */ if (__open("/dev/tty", OPEN_READ) < 0) #else if (open("/dev/tty", OPEN_READ) < 0) #endif dup(inp); #endif /* * Pass the command to the system to be executed. * If we have a SHELL environment variable, use * <$SHELL -c "command"> instead of just . * If the command is empty, just invoke a shell. */ #if HAVE_SHELL p = NULL; if ((shell = lgetenv("SHELL")) != NULL && *shell != '\0') { if (*cmd == '\0') p = save(shell); else { char *esccmd = shell_quote(cmd); if (esccmd != NULL) { int len = (int) (strlen(shell) + strlen(esccmd) + 5); p = (char *) ecalloc(len, sizeof(char)); SNPRINTF3(p, len, "%s %s %s", shell, shell_coption(), esccmd); free(esccmd); } } } if (p == NULL) { if (*cmd == '\0') p = save("sh"); else p = save(cmd); } system(p); free(p); #else #if MSDOS_COMPILER==DJGPPC /* * Make stdin of the child be in cooked mode. */ setmode(0, O_TEXT); /* * We don't need to catch signals of the child (it * also makes trouble with some DPMI servers). */ __djgpp_exception_toggle(); system(cmd); __djgpp_exception_toggle(); #else system(cmd); #endif #endif #if HAVE_DUP /* * Restore standard input, reset signals, raw mode, etc. */ close(0); dup(inp); close(inp); #endif #if MSDOS_COMPILER==WIN32C open_getchr(); #endif init_signals(1); raw_mode(1); if (donemsg != NULL) { putstr(donemsg); putstr(" (press RETURN)"); get_return(); putchr('\n'); flush(); } init(); screen_trashed = 1; #if MSDOS_COMPILER && MSDOS_COMPILER!=WIN32C /* * Restore the previous directory (possibly * changed by the child program we just ran). */ chdir(cwd); #if MSDOS_COMPILER != DJGPPC /* * Some versions of chdir() don't change to the drive * which is part of CWD. (DJGPP does this in chdir.) */ if (cwd[1] == ':') { if (cwd[0] >= 'a' && cwd[0] <= 'z') setdisk(cwd[0] - 'a'); else if (cwd[0] >= 'A' && cwd[0] <= 'Z') setdisk(cwd[0] - 'A'); } #endif #endif /* * Reopen the current input file. */ reedit_ifile(save_ifile); #if defined(SIGWINCH) || defined(SIGWIND) /* * Since we were ignoring window change signals while we executed * the system command, we must assume the window changed. * Warning: this leaves a signal pending (in "sigs"), * so psignals() should be called soon after lsystem(). */ winch(0); #endif } #endif #if PIPEC /* * Pipe a section of the input file into the given shell command. * The section to be piped is the section "between" the current * position and the position marked by the given letter. * * If the mark is after the current screen, the section between * the top line displayed and the mark is piped. * If the mark is before the current screen, the section between * the mark and the bottom line displayed is piped. * If the mark is on the current screen, or if the mark is ".", * the whole current screen is piped. */ public int -pipe_mark(c, cmd) - int c; - char *cmd; +pipe_mark(int c, char *cmd) { POSITION mpos, tpos, bpos; /* * mpos = the marked position. * tpos = top of screen. * bpos = bottom of screen. */ mpos = markpos(c); if (mpos == NULL_POSITION) return (-1); tpos = position(TOP); if (tpos == NULL_POSITION) tpos = ch_zero(); bpos = position(BOTTOM); if (c == '.') return (pipe_data(cmd, tpos, bpos)); else if (mpos <= tpos) return (pipe_data(cmd, mpos, bpos)); else if (bpos == NULL_POSITION) return (pipe_data(cmd, tpos, bpos)); else return (pipe_data(cmd, tpos, mpos)); } /* * Create a pipe to the given shell command. * Feed it the file contents between the positions spos and epos. */ public int -pipe_data(cmd, spos, epos) - char *cmd; - POSITION spos; - POSITION epos; +pipe_data(char *cmd, POSITION spos, POSITION epos) { - register FILE *f; - register int c; + FILE *f; + int c; extern FILE *popen(); /* * This is structured much like lsystem(). * Since we're running a shell program, we must be careful * to perform the necessary deinitialization before running * the command, and reinitialization after it. */ if (ch_seek(spos) != 0) { error("Cannot seek to start position", NULL_PARG); return (-1); } if ((f = popen(cmd, "w")) == NULL) { error("Cannot create pipe", NULL_PARG); return (-1); } clear_bot(); putstr("!"); putstr(cmd); putstr("\n"); deinit(); flush(); raw_mode(0); init_signals(0); #if MSDOS_COMPILER==WIN32C close_getchr(); #endif #ifdef SIGPIPE LSIGNAL(SIGPIPE, SIG_IGN); #endif c = EOI; while (epos == NULL_POSITION || spos++ <= epos) { /* * Read a character from the file and give it to the pipe. */ c = ch_forw_get(); if (c == EOI) break; if (putc(c, f) == EOF) break; } /* * Finish up the last line. */ while (c != '\n' && c != EOI ) { c = ch_forw_get(); if (c == EOI) break; if (putc(c, f) == EOF) break; } pclose(f); #ifdef SIGPIPE LSIGNAL(SIGPIPE, SIG_DFL); #endif #if MSDOS_COMPILER==WIN32C open_getchr(); #endif init_signals(1); raw_mode(1); init(); screen_trashed = 1; #if defined(SIGWINCH) || defined(SIGWIND) /* {{ Probably don't need this here. }} */ winch(0); #endif return (0); } #endif Index: head/contrib/less/main.c =================================================================== --- head/contrib/less/main.c (revision 316338) +++ head/contrib/less/main.c (revision 316339) @@ -1,420 +1,412 @@ /* $FreeBSD$ */ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Entry point, initialization, miscellaneous routines. */ #include "less.h" #if MSDOS_COMPILER==WIN32C #include #endif public char * every_first_cmd = NULL; public int new_file; public int is_tty; public IFILE curr_ifile = NULL_IFILE; public IFILE old_ifile = NULL_IFILE; public struct scrpos initial_scrpos; public int any_display = FALSE; public POSITION start_attnpos = NULL_POSITION; public POSITION end_attnpos = NULL_POSITION; public int wscroll; public char * progname; public int quitting; public int secure; public int dohelp; #if LOGFILE public int logfile = -1; public int force_logfile = FALSE; public char * namelogfile = NULL; #endif #if EDITOR public char * editor; public char * editproto; #endif #if TAGS extern char * tags; extern char * tagoption; extern int jump_sline; #endif #ifdef WIN32 static char consoleTitle[256]; #endif extern int less_is_more; extern int missing_cap; extern int know_dumb; extern int no_init; extern int pr_type; /* * Entry point. */ int main(argc, argv) int argc; char *argv[]; { IFILE ifile; char *s; extern char *__progname; #ifdef __EMX__ _response(&argc, &argv); _wildcard(&argc, &argv); #endif progname = *argv++; argc--; secure = 0; s = lgetenv("LESSSECURE"); if (s != NULL && *s != '\0') secure = 1; #ifdef WIN32 if (getenv("HOME") == NULL) { /* * If there is no HOME environment variable, * try the concatenation of HOMEDRIVE + HOMEPATH. */ char *drive = getenv("HOMEDRIVE"); char *path = getenv("HOMEPATH"); if (drive != NULL && path != NULL) { char *env = (char *) ecalloc(strlen(drive) + strlen(path) + 6, sizeof(char)); strcpy(env, "HOME="); strcat(env, drive); strcat(env, path); putenv(env); } } GetConsoleTitle(consoleTitle, sizeof(consoleTitle)/sizeof(char)); #endif /* WIN32 */ /* * Process command line arguments and LESS environment arguments. * Command line arguments override environment arguments. */ is_tty = isatty(1); get_term(); init_cmds(); init_charset(); init_line(); init_cmdhist(); init_option(); init_search(); /* * If the name of the executable program is "more", * act like LESS_IS_MORE is set. */ for (s = progname + strlen(progname); s > progname; s--) { if (s[-1] == PATHNAME_SEP[0]) break; } if (strcmp(s, "more") == 0) less_is_more = 1; init_prompt(); if (less_is_more) scan_option("-fG"); s = lgetenv(less_is_more ? "MORE" : "LESS"); if (s != NULL) scan_option(save(s)); #define isoptstring(s) less_is_more ? (((s)[0] == '-') && (s)[1] != '\0') : \ (((s)[0] == '-' || (s)[0] == '+') && (s)[1] != '\0') while (argc > 0 && (isoptstring(*argv) || isoptpending())) { s = *argv++; argc--; if (strcmp(s, "--") == 0) break; scan_option(s); } #undef isoptstring if (isoptpending()) { /* * Last command line option was a flag requiring a * following string, but there was no following string. */ nopendopt(); quit(QUIT_OK); } if (less_is_more) no_init = TRUE; #if EDITOR editor = lgetenv("VISUAL"); if (editor == NULL || *editor == '\0') { editor = lgetenv("EDITOR"); if (editor == NULL || *editor == '\0') editor = EDIT_PGM; } editproto = lgetenv("LESSEDIT"); if (editproto == NULL || *editproto == '\0') editproto = "%E ?lm+%lm. %f"; #endif /* * Call get_ifile with all the command line filenames * to "register" them with the ifile system. */ ifile = NULL_IFILE; if (dohelp) ifile = get_ifile(FAKE_HELPFILE, ifile); while (argc-- > 0) { char *filename; #if (MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC) /* * Because the "shell" doesn't expand filename patterns, * treat each argument as a filename pattern rather than * a single filename. * Expand the pattern and iterate over the expanded list. */ struct textlist tlist; char *gfilename; gfilename = lglob(*argv++); init_textlist(&tlist, gfilename); filename = NULL; while ((filename = forw_textlist(&tlist, filename)) != NULL) { (void) get_ifile(filename, ifile); ifile = prev_ifile(NULL_IFILE); } free(gfilename); #else filename = shell_quote(*argv); if (filename == NULL) filename = *argv; argv++; (void) get_ifile(filename, ifile); ifile = prev_ifile(NULL_IFILE); free(filename); #endif } /* * Set up terminal, etc. */ if (!is_tty) { /* * Output is not a tty. * Just copy the input file(s) to output. */ SET_BINARY(1); if (nifile() == 0) { if (edit_stdin() == 0) cat_file(); } else if (edit_first() == 0) { do { cat_file(); } while (edit_next(1) == 0); } quit(QUIT_OK); } if (missing_cap && !know_dumb && !less_is_more) error("WARNING: terminal is not fully functional", NULL_PARG); init_mark(); open_getchr(); raw_mode(1); init_signals(1); /* * Select the first file to examine. */ #if TAGS if (tagoption != NULL || strcmp(tags, "-") == 0) { /* * A -t option was given. * Verify that no filenames were also given. * Edit the file selected by the "tags" search, * and search for the proper line in the file. */ if (nifile() > 0) { error("No filenames allowed with -t option", NULL_PARG); quit(QUIT_ERROR); } findtag(tagoption); if (edit_tagfile()) /* Edit file which contains the tag */ quit(QUIT_ERROR); /* * Search for the line which contains the tag. * Set up initial_scrpos so we display that line. */ initial_scrpos.pos = tagsearch(); if (initial_scrpos.pos == NULL_POSITION) quit(QUIT_ERROR); initial_scrpos.ln = jump_sline; } else #endif if (nifile() == 0) { if (edit_stdin()) /* Edit standard input */ quit(QUIT_ERROR); } else { if (edit_first()) /* Edit first valid file in cmd line */ quit(QUIT_ERROR); } init(); commands(); quit(QUIT_OK); /*NOTREACHED*/ return (0); } /* * Copy a string to a "safe" place * (that is, to a buffer allocated by calloc). */ public char * -save(s) - char *s; +save(constant char *s) { - register char *p; + char *p; p = (char *) ecalloc(strlen(s)+1, sizeof(char)); strcpy(p, s); return (p); } /* * Allocate memory. * Like calloc(), but never returns an error (NULL). */ public VOID_POINTER -ecalloc(count, size) - int count; - unsigned int size; +ecalloc(int count, unsigned int size) { - register VOID_POINTER p; + VOID_POINTER p; p = (VOID_POINTER) calloc(count, size); if (p != NULL) return (p); error("Cannot allocate memory", NULL_PARG); quit(QUIT_ERROR); /*NOTREACHED*/ return (NULL); } /* * Skip leading spaces in a string. */ public char * -skipsp(s) - register char *s; +skipsp(char *s) { while (*s == ' ' || *s == '\t') s++; return (s); } /* * See how many characters of two strings are identical. * If uppercase is true, the first string must begin with an uppercase * character; the remainder of the first string may be either case. */ public int -sprefix(ps, s, uppercase) - char *ps; - char *s; - int uppercase; +sprefix(char *ps, char *s, int uppercase) { - register int c; - register int sc; - register int len = 0; + int c; + int sc; + int len = 0; for ( ; *s != '\0'; s++, ps++) { c = *ps; if (uppercase) { if (len == 0 && ASCII_IS_LOWER(c)) return (-1); if (ASCII_IS_UPPER(c)) c = ASCII_TO_LOWER(c); } sc = *s; if (len > 0 && ASCII_IS_UPPER(sc)) sc = ASCII_TO_LOWER(sc); if (c != sc) break; len++; } return (len); } /* * Exit the program. */ public void -quit(status) - int status; +quit(int status) { static int save_status; /* * Put cursor at bottom left corner, clear the line, * reset the terminal modes, and exit. */ if (status < 0) status = save_status; else save_status = status; quitting = 1; edit((char*)NULL); save_cmdhist(); if (any_display && is_tty) clear_bot(); deinit(); flush(); raw_mode(0); #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC /* * If we don't close 2, we get some garbage from * 2's buffer when it flushes automatically. * I cannot track this one down RB * The same bug shows up if we use ^C^C to abort. */ close(2); #endif #ifdef WIN32 SetConsoleTitle(consoleTitle); #endif close_getchr(); exit(status); } Index: head/contrib/less/mark.c =================================================================== --- head/contrib/less/mark.c (revision 316338) +++ head/contrib/less/mark.c (revision 316339) @@ -1,249 +1,242 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ #include "less.h" extern IFILE curr_ifile; extern int sc_height; extern int jump_sline; /* * The table of marks. * Each mark is identified by a lowercase or uppercase letter. * The final one is lmark, for the "last mark"; addressed by the apostrophe. */ #define NMARKS ((2*26)+1) /* a-z, A-Z, lastmark */ #define LASTMARK (NMARKS-1) static struct mark marks[NMARKS]; /* * Initialize the mark table to show no marks are set. */ public void -init_mark() +init_mark(void) { int i; for (i = 0; i < NMARKS; i++) marks[i].m_scrpos.pos = NULL_POSITION; } /* * See if a mark letter is valid (between a and z). */ static struct mark * -getumark(c) - int c; +getumark(int c) { if (c >= 'a' && c <= 'z') return (&marks[c-'a']); if (c >= 'A' && c <= 'Z') return (&marks[c-'A'+26]); error("Invalid mark letter", NULL_PARG); return (NULL); } /* * Get the mark structure identified by a character. * The mark struct may come either from the mark table * or may be constructed on the fly for certain characters like ^, $. */ static struct mark * -getmark(c) - int c; +getmark(int c) { - register struct mark *m; + struct mark *m; static struct mark sm; switch (c) { case '^': /* * Beginning of the current file. */ m = &sm; m->m_scrpos.pos = ch_zero(); m->m_scrpos.ln = 0; m->m_ifile = curr_ifile; break; case '$': /* * End of the current file. */ if (ch_end_seek()) { error("Cannot seek to end of file", NULL_PARG); return (NULL); } m = &sm; m->m_scrpos.pos = ch_tell(); m->m_scrpos.ln = sc_height-1; m->m_ifile = curr_ifile; break; case '.': /* * Current position in the current file. */ m = &sm; get_scrpos(&m->m_scrpos); m->m_ifile = curr_ifile; break; case '\'': /* * The "last mark". */ m = &marks[LASTMARK]; break; default: /* * Must be a user-defined mark. */ m = getumark(c); if (m == NULL) break; if (m->m_scrpos.pos == NULL_POSITION) { error("Mark not set", NULL_PARG); return (NULL); } break; } return (m); } /* * Is a mark letter is invalid? */ public int -badmark(c) - int c; +badmark(int c) { return (getmark(c) == NULL); } /* * Set a user-defined mark. */ public void -setmark(c) - int c; +setmark(int c) { - register struct mark *m; + struct mark *m; struct scrpos scrpos; m = getumark(c); if (m == NULL) return; get_scrpos(&scrpos); m->m_scrpos = scrpos; m->m_ifile = curr_ifile; } /* * Set lmark (the mark named by the apostrophe). */ public void -lastmark() +lastmark(void) { struct scrpos scrpos; if (ch_getflags() & CH_HELPFILE) return; get_scrpos(&scrpos); if (scrpos.pos == NULL_POSITION) return; marks[LASTMARK].m_scrpos = scrpos; marks[LASTMARK].m_ifile = curr_ifile; } /* * Go to a mark. */ public void -gomark(c) - int c; +gomark(int c) { - register struct mark *m; + struct mark *m; struct scrpos scrpos; m = getmark(c); if (m == NULL) return; /* * If we're trying to go to the lastmark and * it has not been set to anything yet, * set it to the beginning of the current file. */ if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION) { m->m_ifile = curr_ifile; m->m_scrpos.pos = ch_zero(); m->m_scrpos.ln = jump_sline; } /* * If we're using lmark, we must save the screen position now, * because if we call edit_ifile() below, lmark will change. * (We save the screen position even if we're not using lmark.) */ scrpos = m->m_scrpos; if (m->m_ifile != curr_ifile) { /* * Not in the current file; edit the correct file. */ if (edit_ifile(m->m_ifile)) return; } jump_loc(scrpos.pos, scrpos.ln); } /* * Return the position associated with a given mark letter. * * We don't return which screen line the position * is associated with, but this doesn't matter much, * because it's always the first non-blank line on the screen. */ public POSITION -markpos(c) - int c; +markpos(int c) { - register struct mark *m; + struct mark *m; m = getmark(c); if (m == NULL) return (NULL_POSITION); if (m->m_ifile != curr_ifile) { error("Mark not in current file", NULL_PARG); return (NULL_POSITION); } return (m->m_scrpos.pos); } /* * Clear the marks associated with a specified ifile. */ public void -unmark(ifile) - IFILE ifile; +unmark(IFILE ifile) { int i; for (i = 0; i < NMARKS; i++) if (marks[i].m_ifile == ifile) marks[i].m_scrpos.pos = NULL_POSITION; } Index: head/contrib/less/mkhelp.c =================================================================== --- head/contrib/less/mkhelp.c (revision 316338) +++ head/contrib/less/mkhelp.c (revision 316339) @@ -1,68 +1,66 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Silly little program to generate the help.c source file * from the less.hlp text file. * help.c just contains a char array whose contents are * the contents of less.hlp. */ #include int -main(argc, argv) - int argc; - char *argv[]; +main(int argc, char *argv[]) { int ch; int prevch; printf("/* This file was generated by mkhelp from less.hlp */\n"); printf("#include \"less.h\"\n"); printf("constant char helpdata[] = {\n"); ch = 0; while (prevch = ch, (ch = getchar()) != EOF) { switch (ch) { case '\'': printf("'\\'',"); break; case '\\': printf("'\\\\',"); break; case '\b': printf("'\\b',"); break; case '\t': printf("'\\t',"); break; case '\n': if (prevch != '\r') printf("'\\n',\n"); break; case '\r': if (prevch != '\n') printf("'\\n',\n"); break; default: if (ch >= ' ' && ch < 0x7f) printf("'%c',", ch); else printf("0x%02x,", ch); break; } } /* Add an extra null char to avoid having a trailing comma. */ printf(" 0 };\n"); printf("constant int size_helpdata = sizeof(helpdata) - 1;\n"); return (0); } Index: head/contrib/less/optfunc.c =================================================================== --- head/contrib/less/optfunc.c (revision 316338) +++ head/contrib/less/optfunc.c (revision 316339) @@ -1,743 +1,708 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Handling functions for command line options. * * Most options are handled by the generic code in option.c. * But all string options, and a few non-string options, require * special handling specific to the particular option. * This special processing is done by the "handling functions" in this file. * * Each handling function is passed a "type" and, if it is a string * option, the string which should be "assigned" to the option. * The type may be one of: * INIT The option is being initialized from the command line. * TOGGLE The option is being changed from within the program. * QUERY The setting of the option is merely being queried. */ #include "less.h" #include "option.h" extern int nbufs; extern int bufspace; extern int pr_type; extern int plusoption; extern int swindow; extern int sc_width; extern int sc_height; extern int secure; extern int dohelp; extern int any_display; extern char openquote; extern char closequote; extern char *prproto[]; extern char *eqproto; extern char *hproto; extern char *wproto; extern char *every_first_cmd; extern IFILE curr_ifile; extern char version[]; extern int jump_sline; extern int jump_sline_fraction; extern int shift_count; extern int shift_count_fraction; extern int less_is_more; #if LOGFILE extern char *namelogfile; extern int force_logfile; extern int logfile; #endif #if TAGS public char *tagoption = NULL; extern char *tags; extern char ztags[]; #endif #if MSDOS_COMPILER extern int nm_fg_color, nm_bg_color; extern int bo_fg_color, bo_bg_color; extern int ul_fg_color, ul_bg_color; extern int so_fg_color, so_bg_color; extern int bl_fg_color, bl_bg_color; #endif #if LOGFILE /* * Handler for -o option. */ public void -opt_o(type, s) - int type; - char *s; +opt_o(int type, char *s) { PARG parg; if (secure) { error("log file support is not available", NULL_PARG); return; } switch (type) { case INIT: namelogfile = save(s); break; case TOGGLE: if (ch_getflags() & CH_CANSEEK) { error("Input is not a pipe", NULL_PARG); return; } if (logfile >= 0) { error("Log file is already in use", NULL_PARG); return; } s = skipsp(s); if (namelogfile != NULL) free(namelogfile); namelogfile = lglob(s); use_logfile(namelogfile); sync_logfile(); break; case QUERY: if (logfile < 0) error("No log file", NULL_PARG); else { parg.p_string = namelogfile; error("Log file \"%s\"", &parg); } break; } } /* * Handler for -O option. */ public void -opt__O(type, s) - int type; - char *s; +opt__O(int type, char *s) { force_logfile = TRUE; opt_o(type, s); } #endif /* * Handlers for -j option. */ public void -opt_j(type, s) - int type; - char *s; +opt_j(int type, char *s) { PARG parg; char buf[16]; int len; int err; switch (type) { case INIT: case TOGGLE: if (*s == '.') { s++; jump_sline_fraction = getfraction(&s, "j", &err); if (err) error("Invalid line fraction", NULL_PARG); else calc_jump_sline(); } else { int sline = getnum(&s, "j", &err); if (err) error("Invalid line number", NULL_PARG); else { jump_sline = sline; jump_sline_fraction = -1; } } break; case QUERY: if (jump_sline_fraction < 0) { parg.p_int = jump_sline; error("Position target at screen line %d", &parg); } else { sprintf(buf, ".%06d", jump_sline_fraction); len = (int) strlen(buf); while (len > 2 && buf[len-1] == '0') len--; buf[len] = '\0'; parg.p_string = buf; error("Position target at screen position %s", &parg); } break; } } public void -calc_jump_sline() +calc_jump_sline(void) { if (jump_sline_fraction < 0) return; jump_sline = sc_height * jump_sline_fraction / NUM_FRAC_DENOM; } /* * Handlers for -# option. */ public void -opt_shift(type, s) - int type; - char *s; +opt_shift(int type, char *s) { PARG parg; char buf[16]; int len; int err; switch (type) { case INIT: case TOGGLE: if (*s == '.') { s++; shift_count_fraction = getfraction(&s, "#", &err); if (err) error("Invalid column fraction", NULL_PARG); else calc_shift_count(); } else { int hs = getnum(&s, "#", &err); if (err) error("Invalid column number", NULL_PARG); else { shift_count = hs; shift_count_fraction = -1; } } break; case QUERY: if (shift_count_fraction < 0) { parg.p_int = shift_count; error("Horizontal shift %d columns", &parg); } else { sprintf(buf, ".%06d", shift_count_fraction); len = (int) strlen(buf); while (len > 2 && buf[len-1] == '0') len--; buf[len] = '\0'; parg.p_string = buf; error("Horizontal shift %s of screen width", &parg); } break; } } public void -calc_shift_count() +calc_shift_count(void) { if (shift_count_fraction < 0) return; shift_count = sc_width * shift_count_fraction / NUM_FRAC_DENOM; } #if USERFILE public void -opt_k(type, s) - int type; - char *s; +opt_k(int type, char *s) { PARG parg; switch (type) { case INIT: if (lesskey(s, 0)) { parg.p_string = s; error("Cannot use lesskey file \"%s\"", &parg); } break; } } #endif #if TAGS /* * Handler for -t option. */ public void -opt_t(type, s) - int type; - char *s; +opt_t(int type, char *s) { IFILE save_ifile; POSITION pos; switch (type) { case INIT: tagoption = save(s); /* Do the rest in main() */ break; case TOGGLE: if (secure) { error("tags support is not available", NULL_PARG); break; } findtag(skipsp(s)); save_ifile = save_curr_ifile(); /* * Try to open the file containing the tag * and search for the tag in that file. */ if (edit_tagfile() || (pos = tagsearch()) == NULL_POSITION) { /* Failed: reopen the old file. */ reedit_ifile(save_ifile); break; } unsave_ifile(save_ifile); jump_loc(pos, jump_sline); break; } } /* * Handler for -T option. */ public void -opt__T(type, s) - int type; - char *s; +opt__T(int type, char *s) { PARG parg; switch (type) { case INIT: tags = save(s); break; case TOGGLE: s = skipsp(s); if (tags != NULL && tags != ztags) free(tags); tags = lglob(s); break; case QUERY: parg.p_string = tags; error("Tags file \"%s\"", &parg); break; } } #endif /* * Handler for -p option. */ public void -opt_p(type, s) - int type; - register char *s; +opt_p(int type, char *s) { switch (type) { case INIT: /* * Unget a command for the specified string. */ if (less_is_more) { /* * In "more" mode, the -p argument is a command, * not a search string, so we don't need a slash. */ every_first_cmd = save(s); } else { plusoption = TRUE; ungetcc(CHAR_END_COMMAND); ungetsc(s); /* * {{ This won't work if the "/" command is * changed or invalidated by a .lesskey file. }} */ ungetsc("/"); } break; } } /* * Handler for -P option. */ public void -opt__P(type, s) - int type; - register char *s; +opt__P(int type, char *s) { - register char **proto; + char **proto; PARG parg; switch (type) { case INIT: case TOGGLE: /* * Figure out which prototype string should be changed. */ switch (*s) { case 's': proto = &prproto[PR_SHORT]; s++; break; case 'm': proto = &prproto[PR_MEDIUM]; s++; break; case 'M': proto = &prproto[PR_LONG]; s++; break; case '=': proto = &eqproto; s++; break; case 'h': proto = &hproto; s++; break; case 'w': proto = &wproto; s++; break; default: proto = &prproto[PR_SHORT]; break; } free(*proto); *proto = save(s); break; case QUERY: parg.p_string = prproto[pr_type]; error("%s", &parg); break; } } /* * Handler for the -b option. */ /*ARGSUSED*/ public void -opt_b(type, s) - int type; - char *s; +opt_b(int type, char *s) { switch (type) { case INIT: case TOGGLE: /* * Set the new number of buffers. */ ch_setbufspace(bufspace); break; case QUERY: break; } } /* * Handler for the -i option. */ /*ARGSUSED*/ public void -opt_i(type, s) - int type; - char *s; +opt_i(int type, char *s) { switch (type) { case TOGGLE: chg_caseless(); break; case QUERY: case INIT: break; } } /* * Handler for the -V option. */ /*ARGSUSED*/ public void -opt__V(type, s) - int type; - char *s; +opt__V(int type, char *s) { switch (type) { case TOGGLE: case QUERY: dispversion(); break; case INIT: /* * Force output to stdout per GNU standard for --version output. */ any_display = 1; putstr("less "); putstr(version); putstr(" ("); #if HAVE_GNU_REGEX putstr("GNU "); #endif #if HAVE_POSIX_REGCOMP putstr("POSIX "); #endif #if HAVE_PCRE putstr("PCRE "); #endif #if HAVE_RE_COMP putstr("BSD "); #endif #if HAVE_REGCMP putstr("V8 "); #endif #if HAVE_V8_REGCOMP putstr("Spencer V8 "); #endif #if !HAVE_GNU_REGEX && !HAVE_POSIX_REGCOMP && !HAVE_PCRE && !HAVE_RE_COMP && !HAVE_REGCMP && !HAVE_V8_REGCOMP putstr("no "); #endif putstr("regular expressions)\n"); putstr("Copyright (C) 1984-2015 Mark Nudelman\n\n"); putstr("less comes with NO WARRANTY, to the extent permitted by law.\n"); putstr("For information about the terms of redistribution,\n"); putstr("see the file named README in the less distribution.\n"); putstr("Homepage: http://www.greenwoodsoftware.com/less\n"); quit(QUIT_OK); break; } } #if MSDOS_COMPILER /* * Parse an MSDOS color descriptor. */ static void -colordesc(s, fg_color, bg_color) - char *s; - int *fg_color; - int *bg_color; +colordesc(char *s, int *fg_color, int *bg_color) { int fg, bg; int err; fg = getnum(&s, "D", &err); if (err) { error("Missing fg color in -D", NULL_PARG); return; } if (*s != '.') bg = nm_bg_color; else { s++; bg = getnum(&s, "D", &err); if (err) { error("Missing bg color in -D", NULL_PARG); return; } } if (*s != '\0') error("Extra characters at end of -D option", NULL_PARG); *fg_color = fg; *bg_color = bg; } /* * Handler for the -D option. */ /*ARGSUSED*/ public void -opt_D(type, s) - int type; - char *s; +opt_D(int type, char *s) { switch (type) { case INIT: case TOGGLE: switch (*s++) { case 'n': colordesc(s, &nm_fg_color, &nm_bg_color); break; case 'd': colordesc(s, &bo_fg_color, &bo_bg_color); break; case 'u': colordesc(s, &ul_fg_color, &ul_bg_color); break; case 'k': colordesc(s, &bl_fg_color, &bl_bg_color); break; case 's': colordesc(s, &so_fg_color, &so_bg_color); break; default: error("-D must be followed by n, d, u, k or s", NULL_PARG); break; } if (type == TOGGLE) { at_enter(AT_STANDOUT); at_exit(); } break; case QUERY: break; } } #endif /* * Handler for the -x option. */ public void -opt_x(type, s) - int type; - register char *s; +opt_x(int type, char *s) { extern int tabstops[]; extern int ntabstops; extern int tabdefault; char msg[60+(4*TABSTOP_MAX)]; int i; PARG p; switch (type) { case INIT: case TOGGLE: /* Start at 1 because tabstops[0] is always zero. */ for (i = 1; i < TABSTOP_MAX; ) { int n = 0; s = skipsp(s); while (*s >= '0' && *s <= '9') n = (10 * n) + (*s++ - '0'); if (n > tabstops[i-1]) tabstops[i++] = n; s = skipsp(s); if (*s++ != ',') break; } if (i < 2) return; ntabstops = i; tabdefault = tabstops[ntabstops-1] - tabstops[ntabstops-2]; break; case QUERY: strcpy(msg, "Tab stops "); if (ntabstops > 2) { for (i = 1; i < ntabstops; i++) { if (i > 1) strcat(msg, ","); sprintf(msg+strlen(msg), "%d", tabstops[i]); } sprintf(msg+strlen(msg), " and then "); } sprintf(msg+strlen(msg), "every %d spaces", tabdefault); p.p_string = msg; error("%s", &p); break; } } /* * Handler for the -" option. */ public void -opt_quote(type, s) - int type; - register char *s; +opt_quote(int type, char *s) { char buf[3]; PARG parg; switch (type) { case INIT: case TOGGLE: if (s[0] == '\0') { openquote = closequote = '\0'; break; } if (s[1] != '\0' && s[2] != '\0') { error("-\" must be followed by 1 or 2 chars", NULL_PARG); return; } openquote = s[0]; if (s[1] == '\0') closequote = openquote; else closequote = s[1]; break; case QUERY: buf[0] = openquote; buf[1] = closequote; buf[2] = '\0'; parg.p_string = buf; error("quotes %s", &parg); break; } } /* * "-?" means display a help message. * If from the command line, exit immediately. */ /*ARGSUSED*/ public void -opt_query(type, s) - int type; - char *s; +opt_query(int type, char *s) { switch (type) { case QUERY: case TOGGLE: error("Use \"h\" for help", NULL_PARG); break; case INIT: dohelp = 1; } } /* * Get the "screen window" size. */ public int -get_swindow() +get_swindow(void) { if (swindow > 0) return (swindow); return (sc_height + swindow); } Index: head/contrib/less/option.c =================================================================== --- head/contrib/less/option.c (revision 316338) +++ head/contrib/less/option.c (revision 316339) @@ -1,708 +1,684 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Process command line options. * * Each option is a single letter which controls a program variable. * The options have defaults which may be changed via * the command line option, toggled via the "-" command, * or queried via the "_" command. */ #include "less.h" #include "option.h" static struct loption *pendopt; public int plusoption = FALSE; -static char *optstring(); -static int flip_triple(); +static char *optstring(char *s, char **p_str, char *printopt, char *validchars); +static int flip_triple(int val, int lc); extern int screen_trashed; extern int less_is_more; extern int quit_at_eof; extern char *every_first_cmd; extern int opt_use_backslash; /* * Return a printable description of an option. */ static char * -opt_desc(o) - struct loption *o; +opt_desc(struct loption *o) { static char buf[OPTNAME_MAX + 10]; if (o->oletter == OLETTER_NONE) SNPRINTF1(buf, sizeof(buf), "--%s", o->onames->oname); else SNPRINTF2(buf, sizeof(buf), "-%c (--%s)", o->oletter, o->onames->oname); return (buf); } /* * Return a string suitable for printing as the "name" of an option. * For example, if the option letter is 'x', just return "-x". */ public char * -propt(c) - int c; +propt(int c) { static char buf[8]; sprintf(buf, "-%s", prchar(c)); return (buf); } /* * Scan an argument (either from the command line or from the * LESS environment variable) and process it. */ public void -scan_option(s) - char *s; +scan_option(char *s) { - register struct loption *o; - register int optc; + struct loption *o; + int optc; char *optname; char *printopt; char *str; int set_default; int lc; int err; PARG parg; if (s == NULL) return; /* * If we have a pending option which requires an argument, * handle it now. * This happens if the previous option was, for example, "-P" * without a following string. In that case, the current * option is simply the argument for the previous option. */ if (pendopt != NULL) { switch (pendopt->otype & OTYPE) { case STRING: (*pendopt->ofunc)(INIT, s); break; case NUMBER: printopt = opt_desc(pendopt); *(pendopt->ovar) = getnum(&s, printopt, (int*)NULL); break; } pendopt = NULL; return; } set_default = FALSE; optname = NULL; while (*s != '\0') { /* * Check some special cases first. */ switch (optc = *s++) { case ' ': case '\t': case END_OPTION_STRING: continue; case '-': /* * "--" indicates an option name instead of a letter. */ if (*s == '-') { optname = ++s; break; } /* * "-+" means set these options back to their defaults. * (They may have been set otherwise by previous * options.) */ set_default = (*s == '+'); if (set_default) s++; continue; case '+': /* * An option prefixed by a "+" is ungotten, so * that it is interpreted as less commands * processed at the start of the first input file. * "++" means process the commands at the start of * EVERY input file. */ plusoption = TRUE; s = optstring(s, &str, propt('+'), NULL); if (s == NULL) return; if (*str == '+') every_first_cmd = save(str+1); else { ungetcc(CHAR_END_COMMAND); ungetsc(str); } free(str); continue; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* * Special "more" compatibility form "-" * instead of -z to set the scrolling * window size. */ s--; optc = 'z'; break; case 'n': if (less_is_more) optc = 'z'; break; } /* * Not a special case. * Look up the option letter in the option table. */ err = 0; if (optname == NULL) { printopt = propt(optc); lc = ASCII_IS_LOWER(optc); o = findopt(optc); } else { printopt = optname; lc = ASCII_IS_LOWER(optname[0]); o = findopt_name(&optname, NULL, &err); s = optname; optname = NULL; if (*s == '\0' || *s == ' ') { /* * The option name matches exactly. */ ; } else if (*s == '=') { /* * The option name is followed by "=value". */ if (o != NULL && (o->otype & OTYPE) != STRING && (o->otype & OTYPE) != NUMBER) { parg.p_string = printopt; error("The %s option should not be followed by =", &parg); return; } s++; } else { /* * The specified name is longer than the * real option name. */ o = NULL; } } if (o == NULL) { parg.p_string = printopt; if (err == OPT_AMBIG) error("%s is an ambiguous abbreviation (\"less --help\" for help)", &parg); else error("There is no %s option (\"less --help\" for help)", &parg); return; } str = NULL; switch (o->otype & OTYPE) { case BOOL: if (set_default) *(o->ovar) = o->odefault; else *(o->ovar) = ! o->odefault; break; case TRIPLE: if (set_default) *(o->ovar) = o->odefault; else *(o->ovar) = flip_triple(o->odefault, lc); break; case STRING: if (*s == '\0') { /* * Set pendopt and return. * We will get the string next time * scan_option is called. */ pendopt = o; return; } /* * Don't do anything here. * All processing of STRING options is done by * the handling function. */ while (*s == ' ') s++; s = optstring(s, &str, printopt, o->odesc[1]); if (s == NULL) return; break; case NUMBER: if (*s == '\0') { pendopt = o; return; } *(o->ovar) = getnum(&s, printopt, (int*)NULL); break; } /* * If the option has a handling function, call it. */ if (o->ofunc != NULL) (*o->ofunc)(INIT, str); if (str != NULL) free(str); } } /* * Toggle command line flags from within the program. * Used by the "-" and "_" commands. * how_toggle may be: * OPT_NO_TOGGLE just report the current setting, without changing it. * OPT_TOGGLE invert the current setting * OPT_UNSET set to the default value * OPT_SET set to the inverse of the default value */ public void -toggle_option(o, lower, s, how_toggle) - struct loption *o; - int lower; - char *s; - int how_toggle; +toggle_option(struct loption *o, int lower, char *s, int how_toggle) { - register int num; + int num; int no_prompt; int err; PARG parg; no_prompt = (how_toggle & OPT_NO_PROMPT); how_toggle &= ~OPT_NO_PROMPT; if (o == NULL) { error("No such option", NULL_PARG); return; } if (how_toggle == OPT_TOGGLE && (o->otype & NO_TOGGLE)) { parg.p_string = opt_desc(o); error("Cannot change the %s option", &parg); return; } if (how_toggle == OPT_NO_TOGGLE && (o->otype & NO_QUERY)) { parg.p_string = opt_desc(o); error("Cannot query the %s option", &parg); return; } /* * Check for something which appears to be a do_toggle * (because the "-" command was used), but really is not. * This could be a string option with no string, or * a number option with no number. */ switch (o->otype & OTYPE) { case STRING: case NUMBER: if (how_toggle == OPT_TOGGLE && *s == '\0') how_toggle = OPT_NO_TOGGLE; break; } #if HILITE_SEARCH if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) repaint_hilite(0); #endif /* * Now actually toggle (change) the variable. */ if (how_toggle != OPT_NO_TOGGLE) { switch (o->otype & OTYPE) { case BOOL: /* * Boolean. */ switch (how_toggle) { case OPT_TOGGLE: *(o->ovar) = ! *(o->ovar); break; case OPT_UNSET: *(o->ovar) = o->odefault; break; case OPT_SET: *(o->ovar) = ! o->odefault; break; } break; case TRIPLE: /* * Triple: * If user gave the lower case letter, then switch * to 1 unless already 1, in which case make it 0. * If user gave the upper case letter, then switch * to 2 unless already 2, in which case make it 0. */ switch (how_toggle) { case OPT_TOGGLE: *(o->ovar) = flip_triple(*(o->ovar), lower); break; case OPT_UNSET: *(o->ovar) = o->odefault; break; case OPT_SET: *(o->ovar) = flip_triple(o->odefault, lower); break; } break; case STRING: /* * String: don't do anything here. * The handling function will do everything. */ switch (how_toggle) { case OPT_SET: case OPT_UNSET: error("Cannot use \"-+\" or \"--\" for a string option", NULL_PARG); return; } break; case NUMBER: /* * Number: set the variable to the given number. */ switch (how_toggle) { case OPT_TOGGLE: num = getnum(&s, NULL, &err); if (!err) *(o->ovar) = num; break; case OPT_UNSET: *(o->ovar) = o->odefault; break; case OPT_SET: error("Can't use \"-!\" for a numeric option", NULL_PARG); return; } break; } } /* * Call the handling function for any special action * specific to this option. */ if (o->ofunc != NULL) (*o->ofunc)((how_toggle==OPT_NO_TOGGLE) ? QUERY : TOGGLE, s); #if HILITE_SEARCH if (how_toggle != OPT_NO_TOGGLE && (o->otype & HL_REPAINT)) chg_hilite(); #endif if (!no_prompt) { /* * Print a message describing the new setting. */ switch (o->otype & OTYPE) { case BOOL: case TRIPLE: /* * Print the odesc message. */ error(o->odesc[*(o->ovar)], NULL_PARG); break; case NUMBER: /* * The message is in odesc[1] and has a %d for * the value of the variable. */ parg.p_int = *(o->ovar); error(o->odesc[1], &parg); break; case STRING: /* * Message was already printed by the handling function. */ break; } } if (how_toggle != OPT_NO_TOGGLE && (o->otype & REPAINT)) screen_trashed = TRUE; } /* * "Toggle" a triple-valued option. */ static int -flip_triple(val, lc) - int val; - int lc; +flip_triple(int val, int lc) { if (lc) return ((val == OPT_ON) ? OPT_OFF : OPT_ON); else return ((val == OPT_ONPLUS) ? OPT_OFF : OPT_ONPLUS); } /* * Determine if an option takes a parameter. */ public int -opt_has_param(o) - struct loption *o; +opt_has_param(struct loption *o) { if (o == NULL) return (0); if (o->otype & (BOOL|TRIPLE|NOVAR|NO_TOGGLE)) return (0); return (1); } /* * Return the prompt to be used for a given option letter. * Only string and number valued options have prompts. */ public char * -opt_prompt(o) - struct loption *o; +opt_prompt(struct loption *o) { if (o == NULL || (o->otype & (STRING|NUMBER)) == 0) return ("?"); return (o->odesc[0]); } /* * Return whether or not there is a string option pending; * that is, if the previous option was a string-valued option letter * (like -P) without a following string. * In that case, the current option is taken to be the string for * the previous option. */ public int -isoptpending() +isoptpending(void) { return (pendopt != NULL); } /* * Print error message about missing string. */ static void -nostring(printopt) - char *printopt; +nostring(char *printopt) { PARG parg; parg.p_string = printopt; error("Value is required after %s", &parg); } /* * Print error message if a STRING type option is not followed by a string. */ public void -nopendopt() +nopendopt(void) { nostring(opt_desc(pendopt)); } /* * Scan to end of string or to an END_OPTION_STRING character. * In the latter case, replace the char with a null char. * Return a pointer to the remainder of the string, if any. */ static char * -optstring(s, p_str, printopt, validchars) - char *s; - char **p_str; - char *printopt; - char *validchars; +optstring(char *s, char **p_str, char *printopt, char *validchars) { - register char *p; - register char *out; + char *p; + char *out; if (*s == '\0') { nostring(printopt); return (NULL); } /* Alloc could be more than needed, but not worth trimming. */ *p_str = (char *) ecalloc(strlen(s)+1, sizeof(char)); out = *p_str; for (p = s; *p != '\0'; p++) { if (opt_use_backslash && *p == '\\' && p[1] != '\0') { /* Take next char literally. */ ++p; } else { if (*p == END_OPTION_STRING || (validchars != NULL && strchr(validchars, *p) == NULL)) /* End of option string. */ break; } *out++ = *p; } *out = '\0'; return (p); } /* */ static int -num_error(printopt, errp) - char *printopt; - int *errp; +num_error(char *printopt, int *errp) { PARG parg; if (errp != NULL) { *errp = TRUE; return (-1); } if (printopt != NULL) { parg.p_string = printopt; error("Number is required after %s", &parg); } return (-1); } /* * Translate a string into a number. * Like atoi(), but takes a pointer to a char *, and updates * the char * to point after the translated number. */ public int -getnum(sp, printopt, errp) - char **sp; - char *printopt; - int *errp; +getnum(char **sp, char *printopt, int *errp) { - register char *s; - register int n; - register int neg; + char *s; + int n; + int neg; s = skipsp(*sp); neg = FALSE; if (*s == '-') { neg = TRUE; s++; } if (*s < '0' || *s > '9') return (num_error(printopt, errp)); n = 0; while (*s >= '0' && *s <= '9') n = 10 * n + *s++ - '0'; *sp = s; if (errp != NULL) *errp = FALSE; if (neg) n = -n; return (n); } /* * Translate a string into a fraction, represented by the part of a * number which would follow a decimal point. * The value of the fraction is returned as parts per NUM_FRAC_DENOM. * That is, if "n" is returned, the fraction intended is n/NUM_FRAC_DENOM. */ public long -getfraction(sp, printopt, errp) - char **sp; - char *printopt; - int *errp; +getfraction(char **sp, char *printopt, int *errp) { - register char *s; + char *s; long frac = 0; int fraclen = 0; s = skipsp(*sp); if (*s < '0' || *s > '9') return (num_error(printopt, errp)); for ( ; *s >= '0' && *s <= '9'; s++) { frac = (frac * 10) + (*s - '0'); fraclen++; } if (fraclen > NUM_LOG_FRAC_DENOM) while (fraclen-- > NUM_LOG_FRAC_DENOM) frac /= 10; else while (fraclen++ < NUM_LOG_FRAC_DENOM) frac *= 10; *sp = s; if (errp != NULL) *errp = FALSE; return (frac); } /* * Get the value of the -e flag. */ public int -get_quit_at_eof() +get_quit_at_eof(void) { if (!less_is_more) return quit_at_eof; /* When less_is_more is set, the -e flag semantics are different. */ return quit_at_eof ? OPT_ONPLUS : OPT_ON; } Index: head/contrib/less/opttbl.c =================================================================== --- head/contrib/less/opttbl.c (revision 316338) +++ head/contrib/less/opttbl.c (revision 316339) @@ -1,608 +1,603 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * The option table. */ #include "less.h" #include "option.h" /* * Variables controlled by command line options. */ public int quiet; /* Should we suppress the audible bell? */ public int how_search; /* Where should forward searches start? */ public int top_scroll; /* Repaint screen from top? (alternative is scroll from bottom) */ public int pr_type; /* Type of prompt (short, medium, long) */ public int bs_mode; /* How to process backspaces */ public int know_dumb; /* Don't complain about dumb terminals */ public int quit_at_eof; /* Quit after hitting end of file twice */ public int quit_if_one_screen; /* Quit if EOF on first screen */ public int squeeze; /* Squeeze multiple blank lines into one */ public int tabstop; /* Tab settings */ public int back_scroll; /* Repaint screen on backwards movement */ public int forw_scroll; /* Repaint screen on forward movement */ public int caseless; /* Do "caseless" searches */ public int linenums; /* Use line numbers */ public int autobuf; /* Automatically allocate buffers as needed */ public int bufspace; /* Max buffer space per file (K) */ public int ctldisp; /* Send control chars to screen untranslated */ public int force_open; /* Open the file even if not regular file */ public int swindow; /* Size of scrolling window */ public int jump_sline; /* Screen line of "jump target" */ public long jump_sline_fraction = -1; public long shift_count_fraction = -1; public int chopline; /* Truncate displayed lines at screen width */ public int no_init; /* Disable sending ti/te termcap strings */ public int no_keypad; /* Disable sending ks/ke termcap strings */ public int twiddle; /* Show tildes after EOF */ public int show_attn; /* Hilite first unread line */ public int shift_count; /* Number of positions to shift horizontally */ public int status_col; /* Display a status column */ public int use_lessopen; /* Use the LESSOPEN filter */ public int quit_on_intr; /* Quit on interrupt */ public int follow_mode; /* F cmd Follows file desc or file name? */ public int oldbot; /* Old bottom of screen behavior {{REMOVE}} */ public int opt_use_backslash; /* Use backslash escaping in option parsing */ #if HILITE_SEARCH public int hilite_search; /* Highlight matched search patterns? */ #endif public int less_is_more = 0; /* Make compatible with POSIX more */ /* * Long option names. */ static struct optname a_optname = { "search-skip-screen", NULL }; static struct optname b_optname = { "buffers", NULL }; static struct optname B__optname = { "auto-buffers", NULL }; static struct optname c_optname = { "clear-screen", NULL }; static struct optname d_optname = { "dumb", NULL }; #if MSDOS_COMPILER static struct optname D__optname = { "color", NULL }; #endif static struct optname e_optname = { "quit-at-eof", NULL }; static struct optname f_optname = { "force", NULL }; static struct optname F__optname = { "quit-if-one-screen", NULL }; #if HILITE_SEARCH static struct optname g_optname = { "hilite-search", NULL }; #endif static struct optname h_optname = { "max-back-scroll", NULL }; static struct optname i_optname = { "ignore-case", NULL }; static struct optname j_optname = { "jump-target", NULL }; static struct optname J__optname = { "status-column", NULL }; #if USERFILE static struct optname k_optname = { "lesskey-file", NULL }; #endif static struct optname K__optname = { "quit-on-intr", NULL }; static struct optname L__optname = { "no-lessopen", NULL }; static struct optname m_optname = { "long-prompt", NULL }; static struct optname n_optname = { "line-numbers", NULL }; #if LOGFILE static struct optname o_optname = { "log-file", NULL }; static struct optname O__optname = { "LOG-FILE", NULL }; #endif static struct optname p_optname = { "pattern", NULL }; static struct optname P__optname = { "prompt", NULL }; static struct optname q2_optname = { "silent", NULL }; static struct optname q_optname = { "quiet", &q2_optname }; static struct optname r_optname = { "raw-control-chars", NULL }; static struct optname s_optname = { "squeeze-blank-lines", NULL }; static struct optname S__optname = { "chop-long-lines", NULL }; #if TAGS static struct optname t_optname = { "tag", NULL }; static struct optname T__optname = { "tag-file", NULL }; #endif static struct optname u_optname = { "underline-special", NULL }; static struct optname V__optname = { "version", NULL }; static struct optname w_optname = { "hilite-unread", NULL }; static struct optname x_optname = { "tabs", NULL }; static struct optname X__optname = { "no-init", NULL }; static struct optname y_optname = { "max-forw-scroll", NULL }; static struct optname z_optname = { "window", NULL }; static struct optname quote_optname = { "quotes", NULL }; static struct optname tilde_optname = { "tilde", NULL }; static struct optname query_optname = { "help", NULL }; static struct optname pound_optname = { "shift", NULL }; static struct optname keypad_optname = { "no-keypad", NULL }; static struct optname oldbot_optname = { "old-bot", NULL }; static struct optname follow_optname = { "follow-name", NULL }; static struct optname use_backslash_optname = { "use-backslash", NULL }; /* * Table of all options and their semantics. * * For BOOL and TRIPLE options, odesc[0], odesc[1], odesc[2] are * the description of the option when set to 0, 1 or 2, respectively. * For NUMBER options, odesc[0] is the prompt to use when entering * a new value, and odesc[1] is the description, which should contain * one %d which is replaced by the value of the number. * For STRING options, odesc[0] is the prompt to use when entering * a new value, and odesc[1], if not NULL, is the set of characters * that are valid in the string. */ static struct loption option[] = { { 'a', &a_optname, TRIPLE, OPT_ONPLUS, &how_search, NULL, { "Search includes displayed screen", "Search skips displayed screen", "Search includes all of displayed screen" } }, { 'b', &b_optname, NUMBER|INIT_HANDLER, 64, &bufspace, opt_b, { "Max buffer space per file (K): ", "Max buffer space per file: %dK", NULL } }, { 'B', &B__optname, BOOL, OPT_ON, &autobuf, NULL, { "Don't automatically allocate buffers", "Automatically allocate buffers when needed", NULL } }, { 'c', &c_optname, TRIPLE, OPT_OFF, &top_scroll, NULL, { "Repaint by scrolling from bottom of screen", "Repaint by painting from top of screen", "Repaint by painting from top of screen" } }, { 'd', &d_optname, BOOL|NO_TOGGLE, OPT_OFF, &know_dumb, NULL, { "Assume intelligent terminal", "Assume dumb terminal", NULL } }, #if MSDOS_COMPILER { 'D', &D__optname, STRING|REPAINT|NO_QUERY, 0, NULL, opt_D, { "color desc: ", "Ddknsu0123456789.", NULL } }, #endif { 'e', &e_optname, TRIPLE, OPT_OFF, &quit_at_eof, NULL, { "Don't quit at end-of-file", "Quit at end-of-file", "Quit immediately at end-of-file" } }, { 'f', &f_optname, BOOL, OPT_OFF, &force_open, NULL, { "Open only regular files", "Open even non-regular files", NULL } }, { 'F', &F__optname, BOOL, OPT_OFF, &quit_if_one_screen, NULL, { "Don't quit if end-of-file on first screen", "Quit if end-of-file on first screen", NULL } }, #if HILITE_SEARCH { 'g', &g_optname, TRIPLE|HL_REPAINT, OPT_ONPLUS, &hilite_search, NULL, { "Don't highlight search matches", "Highlight matches for previous search only", "Highlight all matches for previous search pattern", } }, #endif { 'h', &h_optname, NUMBER, -1, &back_scroll, NULL, { "Backwards scroll limit: ", "Backwards scroll limit is %d lines", NULL } }, { 'i', &i_optname, TRIPLE|HL_REPAINT, OPT_OFF, &caseless, opt_i, { "Case is significant in searches", "Ignore case in searches", "Ignore case in searches and in patterns" } }, { 'j', &j_optname, STRING, 0, NULL, opt_j, { "Target line: ", "0123456789.-", NULL } }, { 'J', &J__optname, BOOL|REPAINT, OPT_OFF, &status_col, NULL, { "Don't display a status column", "Display a status column", NULL } }, #if USERFILE { 'k', &k_optname, STRING|NO_TOGGLE|NO_QUERY, 0, NULL, opt_k, { NULL, NULL, NULL } }, #endif { 'K', &K__optname, BOOL, OPT_OFF, &quit_on_intr, NULL, { "Interrupt (ctrl-C) returns to prompt", "Interrupt (ctrl-C) exits less", NULL } }, { 'L', &L__optname, BOOL, OPT_ON, &use_lessopen, NULL, { "Don't use the LESSOPEN filter", "Use the LESSOPEN filter", NULL } }, { 'm', &m_optname, TRIPLE, OPT_OFF, &pr_type, NULL, { "Short prompt", "Medium prompt", "Long prompt" } }, { 'n', &n_optname, TRIPLE|REPAINT, OPT_ON, &linenums, NULL, { "Don't use line numbers", "Use line numbers", "Constantly display line numbers" } }, #if LOGFILE { 'o', &o_optname, STRING, 0, NULL, opt_o, { "log file: ", NULL, NULL } }, { 'O', &O__optname, STRING, 0, NULL, opt__O, { "Log file: ", NULL, NULL } }, #endif { 'p', &p_optname, STRING|NO_TOGGLE|NO_QUERY, 0, NULL, opt_p, { NULL, NULL, NULL } }, { 'P', &P__optname, STRING, 0, NULL, opt__P, { "prompt: ", NULL, NULL } }, { 'q', &q_optname, TRIPLE, OPT_OFF, &quiet, NULL, { "Ring the bell for errors AND at eof/bof", "Ring the bell for errors but not at eof/bof", "Never ring the bell" } }, { 'r', &r_optname, TRIPLE|REPAINT, OPT_OFF, &ctldisp, NULL, { "Display control characters as ^X", "Display control characters directly", "Display control characters directly, processing ANSI sequences" } }, { 's', &s_optname, BOOL|REPAINT, OPT_OFF, &squeeze, NULL, { "Display all blank lines", "Squeeze multiple blank lines", NULL } }, { 'S', &S__optname, BOOL|REPAINT, OPT_OFF, &chopline, NULL, { "Fold long lines", "Chop long lines", NULL } }, #if TAGS { 't', &t_optname, STRING|NO_QUERY, 0, NULL, opt_t, { "tag: ", NULL, NULL } }, { 'T', &T__optname, STRING, 0, NULL, opt__T, { "tags file: ", NULL, NULL } }, #endif { 'u', &u_optname, TRIPLE|REPAINT, OPT_OFF, &bs_mode, NULL, { "Display underlined text in underline mode", "Backspaces cause overstrike", "Print backspace as ^H" } }, { 'V', &V__optname, NOVAR, 0, NULL, opt__V, { NULL, NULL, NULL } }, { 'w', &w_optname, TRIPLE|REPAINT, OPT_OFF, &show_attn, NULL, { "Don't highlight first unread line", "Highlight first unread line after forward-screen", "Highlight first unread line after any forward movement", } }, { 'x', &x_optname, STRING|REPAINT, 0, NULL, opt_x, { "Tab stops: ", "0123456789,", NULL } }, { 'X', &X__optname, BOOL|NO_TOGGLE, OPT_OFF, &no_init, NULL, { "Send init/deinit strings to terminal", "Don't use init/deinit strings", NULL } }, { 'y', &y_optname, NUMBER, -1, &forw_scroll, NULL, { "Forward scroll limit: ", "Forward scroll limit is %d lines", NULL } }, { 'z', &z_optname, NUMBER, -1, &swindow, NULL, { "Scroll window size: ", "Scroll window size is %d lines", NULL } }, { '"', "e_optname, STRING, 0, NULL, opt_quote, { "quotes: ", NULL, NULL } }, { '~', &tilde_optname, BOOL|REPAINT, OPT_ON, &twiddle, NULL, { "Don't show tildes after end of file", "Show tildes after end of file", NULL } }, { '?', &query_optname, NOVAR, 0, NULL, opt_query, { NULL, NULL, NULL } }, { '#', £_optname, STRING, 0, NULL, opt_shift, { "Horizontal shift: ", "0123456789.", NULL } }, { OLETTER_NONE, &keypad_optname, BOOL|NO_TOGGLE, OPT_OFF, &no_keypad, NULL, { "Use keypad mode", "Don't use keypad mode", NULL } }, { OLETTER_NONE, &oldbot_optname, BOOL, OPT_OFF, &oldbot, NULL, { "Use new bottom of screen behavior", "Use old bottom of screen behavior", NULL } }, { OLETTER_NONE, &follow_optname, BOOL, FOLLOW_DESC, &follow_mode, NULL, { "F command follows file descriptor", "F command follows file name", NULL } }, { OLETTER_NONE, &use_backslash_optname, BOOL, OPT_OFF, &opt_use_backslash, NULL, { "Use backslash escaping in command line parameters", "Don't use backslash escaping in command line parameters", NULL } }, { '\0', NULL, NOVAR, 0, NULL, NULL, { NULL, NULL, NULL } } }; /* * Initialize each option to its default value. */ public void -init_option() +init_option(void) { - register struct loption *o; + struct loption *o; char *p; p = lgetenv("LESS_IS_MORE"); if (p != NULL && *p != '\0') less_is_more = 1; for (o = option; o->oletter != '\0'; o++) { /* * Set each variable to its default. */ if (o->ovar != NULL) *(o->ovar) = o->odefault; if (o->otype & INIT_HANDLER) (*(o->ofunc))(INIT, (char *) NULL); } } /* * Find an option in the option table, given its option letter. */ public struct loption * -findopt(c) - int c; +findopt(int c) { - register struct loption *o; + struct loption *o; for (o = option; o->oletter != '\0'; o++) { if (o->oletter == c) return (o); if ((o->otype & TRIPLE) && ASCII_TO_UPPER(o->oletter) == c) return (o); } return (NULL); } /* * */ static int -is_optchar(c) - char c; +is_optchar(char c) { if (ASCII_IS_UPPER(c)) return 1; if (ASCII_IS_LOWER(c)) return 1; if (c == '-') return 1; return 0; } /* * Find an option in the option table, given its option name. * p_optname is the (possibly partial) name to look for, and * is updated to point after the matched name. * p_oname if non-NULL is set to point to the full option name. */ public struct loption * -findopt_name(p_optname, p_oname, p_err) - char **p_optname; - char **p_oname; - int *p_err; +findopt_name(char **p_optname, char **p_oname, int *p_err) { char *optname = *p_optname; - register struct loption *o; - register struct optname *oname; - register int len; + struct loption *o; + struct optname *oname; + int len; int uppercase; struct loption *maxo = NULL; struct optname *maxoname = NULL; int maxlen = 0; int ambig = 0; int exact = 0; /* * Check all options. */ for (o = option; o->oletter != '\0'; o++) { /* * Check all names for this option. */ for (oname = o->onames; oname != NULL; oname = oname->onext) { /* * Try normal match first (uppercase == 0), * then, then if it's a TRIPLE option, * try uppercase match (uppercase == 1). */ for (uppercase = 0; uppercase <= 1; uppercase++) { len = sprefix(optname, oname->oname, uppercase); if (len <= 0 || is_optchar(optname[len])) { /* * We didn't use all of the option name. */ continue; } if (!exact && len == maxlen) /* * Already had a partial match, * and now there's another one that * matches the same length. */ ambig = 1; else if (len > maxlen) { /* * Found a better match than * the one we had. */ maxo = o; maxoname = oname; maxlen = len; ambig = 0; exact = (len == (int)strlen(oname->oname)); } if (!(o->otype & TRIPLE)) break; } } } if (ambig) { /* * Name matched more than one option. */ if (p_err != NULL) *p_err = OPT_AMBIG; return (NULL); } *p_optname = optname + maxlen; if (p_oname != NULL) *p_oname = maxoname == NULL ? NULL : maxoname->oname; return (maxo); } Index: head/contrib/less/os.c =================================================================== --- head/contrib/less/os.c (revision 316338) +++ head/contrib/less/os.c (revision 316339) @@ -1,357 +1,345 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Operating system dependent routines. * * Most of the stuff in here is based on Unix, but an attempt * has been made to make things work on other operating systems. * This will sometimes result in a loss of functionality, unless * someone rewrites code specifically for the new operating system. * * The makefile provides defines to decide whether various * Unix features are present. */ #include "less.h" #include #include #if HAVE_TIME_H #include #endif #if HAVE_ERRNO_H #include #endif #if HAVE_VALUES_H #include #endif /* * BSD setjmp() saves (and longjmp() restores) the signal mask. * This costs a system call or two per setjmp(), so if possible we clear the * signal mask with sigsetmask(), and use _setjmp()/_longjmp() instead. * On other systems, setjmp() doesn't affect the signal mask and so * _setjmp() does not exist; we just use setjmp(). */ #if HAVE__SETJMP && HAVE_SIGSETMASK #define SET_JUMP _setjmp #define LONG_JUMP _longjmp #else #define SET_JUMP setjmp #define LONG_JUMP longjmp #endif public int reading; static jmp_buf read_label; extern int sigs; /* * Like read() system call, but is deliberately interruptible. * A call to intread() from a signal handler will interrupt * any pending iread(). */ public int -iread(fd, buf, len) - int fd; - char *buf; - unsigned int len; +iread(int fd, char *buf, unsigned int len) { - register int n; + int n; start: #if MSDOS_COMPILER==WIN32C if (ABORT_SIGS()) return (READ_INTR); #else #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC if (kbhit()) { int c; c = getch(); if (c == '\003') return (READ_INTR); ungetch(c); } #endif #endif if (SET_JUMP(read_label)) { /* * We jumped here from intread. */ reading = 0; #if HAVE_SIGPROCMASK { sigset_t mask; sigemptyset(&mask); sigprocmask(SIG_SETMASK, &mask, NULL); } #else #if HAVE_SIGSETMASK sigsetmask(0); #else #ifdef _OSK sigmask(~0); #endif #endif #endif return (READ_INTR); } flush(); reading = 1; #if MSDOS_COMPILER==DJGPPC if (isatty(fd)) { /* * Don't try reading from a TTY until a character is * available, because that makes some background programs * believe DOS is busy in a way that prevents those * programs from working while "less" waits. */ fd_set readfds; FD_ZERO(&readfds); FD_SET(fd, &readfds); if (select(fd+1, &readfds, 0, 0, 0) == -1) return (-1); } #endif n = read(fd, buf, len); #if 1 /* * This is a kludge to workaround a problem on some systems * where terminating a remote tty connection causes read() to * start returning 0 forever, instead of -1. */ { extern int ignore_eoi; if (!ignore_eoi) { static int consecutive_nulls = 0; if (n == 0) consecutive_nulls++; else consecutive_nulls = 0; if (consecutive_nulls > 20) quit(QUIT_ERROR); } } #endif reading = 0; if (n < 0) { #if HAVE_ERRNO /* * Certain values of errno indicate we should just retry the read. */ #if MUST_DEFINE_ERRNO extern int errno; #endif #ifdef EINTR if (errno == EINTR) goto start; #endif #ifdef EAGAIN if (errno == EAGAIN) goto start; #endif #endif return (-1); } return (n); } /* * Interrupt a pending iread(). */ public void -intread() +intread(void) { LONG_JUMP(read_label, 1); } /* * Return the current time. */ #if HAVE_TIME public time_type -get_time() +get_time(void) { time_type t; time(&t); return (t); } #endif #if !HAVE_STRERROR /* * Local version of strerror, if not available from the system. */ static char * -strerror(err) - int err; +strerror(int err) { #if HAVE_SYS_ERRLIST static char buf[16]; extern char *sys_errlist[]; extern int sys_nerr; if (err < sys_nerr) return sys_errlist[err]; sprintf(buf, "Error %d", err); return buf; #else return ("cannot open"); #endif } #endif /* * errno_message: Return an error message based on the value of "errno". */ public char * -errno_message(filename) - char *filename; +errno_message(char *filename) { - register char *p; - register char *m; + char *p; + char *m; int len; #if HAVE_ERRNO #if MUST_DEFINE_ERRNO extern int errno; #endif p = strerror(errno); #else p = "cannot open"; #endif len = (int) (strlen(filename) + strlen(p) + 3); m = (char *) ecalloc(len, sizeof(char)); SNPRINTF2(m, len, "%s: %s", filename, p); return (m); } /* #define HAVE_FLOAT 0 */ static POSITION -muldiv(val, num, den) - POSITION val, num, den; +muldiv(POSITION val, POSITION num, POSITION den) { #if HAVE_FLOAT double v = (((double) val) * num) / den; return ((POSITION) (v + 0.5)); #else POSITION v = ((POSITION) val) * num; if (v / num == val) /* No overflow */ return (POSITION) (v / den); else /* Above calculation overflows; * use a method that is less precise but won't overflow. */ return (POSITION) (val / (den / num)); #endif } /* * Return the ratio of two POSITIONS, as a percentage. * {{ Assumes a POSITION is a long int. }} */ public int -percentage(num, den) - POSITION num, den; +percentage(POSITION num, POSITION den) { return (int) muldiv(num, (POSITION) 100, den); } /* * Return the specified percentage of a POSITION. */ public POSITION -percent_pos(pos, percent, fraction) - POSITION pos; - int percent; - long fraction; +percent_pos(POSITION pos, int percent, long fraction) { /* Change percent (parts per 100) to perden (parts per NUM_FRAC_DENOM). */ POSITION perden = (percent * (NUM_FRAC_DENOM / 100)) + (fraction / 100); if (perden == 0) return (0); return (POSITION) muldiv(pos, perden, (POSITION) NUM_FRAC_DENOM); } #if !HAVE_STRCHR /* * strchr is used by regexp.c. */ char * strchr(s, c) char *s; int c; { for ( ; *s != '\0'; s++) if (*s == c) return (s); if (c == '\0') return (s); return (NULL); } #endif #if !HAVE_MEMCPY VOID_POINTER memcpy(dst, src, len) VOID_POINTER dst; VOID_POINTER src; int len; { char *dstp = (char *) dst; char *srcp = (char *) src; int i; for (i = 0; i < len; i++) dstp[i] = srcp[i]; return (dst); } #endif #ifdef _OSK_MWC32 /* * This implements an ANSI-style intercept setup for Microware C 3.2 */ public int -os9_signal(type, handler) - int type; - RETSIGTYPE (*handler)(); +os9_signal(int type, RETSIGTYPE (*handler)()) { intercept(handler); } #include int isatty(f) int f; { struct sgbuf sgbuf; if (_gs_opt(f, &sgbuf) < 0) return -1; return (sgbuf.sg_class == 0); } #endif Index: head/contrib/less/output.c =================================================================== --- head/contrib/less/output.c (revision 316338) +++ head/contrib/less/output.c (revision 316339) @@ -1,614 +1,602 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * High level routines dealing with the output to the screen. */ #include "less.h" #if MSDOS_COMPILER==WIN32C #include "windows.h" #endif public int errmsgs; /* Count of messages displayed by error() */ public int need_clr; public int final_attr; public int at_prompt; extern int sigs; extern int sc_width; extern int so_s_width, so_e_width; extern int screen_trashed; extern int any_display; extern int is_tty; extern int oldbot; #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC extern int ctldisp; extern int nm_fg_color, nm_bg_color; extern int bo_fg_color, bo_bg_color; extern int ul_fg_color, ul_bg_color; extern int so_fg_color, so_bg_color; extern int bl_fg_color, bl_bg_color; #endif /* * Display the line which is in the line buffer. */ public void -put_line() +put_line(void) { - register int c; - register int i; + int c; + int i; int a; if (ABORT_SIGS()) { /* * Don't output if a signal is pending. */ screen_trashed = 1; return; } final_attr = AT_NORMAL; for (i = 0; (c = gline(i, &a)) != '\0'; i++) { at_switch(a); final_attr = a; if (c == '\b') putbs(); else putchr(c); } at_exit(); } static char obuf[OUTBUF_SIZE]; static char *ob = obuf; /* * Flush buffered output. * * If we haven't displayed any file data yet, * output messages on error output (file descriptor 2), * otherwise output on standard output (file descriptor 1). * * This has the desirable effect of producing all * error messages on error output if standard output * is directed to a file. It also does the same if * we never produce any real output; for example, if * the input file(s) cannot be opened. If we do * eventually produce output, code in edit() makes * sure these messages can be seen before they are * overwritten or scrolled away. */ public void -flush() +flush(void) { - register int n; - register int fd; + int n; + int fd; n = (int) (ob - obuf); if (n == 0) return; #if MSDOS_COMPILER==MSOFTC if (is_tty && any_display) { *ob = '\0'; _outtext(obuf); ob = obuf; return; } #else #if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC if (is_tty && any_display) { *ob = '\0'; if (ctldisp != OPT_ONPLUS) WIN32textout(obuf, ob - obuf); else { /* * Look for SGR escape sequences, and convert them * to color commands. Replace bold, underline, * and italic escapes into colors specified via * the -D command-line option. */ char *anchor, *p, *p_next; unsigned char fg, bg; static unsigned char at; #if MSDOS_COMPILER==WIN32C /* Screen colors used by 3x and 4x SGR commands. */ static unsigned char screen_color[] = { 0, /* BLACK */ FOREGROUND_RED, FOREGROUND_GREEN, FOREGROUND_RED|FOREGROUND_GREEN, FOREGROUND_BLUE, FOREGROUND_BLUE|FOREGROUND_RED, FOREGROUND_BLUE|FOREGROUND_GREEN, FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_RED }; #else static enum COLORS screen_color[] = { BLACK, RED, GREEN, BROWN, BLUE, MAGENTA, CYAN, LIGHTGRAY }; #endif for (anchor = p_next = obuf; (p_next = memchr(p_next, ESC, ob - p_next)) != NULL; ) { p = p_next; if (p[1] == '[') /* "ESC-[" sequence */ { if (p > anchor) { /* * If some chars seen since * the last escape sequence, * write them out to the screen. */ WIN32textout(anchor, p-anchor); anchor = p; } p += 2; /* Skip the "ESC-[" */ if (is_ansi_end(*p)) { /* * Handle null escape sequence * "ESC[m", which restores * the normal color. */ p++; anchor = p_next = p; at = 0; WIN32setcolors(nm_fg_color, nm_bg_color); continue; } p_next = p; /* * Select foreground/background colors * based on the escape sequence. */ fg = nm_fg_color; bg = nm_bg_color; while (!is_ansi_end(*p)) { char *q; long code = strtol(p, &q, 10); if (*q == '\0') { /* * Incomplete sequence. * Leave it unprocessed * in the buffer. */ int slop = (int) (q - anchor); /* {{ strcpy args overlap! }} */ strcpy(obuf, anchor); ob = &obuf[slop]; return; } if (q == p || code > 49 || code < 0 || (!is_ansi_end(*q) && *q != ';')) { p_next = q; break; } if (*q == ';') q++; switch (code) { default: /* case 0: all attrs off */ fg = nm_fg_color; bg = nm_bg_color; at = 0; break; case 1: /* bold on */ at |= 1; break; case 3: /* italic on */ case 7: /* inverse on */ at |= 2; break; case 4: /* underline on */ at |= 4; break; case 5: /* slow blink on */ case 6: /* fast blink on */ at |= 8; break; case 8: /* concealed on */ fg = (bg & 7) | 8; break; case 22: /* bold off */ at &= ~1; break; case 23: /* italic off */ case 27: /* inverse off */ at &= ~2; break; case 24: /* underline off */ at &= ~4; break; case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: fg = (fg & 8) | (screen_color[code - 30]); break; case 39: /* default fg */ fg = nm_fg_color; break; case 40: case 41: case 42: case 43: case 44: case 45: case 46: case 47: bg = (bg & 8) | (screen_color[code - 40]); break; case 49: /* default fg */ bg = nm_bg_color; break; } p = q; } if (!is_ansi_end(*p) || p == p_next) break; if (at & 1) { /* * If \e[1m use defined bold * color, else set intensity. */ if (p[-2] == '[') { #if MSDOS_COMPILER==WIN32C fg |= FOREGROUND_INTENSITY; bg |= BACKGROUND_INTENSITY; #else fg = bo_fg_color; bg = bo_bg_color; #endif } else fg |= 8; } else if (at & 2) { fg = so_fg_color; bg = so_bg_color; } else if (at & 4) { fg = ul_fg_color; bg = ul_bg_color; } else if (at & 8) { fg = bl_fg_color; bg = bl_bg_color; } fg &= 0xf; bg &= 0xf; WIN32setcolors(fg, bg); p_next = anchor = p + 1; } else p_next++; } /* Output what's left in the buffer. */ WIN32textout(anchor, ob - anchor); } ob = obuf; return; } #endif #endif fd = (any_display) ? 1 : 2; if (write(fd, obuf, n) != n) screen_trashed = 1; ob = obuf; } /* * Output a character. */ public int -putchr(c) - int c; +putchr(int c) { #if 0 /* fake UTF-8 output for testing */ extern int utf_mode; if (utf_mode) { static char ubuf[MAX_UTF_CHAR_LEN]; static int ubuf_len = 0; static int ubuf_index = 0; if (ubuf_len == 0) { ubuf_len = utf_len(c); ubuf_index = 0; } ubuf[ubuf_index++] = c; if (ubuf_index < ubuf_len) return c; c = get_wchar(ubuf) & 0xFF; ubuf_len = 0; } #endif if (need_clr) { need_clr = 0; clear_bot(); } #if MSDOS_COMPILER if (c == '\n' && is_tty) { /* remove_top(1); */ putchr('\r'); } #else #ifdef _OSK if (c == '\n' && is_tty) /* In OS-9, '\n' == 0x0D */ putchr(0x0A); #endif #endif /* * Some versions of flush() write to *ob, so we must flush * when we are still one char from the end of obuf. */ if (ob >= &obuf[sizeof(obuf)-1]) flush(); *ob++ = c; at_prompt = 0; return (c); } /* * Output a string. */ public void -putstr(s) - register char *s; +putstr(constant char *s) { while (*s != '\0') putchr(*s++); } /* * Convert an integral type to a string. */ #define TYPE_TO_A_FUNC(funcname, type) \ void funcname(num, buf) \ type num; \ char *buf; \ { \ int neg = (num < 0); \ char tbuf[INT_STRLEN_BOUND(num)+2]; \ - register char *s = tbuf + sizeof(tbuf); \ + char *s = tbuf + sizeof(tbuf); \ if (neg) num = -num; \ *--s = '\0'; \ do { \ *--s = (num % 10) + '0'; \ } while ((num /= 10) != 0); \ if (neg) *--s = '-'; \ strcpy(buf, s); \ } TYPE_TO_A_FUNC(postoa, POSITION) TYPE_TO_A_FUNC(linenumtoa, LINENUM) TYPE_TO_A_FUNC(inttoa, int) /* * Output an integer in a given radix. */ static int -iprint_int(num) - int num; +iprint_int(int num) { char buf[INT_STRLEN_BOUND(num)]; inttoa(num, buf); putstr(buf); return ((int) strlen(buf)); } /* * Output a line number in a given radix. */ static int -iprint_linenum(num) - LINENUM num; +iprint_linenum(LINENUM num) { char buf[INT_STRLEN_BOUND(num)]; linenumtoa(num, buf); putstr(buf); return ((int) strlen(buf)); } /* * This function implements printf-like functionality * using a more portable argument list mechanism than printf's. */ static int -less_printf(fmt, parg) - register char *fmt; - PARG *parg; +less_printf(char *fmt, PARG *parg) { - register char *s; - register int col; + char *s; + int col; col = 0; while (*fmt != '\0') { if (*fmt != '%') { putchr(*fmt++); col++; } else { ++fmt; switch (*fmt++) { case 's': s = parg->p_string; parg++; while (*s != '\0') { putchr(*s++); col++; } break; case 'd': col += iprint_int(parg->p_int); parg++; break; case 'n': col += iprint_linenum(parg->p_linenum); parg++; break; } } } return (col); } /* * Get a RETURN. * If some other non-trivial char is pressed, unget it, so it will * become the next command. */ public void -get_return() +get_return(void) { int c; #if ONLY_RETURN while ((c = getchr()) != '\n' && c != '\r') bell(); #else c = getchr(); if (c != '\n' && c != '\r' && c != ' ' && c != READ_INTR) ungetcc(c); #endif } /* * Output a message in the lower left corner of the screen * and wait for carriage return. */ public void -error(fmt, parg) - char *fmt; - PARG *parg; +error(char *fmt, PARG *parg) { int col = 0; static char return_to_continue[] = " (press RETURN)"; errmsgs++; if (any_display && is_tty) { if (!oldbot) squish_check(); at_exit(); clear_bot(); at_enter(AT_STANDOUT); col += so_s_width; } col += less_printf(fmt, parg); if (!(any_display && is_tty)) { putchr('\n'); return; } putstr(return_to_continue); at_exit(); col += sizeof(return_to_continue) + so_e_width; get_return(); lower_left(); clear_eol(); if (col >= sc_width) /* * Printing the message has probably scrolled the screen. * {{ Unless the terminal doesn't have auto margins, * in which case we just hammered on the right margin. }} */ screen_trashed = 1; flush(); } static char intr_to_abort[] = "... (interrupt to abort)"; /* * Output a message in the lower left corner of the screen * and don't wait for carriage return. * Usually used to warn that we are beginning a potentially * time-consuming operation. */ public void -ierror(fmt, parg) - char *fmt; - PARG *parg; +ierror(char *fmt, PARG *parg) { at_exit(); clear_bot(); at_enter(AT_STANDOUT); (void) less_printf(fmt, parg); putstr(intr_to_abort); at_exit(); flush(); need_clr = 1; } /* * Output a message in the lower left corner of the screen * and return a single-character response. */ public int -query(fmt, parg) - char *fmt; - PARG *parg; +query(char *fmt, PARG *parg) { - register int c; + int c; int col = 0; if (any_display && is_tty) clear_bot(); (void) less_printf(fmt, parg); c = getchr(); if (!(any_display && is_tty)) { putchr('\n'); return (c); } lower_left(); if (col >= sc_width) screen_trashed = 1; flush(); return (c); } Index: head/contrib/less/pattern.c =================================================================== --- head/contrib/less/pattern.c (revision 316338) +++ head/contrib/less/pattern.c (revision 316339) @@ -1,404 +1,381 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines to do pattern matching. */ #include "less.h" #include "pattern.h" extern int caseless; /* * Compile a search pattern, for future use by match_pattern. */ static int -compile_pattern2(pattern, search_type, comp_pattern, show_error) - char *pattern; - int search_type; - void **comp_pattern; - int show_error; +compile_pattern2(char *pattern, int search_type, void **comp_pattern, int show_error) { if (search_type & SRCH_NO_REGEX) return (0); { #if HAVE_GNU_REGEX struct re_pattern_buffer *comp = (struct re_pattern_buffer *) ecalloc(1, sizeof(struct re_pattern_buffer)); struct re_pattern_buffer **pcomp = (struct re_pattern_buffer **) comp_pattern; re_set_syntax(RE_SYNTAX_POSIX_EXTENDED); if (re_compile_pattern(pattern, strlen(pattern), comp)) { free(comp); if (show_error) error("Invalid pattern", NULL_PARG); return (-1); } if (*pcomp != NULL) regfree(*pcomp); *pcomp = comp; #endif #if HAVE_POSIX_REGCOMP regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t)); regex_t **pcomp = (regex_t **) comp_pattern; if (regcomp(comp, pattern, REGCOMP_FLAG)) { free(comp); if (show_error) error("Invalid pattern", NULL_PARG); return (-1); } if (*pcomp != NULL) regfree(*pcomp); *pcomp = comp; #endif #if HAVE_PCRE pcre *comp; pcre **pcomp = (pcre **) comp_pattern; constant char *errstring; int erroffset; PARG parg; comp = pcre_compile(pattern, 0, &errstring, &erroffset, NULL); if (comp == NULL) { parg.p_string = (char *) errstring; if (show_error) error("%s", &parg); return (-1); } *pcomp = comp; #endif #if HAVE_RE_COMP PARG parg; int *pcomp = (int *) comp_pattern; if ((parg.p_string = re_comp(pattern)) != NULL) { if (show_error) error("%s", &parg); return (-1); } *pcomp = 1; #endif #if HAVE_REGCMP char *comp; char **pcomp = (char **) comp_pattern; if ((comp = regcmp(pattern, 0)) == NULL) { if (show_error) error("Invalid pattern", NULL_PARG); return (-1); } if (pcomp != NULL) free(*pcomp); *pcomp = comp; #endif #if HAVE_V8_REGCOMP struct regexp *comp; struct regexp **pcomp = (struct regexp **) comp_pattern; reg_show_error = show_error; comp = regcomp(pattern); reg_show_error = 1; if (comp == NULL) { /* * regcomp has already printed an error message * via regerror(). */ return (-1); } if (*pcomp != NULL) free(*pcomp); *pcomp = comp; #endif } return (0); } /* * Like compile_pattern2, but convert the pattern to lowercase if necessary. */ public int -compile_pattern(pattern, search_type, comp_pattern) - char *pattern; - int search_type; - void **comp_pattern; +compile_pattern(char *pattern, int search_type, void **comp_pattern) { char *cvt_pattern; int result; if (caseless != OPT_ONPLUS) cvt_pattern = pattern; else { cvt_pattern = (char*) ecalloc(1, cvt_length(strlen(pattern), CVT_TO_LC)); cvt_text(cvt_pattern, pattern, (int *)NULL, (int *)NULL, CVT_TO_LC); } result = compile_pattern2(cvt_pattern, search_type, comp_pattern, 1); if (cvt_pattern != pattern) free(cvt_pattern); return (result); } /* * Forget that we have a compiled pattern. */ public void -uncompile_pattern(pattern) - void **pattern; +uncompile_pattern(void **pattern) { #if HAVE_GNU_REGEX struct re_pattern_buffer **pcomp = (struct re_pattern_buffer **) pattern; if (*pcomp != NULL) regfree(*pcomp); *pcomp = NULL; #endif #if HAVE_POSIX_REGCOMP regex_t **pcomp = (regex_t **) pattern; if (*pcomp != NULL) regfree(*pcomp); *pcomp = NULL; #endif #if HAVE_PCRE pcre **pcomp = (pcre **) pattern; if (*pcomp != NULL) pcre_free(*pcomp); *pcomp = NULL; #endif #if HAVE_RE_COMP int *pcomp = (int *) pattern; *pcomp = 0; #endif #if HAVE_REGCMP char **pcomp = (char **) pattern; if (*pcomp != NULL) free(*pcomp); *pcomp = NULL; #endif #if HAVE_V8_REGCOMP struct regexp **pcomp = (struct regexp **) pattern; if (*pcomp != NULL) free(*pcomp); *pcomp = NULL; #endif } /* * Can a pattern be successfully compiled? */ public int -valid_pattern(pattern) - char *pattern; +valid_pattern(char *pattern) { void *comp_pattern; int result; CLEAR_PATTERN(comp_pattern); result = compile_pattern2(pattern, 0, &comp_pattern, 0); if (result != 0) return (0); uncompile_pattern(&comp_pattern); return (1); } /* * Is a compiled pattern null? */ public int -is_null_pattern(pattern) - void *pattern; +is_null_pattern(void *pattern) { #if HAVE_GNU_REGEX return (pattern == NULL); #endif #if HAVE_POSIX_REGCOMP return (pattern == NULL); #endif #if HAVE_PCRE return (pattern == NULL); #endif #if HAVE_RE_COMP return (pattern == 0); #endif #if HAVE_REGCMP return (pattern == NULL); #endif #if HAVE_V8_REGCOMP return (pattern == NULL); #endif #if NO_REGEX return (pattern == NULL); #endif } /* * Simple pattern matching function. * It supports no metacharacters like *, etc. */ static int -match(pattern, pattern_len, buf, buf_len, pfound, pend) - char *pattern; - int pattern_len; - char *buf; - int buf_len; - char **pfound, **pend; +match(char *pattern, int pattern_len, char *buf, int buf_len, char **pfound, char **pend) { - register char *pp, *lp; - register char *pattern_end = pattern + pattern_len; - register char *buf_end = buf + buf_len; + char *pp, *lp; + char *pattern_end = pattern + pattern_len; + char *buf_end = buf + buf_len; for ( ; buf < buf_end; buf++) { for (pp = pattern, lp = buf; ; pp++, lp++) { char cp = *pp; char cl = *lp; if (caseless == OPT_ONPLUS && ASCII_IS_UPPER(cp)) cp = ASCII_TO_LOWER(cp); if (cp != cl) break; if (pp == pattern_end || lp == buf_end) break; } if (pp == pattern_end) { if (pfound != NULL) *pfound = buf; if (pend != NULL) *pend = lp; return (1); } } return (0); } /* * Perform a pattern match with the previously compiled pattern. * Set sp and ep to the start and end of the matched string. */ public int -match_pattern(pattern, tpattern, line, line_len, sp, ep, notbol, search_type) - void *pattern; - char *tpattern; - char *line; - int line_len; - char **sp; - char **ep; - int notbol; - int search_type; +match_pattern(void *pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int notbol, int search_type) { int matched; #if HAVE_GNU_REGEX struct re_pattern_buffer *spattern = (struct re_pattern_buffer *) pattern; #endif #if HAVE_POSIX_REGCOMP regex_t *spattern = (regex_t *) pattern; #endif #if HAVE_PCRE pcre *spattern = (pcre *) pattern; #endif #if HAVE_RE_COMP int spattern = (int) pattern; #endif #if HAVE_REGCMP char *spattern = (char *) pattern; #endif #if HAVE_V8_REGCOMP struct regexp *spattern = (struct regexp *) pattern; #endif *sp = *ep = NULL; #if NO_REGEX search_type |= SRCH_NO_REGEX; #endif if (search_type & SRCH_NO_REGEX) matched = match(tpattern, strlen(tpattern), line, line_len, sp, ep); else { #if HAVE_GNU_REGEX { struct re_registers search_regs; spattern->not_bol = notbol; spattern->regs_allocated = REGS_UNALLOCATED; matched = re_search(spattern, line, line_len, 0, line_len, &search_regs) >= 0; if (matched) { *sp = line + search_regs.start[0]; *ep = line + search_regs.end[0]; } } #endif #if HAVE_POSIX_REGCOMP { regmatch_t rm; int flags = (notbol) ? REG_NOTBOL : 0; #ifdef REG_STARTEND flags |= REG_STARTEND; rm.rm_so = 0; rm.rm_eo = line_len; #endif matched = !regexec(spattern, line, 1, &rm, flags); if (matched) { #ifndef __WATCOMC__ *sp = line + rm.rm_so; *ep = line + rm.rm_eo; #else *sp = rm.rm_sp; *ep = rm.rm_ep; #endif } } #endif #if HAVE_PCRE { int flags = (notbol) ? PCRE_NOTBOL : 0; int ovector[3]; matched = pcre_exec(spattern, NULL, line, line_len, 0, flags, ovector, 3) >= 0; if (matched) { *sp = line + ovector[0]; *ep = line + ovector[1]; } } #endif #if HAVE_RE_COMP matched = (re_exec(line) == 1); /* * re_exec doesn't seem to provide a way to get the matched string. */ *sp = *ep = NULL; #endif #if HAVE_REGCMP *ep = regex(spattern, line); matched = (*ep != NULL); if (matched) *sp = __loc1; #endif #if HAVE_V8_REGCOMP #if HAVE_REGEXEC2 matched = regexec2(spattern, line, notbol); #else matched = regexec(spattern, line); #endif if (matched) { *sp = spattern->startp[0]; *ep = spattern->endp[0]; } #endif } matched = (!(search_type & SRCH_NO_MATCH) && matched) || ((search_type & SRCH_NO_MATCH) && !matched); return (matched); } Index: head/contrib/less/position.c =================================================================== --- head/contrib/less/position.c (revision 316338) +++ head/contrib/less/position.c (revision 316339) @@ -1,231 +1,223 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines dealing with the "position" table. * This is a table which tells the position (in the input file) of the * first char on each currently displayed line. * * {{ The position table is scrolled by moving all the entries. * Would be better to have a circular table * and just change a couple of pointers. }} */ #include "less.h" #include "position.h" static POSITION *table = NULL; /* The position table */ static int table_size; extern int sc_width, sc_height; /* * Return the starting file position of a line displayed on the screen. * The line may be specified as a line number relative to the top * of the screen, but is usually one of these special cases: * the top (first) line on the screen * the second line on the screen * the bottom line on the screen * the line after the bottom line on the screen */ public POSITION -position(where) - int where; +position(int where) { switch (where) { case BOTTOM: where = sc_height - 2; break; case BOTTOM_PLUS_ONE: where = sc_height - 1; break; case MIDDLE: where = (sc_height - 1) / 2; } return (table[where]); } /* * Add a new file position to the bottom of the position table. */ public void -add_forw_pos(pos) - POSITION pos; +add_forw_pos(POSITION pos) { - register int i; + int i; /* * Scroll the position table up. */ for (i = 1; i < sc_height; i++) table[i-1] = table[i]; table[sc_height - 1] = pos; } /* * Add a new file position to the top of the position table. */ public void -add_back_pos(pos) - POSITION pos; +add_back_pos(POSITION pos) { - register int i; + int i; /* * Scroll the position table down. */ for (i = sc_height - 1; i > 0; i--) table[i] = table[i-1]; table[0] = pos; } /* * Initialize the position table, done whenever we clear the screen. */ public void -pos_clear() +pos_clear(void) { - register int i; + int i; for (i = 0; i < sc_height; i++) table[i] = NULL_POSITION; } /* * Allocate or reallocate the position table. */ public void -pos_init() +pos_init(void) { struct scrpos scrpos; if (sc_height <= table_size) return; /* * If we already have a table, remember the first line in it * before we free it, so we can copy that line to the new table. */ if (table != NULL) { get_scrpos(&scrpos); free((char*)table); } else scrpos.pos = NULL_POSITION; table = (POSITION *) ecalloc(sc_height, sizeof(POSITION)); table_size = sc_height; pos_clear(); if (scrpos.pos != NULL_POSITION) table[scrpos.ln-1] = scrpos.pos; } /* * See if the byte at a specified position is currently on the screen. * Check the position table to see if the position falls within its range. * Return the position table entry if found, -1 if not. */ public int -onscreen(pos) - POSITION pos; +onscreen(POSITION pos) { - register int i; + int i; if (pos < table[0]) return (-1); for (i = 1; i < sc_height; i++) if (pos < table[i]) return (i-1); return (-1); } /* * See if the entire screen is empty. */ public int -empty_screen() +empty_screen(void) { return (empty_lines(0, sc_height-1)); } public int -empty_lines(s, e) - int s; - int e; +empty_lines(int s, int e) { - register int i; + int i; for (i = s; i <= e; i++) if (table[i] != NULL_POSITION && table[i] != 0) return (0); return (1); } /* * Get the current screen position. * The screen position consists of both a file position and * a screen line number where the file position is placed on the screen. * Normally the screen line number is 0, but if we are positioned * such that the top few lines are empty, we may have to set * the screen line to a number > 0. */ public void -get_scrpos(scrpos) - struct scrpos *scrpos; +get_scrpos(struct scrpos *scrpos) { - register int i; + int i; /* * Find the first line on the screen which has something on it, * and return the screen line number and the file position. */ for (i = 0; i < sc_height; i++) if (table[i] != NULL_POSITION) { scrpos->ln = i+1; scrpos->pos = table[i]; return; } /* * The screen is empty. */ scrpos->pos = NULL_POSITION; } /* * Adjust a screen line number to be a simple positive integer * in the range { 0 .. sc_height-2 }. * (The bottom line, sc_height-1, is reserved for prompts, etc.) * The given "sline" may be in the range { 1 .. sc_height-1 } * to refer to lines relative to the top of the screen (starting from 1), * or it may be in { -1 .. -(sc_height-1) } to refer to lines * relative to the bottom of the screen. */ public int -adjsline(sline) - int sline; +adjsline(int sline) { /* * Negative screen line number means * relative to the bottom of the screen. */ if (sline < 0) sline += sc_height; /* * Can't be less than 1 or greater than sc_height-1. */ if (sline <= 0) sline = 1; if (sline >= sc_height) sline = sc_height - 1; /* * Return zero-based line number, not one-based. */ return (sline-1); } Index: head/contrib/less/prompt.c =================================================================== --- head/contrib/less/prompt.c (revision 316338) +++ head/contrib/less/prompt.c (revision 316339) @@ -1,586 +1,570 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Prompting and other messages. * There are three flavors of prompts, SHORT, MEDIUM and LONG, * selected by the -m/-M options. * There is also the "equals message", printed by the = command. * A prompt is a message composed of various pieces, such as the * name of the file being viewed, the percentage into the file, etc. */ #include "less.h" #include "position.h" extern int pr_type; extern int new_file; extern int sc_width; extern int so_s_width, so_e_width; extern int linenums; extern int hshift; extern int sc_height; extern int jump_sline; extern int less_is_more; extern IFILE curr_ifile; #if EDITOR extern char *editor; extern char *editproto; #endif /* * Prototypes for the three flavors of prompts. * These strings are expanded by pr_expand(). */ static constant char s_proto[] = "?n?f%f .?m(%T %i of %m) ..?e(END) ?x- Next\\: %x..%t"; static constant char m_proto[] = "?n?f%f .?m(%T %i of %m) ..?e(END) ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t"; static constant char M_proto[] = "?f%f .?n?m(%T %i of %m) ..?ltlines %lt-%lb?L/%L. :byte %bB?s/%s. .?e(END) ?x- Next\\: %x.:?pB%pB\\%..%t"; static constant char e_proto[] = "?f%f .?m(%T %i of %m) .?ltlines %lt-%lb?L/%L. .byte %bB?s/%s. ?e(END) :?pB%pB\\%..%t"; static constant char h_proto[] = "HELP -- ?eEND -- Press g to see it again:Press RETURN for more., or q when done"; static constant char w_proto[] = "Waiting for data"; static constant char more_proto[] = "--More--(?eEND ?x- Next\\: %x.:?pB%pB\\%:byte %bB?s/%s...%t)"; public char *prproto[3]; public char constant *eqproto = e_proto; public char constant *hproto = h_proto; public char constant *wproto = w_proto; static char message[PROMPT_SIZE]; static char *mp; /* * Initialize the prompt prototype strings. */ public void -init_prompt() +init_prompt(void) { prproto[0] = save(s_proto); prproto[1] = save(less_is_more ? more_proto : m_proto); prproto[2] = save(M_proto); eqproto = save(e_proto); hproto = save(h_proto); wproto = save(w_proto); } /* * Append a string to the end of the message. */ static void -ap_str(s) - char *s; +ap_str(char *s) { int len; len = (int) strlen(s); if (mp + len >= message + PROMPT_SIZE) len = (int) (message + PROMPT_SIZE - mp - 1); strncpy(mp, s, len); mp += len; *mp = '\0'; } /* * Append a character to the end of the message. */ static void -ap_char(c) - char c; +ap_char(char c) { char buf[2]; buf[0] = c; buf[1] = '\0'; ap_str(buf); } /* * Append a POSITION (as a decimal integer) to the end of the message. */ static void -ap_pos(pos) - POSITION pos; +ap_pos(POSITION pos) { char buf[INT_STRLEN_BOUND(pos) + 2]; postoa(pos, buf); ap_str(buf); } /* * Append a line number to the end of the message. */ static void -ap_linenum(linenum) - LINENUM linenum; +ap_linenum(LINENUM linenum) { char buf[INT_STRLEN_BOUND(linenum) + 2]; linenumtoa(linenum, buf); ap_str(buf); } /* * Append an integer to the end of the message. */ static void -ap_int(num) - int num; +ap_int(int num) { char buf[INT_STRLEN_BOUND(num) + 2]; inttoa(num, buf); ap_str(buf); } /* * Append a question mark to the end of the message. */ static void -ap_quest() +ap_quest(void) { ap_str("?"); } /* * Return the "current" byte offset in the file. */ static POSITION -curr_byte(where) - int where; +curr_byte(int where) { POSITION pos; pos = position(where); while (pos == NULL_POSITION && where >= 0 && where < sc_height-1) pos = position(++where); if (pos == NULL_POSITION) pos = ch_length(); return (pos); } /* * Return the value of a prototype conditional. * A prototype string may include conditionals which consist of a * question mark followed by a single letter. * Here we decode that letter and return the appropriate boolean value. */ static int -cond(c, where) - char c; - int where; +cond(char c, int where) { POSITION len; switch (c) { case 'a': /* Anything in the message yet? */ return (mp > message); case 'b': /* Current byte offset known? */ return (curr_byte(where) != NULL_POSITION); case 'c': return (hshift != 0); case 'e': /* At end of file? */ return (eof_displayed()); case 'f': /* Filename known? */ return (strcmp(get_filename(curr_ifile), "-") != 0); case 'l': /* Line number known? */ case 'd': /* Same as l */ return (linenums); case 'L': /* Final line number known? */ case 'D': /* Final page number known? */ return (linenums && ch_length() != NULL_POSITION); case 'm': /* More than one file? */ #if TAGS return (ntags() ? (ntags() > 1) : (nifile() > 1)); #else return (nifile() > 1); #endif case 'n': /* First prompt in a new file? */ #if TAGS return (ntags() ? 1 : new_file); #else return (new_file); #endif case 'p': /* Percent into file (bytes) known? */ return (curr_byte(where) != NULL_POSITION && ch_length() > 0); case 'P': /* Percent into file (lines) known? */ return (currline(where) != 0 && (len = ch_length()) > 0 && find_linenum(len) != 0); case 's': /* Size of file known? */ case 'B': return (ch_length() != NULL_POSITION); case 'x': /* Is there a "next" file? */ #if TAGS if (ntags()) return (0); #endif return (next_ifile(curr_ifile) != NULL_IFILE); } return (0); } /* * Decode a "percent" prototype character. * A prototype string may include various "percent" escapes; * that is, a percent sign followed by a single letter. * Here we decode that letter and take the appropriate action, * usually by appending something to the message being built. */ static void -protochar(c, where, iseditproto) - int c; - int where; - int iseditproto; +protochar(int c, int where, int iseditproto) { POSITION pos; POSITION len; int n; LINENUM linenum; LINENUM last_linenum; IFILE h; #undef PAGE_NUM #define PAGE_NUM(linenum) ((((linenum) - 1) / (sc_height - 1)) + 1) switch (c) { case 'b': /* Current byte offset */ pos = curr_byte(where); if (pos != NULL_POSITION) ap_pos(pos); else ap_quest(); break; case 'c': ap_int(hshift); break; case 'd': /* Current page number */ linenum = currline(where); if (linenum > 0 && sc_height > 1) ap_linenum(PAGE_NUM(linenum)); else ap_quest(); break; case 'D': /* Final page number */ /* Find the page number of the last byte in the file (len-1). */ len = ch_length(); if (len == NULL_POSITION) ap_quest(); else if (len == 0) /* An empty file has no pages. */ ap_linenum(0); else { linenum = find_linenum(len - 1); if (linenum <= 0) ap_quest(); else ap_linenum(PAGE_NUM(linenum)); } break; #if EDITOR case 'E': /* Editor name */ ap_str(editor); break; #endif case 'f': /* File name */ ap_str(get_filename(curr_ifile)); break; case 'F': /* Last component of file name */ ap_str(last_component(get_filename(curr_ifile))); break; case 'i': /* Index into list of files */ #if TAGS if (ntags()) ap_int(curr_tag()); else #endif ap_int(get_index(curr_ifile)); break; case 'l': /* Current line number */ linenum = currline(where); if (linenum != 0) ap_linenum(linenum); else ap_quest(); break; case 'L': /* Final line number */ len = ch_length(); if (len == NULL_POSITION || len == ch_zero() || (linenum = find_linenum(len)) <= 0) ap_quest(); else ap_linenum(linenum-1); break; case 'm': /* Number of files */ #if TAGS n = ntags(); if (n) ap_int(n); else #endif ap_int(nifile()); break; case 'p': /* Percent into file (bytes) */ pos = curr_byte(where); len = ch_length(); if (pos != NULL_POSITION && len > 0) ap_int(percentage(pos,len)); else ap_quest(); break; case 'P': /* Percent into file (lines) */ linenum = currline(where); if (linenum == 0 || (len = ch_length()) == NULL_POSITION || len == ch_zero() || (last_linenum = find_linenum(len)) <= 0) ap_quest(); else ap_int(percentage(linenum, last_linenum)); break; case 's': /* Size of file */ case 'B': len = ch_length(); if (len != NULL_POSITION) ap_pos(len); else ap_quest(); break; case 't': /* Truncate trailing spaces in the message */ while (mp > message && mp[-1] == ' ') mp--; *mp = '\0'; break; case 'T': /* Type of list */ #if TAGS if (ntags()) ap_str("tag"); else #endif ap_str("file"); break; case 'x': /* Name of next file */ h = next_ifile(curr_ifile); if (h != NULL_IFILE) ap_str(get_filename(h)); else ap_quest(); break; } } /* * Skip a false conditional. * When a false condition is found (either a false IF or the ELSE part * of a true IF), this routine scans the prototype string to decide * where to resume parsing the string. * We must keep track of nested IFs and skip them properly. */ static constant char * -skipcond(p) - register constant char *p; +skipcond(constant char *p) { - register int iflevel; + int iflevel; /* * We came in here after processing a ? or :, * so we start nested one level deep. */ iflevel = 1; for (;;) switch (*++p) { case '?': /* * Start of a nested IF. */ iflevel++; break; case ':': /* * Else. * If this matches the IF we came in here with, * then we're done. */ if (iflevel == 1) return (p); break; case '.': /* * Endif. * If this matches the IF we came in here with, * then we're done. */ if (--iflevel == 0) return (p); break; case '\\': /* * Backslash escapes the next character. */ ++p; break; case '\0': /* * Whoops. Hit end of string. * This is a malformed conditional, but just treat it * as if all active conditionals ends here. */ return (p-1); } /*NOTREACHED*/ } /* * Decode a char that represents a position on the screen. */ static constant char * -wherechar(p, wp) - char constant *p; - int *wp; +wherechar(char constant *p, int *wp) { switch (*p) { case 'b': case 'd': case 'l': case 'p': case 'P': switch (*++p) { case 't': *wp = TOP; break; case 'm': *wp = MIDDLE; break; case 'b': *wp = BOTTOM; break; case 'B': *wp = BOTTOM_PLUS_ONE; break; case 'j': *wp = adjsline(jump_sline); break; default: *wp = TOP; p--; break; } } return (p); } /* * Construct a message based on a prototype string. */ public char * -pr_expand(proto, maxwidth) - constant char *proto; - int maxwidth; +pr_expand(constant char *proto, int maxwidth) { - register constant char *p; - register int c; + constant char *p; + int c; int where; mp = message; if (*proto == '\0') return (""); for (p = proto; *p != '\0'; p++) { switch (*p) { default: /* Just put the character in the message */ ap_char(*p); break; case '\\': /* Backslash escapes the next character */ p++; ap_char(*p); break; case '?': /* Conditional (IF) */ if ((c = *++p) == '\0') --p; else { where = 0; p = wherechar(p, &where); if (!cond(c, where)) p = skipcond(p); } break; case ':': /* ELSE */ p = skipcond(p); break; case '.': /* ENDIF */ break; case '%': /* Percent escape */ if ((c = *++p) == '\0') --p; else { where = 0; p = wherechar(p, &where); protochar(c, where, #if EDITOR (proto == editproto)); #else 0); #endif } break; } } if (mp == message) return (""); if (maxwidth > 0 && mp >= message + maxwidth) { /* * Message is too long. * Return just the final portion of it. */ return (mp - maxwidth); } return (message); } /* * Return a message suitable for printing by the "=" command. */ public char * -eq_message() +eq_message(void) { return (pr_expand(eqproto, 0)); } /* * Return a prompt. * This depends on the prompt type (SHORT, MEDIUM, LONG), etc. * If we can't come up with an appropriate prompt, return NULL * and the caller will prompt with a colon. */ public char * -pr_string() +pr_string(void) { char *prompt; int type; type = (!less_is_more) ? pr_type : pr_type ? 0 : 1; prompt = pr_expand((ch_getflags() & CH_HELPFILE) ? hproto : prproto[type], sc_width-so_s_width-so_e_width-2); new_file = 0; return (prompt); } /* * Return a message suitable for printing while waiting in the F command. */ public char * -wait_message() +wait_message(void) { return (pr_expand(wproto, sc_width-so_s_width-so_e_width-2)); } Index: head/contrib/less/regexp.c =================================================================== --- head/contrib/less/regexp.c (revision 316338) +++ head/contrib/less/regexp.c (revision 316339) @@ -1,1253 +1,1225 @@ /* * regcomp and regexec -- regsub and regerror are elsewhere * * Copyright (c) 1986 by University of Toronto. * Written by Henry Spencer. Not derived from licensed software. * * Permission is granted to anyone to use this software for any * purpose on any computer system, and to redistribute it freely, * subject to the following restrictions: * * 1. The author is not responsible for the consequences of use of * this software, no matter how awful, even if they arise * from defects in it. * * 2. The origin of this software must not be misrepresented, either * by explicit claim or by omission. * * 3. Altered versions must be plainly marked as such, and must not * be misrepresented as being the original software. * * Beware that some of this code is subtly aware of the way operator * precedence is structured in regular expressions. Serious changes in * regular-expression syntax might require a total rethink. * * *** NOTE: this code has been altered slightly for use in Tcl. *** * Slightly modified by David MacKenzie to undo most of the changes for TCL. * Added regexec2 with notbol parameter. -- 4/19/99 Mark Nudelman */ #include "less.h" #if HAVE_STDIO_H #include #endif #if HAVE_STDLIB_H #include #endif #if HAVE_STRING_H #include #endif #include "regexp.h" /* * The "internal use only" fields in regexp.h are present to pass info from * compile to execute that permits the execute phase to run lots faster on * simple cases. They are: * * regstart char that must begin a match; '\0' if none obvious * reganch is the match anchored (at beginning-of-line only)? * regmust string (pointer into program) that match must include, or NULL * regmlen length of regmust string * * Regstart and reganch permit very fast decisions on suitable starting points * for a match, cutting down the work a lot. Regmust permits fast rejection * of lines that cannot possibly match. The regmust tests are costly enough * that regcomp() supplies a regmust only if the r.e. contains something * potentially expensive (at present, the only such thing detected is * or + * at the start of the r.e., which can involve a lot of backup). Regmlen is * supplied because the test in regexec() needs it and regcomp() is * computing it anyway. */ /* * Structure for regexp "program". This is essentially a linear encoding * of a nondeterministic finite-state machine (aka syntax charts or * "railroad normal form" in parsing technology). Each node is an opcode * plus a "next" pointer, possibly plus an operand. "Next" pointers of * all nodes except BRANCH implement concatenation; a "next" pointer with * a BRANCH on both ends of it is connecting two alternatives. (Here we * have one of the subtle syntax dependencies: an individual BRANCH (as * opposed to a collection of them) is never concatenated with anything * because of operator precedence.) The operand of some types of node is * a literal string; for others, it is a node leading into a sub-FSM. In * particular, the operand of a BRANCH node is the first node of the branch. * (NB this is *not* a tree structure: the tail of the branch connects * to the thing following the set of BRANCHes.) The opcodes are: */ /* definition number opnd? meaning */ #undef EOL #define END 0 /* no End of program. */ #define BOL 1 /* no Match "" at beginning of line. */ #define EOL 2 /* no Match "" at end of line. */ #define ANY 3 /* no Match any one character. */ #define ANYOF 4 /* str Match any character in this string. */ #define ANYBUT 5 /* str Match any character not in this string. */ #define BRANCH 6 /* node Match this alternative, or the next... */ #define BACK 7 /* no Match "", "next" ptr points backward. */ #define EXACTLY 8 /* str Match this string. */ #define NOTHING 9 /* no Match empty string. */ #define STAR 10 /* node Match this (simple) thing 0 or more times. */ #define PLUS 11 /* node Match this (simple) thing 1 or more times. */ #define OPEN 20 /* no Mark this point in input as start of #n. */ /* OPEN+1 is number 1, etc. */ #define CLOSE 30 /* no Analogous to OPEN. */ /* * Opcode notes: * * BRANCH The set of branches constituting a single choice are hooked * together with their "next" pointers, since precedence prevents * anything being concatenated to any individual branch. The * "next" pointer of the last BRANCH in a choice points to the * thing following the whole choice. This is also where the * final "next" pointer of each individual branch points; each * branch starts with the operand node of a BRANCH node. * * BACK Normal "next" pointers all implicitly point forward; BACK * exists to make loop structures possible. * * STAR,PLUS '?', and complex '*' and '+', are implemented as circular * BRANCH structures using BACK. Simple cases (one character * per match) are implemented with STAR and PLUS for speed * and to minimize recursive plunges. * * OPEN,CLOSE ...are numbered at compile time. */ /* * A node is one char of opcode followed by two chars of "next" pointer. * "Next" pointers are stored as two 8-bit pieces, high order first. The * value is a positive offset from the opcode of the node containing it. * An operand, if any, simply follows the node. (Note that much of the * code generation knows about this implicit relationship.) * * Using two bytes for the "next" pointer is vast overkill for most things, * but allows patterns to get big without disasters. */ #define OP(p) (*(p)) #define NEXT(p) (((*((p)+1)&0377)<<8) + (*((p)+2)&0377)) #define OPERAND(p) ((p) + 3) /* * See regmagic.h for one further detail of program structure. */ /* * Utility definitions. */ #ifndef CHARBITS #define UCHARAT(p) ((int)*(unsigned char *)(p)) #else #define UCHARAT(p) ((int)*(p)&CHARBITS) #endif #define FAIL(m) { regerror(m); return(NULL); } #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?') #define META "^$.[()|?+*\\" /* * Flags to be passed up and down. */ #define HASWIDTH 01 /* Known never to match null string. */ #define SIMPLE 02 /* Simple enough to be STAR/PLUS operand. */ #define SPSTART 04 /* Starts with * or +. */ #define WORST 0 /* Worst case. */ /* * Global work variables for regcomp(). */ static char *regparse; /* Input-scan pointer. */ static int regnpar; /* () count. */ static char regdummy; static char *regcode; /* Code-emit pointer; ®dummy = don't. */ static long regsize; /* Code size. */ /* * The first byte of the regexp internal "program" is actually this magic * number; the start node begins in the second byte. */ #define MAGIC 0234 /* * Forward declarations for regcomp()'s friends. */ #ifndef STATIC #define STATIC static #endif STATIC char *reg(); STATIC char *regbranch(); STATIC char *regpiece(); STATIC char *regatom(); STATIC char *regnode(); STATIC char *regnext(); STATIC void regc(); STATIC void reginsert(); STATIC void regtail(); STATIC void regoptail(); #ifdef STRCSPN STATIC int strcspn(); #endif /* - regcomp - compile a regular expression into internal code * * We can't allocate space until we know how big the compiled form will be, * but we can't compile it (and thus know how big it is) until we've got a * place to put the code. So we cheat: we compile it twice, once with code * generation turned off and size counting turned on, and once "for real". * This also means that we don't allocate space until we are sure that the * thing really will compile successfully, and we never have to move the * code and thus invalidate pointers into it. (Note that it has to be in * one piece because free() must be able to free it all.) * * Beware that the optimization-preparation code in here knows about some * of the structure of the compiled regexp. */ regexp * -regcomp(exp) -char *exp; +regcomp(char *exp) { - register regexp *r; - register char *scan; - register char *longest; - register int len; + regexp *r; + char *scan; + char *longest; + int len; int flags; if (exp == NULL) FAIL("NULL argument"); /* First pass: determine size, legality. */ regparse = exp; regnpar = 1; regsize = 0L; regcode = ®dummy; regc(MAGIC); if (reg(0, &flags) == NULL) return(NULL); /* Small enough for pointer-storage convention? */ if (regsize >= 32767L) /* Probably could be 65535L. */ FAIL("regexp too big"); /* Allocate space. */ r = (regexp *)malloc(sizeof(regexp) + (unsigned)regsize); if (r == NULL) FAIL("out of space"); /* Second pass: emit code. */ regparse = exp; regnpar = 1; regcode = r->program; regc(MAGIC); if (reg(0, &flags) == NULL) { free(r); return(NULL); } /* Dig out information for optimizations. */ r->regstart = '\0'; /* Worst-case defaults. */ r->reganch = 0; r->regmust = NULL; r->regmlen = 0; scan = r->program+1; /* First BRANCH. */ if (OP(regnext(scan)) == END) { /* Only one top-level choice. */ scan = OPERAND(scan); /* Starting-point info. */ if (OP(scan) == EXACTLY) r->regstart = *OPERAND(scan); else if (OP(scan) == BOL) r->reganch++; /* * If there's something expensive in the r.e., find the * longest literal string that must appear and make it the * regmust. Resolve ties in favor of later strings, since * the regstart check works with the beginning of the r.e. * and avoiding duplication strengthens checking. Not a * strong reason, but sufficient in the absence of others. */ if (flags&SPSTART) { longest = NULL; len = 0; for (; scan != NULL; scan = regnext(scan)) if (OP(scan) == EXACTLY && ((int) strlen(OPERAND(scan))) >= len) { longest = OPERAND(scan); len = (int) strlen(OPERAND(scan)); } r->regmust = longest; r->regmlen = len; } } return(r); } /* - reg - regular expression, i.e. main body or parenthesized thing * * Caller must absorb opening parenthesis. * * Combining parenthesis handling with the base level of regular expression * is a trifle forced, but the need to tie the tails of the branches to what * follows makes it hard to avoid. */ static char * -reg(paren, flagp) -int paren; /* Parenthesized? */ -int *flagp; +reg(int paren, int *flagp) { - register char *ret; - register char *br; - register char *ender; - register int parno = 0; + char *ret; + char *br; + char *ender; + int parno = 0; int flags; *flagp = HASWIDTH; /* Tentatively. */ /* Make an OPEN node, if parenthesized. */ if (paren) { if (regnpar >= NSUBEXP) FAIL("too many ()"); parno = regnpar; regnpar++; ret = regnode(OPEN+parno); } else ret = NULL; /* Pick up the branches, linking them together. */ br = regbranch(&flags); if (br == NULL) return(NULL); if (ret != NULL) regtail(ret, br); /* OPEN -> first. */ else ret = br; if (!(flags&HASWIDTH)) *flagp &= ~HASWIDTH; *flagp |= flags&SPSTART; while (*regparse == '|') { regparse++; br = regbranch(&flags); if (br == NULL) return(NULL); regtail(ret, br); /* BRANCH -> BRANCH. */ if (!(flags&HASWIDTH)) *flagp &= ~HASWIDTH; *flagp |= flags&SPSTART; } /* Make a closing node, and hook it on the end. */ ender = regnode((paren) ? CLOSE+parno : END); regtail(ret, ender); /* Hook the tails of the branches to the closing node. */ for (br = ret; br != NULL; br = regnext(br)) regoptail(br, ender); /* Check for proper termination. */ if (paren && *regparse++ != ')') { FAIL("unmatched ()"); } else if (!paren && *regparse != '\0') { if (*regparse == ')') { FAIL("unmatched ()"); } else FAIL("junk on end"); /* "Can't happen". */ /* NOTREACHED */ } return(ret); } /* - regbranch - one alternative of an | operator * * Implements the concatenation operator. */ static char * -regbranch(flagp) -int *flagp; +regbranch(int *flagp) { - register char *ret; - register char *chain; - register char *latest; + char *ret; + char *chain; + char *latest; int flags; *flagp = WORST; /* Tentatively. */ ret = regnode(BRANCH); chain = NULL; while (*regparse != '\0' && *regparse != '|' && *regparse != ')') { latest = regpiece(&flags); if (latest == NULL) return(NULL); *flagp |= flags&HASWIDTH; if (chain == NULL) /* First piece. */ *flagp |= flags&SPSTART; else regtail(chain, latest); chain = latest; } if (chain == NULL) /* Loop ran zero times. */ (void) regnode(NOTHING); return(ret); } /* - regpiece - something followed by possible [*+?] * * Note that the branching code sequences used for ? and the general cases * of * and + are somewhat optimized: they use the same NOTHING node as * both the endmarker for their branch list and the body of the last branch. * It might seem that this node could be dispensed with entirely, but the * endmarker role is not redundant. */ static char * -regpiece(flagp) -int *flagp; +regpiece(int *flagp) { - register char *ret; - register char op; - register char *next; + char *ret; + char op; + char *next; int flags; ret = regatom(&flags); if (ret == NULL) return(NULL); op = *regparse; if (!ISMULT(op)) { *flagp = flags; return(ret); } if (!(flags&HASWIDTH) && op != '?') FAIL("*+ operand could be empty"); *flagp = (op != '+') ? (WORST|SPSTART) : (WORST|HASWIDTH); if (op == '*' && (flags&SIMPLE)) reginsert(STAR, ret); else if (op == '*') { /* Emit x* as (x&|), where & means "self". */ reginsert(BRANCH, ret); /* Either x */ regoptail(ret, regnode(BACK)); /* and loop */ regoptail(ret, ret); /* back */ regtail(ret, regnode(BRANCH)); /* or */ regtail(ret, regnode(NOTHING)); /* null. */ } else if (op == '+' && (flags&SIMPLE)) reginsert(PLUS, ret); else if (op == '+') { /* Emit x+ as x(&|), where & means "self". */ next = regnode(BRANCH); /* Either */ regtail(ret, next); regtail(regnode(BACK), ret); /* loop back */ regtail(next, regnode(BRANCH)); /* or */ regtail(ret, regnode(NOTHING)); /* null. */ } else if (op == '?') { /* Emit x? as (x|) */ reginsert(BRANCH, ret); /* Either x */ regtail(ret, regnode(BRANCH)); /* or */ next = regnode(NOTHING); /* null. */ regtail(ret, next); regoptail(ret, next); } regparse++; if (ISMULT(*regparse)) FAIL("nested *?+"); return(ret); } /* - regatom - the lowest level * * Optimization: gobbles an entire sequence of ordinary characters so that * it can turn them into a single node, which is smaller to store and * faster to run. Backslashed characters are exceptions, each becoming a * separate node; the code is simpler that way and it's not worth fixing. */ static char * -regatom(flagp) -int *flagp; +regatom(int *flagp) { - register char *ret; + char *ret; int flags; *flagp = WORST; /* Tentatively. */ switch (*regparse++) { case '^': ret = regnode(BOL); break; case '$': ret = regnode(EOL); break; case '.': ret = regnode(ANY); *flagp |= HASWIDTH|SIMPLE; break; case '[': { - register int clss; - register int classend; + int clss; + int classend; if (*regparse == '^') { /* Complement of range. */ ret = regnode(ANYBUT); regparse++; } else ret = regnode(ANYOF); if (*regparse == ']' || *regparse == '-') regc(*regparse++); while (*regparse != '\0' && *regparse != ']') { if (*regparse == '-') { regparse++; if (*regparse == ']' || *regparse == '\0') regc('-'); else { clss = UCHARAT(regparse-2)+1; classend = UCHARAT(regparse); if (clss > classend+1) FAIL("invalid [] range"); for (; clss <= classend; clss++) regc(clss); regparse++; } } else regc(*regparse++); } regc('\0'); if (*regparse != ']') FAIL("unmatched []"); regparse++; *flagp |= HASWIDTH|SIMPLE; } break; case '(': ret = reg(1, &flags); if (ret == NULL) return(NULL); *flagp |= flags&(HASWIDTH|SPSTART); break; case '\0': case '|': case ')': FAIL("internal urp"); /* Supposed to be caught earlier. */ /* NOTREACHED */ break; case '?': case '+': case '*': FAIL("?+* follows nothing"); /* NOTREACHED */ break; case '\\': if (*regparse == '\0') FAIL("trailing \\"); ret = regnode(EXACTLY); regc(*regparse++); regc('\0'); *flagp |= HASWIDTH|SIMPLE; break; default: { - register int len; - register char ender; + int len; + char ender; regparse--; len = (int) strcspn(regparse, META); if (len <= 0) FAIL("internal disaster"); ender = *(regparse+len); if (len > 1 && ISMULT(ender)) len--; /* Back off clear of ?+* operand. */ *flagp |= HASWIDTH; if (len == 1) *flagp |= SIMPLE; ret = regnode(EXACTLY); while (len > 0) { regc(*regparse++); len--; } regc('\0'); } break; } return(ret); } /* - regnode - emit a node */ static char * /* Location. */ -regnode(op) -char op; +regnode(char op) { - register char *ret; - register char *ptr; + char *ret; + char *ptr; ret = regcode; if (ret == ®dummy) { regsize += 3; return(ret); } ptr = ret; *ptr++ = op; *ptr++ = '\0'; /* Null "next" pointer. */ *ptr++ = '\0'; regcode = ptr; return(ret); } /* - regc - emit (if appropriate) a byte of code */ static void -regc(b) -char b; +regc(char b) { if (regcode != ®dummy) *regcode++ = b; else regsize++; } /* - reginsert - insert an operator in front of already-emitted operand * * Means relocating the operand. */ static void -reginsert(op, opnd) -char op; -char *opnd; +reginsert(char op, char *opnd) { - register char *src; - register char *dst; - register char *place; + char *src; + char *dst; + char *place; if (regcode == ®dummy) { regsize += 3; return; } src = regcode; regcode += 3; dst = regcode; while (src > opnd) *--dst = *--src; place = opnd; /* Op node, where operand used to be. */ *place++ = op; *place++ = '\0'; *place++ = '\0'; } /* - regtail - set the next-pointer at the end of a node chain */ static void -regtail(p, val) -char *p; -char *val; +regtail(char *p, char *val) { - register char *scan; - register char *temp; - register int offset; + char *scan; + char *temp; + int offset; if (p == ®dummy) return; /* Find last node. */ scan = p; for (;;) { temp = regnext(scan); if (temp == NULL) break; scan = temp; } if (OP(scan) == BACK) offset = (int) (scan - val); else offset = (int) (val - scan); *(scan+1) = (offset>>8)&0377; *(scan+2) = offset&0377; } /* - regoptail - regtail on operand of first argument; nop if operandless */ static void -regoptail(p, val) -char *p; -char *val; +regoptail(char *p, char *val) { /* "Operandless" and "op != BRANCH" are synonymous in practice. */ if (p == NULL || p == ®dummy || OP(p) != BRANCH) return; regtail(OPERAND(p), val); } /* * regexec and friends */ /* * Global work variables for regexec(). */ static char *reginput; /* String-input pointer. */ static char *regbol; /* Beginning of input, for ^ check. */ static char **regstartp; /* Pointer to startp array. */ static char **regendp; /* Ditto for endp. */ /* * Forwards. */ STATIC int regtry(); STATIC int regmatch(); STATIC int regrepeat(); #ifdef DEBUG int regnarrate = 0; void regdump(); STATIC char *regprop(); #endif /* - regexec - match a regexp against a string */ int -regexec2(prog, string, notbol) -register regexp *prog; -register char *string; -int notbol; +regexec2(regexp *prog, char *string, int notbol) { - register char *s; + char *s; /* Be paranoid... */ if (prog == NULL || string == NULL) { regerror("NULL parameter"); return(0); } /* Check validity of program. */ if (UCHARAT(prog->program) != MAGIC) { regerror("corrupted program"); return(0); } /* If there is a "must appear" string, look for it. */ if (prog->regmust != NULL) { s = string; while ((s = strchr(s, prog->regmust[0])) != NULL) { if (strncmp(s, prog->regmust, prog->regmlen) == 0) break; /* Found it. */ s++; } if (s == NULL) /* Not present. */ return(0); } /* Mark beginning of line for ^ . */ if (notbol) regbol = NULL; else regbol = string; /* Simplest case: anchored match need be tried only once. */ if (prog->reganch) return(regtry(prog, string)); /* Messy cases: unanchored match. */ s = string; if (prog->regstart != '\0') /* We know what char it must start with. */ while ((s = strchr(s, prog->regstart)) != NULL) { if (regtry(prog, s)) return(1); s++; } else /* We don't -- general case. */ do { if (regtry(prog, s)) return(1); } while (*s++ != '\0'); /* Failure. */ return(0); } int -regexec(prog, string) -register regexp *prog; -register char *string; +regexec(regexp *prog, char *string) { return regexec2(prog, string, 0); } /* - regtry - try match at specific point */ static int /* 0 failure, 1 success */ -regtry(prog, string) -regexp *prog; -char *string; +regtry(regexp *prog, char *string) { - register int i; - register char **sp; - register char **ep; + int i; + char **sp; + char **ep; reginput = string; regstartp = prog->startp; regendp = prog->endp; sp = prog->startp; ep = prog->endp; for (i = NSUBEXP; i > 0; i--) { *sp++ = NULL; *ep++ = NULL; } if (regmatch(prog->program + 1)) { prog->startp[0] = string; prog->endp[0] = reginput; return(1); } else return(0); } /* - regmatch - main matching routine * * Conceptually the strategy is simple: check to see whether the current * node matches, call self recursively to see whether the rest matches, * and then act accordingly. In practice we make some effort to avoid * recursion, in particular by going through "ordinary" nodes (that don't * need to know whether the rest of the match failed) by a loop instead of * by recursion. */ static int /* 0 failure, 1 success */ -regmatch(prog) -char *prog; +regmatch(char *prog) { - register char *scan; /* Current node. */ - char *next; /* Next node. */ + char *scan; /* Current node. */ + char *next; /* Next node. */ scan = prog; #ifdef DEBUG if (scan != NULL && regnarrate) fprintf(stderr, "%s(\n", regprop(scan)); #endif while (scan != NULL) { #ifdef DEBUG if (regnarrate) fprintf(stderr, "%s...\n", regprop(scan)); #endif next = regnext(scan); switch (OP(scan)) { case BOL: if (reginput != regbol) return(0); break; case EOL: if (*reginput != '\0') return(0); break; case ANY: if (*reginput == '\0') return(0); reginput++; break; case EXACTLY: { - register int len; - register char *opnd; + int len; + char *opnd; opnd = OPERAND(scan); /* Inline the first character, for speed. */ if (*opnd != *reginput) return(0); len = (int) strlen(opnd); if (len > 1 && strncmp(opnd, reginput, len) != 0) return(0); reginput += len; } break; case ANYOF: if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) == NULL) return(0); reginput++; break; case ANYBUT: if (*reginput == '\0' || strchr(OPERAND(scan), *reginput) != NULL) return(0); reginput++; break; case NOTHING: break; case BACK: break; case OPEN+1: case OPEN+2: case OPEN+3: case OPEN+4: case OPEN+5: case OPEN+6: case OPEN+7: case OPEN+8: case OPEN+9: { - register int no; - register char *save; + int no; + char *save; no = OP(scan) - OPEN; save = reginput; if (regmatch(next)) { /* * Don't set startp if some later * invocation of the same parentheses * already has. */ if (regstartp[no] == NULL) regstartp[no] = save; return(1); } else return(0); } /* NOTREACHED */ break; case CLOSE+1: case CLOSE+2: case CLOSE+3: case CLOSE+4: case CLOSE+5: case CLOSE+6: case CLOSE+7: case CLOSE+8: case CLOSE+9: { - register int no; - register char *save; + int no; + char *save; no = OP(scan) - CLOSE; save = reginput; if (regmatch(next)) { /* * Don't set endp if some later * invocation of the same parentheses * already has. */ if (regendp[no] == NULL) regendp[no] = save; return(1); } else return(0); } /* NOTREACHED */ break; case BRANCH: { - register char *save; + char *save; if (OP(next) != BRANCH) /* No choice. */ next = OPERAND(scan); /* Avoid recursion. */ else { do { save = reginput; if (regmatch(OPERAND(scan))) return(1); reginput = save; scan = regnext(scan); } while (scan != NULL && OP(scan) == BRANCH); return(0); /* NOTREACHED */ } } /* NOTREACHED */ break; case STAR: case PLUS: { - register char nextch; - register int no; - register char *save; - register int min; + char nextch; + int no; + char *save; + int min; /* * Lookahead to avoid useless match attempts * when we know what character comes next. */ nextch = '\0'; if (OP(next) == EXACTLY) nextch = *OPERAND(next); min = (OP(scan) == STAR) ? 0 : 1; save = reginput; no = regrepeat(OPERAND(scan)); while (no >= min) { /* If it could work, try it. */ if (nextch == '\0' || *reginput == nextch) if (regmatch(next)) return(1); /* Couldn't or didn't -- back up. */ no--; reginput = save + no; } return(0); } /* NOTREACHED */ break; case END: return(1); /* Success! */ /* NOTREACHED */ break; default: regerror("memory corruption"); return(0); /* NOTREACHED */ break; } scan = next; } /* * We get here only if there's trouble -- normally "case END" is * the terminating point. */ regerror("corrupted pointers"); return(0); } /* - regrepeat - repeatedly match something simple, report how many */ static int -regrepeat(p) -char *p; +regrepeat(char *p) { - register int count = 0; - register char *scan; - register char *opnd; + int count = 0; + char *scan; + char *opnd; scan = reginput; opnd = OPERAND(p); switch (OP(p)) { case ANY: count = (int) strlen(scan); scan += count; break; case EXACTLY: while (*opnd == *scan) { count++; scan++; } break; case ANYOF: while (*scan != '\0' && strchr(opnd, *scan) != NULL) { count++; scan++; } break; case ANYBUT: while (*scan != '\0' && strchr(opnd, *scan) == NULL) { count++; scan++; } break; default: /* Oh dear. Called inappropriately. */ regerror("internal foulup"); count = 0; /* Best compromise. */ break; } reginput = scan; return(count); } /* - regnext - dig the "next" pointer out of a node */ static char * -regnext(p) -register char *p; +regnext(char *p) { - register int offset; + int offset; if (p == ®dummy) return(NULL); offset = NEXT(p); if (offset == 0) return(NULL); if (OP(p) == BACK) return(p-offset); else return(p+offset); } #ifdef DEBUG STATIC char *regprop(); /* - regdump - dump a regexp onto stdout in vaguely comprehensible form */ void -regdump(r) -regexp *r; +regdump(regexp *r) { - register char *s; - register char op = EXACTLY; /* Arbitrary non-END op. */ - register char *next; + char *s; + char op = EXACTLY; /* Arbitrary non-END op. */ + char *next; s = r->program + 1; while (op != END) { /* While that wasn't END last time... */ op = OP(s); printf("%2d%s", s-r->program, regprop(s)); /* Where, what. */ next = regnext(s); if (next == NULL) /* Next ptr. */ printf("(0)"); else printf("(%d)", (s-r->program)+(next-s)); s += 3; if (op == ANYOF || op == ANYBUT || op == EXACTLY) { /* Literal string, where present. */ while (*s != '\0') { putchar(*s); s++; } s++; } putchar('\n'); } /* Header fields of interest. */ if (r->regstart != '\0') printf("start `%c' ", r->regstart); if (r->reganch) printf("anchored "); if (r->regmust != NULL) printf("must have \"%s\"", r->regmust); printf("\n"); } /* - regprop - printable representation of opcode */ static char * -regprop(op) -char *op; +regprop(char *op) { - register char *p; + char *p; static char buf[50]; (void) strcpy(buf, ":"); switch (OP(op)) { case BOL: p = "BOL"; break; case EOL: p = "EOL"; break; case ANY: p = "ANY"; break; case ANYOF: p = "ANYOF"; break; case ANYBUT: p = "ANYBUT"; break; case BRANCH: p = "BRANCH"; break; case EXACTLY: p = "EXACTLY"; break; case NOTHING: p = "NOTHING"; break; case BACK: p = "BACK"; break; case END: p = "END"; break; case OPEN+1: case OPEN+2: case OPEN+3: case OPEN+4: case OPEN+5: case OPEN+6: case OPEN+7: case OPEN+8: case OPEN+9: sprintf(buf+strlen(buf), "OPEN%d", OP(op)-OPEN); p = NULL; break; case CLOSE+1: case CLOSE+2: case CLOSE+3: case CLOSE+4: case CLOSE+5: case CLOSE+6: case CLOSE+7: case CLOSE+8: case CLOSE+9: sprintf(buf+strlen(buf), "CLOSE%d", OP(op)-CLOSE); p = NULL; break; case STAR: p = "STAR"; break; case PLUS: p = "PLUS"; break; default: regerror("corrupted opcode"); break; } if (p != NULL) (void) strcat(buf, p); return(buf); } #endif /* * The following is provided for those people who do not have strcspn() in * their C libraries. They should get off their butts and do something * about it; at least one public-domain implementation of those (highly * useful) string routines has been published on Usenet. */ #ifdef STRCSPN /* * strcspn - find length of initial segment of s1 consisting entirely * of characters not from s2 */ static int -strcspn(s1, s2) -char *s1; -char *s2; +strcspn(char *s1, char *s2) { - register char *scan1; - register char *scan2; - register int count; + char *scan1; + char *scan2; + int count; count = 0; for (scan1 = s1; *scan1 != '\0'; scan1++) { for (scan2 = s2; *scan2 != '\0';) /* ++ moved down. */ if (*scan1 == *scan2++) return(count); count++; } return(count); } #endif Index: head/contrib/less/screen.c =================================================================== --- head/contrib/less/screen.c (revision 316338) +++ head/contrib/less/screen.c (revision 316339) @@ -1,2501 +1,2470 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines which deal with the characteristics of the terminal. * Uses termcap to be as terminal-independent as possible. */ #include "less.h" #include "cmd.h" #if MSDOS_COMPILER #include "pckeys.h" #if MSDOS_COMPILER==MSOFTC #include #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC #include #if MSDOS_COMPILER==DJGPPC #include extern int fd0; #endif #else #if MSDOS_COMPILER==WIN32C #include #endif #endif #endif #include #else #if HAVE_SYS_IOCTL_H #include #endif #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS #include #else #if HAVE_TERMIO_H #include #else #if HAVE_SGSTAT_H #include #else #include #endif #endif #endif #if HAVE_TERMCAP_H #include #endif #ifdef _OSK #include #endif #if OS2 #include #include "pckeys.h" #endif #if HAVE_SYS_STREAM_H #include #endif #if HAVE_SYS_PTEM_H #include #endif #endif /* MSDOS_COMPILER */ /* * Check for broken termios package that forces you to manually * set the line discipline. */ #ifdef __ultrix__ #define MUST_SET_LINE_DISCIPLINE 1 #else #define MUST_SET_LINE_DISCIPLINE 0 #endif #if OS2 #define DEFAULT_TERM "ansi" static char *windowid; #else #define DEFAULT_TERM "unknown" #endif #if MSDOS_COMPILER==MSOFTC static int videopages; static long msec_loops; static int flash_created = 0; #define SETCOLORS(fg,bg) { _settextcolor(fg); _setbkcolor(bg); } #endif #if MSDOS_COMPILER==BORLANDC static unsigned short *whitescreen; static int flash_created = 0; #endif #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC #define _settextposition(y,x) gotoxy(x,y) #define _clearscreen(m) clrscr() #define _outtext(s) cputs(s) #define SETCOLORS(fg,bg) { textcolor(fg); textbackground(bg); } extern int sc_height; #endif #if MSDOS_COMPILER==WIN32C struct keyRecord { int ascii; int scan; } currentKey; static int keyCount = 0; static WORD curr_attr; static int pending_scancode = 0; static WORD *whitescreen; static HANDLE con_out_save = INVALID_HANDLE_VALUE; /* previous console */ static HANDLE con_out_ours = INVALID_HANDLE_VALUE; /* our own */ HANDLE con_out = INVALID_HANDLE_VALUE; /* current console */ extern int quitting; static void win32_init_term(); static void win32_deinit_term(); #define FG_COLORS (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY) #define BG_COLORS (BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY) #define MAKEATTR(fg,bg) ((WORD)((fg)|((bg)<<4))) #define SETCOLORS(fg,bg) { curr_attr = MAKEATTR(fg,bg); \ if (SetConsoleTextAttribute(con_out, curr_attr) == 0) \ error("SETCOLORS failed"); } #endif #if MSDOS_COMPILER public int nm_fg_color; /* Color of normal text */ public int nm_bg_color; public int bo_fg_color; /* Color of bold text */ public int bo_bg_color; public int ul_fg_color; /* Color of underlined text */ public int ul_bg_color; public int so_fg_color; /* Color of standout text */ public int so_bg_color; public int bl_fg_color; /* Color of blinking text */ public int bl_bg_color; static int sy_fg_color; /* Color of system text (before less) */ static int sy_bg_color; #else /* * Strings passed to tputs() to do various terminal functions. */ static char *sc_pad, /* Pad string */ *sc_home, /* Cursor home */ *sc_addline, /* Add line, scroll down following lines */ *sc_lower_left, /* Cursor to last line, first column */ *sc_return, /* Cursor to beginning of current line */ *sc_move, /* General cursor positioning */ *sc_clear, /* Clear screen */ *sc_eol_clear, /* Clear to end of line */ *sc_eos_clear, /* Clear to end of screen */ *sc_s_in, /* Enter standout (highlighted) mode */ *sc_s_out, /* Exit standout mode */ *sc_u_in, /* Enter underline mode */ *sc_u_out, /* Exit underline mode */ *sc_b_in, /* Enter bold mode */ *sc_b_out, /* Exit bold mode */ *sc_bl_in, /* Enter blink mode */ *sc_bl_out, /* Exit blink mode */ *sc_visual_bell, /* Visual bell (flash screen) sequence */ *sc_backspace, /* Backspace cursor */ *sc_s_keypad, /* Start keypad mode */ *sc_e_keypad, /* End keypad mode */ *sc_init, /* Startup terminal initialization */ *sc_deinit; /* Exit terminal de-initialization */ #endif static int init_done = 0; public int auto_wrap; /* Terminal does \r\n when write past margin */ public int ignaw; /* Terminal ignores \n immediately after wrap */ public int erase_char; /* The user's erase char */ public int erase2_char; /* The user's other erase char */ public int kill_char; /* The user's line-kill char */ public int werase_char; /* The user's word-erase char */ public int sc_width, sc_height; /* Height & width of screen */ public int bo_s_width, bo_e_width; /* Printing width of boldface seq */ public int ul_s_width, ul_e_width; /* Printing width of underline seq */ public int so_s_width, so_e_width; /* Printing width of standout seq */ public int bl_s_width, bl_e_width; /* Printing width of blink seq */ public int above_mem, below_mem; /* Memory retained above/below screen */ public int can_goto_line; /* Can move cursor to any line */ public int clear_bg; /* Clear fills with background color */ public int missing_cap = 0; /* Some capability is missing */ static int attrmode = AT_NORMAL; extern int binattr; #if !MSDOS_COMPILER -static char *cheaper(); -static void tmodes(); +static char *cheaper(char *t1, char *t2, char *def); +static void tmodes(char *incap, char *outcap, char **instr, char **outstr, + char *def_instr, char *def_outstr, char **spp); #endif /* * These two variables are sometimes defined in, * and needed by, the termcap library. */ #if MUST_DEFINE_OSPEED extern short ospeed; /* Terminal output baud rate */ extern char PC; /* Pad character */ #endif #ifdef _OSK short ospeed; char PC_, *UP, *BC; #endif extern int quiet; /* If VERY_QUIET, use visual bell for bell */ extern int no_back_scroll; extern int swindow; extern int no_init; extern int no_keypad; extern int sigs; extern int wscroll; extern int screen_trashed; extern int tty; extern int top_scroll; extern int oldbot; #if HILITE_SEARCH extern int hilite_search; #endif extern char *tgetstr(); extern char *tgoto(); /* * Change terminal to "raw mode", or restore to "normal" mode. * "Raw mode" means * 1. An outstanding read will complete on receipt of a single keystroke. * 2. Input is not echoed. * 3. On output, \n is mapped to \r\n. * 4. \t is NOT expanded into spaces. * 5. Signal-causing characters such as ctrl-C (interrupt), * etc. are NOT disabled. * It doesn't matter whether an input \n is mapped to \r, or vice versa. */ public void -raw_mode(on) - int on; +raw_mode(int on) { static int curr_on = 0; if (on == curr_on) return; erase2_char = '\b'; /* in case OS doesn't know about erase2 */ #if HAVE_TERMIOS_H && HAVE_TERMIOS_FUNCS { struct termios s; static struct termios save_term; static int saved_term = 0; if (on) { /* * Get terminal modes. */ tcgetattr(tty, &s); /* * Save modes and set certain variables dependent on modes. */ if (!saved_term) { save_term = s; saved_term = 1; } #if HAVE_OSPEED switch (cfgetospeed(&s)) { #ifdef B0 case B0: ospeed = 0; break; #endif #ifdef B50 case B50: ospeed = 1; break; #endif #ifdef B75 case B75: ospeed = 2; break; #endif #ifdef B110 case B110: ospeed = 3; break; #endif #ifdef B134 case B134: ospeed = 4; break; #endif #ifdef B150 case B150: ospeed = 5; break; #endif #ifdef B200 case B200: ospeed = 6; break; #endif #ifdef B300 case B300: ospeed = 7; break; #endif #ifdef B600 case B600: ospeed = 8; break; #endif #ifdef B1200 case B1200: ospeed = 9; break; #endif #ifdef B1800 case B1800: ospeed = 10; break; #endif #ifdef B2400 case B2400: ospeed = 11; break; #endif #ifdef B4800 case B4800: ospeed = 12; break; #endif #ifdef B9600 case B9600: ospeed = 13; break; #endif #ifdef EXTA case EXTA: ospeed = 14; break; #endif #ifdef EXTB case EXTB: ospeed = 15; break; #endif #ifdef B57600 case B57600: ospeed = 16; break; #endif #ifdef B115200 case B115200: ospeed = 17; break; #endif default: ; } #endif erase_char = s.c_cc[VERASE]; #ifdef VERASE2 erase2_char = s.c_cc[VERASE2]; #endif kill_char = s.c_cc[VKILL]; #ifdef VWERASE werase_char = s.c_cc[VWERASE]; #else werase_char = CONTROL('W'); #endif /* * Set the modes to the way we want them. */ s.c_lflag &= ~(0 #ifdef ICANON | ICANON #endif #ifdef ECHO | ECHO #endif #ifdef ECHOE | ECHOE #endif #ifdef ECHOK | ECHOK #endif #if ECHONL | ECHONL #endif ); s.c_oflag |= (0 #ifdef OXTABS | OXTABS #else #ifdef TAB3 | TAB3 #else #ifdef XTABS | XTABS #endif #endif #endif #ifdef OPOST | OPOST #endif #ifdef ONLCR | ONLCR #endif ); s.c_oflag &= ~(0 #ifdef ONOEOT | ONOEOT #endif #ifdef OCRNL | OCRNL #endif #ifdef ONOCR | ONOCR #endif #ifdef ONLRET | ONLRET #endif ); s.c_cc[VMIN] = 1; s.c_cc[VTIME] = 0; #ifdef VLNEXT s.c_cc[VLNEXT] = 0; #endif #ifdef VDSUSP s.c_cc[VDSUSP] = 0; #endif #if MUST_SET_LINE_DISCIPLINE /* * System's termios is broken; need to explicitly * request TERMIODISC line discipline. */ s.c_line = TERMIODISC; #endif } else { /* * Restore saved modes. */ s = save_term; } #if HAVE_FSYNC fsync(tty); #endif tcsetattr(tty, TCSADRAIN, &s); #if MUST_SET_LINE_DISCIPLINE if (!on) { /* * Broken termios *ignores* any line discipline * except TERMIODISC. A different old line discipline * is therefore not restored, yet. Restore the old * line discipline by hand. */ ioctl(tty, TIOCSETD, &save_term.c_line); } #endif } #else #ifdef TCGETA { struct termio s; static struct termio save_term; static int saved_term = 0; if (on) { /* * Get terminal modes. */ ioctl(tty, TCGETA, &s); /* * Save modes and set certain variables dependent on modes. */ if (!saved_term) { save_term = s; saved_term = 1; } #if HAVE_OSPEED ospeed = s.c_cflag & CBAUD; #endif erase_char = s.c_cc[VERASE]; kill_char = s.c_cc[VKILL]; #ifdef VWERASE werase_char = s.c_cc[VWERASE]; #else werase_char = CONTROL('W'); #endif /* * Set the modes to the way we want them. */ s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); s.c_oflag |= (OPOST|ONLCR|TAB3); s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); s.c_cc[VMIN] = 1; s.c_cc[VTIME] = 0; } else { /* * Restore saved modes. */ s = save_term; } ioctl(tty, TCSETAW, &s); } #else #ifdef TIOCGETP { struct sgttyb s; static struct sgttyb save_term; static int saved_term = 0; if (on) { /* * Get terminal modes. */ ioctl(tty, TIOCGETP, &s); /* * Save modes and set certain variables dependent on modes. */ if (!saved_term) { save_term = s; saved_term = 1; } #if HAVE_OSPEED ospeed = s.sg_ospeed; #endif erase_char = s.sg_erase; kill_char = s.sg_kill; werase_char = CONTROL('W'); /* * Set the modes to the way we want them. */ s.sg_flags |= CBREAK; s.sg_flags &= ~(ECHO|XTABS); } else { /* * Restore saved modes. */ s = save_term; } ioctl(tty, TIOCSETN, &s); } #else #ifdef _OSK { struct sgbuf s; static struct sgbuf save_term; static int saved_term = 0; if (on) { /* * Get terminal modes. */ _gs_opt(tty, &s); /* * Save modes and set certain variables dependent on modes. */ if (!saved_term) { save_term = s; saved_term = 1; } erase_char = s.sg_bspch; kill_char = s.sg_dlnch; werase_char = CONTROL('W'); /* * Set the modes to the way we want them. */ s.sg_echo = 0; s.sg_eofch = 0; s.sg_pause = 0; s.sg_psch = 0; } else { /* * Restore saved modes. */ s = save_term; } _ss_opt(tty, &s); } #else /* MS-DOS, Windows, or OS2 */ #if OS2 /* OS2 */ LSIGNAL(SIGINT, SIG_IGN); #endif erase_char = '\b'; #if MSDOS_COMPILER==DJGPPC kill_char = CONTROL('U'); /* * So that when we shell out or run another program, its * stdin is in cooked mode. We do not switch stdin to binary * mode if fd0 is zero, since that means we were called before * tty was reopened in open_getchr, in which case we would be * changing the original stdin device outside less. */ if (fd0 != 0) setmode(0, on ? O_BINARY : O_TEXT); #else kill_char = ESC; #endif werase_char = CONTROL('W'); #endif #endif #endif #endif curr_on = on; } #if !MSDOS_COMPILER /* * Some glue to prevent calling termcap functions if tgetent() failed. */ static int hardcopy; static char * -ltget_env(capname) - char *capname; +ltget_env(char *capname) { char name[16]; char *s; s = lgetenv("LESS_TERMCAP_DEBUG"); if (s != NULL && *s != '\0') { struct env { struct env *next; char *name; char *value; }; static struct env *envs = NULL; struct env *p; for (p = envs; p != NULL; p = p->next) if (strcmp(p->name, capname) == 0) return p->value; p = (struct env *) ecalloc(1, sizeof(struct env)); p->name = save(capname); p->value = (char *) ecalloc(strlen(capname)+3, sizeof(char)); sprintf(p->value, "<%s>", capname); p->next = envs; envs = p; return p->value; } strcpy(name, "LESS_TERMCAP_"); strcat(name, capname); return (lgetenv(name)); } static int -ltgetflag(capname) - char *capname; +ltgetflag(char *capname) { char *s; if ((s = ltget_env(capname)) != NULL) return (*s != '\0' && *s != '0'); if (hardcopy) return (0); return (tgetflag(capname)); } static int -ltgetnum(capname) - char *capname; +ltgetnum(char *capname) { char *s; if ((s = ltget_env(capname)) != NULL) return (atoi(s)); if (hardcopy) return (-1); return (tgetnum(capname)); } static char * -ltgetstr(capname, pp) - char *capname; - char **pp; +ltgetstr(char *capname, char **pp) { char *s; if ((s = ltget_env(capname)) != NULL) return (s); if (hardcopy) return (NULL); return (tgetstr(capname, pp)); } #endif /* MSDOS_COMPILER */ /* * Get size of the output screen. */ public void -scrsize() +scrsize(void) { - register char *s; + char *s; int sys_height; int sys_width; #if !MSDOS_COMPILER int n; #endif #define DEF_SC_WIDTH 80 #if MSDOS_COMPILER #define DEF_SC_HEIGHT 25 #else #define DEF_SC_HEIGHT 24 #endif sys_width = sys_height = 0; #if MSDOS_COMPILER==MSOFTC { struct videoconfig w; _getvideoconfig(&w); sys_height = w.numtextrows; sys_width = w.numtextcols; } #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC { struct text_info w; gettextinfo(&w); sys_height = w.screenheight; sys_width = w.screenwidth; } #else #if MSDOS_COMPILER==WIN32C { CONSOLE_SCREEN_BUFFER_INFO scr; GetConsoleScreenBufferInfo(con_out, &scr); sys_height = scr.srWindow.Bottom - scr.srWindow.Top + 1; sys_width = scr.srWindow.Right - scr.srWindow.Left + 1; } #else #if OS2 { int s[2]; _scrsize(s); sys_width = s[0]; sys_height = s[1]; /* * When using terminal emulators for XFree86/OS2, the * _scrsize function does not work well. * Call the scrsize.exe program to get the window size. */ windowid = getenv("WINDOWID"); if (windowid != NULL) { FILE *fd = popen("scrsize", "rt"); if (fd != NULL) { int w, h; fscanf(fd, "%i %i", &w, &h); if (w > 0 && h > 0) { sys_width = w; sys_height = h; } pclose(fd); } } } #else #ifdef TIOCGWINSZ { struct winsize w; if (ioctl(2, TIOCGWINSZ, &w) == 0) { if (w.ws_row > 0) sys_height = w.ws_row; if (w.ws_col > 0) sys_width = w.ws_col; } } #else #ifdef WIOCGETD { struct uwdata w; if (ioctl(2, WIOCGETD, &w) == 0) { if (w.uw_height > 0) sys_height = w.uw_height / w.uw_vs; if (w.uw_width > 0) sys_width = w.uw_width / w.uw_hs; } } #endif #endif #endif #endif #endif #endif if (sys_height > 0) sc_height = sys_height; else if ((s = lgetenv("LINES")) != NULL) sc_height = atoi(s); #if !MSDOS_COMPILER else if ((n = ltgetnum("li")) > 0) sc_height = n; #endif if (sc_height <= 0) sc_height = DEF_SC_HEIGHT; if (sys_width > 0) sc_width = sys_width; else if ((s = lgetenv("COLUMNS")) != NULL) sc_width = atoi(s); #if !MSDOS_COMPILER else if ((n = ltgetnum("co")) > 0) sc_width = n; #endif if (sc_width <= 0) sc_width = DEF_SC_WIDTH; } #if MSDOS_COMPILER==MSOFTC /* * Figure out how many empty loops it takes to delay a millisecond. */ static void -get_clock() +get_clock(void) { clock_t start; /* * Get synchronized at the start of a tick. */ start = clock(); while (clock() == start) ; /* * Now count loops till the next tick. */ start = clock(); msec_loops = 0; while (clock() == start) msec_loops++; /* * Convert from (loops per clock) to (loops per millisecond). */ msec_loops *= CLOCKS_PER_SEC; msec_loops /= 1000; } /* * Delay for a specified number of milliseconds. */ static void -dummy_func() +dummy_func(void) { static long delay_dummy = 0; delay_dummy++; } static void -delay(msec) - int msec; +delay(int msec) { long i; while (msec-- > 0) { for (i = 0; i < msec_loops; i++) { /* * Make it look like we're doing something here, * so the optimizer doesn't remove the whole loop. */ dummy_func(); } } } #endif /* * Return the characters actually input by a "special" key. */ public char * -special_key_str(key) - int key; +special_key_str(int key) { static char tbuf[40]; char *s; #if MSDOS_COMPILER || OS2 static char k_right[] = { '\340', PCK_RIGHT, 0 }; static char k_left[] = { '\340', PCK_LEFT, 0 }; static char k_ctl_right[] = { '\340', PCK_CTL_RIGHT, 0 }; static char k_ctl_left[] = { '\340', PCK_CTL_LEFT, 0 }; static char k_insert[] = { '\340', PCK_INSERT, 0 }; static char k_delete[] = { '\340', PCK_DELETE, 0 }; static char k_ctl_delete[] = { '\340', PCK_CTL_DELETE, 0 }; static char k_ctl_backspace[] = { '\177', 0 }; static char k_home[] = { '\340', PCK_HOME, 0 }; static char k_end[] = { '\340', PCK_END, 0 }; static char k_up[] = { '\340', PCK_UP, 0 }; static char k_down[] = { '\340', PCK_DOWN, 0 }; static char k_backtab[] = { '\340', PCK_SHIFT_TAB, 0 }; static char k_pagedown[] = { '\340', PCK_PAGEDOWN, 0 }; static char k_pageup[] = { '\340', PCK_PAGEUP, 0 }; static char k_f1[] = { '\340', PCK_F1, 0 }; #endif #if !MSDOS_COMPILER char *sp = tbuf; #endif switch (key) { #if OS2 /* * If windowid is not NULL, assume less is executed in * the XFree86 environment. */ case SK_RIGHT_ARROW: s = windowid ? ltgetstr("kr", &sp) : k_right; break; case SK_LEFT_ARROW: s = windowid ? ltgetstr("kl", &sp) : k_left; break; case SK_UP_ARROW: s = windowid ? ltgetstr("ku", &sp) : k_up; break; case SK_DOWN_ARROW: s = windowid ? ltgetstr("kd", &sp) : k_down; break; case SK_PAGE_UP: s = windowid ? ltgetstr("kP", &sp) : k_pageup; break; case SK_PAGE_DOWN: s = windowid ? ltgetstr("kN", &sp) : k_pagedown; break; case SK_HOME: s = windowid ? ltgetstr("kh", &sp) : k_home; break; case SK_END: s = windowid ? ltgetstr("@7", &sp) : k_end; break; case SK_DELETE: if (windowid) { s = ltgetstr("kD", &sp); if (s == NULL) { tbuf[0] = '\177'; tbuf[1] = '\0'; s = tbuf; } } else s = k_delete; break; #endif #if MSDOS_COMPILER case SK_RIGHT_ARROW: s = k_right; break; case SK_LEFT_ARROW: s = k_left; break; case SK_UP_ARROW: s = k_up; break; case SK_DOWN_ARROW: s = k_down; break; case SK_PAGE_UP: s = k_pageup; break; case SK_PAGE_DOWN: s = k_pagedown; break; case SK_HOME: s = k_home; break; case SK_END: s = k_end; break; case SK_DELETE: s = k_delete; break; #endif #if MSDOS_COMPILER || OS2 case SK_INSERT: s = k_insert; break; case SK_CTL_LEFT_ARROW: s = k_ctl_left; break; case SK_CTL_RIGHT_ARROW: s = k_ctl_right; break; case SK_CTL_BACKSPACE: s = k_ctl_backspace; break; case SK_CTL_DELETE: s = k_ctl_delete; break; case SK_F1: s = k_f1; break; case SK_BACKTAB: s = k_backtab; break; #else case SK_RIGHT_ARROW: s = ltgetstr("kr", &sp); break; case SK_LEFT_ARROW: s = ltgetstr("kl", &sp); break; case SK_UP_ARROW: s = ltgetstr("ku", &sp); break; case SK_DOWN_ARROW: s = ltgetstr("kd", &sp); break; case SK_PAGE_UP: s = ltgetstr("kP", &sp); break; case SK_PAGE_DOWN: s = ltgetstr("kN", &sp); break; case SK_HOME: s = ltgetstr("kh", &sp); break; case SK_END: s = ltgetstr("@7", &sp); break; case SK_DELETE: s = ltgetstr("kD", &sp); if (s == NULL) { tbuf[0] = '\177'; tbuf[1] = '\0'; s = tbuf; } break; #endif case SK_CONTROL_K: tbuf[0] = CONTROL('K'); tbuf[1] = '\0'; s = tbuf; break; default: return (NULL); } return (s); } /* * Get terminal capabilities via termcap. */ public void -get_term() +get_term(void) { #if MSDOS_COMPILER auto_wrap = 1; ignaw = 0; can_goto_line = 1; clear_bg = 1; /* * Set up default colors. * The xx_s_width and xx_e_width vars are already initialized to 0. */ #if MSDOS_COMPILER==MSOFTC sy_bg_color = _getbkcolor(); sy_fg_color = _gettextcolor(); get_clock(); #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC { struct text_info w; gettextinfo(&w); sy_bg_color = (w.attribute >> 4) & 0x0F; sy_fg_color = (w.attribute >> 0) & 0x0F; } #else #if MSDOS_COMPILER==WIN32C { DWORD nread; CONSOLE_SCREEN_BUFFER_INFO scr; con_out_save = con_out = GetStdHandle(STD_OUTPUT_HANDLE); /* * Always open stdin in binary. Note this *must* be done * before any file operations have been done on fd0. */ SET_BINARY(0); GetConsoleScreenBufferInfo(con_out, &scr); ReadConsoleOutputAttribute(con_out, &curr_attr, 1, scr.dwCursorPosition, &nread); sy_bg_color = (curr_attr & BG_COLORS) >> 4; /* normalize */ sy_fg_color = curr_attr & FG_COLORS; } #endif #endif #endif nm_fg_color = sy_fg_color; nm_bg_color = sy_bg_color; bo_fg_color = 11; bo_bg_color = 0; ul_fg_color = 9; ul_bg_color = 0; so_fg_color = 15; so_bg_color = 9; bl_fg_color = 15; bl_bg_color = 0; /* * Get size of the screen. */ scrsize(); pos_init(); #else /* !MSDOS_COMPILER */ char *sp; - register char *t1, *t2; + char *t1, *t2; char *term; char termbuf[TERMBUF_SIZE]; static char sbuf[TERMSBUF_SIZE]; #if OS2 /* * Make sure the termcap database is available. */ sp = lgetenv("TERMCAP"); if (sp == NULL || *sp == '\0') { char *termcap; if ((sp = homefile("termcap.dat")) != NULL) { termcap = (char *) ecalloc(strlen(sp)+9, sizeof(char)); sprintf(termcap, "TERMCAP=%s", sp); free(sp); putenv(termcap); } } #endif /* * Find out what kind of terminal this is. */ if ((term = lgetenv("TERM")) == NULL) term = DEFAULT_TERM; hardcopy = 0; if (tgetent(termbuf, term) != TGETENT_OK) hardcopy = 1; if (ltgetflag("hc")) hardcopy = 1; /* * Get size of the screen. */ scrsize(); pos_init(); auto_wrap = ltgetflag("am"); ignaw = ltgetflag("xn"); above_mem = ltgetflag("da"); below_mem = ltgetflag("db"); clear_bg = ltgetflag("ut"); /* * Assumes termcap variable "sg" is the printing width of: * the standout sequence, the end standout sequence, * the underline sequence, the end underline sequence, * the boldface sequence, and the end boldface sequence. */ if ((so_s_width = ltgetnum("sg")) < 0) so_s_width = 0; so_e_width = so_s_width; bo_s_width = bo_e_width = so_s_width; ul_s_width = ul_e_width = so_s_width; bl_s_width = bl_e_width = so_s_width; #if HILITE_SEARCH if (so_s_width > 0 || so_e_width > 0) /* * Disable highlighting by default on magic cookie terminals. * Turning on highlighting might change the displayed width * of a line, causing the display to get messed up. * The user can turn it back on with -g, * but she won't like the results. */ hilite_search = 0; #endif /* * Get various string-valued capabilities. */ sp = sbuf; #if HAVE_OSPEED sc_pad = ltgetstr("pc", &sp); if (sc_pad != NULL) PC = *sc_pad; #endif sc_s_keypad = ltgetstr("ks", &sp); if (sc_s_keypad == NULL) sc_s_keypad = ""; sc_e_keypad = ltgetstr("ke", &sp); if (sc_e_keypad == NULL) sc_e_keypad = ""; sc_init = ltgetstr("ti", &sp); if (sc_init == NULL) sc_init = ""; sc_deinit= ltgetstr("te", &sp); if (sc_deinit == NULL) sc_deinit = ""; sc_eol_clear = ltgetstr("ce", &sp); if (sc_eol_clear == NULL || *sc_eol_clear == '\0') { missing_cap = 1; sc_eol_clear = ""; } sc_eos_clear = ltgetstr("cd", &sp); if (below_mem && (sc_eos_clear == NULL || *sc_eos_clear == '\0')) { missing_cap = 1; sc_eos_clear = ""; } sc_clear = ltgetstr("cl", &sp); if (sc_clear == NULL || *sc_clear == '\0') { missing_cap = 1; sc_clear = "\n\n"; } sc_move = ltgetstr("cm", &sp); if (sc_move == NULL || *sc_move == '\0') { /* * This is not an error here, because we don't * always need sc_move. * We need it only if we don't have home or lower-left. */ sc_move = ""; can_goto_line = 0; } else can_goto_line = 1; tmodes("so", "se", &sc_s_in, &sc_s_out, "", "", &sp); tmodes("us", "ue", &sc_u_in, &sc_u_out, sc_s_in, sc_s_out, &sp); tmodes("md", "me", &sc_b_in, &sc_b_out, sc_s_in, sc_s_out, &sp); tmodes("mb", "me", &sc_bl_in, &sc_bl_out, sc_s_in, sc_s_out, &sp); sc_visual_bell = ltgetstr("vb", &sp); if (sc_visual_bell == NULL) sc_visual_bell = ""; if (ltgetflag("bs")) sc_backspace = "\b"; else { sc_backspace = ltgetstr("bc", &sp); if (sc_backspace == NULL || *sc_backspace == '\0') sc_backspace = "\b"; } /* * Choose between using "ho" and "cm" ("home" and "cursor move") * to move the cursor to the upper left corner of the screen. */ t1 = ltgetstr("ho", &sp); if (t1 == NULL) t1 = ""; if (*sc_move == '\0') t2 = ""; else { strcpy(sp, tgoto(sc_move, 0, 0)); t2 = sp; sp += strlen(sp) + 1; } sc_home = cheaper(t1, t2, "|\b^"); /* * Choose between using "ll" and "cm" ("lower left" and "cursor move") * to move the cursor to the lower left corner of the screen. */ t1 = ltgetstr("ll", &sp); if (t1 == NULL) t1 = ""; if (*sc_move == '\0') t2 = ""; else { strcpy(sp, tgoto(sc_move, 0, sc_height-1)); t2 = sp; sp += strlen(sp) + 1; } sc_lower_left = cheaper(t1, t2, "\r"); /* * Get carriage return string. */ sc_return = ltgetstr("cr", &sp); if (sc_return == NULL) sc_return = "\r"; /* * Choose between using "al" or "sr" ("add line" or "scroll reverse") * to add a line at the top of the screen. */ t1 = ltgetstr("al", &sp); if (t1 == NULL) t1 = ""; t2 = ltgetstr("sr", &sp); if (t2 == NULL) t2 = ""; #if OS2 if (*t1 == '\0' && *t2 == '\0') sc_addline = ""; else #endif if (above_mem) sc_addline = t1; else sc_addline = cheaper(t1, t2, ""); if (*sc_addline == '\0') { /* * Force repaint on any backward movement. */ no_back_scroll = 1; } #endif /* MSDOS_COMPILER */ } #if !MSDOS_COMPILER /* * Return the cost of displaying a termcap string. * We use the trick of calling tputs, but as a char printing function * we give it inc_costcount, which just increments "costcount". * This tells us how many chars would be printed by using this string. * {{ Couldn't we just use strlen? }} */ static int costcount; /*ARGSUSED*/ static int -inc_costcount(c) - int c; +inc_costcount(int c) { costcount++; return (c); } static int -cost(t) - char *t; +cost(char *t) { costcount = 0; tputs(t, sc_height, inc_costcount); return (costcount); } /* * Return the "best" of the two given termcap strings. * The best, if both exist, is the one with the lower * cost (see cost() function). */ static char * -cheaper(t1, t2, def) - char *t1, *t2; - char *def; +cheaper(char *t1, char *t2, char *def) { if (*t1 == '\0' && *t2 == '\0') { missing_cap = 1; return (def); } if (*t1 == '\0') return (t2); if (*t2 == '\0') return (t1); if (cost(t1) < cost(t2)) return (t1); return (t2); } static void -tmodes(incap, outcap, instr, outstr, def_instr, def_outstr, spp) - char *incap; - char *outcap; - char **instr; - char **outstr; - char *def_instr; - char *def_outstr; - char **spp; +tmodes(char *incap, char *outcap, char **instr, char **outstr, char *def_instr, + char *def_outstr, char **spp) { *instr = ltgetstr(incap, spp); if (*instr == NULL) { /* Use defaults. */ *instr = def_instr; *outstr = def_outstr; return; } *outstr = ltgetstr(outcap, spp); if (*outstr == NULL) /* No specific out capability; use "me". */ *outstr = ltgetstr("me", spp); if (*outstr == NULL) /* Don't even have "me"; use a null string. */ *outstr = ""; } #endif /* MSDOS_COMPILER */ /* * Below are the functions which perform all the * terminal-specific screen manipulation. */ #if MSDOS_COMPILER #if MSDOS_COMPILER==WIN32C static void _settextposition(int row, int col) { COORD cpos; CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(con_out, &csbi); cpos.X = csbi.srWindow.Left + (col - 1); cpos.Y = csbi.srWindow.Top + (row - 1); SetConsoleCursorPosition(con_out, cpos); } #endif /* * Initialize the screen to the correct color at startup. */ static void -initcolor() +initcolor(void) { SETCOLORS(nm_fg_color, nm_bg_color); #if 0 /* * This clears the screen at startup. This is different from * the behavior of other versions of less. Disable it for now. */ char *blanks; int row; int col; /* * Create a complete, blank screen using "normal" colors. */ SETCOLORS(nm_fg_color, nm_bg_color); blanks = (char *) ecalloc(width+1, sizeof(char)); for (col = 0; col < sc_width; col++) blanks[col] = ' '; blanks[sc_width] = '\0'; for (row = 0; row < sc_height; row++) _outtext(blanks); free(blanks); #endif } #endif #if MSDOS_COMPILER==WIN32C /* * Termcap-like init with a private win32 console. */ static void -win32_init_term() +win32_init_term(void) { CONSOLE_SCREEN_BUFFER_INFO scr; COORD size; if (con_out_save == INVALID_HANDLE_VALUE) return; GetConsoleScreenBufferInfo(con_out_save, &scr); if (con_out_ours == INVALID_HANDLE_VALUE) { /* * Create our own screen buffer, so that we * may restore the original when done. */ con_out_ours = CreateConsoleScreenBuffer( GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES) NULL, CONSOLE_TEXTMODE_BUFFER, (LPVOID) NULL); } size.X = scr.srWindow.Right - scr.srWindow.Left + 1; size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; SetConsoleScreenBufferSize(con_out_ours, size); SetConsoleActiveScreenBuffer(con_out_ours); con_out = con_out_ours; } /* * Restore the startup console. */ static void win32_deinit_term() { if (con_out_save == INVALID_HANDLE_VALUE) return; if (quitting) (void) CloseHandle(con_out_ours); SetConsoleActiveScreenBuffer(con_out_save); con_out = con_out_save; } #endif /* * Initialize terminal */ public void -init() +init(void) { #if !MSDOS_COMPILER if (!no_init) tputs(sc_init, sc_height, putchr); if (!no_keypad) tputs(sc_s_keypad, sc_height, putchr); if (top_scroll) { int i; /* * This is nice to terminals with no alternate screen, * but with saved scrolled-off-the-top lines. This way, * no previous line is lost, but we start with a whole * screen to ourself. */ for (i = 1; i < sc_height; i++) putchr('\n'); } else line_left(); #else #if MSDOS_COMPILER==WIN32C if (!no_init) win32_init_term(); #endif initcolor(); flush(); #endif init_done = 1; } /* * Deinitialize terminal */ public void -deinit() +deinit(void) { if (!init_done) return; #if !MSDOS_COMPILER if (!no_keypad) tputs(sc_e_keypad, sc_height, putchr); if (!no_init) tputs(sc_deinit, sc_height, putchr); #else /* Restore system colors. */ SETCOLORS(sy_fg_color, sy_bg_color); #if MSDOS_COMPILER==WIN32C if (!no_init) win32_deinit_term(); #else /* Need clreol to make SETCOLORS take effect. */ clreol(); #endif #endif init_done = 0; } /* * Home cursor (move to upper left corner of screen). */ public void -home() +home(void) { #if !MSDOS_COMPILER tputs(sc_home, 1, putchr); #else flush(); _settextposition(1,1); #endif } /* * Add a blank line (called with cursor at home). * Should scroll the display down. */ public void -add_line() +add_line(void) { #if !MSDOS_COMPILER tputs(sc_addline, sc_height, putchr); #else flush(); #if MSDOS_COMPILER==MSOFTC _scrolltextwindow(_GSCROLLDOWN); _settextposition(1,1); #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC movetext(1,1, sc_width,sc_height-1, 1,2); gotoxy(1,1); clreol(); #else #if MSDOS_COMPILER==WIN32C { CHAR_INFO fillchar; SMALL_RECT rcSrc, rcClip; COORD new_org; CONSOLE_SCREEN_BUFFER_INFO csbi; GetConsoleScreenBufferInfo(con_out,&csbi); /* The clip rectangle is the entire visible screen. */ rcClip.Left = csbi.srWindow.Left; rcClip.Top = csbi.srWindow.Top; rcClip.Right = csbi.srWindow.Right; rcClip.Bottom = csbi.srWindow.Bottom; /* The source rectangle is the visible screen minus the last line. */ rcSrc = rcClip; rcSrc.Bottom--; /* Move the top left corner of the source window down one row. */ new_org.X = rcSrc.Left; new_org.Y = rcSrc.Top + 1; /* Fill the right character and attributes. */ fillchar.Char.AsciiChar = ' '; curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); fillchar.Attributes = curr_attr; ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); _settextposition(1,1); } #endif #endif #endif #endif } #if 0 /* * Remove the n topmost lines and scroll everything below it in the * window upward. This is needed to stop leaking the topmost line * into the scrollback buffer when we go down-one-line (in WIN32). */ public void -remove_top(n) - int n; +remove_top(int n) { #if MSDOS_COMPILER==WIN32C SMALL_RECT rcSrc, rcClip; CHAR_INFO fillchar; COORD new_org; CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */ if (n >= sc_height - 1) { clear(); home(); return; } flush(); GetConsoleScreenBufferInfo(con_out, &csbi); /* Get the extent of all-visible-rows-but-the-last. */ rcSrc.Left = csbi.srWindow.Left; rcSrc.Top = csbi.srWindow.Top + n; rcSrc.Right = csbi.srWindow.Right; rcSrc.Bottom = csbi.srWindow.Bottom; /* Get the clip rectangle. */ rcClip.Left = rcSrc.Left; rcClip.Top = csbi.srWindow.Top; rcClip.Right = rcSrc.Right; rcClip.Bottom = rcSrc.Bottom ; /* Move the source window up n rows. */ new_org.X = rcSrc.Left; new_org.Y = rcSrc.Top - n; /* Fill the right character and attributes. */ fillchar.Char.AsciiChar = ' '; curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); fillchar.Attributes = curr_attr; ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); /* Position cursor on first blank line. */ goto_line(sc_height - n - 1); #endif } #endif #if MSDOS_COMPILER==WIN32C /* * Clear the screen. */ static void -win32_clear() +win32_clear(void) { /* * This will clear only the currently visible rows of the NT * console buffer, which means none of the precious scrollback * rows are touched making for faster scrolling. Note that, if * the window has fewer columns than the console buffer (i.e. * there is a horizontal scrollbar as well), the entire width * of the visible rows will be cleared. */ COORD topleft; DWORD nchars; DWORD winsz; CONSOLE_SCREEN_BUFFER_INFO csbi; /* get the number of cells in the current buffer */ GetConsoleScreenBufferInfo(con_out, &csbi); winsz = csbi.dwSize.X * (csbi.srWindow.Bottom - csbi.srWindow.Top + 1); topleft.X = 0; topleft.Y = csbi.srWindow.Top; curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); FillConsoleOutputCharacter(con_out, ' ', winsz, topleft, &nchars); FillConsoleOutputAttribute(con_out, curr_attr, winsz, topleft, &nchars); } /* * Remove the n topmost lines and scroll everything below it in the * window upward. */ public void -win32_scroll_up(n) - int n; +win32_scroll_up(int n) { SMALL_RECT rcSrc, rcClip; CHAR_INFO fillchar; COORD topleft; COORD new_org; DWORD nchars; DWORD size; CONSOLE_SCREEN_BUFFER_INFO csbi; if (n <= 0) return; if (n >= sc_height - 1) { win32_clear(); _settextposition(1,1); return; } /* Get the extent of what will remain visible after scrolling. */ GetConsoleScreenBufferInfo(con_out, &csbi); rcSrc.Left = csbi.srWindow.Left; rcSrc.Top = csbi.srWindow.Top + n; rcSrc.Right = csbi.srWindow.Right; rcSrc.Bottom = csbi.srWindow.Bottom; /* Get the clip rectangle. */ rcClip.Left = rcSrc.Left; rcClip.Top = csbi.srWindow.Top; rcClip.Right = rcSrc.Right; rcClip.Bottom = rcSrc.Bottom ; /* Move the source text to the top of the screen. */ new_org.X = rcSrc.Left; new_org.Y = rcClip.Top; /* Fill the right character and attributes. */ fillchar.Char.AsciiChar = ' '; fillchar.Attributes = MAKEATTR(nm_fg_color, nm_bg_color); /* Scroll the window. */ SetConsoleTextAttribute(con_out, fillchar.Attributes); ScrollConsoleScreenBuffer(con_out, &rcSrc, &rcClip, new_org, &fillchar); /* Clear remaining lines at bottom. */ topleft.X = csbi.dwCursorPosition.X; topleft.Y = rcSrc.Bottom - n; size = (n * csbi.dwSize.X) + (rcSrc.Right - topleft.X); FillConsoleOutputCharacter(con_out, ' ', size, topleft, &nchars); FillConsoleOutputAttribute(con_out, fillchar.Attributes, size, topleft, &nchars); SetConsoleTextAttribute(con_out, curr_attr); /* Move cursor n lines up from where it was. */ csbi.dwCursorPosition.Y -= n; SetConsoleCursorPosition(con_out, csbi.dwCursorPosition); } #endif /* * Move cursor to lower left corner of screen. */ public void -lower_left() +lower_left(void) { #if !MSDOS_COMPILER tputs(sc_lower_left, 1, putchr); #else flush(); _settextposition(sc_height, 1); #endif } /* * Move cursor to left position of current line. */ public void -line_left() +line_left(void) { #if !MSDOS_COMPILER tputs(sc_return, 1, putchr); #else int row; flush(); #if MSDOS_COMPILER==WIN32C { CONSOLE_SCREEN_BUFFER_INFO scr; GetConsoleScreenBufferInfo(con_out, &scr); row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; } #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC row = wherey(); #else { struct rccoord tpos = _gettextposition(); row = tpos.row; } #endif #endif _settextposition(row, 1); #endif } /* * Check if the console size has changed and reset internals * (in lieu of SIGWINCH for WIN32). */ public void -check_winch() +check_winch(void) { #if MSDOS_COMPILER==WIN32C CONSOLE_SCREEN_BUFFER_INFO scr; COORD size; if (con_out == INVALID_HANDLE_VALUE) return; flush(); GetConsoleScreenBufferInfo(con_out, &scr); size.Y = scr.srWindow.Bottom - scr.srWindow.Top + 1; size.X = scr.srWindow.Right - scr.srWindow.Left + 1; if (size.Y != sc_height || size.X != sc_width) { sc_height = size.Y; sc_width = size.X; if (!no_init && con_out_ours == con_out) SetConsoleScreenBufferSize(con_out, size); pos_init(); wscroll = (sc_height + 1) / 2; screen_trashed = 1; } #endif } /* * Goto a specific line on the screen. */ public void -goto_line(slinenum) - int slinenum; +goto_line(int slinenum) { #if !MSDOS_COMPILER tputs(tgoto(sc_move, 0, slinenum), 1, putchr); #else flush(); _settextposition(slinenum+1, 1); #endif } #if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC /* * Create an alternate screen which is all white. * This screen is used to create a "flash" effect, by displaying it * briefly and then switching back to the normal screen. * {{ Yuck! There must be a better way to get a visual bell. }} */ static void -create_flash() +create_flash(void) { #if MSDOS_COMPILER==MSOFTC struct videoconfig w; char *blanks; int row, col; _getvideoconfig(&w); videopages = w.numvideopages; if (videopages < 2) { at_enter(AT_STANDOUT); at_exit(); } else { _setactivepage(1); at_enter(AT_STANDOUT); blanks = (char *) ecalloc(w.numtextcols, sizeof(char)); for (col = 0; col < w.numtextcols; col++) blanks[col] = ' '; for (row = w.numtextrows; row > 0; row--) _outmem(blanks, w.numtextcols); _setactivepage(0); _setvisualpage(0); free(blanks); at_exit(); } #else #if MSDOS_COMPILER==BORLANDC - register int n; + int n; whitescreen = (unsigned short *) malloc(sc_width * sc_height * sizeof(short)); if (whitescreen == NULL) return; for (n = 0; n < sc_width * sc_height; n++) whitescreen[n] = 0x7020; #else #if MSDOS_COMPILER==WIN32C - register int n; + int n; whitescreen = (WORD *) malloc(sc_height * sc_width * sizeof(WORD)); if (whitescreen == NULL) return; /* Invert the standard colors. */ for (n = 0; n < sc_width * sc_height; n++) whitescreen[n] = (WORD)((nm_fg_color << 4) | nm_bg_color); #endif #endif #endif flash_created = 1; } #endif /* MSDOS_COMPILER */ /* * Output the "visual bell", if there is one. */ public void -vbell() +vbell(void) { #if !MSDOS_COMPILER if (*sc_visual_bell == '\0') return; tputs(sc_visual_bell, sc_height, putchr); #else #if MSDOS_COMPILER==DJGPPC ScreenVisualBell(); #else #if MSDOS_COMPILER==MSOFTC /* * Create a flash screen on the second video page. * Switch to that page, then switch back. */ if (!flash_created) create_flash(); if (videopages < 2) return; _setvisualpage(1); delay(100); _setvisualpage(0); #else #if MSDOS_COMPILER==BORLANDC unsigned short *currscreen; /* * Get a copy of the current screen. * Display the flash screen. * Then restore the old screen. */ if (!flash_created) create_flash(); if (whitescreen == NULL) return; currscreen = (unsigned short *) malloc(sc_width * sc_height * sizeof(short)); if (currscreen == NULL) return; gettext(1, 1, sc_width, sc_height, currscreen); puttext(1, 1, sc_width, sc_height, whitescreen); delay(100); puttext(1, 1, sc_width, sc_height, currscreen); free(currscreen); #else #if MSDOS_COMPILER==WIN32C /* paint screen with an inverse color */ clear(); /* leave it displayed for 100 msec. */ Sleep(100); /* restore with a redraw */ repaint(); #endif #endif #endif #endif #endif } /* * Make a noise. */ static void -beep() +beep(void) { #if !MSDOS_COMPILER putchr(CONTROL('G')); #else #if MSDOS_COMPILER==WIN32C MessageBeep(0); #else write(1, "\7", 1); #endif #endif } /* * Ring the terminal bell. */ public void -bell() +bell(void) { if (quiet == VERY_QUIET) vbell(); else beep(); } /* * Clear the screen. */ public void -clear() +clear(void) { #if !MSDOS_COMPILER tputs(sc_clear, sc_height, putchr); #else flush(); #if MSDOS_COMPILER==WIN32C win32_clear(); #else _clearscreen(_GCLEARSCREEN); #endif #endif } /* * Clear from the cursor to the end of the cursor's line. * {{ This must not move the cursor. }} */ public void -clear_eol() +clear_eol(void) { #if !MSDOS_COMPILER tputs(sc_eol_clear, 1, putchr); #else #if MSDOS_COMPILER==MSOFTC short top, left; short bot, right; struct rccoord tpos; flush(); /* * Save current state. */ tpos = _gettextposition(); _gettextwindow(&top, &left, &bot, &right); /* * Set a temporary window to the current line, * from the cursor's position to the right edge of the screen. * Then clear that window. */ _settextwindow(tpos.row, tpos.col, tpos.row, sc_width); _clearscreen(_GWINDOW); /* * Restore state. */ _settextwindow(top, left, bot, right); _settextposition(tpos.row, tpos.col); #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC flush(); clreol(); #else #if MSDOS_COMPILER==WIN32C DWORD nchars; COORD cpos; CONSOLE_SCREEN_BUFFER_INFO scr; flush(); memset(&scr, 0, sizeof(scr)); GetConsoleScreenBufferInfo(con_out, &scr); cpos.X = scr.dwCursorPosition.X; cpos.Y = scr.dwCursorPosition.Y; curr_attr = MAKEATTR(nm_fg_color, nm_bg_color); FillConsoleOutputAttribute(con_out, curr_attr, scr.dwSize.X - cpos.X, cpos, &nchars); FillConsoleOutputCharacter(con_out, ' ', scr.dwSize.X - cpos.X, cpos, &nchars); #endif #endif #endif #endif } /* * Clear the current line. * Clear the screen if there's off-screen memory below the display. */ static void -clear_eol_bot() +clear_eol_bot(void) { #if MSDOS_COMPILER clear_eol(); #else if (below_mem) tputs(sc_eos_clear, 1, putchr); else tputs(sc_eol_clear, 1, putchr); #endif } /* * Clear the bottom line of the display. * Leave the cursor at the beginning of the bottom line. */ public void -clear_bot() +clear_bot(void) { /* * If we're in a non-normal attribute mode, temporarily exit * the mode while we do the clear. Some terminals fill the * cleared area with the current attribute. */ if (oldbot) lower_left(); else line_left(); if (attrmode == AT_NORMAL) clear_eol_bot(); else { int saved_attrmode = attrmode; at_exit(); clear_eol_bot(); at_enter(saved_attrmode); } } public void -at_enter(attr) - int attr; +at_enter(int attr) { attr = apply_at_specials(attr); #if !MSDOS_COMPILER /* The one with the most priority is last. */ if (attr & AT_UNDERLINE) tputs(sc_u_in, 1, putchr); if (attr & AT_BOLD) tputs(sc_b_in, 1, putchr); if (attr & AT_BLINK) tputs(sc_bl_in, 1, putchr); if (attr & AT_STANDOUT) tputs(sc_s_in, 1, putchr); #else flush(); /* The one with the most priority is first. */ if (attr & AT_STANDOUT) { SETCOLORS(so_fg_color, so_bg_color); } else if (attr & AT_BLINK) { SETCOLORS(bl_fg_color, bl_bg_color); } else if (attr & AT_BOLD) { SETCOLORS(bo_fg_color, bo_bg_color); } else if (attr & AT_UNDERLINE) { SETCOLORS(ul_fg_color, ul_bg_color); } #endif attrmode = attr; } public void -at_exit() +at_exit(void) { #if !MSDOS_COMPILER /* Undo things in the reverse order we did them. */ if (attrmode & AT_STANDOUT) tputs(sc_s_out, 1, putchr); if (attrmode & AT_BLINK) tputs(sc_bl_out, 1, putchr); if (attrmode & AT_BOLD) tputs(sc_b_out, 1, putchr); if (attrmode & AT_UNDERLINE) tputs(sc_u_out, 1, putchr); #else flush(); SETCOLORS(nm_fg_color, nm_bg_color); #endif attrmode = AT_NORMAL; } public void -at_switch(attr) - int attr; +at_switch(int attr) { int new_attrmode = apply_at_specials(attr); int ignore_modes = AT_ANSI; if ((new_attrmode & ~ignore_modes) != (attrmode & ~ignore_modes)) { at_exit(); at_enter(attr); } } public int -is_at_equiv(attr1, attr2) - int attr1; - int attr2; +is_at_equiv(int attr1, int attr2) { attr1 = apply_at_specials(attr1); attr2 = apply_at_specials(attr2); return (attr1 == attr2); } public int -apply_at_specials(attr) - int attr; +apply_at_specials(int attr) { if (attr & AT_BINARY) attr |= binattr; if (attr & AT_HILITE) attr |= AT_STANDOUT; attr &= ~(AT_BINARY|AT_HILITE); return attr; } #if 0 /* No longer used */ /* * Erase the character to the left of the cursor * and move the cursor left. */ public void -backspace() +backspace(void) { #if !MSDOS_COMPILER /* * Erase the previous character by overstriking with a space. */ tputs(sc_backspace, 1, putchr); putchr(' '); tputs(sc_backspace, 1, putchr); #else #if MSDOS_COMPILER==MSOFTC struct rccoord tpos; flush(); tpos = _gettextposition(); if (tpos.col <= 1) return; _settextposition(tpos.row, tpos.col-1); _outtext(" "); _settextposition(tpos.row, tpos.col-1); #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC cputs("\b"); #else #if MSDOS_COMPILER==WIN32C COORD cpos; DWORD cChars; CONSOLE_SCREEN_BUFFER_INFO scr; flush(); GetConsoleScreenBufferInfo(con_out, &scr); cpos = scr.dwCursorPosition; if (cpos.X <= 0) return; cpos.X--; SetConsoleCursorPosition(con_out, cpos); FillConsoleOutputCharacter(con_out, (TCHAR)' ', 1, cpos, &cChars); SetConsoleCursorPosition(con_out, cpos); #endif #endif #endif #endif } #endif /* 0 */ /* * Output a plain backspace, without erasing the previous char. */ public void -putbs() +putbs(void) { #if !MSDOS_COMPILER tputs(sc_backspace, 1, putchr); #else int row, col; flush(); { #if MSDOS_COMPILER==MSOFTC struct rccoord tpos; tpos = _gettextposition(); row = tpos.row; col = tpos.col; #else #if MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC row = wherey(); col = wherex(); #else #if MSDOS_COMPILER==WIN32C CONSOLE_SCREEN_BUFFER_INFO scr; GetConsoleScreenBufferInfo(con_out, &scr); row = scr.dwCursorPosition.Y - scr.srWindow.Top + 1; col = scr.dwCursorPosition.X - scr.srWindow.Left + 1; #endif #endif #endif } if (col <= 1) return; _settextposition(row, col-1); #endif /* MSDOS_COMPILER */ } #if MSDOS_COMPILER==WIN32C /* * Determine whether an input character is waiting to be read. */ static int -win32_kbhit(tty) - HANDLE tty; +win32_kbhit(HANDLE tty) { INPUT_RECORD ip; DWORD read; if (keyCount > 0) return (TRUE); currentKey.ascii = 0; currentKey.scan = 0; /* * Wait for a real key-down event, but * ignore SHIFT and CONTROL key events. */ do { PeekConsoleInput(tty, &ip, 1, &read); if (read == 0) return (FALSE); ReadConsoleInput(tty, &ip, 1, &read); } while (ip.EventType != KEY_EVENT || ip.Event.KeyEvent.bKeyDown != TRUE || ip.Event.KeyEvent.wVirtualScanCode == 0 || ip.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT || ip.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL || ip.Event.KeyEvent.wVirtualKeyCode == VK_MENU); currentKey.ascii = ip.Event.KeyEvent.uChar.AsciiChar; currentKey.scan = ip.Event.KeyEvent.wVirtualScanCode; keyCount = ip.Event.KeyEvent.wRepeatCount; if (ip.Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED)) { switch (currentKey.scan) { case PCK_ALT_E: /* letter 'E' */ currentKey.ascii = 0; break; } } else if (ip.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)) { switch (currentKey.scan) { case PCK_RIGHT: /* right arrow */ currentKey.scan = PCK_CTL_RIGHT; break; case PCK_LEFT: /* left arrow */ currentKey.scan = PCK_CTL_LEFT; break; case PCK_DELETE: /* delete */ currentKey.scan = PCK_CTL_DELETE; break; } } return (TRUE); } /* * Read a character from the keyboard. */ public char -WIN32getch(tty) - int tty; +WIN32getch(int tty) { int ascii; if (pending_scancode) { pending_scancode = 0; return ((char)(currentKey.scan & 0x00FF)); } while (win32_kbhit((HANDLE)tty) == FALSE) { Sleep(20); if (ABORT_SIGS()) return ('\003'); continue; } keyCount --; ascii = currentKey.ascii; /* * On PC's, the extended keys return a 2 byte sequence beginning * with '00', so if the ascii code is 00, the next byte will be * the lsb of the scan code. */ pending_scancode = (ascii == 0x00); return ((char)ascii); } #endif #if MSDOS_COMPILER /* */ public void -WIN32setcolors(fg, bg) - int fg; - int bg; +WIN32setcolors(int fg, int bg) { SETCOLORS(fg, bg); } /* */ public void -WIN32textout(text, len) - char *text; - int len; +WIN32textout(char *text, int len) { #if MSDOS_COMPILER==WIN32C DWORD written; WriteConsole(con_out, text, len, &written, NULL); #else char c = text[len]; text[len] = '\0'; cputs(text); text[len] = c; #endif } #endif Index: head/contrib/less/scrsize.c =================================================================== --- head/contrib/less/scrsize.c (revision 316338) +++ head/contrib/less/scrsize.c (revision 316339) @@ -1,103 +1,97 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * This program is used to determine the screen dimensions on OS/2 systems. * Adapted from code written by Kyosuke Tokoro (NBG01720@nifty.ne.jp). */ /* * When I wrote this routine, I consulted some part of the source code * of the xwininfo utility by X Consortium. * * Copyright (c) 1987, X Consortium * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Except as contained in this notice, the name of the X Consortium shall not * be used in advertising or otherwise to promote the sale, use or other * dealings in this Software without prior written authorization from the X * Consortium. */ #include #include #include #include -static int get_winsize(dpy, window, p_width, p_height) - Display *dpy; - Window window; - int *p_width; - int *p_height; +static int get_winsize(Display *dpy, Window window, int *p_width, int *p_height) { XWindowAttributes win_attributes; XSizeHints hints; long longjunk; if (!XGetWindowAttributes(dpy, window, &win_attributes)) return 1; if (!XGetWMNormalHints(dpy, window, &hints, &longjunk)) return 1; if (!(hints.flags & PResizeInc)) return 1; if (hints.width_inc == 0 || hints.height_inc == 0) return 1; if (!(hints.flags & (PBaseSize|PMinSize))) return 1; if (hints.flags & PBaseSize) { win_attributes.width -= hints.base_width; win_attributes.height -= hints.base_height; } else { win_attributes.width -= hints.min_width; win_attributes.height -= hints.min_height; } *p_width = win_attributes.width / hints.width_inc; *p_height = win_attributes.height / hints.height_inc; return 0; } -int main(argc, argv) - int argc; - char *argv[]; +int main(int argc, char *argv[]) { char *cp; Display *dpy; int size[2]; _scrsize(size); cp = getenv("WINDOWID"); if (cp != NULL) { dpy = XOpenDisplay(NULL); if (dpy != NULL) { get_winsize(dpy, (Window) atol(cp), &size[0], &size[1]); XCloseDisplay(dpy); } } printf("%i %i\n", size[0], size[1]); return (0); } Index: head/contrib/less/search.c =================================================================== --- head/contrib/less/search.c (revision 316338) +++ head/contrib/less/search.c (revision 316339) @@ -1,1743 +1,1692 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines to search a file for a pattern. */ #include "less.h" #include "pattern.h" #include "position.h" #include "charset.h" #define MINPOS(a,b) (((a) < (b)) ? (a) : (b)) #define MAXPOS(a,b) (((a) > (b)) ? (a) : (b)) extern int sigs; extern int how_search; extern int caseless; extern int linenums; extern int sc_height; extern int jump_sline; extern int bs_mode; extern int ctldisp; extern int status_col; extern void * constant ml_search; extern POSITION start_attnpos; extern POSITION end_attnpos; extern int utf_mode; extern int screen_trashed; #if HILITE_SEARCH extern int hilite_search; extern int size_linebuf; extern int squished; extern int can_goto_line; static int hide_hilite; static POSITION prep_startpos; static POSITION prep_endpos; static int is_caseless; static int is_ucase_pattern; /* * Structures for maintaining a set of ranges for hilites and filtered-out * lines. Each range is stored as a node within a red-black tree, and we * try to extend existing ranges (without creating overlaps) rather than * create new nodes if possible. We remember the last node found by a * search for constant-time lookup if the next search is near enough to * the previous. To aid that, we overlay a secondary doubly-linked list * on top of the red-black tree so we can find the preceding/succeeding * nodes also in constant time. * * Each node is allocated from a series of pools, each pool double the size * of the previous (for amortised constant time allocation). Since our only * tree operations are clear and node insertion, not node removal, we don't * need to maintain a usage bitmap or freelist and can just return nodes * from the pool in-order until capacity is reached. */ struct hilite { POSITION hl_startpos; POSITION hl_endpos; }; struct hilite_node { struct hilite_node *parent; struct hilite_node *left; struct hilite_node *right; struct hilite_node *prev; struct hilite_node *next; int red; struct hilite r; }; struct hilite_storage { int capacity; int used; struct hilite_storage *next; struct hilite_node *nodes; }; struct hilite_tree { struct hilite_storage *first; struct hilite_storage *current; struct hilite_node *root; struct hilite_node *lookaside; }; #define HILITE_INITIALIZER() { NULL, NULL, NULL, NULL } #define HILITE_LOOKASIDE_STEPS 2 static struct hilite_tree hilite_anchor = HILITE_INITIALIZER(); static struct hilite_tree filter_anchor = HILITE_INITIALIZER(); #endif /* * These are the static variables that represent the "remembered" * search pattern and filter pattern. */ struct pattern_info { DEFINE_PATTERN(compiled); char* text; int search_type; }; #if NO_REGEX #define info_compiled(info) ((void*)0) #else #define info_compiled(info) ((info)->compiled) #endif static struct pattern_info search_info; static struct pattern_info filter_info; /* * Are there any uppercase letters in this string? */ static int -is_ucase(str) - char *str; +is_ucase(constant char *str) { - char *str_end = str + strlen(str); + constant char *str_end = str + strlen(str); LWCHAR ch; while (str < str_end) { ch = step_char(&str, +1, str_end); if (IS_UPPER(ch)) return (1); } return (0); } /* * Compile and save a search pattern. */ static int -set_pattern(info, pattern, search_type) - struct pattern_info *info; - char *pattern; - int search_type; +set_pattern(struct pattern_info *info, char *pattern, int search_type) { #if !NO_REGEX if (pattern == NULL) CLEAR_PATTERN(info->compiled); - else if (compile_pattern(pattern, search_type, &info->compiled) < 0) + else if (compile_pattern(pattern, search_type, + (void **)&info->compiled) < 0) return -1; #endif /* Pattern compiled successfully; save the text too. */ if (info->text != NULL) free(info->text); info->text = NULL; if (pattern != NULL) { info->text = (char *) ecalloc(1, strlen(pattern)+1); strcpy(info->text, pattern); } info->search_type = search_type; /* * Ignore case if -I is set OR * -i is set AND the pattern is all lowercase. */ is_ucase_pattern = is_ucase(pattern); if (is_ucase_pattern && caseless != OPT_ONPLUS) is_caseless = 0; else is_caseless = caseless; return 0; } /* * Discard a saved pattern. */ static void -clear_pattern(info) - struct pattern_info *info; +clear_pattern(struct pattern_info *info) { if (info->text != NULL) free(info->text); info->text = NULL; #if !NO_REGEX - uncompile_pattern(&info->compiled); + uncompile_pattern((void **)&info->compiled); #endif } /* * Initialize saved pattern to nothing. */ static void -init_pattern(info) - struct pattern_info *info; +init_pattern(struct pattern_info *info) { CLEAR_PATTERN(info->compiled); info->text = NULL; info->search_type = 0; } /* * Initialize search variables. */ public void -init_search() +init_search(void) { init_pattern(&search_info); init_pattern(&filter_info); } /* * Determine which text conversions to perform before pattern matching. */ static int -get_cvt_ops() +get_cvt_ops(void) { int ops = 0; if (is_caseless || bs_mode == BS_SPECIAL) { if (is_caseless) ops |= CVT_TO_LC; if (bs_mode == BS_SPECIAL) ops |= CVT_BS; if (bs_mode != BS_CONTROL) ops |= CVT_CRLF; } else if (bs_mode != BS_CONTROL) { ops |= CVT_CRLF; } if (ctldisp == OPT_ONPLUS) ops |= CVT_ANSI; return (ops); } /* * Is there a previous (remembered) search pattern? */ static int -prev_pattern(info) - struct pattern_info *info; +prev_pattern(struct pattern_info *info) { #if !NO_REGEX if ((info->search_type & SRCH_NO_REGEX) == 0) return (!is_null_pattern(info->compiled)); #endif return (info->text != NULL); } #if HILITE_SEARCH /* * Repaint the hilites currently displayed on the screen. * Repaint each line which contains highlighted text. * If on==0, force all hilites off. */ public void -repaint_hilite(on) - int on; +repaint_hilite(int on) { int slinenum; POSITION pos; int save_hide_hilite; if (squished) repaint(); save_hide_hilite = hide_hilite; if (!on) { if (hide_hilite) return; hide_hilite = 1; } if (!can_goto_line) { repaint(); hide_hilite = save_hide_hilite; return; } for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) { pos = position(slinenum); if (pos == NULL_POSITION) continue; (void) forw_line(pos); goto_line(slinenum); put_line(); } lower_left(); hide_hilite = save_hide_hilite; } /* * Clear the attn hilite. */ public void -clear_attn() +clear_attn(void) { int slinenum; POSITION old_start_attnpos; POSITION old_end_attnpos; POSITION pos; POSITION epos; int moved = 0; if (start_attnpos == NULL_POSITION) return; old_start_attnpos = start_attnpos; old_end_attnpos = end_attnpos; start_attnpos = end_attnpos = NULL_POSITION; if (!can_goto_line) { repaint(); return; } if (squished) repaint(); for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++) { pos = position(slinenum); if (pos == NULL_POSITION) continue; epos = position(slinenum+1); if (pos < old_end_attnpos && (epos == NULL_POSITION || epos > old_start_attnpos)) { (void) forw_line(pos); goto_line(slinenum); put_line(); moved = 1; } } if (moved) lower_left(); } #endif /* * Hide search string highlighting. */ public void -undo_search() +undo_search(void) { if (!prev_pattern(&search_info)) { error("No previous regular expression", NULL_PARG); return; } #if HILITE_SEARCH hide_hilite = !hide_hilite; repaint_hilite(1); #endif } #if HILITE_SEARCH /* * Clear the hilite list. */ public void -clr_hlist(anchor) - struct hilite_tree *anchor; +clr_hlist(struct hilite_tree *anchor) { struct hilite_storage *hls; struct hilite_storage *nexthls; for (hls = anchor->first; hls != NULL; hls = nexthls) { nexthls = hls->next; free((void*)hls->nodes); free((void*)hls); } anchor->first = NULL; anchor->current = NULL; anchor->root = NULL; anchor->lookaside = NULL; prep_startpos = prep_endpos = NULL_POSITION; } public void -clr_hilite() +clr_hilite(void) { clr_hlist(&hilite_anchor); } public void -clr_filter() +clr_filter(void) { clr_hlist(&filter_anchor); } struct hilite_node* hlist_last(anchor) struct hilite_tree *anchor; { struct hilite_node *n = anchor->root; while (n != NULL && n->right != NULL) n = n->right; return n; } struct hilite_node* hlist_next(n) struct hilite_node *n; { return n->next; } struct hilite_node* hlist_prev(n) struct hilite_node *n; { return n->prev; } /* * Find the node covering pos, or the node after it if no node covers it, * or return NULL if pos is after the last range. Remember the found node, * to speed up subsequent searches for the same or similar positions (if * we return NULL, remember the last node.) */ struct hilite_node* hlist_find(anchor, pos) struct hilite_tree *anchor; POSITION pos; { struct hilite_node *n, *m; if (anchor->lookaside) { int steps = 0; int hit = 0; n = anchor->lookaside; for (;;) { if (pos < n->r.hl_endpos) { if (n->prev == NULL || pos >= n->prev->r.hl_endpos) { hit = 1; break; } } else if (n->next == NULL) { n = NULL; hit = 1; break; } /* * If we don't find the right node within a small * distance, don't keep doing a linear search! */ if (steps >= HILITE_LOOKASIDE_STEPS) break; steps++; if (pos < n->r.hl_endpos) anchor->lookaside = n = n->prev; else anchor->lookaside = n = n->next; } if (hit) return n; } n = anchor->root; m = NULL; while (n != NULL) { if (pos < n->r.hl_startpos) { if (n->left != NULL) { m = n; n = n->left; continue; } break; } if (pos >= n->r.hl_endpos) { if (n->right != NULL) { n = n->right; continue; } if (m != NULL) { n = m; } else { m = n; n = NULL; } } break; } if (n != NULL) anchor->lookaside = n; else if (m != NULL) anchor->lookaside = m; return n; } /* * Should any characters in a specified range be highlighted? */ static int -is_hilited_range(pos, epos) - POSITION pos; - POSITION epos; +is_hilited_range(POSITION pos, POSITION epos) { struct hilite_node *n = hlist_find(&hilite_anchor, pos); return (n != NULL && (epos == NULL_POSITION || epos > n->r.hl_startpos)); } /* * Is a line "filtered" -- that is, should it be hidden? */ public int -is_filtered(pos) - POSITION pos; +is_filtered(POSITION pos) { struct hilite_node *n; if (ch_getflags() & CH_HELPFILE) return (0); n = hlist_find(&filter_anchor, pos); return (n != NULL && pos >= n->r.hl_startpos); } /* * If pos is hidden, return the next position which isn't, otherwise * just return pos. */ public POSITION -next_unfiltered(pos) - POSITION pos; +next_unfiltered(POSITION pos) { struct hilite_node *n; if (ch_getflags() & CH_HELPFILE) return (pos); n = hlist_find(&filter_anchor, pos); while (n != NULL && pos >= n->r.hl_startpos) { pos = n->r.hl_endpos; n = n->next; } return (pos); } /* * If pos is hidden, return the previous position which isn't or 0 if * we're filtered right to the beginning, otherwise just return pos. */ public POSITION -prev_unfiltered(pos) - POSITION pos; +prev_unfiltered(POSITION pos) { struct hilite_node *n; if (ch_getflags() & CH_HELPFILE) return (pos); n = hlist_find(&filter_anchor, pos); while (n != NULL && pos >= n->r.hl_startpos) { pos = n->r.hl_startpos; if (pos == 0) break; pos--; n = n->prev; } return (pos); } /* * Should any characters in a specified range be highlighted? * If nohide is nonzero, don't consider hide_hilite. */ public int -is_hilited(pos, epos, nohide, p_matches) - POSITION pos; - POSITION epos; - int nohide; - int *p_matches; +is_hilited(POSITION pos, POSITION epos, int nohide, int *p_matches) { int match; if (p_matches != NULL) *p_matches = 0; if (!status_col && start_attnpos != NULL_POSITION && pos < end_attnpos && (epos == NULL_POSITION || epos > start_attnpos)) /* * The attn line overlaps this range. */ return (1); match = is_hilited_range(pos, epos); if (!match) return (0); if (p_matches != NULL) /* * Report matches, even if we're hiding highlights. */ *p_matches = 1; if (hilite_search == 0) /* * Not doing highlighting. */ return (0); if (!nohide && hide_hilite) /* * Highlighting is hidden. */ return (0); return (1); } /* * Tree node storage: get the current block of nodes if it has spare * capacity, or create a new one if not. */ static struct hilite_storage* -hlist_getstorage(anchor) - struct hilite_tree *anchor; +hlist_getstorage(struct hilite_tree *anchor) { int capacity = 1; struct hilite_storage *s; if (anchor->current) { if (anchor->current->used < anchor->current->capacity) return anchor->current; capacity = anchor->current->capacity * 2; } s = (struct hilite_storage *) ecalloc(1, sizeof(struct hilite_storage)); s->nodes = (struct hilite_node *) ecalloc(capacity, sizeof(struct hilite_node)); s->capacity = capacity; s->used = 0; s->next = NULL; if (anchor->current) anchor->current->next = s; else anchor->first = s; anchor->current = s; return s; } /* * Tree node storage: retrieve a new empty node to be inserted into the * tree. */ static struct hilite_node* -hlist_getnode(anchor) - struct hilite_tree *anchor; +hlist_getnode(struct hilite_tree *anchor) { struct hilite_storage *s = hlist_getstorage(anchor); return &s->nodes[s->used++]; } /* * Rotate the tree left around a pivot node. */ static void -hlist_rotate_left(anchor, n) - struct hilite_tree *anchor; - struct hilite_node *n; +hlist_rotate_left(struct hilite_tree *anchor, struct hilite_node *n) { struct hilite_node *np = n->parent; struct hilite_node *nr = n->right; struct hilite_node *nrl = n->right->left; if (np != NULL) { if (n == np->left) np->left = nr; else np->right = nr; } else { anchor->root = nr; } nr->left = n; n->right = nrl; nr->parent = np; n->parent = nr; if (nrl != NULL) nrl->parent = n; } /* * Rotate the tree right around a pivot node. */ static void -hlist_rotate_right(anchor, n) - struct hilite_tree *anchor; - struct hilite_node *n; +hlist_rotate_right(struct hilite_tree *anchor, struct hilite_node *n) { struct hilite_node *np = n->parent; struct hilite_node *nl = n->left; struct hilite_node *nlr = n->left->right; if (np != NULL) { if (n == np->right) np->right = nl; else np->left = nl; } else { anchor->root = nl; } nl->right = n; n->left = nlr; nl->parent = np; n->parent = nl; if (nlr != NULL) nlr->parent = n; } /* * Add a new hilite to a hilite list. */ static void -add_hilite(anchor, hl) - struct hilite_tree *anchor; - struct hilite *hl; +add_hilite(struct hilite_tree *anchor, struct hilite *hl) { struct hilite_node *p, *n, *u; /* Ignore empty ranges. */ if (hl->hl_startpos >= hl->hl_endpos) return; p = anchor->root; /* Inserting the very first node is trivial. */ if (p == NULL) { n = hlist_getnode(anchor); n->r = *hl; anchor->root = n; anchor->lookaside = n; return; } /* * Find our insertion point. If we come across any overlapping * or adjoining existing ranges, shrink our range and discard * if it become empty. */ for (;;) { if (hl->hl_startpos < p->r.hl_startpos) { if (hl->hl_endpos > p->r.hl_startpos) hl->hl_endpos = p->r.hl_startpos; if (p->left != NULL) { p = p->left; continue; } break; } if (hl->hl_startpos < p->r.hl_endpos) { hl->hl_startpos = p->r.hl_endpos; if (hl->hl_startpos >= hl->hl_endpos) return; } if (p->right != NULL) { p = p->right; continue; } break; } /* * Now we're at the right leaf, again check for contiguous ranges * and extend the existing node if possible to avoid the * insertion. Otherwise insert a new node at the leaf. */ if (hl->hl_startpos < p->r.hl_startpos) { if (hl->hl_endpos == p->r.hl_startpos) { p->r.hl_startpos = hl->hl_startpos; return; } if (p->prev != NULL && p->prev->r.hl_endpos == hl->hl_startpos) { p->prev->r.hl_endpos = hl->hl_endpos; return; } p->left = n = hlist_getnode(anchor); n->next = p; if (p->prev != NULL) { n->prev = p->prev; p->prev->next = n; } p->prev = n; } else { if (p->r.hl_endpos == hl->hl_startpos) { p->r.hl_endpos = hl->hl_endpos; return; } if (p->next != NULL && hl->hl_endpos == p->next->r.hl_startpos) { p->next->r.hl_startpos = hl->hl_startpos; return; } p->right = n = hlist_getnode(anchor); n->prev = p; if (p->next != NULL) { n->next = p->next; p->next->prev = n; } p->next = n; } n->parent = p; n->red = 1; n->r = *hl; /* * The tree is in the correct order and covers the right ranges * now, but may have become unbalanced. Rebalance it using the * standard red-black tree constraints and operations. */ for (;;) { /* case 1 - current is root, root is always black */ if (n->parent == NULL) { n->red = 0; break; } /* case 2 - parent is black, we can always be red */ if (!n->parent->red) break; /* * constraint: because the root must be black, if our * parent is red it cannot be the root therefore we must * have a grandparent */ /* * case 3 - parent and uncle are red, repaint them black, * the grandparent red, and start again at the grandparent. */ u = n->parent->parent->left; if (n->parent == u) u = n->parent->parent->right; if (u != NULL && u->red) { n->parent->red = 0; u->red = 0; n = n->parent->parent; n->red = 1; continue; } /* * case 4 - parent is red but uncle is black, parent and * grandparent on opposite sides. We need to start * changing the structure now. This and case 5 will shorten * our branch and lengthen the sibling, between them * restoring balance. */ if (n == n->parent->right && n->parent == n->parent->parent->left) { hlist_rotate_left(anchor, n->parent); n = n->left; } else if (n == n->parent->left && n->parent == n->parent->parent->right) { hlist_rotate_right(anchor, n->parent); n = n->right; } /* * case 5 - parent is red but uncle is black, parent and * grandparent on same side */ n->parent->red = 0; n->parent->parent->red = 1; if (n == n->parent->left) hlist_rotate_right(anchor, n->parent->parent); else hlist_rotate_left(anchor, n->parent->parent); break; } } /* * Hilight every character in a range of displayed characters. */ static void -create_hilites(linepos, start_index, end_index, chpos) - POSITION linepos; - int start_index; - int end_index; - int *chpos; +create_hilites(POSITION linepos, int start_index, int end_index, int *chpos) { struct hilite hl; int i; /* Start the first hilite. */ hl.hl_startpos = linepos + chpos[start_index]; /* * Step through the displayed chars. * If the source position (before cvt) of the char is one more * than the source pos of the previous char (the usual case), * just increase the size of the current hilite by one. * Otherwise (there are backspaces or something involved), * finish the current hilite and start a new one. */ for (i = start_index+1; i <= end_index; i++) { if (chpos[i] != chpos[i-1] + 1 || i == end_index) { hl.hl_endpos = linepos + chpos[i-1] + 1; add_hilite(&hilite_anchor, &hl); /* Start new hilite unless this is the last char. */ if (i < end_index) { hl.hl_startpos = linepos + chpos[i]; } } } } /* * Make a hilite for each string in a physical line which matches * the current pattern. * sp,ep delimit the first match already found. */ static void -hilite_line(linepos, line, line_len, chpos, sp, ep, cvt_ops) - POSITION linepos; - char *line; - int line_len; - int *chpos; - char *sp; - char *ep; - int cvt_ops; +hilite_line(POSITION linepos, char *line, int line_len, int *chpos, char *sp, + char *ep, int cvt_ops) { char *searchp; char *line_end = line + line_len; /* * sp and ep delimit the first match in the line. * Mark the corresponding file positions, then * look for further matches and mark them. * {{ This technique, of calling match_pattern on subsequent * substrings of the line, may mark more than is correct * if the pattern starts with "^". This bug is fixed * for those regex functions that accept a notbol parameter * (currently POSIX, PCRE and V8-with-regexec2). }} */ searchp = line; do { if (sp == NULL || ep == NULL) return; create_hilites(linepos, sp-line, ep-line, chpos); /* * If we matched more than zero characters, * move to the first char after the string we matched. * If we matched zero, just move to the next char. */ if (ep > searchp) searchp = ep; else if (searchp != line_end) searchp++; else /* end of line */ break; } while (match_pattern(info_compiled(&search_info), search_info.text, searchp, line_end - searchp, &sp, &ep, 1, search_info.search_type)); } #endif /* * Change the caseless-ness of searches. * Updates the internal search state to reflect a change in the -i flag. */ public void -chg_caseless() +chg_caseless(void) { if (!is_ucase_pattern) /* * Pattern did not have uppercase. * Just set the search caselessness to the global caselessness. */ is_caseless = caseless; else /* * Pattern did have uppercase. * Discard the pattern; we can't change search caselessness now. */ clear_pattern(&search_info); } #if HILITE_SEARCH /* * Find matching text which is currently on screen and highlight it. */ static void -hilite_screen() +hilite_screen(void) { struct scrpos scrpos; get_scrpos(&scrpos); if (scrpos.pos == NULL_POSITION) return; prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1); repaint_hilite(1); } /* * Change highlighting parameters. */ public void -chg_hilite() +chg_hilite(void) { /* * Erase any highlights currently on screen. */ clr_hilite(); hide_hilite = 0; if (hilite_search == OPT_ONPLUS) /* * Display highlights. */ hilite_screen(); } #endif /* * Figure out where to start a search. */ static POSITION -search_pos(search_type) - int search_type; +search_pos(int search_type) { POSITION pos; int linenum; if (empty_screen()) { /* * Start at the beginning (or end) of the file. * The empty_screen() case is mainly for * command line initiated searches; * for example, "+/xyz" on the command line. * Also for multi-file (SRCH_PAST_EOF) searches. */ if (search_type & SRCH_FORW) { pos = ch_zero(); } else { pos = ch_length(); if (pos == NULL_POSITION) { (void) ch_end_seek(); pos = ch_length(); } } linenum = 0; } else { int add_one = 0; if (how_search == OPT_ON) { /* * Search does not include current screen. */ if (search_type & SRCH_FORW) linenum = BOTTOM_PLUS_ONE; else linenum = TOP; } else if (how_search == OPT_ONPLUS && !(search_type & SRCH_AFTER_TARGET)) { /* * Search includes all of displayed screen. */ if (search_type & SRCH_FORW) linenum = TOP; else linenum = BOTTOM_PLUS_ONE; } else { /* * Search includes the part of current screen beyond the jump target. * It starts at the jump target (if searching backwards), * or at the jump target plus one (if forwards). */ linenum = adjsline(jump_sline); if (search_type & SRCH_FORW) add_one = 1; } pos = position(linenum); if (add_one) pos = forw_raw_line(pos, (char **)NULL, (int *)NULL); } /* * If the line is empty, look around for a plausible starting place. */ if (search_type & SRCH_FORW) { while (pos == NULL_POSITION) { if (++linenum >= sc_height) break; pos = position(linenum); } } else { while (pos == NULL_POSITION) { if (--linenum < 0) break; pos = position(linenum); } } return (pos); } /* * Search a subset of the file, specified by start/end position. */ static int -search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos) - POSITION pos; - POSITION endpos; - int search_type; - int matches; - int maxlines; - POSITION *plinepos; - POSITION *pendpos; +search_range(POSITION pos, POSITION endpos, int search_type, int matches, + int maxlines, POSITION *plinepos, POSITION *pendpos) { char *line; char *cline; int line_len; LINENUM linenum; char *sp, *ep; int line_match; int cvt_ops; int cvt_len; int *chpos; POSITION linepos, oldpos; linenum = find_linenum(pos); oldpos = pos; for (;;) { /* * Get lines until we find a matching one or until * we hit end-of-file (or beginning-of-file if we're * going backwards), or until we hit the end position. */ if (ABORT_SIGS()) { /* * A signal aborts the search. */ return (-1); } if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0) { /* * Reached end position without a match. */ if (pendpos != NULL) *pendpos = pos; return (matches); } if (maxlines > 0) maxlines--; if (search_type & SRCH_FORW) { /* * Read the next line, and save the * starting position of that line in linepos. */ linepos = pos; pos = forw_raw_line(pos, &line, &line_len); if (linenum != 0) linenum++; } else { /* * Read the previous line and save the * starting position of that line in linepos. */ pos = back_raw_line(pos, &line, &line_len); linepos = pos; if (linenum != 0) linenum--; } if (pos == NULL_POSITION) { /* * Reached EOF/BOF without a match. */ if (pendpos != NULL) *pendpos = oldpos; return (matches); } /* * If we're using line numbers, we might as well * remember the information we have now (the position * and line number of the current line). * Don't do it for every line because it slows down * the search. Remember the line number only if * we're "far" from the last place we remembered it. */ if (linenums && abs((int)(pos - oldpos)) > 2048) add_lnum(linenum, pos); oldpos = pos; if (is_filtered(linepos)) continue; /* * If it's a caseless search, convert the line to lowercase. * If we're doing backspace processing, delete backspaces. */ cvt_ops = get_cvt_ops(); cvt_len = cvt_length(line_len, cvt_ops); cline = (char *) ecalloc(1, cvt_len); chpos = cvt_alloc_chpos(cvt_len); cvt_text(cline, line, chpos, &line_len, cvt_ops); #if HILITE_SEARCH /* * Check to see if the line matches the filter pattern. * If so, add an entry to the filter list. */ if (((search_type & SRCH_FIND_ALL) || prep_startpos == NULL_POSITION || linepos < prep_startpos || linepos >= prep_endpos) && prev_pattern(&filter_info)) { int line_filter = match_pattern(info_compiled(&filter_info), filter_info.text, cline, line_len, &sp, &ep, 0, filter_info.search_type); if (line_filter) { struct hilite hl; hl.hl_startpos = linepos; hl.hl_endpos = pos; add_hilite(&filter_anchor, &hl); continue; } } #endif /* * Test the next line to see if we have a match. * We are successful if we either want a match and got one, * or if we want a non-match and got one. */ if (prev_pattern(&search_info)) { line_match = match_pattern(info_compiled(&search_info), search_info.text, cline, line_len, &sp, &ep, 0, search_type); if (line_match) { /* * Got a match. */ if (search_type & SRCH_FIND_ALL) { #if HILITE_SEARCH /* * We are supposed to find all matches in the range. * Just add the matches in this line to the * hilite list and keep searching. */ hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops); #endif } else if (--matches <= 0) { /* * Found the one match we're looking for. * Return it. */ #if HILITE_SEARCH if (hilite_search == OPT_ON) { /* * Clear the hilite list and add only * the matches in this one line. */ clr_hilite(); hilite_line(linepos, cline, line_len, chpos, sp, ep, cvt_ops); } #endif free(cline); free(chpos); if (plinepos != NULL) *plinepos = linepos; return (0); } } } free(cline); free(chpos); } } /* * search for a pattern in history. If found, compile that pattern. */ static int -hist_pattern(search_type) - int search_type; +hist_pattern(int search_type) { #if CMD_HISTORY char *pattern; set_mlist(ml_search, 0); pattern = cmd_lastpattern(); if (pattern == NULL) return (0); if (set_pattern(&search_info, pattern, search_type) < 0) return (0); #if HILITE_SEARCH if (hilite_search == OPT_ONPLUS && !hide_hilite) hilite_screen(); #endif return (1); #else /* CMD_HISTORY */ return (0); #endif /* CMD_HISTORY */ } /* * Search for the n-th occurrence of a specified pattern, * either forward or backward. * Return the number of matches not yet found in this file * (that is, n minus the number of matches found). * Return -1 if the search should be aborted. * Caller may continue the search in another file * if less than n matches are found in this file. */ public int -search(search_type, pattern, n) - int search_type; - char *pattern; - int n; +search(int search_type, char *pattern, int n) { POSITION pos; if (pattern == NULL || *pattern == '\0') { /* * A null pattern means use the previously compiled pattern. */ search_type |= SRCH_AFTER_TARGET; if (!prev_pattern(&search_info) && !hist_pattern(search_type)) { error("No previous regular expression", NULL_PARG); return (-1); } if ((search_type & SRCH_NO_REGEX) != (search_info.search_type & SRCH_NO_REGEX)) { error("Please re-enter search pattern", NULL_PARG); return -1; } #if HILITE_SEARCH if (hilite_search == OPT_ON) { /* * Erase the highlights currently on screen. * If the search fails, we'll redisplay them later. */ repaint_hilite(0); } if (hilite_search == OPT_ONPLUS && hide_hilite) { /* * Highlight any matches currently on screen, * before we actually start the search. */ hide_hilite = 0; hilite_screen(); } hide_hilite = 0; #endif } else { /* * Compile the pattern. */ if (set_pattern(&search_info, pattern, search_type) < 0) return (-1); #if HILITE_SEARCH if (hilite_search) { /* * Erase the highlights currently on screen. * Also permanently delete them from the hilite list. */ repaint_hilite(0); hide_hilite = 0; clr_hilite(); } if (hilite_search == OPT_ONPLUS) { /* * Highlight any matches currently on screen, * before we actually start the search. */ hilite_screen(); } #endif } /* * Figure out where to start the search. */ pos = search_pos(search_type); if (pos == NULL_POSITION) { /* * Can't find anyplace to start searching from. */ if (search_type & SRCH_PAST_EOF) return (n); /* repaint(); -- why was this here? */ error("Nothing to search", NULL_PARG); return (-1); } n = search_range(pos, NULL_POSITION, search_type, n, -1, &pos, (POSITION*)NULL); if (n != 0) { /* * Search was unsuccessful. */ #if HILITE_SEARCH if (hilite_search == OPT_ON && n > 0) /* * Redisplay old hilites. */ repaint_hilite(1); #endif return (n); } if (!(search_type & SRCH_NO_MOVE)) { /* * Go to the matching line. */ jump_loc(pos, jump_sline); } #if HILITE_SEARCH if (hilite_search == OPT_ON) /* * Display new hilites in the matching line. */ repaint_hilite(1); #endif return (0); } #if HILITE_SEARCH /* * Prepare hilites in a given range of the file. * * The pair (prep_startpos,prep_endpos) delimits a contiguous region * of the file that has been "prepared"; that is, scanned for matches for * the current search pattern, and hilites have been created for such matches. * If prep_startpos == NULL_POSITION, the prep region is empty. * If prep_endpos == NULL_POSITION, the prep region extends to EOF. * prep_hilite asks that the range (spos,epos) be covered by the prep region. */ public void -prep_hilite(spos, epos, maxlines) - POSITION spos; - POSITION epos; - int maxlines; +prep_hilite(POSITION spos, POSITION epos, int maxlines) { POSITION nprep_startpos = prep_startpos; POSITION nprep_endpos = prep_endpos; POSITION new_epos; POSITION max_epos; int result; int i; /* * Search beyond where we're asked to search, so the prep region covers * more than we need. Do one big search instead of a bunch of small ones. */ #define SEARCH_MORE (3*size_linebuf) if (!prev_pattern(&search_info) && !is_filtering()) return; /* * Make sure our prep region always starts at the beginning of * a line. (search_range takes care of the end boundary below.) */ spos = back_raw_line(spos+1, (char **)NULL, (int *)NULL); /* * If we're limited to a max number of lines, figure out the * file position we should stop at. */ if (maxlines < 0) max_epos = NULL_POSITION; else { max_epos = spos; for (i = 0; i < maxlines; i++) max_epos = forw_raw_line(max_epos, (char **)NULL, (int *)NULL); } /* * Find two ranges: * The range that we need to search (spos,epos); and the range that * the "prep" region will then cover (nprep_startpos,nprep_endpos). */ if (prep_startpos == NULL_POSITION || (epos != NULL_POSITION && epos < prep_startpos) || spos > prep_endpos) { /* * New range is not contiguous with old prep region. * Discard the old prep region and start a new one. */ clr_hilite(); clr_filter(); if (epos != NULL_POSITION) epos += SEARCH_MORE; nprep_startpos = spos; } else { /* * New range partially or completely overlaps old prep region. */ if (epos == NULL_POSITION) { /* * New range goes to end of file. */ ; } else if (epos > prep_endpos) { /* * New range ends after old prep region. * Extend prep region to end at end of new range. */ epos += SEARCH_MORE; } else /* (epos <= prep_endpos) */ { /* * New range ends within old prep region. * Truncate search to end at start of old prep region. */ epos = prep_startpos; } if (spos < prep_startpos) { /* * New range starts before old prep region. * Extend old prep region backwards to start at * start of new range. */ if (spos < SEARCH_MORE) spos = 0; else spos -= SEARCH_MORE; nprep_startpos = spos; } else /* (spos >= prep_startpos) */ { /* * New range starts within or after old prep region. * Trim search to start at end of old prep region. */ spos = prep_endpos; } } if (epos != NULL_POSITION && max_epos != NULL_POSITION && epos > max_epos) /* * Don't go past the max position we're allowed. */ epos = max_epos; if (epos == NULL_POSITION || epos > spos) { int search_type = SRCH_FORW | SRCH_FIND_ALL; search_type |= (search_info.search_type & SRCH_NO_REGEX); for (;;) { result = search_range(spos, epos, search_type, 0, maxlines, (POSITION*)NULL, &new_epos); if (result < 0) return; if (prep_endpos == NULL_POSITION || new_epos > prep_endpos) nprep_endpos = new_epos; /* * Check both ends of the resulting prep region to * make sure they're not filtered. If they are, * keep going at least one more line until we find * something that isn't filtered, or hit the end. */ if (prep_endpos == NULL_POSITION || nprep_endpos > prep_endpos) { if (new_epos >= nprep_endpos && is_filtered(new_epos-1)) { spos = nprep_endpos; epos = forw_raw_line(nprep_endpos, (char **)NULL, (int *)NULL); if (epos == NULL_POSITION) break; maxlines = 1; continue; } } if (prep_startpos == NULL_POSITION || nprep_startpos < prep_startpos) { if (nprep_startpos > 0 && is_filtered(nprep_startpos)) { epos = nprep_startpos; spos = back_raw_line(nprep_startpos, (char **)NULL, (int *)NULL); if (spos == NULL_POSITION) break; nprep_startpos = spos; maxlines = 1; continue; } } break; } } prep_startpos = nprep_startpos; prep_endpos = nprep_endpos; } /* * Set the pattern to be used for line filtering. */ public void -set_filter_pattern(pattern, search_type) - char *pattern; - int search_type; +set_filter_pattern(char *pattern, int search_type) { clr_filter(); if (pattern == NULL || *pattern == '\0') clear_pattern(&filter_info); else set_pattern(&filter_info, pattern, search_type); screen_trashed = 1; } /* * Is there a line filter in effect? */ public int -is_filtering() +is_filtering(void) { if (ch_getflags() & CH_HELPFILE) return (0); return prev_pattern(&filter_info); } #endif #if HAVE_V8_REGCOMP /* * This function is called by the V8 regcomp to report * errors in regular expressions. */ public int reg_show_error = 1; void regerror(s) char *s; { PARG parg; if (!reg_show_error) return; parg.p_string = s; error("%s", &parg); } #endif Index: head/contrib/less/signal.c =================================================================== --- head/contrib/less/signal.c (revision 316338) +++ head/contrib/less/signal.c (revision 316339) @@ -1,260 +1,254 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* $FreeBSD$ */ /* * Routines dealing with signals. * * A signal usually merely causes a bit to be set in the "signals" word. * At some convenient time, the mainline code checks to see if any * signals need processing by calling psignal(). * If we happen to be reading from a file [in iread()] at the time * the signal is received, we call intread to interrupt the iread. */ #include "less.h" #include /* * "sigs" contains bits indicating signals which need to be processed. */ public int sigs; extern int sc_width, sc_height; extern int screen_trashed; extern int lnloop; extern int linenums; extern int wscroll; extern int reading; extern int quit_on_intr; extern int less_is_more; extern long jump_sline_fraction; /* * Interrupt signal handler. */ /* ARGSUSED*/ static RETSIGTYPE -u_interrupt(type) - int type; +u_interrupt(int type) { bell(); #if OS2 LSIGNAL(SIGINT, SIG_ACK); #endif LSIGNAL(SIGINT, u_interrupt); sigs |= S_INTERRUPT; #if MSDOS_COMPILER==DJGPPC /* * If a keyboard has been hit, it must be Ctrl-C * (as opposed to Ctrl-Break), so consume it. * (Otherwise, Less will beep when it sees Ctrl-C from keyboard.) */ if (kbhit()) getkey(); #endif if (less_is_more) quit(0); if (reading) intread(); /* May longjmp */ } #ifdef SIGTSTP /* * "Stop" (^Z) signal handler. */ /* ARGSUSED*/ static RETSIGTYPE -stop(type) - int type; +stop(int type) { LSIGNAL(SIGTSTP, stop); sigs |= S_STOP; if (reading) intread(); } #endif #ifdef SIGWINCH /* * "Window" change handler */ /* ARGSUSED*/ public RETSIGTYPE -winch(type) - int type; +winch(int type) { LSIGNAL(SIGWINCH, winch); sigs |= S_WINCH; if (reading) intread(); } #else #ifdef SIGWIND /* * "Window" change handler */ /* ARGSUSED*/ public RETSIGTYPE -winch(type) - int type; +winch(int type) { LSIGNAL(SIGWIND, winch); sigs |= S_WINCH; if (reading) intread(); } #endif #endif #if MSDOS_COMPILER==WIN32C /* * Handle CTRL-C and CTRL-BREAK keys. */ #include "windows.h" static BOOL WINAPI -wbreak_handler(dwCtrlType) - DWORD dwCtrlType; +wbreak_handler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: sigs |= S_INTERRUPT; return (TRUE); default: break; } return (FALSE); } #endif /* * Set up the signal handlers. */ public void -init_signals(on) - int on; +init_signals(int on) { if (on) { /* * Set signal handlers. */ (void) LSIGNAL(SIGINT, u_interrupt); #if MSDOS_COMPILER==WIN32C SetConsoleCtrlHandler(wbreak_handler, TRUE); #endif #ifdef SIGTSTP (void) LSIGNAL(SIGTSTP, stop); #endif #ifdef SIGWINCH (void) LSIGNAL(SIGWINCH, winch); #endif #ifdef SIGWIND (void) LSIGNAL(SIGWIND, winch); #endif #ifdef SIGQUIT (void) LSIGNAL(SIGQUIT, SIG_IGN); #endif } else { /* * Restore signals to defaults. */ (void) LSIGNAL(SIGINT, SIG_DFL); #if MSDOS_COMPILER==WIN32C SetConsoleCtrlHandler(wbreak_handler, FALSE); #endif #ifdef SIGTSTP (void) LSIGNAL(SIGTSTP, SIG_DFL); #endif #ifdef SIGWINCH (void) LSIGNAL(SIGWINCH, SIG_IGN); #endif #ifdef SIGWIND (void) LSIGNAL(SIGWIND, SIG_IGN); #endif #ifdef SIGQUIT (void) LSIGNAL(SIGQUIT, SIG_DFL); #endif } } /* * Process any signals we have received. * A received signal cause a bit to be set in "sigs". */ public void -psignals() +psignals(void) { - register int tsignals; + int tsignals; if ((tsignals = sigs) == 0) return; sigs = 0; #ifdef SIGTSTP if (tsignals & S_STOP) { /* * Clean up the terminal. */ #ifdef SIGTTOU LSIGNAL(SIGTTOU, SIG_IGN); #endif clear_bot(); deinit(); flush(); raw_mode(0); #ifdef SIGTTOU LSIGNAL(SIGTTOU, SIG_DFL); #endif LSIGNAL(SIGTSTP, SIG_DFL); kill(getpid(), SIGTSTP); /* * ... Bye bye. ... * Hopefully we'll be back later and resume here... * Reset the terminal and arrange to repaint the * screen when we get back to the main command loop. */ LSIGNAL(SIGTSTP, stop); raw_mode(1); init(); screen_trashed = 1; tsignals |= S_WINCH; } #endif #ifdef S_WINCH if (tsignals & S_WINCH) { int old_width, old_height; /* * Re-execute scrsize() to read the new window size. */ old_width = sc_width; old_height = sc_height; get_term(); if (sc_width != old_width || sc_height != old_height) { wscroll = (sc_height + 1) / 2; calc_jump_sline(); calc_shift_count(); screen_trashed = 1; } } #endif if (tsignals & S_INTERRUPT) { if (quit_on_intr) quit(QUIT_INTERRUPT); } } Index: head/contrib/less/tags.c =================================================================== --- head/contrib/less/tags.c (revision 316338) +++ head/contrib/less/tags.c (revision 316339) @@ -1,757 +1,742 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ #include "less.h" #define WHITESP(c) ((c)==' ' || (c)=='\t') #if TAGS public char ztags[] = "tags"; public char *tags = ztags; static int total; static int curseq; extern int linenums; extern int sigs; enum tag_result { TAG_FOUND, TAG_NOFILE, TAG_NOTAG, TAG_NOTYPE, TAG_INTR }; /* * Tag type */ enum { T_CTAGS, /* 'tags': standard and extended format (ctags) */ T_CTAGS_X, /* stdin: cross reference format (ctags) */ T_GTAGS, /* 'GTAGS': function defenition (global) */ T_GRTAGS, /* 'GRTAGS': function reference (global) */ T_GSYMS, /* 'GSYMS': other symbols (global) */ T_GPATH /* 'GPATH': path name (global) */ }; -static enum tag_result findctag(); -static enum tag_result findgtag(); -static char *nextgtag(); -static char *prevgtag(); -static POSITION ctagsearch(); -static POSITION gtagsearch(); -static int getentry(); +static enum tag_result findctag(char *tag); +static enum tag_result findgtag(char *tag, int type); +static char *nextgtag(void); +static char *prevgtag(void); +static POSITION ctagsearch(void); +static POSITION gtagsearch(void); +static int getentry(char *buf, char **tag, char **file, char **line); /* * The list of tags generated by the last findgtag() call. * * Use either pattern or line number. * findgtag() always uses line number, so pattern is always NULL. * findctag() uses either pattern (in which case line number is 0), * or line number (in which case pattern is NULL). */ struct taglist { struct tag *tl_first; struct tag *tl_last; }; #define TAG_END ((struct tag *) &taglist) static struct taglist taglist = { TAG_END, TAG_END }; struct tag { struct tag *next, *prev; /* List links */ char *tag_file; /* Source file containing the tag */ LINENUM tag_linenum; /* Appropriate line number in source file */ char *tag_pattern; /* Pattern used to find the tag */ char tag_endline; /* True if the pattern includes '$' */ }; static struct tag *curtag; #define TAG_INS(tp) \ (tp)->next = TAG_END; \ (tp)->prev = taglist.tl_last; \ taglist.tl_last->next = (tp); \ taglist.tl_last = (tp); #define TAG_RM(tp) \ (tp)->next->prev = (tp)->prev; \ (tp)->prev->next = (tp)->next; /* * Delete tag structures. */ public void -cleantags() +cleantags(void) { - register struct tag *tp; + struct tag *tp; /* * Delete any existing tag list. * {{ Ideally, we wouldn't do this until after we know that we * can load some other tag information. }} */ while ((tp = taglist.tl_first) != TAG_END) { TAG_RM(tp); free(tp); } curtag = NULL; total = curseq = 0; } /* * Create a new tag entry. */ static struct tag * -maketagent(name, file, linenum, pattern, endline) - char *name; - char *file; - LINENUM linenum; - char *pattern; - int endline; +maketagent(char *name, char *file, LINENUM linenum, char *pattern, int endline) { - register struct tag *tp; + struct tag *tp; tp = (struct tag *) ecalloc(sizeof(struct tag), 1); tp->tag_file = (char *) ecalloc(strlen(file) + 1, sizeof(char)); strcpy(tp->tag_file, file); tp->tag_linenum = linenum; tp->tag_endline = endline; if (pattern == NULL) tp->tag_pattern = NULL; else { tp->tag_pattern = (char *) ecalloc(strlen(pattern) + 1, sizeof(char)); strcpy(tp->tag_pattern, pattern); } return (tp); } /* * Get tag mode. */ public int -gettagtype() +gettagtype(void) { int f; if (strcmp(tags, "GTAGS") == 0) return T_GTAGS; if (strcmp(tags, "GRTAGS") == 0) return T_GRTAGS; if (strcmp(tags, "GSYMS") == 0) return T_GSYMS; if (strcmp(tags, "GPATH") == 0) return T_GPATH; if (strcmp(tags, "-") == 0) return T_CTAGS_X; f = open(tags, OPEN_READ); if (f >= 0) { close(f); return T_CTAGS; } return T_GTAGS; } /* * Find tags in tag file. * Find a tag in the "tags" file. * Sets "tag_file" to the name of the file containing the tag, * and "tagpattern" to the search pattern which should be used * to find the tag. */ public void -findtag(tag) - register char *tag; +findtag(char *tag) { int type = gettagtype(); enum tag_result result; if (type == T_CTAGS) result = findctag(tag); else result = findgtag(tag, type); switch (result) { case TAG_FOUND: case TAG_INTR: break; case TAG_NOFILE: error("No tags file", NULL_PARG); break; case TAG_NOTAG: error("No such tag in tags file", NULL_PARG); break; case TAG_NOTYPE: error("unknown tag type", NULL_PARG); break; } } /* * Search for a tag. */ public POSITION -tagsearch() +tagsearch(void) { if (curtag == NULL) return (NULL_POSITION); /* No gtags loaded! */ if (curtag->tag_linenum != 0) return gtagsearch(); else return ctagsearch(); } /* * Go to the next tag. */ public char * -nexttag(n) - int n; +nexttag(int n) { char *tagfile = (char *) NULL; while (n-- > 0) tagfile = nextgtag(); return tagfile; } /* * Go to the previous tag. */ public char * -prevtag(n) - int n; +prevtag(int n) { char *tagfile = (char *) NULL; while (n-- > 0) tagfile = prevgtag(); return tagfile; } /* * Return the total number of tags. */ public int -ntags() +ntags(void) { return total; } /* * Return the sequence number of current tag. */ public int -curr_tag() +curr_tag(void) { return curseq; } /***************************************************************************** * ctags */ /* * Find tags in the "tags" file. * Sets curtag to the first tag entry. */ static enum tag_result -findctag(tag) - register char *tag; +findctag(char *tag) { char *p; - register FILE *f; - register int taglen; + FILE *f; + int taglen; LINENUM taglinenum; char *tagfile; char *tagpattern; int tagendline; int search_char; int err; char tline[TAGLINE_SIZE]; struct tag *tp; p = shell_unquote(tags); f = fopen(p, "r"); free(p); if (f == NULL) return TAG_NOFILE; cleantags(); total = 0; taglen = (int) strlen(tag); /* * Search the tags file for the desired tag. */ while (fgets(tline, sizeof(tline), f) != NULL) { if (tline[0] == '!') /* Skip header of extended format. */ continue; if (strncmp(tag, tline, taglen) != 0 || !WHITESP(tline[taglen])) continue; /* * Found it. * The line contains the tag, the filename and the * location in the file, separated by white space. * The location is either a decimal line number, * or a search pattern surrounded by a pair of delimiters. * Parse the line and extract these parts. */ tagpattern = NULL; /* * Skip over the whitespace after the tag name. */ p = skipsp(tline+taglen); if (*p == '\0') /* File name is missing! */ continue; /* * Save the file name. * Skip over the whitespace after the file name. */ tagfile = p; while (!WHITESP(*p) && *p != '\0') p++; *p++ = '\0'; p = skipsp(p); if (*p == '\0') /* Pattern is missing! */ continue; /* * First see if it is a line number. */ tagendline = 0; taglinenum = getnum(&p, 0, &err); if (err) { /* * No, it must be a pattern. * Delete the initial "^" (if present) and * the final "$" from the pattern. * Delete any backslash in the pattern. */ taglinenum = 0; search_char = *p++; if (*p == '^') p++; tagpattern = p; while (*p != search_char && *p != '\0') { if (*p == '\\') p++; p++; } tagendline = (p[-1] == '$'); if (tagendline) p--; *p = '\0'; } tp = maketagent(tag, tagfile, taglinenum, tagpattern, tagendline); TAG_INS(tp); total++; } fclose(f); if (total == 0) return TAG_NOTAG; curtag = taglist.tl_first; curseq = 1; return TAG_FOUND; } /* * Edit current tagged file. */ public int -edit_tagfile() +edit_tagfile(void) { if (curtag == NULL) return (1); return (edit(curtag->tag_file)); } /* * Search for a tag. * This is a stripped-down version of search(). * We don't use search() for several reasons: * - We don't want to blow away any search string we may have saved. * - The various regular-expression functions (from different systems: * regcmp vs. re_comp) behave differently in the presence of * parentheses (which are almost always found in a tag). */ static POSITION -ctagsearch() +ctagsearch(void) { POSITION pos, linepos; LINENUM linenum; int len; char *line; pos = ch_zero(); linenum = find_linenum(pos); for (;;) { /* * Get lines until we find a matching one or * until we hit end-of-file. */ if (ABORT_SIGS()) return (NULL_POSITION); /* * Read the next line, and save the * starting position of that line in linepos. */ linepos = pos; pos = forw_raw_line(pos, &line, (int *)NULL); if (linenum != 0) linenum++; if (pos == NULL_POSITION) { /* * We hit EOF without a match. */ error("Tag not found", NULL_PARG); return (NULL_POSITION); } /* * If we're using line numbers, we might as well * remember the information we have now (the position * and line number of the current line). */ if (linenums) add_lnum(linenum, pos); /* * Test the line to see if we have a match. * Use strncmp because the pattern may be * truncated (in the tags file) if it is too long. * If tagendline is set, make sure we match all * the way to end of line (no extra chars after the match). */ len = (int) strlen(curtag->tag_pattern); if (strncmp(curtag->tag_pattern, line, len) == 0 && (!curtag->tag_endline || line[len] == '\0' || line[len] == '\r')) { curtag->tag_linenum = find_linenum(linepos); break; } } return (linepos); } /******************************************************************************* * gtags */ /* * Find tags in the GLOBAL's tag file. * The findgtag() will try and load information about the requested tag. * It does this by calling "global -x tag" and storing the parsed output * for future use by gtagsearch(). * Sets curtag to the first tag entry. */ static enum tag_result -findgtag(tag, type) - char *tag; /* tag to load */ - int type; /* tags type */ +findgtag(char *tag, int type) { char buf[256]; FILE *fp; struct tag *tp; if (type != T_CTAGS_X && tag == NULL) return TAG_NOFILE; cleantags(); total = 0; /* * If type == T_CTAGS_X then read ctags's -x format from stdin * else execute global(1) and read from it. */ if (type == T_CTAGS_X) { fp = stdin; /* Set tag default because we cannot read stdin again. */ tags = ztags; } else { #if !HAVE_POPEN return TAG_NOFILE; #else char *command; char *flag; char *qtag; char *cmd = lgetenv("LESSGLOBALTAGS"); if (cmd == NULL || *cmd == '\0') return TAG_NOFILE; /* Get suitable flag value for global(1). */ switch (type) { case T_GTAGS: flag = "" ; break; case T_GRTAGS: flag = "r"; break; case T_GSYMS: flag = "s"; break; case T_GPATH: flag = "P"; break; default: return TAG_NOTYPE; } /* Get our data from global(1). */ qtag = shell_quote(tag); if (qtag == NULL) qtag = tag; command = (char *) ecalloc(strlen(cmd) + strlen(flag) + strlen(qtag) + 5, sizeof(char)); sprintf(command, "%s -x%s %s", cmd, flag, qtag); if (qtag != tag) free(qtag); fp = popen(command, "r"); free(command); #endif } if (fp != NULL) { while (fgets(buf, sizeof(buf), fp)) { char *name, *file, *line; int len; if (sigs) { #if HAVE_POPEN if (fp != stdin) pclose(fp); #endif return TAG_INTR; } len = (int) strlen(buf); if (len > 0 && buf[len-1] == '\n') buf[len-1] = '\0'; else { int c; do { c = fgetc(fp); } while (c != '\n' && c != EOF); } if (getentry(buf, &name, &file, &line)) { /* * Couldn't parse this line for some reason. * We'll just pretend it never happened. */ break; } /* Make new entry and add to list. */ tp = maketagent(name, file, (LINENUM) atoi(line), NULL, 0); TAG_INS(tp); total++; } if (fp != stdin) { if (pclose(fp)) { curtag = NULL; total = curseq = 0; return TAG_NOFILE; } } } /* Check to see if we found anything. */ tp = taglist.tl_first; if (tp == TAG_END) return TAG_NOTAG; curtag = tp; curseq = 1; return TAG_FOUND; } static int circular = 0; /* 1: circular tag structure */ /* * Return the filename required for the next gtag in the queue that was setup * by findgtag(). The next call to gtagsearch() will try to position at the * appropriate tag. */ static char * -nextgtag() +nextgtag(void) { struct tag *tp; if (curtag == NULL) /* No tag loaded */ return NULL; tp = curtag->next; if (tp == TAG_END) { if (!circular) return NULL; /* Wrapped around to the head of the queue */ curtag = taglist.tl_first; curseq = 1; } else { curtag = tp; curseq++; } return (curtag->tag_file); } /* * Return the filename required for the previous gtag in the queue that was * setup by findgtat(). The next call to gtagsearch() will try to position * at the appropriate tag. */ static char * -prevgtag() +prevgtag(void) { struct tag *tp; if (curtag == NULL) /* No tag loaded */ return NULL; tp = curtag->prev; if (tp == TAG_END) { if (!circular) return NULL; /* Wrapped around to the tail of the queue */ curtag = taglist.tl_last; curseq = total; } else { curtag = tp; curseq--; } return (curtag->tag_file); } /* * Position the current file at at what is hopefully the tag that was chosen * using either findtag() or one of nextgtag() and prevgtag(). Returns -1 * if it was unable to position at the tag, 0 if successful. */ static POSITION -gtagsearch() +gtagsearch(void) { if (curtag == NULL) return (NULL_POSITION); /* No gtags loaded! */ return (find_pos(curtag->tag_linenum)); } /* * The getentry() parses both standard and extended ctags -x format. * * [standard format] * * +------------------------------------------------ * |main 30 main.c main(argc, argv) * |func 21 subr.c func(arg) * * The following commands write this format. * o Traditinal Ctags with -x option * o Global with -x option * See * * [extended format] * * +---------------------------------------------------------- * |main function 30 main.c main(argc, argv) * |func function 21 subr.c func(arg) * * The following commands write this format. * o Exuberant Ctags with -x option * See * * Returns 0 on success, -1 on error. * The tag, file, and line will each be NUL-terminated pointers * into buf. */ static int -getentry(buf, tag, file, line) - char *buf; /* standard or extended ctags -x format data */ - char **tag; /* name of the tag we actually found */ - char **file; /* file in which to find this tag */ - char **line; /* line number of file where this tag is found */ +getentry(char *buf, char **tag, char **file, char **line) { char *p = buf; for (*tag = p; *p && !IS_SPACE(*p); p++) /* tag name */ ; if (*p == 0) return (-1); *p++ = 0; for ( ; *p && IS_SPACE(*p); p++) /* (skip blanks) */ ; if (*p == 0) return (-1); /* * If the second part begin with other than digit, * it is assumed tag type. Skip it. */ if (!IS_DIGIT(*p)) { for ( ; *p && !IS_SPACE(*p); p++) /* (skip tag type) */ ; for (; *p && IS_SPACE(*p); p++) /* (skip blanks) */ ; } if (!IS_DIGIT(*p)) return (-1); *line = p; /* line number */ for (*line = p; *p && !IS_SPACE(*p); p++) ; if (*p == 0) return (-1); *p++ = 0; for ( ; *p && IS_SPACE(*p); p++) /* (skip blanks) */ ; if (*p == 0) return (-1); *file = p; /* file name */ for (*file = p; *p && !IS_SPACE(*p); p++) ; if (*p == 0) return (-1); *p = 0; /* value check */ if (strlen(*tag) && strlen(*line) && strlen(*file) && atoi(*line) > 0) return (0); return (-1); } #endif Index: head/contrib/less/ttyin.c =================================================================== --- head/contrib/less/ttyin.c (revision 316338) +++ head/contrib/less/ttyin.c (revision 316339) @@ -1,177 +1,177 @@ /* * Copyright (C) 1984-2015 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, see the README file. */ /* * Routines dealing with getting input from the keyboard (i.e. from the user). */ #include "less.h" #if OS2 #include "cmd.h" #include "pckeys.h" #endif #if MSDOS_COMPILER==WIN32C #include "windows.h" extern char WIN32getch(); static DWORD console_mode; #endif public int tty; extern int sigs; extern int utf_mode; /* * Open keyboard for input. */ public void -open_getchr() +open_getchr(void) { #if MSDOS_COMPILER==WIN32C /* Need this to let child processes inherit our console handle */ SECURITY_ATTRIBUTES sa; memset(&sa, 0, sizeof(SECURITY_ATTRIBUTES)); sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle = TRUE; tty = (int) CreateFile("CONIN$", GENERIC_READ, FILE_SHARE_READ, &sa, OPEN_EXISTING, 0L, NULL); GetConsoleMode((HANDLE)tty, &console_mode); /* Make sure we get Ctrl+C events. */ SetConsoleMode((HANDLE)tty, ENABLE_PROCESSED_INPUT); #else #if MSDOS_COMPILER extern int fd0; /* * Open a new handle to CON: in binary mode * for unbuffered keyboard read. */ fd0 = dup(0); close(0); tty = open("CON", OPEN_READ); #if MSDOS_COMPILER==DJGPPC /* * Setting stdin to binary causes Ctrl-C to not * raise SIGINT. We must undo that side-effect. */ (void) __djgpp_set_ctrl_c(1); #endif #else /* * Try /dev/tty. * If that doesn't work, use file descriptor 2, * which in Unix is usually attached to the screen, * but also usually lets you read from the keyboard. */ #if OS2 /* The __open() system call translates "/dev/tty" to "con". */ tty = __open("/dev/tty", OPEN_READ); #else tty = open("/dev/tty", OPEN_READ); #endif if (tty < 0) tty = 2; #endif #endif } /* * Close the keyboard. */ public void -close_getchr() +close_getchr(void) { #if MSDOS_COMPILER==WIN32C SetConsoleMode((HANDLE)tty, console_mode); CloseHandle((HANDLE)tty); #endif } /* * Get a character from the keyboard. */ public int -getchr() +getchr(void) { char c; int result; do { #if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC /* * In raw read, we don't see ^C so look here for it. */ flush(); #if MSDOS_COMPILER==WIN32C if (ABORT_SIGS()) return (READ_INTR); c = WIN32getch(tty); #else c = getch(); #endif result = 1; if (c == '\003') return (READ_INTR); #else result = iread(tty, &c, sizeof(char)); if (result == READ_INTR) return (READ_INTR); if (result < 0) { /* * Don't call error() here, * because error calls getchr! */ quit(QUIT_ERROR); } #endif #if 0 /* allow entering arbitrary hex chars for testing */ /* ctrl-A followed by two hex chars makes a byte */ { int hex_in = 0; int hex_value = 0; if (c == CONTROL('A')) { hex_in = 2; result = 0; continue; } if (hex_in > 0) { int v; if (c >= '0' && c <= '9') v = c - '0'; else if (c >= 'a' && c <= 'f') v = c - 'a' + 10; else if (c >= 'A' && c <= 'F') v = c - 'A' + 10; else hex_in = 0; hex_value = (hex_value << 4) | v; if (--hex_in > 0) { result = 0; continue; } c = hex_value; } } #endif /* * Various parts of the program cannot handle * an input character of '\0'. * If a '\0' was actually typed, convert it to '\340' here. */ if (c == '\0') c = '\340'; } while (result != 1); return (c & 0xFF); }