Add less 643

This commit is contained in:
Justine Tunney 2023-12-10 08:01:37 -08:00
parent 0ed7309fdb
commit 128be2bd2e
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
61 changed files with 33791 additions and 2853 deletions

View file

@ -226,6 +226,7 @@ include third_party/mbedtls/BUILD.mk # │
include third_party/ncurses/BUILD.mk # │
include third_party/libcxx/BUILD.mk # │
include third_party/pcre/BUILD.mk # │
include third_party/less/BUILD.mk # │
include net/https/BUILD.mk # │
include third_party/regex/BUILD.mk #─┘
include third_party/tidy/BUILD.mk

View file

@ -14,6 +14,7 @@ o/$(MODE)/third_party: \
o/$(MODE)/third_party/gdtoa \
o/$(MODE)/third_party/getopt \
o/$(MODE)/third_party/hiredis \
o/$(MODE)/third_party/less \
o/$(MODE)/third_party/libcxx \
o/$(MODE)/third_party/linenoise \
o/$(MODE)/third_party/lua \

86
third_party/less/BUILD.mk vendored Normal file
View file

@ -0,0 +1,86 @@
#-*-mode:lessfile-gless;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=less ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
PKGS += THIRD_PARTY_LESS
THIRD_PARTY_LESS_A = o/$(MODE)/third_party/less/less.a
THIRD_PARTY_LESS_FILES := $(wildcard third_party/less/*)
THIRD_PARTY_LESS_HDRS = $(filter %.h,$(THIRD_PARTY_LESS_FILES))
THIRD_PARTY_LESS_INCS = $(filter %.inc,$(THIRD_PARTY_LESS_FILES))
THIRD_PARTY_LESS_SRCS = $(filter %.c,$(THIRD_PARTY_LESS_FILES))
THIRD_PARTY_LESS_OBJS = $(THIRD_PARTY_LESS_SRCS:%.c=o/$(MODE)/%.o)
THIRD_PARTY_LESS_COMS = o/$(MODE)/third_party/less/less.com
THIRD_PARTY_LESS_CHECKS = $(THIRD_PARTY_LESS_A).pkg
THIRD_PARTY_LESS_BINS = \
$(THIRD_PARTY_LESS_COMS) \
$(THIRD_PARTY_LESS_COMS:%=%.dbg)
THIRD_PARTY_LESS_DIRECTDEPS = \
LIBC_CALLS \
LIBC_FMT \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_PROC \
LIBC_RUNTIME \
LIBC_STDIO \
LIBC_STR \
LIBC_SYSV \
THIRD_PARTY_NCURSES \
THIRD_PARTY_PCRE
THIRD_PARTY_LESS_DEPS := \
$(call uniq,$(foreach x,$(THIRD_PARTY_LESS_DIRECTDEPS),$($(x))))
$(THIRD_PARTY_LESS_A).pkg: \
$(THIRD_PARTY_LESS_OBJS) \
$(foreach x,$(THIRD_PARTY_LESS_DIRECTDEPS),$($(x)_A).pkg)
$(THIRD_PARTY_LESS_A): \
third_party/less/ \
$(THIRD_PARTY_LESS_A).pkg \
$(filter-out %main.o,$(THIRD_PARTY_LESS_OBJS))
o/$(MODE)/third_party/less/less.com.dbg: \
$(THIRD_PARTY_LESS_DEPS) \
$(THIRD_PARTY_LESS_A) \
$(THIRD_PARTY_LESS_A).pkg \
o/$(MODE)/third_party/less/main.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/less/lesskey.com.dbg: \
$(THIRD_PARTY_LESS_DEPS) \
$(THIRD_PARTY_LESS_A) \
$(THIRD_PARTY_LESS_A).pkg \
o/$(MODE)/third_party/less/lesskey.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/less/lessecho.com.dbg: \
$(THIRD_PARTY_LESS_DEPS) \
$(THIRD_PARTY_LESS_A) \
$(THIRD_PARTY_LESS_A).pkg \
o/$(MODE)/third_party/less/lessecho.o \
$(CRT) \
$(APE_NO_MODIFY_SELF)
@$(APELINK)
o/$(MODE)/third_party/less/screen.o: private \
CFLAGS += \
-fportcosmo
$(THIRD_PARTY_LESS_OBJS): private \
CPPFLAGS += \
-DBINDIR=\"/opt/cosmos/bin\" \
-DSYSDIR=\"/opt/cosmos/etc\"
$(THIRD_PARTY_LESS_OBJS): third_party/less/BUILD.mk
.PHONY: o/$(MODE)/third_party/less
o/$(MODE)/third_party/less: \
$(THIRD_PARTY_LESS_BINS) \
$(THIRD_PARTY_LESS_CHECKS)

27
third_party/less/LICENSE vendored Normal file
View file

@ -0,0 +1,27 @@
Less License
------------
Less
Copyright (C) 1984-2023 Mark Nudelman
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice in the documentation and/or other materials provided with
the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

15
third_party/less/README.cosmo vendored Normal file
View file

@ -0,0 +1,15 @@
DESCRIPTION
less is a text paginator for the terminal
LICENSE
BSD-2 license
ORIGIN
https://ftp.gnu.org/gnu/less/less-643.tar.gz
LOCAL CHANGES
None.

99
third_party/less/brac.c vendored Normal file
View file

@ -0,0 +1,99 @@
/*
* Copyright (C) 1984-2023 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(char obrac, char cbrac, int forwdir, int n)
{
int c;
int nest;
POSITION pos;
int (*chget)();
extern int ch_forw_get(), ch_back_get();
/*
* 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)
{
if (nest == INT_MAX)
break;
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);
}

939
third_party/less/ch.c vendored Normal file
View file

@ -0,0 +1,939 @@
/*
* Copyright (C) 1984-2023 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 <errno.h>
/* #include <windows.h> */
#endif
#if HAVE_PROCFS
#include <sys/statfs.h>
#if HAVE_LINUX_MAGIC_H
#include <linux/magic.h>
#endif
#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 int waiting_for_data;
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.
*/
static int ch_get(void)
{
struct buf *bp;
struct bufnode *bn;
int n;
int read_again;
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];
}
/*
* Look for a buffer holding the desired block.
*/
waiting_for_data = FALSE;
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. */
}
for (;;)
{
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));
}
read_again = FALSE;
if (n == READ_INTR)
{
ch_fsize = pos;
return (EOI);
}
if (n == READ_AGAIN)
{
read_again = TRUE;
n = 0;
}
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 (n == 0)
{
/* Either end of file or no data available.
* read_again indicates the latter. */
if (!read_again)
ch_fsize = pos;
if (ignore_eoi || read_again)
{
/* Wait a while, then try again. */
if (!waiting_for_data)
{
PARG parg;
parg.p_string = wait_message();
ixerror("%s", &parg);
waiting_for_data = TRUE;
}
sleep_ms(50); /* Reduce system load */
}
if (ignore_eoi && follow_mode == FOLLOW_NAME && curr_ifile_changed())
{
/* screen_trashed=2 causes make_display to reopen the file. */
screen_trashed = 2;
return (EOI);
}
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)
break;
/*
* After all that, we still don't have enough data.
* Go back and try again.
*/
}
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(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(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;
free(namelogfile);
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(void)
{
struct buf *bp;
struct bufnode *bn;
int warned = FALSE;
BLOCKNUM block;
BLOCKNUM nblocks;
if (logfile < 0)
return;
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(BLOCKNUM block)
{
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(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(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(void)
{
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(void)
{
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(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(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(void)
{
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(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(int bufspace)
{
if (bufspace < 0)
maxbufs = -1;
else
{
int lbufk = LBUFSIZE / 1024;
maxbufs = bufspace / lbufk + (bufspace % lbufk != 0);
if (maxbufs < 1)
maxbufs = 1;
}
}
/*
* Flush (discard) any saved file state, including buffer contents.
*/
public void ch_flush(void)
{
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 HAVE_PROCFS
/*
* 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)
{
struct statfs st;
if (fstatfs(ch_file, &st) == 0)
{
if (st.f_type == PROC_SUPER_MAGIC)
{
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(void)
{
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(void)
{
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(void)
{
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(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(void)
{
if (ch_fsize != NULL_POSITION && ch_fsize < ch_fpos)
ch_fsize = ch_fpos;
}
/*
* Initialize file state for a new file.
*/
public void 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 *)
ecalloc(1, sizeof(struct filestate));
thisfile->buflist.next = thisfile->buflist.prev = END_OF_CHAIN;
thisfile->nbufs = 0;
thisfile->flags = flags;
thisfile->fpos = 0;
thisfile->block = 0;
thisfile->offset = 0;
thisfile->file = -1;
thisfile->fsize = NULL_POSITION;
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(void)
{
int keepstate = FALSE;
if (thisfile == NULL)
return;
if ((ch_flags & (CH_CANSEEK|CH_POPENED|CH_HELPFILE)) && !(ch_flags & CH_KEEPOPEN))
{
/*
* 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(void)
{
if (thisfile == NULL)
return (0);
return (ch_flags);
}
#if 0
static 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

905
third_party/less/charset.c vendored Normal file
View file

@ -0,0 +1,905 @@
/*
* Copyright (C) 1984-2023 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 <locale.h>
#include <ctype.h>
#include <langinfo.h>
#endif
#include "charset.h"
#include "xbuf.h"
#if MSDOS_COMPILER==WIN32C
#define WIN32_LEAN_AND_MEAN
/* #include <windows.h> */
#endif
extern int bs_mode;
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" },
{ "utf8", "utf-8" },
{ "UTF8", "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|AT_COLOR_BIN;
static struct xbuffer user_wide_array;
static struct xbuffer user_ubin_array;
static struct xbuffer user_compose_array;
static struct xbuffer user_prt_array;
static struct wchar_range_table user_wide_table;
static struct wchar_range_table user_ubin_table;
static struct wchar_range_table user_compose_table;
static struct wchar_range_table user_prt_table;
/*
* Set a wchar_range_table to the table in an xbuffer.
*/
static void wchar_range_table_set(struct wchar_range_table *tbl, struct xbuffer *arr)
{
tbl->table = (struct wchar_range *) arr->data;
tbl->count = arr->end / sizeof(struct wchar_range);
}
/*
* Skip over a "U" or "U+" prefix before a hex codepoint.
*/
static char * skip_uprefix(char *s)
{
if (*s == 'U' || *s == 'u')
if (*++s == '+') ++s;
return s;
}
/*
* Parse a dash-separated range of hex values.
*/
static void wchar_range_get(char **ss, struct wchar_range *range)
{
char *s = skip_uprefix(*ss);
range->first = lstrtoul(s, &s, 16);
if (s[0] == '-')
{
s = skip_uprefix(&s[1]);
range->last = lstrtoul(s, &s, 16);
} else
{
range->last = range->first;
}
*ss = s;
}
/*
* Parse the LESSUTFCHARDEF variable.
*/
static void ichardef_utf(char *s)
{
xbuf_init(&user_wide_array);
xbuf_init(&user_ubin_array);
xbuf_init(&user_compose_array);
xbuf_init(&user_prt_array);
if (s != NULL)
{
while (s[0] != '\0')
{
struct wchar_range range;
wchar_range_get(&s, &range);
if (range.last == 0)
{
error("invalid hex number(s) in LESSUTFCHARDEF", NULL_PARG);
quit(QUIT_ERROR);
}
if (*s++ != ':')
{
error("missing colon in LESSUTFCHARDEF", NULL_PARG);
quit(QUIT_ERROR);
}
switch (*s++)
{
case 'b':
xbuf_add_data(&user_ubin_array, (unsigned char *) &range, sizeof(range));
break;
case 'c':
xbuf_add_data(&user_compose_array, (unsigned char *) &range, sizeof(range));
break;
case 'w':
xbuf_add_data(&user_wide_array, (unsigned char *) &range, sizeof(range));
xbuf_add_data(&user_prt_array, (unsigned char *) &range, sizeof(range));
break;
case 'p': case '.':
xbuf_add_data(&user_prt_array, (unsigned char *) &range, sizeof(range));
break;
case '\0':
s--;
break;
default:
/* Ignore unknown character attribute. */
break;
}
if (s[0] == ',') ++s;
}
}
wchar_range_table_set(&user_wide_table, &user_wide_array);
wchar_range_table_set(&user_ubin_table, &user_ubin_array);
wchar_range_table_set(&user_compose_table, &user_compose_array);
wchar_range_table_set(&user_prt_table, &user_prt_array);
}
/*
* 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(char *s)
{
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':
if (ckd_mul(&n, n, 10) || ckd_add(&n, n, s[-1] - '0'))
goto invalid_chardef;
continue;
default:
invalid_chardef:
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(char *name, int no_error)
{
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)
{
#if MSDOS_COMPILER==WIN32C
*(p->p_flag) = 1 + (GetConsoleOutputCP() != CP_UTF8);
#else
*(p->p_flag) = 1;
#endif
}
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(void)
{
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.
*/
public void setfmt(char *s, char **fmtvarptr, int *attrptr, char *default_fmt, int for_printf)
{
if (s && utf_mode)
{
/* It would be too hard to account for width otherwise. */
char constant *t = s;
while (*t)
{
if (*t < ' ' || *t > '~')
{
s = default_fmt;
goto attr;
}
t++;
}
}
if (s == NULL || *s == '\0')
s = default_fmt;
else if (for_printf &&
((*s == '*' && (s[1] == '\0' || s[2] == '\0' || strchr(s + 2, 'n'))) ||
(*s != '*' && strchr(s, 'n'))))
/* %n is evil */
s = default_fmt;
/*
* Select the attributes if it starts with "*".
*/
attr:
if (*s == '*' && s[1] != '\0')
{
switch (s[1])
{
case 'd': *attrptr = AT_BOLD; break;
case 'k': *attrptr = AT_BLINK; break;
case 's': *attrptr = AT_STANDOUT; break;
case 'u': *attrptr = AT_UNDERLINE; break;
default: *attrptr = AT_NORMAL; break;
}
s += 2;
}
*fmtvarptr = s;
}
/*
*
*/
static void set_charset(void)
{
char *s;
#if MSDOS_COMPILER==WIN32C
/*
* If the Windows console is using UTF-8, we'll use it too.
*/
if (GetConsoleOutputCP() == CP_UTF8)
if (icharset("utf-8", 1))
return;
#endif
ichardef_utf(lgetenv("LESSUTFCHARDEF"));
/*
* 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 (!isnullenv(s))
{
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();
#else
#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(void)
{
char *s;
#if HAVE_LOCALE
setlocale(LC_ALL, "");
#endif
set_charset();
s = lgetenv("LESSBINFMT");
setfmt(s, &binfmt, &binattr, "*s<%02X>", TRUE);
s = lgetenv("LESSUTFBINFMT");
setfmt(s, &utfbinfmt, &binattr, "<U+%04lX>", TRUE);
}
/*
* Is a given character a "binary" character?
*/
public int 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(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(LWCHAR c)
{
/* {{ This buffer can be overrun if LESSBINFMT is a long string. }} */
static char buf[MAX_PRCHAR_LEN+1];
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(LWCHAR ch)
{
static char buf[MAX_PRCHAR_LEN+1];
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(int 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(char *ss, int slen)
{
int i;
int len;
unsigned char *s = (unsigned char *) ss;
if (IS_UTF8_INVALID(s[0]))
return (0);
len = utf_len(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);
}
/*
* Skip bytes until a UTF-8 lead byte (11xxxxxx) or ASCII byte (0xxxxxxx) is found.
*/
public void utf_skip_to_lead(char **pp, char *limit)
{
do {
++(*pp);
} while (*pp < limit && !IS_UTF8_LEAD((*pp)[0] & 0377) && !IS_ASCII_OCTET((*pp)[0]));
}
/*
* Get the value of a UTF-8 character.
*/
public LWCHAR 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(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(char **pp, signed int dir, constant char *limit)
{
LWCHAR ch;
int len;
char *p = *pp;
if (!utf_mode)
{
/* It's easy if chars are one byte. */
if (dir > 0)
ch = (LWCHAR) (unsigned char) ((p < limit) ? *p++ : 0);
else
ch = (LWCHAR) (unsigned char) ((p > limit) ? *--p : 0);
} else if (dir > 0)
{
len = utf_len(*p);
if (p + len > limit)
{
ch = 0;
p = (char *) 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.inc"
DECLARE_RANGE_TABLE_END(compose)
DECLARE_RANGE_TABLE_START(ubin)
#include "ubin.inc"
DECLARE_RANGE_TABLE_END(ubin)
DECLARE_RANGE_TABLE_START(wide)
#include "wide.inc"
DECLARE_RANGE_TABLE_END(wide)
DECLARE_RANGE_TABLE_START(fmt)
#include "fmt.inc"
DECLARE_RANGE_TABLE_END(fmt)
/* 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(LWCHAR ch, struct wchar_range_table *table)
{
int hi;
int lo;
/* Binary search in the table. */
if (table->table == NULL || table->count == 0 || 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(LWCHAR ch)
{
if (is_in_table(ch, &user_prt_table)) return 0;
return is_in_table(ch, &user_compose_table) ||
is_in_table(ch, &compose_table) ||
(bs_mode != BS_CONTROL && is_in_table(ch, &fmt_table));
}
/*
* Should this UTF-8 character be treated as binary?
*/
public int is_ubin_char(LWCHAR ch)
{
if (is_in_table(ch, &user_prt_table)) return 0;
return is_in_table(ch, &user_ubin_table) ||
is_in_table(ch, &ubin_table) ||
(bs_mode == BS_CONTROL && is_in_table(ch, &fmt_table));
}
/*
* Is this a double width UTF-8 character?
*/
public int is_wide_char(LWCHAR ch)
{
return is_in_table(ch, &user_wide_table) ||
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(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;
}

18
third_party/less/charset.h vendored Normal file
View file

@ -0,0 +1,18 @@
/*
* Copyright (C) 1984-2023 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 IS_ASCII_OCTET(c) (((c) & 0x80) == 0)
#define IS_UTF8_TRAIL(c) (((c) & 0xC0) == 0x80)
#define IS_UTF8_LEAD2(c) (((c) & 0xE0) == 0xC0)
#define IS_UTF8_LEAD3(c) (((c) & 0xF0) == 0xE0)
#define IS_UTF8_LEAD4(c) (((c) & 0xF8) == 0xF0)
#define IS_UTF8_LEAD5(c) (((c) & 0xFC) == 0xF8)
#define IS_UTF8_LEAD6(c) (((c) & 0xFE) == 0xFC)
#define IS_UTF8_INVALID(c) (((c) & 0xFE) == 0xFE)
#define IS_UTF8_LEAD(c) (((c) & 0xC0) == 0xC0 && !IS_UTF8_INVALID(c))

147
third_party/less/cmd.h vendored Normal file
View file

@ -0,0 +1,147 @@
/*
* Copyright (C) 1984-2023 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 MAX_USERCMD 1000
#define MAX_CMDLEN 16
#define A_B_LINE 2
#define A_B_SCREEN 3
#define A_B_SCROLL 4
#define A_B_SEARCH 5
#define A_DIGIT 6
#define A_DISP_OPTION 7
#define A_DEBUG 8
#define A_EXAMINE 9
#define A_FIRSTCMD 10
#define A_FREPAINT 11
#define A_F_LINE 12
#define A_F_SCREEN 13
#define A_F_SCROLL 14
#define A_F_SEARCH 15
#define A_GOEND 16
#define A_GOLINE 17
#define A_GOMARK 18
#define A_HELP 19
#define A_NEXT_FILE 20
#define A_PERCENT 21
#define A_PREV_FILE 23
#define A_QUIT 24
#define A_REPAINT 25
#define A_SETMARK 26
#define A_SHELL 27
#define A_STAT 28
#define A_FF_LINE 29
#define A_BF_LINE 30
#define A_VERSION 31
#define A_VISUAL 32
#define A_F_WINDOW 33
#define A_B_WINDOW 34
#define A_F_BRACKET 35
#define A_B_BRACKET 36
#define A_PIPE 37
#define A_INDEX_FILE 38
#define A_UNDO_SEARCH 39
#define A_FF_SCREEN 40
#define A_LSHIFT 41
#define A_RSHIFT 42
#define A_AGAIN_SEARCH 43
#define A_T_AGAIN_SEARCH 44
#define A_REVERSE_SEARCH 45
#define A_T_REVERSE_SEARCH 46
#define A_OPT_TOGGLE 47
#define A_OPT_SET 48
#define A_OPT_UNSET 49
#define A_F_FOREVER 50
#define A_GOPOS 51
#define A_REMOVE_FILE 52
#define A_NEXT_TAG 53
#define A_PREV_TAG 54
#define A_FILTER 55
#define A_F_UNTIL_HILITE 56
#define A_GOEND_BUF 57
#define A_LLSHIFT 58
#define A_RRSHIFT 59
#define A_CLRMARK 62
#define A_SETMARKBOT 63
#define A_X11MOUSE_IN 64
#define A_F_MOUSE 66
#define A_B_MOUSE 67
/* Note "X116" refers to extended (1006) X11 mouse reporting. */
#define A_X116MOUSE_IN 68
#define A_PSHELL 69
#define A_CLR_SEARCH 70
/* These values must not conflict with any A_* or EC_* value. */
#define A_INVALID 100
#define A_NOACTION 101
#define A_UINVALID 102
#define A_END_LIST 103
#define A_SPECIAL_KEY 104
#define A_PREFIX 105
#define A_SKIP 127
#define A_EXTRA 0200
/* Line editing characters */
#define EC_BACKSPACE 1
#define EC_LINEKILL 2
#define EC_RIGHT 3
#define EC_LEFT 4
#define EC_W_LEFT 5
#define EC_W_RIGHT 6
#define EC_INSERT 7
#define EC_DELETE 8
#define EC_HOME 9
#define EC_END 10
#define EC_W_BACKSPACE 11
#define EC_W_DELETE 12
#define EC_UP 13
#define EC_DOWN 14
#define EC_EXPAND 15
#define EC_F_COMPLETE 17
#define EC_B_COMPLETE 18
#define EC_LITERAL 19
#define EC_ABORT 20
#define EC_X11MOUSE 21
#define EC_X116MOUSE 22
#define EC_UINVALID 102
/* Flags for editchar() */
#define ECF_PEEK 01
#define ECF_NOHISTORY 02
#define ECF_NOCOMPLETE 04
#define ECF_NORIGHTLEFT 010
/* Environment variable stuff */
#define EV_OK 01
/* Special keys (keys which output different strings on different terminals) */
#define SK_SPECIAL_KEY CONTROL('K')
#define SK_RIGHT_ARROW 1
#define SK_LEFT_ARROW 2
#define SK_UP_ARROW 3
#define SK_DOWN_ARROW 4
#define SK_PAGE_UP 5
#define SK_PAGE_DOWN 6
#define SK_HOME 7
#define SK_END 8
#define SK_DELETE 9
#define SK_INSERT 10
#define SK_CTL_LEFT_ARROW 11
#define SK_CTL_RIGHT_ARROW 12
#define SK_CTL_DELETE 13
#define SK_F1 14
#define SK_BACKTAB 15
#define SK_CTL_BACKSPACE 16
#define SK_BACKSPACE 17
#define SK_CONTROL_K 40

1677
third_party/less/cmdbuf.c vendored Normal file

File diff suppressed because it is too large Load diff

2090
third_party/less/command.c vendored Normal file

File diff suppressed because it is too large Load diff

355
third_party/less/compose.inc vendored Normal file
View file

@ -0,0 +1,355 @@
/* Generated by "./mkutable -f2 Mn Me -- unicode/UnicodeData.txt" on Mon Nov 14 18:19:23 PST 2022 */
{ 0x0300, 0x036f }, /* Mn */
{ 0x0483, 0x0487 }, /* Mn */
{ 0x0488, 0x0489 }, /* Me */
{ 0x0591, 0x05bd }, /* Mn */
{ 0x05bf, 0x05bf }, /* Mn */
{ 0x05c1, 0x05c2 }, /* Mn */
{ 0x05c4, 0x05c5 }, /* Mn */
{ 0x05c7, 0x05c7 }, /* Mn */
{ 0x0610, 0x061a }, /* Mn */
{ 0x064b, 0x065f }, /* Mn */
{ 0x0670, 0x0670 }, /* Mn */
{ 0x06d6, 0x06dc }, /* Mn */
{ 0x06df, 0x06e4 }, /* Mn */
{ 0x06e7, 0x06e8 }, /* Mn */
{ 0x06ea, 0x06ed }, /* Mn */
{ 0x0711, 0x0711 }, /* Mn */
{ 0x0730, 0x074a }, /* Mn */
{ 0x07a6, 0x07b0 }, /* Mn */
{ 0x07eb, 0x07f3 }, /* Mn */
{ 0x07fd, 0x07fd }, /* Mn */
{ 0x0816, 0x0819 }, /* Mn */
{ 0x081b, 0x0823 }, /* Mn */
{ 0x0825, 0x0827 }, /* Mn */
{ 0x0829, 0x082d }, /* Mn */
{ 0x0859, 0x085b }, /* Mn */
{ 0x0898, 0x089f }, /* Mn */
{ 0x08ca, 0x08e1 }, /* Mn */
{ 0x08e3, 0x0902 }, /* Mn */
{ 0x093a, 0x093a }, /* Mn */
{ 0x093c, 0x093c }, /* Mn */
{ 0x0941, 0x0948 }, /* Mn */
{ 0x094d, 0x094d }, /* Mn */
{ 0x0951, 0x0957 }, /* Mn */
{ 0x0962, 0x0963 }, /* Mn */
{ 0x0981, 0x0981 }, /* Mn */
{ 0x09bc, 0x09bc }, /* Mn */
{ 0x09c1, 0x09c4 }, /* Mn */
{ 0x09cd, 0x09cd }, /* Mn */
{ 0x09e2, 0x09e3 }, /* Mn */
{ 0x09fe, 0x09fe }, /* Mn */
{ 0x0a01, 0x0a02 }, /* Mn */
{ 0x0a3c, 0x0a3c }, /* Mn */
{ 0x0a41, 0x0a42 }, /* Mn */
{ 0x0a47, 0x0a48 }, /* Mn */
{ 0x0a4b, 0x0a4d }, /* Mn */
{ 0x0a51, 0x0a51 }, /* Mn */
{ 0x0a70, 0x0a71 }, /* Mn */
{ 0x0a75, 0x0a75 }, /* Mn */
{ 0x0a81, 0x0a82 }, /* Mn */
{ 0x0abc, 0x0abc }, /* Mn */
{ 0x0ac1, 0x0ac5 }, /* Mn */
{ 0x0ac7, 0x0ac8 }, /* Mn */
{ 0x0acd, 0x0acd }, /* Mn */
{ 0x0ae2, 0x0ae3 }, /* Mn */
{ 0x0afa, 0x0aff }, /* Mn */
{ 0x0b01, 0x0b01 }, /* Mn */
{ 0x0b3c, 0x0b3c }, /* Mn */
{ 0x0b3f, 0x0b3f }, /* Mn */
{ 0x0b41, 0x0b44 }, /* Mn */
{ 0x0b4d, 0x0b4d }, /* Mn */
{ 0x0b55, 0x0b56 }, /* Mn */
{ 0x0b62, 0x0b63 }, /* Mn */
{ 0x0b82, 0x0b82 }, /* Mn */
{ 0x0bc0, 0x0bc0 }, /* Mn */
{ 0x0bcd, 0x0bcd }, /* Mn */
{ 0x0c00, 0x0c00 }, /* Mn */
{ 0x0c04, 0x0c04 }, /* Mn */
{ 0x0c3c, 0x0c3c }, /* Mn */
{ 0x0c3e, 0x0c40 }, /* Mn */
{ 0x0c46, 0x0c48 }, /* Mn */
{ 0x0c4a, 0x0c4d }, /* Mn */
{ 0x0c55, 0x0c56 }, /* Mn */
{ 0x0c62, 0x0c63 }, /* Mn */
{ 0x0c81, 0x0c81 }, /* Mn */
{ 0x0cbc, 0x0cbc }, /* Mn */
{ 0x0cbf, 0x0cbf }, /* Mn */
{ 0x0cc6, 0x0cc6 }, /* Mn */
{ 0x0ccc, 0x0ccd }, /* Mn */
{ 0x0ce2, 0x0ce3 }, /* Mn */
{ 0x0d00, 0x0d01 }, /* Mn */
{ 0x0d3b, 0x0d3c }, /* Mn */
{ 0x0d41, 0x0d44 }, /* Mn */
{ 0x0d4d, 0x0d4d }, /* Mn */
{ 0x0d62, 0x0d63 }, /* Mn */
{ 0x0d81, 0x0d81 }, /* Mn */
{ 0x0dca, 0x0dca }, /* Mn */
{ 0x0dd2, 0x0dd4 }, /* Mn */
{ 0x0dd6, 0x0dd6 }, /* Mn */
{ 0x0e31, 0x0e31 }, /* Mn */
{ 0x0e34, 0x0e3a }, /* Mn */
{ 0x0e47, 0x0e4e }, /* Mn */
{ 0x0eb1, 0x0eb1 }, /* Mn */
{ 0x0eb4, 0x0ebc }, /* Mn */
{ 0x0ec8, 0x0ece }, /* Mn */
{ 0x0f18, 0x0f19 }, /* Mn */
{ 0x0f35, 0x0f35 }, /* Mn */
{ 0x0f37, 0x0f37 }, /* Mn */
{ 0x0f39, 0x0f39 }, /* Mn */
{ 0x0f71, 0x0f7e }, /* Mn */
{ 0x0f80, 0x0f84 }, /* Mn */
{ 0x0f86, 0x0f87 }, /* Mn */
{ 0x0f8d, 0x0f97 }, /* Mn */
{ 0x0f99, 0x0fbc }, /* Mn */
{ 0x0fc6, 0x0fc6 }, /* Mn */
{ 0x102d, 0x1030 }, /* Mn */
{ 0x1032, 0x1037 }, /* Mn */
{ 0x1039, 0x103a }, /* Mn */
{ 0x103d, 0x103e }, /* Mn */
{ 0x1058, 0x1059 }, /* Mn */
{ 0x105e, 0x1060 }, /* Mn */
{ 0x1071, 0x1074 }, /* Mn */
{ 0x1082, 0x1082 }, /* Mn */
{ 0x1085, 0x1086 }, /* Mn */
{ 0x108d, 0x108d }, /* Mn */
{ 0x109d, 0x109d }, /* Mn */
{ 0x1160, 0x11ff }, /* Mn */
{ 0x135d, 0x135f }, /* Mn */
{ 0x1712, 0x1714 }, /* Mn */
{ 0x1732, 0x1733 }, /* Mn */
{ 0x1752, 0x1753 }, /* Mn */
{ 0x1772, 0x1773 }, /* Mn */
{ 0x17b4, 0x17b5 }, /* Mn */
{ 0x17b7, 0x17bd }, /* Mn */
{ 0x17c6, 0x17c6 }, /* Mn */
{ 0x17c9, 0x17d3 }, /* Mn */
{ 0x17dd, 0x17dd }, /* Mn */
{ 0x180b, 0x180d }, /* Mn */
{ 0x180f, 0x180f }, /* Mn */
{ 0x1885, 0x1886 }, /* Mn */
{ 0x18a9, 0x18a9 }, /* Mn */
{ 0x1920, 0x1922 }, /* Mn */
{ 0x1927, 0x1928 }, /* Mn */
{ 0x1932, 0x1932 }, /* Mn */
{ 0x1939, 0x193b }, /* Mn */
{ 0x1a17, 0x1a18 }, /* Mn */
{ 0x1a1b, 0x1a1b }, /* Mn */
{ 0x1a56, 0x1a56 }, /* Mn */
{ 0x1a58, 0x1a5e }, /* Mn */
{ 0x1a60, 0x1a60 }, /* Mn */
{ 0x1a62, 0x1a62 }, /* Mn */
{ 0x1a65, 0x1a6c }, /* Mn */
{ 0x1a73, 0x1a7c }, /* Mn */
{ 0x1a7f, 0x1a7f }, /* Mn */
{ 0x1ab0, 0x1abd }, /* Mn */
{ 0x1abe, 0x1abe }, /* Me */
{ 0x1abf, 0x1ace }, /* Mn */
{ 0x1b00, 0x1b03 }, /* Mn */
{ 0x1b34, 0x1b34 }, /* Mn */
{ 0x1b36, 0x1b3a }, /* Mn */
{ 0x1b3c, 0x1b3c }, /* Mn */
{ 0x1b42, 0x1b42 }, /* Mn */
{ 0x1b6b, 0x1b73 }, /* Mn */
{ 0x1b80, 0x1b81 }, /* Mn */
{ 0x1ba2, 0x1ba5 }, /* Mn */
{ 0x1ba8, 0x1ba9 }, /* Mn */
{ 0x1bab, 0x1bad }, /* Mn */
{ 0x1be6, 0x1be6 }, /* Mn */
{ 0x1be8, 0x1be9 }, /* Mn */
{ 0x1bed, 0x1bed }, /* Mn */
{ 0x1bef, 0x1bf1 }, /* Mn */
{ 0x1c2c, 0x1c33 }, /* Mn */
{ 0x1c36, 0x1c37 }, /* Mn */
{ 0x1cd0, 0x1cd2 }, /* Mn */
{ 0x1cd4, 0x1ce0 }, /* Mn */
{ 0x1ce2, 0x1ce8 }, /* Mn */
{ 0x1ced, 0x1ced }, /* Mn */
{ 0x1cf4, 0x1cf4 }, /* Mn */
{ 0x1cf8, 0x1cf9 }, /* Mn */
{ 0x1dc0, 0x1dff }, /* Mn */
{ 0x20d0, 0x20dc }, /* Mn */
{ 0x20dd, 0x20e0 }, /* Me */
{ 0x20e1, 0x20e1 }, /* Mn */
{ 0x20e2, 0x20e4 }, /* Me */
{ 0x20e5, 0x20f0 }, /* Mn */
{ 0x2cef, 0x2cf1 }, /* Mn */
{ 0x2d7f, 0x2d7f }, /* Mn */
{ 0x2de0, 0x2dff }, /* Mn */
{ 0x302a, 0x302d }, /* Mn */
{ 0x3099, 0x309a }, /* Mn */
{ 0xa66f, 0xa66f }, /* Mn */
{ 0xa670, 0xa672 }, /* Me */
{ 0xa674, 0xa67d }, /* Mn */
{ 0xa69e, 0xa69f }, /* Mn */
{ 0xa6f0, 0xa6f1 }, /* Mn */
{ 0xa802, 0xa802 }, /* Mn */
{ 0xa806, 0xa806 }, /* Mn */
{ 0xa80b, 0xa80b }, /* Mn */
{ 0xa825, 0xa826 }, /* Mn */
{ 0xa82c, 0xa82c }, /* Mn */
{ 0xa8c4, 0xa8c5 }, /* Mn */
{ 0xa8e0, 0xa8f1 }, /* Mn */
{ 0xa8ff, 0xa8ff }, /* Mn */
{ 0xa926, 0xa92d }, /* Mn */
{ 0xa947, 0xa951 }, /* Mn */
{ 0xa980, 0xa982 }, /* Mn */
{ 0xa9b3, 0xa9b3 }, /* Mn */
{ 0xa9b6, 0xa9b9 }, /* Mn */
{ 0xa9bc, 0xa9bd }, /* Mn */
{ 0xa9e5, 0xa9e5 }, /* Mn */
{ 0xaa29, 0xaa2e }, /* Mn */
{ 0xaa31, 0xaa32 }, /* Mn */
{ 0xaa35, 0xaa36 }, /* Mn */
{ 0xaa43, 0xaa43 }, /* Mn */
{ 0xaa4c, 0xaa4c }, /* Mn */
{ 0xaa7c, 0xaa7c }, /* Mn */
{ 0xaab0, 0xaab0 }, /* Mn */
{ 0xaab2, 0xaab4 }, /* Mn */
{ 0xaab7, 0xaab8 }, /* Mn */
{ 0xaabe, 0xaabf }, /* Mn */
{ 0xaac1, 0xaac1 }, /* Mn */
{ 0xaaec, 0xaaed }, /* Mn */
{ 0xaaf6, 0xaaf6 }, /* Mn */
{ 0xabe5, 0xabe5 }, /* Mn */
{ 0xabe8, 0xabe8 }, /* Mn */
{ 0xabed, 0xabed }, /* Mn */
{ 0xd7b0, 0xd7c6 }, /* Mn */
{ 0xd7cb, 0xd7fb }, /* Mn */
{ 0xfb1e, 0xfb1e }, /* Mn */
{ 0xfe00, 0xfe0f }, /* Mn */
{ 0xfe20, 0xfe2f }, /* Mn */
{ 0x101fd, 0x101fd }, /* Mn */
{ 0x102e0, 0x102e0 }, /* Mn */
{ 0x10376, 0x1037a }, /* Mn */
{ 0x10a01, 0x10a03 }, /* Mn */
{ 0x10a05, 0x10a06 }, /* Mn */
{ 0x10a0c, 0x10a0f }, /* Mn */
{ 0x10a38, 0x10a3a }, /* Mn */
{ 0x10a3f, 0x10a3f }, /* Mn */
{ 0x10ae5, 0x10ae6 }, /* Mn */
{ 0x10d24, 0x10d27 }, /* Mn */
{ 0x10eab, 0x10eac }, /* Mn */
{ 0x10efd, 0x10eff }, /* Mn */
{ 0x10f46, 0x10f50 }, /* Mn */
{ 0x10f82, 0x10f85 }, /* Mn */
{ 0x11001, 0x11001 }, /* Mn */
{ 0x11038, 0x11046 }, /* Mn */
{ 0x11070, 0x11070 }, /* Mn */
{ 0x11073, 0x11074 }, /* Mn */
{ 0x1107f, 0x11081 }, /* Mn */
{ 0x110b3, 0x110b6 }, /* Mn */
{ 0x110b9, 0x110ba }, /* Mn */
{ 0x110c2, 0x110c2 }, /* Mn */
{ 0x11100, 0x11102 }, /* Mn */
{ 0x11127, 0x1112b }, /* Mn */
{ 0x1112d, 0x11134 }, /* Mn */
{ 0x11173, 0x11173 }, /* Mn */
{ 0x11180, 0x11181 }, /* Mn */
{ 0x111b6, 0x111be }, /* Mn */
{ 0x111c9, 0x111cc }, /* Mn */
{ 0x111cf, 0x111cf }, /* Mn */
{ 0x1122f, 0x11231 }, /* Mn */
{ 0x11234, 0x11234 }, /* Mn */
{ 0x11236, 0x11237 }, /* Mn */
{ 0x1123e, 0x1123e }, /* Mn */
{ 0x11241, 0x11241 }, /* Mn */
{ 0x112df, 0x112df }, /* Mn */
{ 0x112e3, 0x112ea }, /* Mn */
{ 0x11300, 0x11301 }, /* Mn */
{ 0x1133b, 0x1133c }, /* Mn */
{ 0x11340, 0x11340 }, /* Mn */
{ 0x11366, 0x1136c }, /* Mn */
{ 0x11370, 0x11374 }, /* Mn */
{ 0x11438, 0x1143f }, /* Mn */
{ 0x11442, 0x11444 }, /* Mn */
{ 0x11446, 0x11446 }, /* Mn */
{ 0x1145e, 0x1145e }, /* Mn */
{ 0x114b3, 0x114b8 }, /* Mn */
{ 0x114ba, 0x114ba }, /* Mn */
{ 0x114bf, 0x114c0 }, /* Mn */
{ 0x114c2, 0x114c3 }, /* Mn */
{ 0x115b2, 0x115b5 }, /* Mn */
{ 0x115bc, 0x115bd }, /* Mn */
{ 0x115bf, 0x115c0 }, /* Mn */
{ 0x115dc, 0x115dd }, /* Mn */
{ 0x11633, 0x1163a }, /* Mn */
{ 0x1163d, 0x1163d }, /* Mn */
{ 0x1163f, 0x11640 }, /* Mn */
{ 0x116ab, 0x116ab }, /* Mn */
{ 0x116ad, 0x116ad }, /* Mn */
{ 0x116b0, 0x116b5 }, /* Mn */
{ 0x116b7, 0x116b7 }, /* Mn */
{ 0x1171d, 0x1171f }, /* Mn */
{ 0x11722, 0x11725 }, /* Mn */
{ 0x11727, 0x1172b }, /* Mn */
{ 0x1182f, 0x11837 }, /* Mn */
{ 0x11839, 0x1183a }, /* Mn */
{ 0x1193b, 0x1193c }, /* Mn */
{ 0x1193e, 0x1193e }, /* Mn */
{ 0x11943, 0x11943 }, /* Mn */
{ 0x119d4, 0x119d7 }, /* Mn */
{ 0x119da, 0x119db }, /* Mn */
{ 0x119e0, 0x119e0 }, /* Mn */
{ 0x11a01, 0x11a0a }, /* Mn */
{ 0x11a33, 0x11a38 }, /* Mn */
{ 0x11a3b, 0x11a3e }, /* Mn */
{ 0x11a47, 0x11a47 }, /* Mn */
{ 0x11a51, 0x11a56 }, /* Mn */
{ 0x11a59, 0x11a5b }, /* Mn */
{ 0x11a8a, 0x11a96 }, /* Mn */
{ 0x11a98, 0x11a99 }, /* Mn */
{ 0x11c30, 0x11c36 }, /* Mn */
{ 0x11c38, 0x11c3d }, /* Mn */
{ 0x11c3f, 0x11c3f }, /* Mn */
{ 0x11c92, 0x11ca7 }, /* Mn */
{ 0x11caa, 0x11cb0 }, /* Mn */
{ 0x11cb2, 0x11cb3 }, /* Mn */
{ 0x11cb5, 0x11cb6 }, /* Mn */
{ 0x11d31, 0x11d36 }, /* Mn */
{ 0x11d3a, 0x11d3a }, /* Mn */
{ 0x11d3c, 0x11d3d }, /* Mn */
{ 0x11d3f, 0x11d45 }, /* Mn */
{ 0x11d47, 0x11d47 }, /* Mn */
{ 0x11d90, 0x11d91 }, /* Mn */
{ 0x11d95, 0x11d95 }, /* Mn */
{ 0x11d97, 0x11d97 }, /* Mn */
{ 0x11ef3, 0x11ef4 }, /* Mn */
{ 0x11f00, 0x11f01 }, /* Mn */
{ 0x11f36, 0x11f3a }, /* Mn */
{ 0x11f40, 0x11f40 }, /* Mn */
{ 0x11f42, 0x11f42 }, /* Mn */
{ 0x13440, 0x13440 }, /* Mn */
{ 0x13447, 0x13455 }, /* Mn */
{ 0x16af0, 0x16af4 }, /* Mn */
{ 0x16b30, 0x16b36 }, /* Mn */
{ 0x16f4f, 0x16f4f }, /* Mn */
{ 0x16f8f, 0x16f92 }, /* Mn */
{ 0x16fe4, 0x16fe4 }, /* Mn */
{ 0x1bc9d, 0x1bc9e }, /* Mn */
{ 0x1cf00, 0x1cf2d }, /* Mn */
{ 0x1cf30, 0x1cf46 }, /* Mn */
{ 0x1d167, 0x1d169 }, /* Mn */
{ 0x1d17b, 0x1d182 }, /* Mn */
{ 0x1d185, 0x1d18b }, /* Mn */
{ 0x1d1aa, 0x1d1ad }, /* Mn */
{ 0x1d242, 0x1d244 }, /* Mn */
{ 0x1da00, 0x1da36 }, /* Mn */
{ 0x1da3b, 0x1da6c }, /* Mn */
{ 0x1da75, 0x1da75 }, /* Mn */
{ 0x1da84, 0x1da84 }, /* Mn */
{ 0x1da9b, 0x1da9f }, /* Mn */
{ 0x1daa1, 0x1daaf }, /* Mn */
{ 0x1e000, 0x1e006 }, /* Mn */
{ 0x1e008, 0x1e018 }, /* Mn */
{ 0x1e01b, 0x1e021 }, /* Mn */
{ 0x1e023, 0x1e024 }, /* Mn */
{ 0x1e026, 0x1e02a }, /* Mn */
{ 0x1e08f, 0x1e08f }, /* Mn */
{ 0x1e130, 0x1e136 }, /* Mn */
{ 0x1e2ae, 0x1e2ae }, /* Mn */
{ 0x1e2ec, 0x1e2ef }, /* Mn */
{ 0x1e4ec, 0x1e4ef }, /* Mn */
{ 0x1e8d0, 0x1e8d6 }, /* Mn */
{ 0x1e944, 0x1e94a }, /* Mn */
{ 0xe0100, 0xe01ef }, /* Mn */

107
third_party/less/cvt.c vendored Normal file
View file

@ -0,0 +1,107 @@
/*
* Copyright (C) 1984-2023 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(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(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(char *odst, char *osrc, int *chpos, int *lenp, int ops)
{
char *dst;
char *edst = odst;
char *src;
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);
struct ansi_state *pansi;
ch = step_char(&src, +1, src_end);
if ((ops & CVT_BS) && ch == '\b' && dst > odst)
{
/* Delete backspace and preceding char. */
do {
dst--;
} while (dst > odst && utf_mode &&
!IS_ASCII_OCTET(*dst) && !IS_UTF8_LEAD(*dst));
} else if ((ops & CVT_ANSI) && (pansi = ansi_start(ch)) != NULL)
{
/* Skip to end of ANSI escape sequence. */
while (src < src_end)
{
if (ansi_step(pansi, ch) != ANSI_MID)
break;
ch = *src++;
}
ansi_done(pansi);
} 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; */
}

1017
third_party/less/decode.c vendored Normal file

File diff suppressed because it is too large Load diff

475
third_party/less/defines.h vendored Normal file
View file

@ -0,0 +1,475 @@
/* defines.h. Generated from defines.h.in by configure. */
/* defines.h.in. Generated from configure.ac by autoheader. */
/* Unix definition file for less. -*- C -*-
*
* This file has 3 sections:
* User preferences.
* Settings always true on Unix.
* Settings automatically determined by configure.
*
* * * * * * WARNING * * * * * *
* If you edit defines.h by hand, do "touch stamp-h" before you run make
* so config.status doesn't overwrite your changes.
*/
/* User preferences. */
/*
* SECURE is 1 if you wish to disable a bunch of features in order to
* be safe to run by unprivileged users.
* SECURE_COMPILE is set by the --with-secure configure option.
*/
#define SECURE SECURE_COMPILE
/*
* SHELL_ESCAPE is 1 if you wish to allow shell escapes.
* (This is possible only if your system supplies the system() function.)
*/
#define SHELL_ESCAPE (!SECURE)
/*
* EXAMINE is 1 if you wish to allow examining files by name from within less.
*/
#define EXAMINE (!SECURE)
/*
* TAB_COMPLETE_FILENAME is 1 if you wish to allow the TAB key
* to complete filenames at prompts.
*/
#define TAB_COMPLETE_FILENAME (!SECURE)
/*
* CMD_HISTORY is 1 if you wish to allow keys to cycle through
* previous commands at prompts.
*/
#define CMD_HISTORY 1
/*
* HILITE_SEARCH is 1 if you wish to have search targets to be
* displayed in standout mode.
*/
#define HILITE_SEARCH 1
/*
* EDITOR is 1 if you wish to allow editor invocation (the "v" command).
* (This is possible only if your system supplies the system() function.)
* EDIT_PGM is the name of the (default) editor to be invoked.
*/
#define EDITOR (!SECURE)
/*
* TAGS is 1 if you wish to support tag files.
*/
#define TAGS (!SECURE)
/*
* USERFILE is 1 if you wish to allow a .less file to specify
* user-defined key bindings.
*/
#define USERFILE (!SECURE)
/*
* GLOB is 1 if you wish to have shell metacharacters expanded in filenames.
* This will generally work if your system provides the "popen" function
* and the "echo" shell command.
*/
#define GLOB (!SECURE)
/*
* PIPEC is 1 if you wish to have the "|" command
* which allows the user to pipe data into a shell command.
*/
#define PIPEC (!SECURE && HAVE_POPEN)
/*
* LOGFILE is 1 if you wish to allow the -o option (to create log files).
*/
#define LOGFILE (!SECURE)
/*
* GNU_OPTIONS is 1 if you wish to support the GNU-style command
* line options --help and --version.
*/
#define GNU_OPTIONS 1
/*
* ONLY_RETURN is 1 if you want RETURN to be the only input which
* will continue past an error message.
* Otherwise, any key will continue past an error message.
*/
#define ONLY_RETURN 0
/*
* LESSKEYFILE is the filename of the default lesskey output file
* (in the HOME directory).
* LESSKEYFILE_SYS is the filename of the system-wide lesskey output file.
* DEF_LESSKEYINFILE is the filename of the default lesskey input
* (in the HOME directory).
* LESSHISTFILE is the filename of the history file
* (in the HOME directory).
*/
#define LESSKEYFILE ".less"
#define LESSKEYFILE_SYS SYSDIR "/sysless"
#define DEF_LESSKEYINFILE ".lesskey"
#define LESSKEYINFILE_SYS SYSDIR "/syslesskey"
#define LESSHISTFILE ".lesshst"
/* Settings always true on Unix. */
/*
* Define MSDOS_COMPILER if compiling under Microsoft C.
*/
#define MSDOS_COMPILER 0
/*
* Pathname separator character.
*/
#define PATHNAME_SEP "/"
/*
* The value returned from tgetent on success.
* Some HP-UX systems return 0 on success.
*/
#define TGETENT_OK 1
/*
* HAVE_ANSI_PROTOS is 1 if your compiler supports ANSI function prototypes.
*/
#define HAVE_ANSI_PROTOS 1
/*
* HAVE_SYS_TYPES_H is 1 if your system has <sys/types.h>.
*/
#define HAVE_SYS_TYPES_H 1
/*
* Define if you have the <sgstat.h> header file.
*/
/* #undef HAVE_SGSTAT_H */
/*
* HAVE_PERROR is 1 if your system has the perror() call.
* (Actually, if it has sys_errlist, sys_nerr and errno.)
*/
#define HAVE_PERROR 1
/*
* HAVE_TIME is 1 if your system has the time() call.
*/
#define HAVE_TIME 1
/*
* HAVE_SHELL is 1 if your system supports a SHELL command interpreter.
*/
#define HAVE_SHELL 1
/*
* Default shell metacharacters and meta-escape character.
*/
#define DEF_METACHARS "; *?\t\n'\"()<>[]|&^`#\\$%=~{},"
#define DEF_METAESCAPE "\\"
/*
* HAVE_DUP is 1 if your system has the dup() call.
*/
#define HAVE_DUP 1
/* Define to 1 if you have the memcpy() function. */
#define HAVE_MEMCPY 1
/* Define to 1 if you have the strchr() function. */
#define HAVE_STRCHR 1
/* Define to 1 if you have the strstr() function. */
#define HAVE_STRSTR 1
/* Define to 1 to support reading lesskey source files (not just binary). */
#define HAVE_LESSKEYSRC 1
/*
* Sizes of various buffers.
*/
#if 0 /* old sizes for small memory machines */
#define CMDBUF_SIZE 512 /* Buffer for multichar commands */
#define UNGOT_SIZE 100 /* Max chars to unget() */
#define LINEBUF_SIZE 1024 /* Max size of line in input file */
#define OUTBUF_SIZE 1024 /* Output buffer */
#define PROMPT_SIZE 200 /* Max size of prompt string */
#define TERMBUF_SIZE 2048 /* Termcap buffer for tgetent */
#define TERMSBUF_SIZE 1024 /* Buffer to hold termcap strings */
#define TAGLINE_SIZE 512 /* Max size of line in tags file */
#define TABSTOP_MAX 32 /* Max number of custom tab stops */
#else /* more reasonable sizes for modern machines */
#define CMDBUF_SIZE 2048 /* Buffer for multichar commands */
#define UNGOT_SIZE 200 /* Max chars to unget() */
#define LINEBUF_SIZE 1024 /* Initial max size of line in input file */
#define OUTBUF_SIZE 1024 /* Output buffer */
#define PROMPT_SIZE 2048 /* Max size of prompt string */
#define TERMBUF_SIZE 2048 /* Termcap buffer for tgetent */
#define TERMSBUF_SIZE 1024 /* Buffer to hold termcap strings */
#define TAGLINE_SIZE 1024 /* Max size of line in tags file */
#define TABSTOP_MAX 128 /* Max number of custom tab stops */
#endif
/* Define as the return type of signal handlers (int or void). */
#define RETSIGTYPE void
/* Settings automatically determined by configure. */
/* Define EDIT_PGM to your editor. */
#define EDIT_PGM "vi"
/* Define HAVE_CONST if your compiler supports the "const" modifier. */
#define HAVE_CONST 1
/* Define to 1 if you have the <ctype.h> header file. */
#define HAVE_CTYPE_H 1
/* Define HAVE_ERRNO if you have the errno variable. */
#define HAVE_ERRNO 1
/* Define to 1 if you have the <errno.h> header file. */
#define HAVE_ERRNO_H 1
/* Define to 1 if you have the `fchmod' function. */
#define HAVE_FCHMOD 1
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H 1
/* Define HAVE_FILENO if you have the fileno() macro. */
#define HAVE_FILENO 1
/* Define to 1 if you have the `fsync' function. */
#define HAVE_FSYNC 1
/* GNU regex library */
/* #undef HAVE_GNU_REGEX */
/* Define to 1 if you have the <inttypes.h> header file. */
#define HAVE_INTTYPES_H 1
/* Define to 1 if you have the <limits.h> header file. */
#define HAVE_LIMITS_H 1
/* Define to 1 if you have the <linux/magic.h> header file. */
/* #undef HAVE_LINUX_MAGIC_H */
/* Define HAVE_LOCALE if you have locale.h and setlocale. */
#define HAVE_LOCALE 1
/* Define to 1 if you have the `nanosleep' function. */
#define HAVE_NANOSLEEP 1
/* Define to 1 if you have the <ncursesw/termcap.h> header file. */
/* #undef HAVE_NCURSESW_TERMCAP_H */
/* Define to 1 if you have the "third_party/ncurses/termcap.h" header file. */
#define HAVE_NCURSES_TERMCAP_H 1
/* Define HAVE_OSPEED if your termcap library has the ospeed variable. */
#define HAVE_OSPEED 1
/* PCRE (Perl-compatible regular expression) library */
/* #undef HAVE_PCRE */
/* PCRE2 (Perl-compatible regular expression) library */
#define HAVE_PCRE2 1
/* Define to 1 if you have the `poll' function. */
#define HAVE_POLL 1
/* Define to 1 if you have the `popen' function. */
#define HAVE_POPEN 1
/* POSIX regcomp() and regex.h */
/* #undef HAVE_POSIX_REGCOMP */
/* Define HAVE_PROCFS if have have fstatfs with f_type and PROC_SUPER_MAGIC.
*/
/* #undef HAVE_PROCFS */
/* Define to 1 if you have the `realpath' function. */
#define HAVE_REALPATH 1
/* System V regcmp() */
/* #undef HAVE_REGCMP */
/* */
/* #undef HAVE_REGEXEC2 */
/* BSD re_comp() */
/* #undef HAVE_RE_COMP */
/* Define HAVE_SIGEMPTYSET if you have the sigemptyset macro. */
#define HAVE_SIGEMPTYSET 1
/* Define to 1 if you have the `sigprocmask' function. */
#define HAVE_SIGPROCMASK 1
/* Define to 1 if you have the `sigsetmask' function. */
/* #undef HAVE_SIGSETMASK */
/* Define to 1 if the system has the type `sigset_t'. */
#define HAVE_SIGSET_T 1
/* Define to 1 if you have the `snprintf' function. */
#define HAVE_SNPRINTF 1
/* Define to 1 if you have the `stat' function. */
#define HAVE_STAT 1
/* Define HAVE_STAT_INO if your struct stat has st_ino and st_dev. */
#define HAVE_STAT_INO 1
/* Define to 1 if you have the <stdckdint.h> header file. */
#define HAVE_STDCKDINT_H 1
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H 1
/* Define to 1 if you have the <stdio.h> header file. */
#define HAVE_STDIO_H 1
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H 1
/* Define HAVE_STRERROR if you have the strerror() function. */
#define HAVE_STRERROR 1
/* Define to 1 if you have the <strings.h> header file. */
#define HAVE_STRINGS_H 1
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H 1
/* Define to 1 if you have the `strsignal' function. */
#define HAVE_STRSIGNAL 1
/* Define to 1 if you have the `system' function. */
#define HAVE_SYSTEM 1
/* Define HAVE_SYS_ERRLIST if you have the sys_errlist[] variable. */
#define HAVE_SYS_ERRLIST 1
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#define HAVE_SYS_IOCTL_H 1
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H 1
/* Define to 1 if you have the <sys/stream.h> header file. */
/* #undef HAVE_SYS_STREAM_H */
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H 1
/* Define to 1 if you have the <sys/wait.h> header file. */
#define HAVE_SYS_WAIT_H 1
/* Define to 1 if you have the <termcap.h> header file. */
/* #undef HAVE_TERMCAP_H */
/* Define HAVE_TERMIOS_FUNCS if you have tcgetattr/tcsetattr. */
#define HAVE_TERMIOS_FUNCS 1
/* Define to 1 if you have the <termios.h> header file. */
#define HAVE_TERMIOS_H 1
/* Define to 1 if you have the <termio.h> header file. */
/* #undef HAVE_TERMIO_H */
/* Define to 1 if you have the <time.h> header file. */
#define HAVE_TIME_H 1
/* Define HAVE_TIME_T if your system supports the "time_t" type. */
#define HAVE_TIME_T 1
/* Define to 1 if you have the `ttyname' function. */
#define HAVE_TTYNAME 1
/* Define to 1 if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define HAVE_UPPER_LOWER if you have isupper, islower, toupper, tolower. */
#define HAVE_UPPER_LOWER 1
/* Define to 1 if you have the `usleep' function. */
#define HAVE_USLEEP 1
/* Henry Spencer V8 regcomp() and regexp.h */
/* #undef HAVE_V8_REGCOMP */
/* Define to 1 if you have the <values.h> header file. */
/* #undef HAVE_VALUES_H */
/* Define HAVE_VOID if your compiler supports the "void" type. */
#define HAVE_VOID 1
/* Define HAVE_WCTYPE if you have iswupper, iswlower, towupper, towlower. */
#define HAVE_WCTYPE 1
/* Define to 1 if you have the <wctype.h> header file. */
#define HAVE_WCTYPE_H 1
/* Define to 1 if you have the `_setjmp' function. */
#define HAVE__SETJMP 1
/* Define MUST_DEFINE_ERRNO if you have errno but it is not define in errno.h.
*/
/* #undef MUST_DEFINE_ERRNO */
/* Define MUST_DEFINE_OSPEED if you have ospeed but it is not defined in
termcap.h. */
#define MUST_DEFINE_OSPEED 1
/* pattern matching is supported, but without metacharacters. */
/* #undef NO_REGEX */
/* Define to the address where bug reports for this package should be sent. */
#define PACKAGE_BUGREPORT ""
/* Define to the full name of this package. */
#define PACKAGE_NAME "less"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "less 1"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "less"
/* Define to the home page for this package. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "1"
/* Define SECURE_COMPILE=1 to build a secure version of less. */
#define SECURE_COMPILE 0
/* Define to 1 if the `S_IS*' macros in <sys/stat.h> do not work properly. */
/* #undef STAT_MACROS_BROKEN */
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
backward compatibility; new code need not use it. */
#define STDC_HEADERS 1
/* Number of bits in a file offset, on hosts where this is settable. */
/* #undef _FILE_OFFSET_BITS */
/* Define for large files, on AIX-style hosts. */
/* #undef _LARGE_FILES */
/* Define to empty if `const' does not conform to ANSI C. */
/* #undef const */
/* Define to `long int' if <sys/types.h> does not define. */
/* #undef off_t */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */

1017
third_party/less/edit.c vendored Normal file

File diff suppressed because it is too large Load diff

1118
third_party/less/filename.c vendored Normal file

File diff suppressed because it is too large Load diff

22
third_party/less/fmt.inc vendored Normal file
View file

@ -0,0 +1,22 @@
/* Generated by "./mkutable -f2 Cf -- unicode/UnicodeData.txt" on Mon Nov 14 18:19:23 PST 2022 */
{ 0x00ad, 0x00ad }, /* Cf */
{ 0x0600, 0x0605 }, /* Cf */
{ 0x061c, 0x061c }, /* Cf */
{ 0x06dd, 0x06dd }, /* Cf */
{ 0x070f, 0x070f }, /* Cf */
{ 0x0890, 0x0891 }, /* Cf */
{ 0x08e2, 0x08e2 }, /* Cf */
{ 0x180e, 0x180e }, /* Cf */
{ 0x200b, 0x200f }, /* Cf */
{ 0x202a, 0x202e }, /* Cf */
{ 0x2060, 0x2064 }, /* Cf */
{ 0x2066, 0x206f }, /* Cf */
{ 0xfeff, 0xfeff }, /* Cf */
{ 0xfff9, 0xfffb }, /* Cf */
{ 0x110bd, 0x110bd }, /* Cf */
{ 0x110cd, 0x110cd }, /* Cf */
{ 0x13430, 0x1343f }, /* Cf */
{ 0x1bca0, 0x1bca3 }, /* Cf */
{ 0x1d173, 0x1d17a }, /* Cf */
{ 0xe0001, 0xe0001 }, /* Cf */
{ 0xe0020, 0xe007f }, /* Cf */

549
third_party/less/forwback.c vendored Normal file
View file

@ -0,0 +1,549 @@
/*
* Copyright (C) 1984-2023 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 first_time = 1;
extern int sigs;
extern int top_scroll;
extern int quiet;
extern int sc_width, sc_height;
extern int hshift;
extern int auto_wrap;
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 header_lines;
extern int header_cols;
extern int full_screen;
#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.
*/
public void eof_bell(void)
{
#if HAVE_TIME
static time_type last_eof_bell = 0;
time_type now = get_time();
if (now == last_eof_bell) /* max once per second */
return;
last_eof_bell = now;
#endif
if (quiet == NOT_QUIET)
bell();
else
vbell();
}
/*
* Check to see if the end of file is currently displayed.
*/
public int 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(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(void)
{
if (!squished)
return;
squished = 0;
repaint();
}
/*
* Read the first pfx columns of the next line.
* If skipeol==0 stop there, otherwise read and discard chars to end of line.
*/
static POSITION forw_line_pfx(POSITION pos, int pfx, int skipeol)
{
int save_sc_width = sc_width;
int save_auto_wrap = auto_wrap;
int save_hshift = hshift;
/* Set fake sc_width to force only pfx chars to be read. */
sc_width = pfx + line_pfx_width();
auto_wrap = 0;
hshift = 0;
pos = forw_line_seg(pos, skipeol, FALSE, FALSE);
sc_width = save_sc_width;
auto_wrap = save_auto_wrap;
hshift = save_hshift;
return pos;
}
/*
* Set header text color.
* Underline last line of headers, but not at beginning of file
* (where there is no gap between the last header line and the next line).
*/
static void set_attr_header(int ln)
{
set_attr_line(AT_COLOR_HEADER);
if (ln+1 == header_lines && position(0) != ch_zero())
set_attr_line(AT_UNDERLINE);
}
/*
* Display file headers, overlaying text already drawn
* at top and left of screen.
*/
public int overlay_header(void)
{
POSITION pos = ch_zero(); /* header lines are at beginning of file */
int ln;
int moved = FALSE;
if (header_lines > 0)
{
/* Draw header_lines lines from start of file at top of screen. */
home();
for (ln = 0; ln < header_lines; ++ln)
{
pos = forw_line(pos);
set_attr_header(ln);
clear_eol();
put_line();
}
moved = TRUE;
}
if (header_cols > 0)
{
/* Draw header_cols columns at left of each line. */
home();
pos = ch_zero();
for (ln = 0; ln < sc_height-1; ++ln)
{
if (ln >= header_lines) /* switch from header lines to normal lines */
pos = position(ln);
if (pos == NULL_POSITION)
putchr('\n');
else
{
/* Need skipeol for all header lines except the last one. */
pos = forw_line_pfx(pos, header_cols, ln+1 < header_lines);
set_attr_header(ln);
put_line();
}
}
moved = TRUE;
}
if (moved)
lower_left();
return moved;
}
/*
* 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(int n, POSITION pos, int force, int only_last, int nblank)
{
int nlines = 0;
int do_repaint;
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 (pos != NULL_POSITION && (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;
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 && !is_filtering() && full_screen)
{
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 && pos == NULL_POSITION && !top_scroll &&
header_lines == 0 && header_cols == 0 &&
#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 (header_lines > 0)
{
/*
* Don't allow ch_zero to appear on screen except at top of screen.
* Otherwise duplicate header lines may be displayed.
*/
if (onscreen(ch_zero()) > 0)
{
jump_loc(ch_zero(), 0); /* {{ yuck }} */
return;
}
}
if (nlines == 0 && !ignore_eoi)
eof_bell();
else if (do_repaint)
repaint();
else
{
overlay_header();
/* lower_left(); {{ considered harmful? }} */
}
first_time = 0;
(void) currline(BOTTOM);
}
/*
* Display n lines, scrolling backward.
*/
public void 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) || header_lines > 0);
#if HILITE_SEARCH
if (pos != NULL_POSITION && (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)
eof_bell();
else if (do_repaint)
repaint();
else
{
overlay_header();
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(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 && !ABORT_SIGS());
}
} 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(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(void)
{
if (no_back_scroll)
return (0);
if (back_scroll >= 0)
return (back_scroll);
if (top_scroll)
return (sc_height - 2);
return (10000); /* infinity */
}
/*
* Will the entire file fit on one screen?
*/
public int get_one_screen(void)
{
int nlines;
POSITION pos = ch_zero();
for (nlines = 0; nlines < sc_height; nlines++)
{
pos = forw_line(pos);
if (pos == NULL_POSITION) break;
}
return (nlines < sc_height);
}

385
third_party/less/funcs.h vendored Normal file
View file

@ -0,0 +1,385 @@
public char * save(constant char *s);
public void out_of_memory(void);
public void * ecalloc(int count, unsigned int size);
public char * skipsp(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_mouse(void);
public void deinit_mouse(void);
public void init(void);
public void deinit(void);
public int interactive(void);
public void home(void);
public void dump_screen(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 sindex);
public void vbell(void);
public void bell(void);
public void clear(void);
public void clear_eol(void);
public void clear_bot(void);
public COLOR_TYPE parse_color(char *str, int *p_fg, int *p_bg);
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 putbs(void);
public int win32_kbhit(void);
public char WIN32getch(void);
public void WIN32ungetch(int ch);
public void WIN32setcolors(int fg, int bg);
public void WIN32textout(char *text, int len);
public void match_brac(char obrac, char 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);
public void setfmt(char *s, char **fmtvarptr, int *attrptr, char *default_fmt, int for_printf);
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(int ch);
public int is_utf8_well_formed(char *ss, int slen);
public void utf_skip_to_lead(char **pp, char *limit);
public LWCHAR get_wchar(constant char *p);
public void put_wchar(char **pp, LWCHAR ch);
public LWCHAR step_char(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 cmd_repaint(constant char *old_cp);
public void set_mlist(void *mlist, int cmdflags);
public void cmd_addhist(struct mlist *mlist, constant 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 int norm_search_type(int st);
public void dispversion(void);
public int getcc(void);
public void ungetcc(LWCHAR c);
public void ungetcc_back(LWCHAR c);
public void ungetsc(char *s);
public LWCHAR peekcc(void);
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 expand_cmd_tables(void);
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 isnullenv(char *s);
public int lesskey(char *filename, int sysvar);
public int lesskey_src(char *filename, int sysvar);
public int add_hometable(int (*call_lesskey)(char *, int), 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 void close_altpipe(IFILE ifile);
public void check_altpipe_error(void);
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_ifile);
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 * dirfile(char *dirname, char *filename, int must_exist);
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 int is_fake_pathname(char *path);
public char * lrealpath(char *path);
public char * open_altfile(char *filename, int *pf, void **pfd);
public void close_altfile(char *altfilename, char *filename);
public int is_dir(char *filename);
public char * bad_file(char *filename);
public POSITION filesize(int f);
public int curr_ifile_changed(void);
public char * shell_coption(void);
public char * last_component(char *name);
public void eof_bell(void);
public int eof_displayed(void);
public int entire_file_displayed(void);
public void squish_check(void);
public int overlay_header(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 int get_one_screen(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 char * get_real_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 set_altpipe(IFILE ifile, void *p);
public void *get_altpipe(IFILE ifile);
public void set_altfilename(IFILE ifile, char *altfilename);
public char * get_altfilename(IFILE ifile);
public void if_dump(void);
public POSITION forw_line_seg(POSITION curr_pos, int skipeol, int rscroll, int nochop);
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 POSITION line_position(void);
public void prewind(void);
public void plinestart(POSITION pos);
public int line_pfx_width(void);
public void pshift_all(void);
public int pwidth(LWCHAR ch, int a, LWCHAR prev_ch, int prev_a);
public void savec(void);
public void loadc(void);
public int is_ansi_end(LWCHAR ch);
public int is_ansi_middle(LWCHAR ch);
public void skip_ansi(struct ansi_state *pansi, char **pp, constant char *limit);
public struct ansi_state * ansi_start(LWCHAR ch);
public int ansi_step(struct ansi_state *pansi, LWCHAR ch);
public void ansi_done(struct ansi_state *pansi);
public int pappend(int c, POSITION pos);
public int pflushmbc(void);
public void pdone(int endline, int chopped, int forw);
public void set_attr_line(int a);
public void set_status_col(char c, int attr);
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 int skip_columns(int cols, char **linep, int *line_lenp);
public void load_line(constant char *str);
public int rrshift(void);
public int set_color_map(int attr, char *colorstr);
public char * get_color_map(int attr);
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 scan_eof(void);
public LINENUM vlinenum(LINENUM linenum);
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(LWCHAR c);
public void setmark(LWCHAR c, int where);
public void clrmark(LWCHAR c);
public void lastmark(void);
public void gomark(LWCHAR c);
public POSITION markpos(LWCHAR c);
public char posmark(POSITION pos);
public void unmark(IFILE ifile);
public void mark_check_ifile(IFILE ifile);
public void save_marks(FILE *fout, char *hdr);
public void restore_mark(char *line);
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_ks(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 set_tabs(char *s, int len);
public void opt_x(int type, char *s);
public void opt_quote(int type, char *s);
public void opt_rscroll(int type, char *s);
public void opt_query(int type, char *s);
public void opt_mousecap(int type, char *s);
public void opt_wheel_lines(int type, char *s);
public void opt_linenum_width(int type, char *s);
public void opt_status_col_width(int type, char *s);
public void opt_filesize(int type, char *s);
public void opt_intr(int type, char *s);
public void opt_header(int type, char *s);
public void opt_search_type(int type, char *s);
public void opt_ttyin_name(int type, char *s);
public int chop_line(void);
public int get_swindow(void);
public char * propt(int c);
public void scan_option(char *s);
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 char * opt_toggle_disallowed(int c);
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 void init_poll(void);
public int supports_ctrl_x(void);
public int iread(int fd, unsigned char *buf, unsigned int len);
public void intread(void);
public time_type get_time(void);
public char * errno_message(char *filename);
public char * signal_message(int sig);
public uintmax muldiv(uintmax val, uintmax num, uintmax den);
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 sleep_ms(int ms);
public void put_line(void);
public void flush(void);
public void set_output(int fd);
public int putchr(int c);
public void clear_bot_if_needed(void);
public void putstr(constant char *s);
public int less_printf(char *fmt, PARG *parg);
public void get_return(void);
public void error(char *fmt, PARG *parg);
public void ierror(char *fmt, PARG *parg);
public void ixerror(char *fmt, PARG *parg);
public int query(char *fmt, PARG *parg);
public int compile_pattern(char *pattern, int search_type, int show_error, PATTERN_TYPE *comp_pattern);
public void uncompile_pattern(PATTERN_TYPE *pattern);
public int valid_pattern(char *pattern);
public int is_null_pattern(PATTERN_TYPE pattern);
public int match_pattern(PATTERN_TYPE pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int nsp, int notbol, int search_type);
public char * pattern_lib_name(void);
public POSITION position(int sindex);
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, int where);
public int sindex_from_sline(int sline);
public void init_prompt(void);
public char * pr_expand(constant char *proto);
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(int clear);
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_attr(POSITION pos, POSITION epos, int nohide, int *p_matches);
public void chg_hilite(void);
public void chg_caseless(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 int open_tty(void);
public void open_getchr(void);
public void close_getchr(void);
public int pclose(FILE *f);
public int default_wheel_lines(void);
public int getchr(void);
public void xbuf_init(struct xbuffer *xbuf);
public void xbuf_deinit(struct xbuffer *xbuf);
public void xbuf_reset(struct xbuffer *xbuf);
public void xbuf_add_byte(struct xbuffer *xbuf, unsigned char b);
public void xbuf_add_data(struct xbuffer *xbuf, unsigned char *data, int len);
public int xbuf_pop(struct xbuffer *buf);
public void xbuf_set(struct xbuffer *dst, struct xbuffer *src);
public char * xbuf_char_data(struct xbuffer *xbuf);
public int help_ckd_add(void *r, uintmax a, uintmax b, int rsize, int rsigned);
public int help_ckd_mul(void *r, uintmax a, uintmax b, int rsize, int rsigned);

303
third_party/less/help.c vendored Normal file
View file

@ -0,0 +1,303 @@
/* This file was generated by mkhelp.pl from less.hlp at 22:43 on 2023/7/20 */
#include "less.h"
constant char helpdata[] = {
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','\b','S','U','\b','U','M','\b','M','M','\b','M','A','\b','A','R','\b','R','Y','\b','Y',' ','O','\b','O','F','\b','F',' ','L','\b','L','E','\b','E','S','\b','S','S','\b','S',' ','C','\b','C','O','\b','O','M','\b','M','M','\b','M','A','\b','A','N','\b','N','D','\b','D','S','\b','S','\n',
'\n',
' ',' ',' ',' ',' ',' ','C','o','m','m','a','n','d','s',' ','m','a','r','k','e','d',' ','w','i','t','h',' ','*',' ','m','a','y',' ','b','e',' ','p','r','e','c','e','d','e','d',' ','b','y',' ','a',' ','n','u','m','b','e','r',',',' ','_','\b','N','.','\n',
' ',' ',' ',' ',' ',' ','N','o','t','e','s',' ','i','n',' ','p','a','r','e','n','t','h','e','s','e','s',' ','i','n','d','i','c','a','t','e',' ','t','h','e',' ','b','e','h','a','v','i','o','r',' ','i','f',' ','_','\b','N',' ','i','s',' ','g','i','v','e','n','.','\n',
' ',' ',' ',' ',' ',' ','A',' ','k','e','y',' ','p','r','e','c','e','d','e','d',' ','b','y',' ','a',' ','c','a','r','e','t',' ','i','n','d','i','c','a','t','e','s',' ','t','h','e',' ','C','t','r','l',' ','k','e','y',';',' ','t','h','u','s',' ','^','K',' ','i','s',' ','c','t','r','l','-','K','.','\n',
'\n',
' ',' ','h',' ',' ','H',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','t','h','i','s',' ','h','e','l','p','.','\n',
' ',' ','q',' ',' ',':','q',' ',' ','Q',' ',' ',':','Q',' ',' ','Z','Z',' ',' ',' ',' ',' ','E','x','i','t','.','\n',
' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','M','\b','M','O','\b','O','V','\b','V','I','\b','I','N','\b','N','G','\b','G','\n',
'\n',
' ',' ','e',' ',' ','^','E',' ',' ','j',' ',' ','^','N',' ',' ','C','R',' ',' ','*',' ',' ','F','o','r','w','a','r','d',' ',' ','o','n','e',' ','l','i','n','e',' ',' ',' ','(','o','r',' ','_','\b','N',' ','l','i','n','e','s',')','.','\n',
' ',' ','y',' ',' ','^','Y',' ',' ','k',' ',' ','^','K',' ',' ','^','P',' ',' ','*',' ',' ','B','a','c','k','w','a','r','d',' ','o','n','e',' ','l','i','n','e',' ',' ',' ','(','o','r',' ','_','\b','N',' ','l','i','n','e','s',')','.','\n',
' ',' ','f',' ',' ','^','F',' ',' ','^','V',' ',' ','S','P','A','C','E',' ',' ','*',' ',' ','F','o','r','w','a','r','d',' ',' ','o','n','e',' ','w','i','n','d','o','w',' ','(','o','r',' ','_','\b','N',' ','l','i','n','e','s',')','.','\n',
' ',' ','b',' ',' ','^','B',' ',' ','E','S','C','-','v',' ',' ',' ',' ',' ',' ','*',' ',' ','B','a','c','k','w','a','r','d',' ','o','n','e',' ','w','i','n','d','o','w',' ','(','o','r',' ','_','\b','N',' ','l','i','n','e','s',')','.','\n',
' ',' ','z',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','F','o','r','w','a','r','d',' ',' ','o','n','e',' ','w','i','n','d','o','w',' ','(','a','n','d',' ','s','e','t',' ','w','i','n','d','o','w',' ','t','o',' ','_','\b','N',')','.','\n',
' ',' ','w',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','B','a','c','k','w','a','r','d',' ','o','n','e',' ','w','i','n','d','o','w',' ','(','a','n','d',' ','s','e','t',' ','w','i','n','d','o','w',' ','t','o',' ','_','\b','N',')','.','\n',
' ',' ','E','S','C','-','S','P','A','C','E',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','F','o','r','w','a','r','d',' ',' ','o','n','e',' ','w','i','n','d','o','w',',',' ','b','u','t',' ','d','o','n','\'','t',' ','s','t','o','p',' ','a','t',' ','e','n','d','-','o','f','-','f','i','l','e','.','\n',
' ',' ','d',' ',' ','^','D',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','F','o','r','w','a','r','d',' ',' ','o','n','e',' ','h','a','l','f','-','w','i','n','d','o','w',' ','(','a','n','d',' ','s','e','t',' ','h','a','l','f','-','w','i','n','d','o','w',' ','t','o',' ','_','\b','N',')','.','\n',
' ',' ','u',' ',' ','^','U',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','B','a','c','k','w','a','r','d',' ','o','n','e',' ','h','a','l','f','-','w','i','n','d','o','w',' ','(','a','n','d',' ','s','e','t',' ','h','a','l','f','-','w','i','n','d','o','w',' ','t','o',' ','_','\b','N',')','.','\n',
' ',' ','E','S','C','-',')',' ',' ','R','i','g','h','t','A','r','r','o','w',' ','*',' ',' ','R','i','g','h','t',' ','o','n','e',' ','h','a','l','f',' ','s','c','r','e','e','n',' ','w','i','d','t','h',' ','(','o','r',' ','_','\b','N',' ','p','o','s','i','t','i','o','n','s',')','.','\n',
' ',' ','E','S','C','-','(',' ',' ','L','e','f','t','A','r','r','o','w',' ',' ','*',' ',' ','L','e','f','t',' ',' ','o','n','e',' ','h','a','l','f',' ','s','c','r','e','e','n',' ','w','i','d','t','h',' ','(','o','r',' ','_','\b','N',' ','p','o','s','i','t','i','o','n','s',')','.','\n',
' ',' ','E','S','C','-','}',' ',' ','^','R','i','g','h','t','A','r','r','o','w',' ',' ',' ','R','i','g','h','t',' ','t','o',' ','l','a','s','t',' ','c','o','l','u','m','n',' ','d','i','s','p','l','a','y','e','d','.','\n',
' ',' ','E','S','C','-','{',' ',' ','^','L','e','f','t','A','r','r','o','w',' ',' ',' ',' ','L','e','f','t',' ',' ','t','o',' ','f','i','r','s','t',' ','c','o','l','u','m','n','.','\n',
' ',' ','F',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','F','o','r','w','a','r','d',' ','f','o','r','e','v','e','r',';',' ','l','i','k','e',' ','"','t','a','i','l',' ','-','f','"','.','\n',
' ',' ','E','S','C','-','F',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','L','i','k','e',' ','F',' ','b','u','t',' ','s','t','o','p',' ','w','h','e','n',' ','s','e','a','r','c','h',' ','p','a','t','t','e','r','n',' ','i','s',' ','f','o','u','n','d','.','\n',
' ',' ','r',' ',' ','^','R',' ',' ','^','L',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','p','a','i','n','t',' ','s','c','r','e','e','n','.','\n',
' ',' ','R',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','p','a','i','n','t',' ','s','c','r','e','e','n',',',' ','d','i','s','c','a','r','d','i','n','g',' ','b','u','f','f','e','r','e','d',' ','i','n','p','u','t','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
' ',' ',' ',' ',' ',' ',' ',' ','D','e','f','a','u','l','t',' ','"','w','i','n','d','o','w','"',' ','i','s',' ','t','h','e',' ','s','c','r','e','e','n',' ','h','e','i','g','h','t','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','D','e','f','a','u','l','t',' ','"','h','a','l','f','-','w','i','n','d','o','w','"',' ','i','s',' ','h','a','l','f',' ','o','f',' ','t','h','e',' ','s','c','r','e','e','n',' ','h','e','i','g','h','t','.','\n',
' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','\b','S','E','\b','E','A','\b','A','R','\b','R','C','\b','C','H','\b','H','I','\b','I','N','\b','N','G','\b','G','\n',
'\n',
' ',' ','/','_','\b','p','_','\b','a','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','n',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','S','e','a','r','c','h',' ','f','o','r','w','a','r','d',' ','f','o','r',' ','(','_','\b','N','-','t','h',')',' ','m','a','t','c','h','i','n','g',' ','l','i','n','e','.','\n',
' ',' ','?','_','\b','p','_','\b','a','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','n',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','S','e','a','r','c','h',' ','b','a','c','k','w','a','r','d',' ','f','o','r',' ','(','_','\b','N','-','t','h',')',' ','m','a','t','c','h','i','n','g',' ','l','i','n','e','.','\n',
' ',' ','n',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','R','e','p','e','a','t',' ','p','r','e','v','i','o','u','s',' ','s','e','a','r','c','h',' ','(','f','o','r',' ','_','\b','N','-','t','h',' ','o','c','c','u','r','r','e','n','c','e',')','.','\n',
' ',' ','N',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','R','e','p','e','a','t',' ','p','r','e','v','i','o','u','s',' ','s','e','a','r','c','h',' ','i','n',' ','r','e','v','e','r','s','e',' ','d','i','r','e','c','t','i','o','n','.','\n',
' ',' ','E','S','C','-','n',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','R','e','p','e','a','t',' ','p','r','e','v','i','o','u','s',' ','s','e','a','r','c','h',',',' ','s','p','a','n','n','i','n','g',' ','f','i','l','e','s','.','\n',
' ',' ','E','S','C','-','N',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','R','e','p','e','a','t',' ','p','r','e','v','i','o','u','s',' ','s','e','a','r','c','h',',',' ','r','e','v','e','r','s','e',' ','d','i','r','.',' ','&',' ','s','p','a','n','n','i','n','g',' ','f','i','l','e','s','.','\n',
' ',' ','E','S','C','-','u',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','U','n','d','o',' ','(','t','o','g','g','l','e',')',' ','s','e','a','r','c','h',' ','h','i','g','h','l','i','g','h','t','i','n','g','.','\n',
' ',' ','E','S','C','-','U',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','C','l','e','a','r',' ','s','e','a','r','c','h',' ','h','i','g','h','l','i','g','h','t','i','n','g','.','\n',
' ',' ','&','_','\b','p','_','\b','a','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','n',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','D','i','s','p','l','a','y',' ','o','n','l','y',' ','m','a','t','c','h','i','n','g',' ','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
' ',' ',' ',' ',' ',' ',' ',' ','A',' ','s','e','a','r','c','h',' ','p','a','t','t','e','r','n',' ','m','a','y',' ','b','e','g','i','n',' ','w','i','t','h',' ','o','n','e',' ','o','r',' ','m','o','r','e',' ','o','f',':','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','N',' ','o','r',' ','!',' ',' ','S','e','a','r','c','h',' ','f','o','r',' ','N','O','N','-','m','a','t','c','h','i','n','g',' ','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','E',' ','o','r',' ','*',' ',' ','S','e','a','r','c','h',' ','m','u','l','t','i','p','l','e',' ','f','i','l','e','s',' ','(','p','a','s','s',' ','t','h','r','u',' ','E','N','D',' ','O','F',' ','F','I','L','E',')','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','F',' ','o','r',' ','@',' ',' ','S','t','a','r','t',' ','s','e','a','r','c','h',' ','a','t',' ','F','I','R','S','T',' ','f','i','l','e',' ','(','f','o','r',' ','/',')',' ','o','r',' ','l','a','s','t',' ','f','i','l','e',' ','(','f','o','r',' ','?',')','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','K',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','m','a','t','c','h','e','s',',',' ','b','u','t',' ','d','o','n','\'','t',' ','m','o','v','e',' ','(','K','E','E','P',' ','p','o','s','i','t','i','o','n',')','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','R',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','u','s','e',' ','R','E','G','U','L','A','R',' ','E','X','P','R','E','S','S','I','O','N','S','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','S',' ','_','\b','n',' ',' ',' ',' ',' ','S','e','a','r','c','h',' ','f','o','r',' ','m','a','t','c','h',' ','i','n',' ','_','\b','n','-','t','h',' ','p','a','r','e','n','t','h','e','s','i','z','e','d',' ','s','u','b','p','a','t','t','e','r','n','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','^','W',' ',' ',' ',' ',' ',' ',' ','W','R','A','P',' ','s','e','a','r','c','h',' ','i','f',' ','n','o',' ','m','a','t','c','h',' ','f','o','u','n','d','.','\n',
' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','J','\b','J','U','\b','U','M','\b','M','P','\b','P','I','\b','I','N','\b','N','G','\b','G','\n',
'\n',
' ',' ','g',' ',' ','<',' ',' ','E','S','C','-','<',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','f','i','r','s','t',' ','l','i','n','e',' ','i','n',' ','f','i','l','e',' ','(','o','r',' ','l','i','n','e',' ','_','\b','N',')','.','\n',
' ',' ','G',' ',' ','>',' ',' ','E','S','C','-','>',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','l','a','s','t',' ','l','i','n','e',' ','i','n',' ','f','i','l','e',' ','(','o','r',' ','l','i','n','e',' ','_','\b','N',')','.','\n',
' ',' ','p',' ',' ','%',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','b','e','g','i','n','n','i','n','g',' ','o','f',' ','f','i','l','e',' ','(','o','r',' ','_','\b','N',' ','p','e','r','c','e','n','t',' ','i','n','t','o',' ','f','i','l','e',')','.','\n',
' ',' ','t',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','n','e','x','t',' ','t','a','g','.','\n',
' ',' ','T',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','G','o',' ','t','o',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','p','r','e','v','i','o','u','s',' ','t','a','g','.','\n',
' ',' ','{',' ',' ','(',' ',' ','[',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','F','i','n','d',' ','c','l','o','s','e',' ','b','r','a','c','k','e','t',' ','}',' ',')',' ',']','.','\n',
' ',' ','}',' ',' ',')',' ',' ',']',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','F','i','n','d',' ','o','p','e','n',' ','b','r','a','c','k','e','t',' ','{',' ','(',' ','[','.','\n',
' ',' ','E','S','C','-','^','F',' ','_','\b','<','_','\b','c','_','\b','1','_','\b','>',' ','_','\b','<','_','\b','c','_','\b','2','_','\b','>',' ',' ','*',' ',' ','F','i','n','d',' ','c','l','o','s','e',' ','b','r','a','c','k','e','t',' ','_','\b','<','_','\b','c','_','\b','2','_','\b','>','.','\n',
' ',' ','E','S','C','-','^','B',' ','_','\b','<','_','\b','c','_','\b','1','_','\b','>',' ','_','\b','<','_','\b','c','_','\b','2','_','\b','>',' ',' ','*',' ',' ','F','i','n','d',' ','o','p','e','n',' ','b','r','a','c','k','e','t',' ','_','\b','<','_','\b','c','_','\b','1','_','\b','>','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
' ',' ',' ',' ',' ',' ',' ',' ','E','a','c','h',' ','"','f','i','n','d',' ','c','l','o','s','e',' ','b','r','a','c','k','e','t','"',' ','c','o','m','m','a','n','d',' ','g','o','e','s',' ','f','o','r','w','a','r','d',' ','t','o',' ','t','h','e',' ','c','l','o','s','e',' ','b','r','a','c','k','e','t',' ','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','m','a','t','c','h','i','n','g',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','o','p','e','n',' ','b','r','a','c','k','e','t',' ','i','n',' ','t','h','e',' ','t','o','p',' ','l','i','n','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','E','a','c','h',' ','"','f','i','n','d',' ','o','p','e','n',' ','b','r','a','c','k','e','t','"',' ','c','o','m','m','a','n','d',' ','g','o','e','s',' ','b','a','c','k','w','a','r','d',' ','t','o',' ','t','h','e',' ','o','p','e','n',' ','b','r','a','c','k','e','t',' ','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','m','a','t','c','h','i','n','g',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','c','l','o','s','e',' ','b','r','a','c','k','e','t',' ','i','n',' ','t','h','e',' ','b','o','t','t','o','m',' ','l','i','n','e','.','\n',
'\n',
' ',' ','m','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','M','a','r','k',' ','t','h','e',' ','c','u','r','r','e','n','t',' ','t','o','p',' ','l','i','n','e',' ','w','i','t','h',' ','<','l','e','t','t','e','r','>','.','\n',
' ',' ','M','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','M','a','r','k',' ','t','h','e',' ','c','u','r','r','e','n','t',' ','b','o','t','t','o','m',' ','l','i','n','e',' ','w','i','t','h',' ','<','l','e','t','t','e','r','>','.','\n',
' ',' ','\'','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','G','o',' ','t','o',' ','a',' ','p','r','e','v','i','o','u','s','l','y',' ','m','a','r','k','e','d',' ','p','o','s','i','t','i','o','n','.','\n',
' ',' ','\'','\'',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','G','o',' ','t','o',' ','t','h','e',' ','p','r','e','v','i','o','u','s',' ','p','o','s','i','t','i','o','n','.','\n',
' ',' ','^','X','^','X',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','a','m','e',' ','a','s',' ','\'','.','\n',
' ',' ','E','S','C','-','m','_','\b','<','_','\b','l','_','\b','e','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ','C','l','e','a','r',' ','a',' ','m','a','r','k','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
' ',' ',' ',' ',' ',' ',' ',' ','A',' ','m','a','r','k',' ','i','s',' ','a','n','y',' ','u','p','p','e','r','-','c','a','s','e',' ','o','r',' ','l','o','w','e','r','-','c','a','s','e',' ','l','e','t','t','e','r','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','C','e','r','t','a','i','n',' ','m','a','r','k','s',' ','a','r','e',' ','p','r','e','d','e','f','i','n','e','d',':','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','^',' ',' ','m','e','a','n','s',' ',' ','b','e','g','i','n','n','i','n','g',' ','o','f',' ','t','h','e',' ','f','i','l','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','$',' ',' ','m','e','a','n','s',' ',' ','e','n','d',' ','o','f',' ','t','h','e',' ','f','i','l','e','\n',
' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','C','\b','C','H','\b','H','A','\b','A','N','\b','N','G','\b','G','I','\b','I','N','\b','N','G','\b','G',' ','F','\b','F','I','\b','I','L','\b','L','E','\b','E','S','\b','S','\n',
'\n',
' ',' ',':','e',' ','[','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','x','a','m','i','n','e',' ','a',' ','n','e','w',' ','f','i','l','e','.','\n',
' ',' ','^','X','^','V',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','a','m','e',' ','a','s',' ',':','e','.','\n',
' ',' ',':','n',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','E','x','a','m','i','n','e',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','n','e','x','t',' ','f','i','l','e',' ','f','r','o','m',' ','t','h','e',' ','c','o','m','m','a','n','d',' ','l','i','n','e','.','\n',
' ',' ',':','p',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','E','x','a','m','i','n','e',' ','t','h','e',' ','(','_','\b','N','-','t','h',')',' ','p','r','e','v','i','o','u','s',' ','f','i','l','e',' ','f','r','o','m',' ','t','h','e',' ','c','o','m','m','a','n','d',' ','l','i','n','e','.','\n',
' ',' ',':','x',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','*',' ',' ','E','x','a','m','i','n','e',' ','t','h','e',' ','f','i','r','s','t',' ','(','o','r',' ','_','\b','N','-','t','h',')',' ','f','i','l','e',' ','f','r','o','m',' ','t','h','e',' ','c','o','m','m','a','n','d',' ','l','i','n','e','.','\n',
' ',' ',':','d',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','e','l','e','t','e',' ','t','h','e',' ','c','u','r','r','e','n','t',' ','f','i','l','e',' ','f','r','o','m',' ','t','h','e',' ','c','o','m','m','a','n','d',' ','l','i','n','e',' ','l','i','s','t','.','\n',
' ',' ','=',' ',' ','^','G',' ',' ',':','f',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','P','r','i','n','t',' ','c','u','r','r','e','n','t',' ','f','i','l','e',' ','n','a','m','e','.','\n',
' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','M','\b','M','I','\b','I','S','\b','S','C','\b','C','E','\b','E','L','\b','L','L','\b','L','A','\b','A','N','\b','N','E','\b','E','O','\b','O','U','\b','U','S','\b','S',' ','C','\b','C','O','\b','O','M','\b','M','M','\b','M','A','\b','A','N','\b','N','D','\b','D','S','\b','S','\n',
'\n',
' ',' ','-','_','\b','<','_','\b','f','_','\b','l','_','\b','a','_','\b','g','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','T','o','g','g','l','e',' ','a',' ','c','o','m','m','a','n','d',' ','l','i','n','e',' ','o','p','t','i','o','n',' ','[','s','e','e',' ','O','P','T','I','O','N','S',' ','b','e','l','o','w',']','.','\n',
' ',' ','-','-','_','\b','<','_','\b','n','_','\b','a','_','\b','m','_','\b','e','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','T','o','g','g','l','e',' ','a',' ','c','o','m','m','a','n','d',' ','l','i','n','e',' ','o','p','t','i','o','n',',',' ','b','y',' ','n','a','m','e','.','\n',
' ',' ','_','_','\b','<','_','\b','f','_','\b','l','_','\b','a','_','\b','g','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','t','h','e',' ','s','e','t','t','i','n','g',' ','o','f',' ','a',' ','c','o','m','m','a','n','d',' ','l','i','n','e',' ','o','p','t','i','o','n','.','\n',
' ',' ','_','_','_','\b','<','_','\b','n','_','\b','a','_','\b','m','_','\b','e','_','\b','>',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','t','h','e',' ','s','e','t','t','i','n','g',' ','o','f',' ','a','n',' ','o','p','t','i','o','n',',',' ','b','y',' ','n','a','m','e','.','\n',
' ',' ','+','_','\b','c','_','\b','m','_','\b','d',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','x','e','c','u','t','e',' ','t','h','e',' ','l','e','s','s',' ','c','m','d',' ','e','a','c','h',' ','t','i','m','e',' ','a',' ','n','e','w',' ','f','i','l','e',' ','i','s',' ','e','x','a','m','i','n','e','d','.','\n',
'\n',
' ',' ','!','_','\b','c','_','\b','o','_','\b','m','_','\b','m','_','\b','a','_','\b','n','_','\b','d',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','x','e','c','u','t','e',' ','t','h','e',' ','s','h','e','l','l',' ','c','o','m','m','a','n','d',' ','w','i','t','h',' ','$','S','H','E','L','L','.','\n',
' ',' ','#','_','\b','c','_','\b','o','_','\b','m','_','\b','m','_','\b','a','_','\b','n','_','\b','d',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','x','e','c','u','t','e',' ','t','h','e',' ','s','h','e','l','l',' ','c','o','m','m','a','n','d',',',' ','e','x','p','a','n','d','e','d',' ','l','i','k','e',' ','a',' ','p','r','o','m','p','t','.','\n',
' ',' ','|','X','\b','X','_','\b','c','_','\b','o','_','\b','m','_','\b','m','_','\b','a','_','\b','n','_','\b','d',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','P','i','p','e',' ','f','i','l','e',' ','b','e','t','w','e','e','n',' ','c','u','r','r','e','n','t',' ','p','o','s',' ','&',' ','m','a','r','k',' ','X','\b','X',' ','t','o',' ','s','h','e','l','l',' ','c','o','m','m','a','n','d','.','\n',
' ',' ','s',' ','_','\b','f','_','\b','i','_','\b','l','_','\b','e',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','a','v','e',' ','i','n','p','u','t',' ','t','o',' ','a',' ','f','i','l','e','.','\n',
' ',' ','v',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','d','i','t',' ','t','h','e',' ','c','u','r','r','e','n','t',' ','f','i','l','e',' ','w','i','t','h',' ','$','V','I','S','U','A','L',' ','o','r',' ','$','E','D','I','T','O','R','.','\n',
' ',' ','V',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','P','r','i','n','t',' ','v','e','r','s','i','o','n',' ','n','u','m','b','e','r',' ','o','f',' ','"','l','e','s','s','"','.','\n',
' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','O','\b','O','P','\b','P','T','\b','T','I','\b','I','O','\b','O','N','\b','N','S','\b','S','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ','M','o','s','t',' ','o','p','t','i','o','n','s',' ','m','a','y',' ','b','e',' ','c','h','a','n','g','e','d',' ','e','i','t','h','e','r',' ','o','n',' ','t','h','e',' ','c','o','m','m','a','n','d',' ','l','i','n','e',',','\n',
' ',' ',' ',' ',' ',' ',' ',' ','o','r',' ','f','r','o','m',' ','w','i','t','h','i','n',' ','l','e','s','s',' ','b','y',' ','u','s','i','n','g',' ','t','h','e',' ','-',' ','o','r',' ','-','-',' ','c','o','m','m','a','n','d','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ','O','p','t','i','o','n','s',' ','m','a','y',' ','b','e',' ','g','i','v','e','n',' ','i','n',' ','o','n','e',' ','o','f',' ','t','w','o',' ','f','o','r','m','s',':',' ','e','i','t','h','e','r',' ','a',' ','s','i','n','g','l','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ','c','h','a','r','a','c','t','e','r',' ','p','r','e','c','e','d','e','d',' ','b','y',' ','a',' ','-',',',' ','o','r',' ','a',' ','n','a','m','e',' ','p','r','e','c','e','d','e','d',' ','b','y',' ','-','-','.','\n',
'\n',
' ',' ','-','?',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','h','e','l','p','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','h','e','l','p',' ','(','f','r','o','m',' ','c','o','m','m','a','n','d',' ','l','i','n','e',')','.','\n',
' ',' ','-','a',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','s','e','a','r','c','h','-','s','k','i','p','-','s','c','r','e','e','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','a','r','c','h',' ','s','k','i','p','s',' ','c','u','r','r','e','n','t',' ','s','c','r','e','e','n','.','\n',
' ',' ','-','A',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','S','E','A','R','C','H','-','S','K','I','P','-','S','C','R','E','E','N','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','a','r','c','h',' ','s','t','a','r','t','s',' ','j','u','s','t',' ','a','f','t','e','r',' ','t','a','r','g','e','t',' ','l','i','n','e','.','\n',
' ',' ','-','b',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','b','u','f','f','e','r','s','=','[','_','\b','N',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','N','u','m','b','e','r',' ','o','f',' ','b','u','f','f','e','r','s','.','\n',
' ',' ','-','B',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','a','u','t','o','-','b','u','f','f','e','r','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','a','u','t','o','m','a','t','i','c','a','l','l','y',' ','a','l','l','o','c','a','t','e',' ','b','u','f','f','e','r','s',' ','f','o','r',' ','p','i','p','e','s','.','\n',
' ',' ','-','c',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','c','l','e','a','r','-','s','c','r','e','e','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','p','a','i','n','t',' ','b','y',' ','c','l','e','a','r','i','n','g',' ','r','a','t','h','e','r',' ','t','h','a','n',' ','s','c','r','o','l','l','i','n','g','.','\n',
' ',' ','-','d',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','d','u','m','b','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','u','m','b',' ','t','e','r','m','i','n','a','l','.','\n',
' ',' ','-','D',' ','x','\b','x','_','\b','c','_','\b','o','_','\b','l','_','\b','o','_','\b','r',' ',' ','.',' ',' ','-','-','c','o','l','o','r','=','x','\b','x','_','\b','c','_','\b','o','_','\b','l','_','\b','o','_','\b','r','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','s','c','r','e','e','n',' ','c','o','l','o','r','s','.','\n',
' ',' ','-','e',' ',' ','-','E',' ',' ','.','.','.','.',' ',' ','-','-','q','u','i','t','-','a','t','-','e','o','f',' ',' ','-','-','Q','U','I','T','-','A','T','-','E','O','F','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','Q','u','i','t',' ','a','t',' ','e','n','d',' ','o','f',' ','f','i','l','e','.','\n',
' ',' ','-','f',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','f','o','r','c','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','F','o','r','c','e',' ','o','p','e','n',' ','n','o','n','-','r','e','g','u','l','a','r',' ','f','i','l','e','s','.','\n',
' ',' ','-','F',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','q','u','i','t','-','i','f','-','o','n','e','-','s','c','r','e','e','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','Q','u','i','t',' ','i','f',' ','e','n','t','i','r','e',' ','f','i','l','e',' ','f','i','t','s',' ','o','n',' ','f','i','r','s','t',' ','s','c','r','e','e','n','.','\n',
' ',' ','-','g',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','h','i','l','i','t','e','-','s','e','a','r','c','h','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','o','n','l','y',' ','l','a','s','t',' ','m','a','t','c','h',' ','f','o','r',' ','s','e','a','r','c','h','e','s','.','\n',
' ',' ','-','G',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','H','I','L','I','T','E','-','S','E','A','R','C','H','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','h','i','g','h','l','i','g','h','t',' ','a','n','y',' ','m','a','t','c','h','e','s',' ','f','o','r',' ','s','e','a','r','c','h','e','s','.','\n',
' ',' ','-','h',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','m','a','x','-','b','a','c','k','-','s','c','r','o','l','l','=','[','_','\b','N',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','B','a','c','k','w','a','r','d',' ','s','c','r','o','l','l',' ','l','i','m','i','t','.','\n',
' ',' ','-','i',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','i','g','n','o','r','e','-','c','a','s','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','I','g','n','o','r','e',' ','c','a','s','e',' ','i','n',' ','s','e','a','r','c','h','e','s',' ','t','h','a','t',' ','d','o',' ','n','o','t',' ','c','o','n','t','a','i','n',' ','u','p','p','e','r','c','a','s','e','.','\n',
' ',' ','-','I',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','I','G','N','O','R','E','-','C','A','S','E','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','I','g','n','o','r','e',' ','c','a','s','e',' ','i','n',' ','a','l','l',' ','s','e','a','r','c','h','e','s','.','\n',
' ',' ','-','j',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','j','u','m','p','-','t','a','r','g','e','t','=','[','_','\b','N',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','c','r','e','e','n',' ','p','o','s','i','t','i','o','n',' ','o','f',' ','t','a','r','g','e','t',' ','l','i','n','e','s','.','\n',
' ',' ','-','J',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','s','t','a','t','u','s','-','c','o','l','u','m','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','a',' ','s','t','a','t','u','s',' ','c','o','l','u','m','n',' ','a','t',' ','l','e','f','t',' ','e','d','g','e',' ','o','f',' ','s','c','r','e','e','n','.','\n',
' ',' ','-','k',' ','[','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']',' ',' ','.',' ',' ','-','-','l','e','s','s','k','e','y','-','f','i','l','e','=','[','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','U','s','e',' ','a',' ','l','e','s','s','k','e','y',' ','f','i','l','e','.','\n',
' ',' ','-','K',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','q','u','i','t','-','o','n','-','i','n','t','r','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','x','i','t',' ','l','e','s','s',' ','i','n',' ','r','e','s','p','o','n','s','e',' ','t','o',' ','c','t','r','l','-','C','.','\n',
' ',' ','-','L',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','n','o','-','l','e','s','s','o','p','e','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','I','g','n','o','r','e',' ','t','h','e',' ','L','E','S','S','O','P','E','N',' ','e','n','v','i','r','o','n','m','e','n','t',' ','v','a','r','i','a','b','l','e','.','\n',
' ',' ','-','m',' ',' ','-','M',' ',' ','.','.','.','.',' ',' ','-','-','l','o','n','g','-','p','r','o','m','p','t',' ',' ','-','-','L','O','N','G','-','P','R','O','M','P','T','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','p','r','o','m','p','t',' ','s','t','y','l','e','.','\n',
' ',' ','-','n',' ','.','.','.','.','.','.','.','.','.',' ',' ','-','-','l','i','n','e','-','n','u','m','b','e','r','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','u','p','p','r','e','s','s',' ','l','i','n','e',' ','n','u','m','b','e','r','s',' ','i','n',' ','p','r','o','m','p','t','s',' ','a','n','d',' ','m','e','s','s','a','g','e','s','.','\n',
' ',' ','-','N',' ','.','.','.','.','.','.','.','.','.',' ',' ','-','-','L','I','N','E','-','N','U','M','B','E','R','S','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','l','i','n','e',' ','n','u','m','b','e','r',' ','a','t',' ','s','t','a','r','t',' ','o','f',' ','e','a','c','h',' ','l','i','n','e','.','\n',
' ',' ','-','o',' ','[','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']',' ',' ','.',' ',' ','-','-','l','o','g','-','f','i','l','e','=','[','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','C','o','p','y',' ','t','o',' ','l','o','g',' ','f','i','l','e',' ','(','s','t','a','n','d','a','r','d',' ','i','n','p','u','t',' ','o','n','l','y',')','.','\n',
' ',' ','-','O',' ','[','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']',' ',' ','.',' ',' ','-','-','L','O','G','-','F','I','L','E','=','[','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','C','o','p','y',' ','t','o',' ','l','o','g',' ','f','i','l','e',' ','(','u','n','c','o','n','d','i','t','i','o','n','a','l','l','y',' ','o','v','e','r','w','r','i','t','e',')','.','\n',
' ',' ','-','p',' ','[','_','\b','p','_','\b','a','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','n',']',' ',' ','-','-','p','a','t','t','e','r','n','=','[','_','\b','p','_','\b','a','_','\b','t','_','\b','t','_','\b','e','_','\b','r','_','\b','n',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','t','a','r','t',' ','a','t',' ','p','a','t','t','e','r','n',' ','(','f','r','o','m',' ','c','o','m','m','a','n','d',' ','l','i','n','e',')','.','\n',
' ',' ','-','P',' ','[','_','\b','p','_','\b','r','_','\b','o','_','\b','m','_','\b','p','_','\b','t',']',' ',' ',' ','-','-','p','r','o','m','p','t','=','[','_','\b','p','_','\b','r','_','\b','o','_','\b','m','_','\b','p','_','\b','t',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','e','f','i','n','e',' ','n','e','w',' ','p','r','o','m','p','t','.','\n',
' ',' ','-','q',' ',' ','-','Q',' ',' ','.','.','.','.',' ',' ','-','-','q','u','i','e','t',' ',' ','-','-','Q','U','I','E','T',' ',' ','-','-','s','i','l','e','n','t',' ','-','-','S','I','L','E','N','T','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','Q','u','i','e','t',' ','t','h','e',' ','t','e','r','m','i','n','a','l',' ','b','e','l','l','.','\n',
' ',' ','-','r',' ',' ','-','R',' ',' ','.','.','.','.',' ',' ','-','-','r','a','w','-','c','o','n','t','r','o','l','-','c','h','a','r','s',' ',' ','-','-','R','A','W','-','C','O','N','T','R','O','L','-','C','H','A','R','S','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','O','u','t','p','u','t',' ','"','r','a','w','"',' ','c','o','n','t','r','o','l',' ','c','h','a','r','a','c','t','e','r','s','.','\n',
' ',' ','-','s',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','s','q','u','e','e','z','e','-','b','l','a','n','k','-','l','i','n','e','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','q','u','e','e','z','e',' ','m','u','l','t','i','p','l','e',' ','b','l','a','n','k',' ','l','i','n','e','s','.','\n',
' ',' ','-','S',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','c','h','o','p','-','l','o','n','g','-','l','i','n','e','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','C','h','o','p',' ','(','t','r','u','n','c','a','t','e',')',' ','l','o','n','g',' ','l','i','n','e','s',' ','r','a','t','h','e','r',' ','t','h','a','n',' ','w','r','a','p','p','i','n','g','.','\n',
' ',' ','-','t',' ','[','_','\b','t','_','\b','a','_','\b','g',']',' ',' ','.','.',' ',' ','-','-','t','a','g','=','[','_','\b','t','_','\b','a','_','\b','g',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','F','i','n','d',' ','a',' ','t','a','g','.','\n',
' ',' ','-','T',' ','[','_','\b','t','_','\b','a','_','\b','g','_','\b','s','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']',' ','-','-','t','a','g','-','f','i','l','e','=','[','_','\b','t','_','\b','a','_','\b','g','_','\b','s','_','\b','f','_','\b','i','_','\b','l','_','\b','e',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','U','s','e',' ','a','n',' ','a','l','t','e','r','n','a','t','e',' ','t','a','g','s',' ','f','i','l','e','.','\n',
' ',' ','-','u',' ',' ','-','U',' ',' ','.','.','.','.',' ',' ','-','-','u','n','d','e','r','l','i','n','e','-','s','p','e','c','i','a','l',' ',' ','-','-','U','N','D','E','R','L','I','N','E','-','S','P','E','C','I','A','L','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','C','h','a','n','g','e',' ','h','a','n','d','l','i','n','g',' ','o','f',' ','b','a','c','k','s','p','a','c','e','s',',',' ','t','a','b','s',' ','a','n','d',' ','c','a','r','r','i','a','g','e',' ','r','e','t','u','r','n','s','.','\n',
' ',' ','-','V',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','v','e','r','s','i','o','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','t','h','e',' ','v','e','r','s','i','o','n',' ','n','u','m','b','e','r',' ','o','f',' ','"','l','e','s','s','"','.','\n',
' ',' ','-','w',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','h','i','l','i','t','e','-','u','n','r','e','a','d','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','f','i','r','s','t',' ','n','e','w',' ','l','i','n','e',' ','a','f','t','e','r',' ','f','o','r','w','a','r','d','-','s','c','r','e','e','n','.','\n',
' ',' ','-','W',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','H','I','L','I','T','E','-','U','N','R','E','A','D','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','f','i','r','s','t',' ','n','e','w',' ','l','i','n','e',' ','a','f','t','e','r',' ','a','n','y',' ','f','o','r','w','a','r','d',' ','m','o','v','e','m','e','n','t','.','\n',
' ',' ','-','x',' ','[','_','\b','N','[',',','.','.','.',']',']',' ',' ','-','-','t','a','b','s','=','[','_','\b','N','[',',','.','.','.',']',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','t','a','b',' ','s','t','o','p','s','.','\n',
' ',' ','-','X',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','n','o','-','i','n','i','t','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','u','s','e',' ','t','e','r','m','c','a','p',' ','i','n','i','t','/','d','e','i','n','i','t',' ','s','t','r','i','n','g','s','.','\n',
' ',' ','-','y',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','m','a','x','-','f','o','r','w','-','s','c','r','o','l','l','=','[','_','\b','N',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','F','o','r','w','a','r','d',' ','s','c','r','o','l','l',' ','l','i','m','i','t','.','\n',
' ',' ','-','z',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','w','i','n','d','o','w','=','[','_','\b','N',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','s','i','z','e',' ','o','f',' ','w','i','n','d','o','w','.','\n',
' ',' ','-','"',' ','[','_','\b','c','[','_','\b','c',']',']',' ',' ','.',' ',' ','-','-','q','u','o','t','e','s','=','[','_','\b','c','[','_','\b','c',']',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','s','h','e','l','l',' ','q','u','o','t','e',' ','c','h','a','r','a','c','t','e','r','s','.','\n',
' ',' ','-','~',' ',' ','.','.','.','.','.','.','.','.',' ',' ','-','-','t','i','l','d','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','d','i','s','p','l','a','y',' ','t','i','l','d','e','s',' ','a','f','t','e','r',' ','e','n','d',' ','o','f',' ','f','i','l','e','.','\n',
' ',' ','-','#',' ','[','_','\b','N',']',' ',' ','.','.','.','.',' ',' ','-','-','s','h','i','f','t','=','[','_','\b','N',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','h','o','r','i','z','o','n','t','a','l',' ','s','c','r','o','l','l',' ','a','m','o','u','n','t',' ','(','0',' ','=',' ','o','n','e',' ','h','a','l','f',' ','s','c','r','e','e','n',' ','w','i','d','t','h',')','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','e','x','i','t','-','f','o','l','l','o','w','-','o','n','-','c','l','o','s','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','x','i','t',' ','F',' ','c','o','m','m','a','n','d',' ','o','n',' ','a',' ','p','i','p','e',' ','w','h','e','n',' ','w','r','i','t','e','r',' ','c','l','o','s','e','s',' ','p','i','p','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','f','i','l','e','-','s','i','z','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','A','u','t','o','m','a','t','i','c','a','l','l','y',' ','d','e','t','e','r','m','i','n','e',' ','t','h','e',' ','s','i','z','e',' ','o','f',' ','t','h','e',' ','i','n','p','u','t',' ','f','i','l','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','f','o','l','l','o','w','-','n','a','m','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','T','h','e',' ','F',' ','c','o','m','m','a','n','d',' ','c','h','a','n','g','e','s',' ','f','i','l','e','s',' ','i','f',' ','t','h','e',' ','i','n','p','u','t',' ','f','i','l','e',' ','i','s',' ','r','e','n','a','m','e','d','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','h','e','a','d','e','r','=','[','_','\b','N','[',',','_','\b','M',']',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','U','s','e',' ','N',' ','l','i','n','e','s',' ','a','n','d',' ','M',' ','c','o','l','u','m','n','s',' ','t','o',' ','d','i','s','p','l','a','y',' ','f','i','l','e',' ','h','e','a','d','e','r','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','i','n','c','s','e','a','r','c','h','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','a','r','c','h',' ','f','i','l','e',' ','a','s',' ','e','a','c','h',' ','p','a','t','t','e','r','n',' ','c','h','a','r','a','c','t','e','r',' ','i','s',' ','t','y','p','e','d',' ','i','n','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','i','n','t','r','=','_','\b','C','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','U','s','e',' ','_','\b','C',' ','i','n','s','t','e','a','d',' ','o','f',' ','^','X',' ','t','o',' ','i','n','t','e','r','r','u','p','t',' ','a',' ','r','e','a','d','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','l','i','n','e','-','n','u','m','-','w','i','d','t','h','=','_','\b','N','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','t','h','e',' ','w','i','d','t','h',' ','o','f',' ','t','h','e',' ','-','N',' ','l','i','n','e',' ','n','u','m','b','e','r',' ','f','i','e','l','d',' ','t','o',' ','_','\b','N',' ','c','h','a','r','a','c','t','e','r','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','m','o','d','e','l','i','n','e','s','=','_','\b','N','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','a','d',' ','_','\b','N',' ','l','i','n','e','s',' ','f','r','o','m',' ','t','h','e',' ','i','n','p','u','t',' ','f','i','l','e',' ','a','n','d',' ','l','o','o','k',' ','f','o','r',' ','v','i','m',' ','m','o','d','e','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','m','o','u','s','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','n','a','b','l','e',' ','m','o','u','s','e',' ','i','n','p','u','t','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','n','o','-','k','e','y','p','a','d','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','s','e','n','d',' ','t','e','r','m','c','a','p',' ','k','e','y','p','a','d',' ','i','n','i','t','/','d','e','i','n','i','t',' ','s','t','r','i','n','g','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','n','o','-','h','i','s','t','d','u','p','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','m','o','v','e',' ','d','u','p','l','i','c','a','t','e','s',' ','f','r','o','m',' ','c','o','m','m','a','n','d',' ','h','i','s','t','o','r','y','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','n','o','-','n','u','m','b','e','r','-','h','e','a','d','e','r','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','g','i','v','e',' ','l','i','n','e',' ','n','u','m','b','e','r','s',' ','t','o',' ','h','e','a','d','e','r',' ','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','n','o','-','s','e','a','r','c','h','-','h','e','a','d','e','r','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','o','n','\'','t',' ','s','e','a','r','c','h',' ','i','n',' ','h','e','a','d','e','r',' ','l','i','n','e','s',' ','o','r',' ','c','o','l','u','m','n','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','n','o','-','v','b','e','l','l','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','a','b','l','e',' ','t','h','e',' ','t','e','r','m','i','n','a','l','\'','s',' ','v','i','s','u','a','l',' ','b','e','l','l','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','r','e','d','r','a','w','-','o','n','-','q','u','i','t','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','d','r','a','w',' ','f','i','n','a','l',' ','s','c','r','e','e','n',' ','w','h','e','n',' ','q','u','i','t','t','i','n','g','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','r','s','c','r','o','l','l','=','_','\b','C','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','t','h','e',' ','c','h','a','r','a','c','t','e','r',' ','u','s','e','d',' ','t','o',' ','m','a','r','k',' ','t','r','u','n','c','a','t','e','d',' ','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','s','a','v','e','-','m','a','r','k','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','R','e','t','a','i','n',' ','m','a','r','k','s',' ','a','c','r','o','s','s',' ','i','n','v','o','c','a','t','i','o','n','s',' ','o','f',' ','l','e','s','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','s','e','a','r','c','h','-','o','p','t','i','o','n','s','=','[','E','F','K','N','R','W','-',']','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','d','e','f','a','u','l','t',' ','o','p','t','i','o','n','s',' ','f','o','r',' ','e','v','e','r','y',' ','s','e','a','r','c','h','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','s','h','o','w','-','p','r','e','p','r','o','c','-','e','r','r','o','r','s','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','i','s','p','l','a','y',' ','a',' ','m','e','s','s','a','g','e',' ','i','f',' ','p','r','e','p','r','o','c','e','s','s','o','r',' ','e','x','i','t','s',' ','w','i','t','h',' ','a','n',' ','e','r','r','o','r',' ','s','t','a','t','u','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','p','r','o','c','-','b','a','c','k','s','p','a','c','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','P','r','o','c','e','s','s',' ','b','a','c','k','s','p','a','c','e','s',' ','f','o','r',' ','b','o','l','d','/','u','n','d','e','r','l','i','n','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','S','P','E','C','I','A','L','-','B','A','C','K','S','P','A','C','E','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','T','r','e','a','t',' ','b','a','c','k','s','p','a','c','e','s',' ','a','s',' ','c','o','n','t','r','o','l',' ','c','h','a','r','a','c','t','e','r','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','p','r','o','c','-','r','e','t','u','r','n','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','D','e','l','e','t','e',' ','c','a','r','r','i','a','g','e',' ','r','e','t','u','r','n','s',' ','b','e','f','o','r','e',' ','n','e','w','l','i','n','e','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','S','P','E','C','I','A','L','-','R','E','T','U','R','N','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','T','r','e','a','t',' ','c','a','r','r','i','a','g','e',' ','r','e','t','u','r','n','s',' ','a','s',' ','c','o','n','t','r','o','l',' ','c','h','a','r','a','c','t','e','r','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','p','r','o','c','-','t','a','b','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','x','p','a','n','d',' ','t','a','b','s',' ','t','o',' ','s','p','a','c','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','S','P','E','C','I','A','L','-','T','A','B','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','T','r','e','a','t',' ','t','a','b','s',' ','a','s',' ','c','o','n','t','r','o','l',' ','c','h','a','r','a','c','t','e','r','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','s','t','a','t','u','s','-','c','o','l','-','w','i','d','t','h','=','_','\b','N','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','e','t',' ','t','h','e',' ','w','i','d','t','h',' ','o','f',' ','t','h','e',' ','-','J',' ','s','t','a','t','u','s',' ','c','o','l','u','m','n',' ','t','o',' ','_','\b','N',' ','c','h','a','r','a','c','t','e','r','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','s','t','a','t','u','s','-','l','i','n','e','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','H','i','g','h','l','i','g','h','t',' ','o','r',' ','c','o','l','o','r',' ','t','h','e',' ','e','n','t','i','r','e',' ','l','i','n','e',' ','c','o','n','t','a','i','n','i','n','g',' ','a',' ','m','a','r','k','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','u','s','e','-','b','a','c','k','s','l','a','s','h','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','S','u','b','s','e','q','u','e','n','t',' ','o','p','t','i','o','n','s',' ','u','s','e',' ','b','a','c','k','s','l','a','s','h',' ','a','s',' ','e','s','c','a','p','e',' ','c','h','a','r','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','u','s','e','-','c','o','l','o','r','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','n','a','b','l','e','s',' ','c','o','l','o','r','e','d',' ','t','e','x','t','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','w','h','e','e','l','-','l','i','n','e','s','=','_','\b','N','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','E','a','c','h',' ','c','l','i','c','k',' ','o','f',' ','t','h','e',' ','m','o','u','s','e',' ','w','h','e','e','l',' ','m','o','v','e','s',' ','_','\b','N',' ','l','i','n','e','s','.','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','-','-','w','o','r','d','w','r','a','p','\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','W','r','a','p',' ','l','i','n','e','s',' ','a','t',' ','s','p','a','c','e','s','.','\n',
'\n',
'\n',
' ','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','-','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ','L','\b','L','I','\b','I','N','\b','N','E','\b','E',' ','E','\b','E','D','\b','D','I','\b','I','T','\b','T','I','\b','I','N','\b','N','G','\b','G','\n',
'\n',
' ',' ',' ',' ',' ',' ',' ',' ','T','h','e','s','e',' ','k','e','y','s',' ','c','a','n',' ','b','e',' ','u','s','e','d',' ','t','o',' ','e','d','i','t',' ','t','e','x','t',' ','b','e','i','n','g',' ','e','n','t','e','r','e','d',' ','\n',
' ',' ',' ',' ',' ',' ',' ',' ','o','n',' ','t','h','e',' ','"','c','o','m','m','a','n','d',' ','l','i','n','e','"',' ','a','t',' ','t','h','e',' ','b','o','t','t','o','m',' ','o','f',' ','t','h','e',' ','s','c','r','e','e','n','.','\n',
'\n',
' ','R','i','g','h','t','A','r','r','o','w',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','E','S','C','-','l',' ','.','.','.',' ','M','o','v','e',' ','c','u','r','s','o','r',' ','r','i','g','h','t',' ','o','n','e',' ','c','h','a','r','a','c','t','e','r','.','\n',
' ','L','e','f','t','A','r','r','o','w',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','E','S','C','-','h',' ','.','.','.',' ','M','o','v','e',' ','c','u','r','s','o','r',' ','l','e','f','t',' ','o','n','e',' ','c','h','a','r','a','c','t','e','r','.','\n',
' ','c','t','r','l','-','R','i','g','h','t','A','r','r','o','w',' ',' ','E','S','C','-','R','i','g','h','t','A','r','r','o','w',' ',' ','E','S','C','-','w',' ','.','.','.',' ','M','o','v','e',' ','c','u','r','s','o','r',' ','r','i','g','h','t',' ','o','n','e',' ','w','o','r','d','.','\n',
' ','c','t','r','l','-','L','e','f','t','A','r','r','o','w',' ',' ',' ','E','S','C','-','L','e','f','t','A','r','r','o','w',' ',' ',' ','E','S','C','-','b',' ','.','.','.',' ','M','o','v','e',' ','c','u','r','s','o','r',' ','l','e','f','t',' ','o','n','e',' ','w','o','r','d','.','\n',
' ','H','O','M','E',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','E','S','C','-','0',' ','.','.','.',' ','M','o','v','e',' ','c','u','r','s','o','r',' ','t','o',' ','s','t','a','r','t',' ','o','f',' ','l','i','n','e','.','\n',
' ','E','N','D',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','E','S','C','-','$',' ','.','.','.',' ','M','o','v','e',' ','c','u','r','s','o','r',' ','t','o',' ','e','n','d',' ','o','f',' ','l','i','n','e','.','\n',
' ','B','A','C','K','S','P','A','C','E',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','D','e','l','e','t','e',' ','c','h','a','r',' ','t','o',' ','l','e','f','t',' ','o','f',' ','c','u','r','s','o','r','.','\n',
' ','D','E','L','E','T','E',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','E','S','C','-','x',' ','.','.','.',' ','D','e','l','e','t','e',' ','c','h','a','r',' ','u','n','d','e','r',' ','c','u','r','s','o','r','.','\n',
' ','c','t','r','l','-','B','A','C','K','S','P','A','C','E',' ',' ',' ','E','S','C','-','B','A','C','K','S','P','A','C','E',' ','.','.','.','.','.','.','.','.','.','.','.',' ','D','e','l','e','t','e',' ','w','o','r','d',' ','t','o',' ','l','e','f','t',' ','o','f',' ','c','u','r','s','o','r','.','\n',
' ','c','t','r','l','-','D','E','L','E','T','E',' ','.','.','.','.',' ','E','S','C','-','D','E','L','E','T','E',' ','.','.','.','.',' ','E','S','C','-','X',' ','.','.','.',' ','D','e','l','e','t','e',' ','w','o','r','d',' ','u','n','d','e','r',' ','c','u','r','s','o','r','.','\n',
' ','c','t','r','l','-','U',' ','.','.','.','.','.','.','.','.','.',' ','E','S','C',' ','(','M','S','-','D','O','S',' ','o','n','l','y',')',' ','.','.','.','.','.','.','.',' ','D','e','l','e','t','e',' ','e','n','t','i','r','e',' ','l','i','n','e','.','\n',
' ','U','p','A','r','r','o','w',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','E','S','C','-','k',' ','.','.','.',' ','R','e','t','r','i','e','v','e',' ','p','r','e','v','i','o','u','s',' ','c','o','m','m','a','n','d',' ','l','i','n','e','.','\n',
' ','D','o','w','n','A','r','r','o','w',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','E','S','C','-','j',' ','.','.','.',' ','R','e','t','r','i','e','v','e',' ','n','e','x','t',' ','c','o','m','m','a','n','d',' ','l','i','n','e','.','\n',
' ','T','A','B',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','C','o','m','p','l','e','t','e',' ','f','i','l','e','n','a','m','e',' ','&',' ','c','y','c','l','e','.','\n',
' ','S','H','I','F','T','-','T','A','B',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','E','S','C','-','T','A','B',' ',' ',' ','C','o','m','p','l','e','t','e',' ','f','i','l','e','n','a','m','e',' ','&',' ','r','e','v','e','r','s','e',' ','c','y','c','l','e','.','\n',
' ','c','t','r','l','-','L',' ','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.','.',' ','C','o','m','p','l','e','t','e',' ','f','i','l','e','n','a','m','e',',',' ','l','i','s','t',' ','a','l','l','.','\n',
0 };
constant int size_helpdata = sizeof(helpdata) - 1;

358
third_party/less/ifile.c vendored Normal file
View file

@ -0,0 +1,358 @@
/*
* Copyright (C) 1984-2023 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 */
char *h_rfilename; /* Canonical 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 */
void *h_altpipe; /* Alt pipe */
char *h_altfilename; /* Alt filename */
};
/*
* 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, NULL, 0, 0, '\0',
{ NULL_POSITION, 0 } };
static int ifiles = 0;
static void 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(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(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(char *filename, struct ifile *prev)
{
struct ifile *p;
/*
* Allocate and initialize structure.
*/
p = (struct ifile *) ecalloc(1, sizeof(struct ifile));
p->h_filename = save(filename);
p->h_rfilename = lrealpath(filename);
p->h_scrpos.pos = NULL_POSITION;
p->h_opened = 0;
p->h_hold = 0;
p->h_filestate = NULL;
p->h_altfilename = NULL;
p->h_altpipe = NULL;
link_ifile(p, prev);
/*
* {{ It's dodgy to call mark.c functions from here;
* there is potentially dangerous recursion.
* Probably need to revisit this design. }}
*/
mark_check_ifile(ext_ifile(p));
return (p);
}
/*
* Delete an existing ifile structure.
*/
public void del_ifile(IFILE h)
{
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_rfilename);
free(p->h_filename);
free(p);
}
/*
* Get the ifile after a given one in the list.
*/
public IFILE next_ifile(IFILE h)
{
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(IFILE h)
{
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 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(void)
{
return (ifiles);
}
/*
* Find an ifile structure, given a filename.
*/
static struct ifile * find_ifile(char *filename)
{
struct ifile *p;
char *rfilename = lrealpath(filename);
for (p = anchor.h_next; p != &anchor; p = p->h_next)
{
if (strcmp(rfilename, p->h_rfilename) == 0)
{
/*
* If given name is shorter than the name we were
* previously using for this file, adopt shorter name.
*/
if (strlen(filename) < strlen(p->h_filename))
{
free(p->h_filename);
p->h_filename = save(filename);
}
break;
}
}
free(rfilename);
if (p == &anchor)
p = NULL;
return (p);
}
/*
* 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(char *filename, IFILE prev)
{
struct ifile *p;
if ((p = find_ifile(filename)) == NULL)
p = new_ifile(filename, int_ifile(prev));
return (ext_ifile(p));
}
/*
* Get the display filename associated with a ifile.
*/
public char * get_filename(IFILE ifile)
{
if (ifile == NULL)
return (NULL);
return (int_ifile(ifile)->h_filename);
}
/*
* Get the canonical filename associated with a ifile.
*/
public char * get_real_filename(IFILE ifile)
{
if (ifile == NULL)
return (NULL);
return (int_ifile(ifile)->h_rfilename);
}
/*
* Get the index of the file associated with a ifile.
*/
public int 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 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 ifile, struct scrpos *scrpos)
{
*scrpos = int_ifile(ifile)->h_scrpos;
}
/*
* Mark the ifile as "opened".
*/
public void set_open(IFILE ifile)
{
int_ifile(ifile)->h_opened = 1;
}
/*
* Return whether the ifile has been opened previously.
*/
public int opened(IFILE ifile)
{
return (int_ifile(ifile)->h_opened);
}
public void hold_ifile(IFILE ifile, int incr)
{
int_ifile(ifile)->h_hold += incr;
}
public int held_ifile(IFILE ifile)
{
return (int_ifile(ifile)->h_hold);
}
public void * get_filestate(IFILE ifile)
{
return (int_ifile(ifile)->h_filestate);
}
public void set_filestate(IFILE ifile, void *filestate)
{
int_ifile(ifile)->h_filestate = filestate;
}
public void set_altpipe(IFILE ifile, void *p)
{
int_ifile(ifile)->h_altpipe = p;
}
public void *get_altpipe(IFILE ifile)
{
return (int_ifile(ifile)->h_altpipe);
}
public void set_altfilename(IFILE ifile, char *altfilename)
{
struct ifile *p = int_ifile(ifile);
if (p->h_altfilename != NULL && p->h_altfilename != altfilename)
free(p->h_altfilename);
p->h_altfilename = altfilename;
}
public char * get_altfilename(IFILE ifile)
{
return (int_ifile(ifile)->h_altfilename);
}
#if 0
public void if_dump(void)
{
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

624
third_party/less/input.c vendored Normal file
View file

@ -0,0 +1,624 @@
/*
* Copyright (C) 1984-2023 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 hshift;
extern int quit_if_one_screen;
extern int sigs;
extern int ignore_eoi;
extern int status_col;
extern int wordwrap;
extern POSITION start_attnpos;
extern POSITION end_attnpos;
#if HILITE_SEARCH
extern int hilite_search;
extern int size_linebuf;
extern int show_attn;
#endif
/*
* Set the status column.
* base Position of first char in line.
* disp First visible char.
* Different than base_pos if line is shifted.
* edisp Last visible char.
* eol End of line. Normally the newline.
* Different than edisp if line is chopped.
*/
static void init_status_col(POSITION base_pos, POSITION disp_pos, POSITION edisp_pos, POSITION eol_pos)
{
int hl_before = (chop_line() && disp_pos != NULL_POSITION) ?
is_hilited_attr(base_pos, disp_pos, TRUE, NULL) : 0;
int hl_after = (chop_line()) ?
is_hilited_attr(edisp_pos, eol_pos, TRUE, NULL) : 0;
int attr;
char ch;
if (hl_before && hl_after)
{
attr = hl_after;
ch = '=';
} else if (hl_before)
{
attr = hl_before;
ch = '<';
} else if (hl_after)
{
attr = hl_after;
ch = '>';
} else
{
attr = is_hilited_attr(base_pos, eol_pos, TRUE, NULL);
ch = '*';
}
if (attr)
set_status_col(ch, attr);
}
/*
* 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_seg(POSITION curr_pos, int skipeol, int rscroll, int nochop)
{
POSITION base_pos;
POSITION new_pos;
POSITION edisp_pos = 0;
int c;
int blankline;
int endline;
int chopped;
int backchars;
POSITION wrap_pos;
int skipped_leading;
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();
plinestart(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();
if (wordwrap && (c == ' ' || c == '\t'))
{
do
{
new_pos++;
c = ch_forw_get();
} while (c == ' ' || c == '\t');
backchars = 1;
}
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');
wrap_pos = NULL_POSITION;
skipped_leading = FALSE;
/*
* Read each character in the line and append to the line buffer.
*/
chopped = FALSE;
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 && (nochop || !chop_line()) && hshift == 0)
{
new_pos -= backchars + 1;
endline = FALSE;
} else
endline = TRUE;
edisp_pos = new_pos;
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 (skipeol)
{
/* Read to end of line. */
edisp_pos = ch_tell();
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;
chopped = TRUE;
} else
{
if (!wordwrap)
new_pos = ch_tell() - backchars;
else
{
/*
* We're word-wrapping, so go back to the last space.
* However, if it's the space itself that couldn't fit,
* simply ignore it and any subsequent spaces.
*/
if (c == ' ' || c == '\t')
{
do
{
new_pos = ch_tell();
c = ch_forw_get();
} while (c == ' ' || c == '\t');
if (c == '\r')
c = ch_forw_get();
if (c == '\n')
new_pos = ch_tell();
} else if (wrap_pos == NULL_POSITION)
new_pos = ch_tell() - backchars;
else
{
new_pos = wrap_pos;
loadc();
}
}
endline = FALSE;
}
break;
}
if (wordwrap)
{
if (c == ' ' || c == '\t')
{
if (skipped_leading)
{
wrap_pos = ch_tell();
savec();
}
} else
skipped_leading = TRUE;
}
c = ch_forw_get();
}
#if HILITE_SEARCH
if (blankline && show_attn)
{
/* Add spurious space to carry possible attn hilite. */
pappend(' ', ch_tell()-1);
}
#endif
pdone(endline, rscroll && chopped, 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)
init_status_col(base_pos, line_position(), edisp_pos, new_pos);
#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);
}
public POSITION forw_line(POSITION curr_pos)
{
return forw_line_seg(curr_pos, (chop_line() || hshift > 0), TRUE, FALSE);
}
/*
* 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(POSITION curr_pos)
{
POSITION base_pos;
POSITION new_pos;
POSITION edisp_pos = 0;
POSITION begin_new_pos;
int c;
int endline;
int chopped;
int backchars;
POSITION wrap_pos;
int skipped_leading;
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();
plinestart(new_pos);
loop:
wrap_pos = NULL_POSITION;
skipped_leading = FALSE;
begin_new_pos = new_pos;
(void) ch_seek(new_pos);
chopped = FALSE;
for (;;)
{
c = ch_forw_get();
if (c == EOI || ABORT_SIGS())
{
null_line();
return (NULL_POSITION);
}
new_pos++;
if (c == '\n')
{
backchars = pflushmbc();
if (backchars > 0 && !chop_line() && hshift == 0)
{
backchars++;
goto shift;
}
endline = TRUE;
edisp_pos = new_pos;
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 (chop_line() || hshift > 0)
{
endline = TRUE;
chopped = TRUE;
quit_if_one_screen = FALSE;
edisp_pos = new_pos;
break;
}
shift:
if (!wordwrap)
{
pshift_all();
new_pos -= backchars;
} else
{
if (c == ' ' || c == '\t')
{
for (;;)
{
c = ch_forw_get();
if (c == ' ' || c == '\t')
new_pos++;
else
{
if (c == '\r')
{
c = ch_forw_get();
if (c == '\n')
new_pos++;
}
if (c == '\n')
new_pos++;
break;
}
}
if (new_pos >= curr_pos)
break;
pshift_all();
} else
{
pshift_all();
if (wrap_pos == NULL_POSITION)
new_pos -= backchars;
else
new_pos = wrap_pos;
}
}
goto loop;
}
if (wordwrap)
{
if (c == ' ' || c == '\t')
{
if (skipped_leading)
wrap_pos = new_pos;
} else
skipped_leading = TRUE;
}
if (new_pos >= curr_pos)
{
edisp_pos = new_pos;
break;
}
}
pdone(endline, chopped, 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)
init_status_col(base_pos, line_position(), edisp_pos, new_pos);
#endif
return (begin_new_pos);
}
/*
* Set attnpos.
*/
public void 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;
}

325
third_party/less/jump.c vendored Normal file
View file

@ -0,0 +1,325 @@
/*
* Copyright (C) 1984-2023 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(void)
{
POSITION pos;
POSITION end_pos;
if (ch_end_seek())
{
error("Cannot seek to end of file", NULL_PARG);
return;
}
end_pos = ch_tell();
if (position(sc_height-1) == end_pos)
{
eof_bell();
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();
pos = back_line(end_pos);
if (pos == NULL_POSITION)
jump_loc(ch_zero(), 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(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)
{
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(void)
{
struct scrpos scrpos;
/*
* Start at the line currently at the top of the screen
* and redisplay the screen.
*/
get_scrpos(&scrpos, TOP);
pos_clear();
if (scrpos.pos == NULL_POSITION)
/* Screen hasn't been drawn yet. */
jump_loc(ch_zero(), 1);
else
jump_loc(scrpos.pos, scrpos.ln);
}
/*
* Jump to a specified percentage into the file.
*/
public void 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(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(POSITION pos, int sline)
{
int nline;
int sindex;
POSITION tpos;
POSITION bpos;
/*
* Normalize sline.
*/
sindex = sindex_from_sline(sline);
if ((nline = onscreen(pos)) >= 0)
{
/*
* The line is currently displayed.
* Just scroll there.
*/
nline -= sindex;
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 < sindex; 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-sindex+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, sindex-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
* sindex-th line on the screen.
*/
for (nline = sindex; 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);
}
}

635
third_party/less/less.h vendored Normal file
View file

@ -0,0 +1,635 @@
/*
* Copyright (C) 1984-2023 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 "defines.h"
#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_CONST
#define constant const
#else
#define constant
#endif
#define public /* PUBLIC FUNCTION */
/* Library function declarations */
#if HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if HAVE_STDIO_H
#include <stdio.h>
#endif
#if HAVE_FCNTL_H
#include <fcntl.h>
#endif
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_CTYPE_H
#include <ctype.h>
#endif
#if HAVE_WCTYPE_H
#include <wctype.h>
#endif
#if HAVE_LIMITS_H
#include <limits.h>
#endif
#if HAVE_STDINT_H
#include <stdint.h>
#endif
#if HAVE_STDLIB_H
#include <stdlib.h>
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
#if HAVE_STDCKDINT_H
#include <stdckdint.h>
#else
/*
* These substitutes for C23 stdckdint macros do not set *R on overflow,
* and they assume A and B are nonnegative. That is good enough for us.
*/
#define ckd_add(r, a, b) help_ckd_add(r, a, b, sizeof *(r), signed_expr(*(r)))
#define ckd_mul(r, a, b) help_ckd_mul(r, a, b, sizeof *(r), signed_expr(*(r)))
/* True if the integer expression E, after promotion, is signed. */
#define signed_expr(e) ((TRUE ? 0 : e) - 1 < 0)
#endif
#if defined UINTMAX_MAX
typedef uintmax_t uintmax;
#elif defined ULLONG_MAX
typedef unsigned long long uintmax;
#else
typedef unsigned long uintmax;
#endif
/* OS-specific includes */
#ifdef _OSK
#include <modes.h>
#include <strings.h>
#endif
#ifdef __TANDEM
#include <floss.h>
#endif
#if MSDOS_COMPILER==WIN32C || OS2
#include <io.h>
#endif
#if MSDOS_COMPILER==DJGPPC
#include <io.h>
#include <sys/exceptn.h>
#include <conio.h>
#include <pc.h>
#endif
#if !HAVE_STDLIB_H
char *getenv();
off_t lseek();
void *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 /* Default min printing width of a line number */
#define MAX_LINENUM_WIDTH 16 /* Max width of a line number */
#define MAX_STATUSCOL_WIDTH 4 /* Max width of the status column */
#define MAX_UTF_CHAR_LEN 6 /* Max bytes in one UTF-8 char */
#define MAX_PRCHAR_LEN 31 /* Max chars in prchar() result */
#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
/*
* Flags for creat()
*/
#if MSDOS_COMPILER
#define CREAT_RW (S_IREAD|S_IWRITE)
#else
#define CREAT_RW 0644
#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*
#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;
};
typedef union parg
{
char *p_string;
int p_int;
LINENUM p_linenum;
char p_char;
} 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;
};
#if HAVE_POLL
typedef short POLL_EVENTS;
#endif
#define EOI (-1)
#define READ_ERR (-1)
#define READ_INTR (-2)
#define READ_AGAIN (-3)
/*
* A fraction is represented by a long n; the fraction is n/NUM_FRAC_DENOM.
* To avoid overflow problems, 0 <= n < NUM_FRAC_DENUM <= LONG_MAX/100.
*/
#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_INCR (1 << 3) /* Incremental search */
#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_WRAP (1 << 15) /* Wrap-around search (continue at BOF/EOF) */
#define SRCH_SUBSEARCH(i) (1 << (16+(i))) /* Search for subpattern */
/* {{ Depends on NUM_SEARCH_COLORS==5 }} */
#define SRCH_SUBSEARCH_ALL (SRCH_SUBSEARCH(1)|SRCH_SUBSEARCH(2)|SRCH_SUBSEARCH(3)|SRCH_SUBSEARCH(4)|SRCH_SUBSEARCH(5))
#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) */
#define AT_COLOR_SHIFT 8
#define AT_NUM_COLORS 16
#define AT_COLOR ((AT_NUM_COLORS-1) << AT_COLOR_SHIFT)
#define AT_COLOR_ATTN (1 << AT_COLOR_SHIFT)
#define AT_COLOR_BIN (2 << AT_COLOR_SHIFT)
#define AT_COLOR_CTRL (3 << AT_COLOR_SHIFT)
#define AT_COLOR_ERROR (4 << AT_COLOR_SHIFT)
#define AT_COLOR_LINENUM (5 << AT_COLOR_SHIFT)
#define AT_COLOR_MARK (6 << AT_COLOR_SHIFT)
#define AT_COLOR_PROMPT (7 << AT_COLOR_SHIFT)
#define AT_COLOR_RSCROLL (8 << AT_COLOR_SHIFT)
#define AT_COLOR_HEADER (9 << AT_COLOR_SHIFT)
#define AT_COLOR_SEARCH (10 << AT_COLOR_SHIFT)
#define AT_COLOR_SUBSEARCH(i) ((10+(i)) << AT_COLOR_SHIFT)
#define NUM_SEARCH_COLORS (AT_NUM_COLORS-10-1)
typedef enum { CT_NULL, CT_4BIT, CT_6BIT } COLOR_TYPE;
typedef enum {
CV_BLUE = 1,
CV_GREEN = 2,
CV_RED = 4,
CV_BRIGHT = 8,
CV_NOCHANGE = -2,
CV_ERROR = -1
} COLOR_VALUE;
/* ANSI states */
#define ANSI_MID 1
#define ANSI_ERR 2
#define ANSI_END 3
#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 ESCS "\33"
#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))
#ifdef EXIT_SUCCESS
#define QUIT_OK EXIT_SUCCESS
#else
#define QUIT_OK 0
#endif
#ifdef EXIT_FAILURE
#define QUIT_ERROR EXIT_FAILURE
#define QUIT_INTERRUPT (EXIT_FAILURE+1)
#else
#define QUIT_ERROR 1
#define QUIT_INTERRUPT 2
#endif
#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
/* X11 mouse reporting definitions */
#define X11MOUSE_BUTTON1 0 /* Left button press */
#define X11MOUSE_BUTTON2 1 /* Middle button press */
#define X11MOUSE_BUTTON3 2 /* Right button press */
#define X11MOUSE_BUTTON_REL 3 /* Button release */
#define X11MOUSE_WHEEL_UP 0x40 /* Wheel scroll up */
#define X11MOUSE_WHEEL_DOWN 0x41 /* Wheel scroll down */
#define X11MOUSE_OFFSET 0x20 /* Added to button & pos bytes to create a char */
#if LESSTEST
#define LESS_DUMP_CHAR CONTROL(']')
#endif
struct mlist;
struct loption;
struct hilite_tree;
struct ansi_state;
#include "pattern.h"
#include "xbuf.h"
#include "funcs.h"
/* Functions not included in funcs.h */
void postoa(POSITION, char*, int);
void linenumtoa(LINENUM, char*, int);
void inttoa(int, char*, int);
int lstrtoi(char*, char**, int);
POSITION lstrtopos(char*, char**, int);
unsigned long lstrtoul(char*, char**, int);
#if MSDOS_COMPILER==WIN32C
int pclose(FILE*);
#endif

282
third_party/less/lessecho.c vendored Normal file
View file

@ -0,0 +1,282 @@
/*
* Copyright (C) 1984-2023 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 = NULL;
static int num_metachars = 0;
static int size_metachars = 0;
static void pr_usage(void)
{
fprintf(stderr,
"usage: lessecho [-ox] [-cx] [-pn] [-dn] [-mx] [-nn] [-ex] [-fn] [-a] file ...\n");
}
static void 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(char *s)
{
fprintf(stderr, "%s\n", s);
exit(1);
}
static long lstrtol(char *s, char **pend, int radix)
{
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);
}
static void add_metachar(int ch)
{
if (num_metachars+1 >= size_metachars)
{
char *p;
size_metachars = (size_metachars > 0) ? size_metachars*2 : 16;
p = (char *) malloc(size_metachars);
if (p == NULL)
pr_error("Cannot allocate memory");
if (metachars != NULL)
{
strcpy(p, metachars);
free(metachars);
}
metachars = p;
}
metachars[num_metachars++] = ch;
metachars[num_metachars] = '\0';
}
static int is_metachar(int ch)
{
return (metachars != NULL && strchr(metachars, ch) != NULL);
}
#if !HAVE_STRCHR
char * strchr(char *s, char c)
{
for ( ; *s != '\0'; s++)
if (*s == c)
return (s);
if (c == '\0')
return (s);
return (NULL);
}
#endif
int main(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, &s, 0);
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, &s, 0);
meta_escape_buf[1] = '\0';
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, &s, 0);
if (s == arg)
pr_error("Missing number after -p");
break;
case 'm':
add_metachar(*++arg);
break;
case 'n':
add_metachar(lstrtol(++arg, &s, 0));
if (s == arg)
pr_error("Missing number after -n");
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 (is_metachar(*s))
{
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 (is_metachar(*s))
printf("%s", meta_escape);
printf("%c", *s);
}
}
if (argc > 0)
printf(" ");
else
printf("\n");
}
return (0);
}

357
third_party/less/lesskey.c vendored Normal file
View file

@ -0,0 +1,357 @@
/*
* Copyright (C) 1984-2023 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 <whitespace> action [chars] <newline>
*
* "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> <action>
* or
* string <0> <action|A_EXTRA> chars <0>
*
* "string" is the command string.
* "<0>" is one null byte.
* "<action>" 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 "defines.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "lesskey.h"
#include "cmd.h"
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 ;
extern char version[];
static void usage(void)
{
fprintf(stderr, "usage: lesskey [-o output] [input]\n");
exit(1);
}
void lesskey_parse_error(char *s)
{
fprintf(stderr, "%s\n", s);
}
int lstrtoi(char *buf, char **ebuf, int radix)
{
return (int) strtol(buf, ebuf, radix);
}
void out_of_memory(void)
{
fprintf(stderr, "lesskey: cannot allocate memory\n");
exit(1);
}
void * ecalloc(int count, unsigned int size)
{
void *p;
p = calloc(count, size);
if (p == NULL)
out_of_memory();
return (p);
}
static char * mkpathname(char *dirname, char *filename)
{
char *pathname;
pathname = ecalloc(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(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.
*/
static void 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;
}
/*
* Output some bytes.
*/
static void fputbytes(FILE *fd, char *buf, int len)
{
while (len-- > 0)
{
fwrite(buf, sizeof(char), 1, fd);
buf++;
}
}
/*
* Output an integer, in special KRADIX form.
*/
static void fputint(FILE *fd, unsigned int val)
{
char c;
if (val >= KRADIX*KRADIX)
{
fprintf(stderr, "error: cannot write %d, max %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);
}
int main(int argc, char *argv[])
{
struct lesskey_tables tables;
FILE *out;
int errors;
#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);
}
}
#endif /* WIN32 */
/*
* Process command line arguments.
*/
parse_args(argc, argv);
errors = parse_lesskey(infile, &tables);
if (errors)
{
fprintf(stderr, "%d errors; no output produced\n", errors);
return (1);
}
fprintf(stderr, "NOTE: lesskey is deprecated.\n It is no longer necessary to run lesskey,\n when using less version 582 and later.\n");
/*
* Write the output file.
* If no output file was specified, use "$HOME/.less"
*/
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
return (1);
}
/* File header */
fputbytes(out, fileheader, sizeof(fileheader));
/* Command key section */
fputbytes(out, cmdsection, sizeof(cmdsection));
fputint(out, tables.cmdtable.buf.end);
fputbytes(out, (char *)tables.cmdtable.buf.data, tables.cmdtable.buf.end);
/* Edit key section */
fputbytes(out, editsection, sizeof(editsection));
fputint(out, tables.edittable.buf.end);
fputbytes(out, (char *)tables.edittable.buf.data, tables.edittable.buf.end);
/* Environment variable section */
fputbytes(out, varsection, sizeof(varsection));
fputint(out, tables.vartable.buf.end);
fputbytes(out, (char *)tables.vartable.buf.data, tables.vartable.buf.end);
/* File trailer */
fputbytes(out, endsection, sizeof(endsection));
fputbytes(out, filetrailer, sizeof(filetrailer));
fclose(out);
return (0);
}

63
third_party/less/lesskey.h vendored Normal file
View file

@ -0,0 +1,63 @@
/*
* Copyright (C) 1984-2023 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 "xbuf.h"
/*
* Format of a lesskey file:
*
* LESSKEY_MAGIC (4 bytes)
* sections...
* END_LESSKEY_MAGIC (4 bytes)
*
* Each section is:
*
* section_MAGIC (1 byte)
* section_length (2 bytes)
* key table (section_length bytes)
*/
#define C0_LESSKEY_MAGIC '\0'
#define C1_LESSKEY_MAGIC 'M'
#define C2_LESSKEY_MAGIC '+'
#define C3_LESSKEY_MAGIC 'G'
#define CMD_SECTION 'c'
#define EDIT_SECTION 'e'
#define VAR_SECTION 'v'
#define END_SECTION 'x'
#define C0_END_LESSKEY_MAGIC 'E'
#define C1_END_LESSKEY_MAGIC 'n'
#define C2_END_LESSKEY_MAGIC 'd'
/* */
#define KRADIX 64
struct lesskey_cmdname
{
char *cn_name;
int cn_action;
};
struct lesskey_table
{
struct lesskey_cmdname *names;
struct xbuffer buf;
int is_var;
};
struct lesskey_tables
{
struct lesskey_table *currtable;
struct lesskey_table cmdtable;
struct lesskey_table edittable;
struct lesskey_table vartable;
};
extern int parse_lesskey(char *infile, struct lesskey_tables *tables);

651
third_party/less/lesskey_parse.c vendored Normal file
View file

@ -0,0 +1,651 @@
/*
* Copyright (C) 1984-2023 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 "defines.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "lesskey.h"
#include "cmd.h"
#include "xbuf.h"
#define CONTROL(c) ((c)&037)
#define ESC CONTROL('[')
extern void lesskey_parse_error(char *msg);
extern char *homefile(char *filename);
extern void *ecalloc(int count, unsigned int size);
extern int lstrtoi(char *str, char **end, int radix);
extern char version[];
static int linenum;
static int errors;
static int less_version = 0;
static char *lesskey_file;
static struct lesskey_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 },
{ "clear-mark", A_CLRMARK },
{ "debug", A_DEBUG },
{ "digit", A_DIGIT },
{ "display-flag", A_DISP_OPTION },
{ "display-option", A_DISP_OPTION },
{ "end", A_GOEND },
{ "end-scroll", A_RRSHIFT },
{ "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 },
{ "no-scroll", A_LLSHIFT },
{ "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 },
{ "set-mark-bottom", A_SETMARKBOT },
{ "shell", A_SHELL },
{ "pshell", A_PSHELL },
{ "status", A_STAT },
{ "toggle-flag", A_OPT_TOGGLE },
{ "toggle-option", A_OPT_TOGGLE },
{ "undo-hilite", A_UNDO_SEARCH },
{ "clear-search", A_CLR_SEARCH },
{ "version", A_VERSION },
{ "visual", A_VISUAL },
{ NULL, 0 }
};
static struct lesskey_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 }
};
/*
* Print a parse error message.
*/
static void parse_error(char *fmt, char *arg1)
{
char buf[1024];
int n = snprintf(buf, sizeof(buf), "%s: line %d: ", lesskey_file, linenum);
if (n >= 0 && n < sizeof(buf))
snprintf(buf+n, sizeof(buf)-n, fmt, arg1);
++errors;
lesskey_parse_error(buf);
}
/*
* Initialize lesskey_tables.
*/
static void init_tables(struct lesskey_tables *tables)
{
tables->currtable = &tables->cmdtable;
tables->cmdtable.names = cmdnames;
tables->cmdtable.is_var = 0;
xbuf_init(&tables->cmdtable.buf);
tables->edittable.names = editnames;
tables->edittable.is_var = 0;
xbuf_init(&tables->edittable.buf);
tables->vartable.names = NULL;
tables->vartable.is_var = 1;
xbuf_init(&tables->vartable.buf);
}
#define CHAR_STRING_LEN 8
static char * char_string(char *buf, int ch, int lit)
{
if (lit || (ch >= 0x20 && ch < 0x7f))
{
buf[0] = ch;
buf[1] = '\0';
} else
{
snprintf(buf, CHAR_STRING_LEN, "\\x%02x", ch);
}
return buf;
}
/*
* Increment char pointer by one up to terminating nul byte.
*/
static char * increment_pointer(char *p)
{
if (*p == '\0')
return p;
return p+1;
}
/*
* Parse one character of a string.
*/
static char * tstr(char **pp, int xlate)
{
char *p;
char ch;
int i;
static char buf[CHAR_STRING_LEN];
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;
return char_string(buf, ch, 1);
case 'b':
*pp = p+1;
return ("\b");
case 'e':
*pp = p+1;
return char_string(buf, ESC, 1);
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 'b': ch = SK_BACKSPACE; break;
case 'B': ch = SK_CTL_BACKSPACE; break;
case 'd': ch = SK_DOWN_ARROW; break;
case 'D': ch = SK_PAGE_DOWN; break;
case 'e': ch = SK_END; break;
case 'h': ch = SK_HOME; break;
case 'i': ch = SK_INSERT; break;
case 'l': ch = SK_LEFT_ARROW; break;
case 'L': ch = SK_CTL_LEFT_ARROW; break;
case 'r': ch = SK_RIGHT_ARROW; break;
case 'R': ch = SK_CTL_RIGHT_ARROW; break;
case 't': ch = SK_BACKTAB; break;
case 'u': ch = SK_UP_ARROW; break;
case 'U': ch = SK_PAGE_UP; break;
case 'x': ch = SK_DELETE; break;
case 'X': ch = SK_CTL_DELETE; break;
case '1': ch = SK_F1; break;
default:
parse_error("invalid escape sequence \"\\k%s\"", char_string(buf, *p, 0));
*pp = increment_pointer(p);
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 = increment_pointer(p);
char_string(buf, *p, 1);
if (xlate && buf[0] == CONTROL('K'))
return tstr_control_k;
return (buf);
}
case '^':
/*
* Caret means CONTROL.
*/
*pp = increment_pointer(p+1);
char_string(buf, CONTROL(p[1]), 1);
if (xlate && buf[0] == CONTROL('K'))
return tstr_control_k;
return (buf);
}
*pp = increment_pointer(p);
char_string(buf, *p, 1);
if (xlate && buf[0] == CONTROL('K'))
return tstr_control_k;
return (buf);
}
static int issp(char ch)
{
return (ch == ' ' || ch == '\t');
}
/*
* Skip leading spaces in a string.
*/
static char * skipsp(char *s)
{
while (issp(*s))
s++;
return (s);
}
/*
* Skip non-space characters in a string.
*/
static char * skipnsp(char *s)
{
while (*s != '\0' && !issp(*s))
s++;
return (s);
}
/*
* Clean up an input line:
* strip off the trailing newline & any trailing # comment.
*/
static char * clean_line(char *s)
{
int i;
s = skipsp(s);
for (i = 0; s[i] != '\0' && s[i] != '\n' && s[i] != '\r'; i++)
if (s[i] == '#' && (i == 0 || s[i-1] != '\\'))
break;
s[i] = '\0';
return (s);
}
/*
* Add a byte to the output command table.
*/
static void add_cmd_char(unsigned char c, struct lesskey_tables *tables)
{
xbuf_add_byte(&tables->currtable->buf, c);
}
static void erase_cmd_char(struct lesskey_tables *tables)
{
xbuf_pop(&tables->currtable->buf);
}
/*
* Add a string to the output command table.
*/
static void add_cmd_str(char *s, struct lesskey_tables *tables)
{
for ( ; *s != '\0'; s++)
add_cmd_char(*s, tables);
}
/*
* Does a given version number match the running version?
* Operator compares the running version to the given version.
*/
static int match_version(char op, int ver)
{
switch (op)
{
case '>': return less_version > ver;
case '<': return less_version < ver;
case '+': return less_version >= ver;
case '-': return less_version <= ver;
case '=': return less_version == ver;
case '!': return less_version != ver;
default: return 0; /* cannot happen */
}
}
/*
* Handle a #version line.
* If the version matches, return the part of the line that should be executed.
* Otherwise, return NULL.
*/
static char * version_line(char *s, struct lesskey_tables *tables)
{
char op;
int ver;
char *e;
char buf[CHAR_STRING_LEN];
s += strlen("#version");
s = skipsp(s);
op = *s++;
/* Simplify 2-char op to one char. */
switch (op)
{
case '<': if (*s == '=') { s++; op = '-'; } break;
case '>': if (*s == '=') { s++; op = '+'; } break;
case '=': if (*s == '=') { s++; } break;
case '!': if (*s == '=') { s++; } break;
default:
parse_error("invalid operator '%s' in #version line", char_string(buf, op, 0));
return (NULL);
}
s = skipsp(s);
ver = lstrtoi(s, &e, 10);
if (e == s)
{
parse_error("non-numeric version number in #version line", "");
return (NULL);
}
if (!match_version(op, ver))
return (NULL);
return (e);
}
/*
* See if we have a special "control" line.
*/
static char * control_line(char *s, struct lesskey_tables *tables)
{
#define PREFIX(str,pat) (strncmp(str,pat,strlen(pat)) == 0)
if (PREFIX(s, "#line-edit"))
{
tables->currtable = &tables->edittable;
return (NULL);
}
if (PREFIX(s, "#command"))
{
tables->currtable = &tables->cmdtable;
return (NULL);
}
if (PREFIX(s, "#env"))
{
tables->currtable = &tables->vartable;
return (NULL);
}
if (PREFIX(s, "#stop"))
{
add_cmd_char('\0', tables);
add_cmd_char(A_END_LIST, tables);
return (NULL);
}
if (PREFIX(s, "#version"))
{
return (version_line(s, tables));
}
return (s);
}
/*
* Find an action, given the name of the action.
*/
static int findaction(char *actname, struct lesskey_tables *tables)
{
int i;
for (i = 0; tables->currtable->names[i].cn_name != NULL; i++)
if (strcmp(tables->currtable->names[i].cn_name, actname) == 0)
return (tables->currtable->names[i].cn_action);
parse_error("unknown action: \"%s\"", actname);
return (A_INVALID);
}
/*
* Parse a line describing one key binding, of the form
* KEY ACTION [EXTRA]
* where KEY is the user key sequence, ACTION is the
* resulting less action, and EXTRA is an "extra" user
* key sequence injected after the action.
*/
static void parse_cmdline(char *p, struct lesskey_tables *tables)
{
char *actname;
int action;
char *s;
char c;
/*
* Parse the command string and store it in the current table.
*/
do
{
s = tstr(&p, 1);
add_cmd_str(s, tables);
} while (*p != '\0' && !issp(*p));
/*
* Terminate the command string with a null byte.
*/
add_cmd_char('\0', tables);
/*
* 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')
{
parse_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, tables);
/*
* See if an extra string follows the action name.
*/
*p = c;
p = skipsp(p);
if (*p == '\0')
{
add_cmd_char((unsigned char) action, tables);
} else
{
/*
* OR the special value A_EXTRA into the action byte.
* Put the extra string after the action byte.
*/
add_cmd_char((unsigned char) (action | A_EXTRA), tables);
while (*p != '\0')
add_cmd_str(tstr(&p, 0), tables);
add_cmd_char('\0', tables);
}
}
/*
* Parse a variable definition line, of the form
* NAME = VALUE
*/
static void parse_varline(char *line, struct lesskey_tables *tables)
{
char *s;
char *p = line;
char *eq;
eq = strchr(line, '=');
if (eq != NULL && eq > line && eq[-1] == '+')
{
/*
* Rather ugly way of handling a += line.
* {{ Note that we ignore the variable name and
* just append to the previously defined variable. }}
*/
erase_cmd_char(tables); /* backspace over the final null */
p = eq+1;
} else
{
do
{
s = tstr(&p, 0);
add_cmd_str(s, tables);
} while (*p != '\0' && !issp(*p) && *p != '=');
/*
* Terminate the variable name with a null byte.
*/
add_cmd_char('\0', tables);
p = skipsp(p);
if (*p++ != '=')
{
parse_error("missing = in variable definition", "");
return;
}
add_cmd_char(EV_OK|A_EXTRA, tables);
}
p = skipsp(p);
while (*p != '\0')
{
s = tstr(&p, 0);
add_cmd_str(s, tables);
}
add_cmd_char('\0', tables);
}
/*
* Parse a line from the lesskey file.
*/
static void parse_line(char *line, struct lesskey_tables *tables)
{
char *p;
/*
* See if it is a control line.
*/
p = control_line(line, tables);
if (p == NULL)
return;
/*
* Skip leading white space.
* Replace the final newline with a null byte.
* Ignore blank lines and comments.
*/
p = clean_line(p);
if (*p == '\0')
return;
if (tables->currtable->is_var)
parse_varline(p, tables);
else
parse_cmdline(p, tables);
}
/*
* Parse a lesskey source file and store result in tables.
*/
int parse_lesskey(char *infile, struct lesskey_tables *tables)
{
FILE *desc;
char line[1024];
if (infile == NULL)
infile = homefile(DEF_LESSKEYINFILE);
lesskey_file = infile;
init_tables(tables);
errors = 0;
linenum = 0;
if (less_version == 0)
less_version = lstrtoi(version, NULL, 10);
/*
* Open the input file.
*/
if (strcmp(infile, "-") == 0)
desc = stdin;
else if ((desc = fopen(infile, "r")) == NULL)
{
/* parse_error("cannot open lesskey file %s", infile); */
return (-1);
}
/*
* Read and parse the input file, one line at a time.
*/
while (fgets(line, sizeof(line), desc) != NULL)
{
++linenum;
parse_line(line, tables);
}
fclose(desc);
return (errors);
}

94
third_party/less/lglob.h vendored Normal file
View file

@ -0,0 +1,94 @@
/*
* Copyright (C) 1984-2023 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.
*/
/*
* Macros to define the method of doing filename "globbing".
* There are three possible mechanisms:
* 1. GLOB_LIST
* This defines a function that returns a list of matching filenames.
* 2. GLOB_NAME
* This defines a function that steps thru the list of matching
* filenames, returning one name each time it is called.
* 3. GLOB_STRING
* This defines a function that returns the complete list of
* matching filenames as a single space-separated string.
*/
#if OS2
#define DECL_GLOB_LIST(list) char **list; char **pp;
#define GLOB_LIST(filename,list) list = _fnexplode(filename)
#define GLOB_LIST_FAILED(list) list == NULL
#define SCAN_GLOB_LIST(list,p) pp = list; *pp != NULL; pp++
#define INIT_GLOB_LIST(list,p) p = *pp
#define GLOB_LIST_DONE(list) _fnexplodefree(list)
#else
#if MSDOS_COMPILER==DJGPPC
#define DECL_GLOB_LIST(list) glob_t list; int i;
#define GLOB_LIST(filename,list) glob(filename,GLOB_NOCHECK,0,&list)
#define GLOB_LIST_FAILED(list) 0
#define SCAN_GLOB_LIST(list,p) i = 0; i < list.gl_pathc; i++
#define INIT_GLOB_LIST(list,p) p = list.gl_pathv[i]
#define GLOB_LIST_DONE(list) globfree(&list)
#else
#if MSDOS_COMPILER==MSOFTC || MSDOS_COMPILER==BORLANDC
#define GLOB_FIRST_NAME(filename,fndp,h) h = _dos_findfirst(filename, ~_A_VOLID, fndp)
#define GLOB_FIRST_FAILED(handle) ((handle) != 0)
#define GLOB_NEXT_NAME(handle,fndp) _dos_findnext(fndp)
#define GLOB_NAME_DONE(handle)
#define GLOB_NAME name
#define DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) \
struct find_t fnd; \
char drive[_MAX_DRIVE]; \
char dir[_MAX_DIR]; \
char fname[_MAX_FNAME]; \
char ext[_MAX_EXT]; \
int handle;
#else
#if MSDOS_COMPILER==WIN32C && (defined(_MSC_VER) || defined(MINGW))
#define GLOB_FIRST_NAME(filename,fndp,h) h = _findfirst(filename, fndp)
#define GLOB_FIRST_FAILED(handle) ((handle) == -1)
#define GLOB_NEXT_NAME(handle,fndp) _findnext(handle, fndp)
#define GLOB_NAME_DONE(handle) _findclose(handle)
#define GLOB_NAME name
#define DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) \
struct _finddata_t fnd; \
char drive[_MAX_DRIVE]; \
char dir[_MAX_DIR]; \
char fname[_MAX_FNAME]; \
char ext[_MAX_EXT]; \
intptr_t handle;
#else
#if MSDOS_COMPILER==WIN32C && !defined(_MSC_VER) /* Borland C for Windows */
#define GLOB_FIRST_NAME(filename,fndp,h) h = findfirst(filename, fndp, ~FA_LABEL)
#define GLOB_FIRST_FAILED(handle) ((handle) != 0)
#define GLOB_NEXT_NAME(handle,fndp) findnext(fndp)
#define GLOB_NAME_DONE(handle)
#define GLOB_NAME ff_name
#define DECL_GLOB_NAME(fnd,drive,dir,fname,ext,handle) \
struct ffblk fnd; \
char drive[MAXDRIVE]; \
char dir[MAXDIR]; \
char fname[MAXFILE]; \
char ext[MAXEXT]; \
int handle;
#endif
#endif
#endif
#endif
#endif

1593
third_party/less/line.c vendored Normal file

File diff suppressed because it is too large Load diff

498
third_party/less/linenum.c vendored Normal file
View file

@ -0,0 +1,498 @@
/*
* Copyright (C) 1984-2023 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 */
public int scanning_eof = FALSE;
extern int linenums;
extern int sigs;
extern int sc_height;
extern int screen_trashed;
extern int header_lines;
extern int nonum_headers;
/*
* Initialize the line number structures.
*/
public void clr_linenum(void)
{
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(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 linenum, POSITION pos)
{
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(void)
{
ierror("Calculating line numbers", NULL_PARG);
}
static int loopcount;
#if HAVE_TIME
static time_type startime;
#endif
static void 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(void)
{
if (loopcount >= 0)
return;
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(POSITION pos)
{
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
loopcount = 0;
if (p == &anchor || pos - p->prev->pos < p->pos - pos)
{
/*
* Go forward.
*/
p = p->prev;
if (ch_seek(p->pos))
return (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);
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);
}
loopcount = 0;
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)
{
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(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);
}
/*
* Scan entire file, counting line numbers.
*/
public void scan_eof(void)
{
POSITION pos = ch_zero();
LINENUM linenum = 0;
if (ch_seek(0))
return;
ierror("Determining length of file", NULL_PARG);
/*
* scanning_eof prevents the "Waiting for data" message from
* overwriting "Determining length of file".
*/
scanning_eof = TRUE;
while (pos != NULL_POSITION)
{
/* For efficiency, only add one every 256 line numbers. */
if ((linenum++ % 256) == 0)
add_lnum(linenum, pos);
pos = forw_raw_line(pos, (char **)NULL, (int *)NULL);
if (ABORT_SIGS())
break;
}
scanning_eof = FALSE;
}
/*
* Return a line number adjusted for display
* (handles the --no-number-headers option).
*/
public LINENUM vlinenum(LINENUM linenum)
{
if (nonum_headers)
linenum = (linenum < header_lines) ? 0 : linenum - header_lines;
return linenum;
}

364
third_party/less/lsystem.c vendored Normal file
View file

@ -0,0 +1,364 @@
/*
* Copyright (C) 1984-2023 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 <signal.h>
#include "position.h"
#if MSDOS_COMPILER
#include <dos.h>
#if MSDOS_COMPILER==WIN32C && defined(MINGW)
#include <direct.h>
#define setdisk(n) _chdrive((n)+1)
#else
#ifdef _MSC_VER
#include <direct.h>
#define setdisk(n) _chdrive((n)+1)
#else
#include <dir.h>
#endif
#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(char *cmd, char *donemsg)
{
int inp;
#if HAVE_SHELL
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 !MSDOS_COMPILER
if (open_tty() < 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 <command>.
* 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(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(char *cmd, POSITION spos, POSITION epos)
{
FILE *f;
int c;
/*
* 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

457
third_party/less/main.c vendored Normal file
View file

@ -0,0 +1,457 @@
asm(".ident\t\"\\n\\n\
Less\\n\
Copyright (C) 1984-2023 Mark Nudelman\\n\
\\n\
Redistribution and use in source and binary forms, with or without\\n\
modification, are permitted provided that the following conditions\\n\
are met:\\n\
1. Redistributions of source code must retain the above copyright\\n\
notice, this list of conditions and the following disclaimer.\\n\
2. Redistributions in binary form must reproduce the above copyright\\n\
notice in the documentation and/or other materials provided with\\n\
the distribution.\\n\
\\n\
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY\\n\
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\\n\
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\\n\
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE\\n\
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\\n\
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\\n\
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR\\n\
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\\n\
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE\\n\
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN\\n\
IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\"");
/*
* Copyright (C) 1984-2023 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
#define WIN32_LEAN_AND_MEAN
/* #include <windows.h> */
#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 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
public int one_screen;
extern int less_is_more;
extern int missing_cap;
extern int know_dumb;
extern int pr_type;
extern int quit_if_one_screen;
extern int no_init;
extern int errmsgs;
extern int redraw_on_quit;
extern int term_init_done;
extern int first_time;
/*
* Entry point.
*/
int main(int argc, char *argv[])
{
IFILE ifile;
char *s;
#ifdef __EMX__
_response(&argc, &argv);
_wildcard(&argc, &argv);
#endif
progname = *argv++;
argc--;
#if SECURE
secure = 1;
#else
secure = 0;
s = lgetenv("LESSSECURE");
if (!isnullenv(s))
secure = 1;
#endif
#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);
init_mark();
init_cmds();
init_poll();
get_term();
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.
*/
s = last_component(progname);
if (strcmp(s, "more") == 0)
less_is_more = 1;
init_prompt();
s = lgetenv(less_is_more ? "MORE" : "LESS");
if (s != NULL)
scan_option(s);
#define isoptstring(s) (((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);
}
expand_cmd_tables();
#if EDITOR
editor = lgetenv("VISUAL");
if (editor == NULL || *editor == '\0')
{
editor = lgetenv("EDITOR");
if (isnullenv(editor))
editor = EDIT_PGM;
}
editproto = lgetenv("LESSEDIT");
if (isnullenv(editproto))
editproto = "%E ?lm+%lm. %g";
#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)
{
#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 *filename;
char *gfilename;
char *qfilename;
gfilename = lglob(*argv++);
init_textlist(&tlist, gfilename);
filename = NULL;
while ((filename = forw_textlist(&tlist, filename)) != NULL)
{
qfilename = shell_unquote(filename);
(void) get_ifile(qfilename, ifile);
free(qfilename);
ifile = prev_ifile(NULL_IFILE);
}
free(gfilename);
#else
(void) get_ifile(*argv++, ifile);
ifile = prev_ifile(NULL_IFILE);
#endif
}
/*
* Set up terminal, etc.
*/
if (!is_tty)
{
/*
* Output is not a tty.
* Just copy the input file(s) to output.
*/
set_output(1); /* write to stdout */
SET_BINARY(1);
if (edit_first() == 0)
{
do {
cat_file();
} while (edit_next(1) == 0);
}
quit(QUIT_OK);
}
if (missing_cap && !know_dumb)
error("WARNING: terminal is not fully functional", NULL_PARG);
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 (edit_first())
quit(QUIT_ERROR);
/*
* See if file fits on one screen to decide whether
* to send terminal init. But don't need this
* if -X (no_init) overrides this (see init()).
*/
if (quit_if_one_screen)
{
if (nifile() > 1) /* If more than one file, -F cannot be used */
quit_if_one_screen = FALSE;
else if (!no_init)
one_screen = get_one_screen();
}
}
if (errmsgs > 0)
{
/*
* We displayed some messages on error output
* (file descriptor 2; see flush()).
* Before erasing the screen contents, wait for a keystroke.
*/
less_printf("Press RETURN to continue ", NULL_PARG);
get_return();
putchr('\n');
}
set_output(1);
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(constant char *s)
{
char *p;
p = (char *) ecalloc(strlen(s)+1, sizeof(char));
strcpy(p, s);
return (p);
}
public void out_of_memory(void)
{
error("Cannot allocate memory", NULL_PARG);
quit(QUIT_ERROR);
}
/*
* Allocate memory.
* Like calloc(), but never returns an error (NULL).
*/
public void * ecalloc(int count, unsigned int size)
{
void * p;
p = (void *) calloc(count, size);
if (p == NULL)
out_of_memory();
return p;
}
/*
* Skip leading spaces in a string.
*/
public char * 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(char *ps, char *s, int uppercase)
{
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(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;
check_altpipe_error();
if (interactive())
clear_bot();
deinit();
flush();
if (redraw_on_quit && term_init_done)
{
/*
* The last file text displayed might have been on an
* alternate screen, which now (since deinit) cannot be seen.
* redraw_on_quit tells us to redraw it on the main screen.
*/
first_time = 1; /* Don't print "skipping" or tildes */
repaint();
flush();
}
edit((char*)NULL);
save_cmdhist();
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);
}

427
third_party/less/mark.c vendored Normal file
View file

@ -0,0 +1,427 @@
/*
* Copyright (C) 1984-2023 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"
#include "position.h"
extern IFILE curr_ifile;
extern int sc_height;
extern int jump_sline;
extern int perma_marks;
/*
* A mark is an ifile (input file) plus a position within the file.
*/
struct mark
{
/*
* Normally m_ifile != IFILE_NULL and m_filename == NULL.
* For restored marks we set m_filename instead of m_ifile
* because we don't want to create an ifile until the
* user explicitly requests the file (by name or mark).
*/
char m_letter; /* Associated character */
IFILE m_ifile; /* Input file being marked */
char *m_filename; /* Name of the input file */
struct scrpos m_scrpos; /* Position of the mark */
};
/*
* 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)+2) /* a-z, A-Z, mousemark, lastmark */
#define NUMARKS ((2*26)+1) /* user marks (not lastmark) */
#define MOUSEMARK (NMARKS-2)
#define LASTMARK (NMARKS-1)
static struct mark marks[NMARKS];
public int marks_modified = 0;
/*
* Initialize a mark struct.
*/
static void cmark(struct mark *m, IFILE ifile, POSITION pos, int ln)
{
m->m_ifile = ifile;
m->m_scrpos.pos = pos;
m->m_scrpos.ln = ln;
if (m->m_filename != NULL)
/* Normally should not happen but a corrupt lesshst file can do it. */
free(m->m_filename);
m->m_filename = NULL;
}
/*
* Initialize the mark table to show no marks are set.
*/
public void init_mark(void)
{
int i;
for (i = 0; i < NMARKS; i++)
{
char letter;
switch (i) {
case MOUSEMARK: letter = '#'; break;
case LASTMARK: letter = '\''; break;
default: letter = (i < 26) ? 'a'+i : 'A'+i-26; break;
}
marks[i].m_letter = letter;
cmark(&marks[i], NULL_IFILE, NULL_POSITION, -1);
}
}
/*
* Set m_ifile and clear m_filename.
*/
static void mark_set_ifile(struct mark *m, IFILE ifile)
{
m->m_ifile = ifile;
/* With m_ifile set, m_filename is no longer needed. */
free(m->m_filename);
m->m_filename = NULL;
}
/*
* Populate the m_ifile member of a mark struct from m_filename.
*/
static void mark_get_ifile(struct mark *m)
{
if (m->m_ifile != NULL_IFILE)
return; /* m_ifile is already set */
mark_set_ifile(m, get_ifile(m->m_filename, prev_ifile(NULL_IFILE)));
}
/*
* Return the user mark struct identified by a character.
*/
static struct mark * getumark(LWCHAR c)
{
PARG parg;
if (c >= 'a' && c <= 'z')
return (&marks[c-'a']);
if (c >= 'A' && c <= 'Z')
return (&marks[c-'A'+26]);
if (c == '\'')
return (&marks[LASTMARK]);
if (c == '#')
return (&marks[MOUSEMARK]);
parg.p_char = (char) c;
error("Invalid mark letter %c", &parg);
return (NULL);
}
/*
* Get the mark structure identified by a character.
* The mark struct may either be in the mark table (user mark)
* or may be constructed on the fly for certain characters like ^, $.
*/
static struct mark * getmark(LWCHAR c)
{
struct mark *m;
static struct mark sm;
switch (c)
{
case '^':
/*
* Beginning of the current file.
*/
m = &sm;
cmark(m, curr_ifile, ch_zero(), 0);
break;
case '$':
/*
* End of the current file.
*/
if (ch_end_seek())
{
error("Cannot seek to end of file", NULL_PARG);
return (NULL);
}
m = &sm;
cmark(m, curr_ifile, ch_tell(), sc_height);
break;
case '.':
/*
* Current position in the current file.
*/
m = &sm;
get_scrpos(&m->m_scrpos, TOP);
cmark(m, curr_ifile, m->m_scrpos.pos, m->m_scrpos.ln);
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 invalid?
*/
public int badmark(LWCHAR c)
{
return (getmark(c) == NULL);
}
/*
* Set a user-defined mark.
*/
public void setmark(LWCHAR c, int where)
{
struct mark *m;
struct scrpos scrpos;
m = getumark(c);
if (m == NULL)
return;
get_scrpos(&scrpos, where);
if (scrpos.pos == NULL_POSITION)
{
bell();
return;
}
cmark(m, curr_ifile, scrpos.pos, scrpos.ln);
marks_modified = 1;
}
/*
* Clear a user-defined mark.
*/
public void clrmark(LWCHAR c)
{
struct mark *m;
m = getumark(c);
if (m == NULL)
return;
if (m->m_scrpos.pos == NULL_POSITION)
{
bell();
return;
}
m->m_scrpos.pos = NULL_POSITION;
marks_modified = 1;
}
/*
* Set lmark (the mark named by the apostrophe).
*/
public void lastmark(void)
{
struct scrpos scrpos;
if (ch_getflags() & CH_HELPFILE)
return;
get_scrpos(&scrpos, TOP);
if (scrpos.pos == NULL_POSITION)
return;
cmark(&marks[LASTMARK], curr_ifile, scrpos.pos, scrpos.ln);
marks_modified = 1;
}
/*
* Go to a mark.
*/
public void gomark(LWCHAR c)
{
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.
* {{ Couldn't we instead set marks[LASTMARK] in edit()? }}
*/
if (m == &marks[LASTMARK] && m->m_scrpos.pos == NULL_POSITION)
cmark(m, curr_ifile, ch_zero(), jump_sline);
mark_get_ifile(m);
/* Save scrpos; if it's LASTMARK it could change in edit_ifile. */
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(LWCHAR c)
{
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);
}
/*
* Return the mark associated with a given position, if any.
*/
public char posmark(POSITION pos)
{
int i;
/* Only user marks */
for (i = 0; i < NUMARKS; i++)
{
if (marks[i].m_ifile == curr_ifile && marks[i].m_scrpos.pos == pos)
{
if (i < 26) return 'a' + i;
if (i < 26*2) return 'A' + (i - 26);
return '#';
}
}
return 0;
}
/*
* Clear the marks associated with a specified ifile.
*/
public void unmark(IFILE ifile)
{
int i;
for (i = 0; i < NMARKS; i++)
if (marks[i].m_ifile == ifile)
marks[i].m_scrpos.pos = NULL_POSITION;
}
/*
* Check if any marks refer to a specified ifile vi m_filename
* rather than m_ifile.
*/
public void mark_check_ifile(IFILE ifile)
{
int i;
char *filename = get_real_filename(ifile);
for (i = 0; i < NMARKS; i++)
{
struct mark *m = &marks[i];
char *mark_filename = m->m_filename;
if (mark_filename != NULL)
{
mark_filename = lrealpath(mark_filename);
if (strcmp(filename, mark_filename) == 0)
mark_set_ifile(m, ifile);
free(mark_filename);
}
}
}
#if CMD_HISTORY
/*
* Save marks to history file.
*/
public void save_marks(FILE *fout, char *hdr)
{
int i;
if (!perma_marks)
return;
fprintf(fout, "%s\n", hdr);
for (i = 0; i < NMARKS; i++)
{
char *filename;
struct mark *m = &marks[i];
char pos_str[INT_STRLEN_BOUND(m->m_scrpos.pos) + 2];
if (m->m_scrpos.pos == NULL_POSITION)
continue;
postoa(m->m_scrpos.pos, pos_str, 10);
filename = m->m_filename;
if (filename == NULL)
filename = get_real_filename(m->m_ifile);
if (strcmp(filename, "-") != 0)
fprintf(fout, "m %c %d %s %s\n",
m->m_letter, m->m_scrpos.ln, pos_str, filename);
}
}
/*
* Restore one mark from the history file.
*/
public void restore_mark(char *line)
{
struct mark *m;
int ln;
POSITION pos;
#define skip_whitespace while (*line == ' ') line++
if (*line++ != 'm')
return;
skip_whitespace;
m = getumark(*line++);
if (m == NULL)
return;
skip_whitespace;
ln = lstrtoi(line, &line, 10);
if (ln < 0)
return;
if (ln < 1)
ln = 1;
if (ln > sc_height)
ln = sc_height;
skip_whitespace;
pos = lstrtopos(line, &line, 10);
if (pos < 0)
return;
skip_whitespace;
cmark(m, NULL_IFILE, pos, ln);
m->m_filename = save(line);
}
#endif /* CMD_HISTORY */

1096
third_party/less/optfunc.c vendored Normal file

File diff suppressed because it is too large Load diff

688
third_party/less/option.c vendored Normal file
View file

@ -0,0 +1,688 @@
/*
* Copyright (C) 1984-2023 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(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(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(int c)
{
static char buf[MAX_PRCHAR_LEN+2];
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(char *s)
{
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 == '+')
{
if (every_first_cmd != NULL)
free(every_first_cmd);
every_first_cmd = save(str+1);
} else
{
ungetsc(str);
ungetcc_back(CHAR_END_COMMAND);
}
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 "-<number>"
* instead of -z<number> 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(struct loption *o, int lower, char *s, int how_toggle)
{
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(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(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(struct loption *o)
{
if (o == NULL || (o->otype & (STRING|NUMBER)) == 0)
return ("?");
return (o->odesc[0]);
}
/*
* If the specified option can be toggled, return NULL.
* Otherwise return an appropriate error message.
*/
public char * opt_toggle_disallowed(int c)
{
switch (c)
{
case 'o':
if (ch_getflags() & CH_CANSEEK)
return "Input is not a pipe";
break;
}
return NULL;
}
/*
* 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(void)
{
return (pendopt != NULL);
}
/*
* Print error message about missing string.
*/
static void 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(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(char *s, char **p_str, char *printopt, char *validchars)
{
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(char *printopt, int *errp, int overflow)
{
PARG parg;
if (errp != NULL)
{
*errp = TRUE;
return (-1);
}
if (printopt != NULL)
{
parg.p_string = printopt;
error((overflow
? "Number too large in '%s'"
: "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(char **sp, char *printopt, int *errp)
{
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, FALSE));
n = lstrtoi(s, sp, 10);
if (n < 0)
return (num_error(printopt, errp, TRUE));
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(char **sp, char *printopt, int *errp)
{
char *s;
long frac = 0;
int fraclen = 0;
s = skipsp(*sp);
if (*s < '0' || *s > '9')
return (num_error(printopt, errp, FALSE));
for ( ; *s >= '0' && *s <= '9'; s++)
{
if (NUM_LOG_FRAC_DENOM <= fraclen)
continue;
frac = (frac * 10) + (*s - '0');
fraclen++;
}
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(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;
}

66
third_party/less/option.h vendored Normal file
View file

@ -0,0 +1,66 @@
/*
* Copyright (C) 1984-2023 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 END_OPTION_STRING ('$')
/*
* Types of options.
*/
#define BOOL 01 /* Boolean option: 0 or 1 */
#define TRIPLE 02 /* Triple-valued option: 0, 1 or 2 */
#define NUMBER 04 /* Numeric option */
#define STRING 010 /* String-valued option */
#define NOVAR 020 /* No associated variable */
#define REPAINT 040 /* Repaint screen after toggling option */
#define NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */
#define HL_REPAINT 0200 /* Repaint hilites after toggling option */
#define NO_QUERY 0400 /* Option cannot be queried with "_" cmd */
#define INIT_HANDLER 01000 /* Call option handler function at startup */
#define OTYPE (BOOL|TRIPLE|NUMBER|STRING|NOVAR)
#define OLETTER_NONE '\1' /* Invalid option letter */
/*
* Argument to a handling function tells what type of activity:
*/
#define INIT 0 /* Initialization (from command line) */
#define QUERY 1 /* Query (from _ or - command) */
#define TOGGLE 2 /* Change value (from - command) */
/* Flag to toggle_option to specify how to "toggle" */
#define OPT_NO_TOGGLE 0
#define OPT_TOGGLE 1
#define OPT_UNSET 2
#define OPT_SET 3
#define OPT_NO_PROMPT 0100
/* Error code from findopt_name */
#define OPT_AMBIG 1
struct optname
{
char *oname; /* Long (GNU-style) option name */
struct optname *onext; /* List of synonymous option names */
};
#define OPTNAME_MAX 32 /* Max length of long option name */
struct loption
{
char oletter; /* The controlling letter (a-z) */
struct optname *onames; /* Long (GNU-style) option name */
int otype; /* Type of the option */
int odefault; /* Default value */
int *ovar; /* Pointer to the associated variable */
void (*ofunc)(int, char*); /* Pointer to special handling function */
char *odesc[3]; /* Description of each value */
};

861
third_party/less/opttbl.c vendored Normal file
View file

@ -0,0 +1,861 @@
/*
* Copyright (C) 1984-2023 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 no_vbell; /* Should we suppress the visual 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 wordwrap; /* Wrap lines at space */
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 */
public char rscroll_char; /* Char which marks chopped lines with -S */
public int rscroll_attr; /* Attribute of rscroll_char */
public int no_hist_dups; /* Remove dups from history list */
public int mousecap; /* Allow mouse for scrolling */
public int wheel_lines; /* Number of lines to scroll on mouse wheel scroll */
public int perma_marks; /* Save marks in history file */
public int linenum_width; /* Width of line numbers */
public int status_col_width; /* Width of status column */
public int incr_search; /* Incremental search */
public int use_color; /* Use UI color */
public int want_filesize; /* Scan to EOF if necessary to get file size */
public int status_line; /* Highlight entire marked lines */
public int header_lines; /* Freeze header lines at top of screen */
public int header_cols; /* Freeze header columns at left of screen */
public int nonum_headers; /* Don't give headers line numbers */
public int nosearch_headers; /* Don't search in header lines or columns */
public int redraw_on_quit; /* Redraw last screen after term deinit */
public int def_search_type; /* */
public int exit_F_on_close; /* Exit F command when input closes */
public int modelines; /* Lines to read looking for modelines */
public int show_preproc_error; /* Display msg when preproc exits with error */
public int proc_backspace; /* Special handling of backspace */
public int proc_tab; /* Special handling of tab */
public int proc_return; /* Special handling of carriage return */
public char intr_char = CONTROL('X'); /* Char to interrupt reads */
#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 };
static struct optname D__optname = { "color", NULL };
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 };
#if HAVE_LESSKEYSRC
static struct optname ks_optname = { "lesskey-src", NULL };
#endif /* HAVE_LESSKEYSRC */
#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 };
static struct optname rscroll_optname = { "rscroll", NULL };
static struct optname nohistdups_optname = { "no-histdups", NULL };
static struct optname mousecap_optname = { "mouse", NULL };
static struct optname wheel_lines_optname = { "wheel-lines", NULL };
static struct optname perma_marks_optname = { "save-marks", NULL };
static struct optname linenum_width_optname = { "line-num-width", NULL };
static struct optname status_col_width_optname = { "status-col-width", NULL };
static struct optname incr_search_optname = { "incsearch", NULL };
static struct optname use_color_optname = { "use-color", NULL };
static struct optname want_filesize_optname = { "file-size", NULL };
static struct optname status_line_optname = { "status-line", NULL };
static struct optname header_optname = { "header", NULL };
static struct optname nonum_headers_optname = { "no-number-headers", NULL };
static struct optname nosearch_headers_optname = { "no-search-headers", NULL };
static struct optname redraw_on_quit_optname = { "redraw-on-quit", NULL };
static struct optname search_type_optname = { "search-options", NULL };
static struct optname exit_F_on_close_optname = { "exit-follow-on-close", NULL };
static struct optname modelines_optname = { "modelines", NULL };
static struct optname no_vbell_optname = { "no-vbell", NULL };
static struct optname intr_optname = { "intr", NULL };
static struct optname wordwrap_optname = { "wordwrap", NULL };
static struct optname show_preproc_error_optname = { "show-preproc-errors", NULL };
static struct optname proc_backspace_optname = { "proc-backspace", NULL };
static struct optname proc_tab_optname = { "proc-tab", NULL };
static struct optname proc_return_optname = { "proc-return", NULL };
#if LESSTEST
static struct optname ttyin_name_optname = { "tty", NULL };
#endif /*LESSTEST*/
/*
* 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
}
},
{ 'D', &D__optname,
STRING|REPAINT|NO_QUERY, 0, NULL, opt_D,
{
"color desc: ",
NULL,
NULL
}
},
{ '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 }
},
#if HAVE_LESSKEYSRC
{ OLETTER_NONE, &ks_optname,
STRING|NO_TOGGLE|NO_QUERY, 0, NULL, opt_ks,
{ NULL, NULL, NULL }
},
#endif /* HAVE_LESSKEYSRC */
#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 (not recommended)",
"Display ANSI sequences directly, other control characters as ^X"
}
},
{ '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|HL_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
}
},
{ '"', &quote_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 }
},
{ '#', &pound_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
}
},
{ OLETTER_NONE, &rscroll_optname,
STRING|REPAINT|INIT_HANDLER, 0, NULL, opt_rscroll,
{ "rscroll character: ", NULL, NULL }
},
{ OLETTER_NONE, &nohistdups_optname,
BOOL, OPT_OFF, &no_hist_dups, NULL,
{
"Allow duplicates in history list",
"Remove duplicates from history list",
NULL
}
},
{ OLETTER_NONE, &mousecap_optname,
TRIPLE, OPT_OFF, &mousecap, opt_mousecap,
{
"Ignore mouse input",
"Use the mouse for scrolling",
"Use the mouse for scrolling (reverse)"
}
},
{ OLETTER_NONE, &wheel_lines_optname,
NUMBER|INIT_HANDLER, 0, &wheel_lines, opt_wheel_lines,
{
"Lines to scroll on mouse wheel: ",
"Scroll %d line(s) on mouse wheel",
NULL
}
},
{ OLETTER_NONE, &perma_marks_optname,
BOOL, OPT_OFF, &perma_marks, NULL,
{
"Don't save marks in history file",
"Save marks in history file",
NULL
}
},
{ OLETTER_NONE, &linenum_width_optname,
NUMBER|REPAINT, MIN_LINENUM_WIDTH, &linenum_width, opt_linenum_width,
{
"Line number width: ",
"Line number width is %d chars",
NULL
}
},
{ OLETTER_NONE, &status_col_width_optname,
NUMBER|REPAINT, 2, &status_col_width, opt_status_col_width,
{
"Status column width: ",
"Status column width is %d chars",
NULL
}
},
{ OLETTER_NONE, &incr_search_optname,
BOOL, OPT_OFF, &incr_search, NULL,
{
"Incremental search is off",
"Incremental search is on",
NULL
}
},
{ OLETTER_NONE, &use_color_optname,
BOOL|REPAINT, OPT_OFF, &use_color, NULL,
{
"Don't use color",
"Use color",
NULL
}
},
{ OLETTER_NONE, &want_filesize_optname,
BOOL|REPAINT, OPT_OFF, &want_filesize, opt_filesize,
{
"Don't get size of each file",
"Get size of each file",
NULL
}
},
{ OLETTER_NONE, &status_line_optname,
BOOL|REPAINT, OPT_OFF, &status_line, NULL,
{
"Don't color each line with its status column color",
"Color each line with its status column color",
NULL
}
},
{ OLETTER_NONE, &header_optname,
STRING|REPAINT, 0, NULL, opt_header,
{
"Header lines: ",
NULL,
NULL
}
},
{ OLETTER_NONE, &nonum_headers_optname,
BOOL|REPAINT, 0, &nonum_headers, NULL,
{
"Number header lines",
"Don't number header lines",
NULL
}
},
{ OLETTER_NONE, &nosearch_headers_optname,
BOOL|HL_REPAINT, 0, &nosearch_headers, NULL,
{
"Search includes header lines",
"Search does not include header lines",
NULL
}
},
{ OLETTER_NONE, &redraw_on_quit_optname,
BOOL, OPT_OFF, &redraw_on_quit, NULL,
{
"Don't redraw screen when quitting",
"Redraw last screen when quitting",
NULL
}
},
{ OLETTER_NONE, &search_type_optname,
STRING, 0, NULL, opt_search_type,
{
"Search options: ",
NULL,
NULL
}
},
{ OLETTER_NONE, &exit_F_on_close_optname,
BOOL, OPT_OFF, &exit_F_on_close, NULL,
{
"Don't exit F command when input closes",
"Exit F command when input closes",
NULL
}
},
{ OLETTER_NONE, &no_vbell_optname,
BOOL, OPT_OFF, &no_vbell, NULL,
{
"Display visual bell",
"Don't display visual bell",
NULL
}
},
{ OLETTER_NONE, &modelines_optname,
NUMBER, 0, &modelines, NULL,
{
"Lines to read looking for modelines: ",
"Read %d lines looking for modelines",
NULL
}
},
{ OLETTER_NONE, &intr_optname,
STRING, 0, NULL, opt_intr,
{ "interrupt character: ", NULL, NULL }
},
{ OLETTER_NONE, &wordwrap_optname,
BOOL|REPAINT, OPT_OFF, &wordwrap, NULL,
{
"Wrap lines at any character",
"Wrap lines at spaces",
NULL
}
},
{ OLETTER_NONE, &show_preproc_error_optname,
BOOL, OPT_OFF, &show_preproc_error, NULL,
{
"Don't show error message if preprocessor fails",
"Show error message if preprocessor fails",
NULL
}
},
{ OLETTER_NONE, &proc_backspace_optname,
TRIPLE|REPAINT|HL_REPAINT, OPT_OFF, &proc_backspace, NULL,
{
"Backspace handling is specified by the -U option",
"Display underline text in underline mode",
"Print backspaces as ^H"
}
},
{ OLETTER_NONE, &proc_tab_optname,
TRIPLE|REPAINT|HL_REPAINT, OPT_OFF, &proc_tab, NULL,
{
"Tab handling is specified by the -U option",
"Expand tabs to spaces",
"Print tabs as ^I"
}
},
{ OLETTER_NONE, &proc_return_optname,
TRIPLE|REPAINT|HL_REPAINT, OPT_OFF, &proc_return, NULL,
{
"Carriage return handling is specified by the -U option",
"Delete carriage return before newline",
"Print carriage return as ^M"
}
},
#if LESSTEST
{ OLETTER_NONE, &ttyin_name_optname,
STRING|NO_TOGGLE, 0, NULL, opt_ttyin_name,
{
NULL,
NULL,
NULL
}
},
#endif /*LESSTEST*/
{ '\0', NULL, NOVAR, 0, NULL, NULL, { NULL, NULL, NULL } }
};
/*
* Initialize each option to its default value.
*/
public void init_option(void)
{
struct loption *o;
char *p;
p = lgetenv("LESS_IS_MORE");
if (!isnullenv(p))
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(int c)
{
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(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(char **p_optname, char **p_oname, int *p_err)
{
char *optname = *p_optname;
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);
}

507
third_party/less/os.c vendored Normal file
View file

@ -0,0 +1,507 @@
/*
* Copyright (C) 1984-2023 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 <signal.h>
#include <setjmp.h>
#if MSDOS_COMPILER==WIN32C
/* #include <windows.h> */
#endif
#if HAVE_TIME_H
#include <time.h>
#endif
#if HAVE_ERRNO_H
#include <errno.h>
#endif
#if HAVE_VALUES_H
#include <values.h>
#endif
#if defined(__APPLE__)
#include <sys/utsname.h>
#endif
#if HAVE_POLL && !MSDOS_COMPILER
#define USE_POLL 1
static int use_poll = TRUE;
#else
#define USE_POLL 0
#endif
#if USE_POLL
#include <poll.h>
static int any_data = FALSE;
#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;
public int waiting_for_data;
public int consecutive_nulls = 0;
/* Milliseconds to wait for data before displaying "waiting for data" message. */
static int waiting_for_data_delay = 4000;
static jmp_buf read_label;
extern int sigs;
extern int ignore_eoi;
extern int exit_F_on_close;
extern int follow_mode;
extern int scanning_eof;
extern char intr_char;
#if !MSDOS_COMPILER
extern int tty;
#endif
#if LESSTEST
extern char *ttyin_name;
#endif /*LESSTEST*/
public void init_poll(void)
{
char *delay = lgetenv("LESS_DATA_DELAY");
int idelay = (delay == NULL) ? 0 : atoi(delay);
if (idelay > 0)
waiting_for_data_delay = idelay;
#if USE_POLL
#if defined(__APPLE__)
/* In old versions of MacOS, poll() does not work with /dev/tty. */
struct utsname uts;
if (uname(&uts) < 0 || lstrtoi(uts.release, NULL, 10) < 20)
use_poll = FALSE;
#endif
#endif
}
#if USE_POLL
/*
* Check whether data is available, either from a file/pipe or from the tty.
* Return READ_AGAIN if no data currently available, but caller should retry later.
* Return READ_INTR to abort F command (forw_loop).
* Return 0 if safe to read from fd.
*/
static int check_poll(int fd, int tty)
{
struct pollfd poller[2] = { { fd, POLLIN, 0 }, { tty, POLLIN, 0 } };
int timeout = (waiting_for_data && !(scanning_eof && follow_mode == FOLLOW_NAME)) ? -1 : waiting_for_data_delay;
if (!any_data)
{
/*
* Don't do polling if no data has yet been received,
* to allow a program piping data into less to have temporary
* access to the tty (like sudo asking for a password).
*/
return (0);
}
poll(poller, 2, timeout);
#if LESSTEST
if (ttyin_name == NULL) /* Check for ^X only on a real tty. */
#endif /*LESSTEST*/
{
if (poller[1].revents & POLLIN)
{
LWCHAR ch = getchr();
if (ch == intr_char)
/* Break out of "waiting for data". */
return (READ_INTR);
ungetcc_back(ch);
}
}
if (ignore_eoi && exit_F_on_close && (poller[0].revents & (POLLHUP|POLLIN)) == POLLHUP)
/* Break out of F loop on HUP due to --exit-follow-on-close. */
return (READ_INTR);
if ((poller[0].revents & (POLLIN|POLLHUP|POLLERR)) == 0)
/* No data available; let caller take action, then try again. */
return (READ_AGAIN);
/* There is data (or HUP/ERR) available. Safe to call read() without blocking. */
return (0);
}
#endif /* USE_POLL */
public int supports_ctrl_x(void)
{
#if USE_POLL
return (use_poll);
#else
return (FALSE);
#endif /* USE_POLL */
}
/*
* Like read() system call, but is deliberately interruptible.
* A call to intread() from a signal handler will interrupt
* any pending iread().
*/
public int iread(int fd, unsigned char *buf, unsigned int len)
{
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 (!reading && 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
#if !MSDOS_COMPILER
if (fd != tty && !ABORT_SIGS())
/* Non-interrupt signal like SIGWINCH. */
return (READ_AGAIN);
#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.
* {{ This code was added 12 Jan 2007; still needed? }}
*/
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
if (select(fd+1, &readfds, 0, 0, 0) == -1)
{
reading = 0;
return (READ_ERR);
}
}
#endif
#if USE_POLL
if (fd != tty && use_poll)
{
int ret = check_poll(fd, tty);
if (ret != 0)
{
if (ret == READ_INTR)
sigs |= S_INTERRUPT;
reading = 0;
return (ret);
}
}
#else
#if MSDOS_COMPILER==WIN32C
if (win32_kbhit())
{
int c;
c = WIN32getch();
if (c == intr_char)
{
sigs |= S_INTERRUPT;
reading = 0;
return (READ_INTR);
}
WIN32ungetch(c);
}
#endif
#endif
n = read(fd, buf, len);
reading = 0;
#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.
*/
{
if (!ignore_eoi)
{
if (n == 0)
consecutive_nulls++;
else
consecutive_nulls = 0;
if (consecutive_nulls > 20)
quit(QUIT_ERROR);
}
}
#endif
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 (READ_ERR);
}
#if USE_POLL
if (fd != tty && n > 0)
any_data = TRUE;
#endif
return (n);
}
/*
* Interrupt a pending iread().
*/
public void intread(void)
{
LONG_JUMP(read_label, 1);
}
/*
* Return the current time.
*/
#if HAVE_TIME
public time_type 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(int err)
{
static char buf[INT_STRLEN_BOUND(int)+12];
#if HAVE_SYS_ERRLIST
extern char *sys_errlist[];
extern int sys_nerr;
if (err < sys_nerr)
return sys_errlist[err];
#endif
sprintf(buf, "Error %d", err);
return buf;
}
#endif
/*
* errno_message: Return an error message based on the value of "errno".
*/
public char * errno_message(char *filename)
{
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);
}
/*
* Return a description of a signal.
* The return value is good until the next call to this function.
*/
public char * signal_message(int sig)
{
static char sigbuf[sizeof("Signal ") + INT_STRLEN_BOUND(sig) + 1];
#if HAVE_STRSIGNAL
char *description = strsignal(sig);
if (description)
return description;
#endif
sprintf(sigbuf, "Signal %d", sig);
return sigbuf;
}
/*
* Return (VAL * NUM) / DEN, where DEN is positive
* and min(VAL, NUM) <= DEN so the result cannot overflow.
* Round to the nearest integer, breaking ties by rounding to even.
*/
public uintmax muldiv(uintmax val, uintmax num, uintmax den)
{
/*
* Like round(val * (double) num / den), but without rounding error.
* Overflow cannot occur, so there is no need for floating point.
*/
uintmax q = val / den;
uintmax r = val % den;
uintmax qnum = q * num;
uintmax rnum = r * num;
uintmax quot = qnum + rnum / den;
uintmax rem = rnum % den;
return quot + (den / 2 < rem + (quot & ~den & 1));
}
/*
* Return the ratio of two POSITIONS, as a percentage.
* {{ Assumes a POSITION is a long int. }}
*/
public int percentage(POSITION num, POSITION den)
{
return (int) muldiv(num, (POSITION) 100, den);
}
/*
* Return the specified percentage of a POSITION.
* Assume (0 <= POS && 0 <= PERCENT <= 100
* && 0 <= FRACTION < (PERCENT == 100 ? 1 : NUM_FRAC_DENOM)),
* so the result cannot overflow. Round to even.
*/
public POSITION percent_pos(POSITION pos, int percent, long fraction)
{
/*
* Change from percent (parts per 100)
* to pctden (parts per 100 * NUM_FRAC_DENOM).
*/
POSITION pctden = (percent * NUM_FRAC_DENOM) + fraction;
return (POSITION) muldiv(pos, pctden, 100 * (POSITION) NUM_FRAC_DENOM);
}
#if !HAVE_STRCHR
/*
* strchr is used by regexp.c.
*/
char * strchr(char *s, char c)
{
for ( ; *s != '\0'; s++)
if (*s == c)
return (s);
if (c == '\0')
return (s);
return (NULL);
}
#endif
#if !HAVE_MEMCPY
void * memcpy(void *dst, void *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(int type, RETSIGTYPE (*handler)())
{
intercept(handler);
}
#include <sgstat.h>
int isatty(int f)
{
struct sgbuf sgbuf;
if (_gs_opt(f, &sgbuf) < 0)
return -1;
return (sgbuf.sg_class == 0);
}
#endif
public void sleep_ms(int ms)
{
#if MSDOS_COMPILER==WIN32C
Sleep(ms);
#else
#if HAVE_NANOSLEEP
int sec = ms / 1000;
struct timespec t = { sec, (ms - sec*1000) * 1000000 };
nanosleep(&t, NULL);
#else
#if HAVE_USLEEP
usleep(ms);
#else
sleep(ms / 1000 + (ms % 1000 != 0));
#endif
#endif
#endif
}

719
third_party/less/output.c vendored Normal file
View file

@ -0,0 +1,719 @@
/*
* Copyright (C) 1984-2023 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" */
#ifndef COMMON_LVB_UNDERSCORE
#define COMMON_LVB_UNDERSCORE 0x8000
#endif
#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 is_tty;
extern int oldbot;
extern char intr_char;
#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;
extern int sgr_mode;
#if MSDOS_COMPILER==WIN32C
extern int vt_enabled;
#endif
#endif
/*
* Display the line which is in the line buffer.
*/
public void put_line(void)
{
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;
static int outfd = 2; /* stderr */
#if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
static void win_flush(void)
{
if (ctldisp != OPT_ONPLUS || (vt_enabled && sgr_mode))
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;
static int fg, fgi, bg, bgi;
static int at;
int f, b;
#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
if (fg == 0 && bg == 0)
{
fg = nm_fg_color & 7;
fgi = nm_fg_color & 8;
bg = nm_bg_color & 7;
bgi = nm_bg_color & 8;
}
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;
fg = nm_fg_color & 7;
fgi = nm_fg_color & 8;
bg = nm_bg_color & 7;
bgi = nm_bg_color & 8;
at = 0;
WIN32setcolors(nm_fg_color, nm_bg_color);
continue;
}
p_next = p;
at &= ~32;
/*
* Select foreground/background colors
* based on the escape sequence.
*/
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++;
at |= 32;
}
switch (code)
{
default:
/* case 0: all attrs off */
fg = nm_fg_color & 7;
bg = nm_bg_color & 7;
at &= 32;
/*
* \e[0m use normal
* intensities, but
* \e[0;...m resets them
*/
if (at & 32)
{
fgi = 0;
bgi = 0;
} else
{
fgi = nm_fg_color & 8;
bgi = nm_bg_color & 8;
}
break;
case 1: /* bold on */
fgi = 8;
at |= 1;
break;
case 3: /* italic on */
case 7: /* inverse on */
at |= 2;
break;
case 4: /* underline on */
bgi = 8;
at |= 4;
break;
case 5: /* slow blink on */
case 6: /* fast blink on */
bgi = 8;
at |= 8;
break;
case 8: /* concealed on */
at |= 16;
break;
case 22: /* bold off */
fgi = 0;
at &= ~1;
break;
case 23: /* italic off */
case 27: /* inverse off */
at &= ~2;
break;
case 24: /* underline off */
bgi = 0;
at &= ~4;
break;
case 28: /* concealed off */
at &= ~16;
break;
case 30: case 31: case 32:
case 33: case 34: case 35:
case 36: case 37:
fg = screen_color[code - 30];
at |= 32;
break;
case 39: /* default fg */
fg = nm_fg_color & 7;
at |= 32;
break;
case 40: case 41: case 42:
case 43: case 44: case 45:
case 46: case 47:
bg = screen_color[code - 40];
at |= 32;
break;
case 49: /* default bg */
bg = nm_bg_color & 7;
at |= 32;
break;
}
p = q;
}
if (!is_ansi_end(*p) || p == p_next)
break;
/*
* In SGR mode, the ANSI sequence is
* always honored; otherwise if an attr
* is used by itself ("\e[1m" versus
* "\e[1;33m", for example), set the
* color assigned to that attribute.
*/
if (sgr_mode || (at & 32))
{
if (at & 2)
{
f = bg | bgi;
b = fg | fgi;
} else
{
f = fg | fgi;
b = bg | bgi;
}
} else
{
if (at & 1)
{
f = bo_fg_color;
b = bo_bg_color;
} else if (at & 2)
{
f = so_fg_color;
b = so_bg_color;
} else if (at & 4)
{
f = ul_fg_color;
b = ul_bg_color;
} else if (at & 8)
{
f = bl_fg_color;
b = bl_bg_color;
} else
{
f = nm_fg_color;
b = nm_bg_color;
}
}
if (at & 16)
f = b ^ 8;
#if MSDOS_COMPILER==WIN32C
f &= 0xf | COMMON_LVB_UNDERSCORE;
#else
f &= 0xf;
#endif
b &= 0xf;
WIN32setcolors(f, b);
p_next = anchor = p + 1;
} else
p_next++;
}
/* Output what's left in the buffer. */
WIN32textout(anchor, ob - anchor);
}
ob = obuf;
}
#endif
/*
* 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(void)
{
int n;
n = (int) (ob - obuf);
if (n == 0)
return;
ob = obuf;
#if MSDOS_COMPILER==MSOFTC
if (interactive())
{
obuf[n] = '\0';
_outtext(obuf);
return;
}
#else
#if MSDOS_COMPILER==WIN32C || MSDOS_COMPILER==BORLANDC || MSDOS_COMPILER==DJGPPC
if (interactive())
{
ob = obuf + n;
*ob = '\0';
win_flush();
return;
}
#endif
#endif
if (write(outfd, obuf, n) != n)
screen_trashed = 1;
}
/*
* Set the output file descriptor (1=stdout or 2=stderr).
*/
public void set_output(int fd)
{
flush();
outfd = fd;
}
/*
* Output a character.
*/
public int 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
clear_bot_if_needed();
#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);
}
public void clear_bot_if_needed(void)
{
if (!need_clr)
return;
need_clr = 0;
clear_bot();
}
/*
* Output a string.
*/
public void 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(type num, char *buf, int radix) \
{ \
int neg = (num < 0); \
char tbuf[INT_STRLEN_BOUND(num)+2]; \
char *s = tbuf + sizeof(tbuf); \
if (neg) num = -num; \
*--s = '\0'; \
do { \
*--s = "0123456789ABCDEF"[num % radix]; \
} while ((num /= radix) != 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)
/*
* Convert a string to an integral type. Return ((type) -1) on overflow.
*/
#define STR_TO_TYPE_FUNC(funcname, type) \
type funcname(char *buf, char **ebuf, int radix) \
{ \
type val = 0; \
int v = 0; \
for (;; buf++) { \
char c = *buf; \
int digit = (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 10 : (c >= 'A' && c <= 'F') ? c - 'A' + 10 : -1; \
if (digit < 0 || digit >= radix) break; \
v |= ckd_mul(&val, val, radix); \
v |= ckd_add(&val, val, digit); \
} \
if (ebuf != NULL) *ebuf = buf; \
return v ? -1 : val; \
}
STR_TO_TYPE_FUNC(lstrtopos, POSITION)
STR_TO_TYPE_FUNC(lstrtoi, int)
STR_TO_TYPE_FUNC(lstrtoul, unsigned long)
/*
* Print an integral type.
*/
#define IPRINT_FUNC(funcname, type, typetoa) \
static int funcname(type num, int radix) \
{ \
char buf[INT_STRLEN_BOUND(num)]; \
typetoa(num, buf, radix); \
putstr(buf); \
return (int) strlen(buf); \
}
IPRINT_FUNC(iprint_int, int, inttoa)
IPRINT_FUNC(iprint_linenum, LINENUM, linenumtoa)
/*
* This function implements printf-like functionality
* using a more portable argument list mechanism than printf's.
*
* {{ This paranoia about the portability of printf dates from experiences
* with systems in the 1980s and is of course no longer necessary. }}
*/
public int less_printf(char *fmt, PARG *parg)
{
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, 10);
parg++;
break;
case 'x':
col += iprint_int(parg->p_int, 16);
parg++;
break;
case 'n':
col += iprint_linenum(parg->p_linenum, 10);
parg++;
break;
case 'c':
s = prchar(parg->p_char);
parg++;
while (*s != '\0')
{
putchr(*s++);
col++;
}
break;
case '%':
putchr('%');
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(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(char *fmt, PARG *parg)
{
int col = 0;
static char return_to_continue[] = " (press RETURN)";
errmsgs++;
if (!interactive())
{
less_printf(fmt, parg);
putchr('\n');
return;
}
if (!oldbot)
squish_check();
at_exit();
clear_bot();
at_enter(AT_STANDOUT|AT_COLOR_ERROR);
col += so_s_width;
col += less_printf(fmt, parg);
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();
}
/*
* 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.
*/
static void ierror_suffix(char *fmt, PARG *parg, char *suffix1, char *suffix2, char *suffix3)
{
at_exit();
clear_bot();
at_enter(AT_STANDOUT|AT_COLOR_ERROR);
(void) less_printf(fmt, parg);
putstr(suffix1);
putstr(suffix2);
putstr(suffix3);
at_exit();
flush();
need_clr = 1;
}
public void ierror(char *fmt, PARG *parg)
{
ierror_suffix(fmt, parg, "... (interrupt to abort)", "", "");
}
public void ixerror(char *fmt, PARG *parg)
{
if (!supports_ctrl_x())
ierror(fmt, parg);
else
ierror_suffix(fmt, parg,
"... (", prchar(intr_char), " or interrupt to abort)");
}
/*
* Output a message in the lower left corner of the screen
* and return a single-character response.
*/
public int query(char *fmt, PARG *parg)
{
int c;
int col = 0;
if (interactive())
clear_bot();
(void) less_printf(fmt, parg);
c = getchr();
if (interactive())
{
lower_left();
if (col >= sc_width)
screen_trashed = 1;
flush();
} else
{
putchr('\n');
}
if (c == 'Q')
quit(QUIT_OK);
return (c);
}

491
third_party/less/pattern.c vendored Normal file
View file

@ -0,0 +1,491 @@
/*
* Copyright (C) 1984-2023 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"
extern int caseless;
extern int is_caseless;
extern int utf_mode;
/*
* Compile a search pattern, for future use by match_pattern.
*/
static int compile_pattern2(char *pattern, int search_type, PATTERN_TYPE *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));
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 (*comp_pattern != NULL)
{
regfree(*comp_pattern);
free(*comp_pattern);
}
*comp_pattern = comp;
#endif
#if HAVE_POSIX_REGCOMP
regex_t *comp = (regex_t *) ecalloc(1, sizeof(regex_t));
if (regcomp(comp, pattern, REGCOMP_FLAG | (is_caseless ? REG_ICASE : 0)))
{
free(comp);
if (show_error)
error("Invalid pattern", NULL_PARG);
return (-1);
}
if (*comp_pattern != NULL)
{
regfree(*comp_pattern);
free(*comp_pattern);
}
*comp_pattern = comp;
#endif
#if HAVE_PCRE
constant char *errstring;
int erroffset;
PARG parg;
pcre *comp = pcre_compile(pattern,
((utf_mode) ? PCRE_UTF8 | PCRE_NO_UTF8_CHECK : 0) |
(is_caseless ? PCRE_CASELESS : 0),
&errstring, &erroffset, NULL);
if (comp == NULL)
{
parg.p_string = (char *) errstring;
if (show_error)
error("%s", &parg);
return (-1);
}
*comp_pattern = comp;
#endif
#if HAVE_PCRE2
int errcode;
PCRE2_SIZE erroffset;
PARG parg;
pcre2_code *comp = pcre2_compile((PCRE2_SPTR)pattern, strlen(pattern),
(is_caseless ? PCRE2_CASELESS : 0),
&errcode, &erroffset, NULL);
if (comp == NULL)
{
if (show_error)
{
char msg[160];
pcre2_get_error_message(errcode, (PCRE2_UCHAR*)msg, sizeof(msg));
parg.p_string = msg;
error("%s", &parg);
}
return (-1);
}
*comp_pattern = comp;
#endif
#if HAVE_RE_COMP
PARG parg;
if ((parg.p_string = re_comp(pattern)) != NULL)
{
if (show_error)
error("%s", &parg);
return (-1);
}
*comp_pattern = 1;
#endif
#if HAVE_REGCMP
char *comp;
if ((comp = regcmp(pattern, 0)) == NULL)
{
if (show_error)
error("Invalid pattern", NULL_PARG);
return (-1);
}
if (comp_pattern != NULL)
free(*comp_pattern);
*comp_pattern = comp;
#endif
#if HAVE_V8_REGCOMP
struct regexp *comp;
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 (*comp_pattern != NULL)
free(*comp_pattern);
*comp_pattern = comp;
#endif
}
return (0);
}
/*
* Like compile_pattern2, but convert the pattern to lowercase if necessary.
*/
public int compile_pattern(char *pattern, int search_type, int show_error, PATTERN_TYPE *comp_pattern)
{
char *cvt_pattern;
int result;
if (caseless != OPT_ONPLUS || (re_handles_caseless && !(search_type & SRCH_NO_REGEX)))
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, show_error);
if (cvt_pattern != pattern)
free(cvt_pattern);
return (result);
}
/*
* Forget that we have a compiled pattern.
*/
public void uncompile_pattern(PATTERN_TYPE *pattern)
{
#if HAVE_GNU_REGEX
if (*pattern != NULL)
{
regfree(*pattern);
free(*pattern);
}
*pattern = NULL;
#endif
#if HAVE_POSIX_REGCOMP
if (*pattern != NULL)
{
regfree(*pattern);
free(*pattern);
}
*pattern = NULL;
#endif
#if HAVE_PCRE
if (*pattern != NULL)
pcre_free(*pattern);
*pattern = NULL;
#endif
#if HAVE_PCRE2
if (*pattern != NULL)
pcre2_code_free(*pattern);
*pattern = NULL;
#endif
#if HAVE_RE_COMP
*pattern = 0;
#endif
#if HAVE_REGCMP
if (*pattern != NULL)
free(*pattern);
*pattern = NULL;
#endif
#if HAVE_V8_REGCOMP
if (*pattern != NULL)
free(*pattern);
*pattern = NULL;
#endif
}
#if 0
/*
* Can a pattern be successfully compiled?
*/
public int valid_pattern(char *pattern)
{
PATTERN_TYPE comp_pattern;
int result;
SET_NULL_PATTERN(comp_pattern);
result = compile_pattern2(pattern, 0, &comp_pattern, 0);
if (result != 0)
return (0);
uncompile_pattern(&comp_pattern);
return (1);
}
#endif
/*
* Is a compiled pattern null?
*/
public int is_null_pattern(PATTERN_TYPE 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_PCRE2
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(char *pattern, int pattern_len, char *buf, int buf_len, char ***sp, char ***ep, int nsubs)
{
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)
{
*(*sp)++ = buf;
*(*ep)++ = lp;
return (1);
}
}
**sp = **ep = NULL;
return (0);
}
/*
* Perform a pattern match with the previously compiled pattern.
* Set sp[0] and ep[0] to the start and end of the matched string.
* Set sp[i] and ep[i] to the start and end of the i-th matched subpattern.
* Subpatterns are defined by parentheses in the regex language.
*/
static int match_pattern1(PATTERN_TYPE pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int nsp, int notbol, int search_type)
{
int matched;
#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, nsp);
else
{
#if HAVE_GNU_REGEX
{
struct re_registers search_regs;
pattern->not_bol = notbol;
pattern->regs_allocated = REGS_UNALLOCATED;
matched = re_search(pattern, 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
{
#define RM_COUNT (NUM_SEARCH_COLORS+2)
regmatch_t rm[RM_COUNT];
int flags = (notbol) ? REG_NOTBOL : 0;
#ifdef REG_STARTEND
flags |= REG_STARTEND;
rm[0].rm_so = 0;
rm[0].rm_eo = line_len;
#endif
matched = !regexec(pattern, line, RM_COUNT, rm, flags);
if (matched)
{
int i;
int ecount;
for (ecount = RM_COUNT; ecount > 0; ecount--)
if (rm[ecount-1].rm_so >= 0)
break;
if (ecount >= nsp)
ecount = nsp-1;
for (i = 0; i < ecount; i++)
{
if (rm[i].rm_so < 0)
{
*sp++ = *ep++ = line;
} else
{
#ifndef __WATCOMC__
*sp++ = line + rm[i].rm_so;
*ep++ = line + rm[i].rm_eo;
#else
*sp++ = rm[i].rm_sp;
*ep++ = rm[i].rm_ep;
#endif
}
}
}
}
#endif
#if HAVE_PCRE
{
#define OVECTOR_COUNT ((3*NUM_SEARCH_COLORS)+3)
int ovector[OVECTOR_COUNT];
int flags = (notbol) ? PCRE_NOTBOL : 0;
int i;
int ecount;
int mcount = pcre_exec(pattern, NULL, line, line_len,
0, flags, ovector, OVECTOR_COUNT);
matched = (mcount > 0);
ecount = nsp-1;
if (ecount > mcount) ecount = mcount;
for (i = 0; i < ecount*2; )
{
if (ovector[i] < 0 || ovector[i+1] < 0)
{
*sp++ = *ep++ = line;
i += 2;
} else
{
*sp++ = line + ovector[i++];
*ep++ = line + ovector[i++];
}
}
}
#endif
#if HAVE_PCRE2
{
int flags = (notbol) ? PCRE2_NOTBOL : 0;
pcre2_match_data *md = pcre2_match_data_create(nsp-1, NULL);
int mcount = pcre2_match(pattern, (PCRE2_SPTR)line, line_len,
0, flags, md, NULL);
matched = (mcount > 0);
if (matched)
{
PCRE2_SIZE *ovector = pcre2_get_ovector_pointer(md);
int i;
int ecount = nsp-1;
if (ecount > mcount) ecount = mcount;
for (i = 0; i < ecount*2; )
{
if (ovector[i] < 0 || ovector[i+1] < 0)
{
*sp++ = *ep++ = line;
i += 2;
} else
{
*sp++ = line + ovector[i++];
*ep++ = line + ovector[i++];
}
}
}
pcre2_match_data_free(md);
}
#endif
#if HAVE_RE_COMP
matched = (re_exec(line) == 1);
/*
* re_exec doesn't seem to provide a way to get the matched string.
*/
#endif
#if HAVE_REGCMP
matched = ((*ep++ = regex(pattern, line)) != NULL);
if (matched)
*sp++ = __loc1;
#endif
#if HAVE_V8_REGCOMP
#if HAVE_REGEXEC2
matched = regexec2(pattern, line, notbol);
#else
matched = regexec(pattern, line);
#endif
if (matched)
{
*sp++ = pattern->startp[0];
*ep++ = pattern->endp[0];
}
#endif
}
*sp = *ep = NULL;
matched = (!(search_type & SRCH_NO_MATCH) && matched) ||
((search_type & SRCH_NO_MATCH) && !matched);
return (matched);
}
public int match_pattern(PATTERN_TYPE pattern, char *tpattern, char *line, int line_len, char **sp, char **ep, int nsp, int notbol, int search_type)
{
int matched = match_pattern1(pattern, tpattern, line, line_len, sp, ep, nsp, notbol, search_type);
int i;
for (i = 1; i <= NUM_SEARCH_COLORS; i++)
{
if ((search_type & SRCH_SUBSEARCH(i)) && ep[i] == sp[i])
matched = 0;
}
return matched;
}
/*
* Return the name of the pattern matching library.
*/
public char * pattern_lib_name(void)
{
#if HAVE_GNU_REGEX
return ("GNU");
#else
#if HAVE_POSIX_REGCOMP
return ("POSIX");
#else
#if HAVE_PCRE2
return ("PCRE2");
#else
#if HAVE_PCRE
return ("PCRE");
#else
#if HAVE_RE_COMP
return ("BSD");
#else
#if HAVE_REGCMP
return ("V8");
#else
#if HAVE_V8_REGCOMP
return ("Spencer V8");
#else
return ("no");
#endif
#endif
#endif
#endif
#endif
#endif
#endif
}

80
third_party/less/pattern.h vendored Normal file
View file

@ -0,0 +1,80 @@
/*
* Copyright (C) 1984-2023 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.
*/
#if HAVE_GNU_REGEX
#define __USE_GNU 1
#include <regex.h>
#define PATTERN_TYPE struct re_pattern_buffer *
#define SET_NULL_PATTERN(name) name = NULL
#endif
/* ---- POSIX ---- */
#if HAVE_POSIX_REGCOMP
#include <regex.h>
#ifdef REG_EXTENDED
#define REGCOMP_FLAG REG_EXTENDED
#else
#define REGCOMP_FLAG 0
#endif
#define PATTERN_TYPE regex_t *
#define SET_NULL_PATTERN(name) name = NULL
#define re_handles_caseless TRUE
#endif
/* ---- PCRE ---- */
#if HAVE_PCRE
#include <pcre.h>
#define PATTERN_TYPE pcre *
#define SET_NULL_PATTERN(name) name = NULL
#define re_handles_caseless TRUE
#endif
/* ---- PCRE2 ---- */
#if HAVE_PCRE2
#define PCRE2_CODE_UNIT_WIDTH 8
#include "third_party/pcre/pcre2.h"
#define PATTERN_TYPE pcre2_code *
#define SET_NULL_PATTERN(name) name = NULL
#define re_handles_caseless TRUE
#endif
/* ---- RE_COMP ---- */
#if HAVE_RE_COMP
char *re_comp(char*);
int re_exec(char*);
#define PATTERN_TYPE int
#define SET_NULL_PATTERN(name) name = 0
#endif
/* ---- REGCMP ---- */
#if HAVE_REGCMP
char *regcmp(char*);
char *regex(char**, char*);
extern char *__loc1;
#define PATTERN_TYPE char **
#define SET_NULL_PATTERN(name) name = NULL
#endif
/* ---- REGCOMP ---- */
#if HAVE_V8_REGCOMP
#include "regexp.h"
extern int reg_show_error;
#define PATTERN_TYPE struct regexp *
#define SET_NULL_PATTERN(name) name = NULL
#endif
/* ---- NONE ---- */
#if NO_REGEX
#define PATTERN_TYPE void *
#define SET_NULL_PATTERN(name)
#endif
#ifndef re_handles_caseless
#define re_handles_caseless FALSE
#endif

33
third_party/less/pckeys.h vendored Normal file
View file

@ -0,0 +1,33 @@
/*
* Copyright (C) 1984-2023 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.
*/
/*
* Definitions of keys on the PC.
* Special (non-ASCII) keys on the PC send a two-byte sequence,
* where the first byte is 0 and the second is as defined below.
*/
#define PCK_SHIFT_TAB '\017'
#define PCK_ALT_E '\022'
#define PCK_CAPS_LOCK '\072'
#define PCK_F1 '\073'
#define PCK_NUM_LOCK '\105'
#define PCK_HOME '\107'
#define PCK_UP '\110'
#define PCK_PAGEUP '\111'
#define PCK_LEFT '\113'
#define PCK_RIGHT '\115'
#define PCK_END '\117'
#define PCK_DOWN '\120'
#define PCK_PAGEDOWN '\121'
#define PCK_INSERT '\122'
#define PCK_DELETE '\123'
#define PCK_CTL_LEFT '\163'
#define PCK_CTL_RIGHT '\164'
#define PCK_CTL_DELETE '\223'

238
third_party/less/position.c vendored Normal file
View file

@ -0,0 +1,238 @@
/*
* Copyright (C) 1984-2023 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 = 0;
extern int sc_width, sc_height;
extern int header_lines;
/*
* 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(int sindex)
{
switch (sindex)
{
case BOTTOM:
sindex = sc_height - 2;
break;
case BOTTOM_PLUS_ONE:
sindex = sc_height - 1;
break;
case MIDDLE:
sindex = (sc_height - 1) / 2;
break;
}
return (table[sindex]);
}
/*
* Add a new file position to the bottom of the position table.
*/
public void add_forw_pos(POSITION pos)
{
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(POSITION pos)
{
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(void)
{
int i;
for (i = 0; i < sc_height; i++)
table[i] = NULL_POSITION;
}
/*
* Allocate or reallocate the position table.
*/
public void 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, TOP);
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(POSITION pos)
{
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(void)
{
return (empty_lines(0, sc_height-1));
}
public int empty_lines(int s, int e)
{
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(struct scrpos *scrpos, int where)
{
int i;
int dir;
int last;
switch (where)
{
case TOP:
i = 0; dir = +1; last = sc_height-2;
break;
case BOTTOM: case BOTTOM_PLUS_ONE:
i = sc_height-2; dir = -1; last = 0;
break;
default:
i = where;
if (table[i] == NULL_POSITION) {
scrpos->pos = NULL_POSITION;
return;
}
/* Values of dir and last don't matter after this. */
break;
}
/*
* Find the first line on the screen which has something on it,
* and return the screen line number and the file position.
*/
for (;; i += dir)
{
if (table[i] != NULL_POSITION)
{
scrpos->ln = i+1;
scrpos->pos = table[i];
return;
}
if (i == last) break;
}
/*
* 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 sindex_from_sline(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.
*/
if (sline <= 0)
sline = 1;
if (sline > sc_height)
sline = sc_height;
/*
* Return zero-based line number, not one-based.
*/
return (sline-1);
}

18
third_party/less/position.h vendored Normal file
View file

@ -0,0 +1,18 @@
/*
* Copyright (C) 1984-2023 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 file for interfacing to position.c modules.
*/
#define TOP (0)
#define TOP_PLUS_ONE (1)
#define BOTTOM (-1)
#define BOTTOM_PLUS_ONE (-2)
#define MIDDLE (-3)

556
third_party/less/prompt.c vendored Normal file
View file

@ -0,0 +1,556 @@
/*
* Copyright (C) 1984-2023 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 int header_lines;
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(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(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(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(POSITION pos)
{
char buf[INT_STRLEN_BOUND(pos) + 2];
postoa(pos, buf, 10);
ap_str(buf);
}
/*
* Append a line number to the end of the message.
*/
static void ap_linenum(LINENUM linenum)
{
char buf[INT_STRLEN_BOUND(linenum) + 2];
linenumtoa(linenum, buf, 10);
ap_str(buf);
}
/*
* Append an integer to the end of the message.
*/
static void ap_int(int num)
{
char buf[INT_STRLEN_BOUND(num) + 2];
inttoa(num, buf, 10);
ap_str(buf);
}
/*
* Append a question mark to the end of the message.
*/
static void ap_quest(void)
{
ap_str("?");
}
/*
* Return the "current" byte offset in the file.
*/
static POSITION 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(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? */
case 'g':
return (strcmp(get_filename(curr_ifile), "-") != 0);
case 'l': /* Line number known? */
case 'd': /* Same as l */
if (!linenums)
return 0;
return (currline(where) != 0);
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(int c, int where, int iseditproto)
{
POSITION pos;
POSITION len;
int n;
LINENUM linenum;
LINENUM last_linenum;
IFILE h;
char *s;
#undef PAGE_NUM
#define PAGE_NUM(linenum) ((((linenum) - 1) / (sc_height - header_lines - 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 > header_lines + 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 'g': /* Shell-escaped file name */
s = shell_quote(get_filename(curr_ifile));
ap_str(s);
free(s);
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(vlinenum(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(vlinenum(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(constant char *p)
{
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.
*/
if (p[1] != '\0')
++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(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 = sindex_from_sline(jump_sline); break;
default: *wp = TOP; p--; break;
}
}
return (p);
}
/*
* Construct a message based on a prototype string.
*/
public char * pr_expand(constant char *proto)
{
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 */
if (p[1] != '\0')
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 ("");
return (message);
}
/*
* Return a message suitable for printing by the "=" command.
*/
public char * eq_message(void)
{
return (pr_expand(eqproto));
}
/*
* 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(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]);
new_file = 0;
return (prompt);
}
/*
* Return a message suitable for printing while waiting in the F command.
*/
public char * wait_message(void)
{
return (pr_expand(wproto));
}

34
third_party/less/regexp.h vendored Normal file
View file

@ -0,0 +1,34 @@
/*
* Definitions etc. for regexp(3) routines.
*
* Caveat: this is V8 regexp(3) [actually, a reimplementation thereof],
* not the System V one.
*/
#ifndef _REGEXP
#define _REGEXP 1
#define NSUBEXP 10
typedef struct regexp {
char *startp[NSUBEXP];
char *endp[NSUBEXP];
char regstart; /* Internal use only. */
char reganch; /* Internal use only. */
char *regmust; /* Internal use only. */
int regmlen; /* Internal use only. */
char program[1]; /* Unwarranted chumminess with compiler. */
} regexp;
#if defined(__STDC__) || defined(__cplusplus)
# define _ANSI_ARGS_(x) x
#else
# define _ANSI_ARGS_(x) ()
#endif
extern regexp *regcomp _ANSI_ARGS_((char *exp));
extern int regexec _ANSI_ARGS_((regexp *prog, char *string));
extern int regexec2 _ANSI_ARGS_((regexp *prog, char *string, int notbol));
extern void regsub _ANSI_ARGS_((regexp *prog, char *source, char *dest));
extern void regerror _ANSI_ARGS_((char *msg));
#endif /* REGEXP */

3018
third_party/less/screen.c vendored Normal file

File diff suppressed because it is too large Load diff

1868
third_party/less/search.c vendored Normal file

File diff suppressed because it is too large Load diff

261
third_party/less/signal.c vendored Normal file
View file

@ -0,0 +1,261 @@
/*
* Copyright (C) 1984-2023 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 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 <signal.h>
/*
* "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 secure;
extern long jump_sline_fraction;
/*
* Interrupt signal handler.
*/
#if MSDOS_COMPILER!=WIN32C
/* ARGSUSED*/
static RETSIGTYPE 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 HILITE_SEARCH
set_filter_pattern(NULL, 0);
#endif
if (reading)
intread(); /* May longjmp */
}
#endif
#ifdef SIGTSTP
/*
* "Stop" (^Z) signal handler.
*/
/* ARGSUSED*/
static RETSIGTYPE stop(int type)
{
LSIGNAL(SIGTSTP, stop);
sigs |= S_STOP;
if (reading)
intread();
}
#endif
#undef SIG_LESSWINDOW
#ifdef SIGWINCH
#define SIG_LESSWINDOW SIGWINCH
#else
#ifdef SIGWIND
#define SIG_LESSWINDOW SIGWIND
#endif
#endif
#ifdef SIG_LESSWINDOW
/*
* "Window" change handler
*/
/* ARGSUSED*/
public RETSIGTYPE winch(int type)
{
LSIGNAL(SIG_LESSWINDOW, winch);
sigs |= S_WINCH;
if (reading)
intread();
}
#endif
#if MSDOS_COMPILER==WIN32C
/*
* Handle CTRL-C and CTRL-BREAK keys.
*/
#define WIN32_LEAN_AND_MEAN
/* #include <windows.h> */
static BOOL WINAPI wbreak_handler(DWORD dwCtrlType)
{
switch (dwCtrlType)
{
case CTRL_C_EVENT:
case CTRL_BREAK_EVENT:
sigs |= S_INTERRUPT;
#if HILITE_SEARCH
set_filter_pattern(NULL, 0);
#endif
return (TRUE);
default:
break;
}
return (FALSE);
}
#endif
static RETSIGTYPE terminate(int type)
{
quit(15);
}
/*
* Set up the signal handlers.
*/
public void init_signals(int on)
{
if (on)
{
/*
* Set signal handlers.
*/
#if MSDOS_COMPILER==WIN32C
SetConsoleCtrlHandler(wbreak_handler, TRUE);
#else
(void) LSIGNAL(SIGINT, u_interrupt);
#endif
#ifdef SIGTSTP
(void) LSIGNAL(SIGTSTP, secure ? SIG_IGN : stop);
#endif
#ifdef SIGWINCH
(void) LSIGNAL(SIGWINCH, winch);
#endif
#ifdef SIGWIND
(void) LSIGNAL(SIGWIND, winch);
#endif
#ifdef SIGQUIT
(void) LSIGNAL(SIGQUIT, SIG_IGN);
#endif
#ifdef SIGTERM
(void) LSIGNAL(SIGTERM, terminate);
#endif
} else
{
/*
* Restore signals to defaults.
*/
#if MSDOS_COMPILER==WIN32C
SetConsoleCtrlHandler(wbreak_handler, FALSE);
#else
(void) LSIGNAL(SIGINT, SIG_DFL);
#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
#ifdef SIGTERM
(void) LSIGNAL(SIGTERM, SIG_DFL);
#endif
}
}
/*
* Process any signals we have received.
* A received signal cause a bit to be set in "sigs".
*/
public void psignals(void)
{
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);
}
}

758
third_party/less/tags.c vendored Normal file
View file

@ -0,0 +1,758 @@
/*
* Copyright (C) 1984-2023 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;
extern int ctldisp;
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 definition (global) */
T_GRTAGS, /* 'GRTAGS': function reference (global) */
T_GSYMS, /* 'GSYMS': other symbols (global) */
T_GPATH /* 'GPATH': path name (global) */
};
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;
};
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 '$' */
};
#define TAG_END ((struct tag *) &taglist)
static struct taglist taglist = { TAG_END, TAG_END };
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(void)
{
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->tag_file);
free(tp->tag_pattern);
free(tp);
}
curtag = NULL;
total = curseq = 0;
}
/*
* Create a new tag entry.
*/
static struct tag * maketagent(char *name, char *file, LINENUM linenum, char *pattern, int endline)
{
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(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(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(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(int n)
{
char *tagfile = (char *) NULL;
while (n-- > 0)
tagfile = nextgtag();
return tagfile;
}
/*
* Go to the previous tag.
*/
public char * prevtag(int n)
{
char *tagfile = (char *) NULL;
while (n-- > 0)
tagfile = prevgtag();
return tagfile;
}
/*
* Return the total number of tags.
*/
public int ntags(void)
{
return total;
}
/*
* Return the sequence number of current tag.
*/
public int curr_tag(void)
{
return curseq;
}
/*****************************************************************************
* ctags
*/
/*
* Find tags in the "tags" file.
* Sets curtag to the first tag entry.
*/
static enum tag_result findctag(char *tag)
{
char *p;
char *q;
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 = q = p;
while (*p != search_char && *p != '\0')
{
if (*p == '\\')
p++;
if (q != p)
{
*q++ = *p++;
} else
{
q++;
p++;
}
}
tagendline = (q[-1] == '$');
if (tagendline)
q--;
*q = '\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(void)
{
if (curtag == NULL)
return (1);
return (edit(curtag->tag_file));
}
static int curtag_match(char constant *line, POSITION linepos)
{
/*
* 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).
*/
int 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);
return 1;
}
return 0;
}
/*
* 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(void)
{
POSITION pos, linepos;
LINENUM linenum;
int line_len;
char *line;
int found;
pos = ch_zero();
linenum = find_linenum(pos);
for (found = 0; !found;)
{
/*
* 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, &line_len);
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);
if (ctldisp != OPT_ONPLUS)
{
if (curtag_match(line, linepos))
found = 1;
} else
{
int cvt_ops = CVT_ANSI;
int cvt_len = cvt_length(line_len, cvt_ops);
int *chpos = cvt_alloc_chpos(cvt_len);
char *cline = (char *) ecalloc(1, cvt_len);
cvt_text(cline, line, chpos, &line_len, cvt_ops);
if (curtag_match(cline, linepos))
found = 1;
free(chpos);
free(cline);
}
}
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(char *tag, int type)
{
char buf[1024];
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 (isnullenv(cmd))
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(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(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(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]
* <tag> <lineno> <file> <image>
* +------------------------------------------------
* |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 <http://www.gnu.org/software/global/global.html>
*
* [extended format]
* <tag> <type> <lineno> <file> <image>
* +----------------------------------------------------------
* |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 <http://ctags.sourceforge.net>
*
* Returns 0 on success, -1 on error.
* The tag, file, and line will each be NUL-terminated pointers
* into buf.
*/
static int 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

251
third_party/less/ttyin.c vendored Normal file
View file

@ -0,0 +1,251 @@
/*
* Copyright (C) 1984-2023 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
#define WIN32_LEAN_AND_MEAN
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x400
#endif
/* #include <windows.h> */
public DWORD console_mode;
public HANDLE tty;
#else
public int tty;
#endif
#if LESSTEST
public char *ttyin_name = NULL;
#endif /*LESSTEST*/
extern int sigs;
extern int utf_mode;
extern int wheel_lines;
#if !MSDOS_COMPILER
static int open_tty_device(constant char* dev)
{
#if OS2
/* The __open() system call translates "/dev/tty" to "con". */
return __open(dev, OPEN_READ);
#else
return open(dev, OPEN_READ);
#endif
}
/*
* Open the tty device.
* Try ttyname(), then try /dev/tty, then use file descriptor 2.
* In Unix, file descriptor 2 is usually attached to the screen,
* but also usually lets you read from the keyboard.
*/
public int open_tty(void)
{
int fd = -1;
#if LESSTEST
if (ttyin_name != NULL)
fd = open_tty_device(ttyin_name);
#endif /*LESSTEST*/
#if HAVE_TTYNAME
if (fd < 0)
{
constant char *dev = ttyname(2);
if (dev != NULL)
fd = open_tty_device(dev);
}
#endif
if (fd < 0)
fd = open_tty_device("/dev/tty");
if (fd < 0)
fd = 2;
return fd;
}
#endif /* MSDOS_COMPILER */
/*
* Open keyboard for input.
*/
public void 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 = CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ, &sa,
OPEN_EXISTING, 0L, NULL);
GetConsoleMode(tty, &console_mode);
/* Make sure we get Ctrl+C events. */
SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_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
tty = open_tty();
#endif
#endif
}
/*
* Close the keyboard.
*/
public void close_getchr(void)
{
#if MSDOS_COMPILER==WIN32C
SetConsoleMode(tty, console_mode);
CloseHandle(tty);
#endif
}
#if MSDOS_COMPILER==WIN32C
/*
* Close the pipe, restoring the keyboard (CMD resets it, losing the mouse).
*/
public int pclose(FILE *f)
{
int result;
result = _pclose(f);
SetConsoleMode(tty, ENABLE_PROCESSED_INPUT | ENABLE_MOUSE_INPUT);
return result;
}
#endif
/*
* Get the number of lines to scroll when mouse wheel is moved.
*/
public int default_wheel_lines(void)
{
int lines = 1;
#if MSDOS_COMPILER==WIN32C
if (SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &lines, 0))
{
if (lines == WHEEL_PAGESCROLL)
lines = 3;
}
#endif
return lines;
}
/*
* Get a character from the keyboard.
*/
public int getchr(void)
{
char c;
int result;
do
{
flush();
#if MSDOS_COMPILER && MSDOS_COMPILER != DJGPPC
/*
* In raw read, we don't see ^C so look here for it.
*/
#if MSDOS_COMPILER==WIN32C
if (ABORT_SIGS())
return (READ_INTR);
c = WIN32getch();
#else
c = getch();
#endif
result = 1;
if (c == '\003')
return (READ_INTR);
#else
{
unsigned char uc;
result = iread(tty, &uc, sizeof(char));
c = (char) uc;
}
if (result == READ_INTR)
return (READ_INTR);
if (result < 0)
{
/*
* Don't call error() here,
* because error calls getchr!
*/
quit(QUIT_ERROR);
}
#endif
#if LESSTEST
if (c == LESS_DUMP_CHAR)
{
dump_screen();
result = 0;
continue;
}
#endif
#if 0 /* allow entering arbitrary hex chars for testing */
/* ctrl-A followed by two hex chars makes a byte */
{
static int hex_in = 0;
static 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
v = 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);
}

11
third_party/less/ubin.inc vendored Normal file
View file

@ -0,0 +1,11 @@
/* Generated by "./mkutable -f2 Cc Cs Co Zl Zp -- unicode/UnicodeData.txt" on Mon Nov 14 18:19:24 PST 2022 */
{ 0x0000, 0x0007 }, /* Cc */
{ 0x000b, 0x000b }, /* Cc */
{ 0x000e, 0x001f }, /* Cc */
{ 0x007f, 0x009f }, /* Cc */
{ 0x2028, 0x2028 }, /* Zl */
{ 0x2029, 0x2029 }, /* Zp */
{ 0xd800, 0xdfff }, /* Cs */
{ 0xe000, 0xf8ff }, /* Co */
{ 0xf0000, 0xffffd }, /* Co */
{ 0x100000, 0x10fffd }, /* Co */

998
third_party/less/version.c vendored Normal file
View file

@ -0,0 +1,998 @@
/*
* Copyright (C) 1984-2023 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.
*/
/*
----------------------- CHANGE HISTORY --------------------------
1/29/84 Allowed use on standard input
2/1/84 Added E, N, P commands
4/17/84 Added '=' command, 'stop' signal handling
4/20/84 Added line folding
v2 4/27/84 Fixed '=' command to use BOTTOM_PLUS_ONE,
instead of TOP, added 'p' & 'v' commands
v3 5/3/84 Added -m and -t options, '-' command
v4 5/3/84 Added LESS environment variable
v5 5/3/84 New comments, fixed '-' command slightly
v6 5/15/84 Added -Q, visual bell
v7 5/24/84 Fixed jump_back(n) bug: n should count real
lines, not folded lines. Also allow number on G command.
v8 5/30/84 Re-do -q and -Q commands
v9 9/25/84 Added "+<cmd>" argument
v10 10/10/84 Fixed bug in -b<n> argument processing
v11 10/18/84 Made error() ring bell if \n not entered.
-----------------------------------------------------------------
v12 2/13/85 Reorganized signal handling and made portable to 4.2bsd.
v13 2/16/85 Reword error message for '-' command.
v14 2/22/85 Added -bf and -bp variants of -b.
v15 2/25/85 Miscellaneous changes.
v16 3/13/85 Added -u flag for backspace processing.
v17 4/13/85 Added j and k commands, changed -t default.
v18 4/20/85 Rewrote signal handling code.
v19 5/2/85 Got rid of "verbose" eq_message().
Made search() scroll in some cases.
v20 5/21/85 Fixed screen.c ioctls for System V.
v21 5/23/85 Fixed some first_cmd bugs.
v22 5/24/85 Added support for no RECOMP nor REGCMP.
v23 5/25/85 Miscellanous changes and prettying up.
Posted to USENET.
-----------------------------------------------------------------
v24 6/3/85 Added ti,te terminal init & de-init.
(Thanks to Mike Kersenbrock)
v25 6/8/85 Added -U flag, standout mode underlining.
v26 6/9/85 Added -M flag.
Use underline termcap (us) if it exists.
v27 6/15/85 Renamed some variables to make unique in
6 chars. Minor fix to -m.
v28 6/28/85 Fixed right margin bug.
v29 6/28/85 Incorporated M.Rose's changes to signal.c
v30 6/29/85 Fixed stupid bug in argument processing.
v31 7/15/85 Added -p flag, changed repaint algorithm.
Added kludge for magic cookie terminals.
v32 7/16/85 Added cat_file if output not a tty.
v33 7/23/85 Added -e flag and EDITOR.
v34 7/26/85 Added -s flag.
v35 7/27/85 Rewrote option handling; added option.c.
v36 7/29/85 Fixed -e flag to work if not last file.
v37 8/10/85 Added -x flag.
v38 8/19/85 Changed prompting; created prompt.c.
v39 8/24/85 (Not -p) does not initially clear screen.
v40 8/26/85 Added "skipping" indicator in forw().
Posted to USENET.
-----------------------------------------------------------------
v41 9/17/85 ONLY_RETURN, control char commands,
faster search, other minor fixes.
v42 9/25/85 Added ++ command line syntax;
ch_fsize for pipes.
v43 10/15/85 Added -h flag, changed prim.c algorithms.
v44 10/16/85 Made END print in all cases of eof;
ignore SIGTTOU after receiv ing SIGTSTP.
v45 10/16/85 Never print backspaces unless -u.
v46 10/24/85 Backwards scroll in jump_loc.
v47 10/30/85 Fixed bug in edit(): *first_cmd==0
v48 11/16/85 Use TIOCSETN instead of TIOCSETP.
Added marks (m and ' commands).
Posted to USENET.
-----------------------------------------------------------------
v49 1/9/86 Fixed bug: signal didn't clear mcc.
v50 1/15/86 Added ' (quote) to gomark.
v51 1/16/86 Added + cmd, fixed problem if first_cmd
fails, made g cmd sort of "work" on pipes
ev en if bof is no longer buffered.
v52 1/17/86 Made short files work better.
v53 1/20/86 Added -P option.
v54 1/20/86 Changed help to use HELPFILE.
v55 1/23/86 Messages work better if not tty output.
v56 1/24/86 Added -l option.
v57 1/31/86 Fixed -l to get confirmation before
ov erwriting an existing file.
v58 8/28/86 Added filename globbing.
v59 9/15/86 Fixed some bugs with very long filenames.
v60 9/26/86 Incorporated changes from Leith (Casey)
Leedom for boldface and -z option.
v61 9/26/86 Got rid of annoying repaints after ! cmd.
Posted to USENET.
-----------------------------------------------------------------
v62 12/23/86 Added is_directory(); change -z default to
-1 instead of 24; cat-and-exit if -e and
file is less than a screenful.
v63 1/8/87 Fixed bug in cat-and-exit if > 1 file.
v64 1/12/87 Changed puts/putstr, putc/putchr,
getc/getchr to av oid name conflict with
stdio functions.
v65 1/26/87 Allowed '-' command to change NUMBER
v alued options (thanks to Gary Puckering)
v66 2/13/87 Fixed bug: prepaint should use force=1.
v67 2/24/87 Added !! and % expansion to ! command.
v68 2/25/87 Added SIGWINCH and TIOCGWINSZ support;
changed is_directory to bad_file.
(thanks to J. Robert Ward)
v69 2/25/87 Added SIGWIND and WIOCGETD (for Unix PC).
v70 3/13/87 Changed help cmd from 'h' to 'H'; better
error msgs in bad_file, errno_message.
v71 5/11/87 Changed -p to -c, made triple -c/-C
for clear-eol like more's -c.
v72 6/26/87 Added -E, -L, use $SHELL in lsystem().
(thanks to Stev e Spearman)
v73 6/26/87 Allow Examine "#" for previous file.
Posted to USENET 8/25/87.
-----------------------------------------------------------------
v74 9/18/87 Fix conflict in EOF symbol with stdio.h,
Make os.c more portable to BSD.
v75 9/23/87 Fix problems in get_term (thanks to
Paul Eggert); new backwards scrolling in
jump_loc (thanks to Marion Hakanson).
v76 9/23/87 Added -i flag; allow single "!" to
inv oke a shell (thanks to Franco Barber).
v77 9/24/87 Added -n flag and line number support.
v78 9/25/87 Fixed problem with prompts longer than
the screen width.
v79 9/29/87 Added the _ command.
v80 10/6/87 Allow signal to break out of linenum scan.
v81 10/6/87 Allow -b to be changed from within less.
v82 10/7/87 Add cmd_decode to use a table for key
binding (thanks to Dav id Nason).
v83 10/9/87 Allow .less file for user-defined keys.
v84 10/11/87 Fix -e/-E problems (thanks to Felix Lee).
v85 10/15/87 Search now keeps track of line numbers.
v86 10/20/87 Added -B option and autobuf; fixed
"pipe error" bug.
v87 3/1/88 Fix bug re BSD signals while reading file.
v88 3/12/88 Use new format for -P option (thanks to
der Mouse), allow "+-c" without message,
fix bug re BSD hangup.
v89 3/18/88 Turn off line numbers if linenum scan
is interrupted.
v90 3/30/88 Allow -P from within less.
v91 3/30/88 Added tags file support (new -t option)
(thanks to Brian Campbell).
v92 4/4/88 Added -+option syntax.
v93 4/11/88 Add support for slow input (thanks to
Joe Orost & apologies for taking almost
3 years to get this in!)
v94 4/11/88 Redo reading/signal stuff.
v95 4/20/88 Repaint screen better after signal.
v96 4/21/88 Add /! and ?! commands.
v97 5/17/88 Allow -l/-L from within less.
Eliminate some static arrays (use calloc).
Posted to USENET.
-----------------------------------------------------------------
v98 10/14/88 Fix incorrect calloc call; uninitialized
var in exec_mca; core dump on unknown TERM.
Make v cmd work if past last line of file.
Fix some signal bugs.
v99 10/29/88 Allow space between -X and string,
when X is a string-valued option.
v100 1/5/89 Fix globbing bug when $SHELL not set;
allow spaces after -t command.
v101 1/6/89 Fix problem with long (truncated) lines
in tags file (thanks to Neil Dixon).
v102 1/6/89 Fix bug with E# when no prev file;
allow spaces after -l command.
v103 3/14/89 Add -N, -f and -? options. Add z and w
commands. Add %L for prompt strings.
v104 3/16/89 Added EDITPROTO.
v105 3/20/89 Fix bug in find_linenum which cached
incorrectly on long lines.
v106 3/31/89 Added -k option and multiple lesskey
files.
v107 4/27/89 Add 8-bit char support and -g option.
Split option code into 3 files.
v108 5/5/89 Allocate position table dynamically
(thanks to Paul Eggert); change % command
from "percent" to vi-style brace finder.
v109 5/10/89 Added ESC-% command, split prim.c.
v110 5/24/89 Fixed bug in + option; fixed repaint bug
under Sun windows (thanks to Paul Eggert).
v111 5/25/89 Generalized # and % expansion; use
calloc for some error messages.
v112 5/30/89 Get rid of ESC-%, add {}()[] commands.
v113 5/31/89 Optimize lseeks (thanks to Paul Eggert).
v114 7/25/89 Added ESC-/ and ESC-/! commands.
v115 7/26/89 Added ESC-n command.
v116 7/31/89 Added find_pos to optimize g command.
v117 8/1/89 Change -f option to -r.
v118 8/2/89 Save positions for all previous files,
not just the immediately previous one.
v119 8/7/89 Save marks across file boundaries.
Add file handle stuff.
v120 8/11/89 Add :ta command.
v121 8/16/89 Add -f option.
v122 8/30/89 Fix performance with many buffers.
v123 8/31/89 Verbose prompts for string options.
Posted beta to USENET.
-----------------------------------------------------------------
v124 9/18/89 Reorganize search commands,
N = rev, ESC-n = span, add ESC-N.
v125 9/18/89 Fix tab bug (thanks to Alex Liu).
Fix EOF bug when both -w and -c.
v126 10/25/89 Add -j option.
v127 10/27/89 Fix problems with blank lines before BOF.
v128 10/27/89 Add %bj, etc. to prompt strings.
v129 11/3/89 Add -+,-- commands; add set-option and
unset-option to lesskey.
v130 11/6/89 Generalize A_EXTRA to string, remove
set-option, unset-option from lesskey.
v131 11/7/89 Changed name of EDITPROTO to LESSEDIT.
v132 11/8/89 Allow editing of command prefix.
v133 11/16/89 Add -y option (thanks to Jeff Sullivan).
v134 12/1/89 Glob filenames in the -l command.
v135 12/5/89 Combined {}()[] commands into one, and
added ESC-^F and ESC-^B commands.
v136 1/20/90 Added -S, -R flags. Added | command.
Added warning for binary files. (thanks
to Richard Brittain and J. Sullivan).
v137 1/21/90 Rewrote horrible pappend code.
Added * notation for hi-bit chars.
v138 1/24/90 Fix magic cookie terminal handling.
Get rid of "cleanup" loop in ch_get.
v139 1/27/90 Added MSDOS support. (many thanks
to Richard Brittain).
v140 2/7/90 Editing a new file adds it to the
command line list.
v141 2/8/90 Add edit_list for editing >1 file.
v142 2/10/90 Add :x command.
v143 2/11/90 Add * and @ modifies to search cmds.
Change ESC-/ cmd from /@* to / *.
v144 3/1/90 Messed around with ch_zero;
no real change.
v145 3/2/90 Added -R and -v/-V for MSDOS;
renamed FILENAME to avoid conflict.
v146 3/5/90 Pull cmdbuf functions out of command.c
v147 3/7/90 Implement ?@; fix multi-file edit bugs.
v148 3/29/90 Fixed bug in :e<file> then :e#.
v149 4/3/90 Change error,ierror,query to use PARG.
v150 4/6/90 Add LESS_CHARSET, LESS_CHARDEF.
v151 4/13/90 Remove -g option; clean up ispipe.
v152 4/14/90 lsystem() closes input file, for
editors which require exclusive open.
v153 4/18/90 Fix bug if SHELL unset;
fix bug in overstrike control char.
v154 4/25/90 Output to fd 2 via buffer.
v155 4/30/90 Ignore -i if uppercase in pattern
(thanks to Michael Rendell.)
v156 5/3/90 Remove scroll limits in forw() & back();
causes problems with -c.
v157 5/4/90 Forward search starts at next real line
(not screen line) after jump target.
v158 6/14/90 Added F command.
v159 7/29/90 Fix bug in exiting: output not flushed.
v160 7/29/90 Clear screen before initial output w/ -c.
v161 7/29/90 Add -T flag.
v162 8/14/90 Fix bug with +F on command line.
v163 8/21/90 Added LESSBINFMT variable.
v164 9/5/90 Added -p, LINES, COLUMNS and
unset mark ' == BOF, for 1003.2 D5.
v165 9/6/90 At EOF with -c set, don't display empty
screen when try to page forward.
v166 9/6/90 Fix G when final line in file wraps.
v167 9/11/90 Translate CR/LF -> LF for 1003.2.
v168 9/13/90 Return to curr file if "tag not found".
v169 12/12/90 G goes to EOF even if file has grown.
v170 1/17/91 Add optimization for BSD _setjmp;
fix #include ioctl.h TERMIO problem.
(thanks to Paul Eggert)
Posted to USENET.
-----------------------------------------------------------------
v171 3/6/91 Fix -? bug in get_filename.
v172 3/15/91 Fix G bug in empty file.
Fix bug with ?\n and -i and uppercase
pattern at EOF!
(thanks to Paul Eggert)
v173 3/17/91 Change N cmd to not permanently change
direction. (thanks to Brian Matthews)
v174 3/18/91 Fix bug with namelogfile not getting
cleared when change files.
v175 3/18/91 Fix bug with ++cmd on command line.
(thanks to Jim Meyering)
v176 4/2/91 Change | to not force current screen,
include marked line, start/end from
top of screen. Improve search speed.
(thanks to Don Mears)
v177 4/2/91 Add LESSHELP variable.
Fix bug with F command with -e.
Try /dev/tty for input before using fd 2.
Patches posted to USENET 4/2/91.
-----------------------------------------------------------------
v178 4/8/91 Fixed bug in globbing logfile name.
(thanks to Jim Meyering)
v179 4/9/91 Allow negative -z for screen-relative.
v180 4/9/91 Clear to eos rather than eol if "db";
don't use "sr" if "da".
(thanks to Tor Lillqvist)
v181 4/18/91 Fixed bug with "negative" chars 80 - FF.
(thanks to Benny Sander Hofmann)
v182 5/16/91 Fixed bug with attribute at EOL.
(thanks to Brian Matthews)
v183 6/1/91 Rewrite linstall to do smart config.
v184 7/11/91 Process \b in searches based on -u
rather than -i.
v185 7/11/91 -Pxxx sets short prompt; assume SIGWINCH
after a SIGSTOP. (thanks to Ken Laprade)
-----------------------------------------------------------------
v186 4/20/92 Port to MS-DOS (Microsoft C).
v187 4/23/92 Added -D option & TAB_COMPLETE_FILENAME.
v188 4/28/92 Added command line editing features.
v189 12/8/92 Fix mem overrun in anscreen.c:init;
fix edit_list to recover from bin file.
v190 2/13/93 Make TAB enter one filename at a time;
create ^L with old TAB functionality.
v191 3/10/93 Defer creating "flash" page for MS-DOS.
v192 9/6/93 Add BACK-TAB.
v193 9/17/93 Simplify binary_file handling.
v194 1/4/94 Add rudiments of alt_filename handling.
v195 1/11/94 Port back to Unix; support keypad.
-----------------------------------------------------------------
v196 6/7/94 Fix bug with bad filename; fix IFILE
type problem. (thanks to David MacKenzie)
v197 6/7/94 Fix bug with .less tables inserted wrong.
v198 6/23/94 Use autoconf installation technology.
(thanks to David MacKenzie)
v199 6/29/94 Fix MS-DOS build (thanks to Tim Wiegman).
v200 7/25/94 Clean up copyright, minor fixes.
Posted to prep.ai.mit.edu
-----------------------------------------------------------------
v201 7/27/94 Check for no memcpy; add casts to calloc;
look for regcmp in libgen.a.
(thanks to Kaveh Ghazi).
v202 7/28/94 Fix bug in edit_next/edit_prev with
non-existent files.
v203 8/2/94 Fix a variety of configuration bugs on
various systems. (thanks to Sakai
Kiyotaka, Harald Koenig, Bjorn Brox,
Teemu Rantanen, and Thorsten Lockert)
v204 8/3/94 Use strerror if available.
(thanks to J.T. Conklin)
v205 8/5/94 Fix bug in finding "me" termcap entry.
(thanks to Andreas Stolcke)
8/10/94 v205+: Change BUFSIZ to LBUFSIZE to avoid name
conflict with stdio.h.
Posted to prep.ai.mit.edu
-----------------------------------------------------------------
v206 8/10/94 Use initial_scrpos for -t to avoid
displaying first page before init().
(thanks to Dominique Petitpierre)
v207 8/12/94 Fix bug if stdout is not tty.
v208 8/16/94 Fix bug in close_altfile if goto err1
in edit_ifile. (Thanks to M.J. Hewitt)
v209 8/16/94 Change scroll to wscroll to avoid
conflict with library function.
v210 8/16/94 Fix bug with bold on 8 bit chars.
(thanks to Vitor Duarte)
v211 8/16/94 Don't quit on EOI in jump_loc / forw.
v212 8/18/94 Use time_t if available.
v213 8/20/94 Allow ospeed to be defined in termcap.h.
v214 8/20/94 Added HILITE_SEARCH, -F, ESC-u cmd.
(thanks to Paul Lew and Bob Byrnes)
v215 8/23/94 Fix -i toggle behavior.
v216 8/23/94 Process BS in all searches, not only -u.
v217 8/24/94 Added -X flag.
v218 8/24/94 Reimplement undo_search.
v219 8/24/94 Find tags marked with line number
instead of pattern.
v220 8/24/94 Stay at same position after SIG_WINCH.
v221 8/24/94 Fix bug in file percentage in big file.
v222 8/25/94 Do better if can't reopen current file.
v223 8/27/94 Support setlocale.
(thanks to Robert Joop)
v224 8/29/94 Revert v216: process BS in search
only if -u.
v225 9/6/94 Rewrite undo_search again: toggle.
v226 9/15/94 Configuration fixes.
(thanks to David MacKenzie)
v227 9/19/94 Fixed strerror config problem.
Posted to prep.ai.mit.edu
-----------------------------------------------------------------
v228 9/21/94 Fix bug in signals: repeated calls to
get_editkeys overflowed st_edittable.
v229 9/21/94 Fix "Nothing to search" error if -a
and SRCH_PAST_EOF.
v230 9/21/94 Don't print extra error msg in search
after regerror().
v231 9/22/94 Fix hilite bug if search matches 0 chars.
(thanks to John Polstra)
v232 9/23/94 Deal with weird systems that have
termios.h but not tcgetattr().
Posted to prep.ai.mit.edu
-----------------------------------------------------------------
v233 9/26/94 Use get_term() instead of pos_init() in
psignals to re-get lower_left termcap.
(Thanks to John Malecki)
v234 9/26/94 Make MIDDLE closer to middle of screen.
v235 9/27/94 Use local strchr if system doesn't have.
v236 9/28/94 Don't use libucb; use libterm if
libtermcap & libcurses doesn't work.
(Fix for Solaris; thanks to Frank Kaefer)
v237 9/30/94 Use system isupper() etc if provided.
Posted to prep.ai.mit.edu
-----------------------------------------------------------------
v238 10/6/94 Make binary non-blinking if LESSBINFMT
is set to a string without a *.
v239 10/7/94 Don't let delimit_word run back past
beginning of cmdbuf.
v240 10/10/94 Don't write into termcap buffer.
(Thanks to Benoit Speckel)
v241 10/13/94 New lesskey file format.
Don't expand filenames in search command.
v242 10/14/94 Allow lesskey specification of "literal".
v243 10/14/94 Add #stop command to lesskey.
v244 10/16/94 Add -f flag to lesskey.
v245 10/25/94 Allow TAB_COMPLETE_FILENAME to be undefd.
v246 10/27/94 Move help file to /usr/local/share.
v247 10/27/94 Add -V option.
v248 11/5/94 Add -V option to lesskey.
v249 11/5/94 Remove -f flag from lesskey; default
input file is ~/.lesskey.in, not stdin.
v250 11/7/94 Lesskey input file "-" means stdin.
v251 11/9/94 Convert cfgetospeed result to ospeed.
(Thanks to Andrew Chernov)
v252 11/16/94 Change default lesskey input file from
.lesskey.in to .lesskey.
Posted to prep.ai.mit.edu
-----------------------------------------------------------------
v253 11/21/94 Fix bug when tags file has a backslash.
v254 12/6/94 Fix -k option.
v255 12/8/94 Add #define EXAMINE to disable :e etc.
v256 12/10/94 Change highlighting: only highlite search
results (but now it is reliable).
v257 12/10/94 Add goto_line and repaint_highlight
to optimize highlight repaints.
v258 12/12/94 Fixup in hilite_line if BS_SPECIAL.
v259 12/12/94 Convert to autoconf 2.0.
v260 12/13/94 Add SECURE define.
v261 12/14/94 Use system WERASE char as EC_W_BACKSPACE.
v262 12/16/94 Add -g/-G flag and screen_hilite.
v263 12/20/94 Reimplement/optimize -G flag behavior.
v264 12/23/94 Allow EXTRA string after line-edit cmd
in lesskey file.
v265 12/24/94 Add LESSOPEN=|cmd syntax.
v266 12/26/94 Add -I flag.
v267 12/28/94 Formalize the four-byte header emitted
by a LESSOPEN pipe.
v268 12/28/94 Get rid of four-byte header.
v269 1/2/95 Close alt file before open new one.
Avoids multiple popen().
v270 1/3/95 Use VISUAL; use S_ISDIR/S_ISREG; fix
config problem with Solaris POSIX regcomp.
v271 1/4/95 Don't quit on read error.
v272 1/5/95 Get rid of -L.
v273 1/6/95 Fix ch_ungetchar bug; don't call
LESSOPEN on a pipe.
v274 1/6/95 Ported to OS/2 (thanks to Kai Uwe Rommel)
v275 1/18/95 Fix bug if toggle -G at EOF.
v276 1/30/95 Fix OS/2 version.
v277 1/31/95 Add "next" charset; don't display ^X
for X > 128.
v278 2/14/95 Change default for -G.
Posted to prep.ai.mit.edu
-----------------------------------------------------------------
v279 2/22/95 Add GNU options --help, --version.
Minor config fixes.
v280 2/24/95 Clean up calls to glob(); don't set #
if we can't open the new file.
v281 2/24/95 Repeat search should turn on hilites.
v282 3/2/95 Minor fixes.
v283 3/2/95 Fix homefile; make OS2 look in $HOME.
v284 3/2/95 Error if "v" on LESSOPENed file;
"%" figures out file size on pipe.
v285 3/7/95 Don't set # in lsystem;
lesskey try $HOME first.
v286 3/7/95 Reformat change history (too much free time?).
v287 3/8/95 Fix hilite bug if overstrike multiple chars.
v288 3/8/95 Allow lesskey to override get_editkey keys.
v289 3/9/95 Fix adj_hilite bug when line gets processed by
hilite_line more than once.
v290 3/9/95 Make configure automatically. Fix Sequent problem
with incompatible sigsetmask().
Posted to prep.ai.mit.edu
-----------------------------------------------------------------
v291 3/21/95 Add #env to lesskey. Fix MS-DOS build.
Posted to simtel.
-----------------------------------------------------------------
v292 4/24/95 Add MS-DOS support for Borland C.
Fix arrow keys in MS-DOS versions.
v293 4/28/95 Add auto-versioning stuff to make dist.
v294 5/12/95 Fix Borland build.
v295 1/20/96 Fix search on squished file; add /@@.
v296 1/23/96 Allow cmdbuf larger than screen width.
v297 1/24/96 Don't call termcap if tgetent fails;
add #defines for buffers.
v298 1/24/96 Change @@ to ^K.
Add alternate search modifiers ^N, ^F, ^E.
v299 1/25/96 Fix percent overflow in jump_percent (thanks to Brent Wiese);
don't send "ti" after shell command till RETURN pressed.
v300 1/25/96 Change -U to print tabs as ^I.
v301 1/30/96 Make hilites work in cmd F output.
v302 1/31/96 Fix cmd F to notice window-change signals.
v303 1/31/96 Add ESC-SPACE command.
v304 2/1/96 Add ^R search modifier; add LESSSECURE.
v305 2/2/96 Workaround Linux /proc kernel bug; add LESSKEY.
v306 3/16/96 Minor fixes.
v307 3/25/96 Allow cmd line arg "--"; fix DOS & OS/2 defines.h.
v308 4/4/96 Port to OS-9 (thanks to Boisy Pitre); fix -d.
v309 4/9/96 Fix OS-9 version; fix tags bug with "$".
v310 4/10/96 Get rid of HELPFILE.
v311 4/22/96 Add Windows32 support; merge doscreen.c into screen.c.
v312 4/24/96 Don't quit after "cannot reopen" error.
v313 4/25/96 Added horizontal scrolling.
v314 4/26/96 Modified -e to quit on reaching end of a squished file.
v315 4/26/96 Fix "!;TAB" bug.
v316 5/2/96 Make "|a" when (a < curr screen) go to end of curr screen.
v317 5/14/96 Various fixes for the MS-DOS and OS/2 builds.
Added ## and %% handling for filenames
v318 5/29/96 Port to OS-9 Microware compiler; minor fixes
(thanks to Martin Gregorie).
v319 7/8/96 Fix Windows port (thanks to Jeff Paquette).
v320 7/11/96 Final fixes for Windows port.
v321 7/18/96 Minor fixes.
Posted to Web page.
-----------------------------------------------------------------
v322 8/13/96 Fix bug in shell escape from help file; add support for
Microsoft Visual C under Windows; numerous small fixes.
v323 8/19/96 Fixes for Windows version (thanks to Simon Munton);
fix for Linux library weirdness (thanks to Jim Diamond);
port to DJGPP (thanks to Eli Zaretskii).
v324 8/21/96 Add support for spaces in filenames (thanks to Simon Munton).
v325 8/21/96 Add lessecho, for spaces in filenames under Unix.
v326 8/27/96 Fix DJGPP version.
v327 9/1/96 Reorganize lglob, make spaces in filenames work better in Unix.
v328 10/7/96 Append / to directory name in filename completion.
Fix MS-DOS and OS-9 versions.
v329 10/11/96 Fix more MS-DOS bugs; add LESSSEPARATOR; add -" option.
Add LESSMETACHARS, LESSMETAESCAPE.
v330 10/21/96 Minor fixes.
Posted to Web page.
-----------------------------------------------------------------
v331 4/22/97 Various Windows fixes (thanks to Gurusamy Sarathy).
v332 4/22/97 Enter filenames from cmd line into edit history.
Posted to Web page.
-----------------------------------------------------------------
v333 3/4/99 Changed -w to highlite new line after forward movement.
v334 3/9/99 Avoid overflowing prompt buffer; add %d and %D.
v335 3/20/99 Add EBCDIC support (thanks to Thomas Dorner).
Use HOMEDRIVE/HOMEPATH on Windows (thanks to Preston Bannister).
Posted to Web page.
-----------------------------------------------------------------
v336 4/8/99 Fix installation bugs.
v337 4/9/99 Fix another installation bug.
Posted to Web page.
-----------------------------------------------------------------
v338 4/13/99 Add support for long option names.
v339 4/18/99 Add \k, long option names to lesskey. Add -^P. Add :d.
v340 4/21/99 Add regexec2. Fix Windows build.
Posted to Web page.
-----------------------------------------------------------------
v341 5/6/99 Add -F option; %c & ?c prompt escapes.
(Thanks to Michele Maltoni)
v342 7/22/99 Add system-wide lesskey file; allow GPL or Less License.
v343 9/23/99 Support UTF-8 (Thanks to Robert Brady).
Add %P and ?P in prompts.
v344 10/27/99 -w highlights target line of g and p commands.
v345 10/29/99 Make -R pass thru ESC but not other control chars.
Posted to Web page.
-----------------------------------------------------------------
v346 11/4/99 Fix bugs in long option processing; R cmd should clear hilites.
Posted to Web page.
-----------------------------------------------------------------
v347 12/13/99 Fixes for DJGPP version (thanks to Eli Zaretskii).
v348 12/28/99 Fix deleting file with marks (thanks to Dimitar Jekov).
Fix color problem in DJGPP version (thanks to Eli Zaretskii).
v349 1/24/00 Fix minor DJGPP bugs; check environment vars for UTF-8;
add --with-editor (thanks to Eli, Markus Kuhn, Thomas Schoepf).
v350 3/1/00 Fix clear-while-standout bug.
v351 3/5/00 Change -M and = prompts to show top & bottom line number.
Posted to Web page.
-----------------------------------------------------------------
v352 3/8/00 Fix scan_option NULL dereference.
-----------------------------------------------------------------
v353 3/20/00 Fix SECURE compile bug, allow space after numeric option.
v354 3/23/00 Add support for PCRE; add --with-regex configure option.
-----------------------------------------------------------------
v355 6/28/00 Add -# option (thanks to Andy Levinson).
v356 7/5/00 Add -J option.
v357 7/6/00 Support sigprocmask.
-----------------------------------------------------------------
v358 7/8/00 Fix problems with #stop in lesskey file.
Posted to Web page.
-----------------------------------------------------------------
v359 9/10/00 Fixes for Win32 display problems (thanks to Maurizio Vairani).
v360 1/17/01 Move sysless to etc.
v361 12/4/01 Add IBM-1047 charset & EBCDIC fixes (thanks to Thomas Dorner).
Fix 32 bit dependencies (thanks to Paul Eggert).
Fix UTF-8 overstriking (thanks to Robert Brady).
v362 12/4/01 Make status column show search targets.
v363 12/6/01 Add --no-keypad option.
Add variable width tabstops (thanks to Peter Samuelson).
v364 12/10/01 Better handling of very long lines in input;
Fix horizontal shifting of colored text.
v365 12/11/01 Fix overstriking of tabs;
Add support for global(1) and multiple tag matches
(thanks to Shigio Yamaguchi and Tim Vanderhoek).
v366 12/11/01 Fixes for OS/2 (thanks to Kyosuke Tokoro).
v367 12/13/01 Allow -D and -x options to terminate without dollar sign;
Right/left arrow when entering N are shift cmds, not line edit.
v368 12/18/01 Update lesskey commands.
v370 12/23/01 Fix tags error messages.
Posted to Web page.
-----------------------------------------------------------------
v371 12/26/01 Fix new_file bug; use popen in Windows version;
fix some compiler warnings.
v372 12/29/01 Make -b be in units of 1K.
v373 1/14/02 Improve handling of filenames containing shell metachars.
v374 2/7/02 Fix memory leak; fix bug in -x argument parsing.
v375 4/7/02 Fix searching for SGR sequences; fix SECURE build;
add SGR support to DJGPP version (thanks to Eli Zaretskii).
v376 6/10/02 Fix bug in overstriking mulitbyte UTF-8 characters
(thanks to Jungshik Shin).
Posted to Web page.
-----------------------------------------------------------------
v377 9/10/02 Fix bug in Windows version when file contains CR;
fix bug in search highlights with -R;
make initial buffer limit really be 64K not unlimited.
v378 9/30/02 Misc bug fixes and compiler warning cleanup.
Posted to Web page.
-----------------------------------------------------------------
v379 11/23/02 Add -L option; fix bug with ctrl-K in lesskey files;
improve UTF-8 overstriking and underscore overstriking;
fix minor man page problems; change to autoconf 2.54.
v380 11/24/02 Make LINENUM same as POSITION.
v381 11/28/02 Make -N use 7 columns for line number if possible.
-----------------------------------------------------------------
v382 2/3/04 Remove copyrighted code.
-----------------------------------------------------------------
v383 2/16/04 Add history file; add -K option; improve UTF-8 handling;
fix some signed char bugs (thanks to Christian Biere);
fix some upper/lower case bugs (thanks to Bjoern Jacke);
add erase2 char (thanks to David Lawrence);
add windows charset (thanks to Dimitar Zhekov).
v384 2/20/04 Improvements in UTF-8 handling.
v385 2/23/04 Fix UTF-8 output bug.
-----------------------------------------------------------------
v386 9/13/05 Improvements to UTF-8 shift & color (thanks to Charles Levert);
protect against invalid LESSOPEN and LESSCLOSE values.
v387 9/14/05 Update Charles Levert's UTF-8 patch.
v388 9/14/05 Change history behavior; change most sprintf calls to snprintf.
v389 9/14/05 Fix copy & paste with long lines; improve performance of
expand_linebuf; fix crash in init_mlist;
v390 9/15/05 Show search matches in status column even if -G is set.
-----------------------------------------------------------------
v391 9/17/05 Fix bugs.
v392 10/14/05 Fix line wrapping bug.
v393 10/19/05 Allow multiple attributes per char; fix bold+underline bug
(thanks again to Charles Levert).
v394 11/8/05 Fix prompt bug; fix compile problem in Windows build.
-----------------------------------------------------------------
v395 1/12/07 Update Unicode tables (thanks to Charles Levert);
don't chmod if LESSHISTFILE = /dev/null;
make -f work for directories; support DESTDIR in Makefile;
fix sigset_t detection in configure;
make "t" cmd traverse tags in correct order
v396 1/13/07 Add compatibility with POSIX more.
v397 3/21/07 Allow decimal point in number for % command;
Allow decimal point in number for -j option;
Allow n command to fetch last search pattern from history
(thanks to arno).
v398 3/22/07 Don't rewrite history file if not necessary;
fix bug when filenames contain "$".
v399 3/22/07 Don't move to bottom of screen at startup;
don't output extraneous newlines.
v400 3/23/07 Allow search to find pattern after null byte (PCRE and no-regex)
(thanks to Michael Constant).
-----------------------------------------------------------------
v401 3/24/07 Minor documentation fixes.
v402 3/30/07 Fix autoconf bug when memcpy etc are inline;
fix bug in terminating number following -j option.
v403 5/25/07 Fix Windows build.
v404 6/5/07 Fix display bug with F command and long lines.
v405 6/17/07 Fix display bug when using -w option.
v406 6/17/07 Fix secure build.
v407 8/16/07 Fix bugs; support CSI chars.
v408 10/1/07 Fix bug in -i with non-ASCII chars.
v409 10/12/07 Fix crash when viewing text with invalid UTF-8 sequences.
v411 11/6/07 Fix case-insensitive searching with non-ASCII text.
v412 11/6/07 Use symbolic SEEK constants.
v413 11/6/07 Fix search highlight bug with non-ASCII text.
v414 11/6/07 Fix display bug with no-wrap terminals.
v415 11/14/07 Add --follow-name option.
v416 11/22/07 Fix crash when searching text with invalid UTF-8 sequences.
v417 12/31/07 Don't support single-char CSI in UTF-8 mode;
fix bug with -R and invalid CSI sequences;
fix bug searching text with SGR sequences with -r;
emulate SGR sequences in WIN32 build.
v418 12/31/07 Clean up.
-----------------------------------------------------------------
v419 1/16/08 Make CSI char 0x9B work in UTF-8 mode (thanks to Colin Watson).
v420 2/24/08 Add & command; fix -F option; fix '' after G.
v421 2/24/08 Ignore filtered lines when searching.
v422 3/2/08 Output CR at startup.
v423 5/27/08 Clean up.
v424 6/16/08 Fix compile bug with pcre; don't filter help file.
v425 7/14/08 Fix non-ANSI code in list handling in ch.c.
v426 10/27/08 Fix ignaw terminal handling (thanks to Per Hedeland);
fix binary file detection in UTF-8 mode.
v427 3/16/09 A few Win32 fixes (thanks to Jason Hood).
v428 3/30/09 Add "|-" syntax to LESSOPEN.
v429 4/10/09 Fix search highlighting bug with underlined text.
-----------------------------------------------------------------
v430 4/22/09 Don't pass "-" to non-pipe LESSOPEN unless it starts with "-".
v431 4/29/09 Fix highlight bug when match is at end of line.
v432 6/27/09 Better fix for highlight bugs;
fix new problems with ignaw terminals.
v433 6/28/09 Cleanup search code.
v434 6/29/09 More cleanup.
v435 7/04/09 Fix bugs with non-regex filtering.
v436 7/05/09 Fix memory leak.
-----------------------------------------------------------------
v437 7/14/09 Fix bug in handling some long option names;
make percentage calculation more accurate.
v438 12/29/10 Fix bugs with -i/-I and & filtering;
exit with status 2 on ctrl-C with -K.
v439 12/31/10 Add -A option.
v440 1/5/11 Fix bug displaying prompt after = command.
v441 1/21/11 Fix semi-infinite loop if no newlines in file;
make new -A behavior the default.
-----------------------------------------------------------------
v442 3/2/11 Fix search bug.
Add ctrl-G line edit command.
v443 4/9/11 Fix Windows build.
v444 6/8/11 Fix ungetc bug; remove vestiges of obsolete -l option.
-----------------------------------------------------------------
v445 10/19/11 Fix hilite bug in backwards scroll with -J.
Fix hilite bug with backspaces.
Fix bugs handling SGR sequences in Win32 (thanks to Eric Lee).
Add support for GNU regex (thanks to Reuben Thomas).
v446 5/15/12 Up/down arrows in cmd editing search for matching cmd.
v447 5/21/12 Add ESC-F command, two-pipe LESSOPEN syntax.
v448 6/15/12 Print name of regex library in version message.
v449 6/23/12 Allow config option --with-regex=none.
v450 7/4/12 Fix EOF bug with ESC-F.
v451 7/20/12 Fix typo.
-----------------------------------------------------------------
v452 10/19/12 Fix --with-regex=none, fix "stty 0", fix Win32.
Don't quit if errors in cmd line options.
v453 10/27/12 Increase buffer sizes.
v454 11/5/12 Fix typo.
v455 11/5/12 Fix typo.
v456 11/8/12 Fix option string incompatibility.
v457 12/8/12 Use new option string syntax only after --use-backslash.
v458 4/4/13 Fix display bug in using up/down in cmd buffer.
-----------------------------------------------------------------
v459 5/6/13 Fix ++ bug.
v460 6/19/13 Automate construction of Unicode tables.
v461 6/21/13 Collapse multiple CRs before LF.
v462 11/26/13 Don't overwrite history file, just append to it.
v463 7/13/14 Misc. fixes.
v464 7/19/14 Fix bugs & improve performance in & filtering
(thanks to John Sullivan).
v465 8/9/14 More fixes from John Sullivan.
v466 8/23/14 Add colon to LESSANSIMIDCHARS.
v467 9/18/14 Misc. fixes.
v468 9/18/14 Fix typo
v469 10/2/14 Allow extra string in command to append to a multichar
cmd without executing it; fix bug using GNU regex.
v470 10/5/14 Fix some compiler warnings.
v471 12/14/14 Fix unget issues with prompt. Allow disabling history
when compiled value of LESSHISTFILE = "-".
v473 12/19/14 Fix prompt bug with stdin and -^P in lesskey extra string.
v474 1/30/15 Fix bug in backwards search with match on bottom line.
Make follow mode reopen file if file shrinks.
v475 3/2/15 Fix possible buffer overrun with invalid UTF-8;
fix bug when compiled with no regex; fix non-match search.
v476 5/3/15 Update man pages.
v477 5/19/15 Fix off-by-one in jump_forw_buffered;
don't add FAKE_* files to cmd history.
v478 5/21/15 Fix nonportable pointer usage in hilite tree.
v479 7/6/15 Allow %% escapes in LESSOPEN variable.
v480 7/24/15 Fix bug in no-regex searches; support MSVC v1900.
v481 8/20/15 Fix broken -g option.
-----------------------------------------------------------------
v482 2/25/16 Update Unicode database to "2015-06-16, 20:24:00 GMT [KW]".
v483 2/27/16 Regenerate hilite when change search caselessness.
(Thanks to Jason Hood)
Fix bug when terminal has no "cm". (Thanks to Noel Cragg)
v484 9/20/16 Update to Unicode 9.0.0 database.
v485 10/21/16 Fix "nothing to search" bug when top/bottom line is empty;
Display line numbers in bold. (thanks to Jason Hood);
Fix incorrect display when entering double-width chars in
search string.
v486 10/22/16 New commands ESC-{ and ESC-} to shift to start/end of
displayed lines; new option -Da in Windows version to
enable SGR mode (thanks to Jason Hood).
v487 10/23/16 configure --help formatting.
-----------------------------------------------------------------
v488 2/23/17 Fix memory leaks in search (thanks to John Brooks).
v489 3/30/17 Make -F not do init/deinit if file fits on one screen
(thanks to Jindrich Novy).
v490 4/5/17 Switch to ANSI prototypes in funcs.h; remove "register".
v491 4/7/17 Fix signed char bug.
v492 4/21/17 Handle SIGTERM.
v493 6/22/17 Fix bug initializing charset in MSDOS build.
v494 6/26/17 Update Unicode tables; make Cf chars composing not binary.
v495 7/3/17 Improve binary file detection (thanks to Bela Lubkin);
do -R filter when matching tags (thanks to Matthew Malcomson).
v496 7/5/17 Add LESSRSCROLL marker.
v497 7/5/17 Sync.
v498 7/7/17 Fix early truncation of text if last char is double-width.
v499 7/10/17 Misc fixes.
v500 7/11/17 Fix bug where certain env variables couldn't be set in lesskey.
v501 7/12/17 Make sure rscroll char is standout by default.
v502 7/13/17 Control rscroll char via command line option not env variable.
v503 7/13/17 Switch to git.
v504 7/13/17 Call opt_rscroll at startup; change mkhelp.c to mkhelp.pl.
v505 7/17/17 Add M and ESC-M commands;
fix buffer handling with stdin and LESSOPEN.
v506 7/17/17 On Windows, convert UTF-8 to multibyte if console is not UTF-8;
handle extended chars on input (thanks to Jason Hood).
v507 7/18/17 Fix some bugs handling filenames containing shell metachars.
v508 7/19/17 Fix bugs when using LESSOPEN to read stdin.
v509 7/19/17 Fix another stdin bug.
v510 7/20/17 Fix bug in determining when to reopen a file.
v511 7/25/17 Fix bugs in recent MSDOS changes (thanks to Jason Hood).
v512 7/26/17 Fix MSDOS build.
v513 7/26/17 Fix switch to normal attr at end of line with -R and rscroll.
v514 7/27/17 Fix bug in fcomplete when pattern does not match a file.
v515 7/28/17 Allow 'u' in -D option on Windows.
v516 7/29/17 Fix bug using LESSOPEN with filename containing metachars.
v517 7/30/17 Status column shows matches even if hiliting is disabled via -G.
v518 8/1/17 Use underline in sgr mode in MSDOS (thanks to Jason Hood).
v519 8/10/17 Fix rscroll bug when last char of line starts coloration.
v520 9/3/17 Fix compiler warning.
v521 10/20/17 Fix binary file warning in UTF-8 files with SGI sequences.
v522 10/20/17 Handle keypad ENTER key properly.
v523 10/23/17 Cleanup.
v524 10/24/17 Fix getcc bug.
v525 10/24/17 Change M command to mark last displayed line.
v526 10/25/17 Fix search hilite bug introduced in v517.
v527 10/30/17 Fix search hilite bug on last page with -a.
v528 11/3/17 Make second ESC-u clear status column.
v529 11/12/17 Display Unicode formatting chars in hex if -U is set.
v530 12/2/17 Minor doc change and add missing VOID_PARAM.
-----------------------------------------------------------------
v531 5/13/18 Fix bug with v on empty file; fix bug with v on file with
metachars in name; add --nohistdups option.
v532 7/27/18 Redraw screen on SIGWINCH even if screen size doesn't change.
v533 8/1/18 Shell escape filenames in history; use PCRE_UTF8 flag;
use wide-chars for Windows console title (thanks to Jason Hood).
v534 8/9/18 Support PCRE2.
v535 8/16/18 Don't count lines of initial screen if using -X with -F
(thanks to Linus Torvalds).
v536 8/31/18 Use descriptive error messages for PCRE2.
v537 8/31/18 Support mingw build system (thanks to Mike Soyka).
v538 9/3/18 Clean up some WIN32 code.
v539 9/13/18 Fix spurious input on Windows with CAPSLOCK.
v540 10/29/18 Add --mouse option.
v541 10/30/18 Add --MOUSE option.
v542 11/6/18 Add mouse support for WIN32; add --wheel-lines option.
(thanks to Jason Hood).
v543 11/12/18 Code cleanup.
v544 11/16/18 Don't init/deinit keyboard/mouse if quit due to -F.
v545 11/22/18 Fix Windows build, memory leaks.
v546 11/29/18 Add --save-marks option.
v547 11/30/18 Fix some bugs with saved marks.
v548 12/14/18 Ignore mouse input when line editing.
v549 2/10/19 Support X11 mouse extension 1006;
Win32 fixes (thanks to Jason Hood).
v550 2/16/19 Fix Win32 build; don't enable mouse unless --mouse is set.
v551 6/10/19 Doc changes.
-----------------------------------------------------------------
v552 7/8/19 Update Unicode tables.
v553 10/17/19 Support tinfow; handle zero-width Hangul chars.
v554 1/19/20 Remove erroneous free().
v555 3/15/20 Display error msg immediately when toggle -o without stdin.
v556 3/15/20 Update copyright.
v557 3/21/20 Fix memory corruption with libtermcap.
v558 4/17/20 Don't init terminal if -F and file fits on one screen (WIN32).
v559 4/19/20 Handle deinit correctly on WIN32.
v560 5/3/20 Fix regression when command results in no movement;
fix some less.nro issues (thanks to Bjarni I. Gislason).
v561 5/11/20 Fix erroneous EOF calculation when F command is interrupted.
v562 5/19/20 Update Unicode tables; minor doc formatting.
v563 6/13/20 Fix crash due to realpath() incompatibility.
v564 8/25/20 Handle realpath consistently; update docs.
v565 11/3/20 Add ESC-U command, optimize calls to realpath().
v566 11/25/20 Fix crash when reopening a file while using LESSOPEN;
support OSC 8 hyperlinks.
v567 11/25/20 Fix typo.
v568 11/29/20 Fix some hyperlink bugs; add ^W search modifier
(thanks to Arminius); allow Makefile.aut to use Python
instead of Perl (thanks to Charlie Lin).
v569 12/1/20 Allow multiple & filters (thanks to Mattias Johansson),
allow ^X to exit F command.
v570 12/12/20 Better handling of multiple + or -p options;
fix bugs in horizontal scrolling.
v571 12/30/20 Add --line-num-width and --status-col-width options.
v572 1/4/21 Save lastmark in history file; don't toggle mouse reporting;
implement termcap delays.
v573 1/9/21 Limit eof bell to 1 per second.
v574 1/13/21 Add incremental search.
v575 1/17/21 Fix build without HILITE_SEARCH;
fix bug with ^K in lesskey extra string.
v576 2/4/21 Make sure search result is visible; add --use-color and --color.
v577 2/9/21 Use ttyname to get name of tty device.
v578 2/9/21 Doc
v579 2/14/21 Fix double-width char bugs and non-match search crash.
v580 3/2/21 Some color fixes; fix compiler warnings; some lesstest support.
v581 4/6/21 Ignore SIGTSTP in secure mode; don't print "skipping" when filtering.
v582 4/21/21 Less now reads lesskey source file rather than binary;
fix bug in finding tags with backslashes.
v583 4/21/21 Use XDG_CONFIG_HOME and XDG_DATA_HOME to find files.
v584 4/30/21 Add --file-size option.
v585 5/2/21 Allow color desc W per man page.
v586 5/7/21 Doc changes.
v587 5/27/21 Fix --with-secure; fix --file-size message on Windows;
fix colored search hilite in colored text; don't exit
if -F and screen is resized; fix memcpy usage.
v588 5/27/21 Fix release.
v589 5/29/21 Copyright & build changes.
v590 6/3/21 Fix non-autoconf Makefiles.
v591 8/8/21 Use \kB for backspace key in lesskey; add more \k codes;
handle multibyte chars in prompt.
v592 8/24/21 Add --status-line option; limit use of /proc kludge; add --header.
v593 8/30/21 Add header columns, --no-number-headers.
v594 10/1/21 Let regex library handle caseless; add --redraw-on-quit option;
add #version to lesskey.
v595 10/12/21 Add H color type; add += to lesskey var section;
add --search-options.
v596 11/8/21 Look for lesskey in $HOME/.config.
v597 11/16/21 Fix bugs in --header.
v598 12/6/21 Look for lesshst in $XDG_STATE_HOME and $HOME/.local/state.
v599 12/28/21 Defer moving to lower left in some cases;
suppress TAB expansion in some cases.
v600 1/7/22 Use /dev/tty if cannot open ttyname().
v601 1/31/22 Add --exit-follow-on-close option.
v602 3/1/22 Doc changes.
v603 3/14/22 Fix --header.
v604 5/14/22 Fix termlib detection; fix non-ASCII input on Windows.
v605 6/14/22 Update version number.
v606 7/17/22 Fix bug with multibyte chars and --incsearch;
escape filenames in LESSCLOSE; fix bin_file overrun.
v607 7/19/22 Update Unicode tables.
v608 7/22/22 Fix highlighting on colored text boundaries.
v609 11/10/22 Add LESSUTFCHARDEF; fix overstrike color bug;
fix procfs bug; fix signal race.
v610 11/14/22 Update Unicode tables; fix again-search after filter;
improve ^X to interrupt F command.
v611 11/16/22 Fix EOF bug related to ^X change.
v612 11/18/22 Fix more bugs related to ^X change.
v613 11/28/22 Even more ^X issues.
v614 11/28/22 Add ^X to wait message.
v615 11/30/22 Add --no-vbell option.
v616 12/9/22 Don't open tty as input file without -f.
v617 12/10/22 Support poll on newer versions of MacOS.
v618 12/29/22 Add --no-search-headers option; use C89 function definitions.
v619 12/30/22 Fix bug using 'n' before '/'.
v620 1/12/23 Add --modelines option; add --intr option;
add subpattern coloring.
v621 1/15/23 Add --wordwrap option; add LESS_LINES & LESS_COLUMNS.
v622 1/27/23 Add --show-preproc-errors option.
v623 2/2/23 Add # command; add ^S search modifier.
v624 2/11/23 Add --proc-backspace, --proc-tab and --proc-return options.
v625 2/16/23 Minor fixes.
v626 2/19/23 Fix rare crash in add_attr_normal.
v627 2/19/23 Doc.
v628 2/20/23 Don't require newline after +&...
v629 2/26/23 Delay "waiting for data" message for 500 ms.
v630 3/18/23 Add LESS_DATA_DELAY.
v631 3/26/23 Fix input of dead keys on Windows.
v632 4/6/23 Make lesstest work on MacOS; minor fixes.
v633 5/3/23 Fix build on systems with ncurses/termcap.h or ncursesw/termcap.h.
v634 5/29/23 Allow program piping into less to access tty;
fix search modifier ^E after ^W.
v635 6/2/23 Fix crash with ! search modifier.
v636 6/18/23 Fix -D in MS-DOS build; fix mouse wheel in MS-DOS build.
v637 6/28/23 Fix early EOF when SIGWINCH is received.
v638 6/29/23 Fix compile error with ECHONL.
v639 6/29/23 Fix SIGWINCH while reading tty.
v640 7/10/23 Add lesstest to release.
v641 7/10/23 Fix release.
v642 7/10/23 Fix release.
v643 7/20/23 Fix crash on Windows with -o.
*/
char version[] = "643";

123
third_party/less/wide.inc vendored Normal file
View file

@ -0,0 +1,123 @@
/* Generated by "./mkutable -f1 W F -- unicode/EastAsianWidth.txt" on Mon Nov 14 18:19:24 PST 2022 */
{ 0x1100, 0x115f }, /* W */
{ 0x231a, 0x231b }, /* W */
{ 0x2329, 0x232a }, /* W */
{ 0x23e9, 0x23ec }, /* W */
{ 0x23f0, 0x23f0 }, /* W */
{ 0x23f3, 0x23f3 }, /* W */
{ 0x25fd, 0x25fe }, /* W */
{ 0x2614, 0x2615 }, /* W */
{ 0x2648, 0x2653 }, /* W */
{ 0x267f, 0x267f }, /* W */
{ 0x2693, 0x2693 }, /* W */
{ 0x26a1, 0x26a1 }, /* W */
{ 0x26aa, 0x26ab }, /* W */
{ 0x26bd, 0x26be }, /* W */
{ 0x26c4, 0x26c5 }, /* W */
{ 0x26ce, 0x26ce }, /* W */
{ 0x26d4, 0x26d4 }, /* W */
{ 0x26ea, 0x26ea }, /* W */
{ 0x26f2, 0x26f3 }, /* W */
{ 0x26f5, 0x26f5 }, /* W */
{ 0x26fa, 0x26fa }, /* W */
{ 0x26fd, 0x26fd }, /* W */
{ 0x2705, 0x2705 }, /* W */
{ 0x270a, 0x270b }, /* W */
{ 0x2728, 0x2728 }, /* W */
{ 0x274c, 0x274c }, /* W */
{ 0x274e, 0x274e }, /* W */
{ 0x2753, 0x2755 }, /* W */
{ 0x2757, 0x2757 }, /* W */
{ 0x2795, 0x2797 }, /* W */
{ 0x27b0, 0x27b0 }, /* W */
{ 0x27bf, 0x27bf }, /* W */
{ 0x2b1b, 0x2b1c }, /* W */
{ 0x2b50, 0x2b50 }, /* W */
{ 0x2b55, 0x2b55 }, /* W */
{ 0x2e80, 0x2e99 }, /* W */
{ 0x2e9b, 0x2ef3 }, /* W */
{ 0x2f00, 0x2fd5 }, /* W */
{ 0x2ff0, 0x2ffb }, /* W */
{ 0x3000, 0x3000 }, /* F */
{ 0x3001, 0x303e }, /* W */
{ 0x3041, 0x3096 }, /* W */
{ 0x3099, 0x30ff }, /* W */
{ 0x3105, 0x312f }, /* W */
{ 0x3131, 0x318e }, /* W */
{ 0x3190, 0x31e3 }, /* W */
{ 0x31f0, 0x321e }, /* W */
{ 0x3220, 0x3247 }, /* W */
{ 0x3250, 0x4dbf }, /* W */
{ 0x4e00, 0xa48c }, /* W */
{ 0xa490, 0xa4c6 }, /* W */
{ 0xa960, 0xa97c }, /* W */
{ 0xac00, 0xd7a3 }, /* W */
{ 0xf900, 0xfaff }, /* W */
{ 0xfe10, 0xfe19 }, /* W */
{ 0xfe30, 0xfe52 }, /* W */
{ 0xfe54, 0xfe66 }, /* W */
{ 0xfe68, 0xfe6b }, /* W */
{ 0xff01, 0xff60 }, /* F */
{ 0xffe0, 0xffe6 }, /* F */
{ 0x16fe0, 0x16fe4 }, /* W */
{ 0x16ff0, 0x16ff1 }, /* W */
{ 0x17000, 0x187f7 }, /* W */
{ 0x18800, 0x18cd5 }, /* W */
{ 0x18d00, 0x18d08 }, /* W */
{ 0x1aff0, 0x1aff3 }, /* W */
{ 0x1aff5, 0x1affb }, /* W */
{ 0x1affd, 0x1affe }, /* W */
{ 0x1b000, 0x1b122 }, /* W */
{ 0x1b132, 0x1b132 }, /* W */
{ 0x1b150, 0x1b152 }, /* W */
{ 0x1b155, 0x1b155 }, /* W */
{ 0x1b164, 0x1b167 }, /* W */
{ 0x1b170, 0x1b2fb }, /* W */
{ 0x1f004, 0x1f004 }, /* W */
{ 0x1f0cf, 0x1f0cf }, /* W */
{ 0x1f18e, 0x1f18e }, /* W */
{ 0x1f191, 0x1f19a }, /* W */
{ 0x1f200, 0x1f202 }, /* W */
{ 0x1f210, 0x1f23b }, /* W */
{ 0x1f240, 0x1f248 }, /* W */
{ 0x1f250, 0x1f251 }, /* W */
{ 0x1f260, 0x1f265 }, /* W */
{ 0x1f300, 0x1f320 }, /* W */
{ 0x1f32d, 0x1f335 }, /* W */
{ 0x1f337, 0x1f37c }, /* W */
{ 0x1f37e, 0x1f393 }, /* W */
{ 0x1f3a0, 0x1f3ca }, /* W */
{ 0x1f3cf, 0x1f3d3 }, /* W */
{ 0x1f3e0, 0x1f3f0 }, /* W */
{ 0x1f3f4, 0x1f3f4 }, /* W */
{ 0x1f3f8, 0x1f43e }, /* W */
{ 0x1f440, 0x1f440 }, /* W */
{ 0x1f442, 0x1f4fc }, /* W */
{ 0x1f4ff, 0x1f53d }, /* W */
{ 0x1f54b, 0x1f54e }, /* W */
{ 0x1f550, 0x1f567 }, /* W */
{ 0x1f57a, 0x1f57a }, /* W */
{ 0x1f595, 0x1f596 }, /* W */
{ 0x1f5a4, 0x1f5a4 }, /* W */
{ 0x1f5fb, 0x1f64f }, /* W */
{ 0x1f680, 0x1f6c5 }, /* W */
{ 0x1f6cc, 0x1f6cc }, /* W */
{ 0x1f6d0, 0x1f6d2 }, /* W */
{ 0x1f6d5, 0x1f6d7 }, /* W */
{ 0x1f6dc, 0x1f6df }, /* W */
{ 0x1f6eb, 0x1f6ec }, /* W */
{ 0x1f6f4, 0x1f6fc }, /* W */
{ 0x1f7e0, 0x1f7eb }, /* W */
{ 0x1f7f0, 0x1f7f0 }, /* W */
{ 0x1f90c, 0x1f93a }, /* W */
{ 0x1f93c, 0x1f945 }, /* W */
{ 0x1f947, 0x1f9ff }, /* W */
{ 0x1fa70, 0x1fa7c }, /* W */
{ 0x1fa80, 0x1fa88 }, /* W */
{ 0x1fa90, 0x1fabd }, /* W */
{ 0x1fabf, 0x1fac5 }, /* W */
{ 0x1face, 0x1fadb }, /* W */
{ 0x1fae0, 0x1fae8 }, /* W */
{ 0x1faf0, 0x1faf8 }, /* W */
{ 0x20000, 0x2fffd }, /* W */
{ 0x30000, 0x3fffd }, /* W */

163
third_party/less/xbuf.c vendored Normal file
View file

@ -0,0 +1,163 @@
#include "less.h"
#include "xbuf.h"
/*
* Initialize an expandable text buffer.
*/
public void xbuf_init(struct xbuffer *xbuf)
{
xbuf->data = NULL;
xbuf->size = xbuf->end = 0;
}
public void xbuf_deinit(struct xbuffer *xbuf)
{
if (xbuf->data != NULL)
free(xbuf->data);
xbuf_init(xbuf);
}
public void xbuf_reset(struct xbuffer *xbuf)
{
xbuf->end = 0;
}
/*
* Add a byte to an expandable text buffer.
*/
public void xbuf_add_byte(struct xbuffer *xbuf, unsigned char b)
{
if (xbuf->end >= xbuf->size)
{
unsigned char *data;
if (ckd_add(&xbuf->size, xbuf->size, xbuf->size ? xbuf->size : 16))
out_of_memory();
data = (unsigned char *) ecalloc(xbuf->size, sizeof(unsigned char));
if (xbuf->data != NULL)
{
memcpy(data, xbuf->data, xbuf->end);
free(xbuf->data);
}
xbuf->data = data;
}
xbuf->data[xbuf->end++] = (unsigned char) b;
}
public void xbuf_add_data(struct xbuffer *xbuf, unsigned char *data, int len)
{
int i;
for (i = 0; i < len; i++)
xbuf_add_byte(xbuf, data[i]);
}
public int xbuf_pop(struct xbuffer *buf)
{
if (buf->end == 0)
return -1;
return (int) buf->data[--(buf->end)];
}
public void xbuf_set(struct xbuffer *dst, struct xbuffer *src)
{
xbuf_reset(dst);
xbuf_add_data(dst, src->data, src->end);
}
public char * xbuf_char_data(struct xbuffer *xbuf)
{
return (char *)(xbuf->data);
}
/*
* Helper functions for the ckd_add and ckd_mul macro substitutes.
* These helper functions do not set *R on overflow, and assume that
* arguments are nonnegative, that INTMAX_MAX <= UINTMAX_MAX, and that
* sizeof is a reliable way to distinguish integer representations.
* Despite these limitations they are good enough for 'less' on all
* known practical platforms. For more-complicated substitutes
* without most of these limitations, see Gnulib's stdckdint module.
*/
#if !HAVE_STDCKDINT_H
/*
* If the integer *R can represent VAL, store the value and return FALSE.
* Otherwise, possibly set *R to an indeterminate value and return TRUE.
* R has size RSIZE, and is signed if and only if RSIGNED is nonzero.
*/
static int help_fixup(void *r, uintmax val, int rsize, int rsigned)
{
if (rsigned)
{
if (rsize == sizeof (int))
{
int *pr = r;
if (INT_MAX < val)
return TRUE;
*pr = (int) val;
#ifdef LLONG_MAX
} else if (rsize == sizeof (long long))
{
long long *pr = r;
if (LLONG_MAX < val)
return TRUE;
*pr = val;
#endif
#ifdef INTMAX_MAX
} else if (rsize == sizeof (intmax_t)) {
intmax_t *pr = r;
if (INTMAX_MAX < val)
return TRUE;
*pr = val;
#endif
} else /* rsize == sizeof (long) */
{
long *pr = r;
if (LONG_MAX < val)
return TRUE;
*pr = (long) val;
}
} else {
if (rsize == sizeof (unsigned)) {
unsigned *pr = r;
if (UINT_MAX < val)
return TRUE;
*pr = (unsigned) val;
} else if (rsize == sizeof (unsigned long)) {
unsigned long *pr = r;
if (ULONG_MAX < val)
return TRUE;
*pr = (unsigned long) val;
#ifdef ULLONG_MAX
} else if (rsize == sizeof (unsigned long long)) {
long long *pr = r;
if (ULLONG_MAX < val)
return TRUE;
*pr = val;
#endif
} else /* rsize == sizeof (uintmax) */
{
uintmax *pr = r;
*pr = val;
}
}
return FALSE;
}
/*
* If *R can represent the mathematical sum of A and B, store the sum
* and return FALSE. Otherwise, possibly set *R to an indeterminate
* value and return TRUE. R has size RSIZE, and is signed if and only
* if RSIGNED is nonzero.
*/
public int help_ckd_add(void *r, uintmax a, uintmax b, int rsize, int rsigned)
{
uintmax sum = a + b;
return sum < a || help_fixup(r, sum, rsize, rsigned);
}
/* Likewise, but for the product of A and B. */
public int help_ckd_mul(void *r, uintmax a, uintmax b, int rsize, int rsigned)
{
uintmax product = a * b;
return ((b != 0 && a != product / b)
|| help_fixup(r, product, rsize, rsigned));
}
#endif

19
third_party/less/xbuf.h vendored Normal file
View file

@ -0,0 +1,19 @@
#ifndef XBUF_H_
#define XBUF_H_
struct xbuffer
{
unsigned char *data;
int end;
int size;
};
void xbuf_init(struct xbuffer *xbuf);
void xbuf_deinit(struct xbuffer *xbuf);
void xbuf_reset(struct xbuffer *xbuf);
void xbuf_add_byte(struct xbuffer *xbuf, unsigned char b);
void xbuf_add_data(struct xbuffer *xbuf, unsigned char *data, int len);
int xbuf_pop(struct xbuffer *xbuf);
char *xbuf_char_data(struct xbuffer *xbuf);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff