Thorough revamp of how input commands are processed. This allows customization
of user keys (documentation pending). The only key whose semantics have changed is the capital 'N' key, which now performs a repeat-search in the opposite direction (just like in vi). This commit is a little bulkier than what I had originally planned. I'm not completely happy with the direction it went, but it's definately an improvement, and the alternative is to continue becoming irrelevant compared to GNU less. (Does anyone even _use_ /usr/bin/more these days?)
This commit is contained in:
parent
fa9b8447b7
commit
20d6e5fe6e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=50866
@ -1,16 +1,34 @@
|
||||
# From: @(#)Makefile 8.1 (Berkeley) 6/6/93
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
PROG= more
|
||||
CFLAGS+=-I${.CURDIR} -DTERMIOS
|
||||
SRCS= ch.c command.c decode.c help.c input.c line.c linenum.c main.c \
|
||||
option.c os.c output.c position.c prim.c screen.c signal.c tags.c \
|
||||
ttyin.c
|
||||
CFLAGS+=-I${.CURDIR} -I${.OBJDIR} -DTERMIOS
|
||||
SRCS= ch.c command.c defrc.h help.c input.c line.c linenum.c macro.c main.c \
|
||||
ncommand.c option.c os.c output.c position.c prim.c screen.c signal.c \
|
||||
tags.c ttyin.c
|
||||
DPADD= ${LIBTERMCAP}
|
||||
LDADD= -ltermcap
|
||||
|
||||
CLEANFILES+= defrc.h
|
||||
|
||||
EXAMPDIR= /usr/share/examples/more
|
||||
EXAMPLES= default.morerc less.morerc most.morerc
|
||||
|
||||
defrc.h: default.morerc
|
||||
@${ECHO} '/* ${.TARGET:T} auto-generated from ${.ALLSRC:T} */' \
|
||||
> ${.TARGET}
|
||||
@${ECHO} '#define DEFRC "\' >> ${.TARGET}
|
||||
sed -e 's/\\/\\\\/g' -e 's/\"/\\\"/g' -e 's/$$/\\n\\/' \
|
||||
< ${.ALLSRC} >> ${.TARGET}
|
||||
@${ECHO} \" >> ${.TARGET}
|
||||
|
||||
beforeinstall:
|
||||
${INSTALL} -c -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/more.help \
|
||||
${DESTDIR}/usr/share/misc
|
||||
${INSTALL} ${COPY} -o ${SHAREOWN} -g ${SHAREGRP} -m ${SHAREMODE} \
|
||||
${.CURDIR}/more.help ${DESTDIR}/usr/share/misc
|
||||
.for xzamp in ${EXAMPLES}
|
||||
${INSTALL} ${COPY} -o ${SHAREOWN} -g ${SHAREGRP} -m ${SHAREMODE} \
|
||||
${.CURDIR}/${xzamp} ${DESTDIR}${EXAMPDIR}/${xzamp}
|
||||
.endfor
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,223 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 1988 Mark Nudleman
|
||||
* Copyright (c) 1988, 1993
|
||||
* The Regents of the University of California. All rights reserved.
|
||||
*
|
||||
* 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, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the University of
|
||||
* California, Berkeley and its contributors.
|
||||
* 4. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static char sccsid[] = "@(#)decode.c 8.1 (Berkeley) 6/6/93";
|
||||
#endif /* not lint */
|
||||
|
||||
#ifndef lint
|
||||
static const char rcsid[] =
|
||||
"$FreeBSD$";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Routines to decode user commands.
|
||||
*
|
||||
* This is all table driven.
|
||||
* A command table is a sequence of command descriptors.
|
||||
* Each command descriptor is a sequence of bytes with the following format:
|
||||
* <c1><c2>...<cN><0><action>
|
||||
* The characters c1,c2,...,cN are the command string; that is,
|
||||
* the characters which the user must type.
|
||||
* It is terminated by a null <0> byte.
|
||||
* The byte after the null byte is the action code associated
|
||||
* with the command string.
|
||||
*
|
||||
* The default commands are described by cmdtable.
|
||||
*/
|
||||
|
||||
#include <sys/file.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "less.h"
|
||||
|
||||
/*
|
||||
* Command table is ordered roughly according to expected
|
||||
* frequency of use, so the common commands are near the beginning.
|
||||
*/
|
||||
#define CONTROL(c) ((c)&037)
|
||||
|
||||
/*
|
||||
* Ideally the home and end keys would reset the horiz_scroll, too,
|
||||
* but this whole thing needs to be made dynamic along with some type
|
||||
* of macro commands.
|
||||
*/
|
||||
static char cmdtable[] = {
|
||||
'\e','[','B',0, A_F_LINE,
|
||||
'\e','[','A',0, A_B_LINE,
|
||||
'\e','[','C',0, A_R_COL,
|
||||
'\e','[','D',0, A_L_COL,
|
||||
'\r',0, A_F_LINE,
|
||||
'\n',0, A_F_LINE,
|
||||
'j',0, A_F_LINE,
|
||||
'k',0, A_B_LINE,
|
||||
'd',0, A_F_SCROLL,
|
||||
CONTROL('D'),0, A_F_SCROLL,
|
||||
'u',0, A_B_SCROLL,
|
||||
CONTROL('U'),0, A_B_SCROLL,
|
||||
' ',0, A_F_SCREEN,
|
||||
'f',0, A_F_SCREEN,
|
||||
CONTROL('F'),0, A_F_SCREEN,
|
||||
'\e','[','G',0, A_F_SCREEN,
|
||||
'b',0, A_B_SCREEN,
|
||||
CONTROL('B'),0, A_B_SCREEN,
|
||||
'\e','[','I',0, A_B_SCREEN,
|
||||
'R',0, A_FREPAINT,
|
||||
'r',0, A_REPAINT,
|
||||
CONTROL('L'),0, A_REPAINT,
|
||||
'g',0, A_GOLINE,
|
||||
'\e','[','H',0, A_HOME,
|
||||
'p',0, A_PERCENT,
|
||||
'%',0, A_PERCENT,
|
||||
'G',0, A_GOEND,
|
||||
'\e','[','F',0, A_GOEND,
|
||||
'0',0, A_DIGIT,
|
||||
'1',0, A_DIGIT,
|
||||
'2',0, A_DIGIT,
|
||||
'3',0, A_DIGIT,
|
||||
'4',0, A_DIGIT,
|
||||
'5',0, A_DIGIT,
|
||||
'6',0, A_DIGIT,
|
||||
'7',0, A_DIGIT,
|
||||
'8',0, A_DIGIT,
|
||||
'9',0, A_DIGIT,
|
||||
|
||||
'=',0, A_STAT,
|
||||
CONTROL('G'),0, A_STAT,
|
||||
'/',0, A_F_SEARCH,
|
||||
'?',0, A_B_SEARCH,
|
||||
'n',0, A_AGAIN_SEARCH,
|
||||
'm',0, A_SETMARK,
|
||||
'\'',0, A_GOMARK,
|
||||
'E',0, A_EXAMINE,
|
||||
'N',0, A_NEXT_FILE,
|
||||
':','n',0, A_NEXT_FILE,
|
||||
'P',0, A_PREV_FILE,
|
||||
':','p',0, A_PREV_FILE,
|
||||
'v',0, A_VISUAL,
|
||||
|
||||
'h',0, A_HELP,
|
||||
'q',0, A_QUIT,
|
||||
':','q',0, A_QUIT,
|
||||
':','t',0, A_TAGFILE,
|
||||
'T',0, A_PREVTAG,
|
||||
't',0, A_NEXTTAG,
|
||||
':', 'a', 0, A_FILE_LIST,
|
||||
'Z','Z',0, A_QUIT,
|
||||
};
|
||||
|
||||
char *cmdendtable = cmdtable + sizeof(cmdtable);
|
||||
|
||||
#define MAX_CMDLEN 16
|
||||
|
||||
static char kbuf[MAX_CMDLEN+1];
|
||||
static char *kp = kbuf;
|
||||
|
||||
/*
|
||||
* Indicate that we're not in a prefix command
|
||||
* by resetting the command buffer pointer.
|
||||
*/
|
||||
noprefix()
|
||||
{
|
||||
kp = kbuf;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decode a command character and return the associated action.
|
||||
*/
|
||||
cmd_decode(c)
|
||||
int c;
|
||||
{
|
||||
register int action = A_INVALID;
|
||||
|
||||
/*
|
||||
* Append the new command character to the command string in kbuf.
|
||||
*/
|
||||
*kp++ = c;
|
||||
*kp = '\0';
|
||||
|
||||
action = cmd_search(cmdtable, cmdendtable);
|
||||
|
||||
/* This is not a prefix character. */
|
||||
if (action != A_PREFIX)
|
||||
noprefix();
|
||||
return(action);
|
||||
}
|
||||
|
||||
/*
|
||||
* Search a command table for the current command string (in kbuf).
|
||||
*/
|
||||
cmd_search(table, endtable)
|
||||
char *table;
|
||||
char *endtable;
|
||||
{
|
||||
register char *p, *q;
|
||||
|
||||
for (p = table, q = kbuf; p < endtable; p++, q++) {
|
||||
if (*p == *q) {
|
||||
/*
|
||||
* Current characters match.
|
||||
* If we're at the end of the string, we've found it.
|
||||
* Return the action code, which is the character
|
||||
* after the null at the end of the string
|
||||
* in the command table.
|
||||
*/
|
||||
if (*p == '\0')
|
||||
return(p[1]);
|
||||
}
|
||||
else if (*q == '\0') {
|
||||
/*
|
||||
* Hit the end of the user's command,
|
||||
* but not the end of the string in the command table.
|
||||
* The user's command is incomplete.
|
||||
*/
|
||||
return(A_PREFIX);
|
||||
} else {
|
||||
/*
|
||||
* Not a match.
|
||||
* Skip ahead to the next command in the
|
||||
* command table, and reset the pointer
|
||||
* to the user's command.
|
||||
*/
|
||||
while (*p++ != '\0');
|
||||
q = kbuf-1;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* No match found in the entire command table.
|
||||
*/
|
||||
return(A_INVALID);
|
||||
}
|
134
usr.bin/more/default.morerc
Normal file
134
usr.bin/more/default.morerc
Normal file
@ -0,0 +1,134 @@
|
||||
#
|
||||
# This is the default initialization file for more(1). To avoid any need to
|
||||
# change the manpage or helpfile, almost all commands maintain their historical
|
||||
# keymappings. Some additional twoggles may be added that will be left for
|
||||
# the intrepid user to discover.
|
||||
#
|
||||
# This file is compiled directly into more; changing this file will not change
|
||||
# the actual defaults (unless it is changed in the source directory and more
|
||||
# is recompiled). The correct way to change the global defaults is by
|
||||
# adding a /etc/dot.morerc global initialization file.
|
||||
#
|
||||
# If you use an ~/.morerc that is dependent on specific features of this
|
||||
# default morerc, you should copy this default morerc to ~/.defmorerc so that
|
||||
# possible future changes in this file do not cause problems for you. The
|
||||
# ~/.defmorerc file will cause the compiled-in default morerc to be ignored.
|
||||
#
|
||||
# The default initialization file is compiled into more(1) so that more(1)
|
||||
# will work and be usable even if the filesystem (and the location
|
||||
# /usr/share/misc/default.morerc, where this would be stored if it was not
|
||||
# compiled into more(1)) is missing or away without leave (chroot directory,
|
||||
# fs crash, badly written rescue floppy, or any other reason).
|
||||
#
|
||||
# BUGS: a) There is no documentation.
|
||||
# b) There is no "map" command.
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
# required -- initialize more(1)
|
||||
deftog
|
||||
|
||||
#
|
||||
# basic internal initialization
|
||||
#
|
||||
set lsthscr 1
|
||||
# Add "set hkey_scroll true" to ~/.morerc to enable all the hjkl keys (but
|
||||
# disabling h)elp).
|
||||
set hkey_scroll false
|
||||
set scr_scroll 0
|
||||
# We have no way of resetting this on SIGWINCH as the old more A_H_SCROLL did
|
||||
# It's probably just as well... (since resetting would lose the old value!)
|
||||
# (Actually, we could emulate it from here if we really wanted to).
|
||||
set half_scroll (${_sc_height} / 2)
|
||||
# magic number indicating the value is not initialized
|
||||
set savedhscroll 87382
|
||||
|
||||
macro 1 j 'forw_scroll ${number}'
|
||||
macro 1 k 'back_scroll ${number}'
|
||||
macro 1 \e[B 'forw_scroll ${number}'
|
||||
macro 1 \e[A 'back_scroll ${number}'
|
||||
macro 1 \n 'forw_scroll ${number}'
|
||||
macro 1 \e[G 'forw (${_sc_height} * ${number})'
|
||||
macro 1 \e[I 'back (${_sc_height} * ${number})'
|
||||
set com_getscr 'condition (${number} != 0); \
|
||||
set scr_scroll ${number}; \
|
||||
condition (${number} == 0); \
|
||||
set scr_scroll ${_sc_height}; \
|
||||
condition true;'
|
||||
macro 0 " " 'eval ${com_getscr}; forw ${scr_scroll};'
|
||||
macro 0 f 'eval ${com_getscr}; forw ${scr_scroll};'
|
||||
macro 0 "" 'eval ${com_getscr}; forw ${scr_scroll};'
|
||||
macro 0 b 'eval ${com_getscr}; back ${scr_scroll};'
|
||||
macro 0 "" 'eval ${com_getscr}; back ${scr_scroll};'
|
||||
set com_sethalfscroll 'condition (${number} != 0); \
|
||||
set half_scroll ${number}; \
|
||||
condition true;'
|
||||
macro 0 d 'eval ${com_sethalfscroll}; forw_scroll ${half_scroll}'
|
||||
macro 0 "" 'eval ${com_sethalfscroll}; forw_scroll ${half_scroll}'
|
||||
macro 0 u 'eval ${com_sethalfscroll}; back_scroll ${half_scroll}'
|
||||
macro 0 "" 'eval ${com_sethalfscroll}; back_scroll ${half_scroll}'
|
||||
set com_rscroll 'condition (${number} != 0); \
|
||||
set lsthscr ${number}; \
|
||||
condition true; \
|
||||
rscroll ${lsthscr};'
|
||||
set com_lscroll 'condition (${number} != 0); \
|
||||
set lsthscr ${number}; \
|
||||
condition true; \
|
||||
lscroll ${lsthscr};'
|
||||
# this little trick lets the user simply set hkey_scroll=true in their own
|
||||
# ~/.morerc file to enable the 'l' and 'h' keys the way Bill meant them
|
||||
macro 0 h 'condition ${hkey_scroll}; eval ${com_lscroll}; \
|
||||
condition_! ${hkey_scroll}; help; \
|
||||
condition true;'
|
||||
macro 0 l 'condition ${hkey_scroll}; eval ${com_rscroll}; \
|
||||
condition_! ${hkey_scroll}; error "key not enabled"; \
|
||||
condition true;'
|
||||
macro 0 :help 'help'
|
||||
macro 0 \e[C 'eval ${com_rscroll}'
|
||||
macro 0 \e[D 'eval ${com_lscroll}'
|
||||
macro 0 \e[H 'condition (${_wraplines_n} && (${savedhscroll} != 87382)); \
|
||||
rscroll 1; \
|
||||
rscroll ${savedhscroll}; \
|
||||
condition_toggle; \
|
||||
set savedhscroll ${_curhscroll}; \
|
||||
lscroll ${_curhscroll}; \
|
||||
lscroll 1; \
|
||||
condition true;'
|
||||
macro 1 n 'research ${_ls_direction_n} ${number}'
|
||||
macro 1 N 'research (${_ls_direction_n} + 1) ${number}'
|
||||
macro 1 / 'magicasksearch forw ${number}'
|
||||
macro 1 ? 'magicasksearch back ${number}'
|
||||
macro 0 G 'condition (${number} == 0); goend; \
|
||||
condition (${number} != 0); goline ${number}; \
|
||||
condition true;'
|
||||
macro 1 g 'goline ${number}'
|
||||
macro 0 p 'gopercent ${number}'
|
||||
macro 0 % 'gopercent ${number}'
|
||||
macro 0 \e[F 'goend'
|
||||
# Quote since it's technically an isspace() character
|
||||
macro 0 "" 'repaint'
|
||||
macro 0 r 'repaint'
|
||||
macro 0 R 'flush'
|
||||
macro 0 v 'edit'
|
||||
macro 0 :e 'askfile'
|
||||
macro 0 E 'askfile'
|
||||
# The old keymaping for 'N'
|
||||
#macro 1 N 'file next ${number}'
|
||||
macro 1 :n 'file next ${number}'
|
||||
macro 1 P 'file prev ${number}'
|
||||
macro 1 :p 'file prev ${number}'
|
||||
macro 0 :a 'file_list'
|
||||
macro 0 m 'setmark ?'
|
||||
macro 0 \' 'gomark ?'
|
||||
macro 0 :t 'asktag'
|
||||
macro 1 t 'nexttag ${number}'
|
||||
macro 1 T 'prevtag ${number}'
|
||||
macro 0 "" 'stat (${_stat_n} + 1)'
|
||||
macro 0 = 'stat (${_stat_n} + 1)'
|
||||
macro 0 q 'quit'
|
||||
macro 0 :q 'quit'
|
||||
macro 0 ZZ 'quit'
|
||||
# This command intentionally disabled by default. The command parser is
|
||||
# too baroque to expose hapless users to.
|
||||
#macro 0 :: 'usercom'
|
@ -55,7 +55,9 @@ static const char rcsid[] =
|
||||
|
||||
#include "less.h"
|
||||
|
||||
int horiz_off = NO_HORIZ_OFF; /* # characters scrolled off left of screen */
|
||||
/* NOTE!: if (wraplines) assert (horiz_off == 0) */
|
||||
int horiz_off = 0; /* # characters scrolled off left of screen */
|
||||
int wraplines = 1; /* wrap lines around screen, yes or no */
|
||||
|
||||
extern int squeeze;
|
||||
extern int sigs;
|
||||
@ -103,7 +105,7 @@ forw_line(curr_pos)
|
||||
/*
|
||||
* Append the char to the line and get the next char.
|
||||
* The pappend() will throw away any unimportant chars
|
||||
* (ie. not underlines or bolds) as per horiz_off.
|
||||
* (ie. not underlines or bolds) as per wraplines.
|
||||
*
|
||||
* XXX line.c needs to be rewritten...
|
||||
*/
|
||||
@ -114,7 +116,7 @@ forw_line(curr_pos)
|
||||
* is too long to print in the screen width.
|
||||
* End the line here.
|
||||
*/
|
||||
if (horiz_off != NO_HORIZ_OFF) {
|
||||
if (!wraplines) {
|
||||
/* Throw away left-over characters on line */
|
||||
c = ch_forw_get();
|
||||
while (c != '\n' && c != EOI)
|
||||
@ -247,7 +249,7 @@ back_line(curr_pos)
|
||||
break;
|
||||
if (pappend(c))
|
||||
{
|
||||
if (horiz_off == NO_HORIZ_OFF) {
|
||||
if (wraplines) {
|
||||
/*
|
||||
* Got a full printable line, but we haven't
|
||||
* reached our curr_pos yet. Discard the line
|
||||
|
@ -36,6 +36,8 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#define MAXVARLENGTH (20)
|
||||
|
||||
#define NULL_POSITION ((off_t)(-1))
|
||||
|
||||
#define EOI (0)
|
||||
@ -58,37 +60,77 @@
|
||||
#define BOTTOM_PLUS_ONE (-2)
|
||||
#define MIDDLE (-3)
|
||||
|
||||
#define A_INVALID -1
|
||||
/* The return type of runmacro() */
|
||||
enum runmacro { OK=0, TOOMACRO, BADMACRO, NOMACRO, BADCOMMAND };
|
||||
|
||||
#define A_AGAIN_SEARCH 1
|
||||
#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_EXAMINE 7
|
||||
#define A_FREPAINT 8
|
||||
#define A_F_LINE 9
|
||||
#define A_F_SCREEN 10
|
||||
#define A_F_SCROLL 11
|
||||
#define A_F_SEARCH 12
|
||||
#define A_GOEND 13
|
||||
#define A_GOLINE 14
|
||||
#define A_GOMARK 15
|
||||
#define A_HELP 16
|
||||
#define A_NEXT_FILE 17
|
||||
#define A_PERCENT 18
|
||||
#define A_PREFIX 19
|
||||
#define A_PREV_FILE 20
|
||||
#define A_QUIT 21
|
||||
#define A_REPAINT 22
|
||||
#define A_SETMARK 23
|
||||
#define A_STAT 24
|
||||
#define A_VISUAL 25
|
||||
#define A_TAGFILE 26
|
||||
#define A_FILE_LIST 27
|
||||
#define A_L_COL 28
|
||||
#define A_R_COL 29
|
||||
#define A_HOME 30
|
||||
#define A_NEXTTAG 31
|
||||
#define A_PREVTAG 32
|
||||
#ifdef DEFINEGLOBALS
|
||||
#define GLOBAL(var, val) var = val
|
||||
#else
|
||||
#define GLOBAL(var, val) extern var
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* This style of error-reporting (see also command.c) is only used by some
|
||||
* code. Eventually most of the code should use it, since it is becoming
|
||||
* inconvenient to have John Q. random function() calling error().
|
||||
*
|
||||
* This style of error-reporting still leaves somewhat to be desired....
|
||||
*
|
||||
* Note that more(1) needs to potentially work under low-memory conditions
|
||||
* (such as may occur when all available memory has been sucked-up by
|
||||
* the file buffer in ch.c).
|
||||
*/
|
||||
|
||||
/* Be careful about ordering correctly!! (must match deferrinit_) */
|
||||
enum error { E_OK=0, E_AMBIG, E_BADMATH, E_BADVAR, E_BOGCOM, E_CANTPARSE,
|
||||
E_CANTXPND, E_COMPLIM, E_EXTERN, E_NOMAC, E_MALLOC, E_NONUM,
|
||||
E_NOSTR, E_NOTOG, E_NULL };
|
||||
|
||||
/* Listed here for reference only. Be careful about ordering correctly!! */
|
||||
#define deferrinit_ { \
|
||||
"", /* E_OK */ \
|
||||
"ambigious macro", /* E_AMBIG */ \
|
||||
"invalid arithmetic expression", /* E_BADMATH */ \
|
||||
"bad variable", /* E_BADVAR */ \
|
||||
"bogus command", /* E_BOGCOM */ \
|
||||
"could not parse command string", /* E_CANTPARSE */ \
|
||||
"could not expand macro", /* E_CANTXPND */ \
|
||||
"compile time limit", /* E_COMPLIM */ \
|
||||
"external dependency error", /* E_EXTERN */ \
|
||||
"could not find match for macro", /* E_NOMAC */ \
|
||||
"malloc() failed", /* E_MALLOC */ \
|
||||
"missing numeric argument to command", /* E_NONUM */ \
|
||||
"missing string argument to command", /* E_NOSTR */ \
|
||||
"bad n-toggle argument to command", /* E_NOTOG */ \
|
||||
"to the unknown error", /* E_NULL */ \
|
||||
}
|
||||
GLOBAL(const char *deferr[], deferrinit_ );
|
||||
|
||||
/*
|
||||
* It is possible for erreur to become dis-synchronized from errstr if
|
||||
* its users aren't careful. Access through the macros is considered
|
||||
* careful.
|
||||
*/
|
||||
GLOBAL(enum error erreur, NULL);
|
||||
GLOBAL(char *errstr, NULL); /* must point be null or free()'ble */
|
||||
|
||||
#define SETERR(e) do { \
|
||||
erreur = (e); \
|
||||
if (errstr) free(errstr); \
|
||||
errstr = NULL; \
|
||||
} while (0)
|
||||
/* SETERRSTR() also exists. It is in command.c */
|
||||
|
||||
/*
|
||||
* An emalloc() traditionally never fails, but fmalloc() may fail, hence
|
||||
* the non-standard name. The fmalloc() is just syntactic sugar that sets
|
||||
* erreur for the user.
|
||||
*
|
||||
* fmalloc(size, pointer-to-new-memory);
|
||||
*
|
||||
* Don't compile this puppy with -Wall...
|
||||
*/
|
||||
|
||||
#define FMALLOC(s,v) ((((v) = malloc(s)) ? 0 : \
|
||||
((errstr ? free(errstr), errstr=NULL : 0), erreur = E_MALLOC)), (v))
|
||||
|
61
usr.bin/more/less.morerc
Normal file
61
usr.bin/more/less.morerc
Normal file
@ -0,0 +1,61 @@
|
||||
#
|
||||
# This sample .morerc causes more to emulate the default GNU less(1)
|
||||
# keys, in so far as more(1) is capable (which is not very far at the
|
||||
# moment).
|
||||
#
|
||||
# Some of this will/should/may be eventually merged into default.morerc.
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
|
||||
# magic value indicating we should use ${sc_height}
|
||||
set window 2424989898
|
||||
|
||||
macro 0 H 'help'
|
||||
set com_getscr 'condition (${number} == 0); \
|
||||
condition (${window} == 2424989898); \
|
||||
set scr_scroll ${sc_height}; \
|
||||
condition_toggle; \
|
||||
set scr_scroll ${window}; \
|
||||
condition (${number} != 0); \
|
||||
set scr_scroll ${number}; \
|
||||
condition true;'
|
||||
macro 0 "" 'eval ${com_getscr}; forw ${scr_scroll};'
|
||||
macro 0 z 'condition (${number} == 0); \
|
||||
eval ${com_getscr}; forw ${scr_scroll}; \
|
||||
condition (${number} != 0); \
|
||||
set window ${number}; forw ${number}; \
|
||||
condition true;'
|
||||
macro 0 w 'condition (${number} == 0); \
|
||||
eval ${com_getscr}; back ${scr_scroll}; \
|
||||
condition (${number} != 0); \
|
||||
set window ${number}; back ${number}; \
|
||||
condition true;'
|
||||
macro 0 "\ev" 'eval ${com_getscr}; back ${scr_scroll};'
|
||||
macro 1 "" 'forw_scroll ${number};'
|
||||
macro 1 e 'forw_scroll ${number};'
|
||||
macro 1 "" 'forw_scroll ${number};'
|
||||
macro 1 y 'back_scroll ${number};'
|
||||
macro 1 "" 'back_scroll ${number};'
|
||||
macro 1 "" 'back_scroll ${number};'
|
||||
macro 1 "" 'back_scroll ${number};'
|
||||
macro 8 \e) 'rscroll ${number};'
|
||||
macro 8 \e[C 'rscroll ${number};'
|
||||
macro 8 \e( 'lscroll ${number};'
|
||||
macro 8 \e[D 'lscroll ${number};'
|
||||
macro 1 "<" 'goline ${number};'
|
||||
macro 1 "\e<" 'goline ${number};
|
||||
macro 0 ">" 'condition (${number} == 0); goend; \
|
||||
condition (${number} != 0); goline ${number}; \
|
||||
condition true;'
|
||||
macro 0 "\e>" 'condition (${number} == 0); goend; \
|
||||
condition (${number} != 0); goline ${number}; \
|
||||
condition true;'
|
||||
macro 0 "" 'gomark ?;'
|
||||
macro 0 "" 'askfile;'
|
||||
macro 0 :f 'stat (${_stat_n} + 1);'
|
||||
macro 0 V 'error "Less is not being run!"
|
||||
macro 0 Q 'quit;'
|
||||
macro 0 :Q 'quit;'
|
||||
# It might be possible to match the brace/bracket-pairing feature of
|
||||
# less using some complex regexps... Project for a rain weekend... :-)
|
@ -111,7 +111,7 @@ prewind()
|
||||
{
|
||||
line = curr = linebuf;
|
||||
ln_state = LN_NORMAL;
|
||||
column = (horiz_off == NO_HORIZ_OFF) ? 0 : -horiz_off;
|
||||
column = -horiz_off;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -379,14 +379,9 @@ pappend(c)
|
||||
/*
|
||||
* Expand a tab into spaces.
|
||||
*/
|
||||
if (horiz_off != NO_HORIZ_OFF)
|
||||
do {
|
||||
NEW_COLUMN(1);
|
||||
} while (((column + horiz_off) % tabstop) != 0);
|
||||
else
|
||||
do {
|
||||
NEW_COLUMN(1);
|
||||
} while ((column % tabstop) != 0);
|
||||
do {
|
||||
NEW_COLUMN(1);
|
||||
} while (((column + horiz_off) % tabstop) != 0);
|
||||
*curr++ = '\t';
|
||||
return (0);
|
||||
}
|
||||
|
292
usr.bin/more/macro.c
Normal file
292
usr.bin/more/macro.c
Normal file
@ -0,0 +1,292 @@
|
||||
/*-
|
||||
* Copyright (c) 1999 Timmy M. Vanderhoek
|
||||
* All rights reserved.
|
||||
*
|
||||
* 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, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef lint
|
||||
static const char rcsid[] =
|
||||
"$Id$";
|
||||
#endif /* not lint */
|
||||
|
||||
/*
|
||||
* Expansion of macros.
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "less.h"
|
||||
|
||||
|
||||
/*
|
||||
* Used to construct tables of macros. Each macro string expands to command.
|
||||
* A number N is associated with each execution of a macro. The command
|
||||
* "set number <N>" will be done before the expansion. The end of the table is
|
||||
* specified by mactabsize. A NULL entry for command denotes a macro that
|
||||
* has been marked deleted for some reason. As of this writing, there is no
|
||||
* code that actually deletes a macro...
|
||||
*/
|
||||
struct macro {
|
||||
char *string; /* characters typed to activate macro */
|
||||
char *command; /* command resulting after the macro is activated */
|
||||
long defnumber; /* default value of the N number */
|
||||
int flags; /* only holds STICKYNUMB for now... */
|
||||
};
|
||||
/* (struct macro) ->flags */
|
||||
#define NOFLAGS 0
|
||||
#define STICKYNUMB 1 /* Set defnumber to current number, if current number */
|
||||
|
||||
/*
|
||||
* The macro table.
|
||||
*/
|
||||
struct macro *mactab = NULL;
|
||||
int mactabsize = 0;
|
||||
|
||||
static enum runmacro runmacro_();
|
||||
static struct macro *matchmac();
|
||||
|
||||
|
||||
/*
|
||||
* XXX Everything's really just a macro until resolved as a quantum wave
|
||||
* probability distribution.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Attempts to run the appropriate macro. Returns 0, or OK, if the macro
|
||||
* was succesfully run. Returns BADMACRO and sets erreur if something is
|
||||
* horribly wrong with the macro. Returns NOMACRO if the macro has no valid
|
||||
* expansion. BADMACRO and NOMACRO are almost the same. Returns BADCOMMAND
|
||||
* and leaves erreur set (hopefully it was set when runmacro() tried to execute
|
||||
* the command associated with the macro) if the command associated with
|
||||
* the macro was unsuccessful. Returns TOOMACRO if the macro appears to be
|
||||
* incomplete (ie. the user has not finished typing it in yet). The erreur
|
||||
* is not set in this case.
|
||||
*
|
||||
* XXX There's no good reason not to just disallow badmacros from within
|
||||
* setmacro() ... It's not clear what the author was thinking at the time.
|
||||
*/
|
||||
enum runmacro
|
||||
runmacro(macro, number, anyN)
|
||||
const char *macro; /* the macro string to try and expand */
|
||||
long number; /* the number N associated with this execution */
|
||||
int anyN; /* FALSE is we should use the default N associated with
|
||||
* the macro. TRUE if we should use the number argument. */
|
||||
{
|
||||
struct macro *cur, *matched;
|
||||
int match, yetmatch;
|
||||
int s;
|
||||
|
||||
if (!mactab) {
|
||||
/* Should only happen with really sucky default rc files... */
|
||||
SETERR (E_CANTXPND);
|
||||
return NOMACRO;
|
||||
}
|
||||
|
||||
match = yetmatch = 0;
|
||||
for (cur = mactab, s = mactabsize; s; cur++, s--) {
|
||||
if (!cur->command)
|
||||
continue; /* deleted macro */
|
||||
if (!strcmp(cur->string, macro))
|
||||
matched = cur, match++;
|
||||
else if (!strncmp(cur->string, macro, strlen(macro)))
|
||||
yetmatch++;
|
||||
}
|
||||
|
||||
if (match == 1) {
|
||||
if (yetmatch) {
|
||||
SETERR (E_AMBIG);
|
||||
return BADMACRO;
|
||||
}
|
||||
|
||||
/* XXX it's not clear how to handle error when setting
|
||||
* the number N --- this is a deficiency in the style of error-
|
||||
* reporting suggested in command.c and less.h. Could have
|
||||
* setvar() guarantee success when setting "number". A failure
|
||||
* must not become fatal or it becomes impossible to do
|
||||
* any commands at all. */
|
||||
if (anyN) {
|
||||
if (matched->flags & STICKYNUMB)
|
||||
matched->defnumber = number;
|
||||
(void) setvari("number", number);
|
||||
} else
|
||||
(void) setvari("number", matched->defnumber);
|
||||
clear_error();
|
||||
|
||||
if (command(matched->command))
|
||||
return BADCOMMAND;
|
||||
return OK;
|
||||
}
|
||||
if (match > 1) {
|
||||
SETERR (E_AMBIG);
|
||||
return BADMACRO;
|
||||
}
|
||||
if (!match && !yetmatch) {
|
||||
SETERR (E_CANTXPND);
|
||||
return NOMACRO;
|
||||
}
|
||||
assert(yetmatch);
|
||||
return TOOMACRO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Associates a macro with a given command. Returns -1 if it was unable to
|
||||
* set the macro. Errors associated with setting a macro may be caught
|
||||
* either in this function, setmacro(), or in runmacro(). Both macro and
|
||||
* command are strcpy()'d into their own space.
|
||||
*/
|
||||
int
|
||||
setmacro(macro, command)
|
||||
const char *macro;
|
||||
const char *command;
|
||||
{
|
||||
struct macro *cur, *new = NULL;
|
||||
char *new_mac, *new_com;
|
||||
int s;
|
||||
|
||||
assert (macro); assert (command);
|
||||
|
||||
/* First, check for any existing macro matches in the custom table */
|
||||
s = mactabsize;
|
||||
for (cur = mactab; s; cur++, s--) {
|
||||
if (!cur->command) {
|
||||
/* Hmm... A deleted macro in the table */
|
||||
new = cur;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(cur->string, macro)) {
|
||||
/*
|
||||
* An exact match to the new macro already exists.
|
||||
* Calling realloc() on cur->string and cur->command
|
||||
* without risking being left in bad state is tricky.
|
||||
* Just do it the slow but sure way...
|
||||
*/
|
||||
new = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Do the allocations here so that we can maintain consistent state
|
||||
* even if realloc() fails when we try to expand the table (suppose
|
||||
* the table gets expanded but the next malloc to get space for the
|
||||
* macro fails).
|
||||
*/
|
||||
if (!FMALLOC(strlen(macro) + 1, new_mac))
|
||||
return -1;
|
||||
if (!FMALLOC(strlen(command) + 1, new_com))
|
||||
return -1;
|
||||
|
||||
if (!new) {
|
||||
/* Extend the command table by one record */
|
||||
struct macro *t = realloc(mactab, (mactabsize + 1) *
|
||||
sizeof(struct macro));
|
||||
if (!t) {
|
||||
/* The old mactab is still valid. Just back out. */
|
||||
free(new_mac), free(new_com);
|
||||
SETERR (E_MALLOC);
|
||||
return -1;
|
||||
} else
|
||||
mactab = t;
|
||||
new = &mactab[mactabsize];
|
||||
mactabsize++;
|
||||
new->string = new->command = NULL;
|
||||
}
|
||||
|
||||
if (new->string) free(new->string);
|
||||
if (new->command) free(new->command);
|
||||
new->string = new_mac;
|
||||
new->command = new_com;
|
||||
strcpy(new->string, macro);
|
||||
strcpy(new->command, command);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the sticky tag on a macro. Returns -1 on failure, 0 on success.
|
||||
*/
|
||||
int
|
||||
stickymac(macro, state)
|
||||
const char *macro;
|
||||
int state; /* set it to TRUE or set it to FALSE */
|
||||
{
|
||||
struct macro *m = matchmac(macro);
|
||||
if (!m)
|
||||
return -1;
|
||||
|
||||
if (state)
|
||||
m->flags |= STICKYNUMB;
|
||||
else
|
||||
m->flags &= ~STICKYNUMB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the default number of a macro. Returns -1 on failure, 0 on success.
|
||||
*/
|
||||
int
|
||||
setmacnumb(macro, N)
|
||||
const char *macro;
|
||||
long N; /* The default number */
|
||||
{
|
||||
struct macro *m = matchmac(macro);
|
||||
if (!m)
|
||||
return -1;
|
||||
|
||||
m->defnumber = N;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tries to find a struct macro matching "macro". Returns NULL if an exact
|
||||
* match could not be found (eg. ambiguous macro, no macro, etc).
|
||||
*/
|
||||
static struct macro *
|
||||
matchmac(macro)
|
||||
const char *macro;
|
||||
{
|
||||
struct macro *retr, *cur;
|
||||
int s;
|
||||
|
||||
retr = NULL;
|
||||
for (cur = mactab, s = mactabsize; s; cur++, s--) {
|
||||
if (!cur->command)
|
||||
continue;
|
||||
if (!strcmp(cur->string, macro)) {
|
||||
if (retr) {
|
||||
SETERR (E_AMBIG);
|
||||
return NULL; /* matched twice! */
|
||||
} else
|
||||
retr = cur;
|
||||
} else if (!strncmp(cur->string, macro, strlen(macro))) {
|
||||
SETERR (E_AMBIG);
|
||||
return NULL; /* ambiguous macro! */
|
||||
}
|
||||
}
|
||||
return retr;
|
||||
}
|
@ -56,18 +56,21 @@ static const char rcsid[] =
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define DEFINEGLOBALS
|
||||
#include "defrc.h"
|
||||
#include "less.h"
|
||||
#include "pathnames.h"
|
||||
|
||||
int ispipe;
|
||||
char *current_file, *previous_file, *current_name, *next_name;
|
||||
int any_display;
|
||||
int scroll;
|
||||
int ac;
|
||||
char **av;
|
||||
int curr_ac;
|
||||
@ -88,7 +91,6 @@ extern int tagoption;
|
||||
edit(filename)
|
||||
register char *filename;
|
||||
{
|
||||
extern int errno;
|
||||
register int f;
|
||||
register char *m;
|
||||
off_t initial_pos, prev_pos, position();
|
||||
@ -334,8 +336,15 @@ main(argc, argv)
|
||||
} while (file < 0 && ++curr_ac < ac);
|
||||
}
|
||||
|
||||
if (file >= 0)
|
||||
if (file >= 0) {
|
||||
/*
|
||||
* Don't call rcfiles() until now so that people who put
|
||||
* wierd things (like "forw_scroll") in their rc file don't
|
||||
* cause us to SEGV.
|
||||
*/
|
||||
rcfiles();
|
||||
commands();
|
||||
}
|
||||
quit();
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
@ -375,3 +384,156 @@ quit()
|
||||
raw_mode(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in from each of the three rc files - default, system, user.
|
||||
* Calls handle_error() directly to report errors.
|
||||
*/
|
||||
rcfiles()
|
||||
{
|
||||
FILE *fd;
|
||||
char fbuf[MAXPATHLEN + 1];
|
||||
char *c;
|
||||
int readrc();
|
||||
int savederrno;
|
||||
static int str_read();
|
||||
|
||||
/* The default builtin rc file */
|
||||
if ((c = getenv("HOME")) &&
|
||||
strlen(c) + strlen(_PATH_DEFRC) + 1 < MAXPATHLEN) {
|
||||
sprintf(fbuf, "%s/%s", c, _PATH_DEFRC);
|
||||
fd = fopen(fbuf, "r");
|
||||
savederrno = errno;
|
||||
if (!fd) {
|
||||
if (!access(_PATH_SYSMORERC, F_OK)) {
|
||||
SETERRSTR(E_EXTERN, "unable to read %s: %s",
|
||||
_PATH_SYSMORERC, strerror(savederrno));
|
||||
handle_error();
|
||||
}
|
||||
/* We'd better have some type of default keys!! */
|
||||
goto use_builtin_defrc;
|
||||
} else {
|
||||
readrc(fd);
|
||||
fclose(fd);
|
||||
}
|
||||
} else {
|
||||
use_builtin_defrc:
|
||||
fd = fropen(DEFRC, str_read);
|
||||
readrc(fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
/* The system rc file */
|
||||
fd = fopen(_PATH_SYSMORERC, "r");
|
||||
savederrno = errno;
|
||||
if (!fd) {
|
||||
if (!access(_PATH_SYSMORERC, F_OK)) {
|
||||
SETERRSTR(E_EXTERN, "unable to read %s: %s",
|
||||
_PATH_SYSMORERC, strerror(savederrno));
|
||||
handle_error();
|
||||
} else
|
||||
; /* non-existant => non-error */
|
||||
} else {
|
||||
readrc(fd);
|
||||
fclose(fd);
|
||||
}
|
||||
|
||||
/* The user rc file */
|
||||
if ((c = getenv("HOME")) &&
|
||||
strlen(c) + strlen(_PATH_RC) + 1 < MAXPATHLEN) {
|
||||
sprintf(fbuf, "%s/%s", c, _PATH_RC);
|
||||
fd = fopen(fbuf, "r");
|
||||
savederrno = errno;
|
||||
if (!fd) {
|
||||
if (!access(fbuf, F_OK)) {
|
||||
SETERRSTR(E_EXTERN,
|
||||
"unable to read %s: %s", fbuf,
|
||||
strerror(savederrno));
|
||||
handle_error();
|
||||
} else
|
||||
; /* non-existant => non-error */
|
||||
} else {
|
||||
readrc(fd);
|
||||
fclose(fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read-in an rc file from a fd. Calls handle_error() directly to handle
|
||||
* errors.
|
||||
*
|
||||
* This really belongs in ncommand.c, but that file is already 33292 bytes
|
||||
* long.
|
||||
*/
|
||||
readrc(fd)
|
||||
FILE *fd;
|
||||
{
|
||||
char *bufptr, *buf;
|
||||
size_t len;
|
||||
int strlenbuf;
|
||||
|
||||
buf = NULL;
|
||||
strlenbuf = 0;
|
||||
while (bufptr = fgetln(fd, &len)) {
|
||||
if (!len)
|
||||
continue; /* ??? */
|
||||
if (*bufptr == '#')
|
||||
continue; /* skip comments */
|
||||
if (!(buf = reallocf(buf, strlenbuf + len + 1))) {
|
||||
SETERR(E_MALLOC);
|
||||
handle_error();
|
||||
if (strlenbuf + len < 1024)
|
||||
return; /* major memory shortage... */
|
||||
continue;
|
||||
}
|
||||
memcpy (buf + strlenbuf, bufptr, len);
|
||||
buf[len + strlenbuf] = '\0';
|
||||
if (len > 1 && buf[strlenbuf + len - 2] == '\\') {
|
||||
/* line continuation */
|
||||
buf[strlenbuf + len - 2] = '\0';
|
||||
strlenbuf = strlen(buf);
|
||||
continue;
|
||||
}
|
||||
if (buf[len + strlenbuf - 1] == '\n')
|
||||
buf[len + strlenbuf - 1] = '\0';
|
||||
if (command(buf))
|
||||
handle_error();
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
strlenbuf = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read from the NUL-terminated cookie. Non-reentrant: keeps a static pointer
|
||||
* to the current position in the cookie. Used for funopen().
|
||||
*/
|
||||
static int
|
||||
str_read(cookie, buf, len)
|
||||
void *cookie;
|
||||
char *buf;
|
||||
size_t len;
|
||||
{
|
||||
static char *curpos;
|
||||
static int cooklen;
|
||||
static char *lastcook;
|
||||
|
||||
if (lastcook != cookie) {
|
||||
/* begin working on a new cookie */
|
||||
curpos = cookie;
|
||||
lastcook = cookie;
|
||||
cooklen = strlen(cookie);
|
||||
}
|
||||
|
||||
if (curpos + len > lastcook + cooklen) {
|
||||
ssize_t r;
|
||||
memcpy(buf, curpos, r = (cooklen - (curpos - lastcook)));
|
||||
curpos = cookie + cooklen;
|
||||
return (int) r;
|
||||
} else {
|
||||
memcpy(buf, curpos, len);
|
||||
curpos += len;
|
||||
return (int) len;
|
||||
}
|
||||
}
|
||||
|
@ -225,8 +225,10 @@ which does NOT contain the pattern.
|
||||
.It Ic \&?\&! Ns Ar pattern
|
||||
Like ?, but the search is for the N-th line
|
||||
which does NOT contain the pattern.
|
||||
.It Ic n
|
||||
Repeat previous search, for N-th line containing the last pattern
|
||||
.It Ic n No and Ic N
|
||||
Repeat previous search,
|
||||
in same or opposite direction respectively,
|
||||
for N-th line containing the last pattern
|
||||
(or
|
||||
.Tn NOT
|
||||
containing the last pattern, if the previous search
|
||||
@ -237,11 +239,11 @@ If the filename is missing, the "current" file (see the N and P commands
|
||||
below) from the list of files in the command line is re-examined.
|
||||
If the filename is a pound sign (#), the previously examined file is
|
||||
re-examined.
|
||||
.It Ic N No or Ic \&:n
|
||||
.It Ic \&:n
|
||||
Examine the next file (from the list of files given in the command line).
|
||||
If a number N is specified (not to be confused with the command N),
|
||||
the N-th next file is examined.
|
||||
.It Ic P No or Ic \&:p
|
||||
.It Ic \&:p
|
||||
Examine the previous file.
|
||||
If a number N is specified, the N-th previous file is examined.
|
||||
.It Ic \&:t
|
||||
|
@ -25,11 +25,13 @@
|
||||
?pattern * Search backward for N-th line containing the pattern.
|
||||
?!pattern * Search backward for N-th line NOT containing the pattern.
|
||||
n * Repeat previous search (for N-th occurence).
|
||||
N * Repeat previous search (for N-th occurence), switching
|
||||
the direction of the search.
|
||||
|
||||
:a Display the list of files.
|
||||
E [file] Examine a new file.
|
||||
:n, N * Examine the next file.
|
||||
:p, P * Examine the previous file.
|
||||
:n * Examine the next file.
|
||||
:p * Examine the previous file.
|
||||
:t [tag] Examine the tag.
|
||||
t, T Move forward or backward N tags in the gtags queue.
|
||||
v Run an editor on the current file.
|
||||
|
86
usr.bin/more/most.morerc
Normal file
86
usr.bin/more/most.morerc
Normal file
@ -0,0 +1,86 @@
|
||||
#
|
||||
# This sample .morerc causes more to emulate the default most(1)
|
||||
# keys, in so far as more(1) is capable (which is not very far at the
|
||||
# moment).
|
||||
#
|
||||
# $FreeBSD$
|
||||
#
|
||||
# BUGS: It's extremely unlikely that more(1) will ever support multiple
|
||||
# windows as most(1) does. Multiple windows is an editor function,
|
||||
# isn't it?
|
||||
#
|
||||
|
||||
macro 1 "" 'forw (${_sc_height} * ${number})'
|
||||
macro 1 v 'forw ${number}'
|
||||
macro 1 V 'forw ${number}'
|
||||
macro 1 "" 'forw ${number}'
|
||||
macro 1 "" 'back ${number}'
|
||||
macro 1 ^ 'back ${number}'
|
||||
macro 0 T 'goline 1'
|
||||
macro 0 "\e<" 'goline 1'
|
||||
macro 0 B 'goend'
|
||||
macro 0 "\e>" 'goend'
|
||||
# Doesn't match most(1) documentation
|
||||
macro 1 "\e[C" 'rscroll ${number}'
|
||||
macro 1 "\t" 'rscroll (60 * ${number})'
|
||||
macro 1 > 'rscroll (60 * ${number})'
|
||||
# Doesn't match most(1) documentation
|
||||
macro 1 "\e[D" 'lscroll ${number}'
|
||||
# Doesn't really do much, being ^B and all...
|
||||
macro 1 "" 'lscroll (60 * ${number})'
|
||||
macro 1 < 'lscroll (60 * ${number})'
|
||||
macro 1 u 'back (${_sc_height} * ${number})'
|
||||
macro 1 U 'back (${_sc_height} * ${number})'
|
||||
macro 1 "" 'back (${_sc_height} * ${number})'
|
||||
macro 1 "" 'back (${_sc_height} * ${number})'
|
||||
macro 0 R 'repaint'
|
||||
macro 0 r 'repaint'
|
||||
macro 0 "" 'repaint'
|
||||
macro 0 j 'condition (${number} == 0); \
|
||||
error "prompt for line-number not supported"; \
|
||||
condition (${number} != 0); \
|
||||
goline ${number}; \
|
||||
condition true;'
|
||||
macro 0 J 'condition (${number} == 0); \
|
||||
error "prompt for line-number not supported"; \
|
||||
condition (${number} != 0); \
|
||||
goline ${number}; \
|
||||
condition true;'
|
||||
macro 0 g 'condition (${number} == 0); \
|
||||
error "prompt for line-number not supported"; \
|
||||
condition (${number} != 0); \
|
||||
goline ${number}; \
|
||||
condition true;'
|
||||
macro 0 G 'condition (${number} == 0); \
|
||||
error "prompt for line-number not supported"; \
|
||||
condition (${number} != 0); \
|
||||
goline ${number}; \
|
||||
condition true;'
|
||||
macro 0 % 'condition (${number} == 0); \
|
||||
error "prompt for percent not supported"; \
|
||||
condition_toggle; \
|
||||
gopercent ${number}; \
|
||||
condition true;'
|
||||
macro 0 q 'quit'
|
||||
macro 0 Q 'quit'
|
||||
macro 0 "E" 'quit'
|
||||
macro 0 h 'help'
|
||||
macro 0 H 'help'
|
||||
macro 0 "" 'help'
|
||||
macro 0 "\e[N" 'help'
|
||||
macro 1 f 'magicasksearch forw ${number}'
|
||||
macro 1 / 'magicasksearch forw ${number}'
|
||||
macro 1 "" 'magicasksearch forw ${number}'
|
||||
macro 1 ? 'magicasksearch back ${number}'
|
||||
macro 1 n 'research ${_ls_direction_n} ${number}'
|
||||
macro 1 N 'research ${_ls_direction_n} ${number}'
|
||||
# The mark stuff could be more effeciently done with a temp var, of course... :)
|
||||
# These are nice enough that I'm tempted to bring them into default.morerc
|
||||
macro 0 m 'setmark z'
|
||||
macro 0 "M" 'setmark z'
|
||||
macro 0 "." 'setmark z'
|
||||
macro 0 "" 'setmark y; gomark z; setmark x; gomark y; setmark z; gomark x;'
|
||||
macro 0 "," 'setmark y; gomark z; setmark x; gomark y; setmark z; gomark x;'
|
||||
macro 0 e 'edit'
|
||||
macro 0 E 'edit'
|
||||
macro 0 :n 'file next ${number}'
|
1452
usr.bin/more/ncommand.c
Normal file
1452
usr.bin/more/ncommand.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -77,6 +77,16 @@ option(argc, argv)
|
||||
while ((ch = getopt(argc, argv, "/:ceinst:ux:f")) != -1)
|
||||
switch((char)ch) {
|
||||
case '/':
|
||||
/*
|
||||
* Might be interesting to make this option search
|
||||
* through the whole list of files on the command line
|
||||
* until a match is found. Prior to this commit adding
|
||||
* the new comand interpreter, it would sort-of do
|
||||
* this, provided all the files listed on the command
|
||||
* line were of length zero bytes (well, with the
|
||||
* exception of the file actually containing a match,
|
||||
* I suppose).
|
||||
*/
|
||||
firstsearch = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
|
@ -51,8 +51,6 @@ static const char rcsid[] =
|
||||
|
||||
#include "less.h"
|
||||
|
||||
int errmsgs; /* Count of messages displayed by error() */
|
||||
|
||||
extern int bs_mode;
|
||||
extern int sigs;
|
||||
extern int sc_width, sc_height;
|
||||
@ -61,7 +59,6 @@ extern int so_width, se_width;
|
||||
extern int bo_width, be_width;
|
||||
extern int tabstop;
|
||||
extern int screen_trashed;
|
||||
extern int any_display;
|
||||
extern char *line;
|
||||
extern int horiz_off;
|
||||
extern int mode_flags;
|
||||
@ -121,7 +118,7 @@ markup(ent_ul, ent_bo)
|
||||
* UL_CHAR, UE_CHAR, BO_CHAR, BE_CHAR markups.
|
||||
*/
|
||||
#define MAYPUTCHR(char) \
|
||||
if (column >= eff_horiz_off) { \
|
||||
if (column >= horiz_off) { \
|
||||
column += markup(&ent_ul, &ent_bo); \
|
||||
putchr(char); \
|
||||
}
|
||||
@ -133,7 +130,6 @@ put_line()
|
||||
register int column;
|
||||
extern int auto_wrap, ignaw;
|
||||
int ent_ul, ent_bo; /* enter or exit ul|bo mode for next char */
|
||||
int eff_horiz_off;
|
||||
|
||||
if (sigs)
|
||||
{
|
||||
@ -144,11 +140,6 @@ put_line()
|
||||
return;
|
||||
}
|
||||
|
||||
if (horiz_off == NO_HORIZ_OFF)
|
||||
eff_horiz_off = 0;
|
||||
else
|
||||
eff_horiz_off = horiz_off;
|
||||
|
||||
if (line == NULL)
|
||||
line = "";
|
||||
|
||||
@ -198,11 +189,11 @@ put_line()
|
||||
case '\b':
|
||||
/*
|
||||
* column must be at least one greater than
|
||||
* eff_horiz_off (ie. we must be in the second or
|
||||
* horiz_off (ie. we must be in the second or
|
||||
* beyond screen column) or we'll just end-up
|
||||
* backspacing up to the previous line.
|
||||
*/
|
||||
if (column > eff_horiz_off) {
|
||||
if (column > horiz_off) {
|
||||
column += markup(&ent_ul, &ent_bo);
|
||||
putbs();
|
||||
column--;
|
||||
@ -234,11 +225,11 @@ put_line()
|
||||
column++;
|
||||
}
|
||||
}
|
||||
if (column == sc_width + eff_horiz_off && mode_flags)
|
||||
if (column == sc_width + horiz_off && mode_flags)
|
||||
last_pos_highlighted = 1;
|
||||
}
|
||||
column += markup(&ent_ul, &ent_bo);
|
||||
if (column < sc_width + eff_horiz_off || !auto_wrap || ignaw)
|
||||
if (column < sc_width + horiz_off || !auto_wrap || ignaw)
|
||||
putchr('\n');
|
||||
}
|
||||
|
||||
@ -290,65 +281,28 @@ putstr(s)
|
||||
putchr(*s++);
|
||||
}
|
||||
|
||||
int cmdstack;
|
||||
static char return_to_continue[] = "(press RETURN)";
|
||||
|
||||
/*
|
||||
* Output a message in the lower left corner of the screen
|
||||
* and wait for carriage return.
|
||||
* Output a string, expanding control characters into printable sequences.
|
||||
* Returns the number of characters printed.
|
||||
*/
|
||||
error(s)
|
||||
int
|
||||
putxstr(s)
|
||||
char *s;
|
||||
{
|
||||
int ch;
|
||||
int c;
|
||||
int retr = 0;
|
||||
|
||||
++errmsgs;
|
||||
if (!any_display) {
|
||||
/*
|
||||
* Nothing has been displayed yet. Output this message on
|
||||
* error output (file descriptor 2) and don't wait for a
|
||||
* keystroke to continue.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
(void)write(2, s, strlen(s));
|
||||
(void)write(2, "\n", 1);
|
||||
return;
|
||||
for (; c = *s; s++) {
|
||||
if (CONTROL_CHAR(c)) {
|
||||
putchr('^');
|
||||
retr++;
|
||||
c &= ~0200;
|
||||
c = CARAT_CHAR(c);
|
||||
}
|
||||
putchr(c);
|
||||
}
|
||||
|
||||
lower_left();
|
||||
clear_eol();
|
||||
so_enter();
|
||||
if (s) {
|
||||
putstr(s);
|
||||
putstr(" ");
|
||||
}
|
||||
putstr(return_to_continue);
|
||||
so_exit();
|
||||
|
||||
if ((ch = getchr()) != '\n') {
|
||||
/* XXX hardcoded */
|
||||
if (ch == 'q')
|
||||
quit();
|
||||
cmdstack = ch;
|
||||
}
|
||||
lower_left();
|
||||
|
||||
if ((s==NULL)?0:(strlen(s)) + sizeof(return_to_continue) +
|
||||
so_width + se_width + 1 > 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. }}
|
||||
*/
|
||||
repaint();
|
||||
flush();
|
||||
return(retr);
|
||||
}
|
||||
|
||||
static char intr_to_abort[] = "... (interrupt to abort)";
|
||||
|
@ -31,8 +31,14 @@
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)pathnames.h 8.1 (Berkeley) 6/6/93
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <paths.h>
|
||||
|
||||
#define _PATH_HELPFILE "/usr/share/misc/more.help"
|
||||
#define _PATH_RC ".morerc"
|
||||
#define _PATH_DEFRC ".defmorerc"
|
||||
#define _PATH_SYSMORERC "/etc/dot.morerc"
|
||||
/* Should have a /etc/dot.defmorerc, too... */
|
||||
|
@ -313,7 +313,7 @@ prepaint(pos)
|
||||
off_t pos;
|
||||
{
|
||||
hit_eof = 0;
|
||||
forw(sc_height-1, pos, 0);
|
||||
forw(sc_height - 1, pos, 0);
|
||||
screen_trashed = 0;
|
||||
}
|
||||
|
||||
@ -581,26 +581,18 @@ gomark(c)
|
||||
new_horiz_off = marks[c-'a'].horiz_off;
|
||||
}
|
||||
|
||||
/* Try to be nice about changing the horizontal scroll */
|
||||
if (!(horiz_off == NO_HORIZ_OFF && new_horiz_off <= sc_width)) {
|
||||
/* Try to be nice about changing the horizontal scroll and wrapping */
|
||||
if (new_horiz_off > sc_width / 3 + horiz_off) {
|
||||
/*
|
||||
* We're going to have to change the horiz_off, even if
|
||||
* it's currently set to NO_HORIZ_OFF: if we don't change
|
||||
* horiz_off the bookmarked location won't show on the screen.
|
||||
* We should change horiz_off: if we don't change horiz_off
|
||||
* the bookmarked location won't be readily visible.
|
||||
*/
|
||||
if (horiz_off != new_horiz_off) {
|
||||
/* We'll need to repaint(), too... */
|
||||
horiz_off = new_horiz_off;
|
||||
prepaint(pos);
|
||||
} else {
|
||||
/* No need to repaint. */
|
||||
jump_loc(pos);
|
||||
}
|
||||
horiz_off = new_horiz_off;
|
||||
prepaint(pos);
|
||||
} else {
|
||||
/*
|
||||
* The user doesn't want horizontal scrolling, and we can
|
||||
* fortunately honour the bookmark request without doing
|
||||
* any horizontal scrolling.
|
||||
* We can honour the bookmark request without doing any
|
||||
* horizontal scrolling.
|
||||
*/
|
||||
jump_loc(pos);
|
||||
}
|
||||
|
@ -102,7 +102,6 @@ int ignaw; /* Terminal ignores \n immediately after wrap */
|
||||
int retain_below; /* Terminal retains text below the screen */
|
||||
int erase_char, kill_char, werase_char;
|
||||
int sc_width, sc_height = -1; /* Height & width of screen */
|
||||
int sc_window = -1; /* window size for forward and backward */
|
||||
int bo_width, be_width; /* Printing width of boldface sequences */
|
||||
int ul_width, ue_width; /* Printing width of underline sequences */
|
||||
int so_width, se_width; /* Printing width of standout sequences */
|
||||
@ -294,6 +293,8 @@ get_term()
|
||||
sc_width = tgetnum("co");
|
||||
if (sc_width < 0)
|
||||
sc_width = 80;
|
||||
(void) setvari("_sc_height", (long) sc_height - 1);
|
||||
(void) setvari("_sc_width", (long) sc_width);
|
||||
|
||||
auto_wrap = tgetflag("am");
|
||||
ignaw = tgetflag("xn");
|
||||
|
@ -65,7 +65,6 @@ extern int sc_width, sc_height;
|
||||
extern int screen_trashed;
|
||||
extern int lnloop;
|
||||
extern int linenums;
|
||||
extern int scroll;
|
||||
extern volatile int reading;
|
||||
|
||||
#ifdef SIGTSTP
|
||||
@ -181,7 +180,8 @@ psignals()
|
||||
get_term();
|
||||
if (sc_width != old_width || sc_height != old_height)
|
||||
{
|
||||
scroll = (sc_height + 1) / 2;
|
||||
(void) setvari("_sc_width", (long) sc_width);
|
||||
(void) setvari("_sc_height", (long) sc_height - 1);
|
||||
screen_trashed = 1;
|
||||
}
|
||||
}
|
||||
|
@ -74,6 +74,6 @@ getchr()
|
||||
*/
|
||||
quit();
|
||||
}
|
||||
} while (result != 1);
|
||||
} while (result != 1 || c == 0);
|
||||
return ((unsigned char)c);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user