sources-request@mirror.UUCP (08/11/86)
Submitted by: seismo!lll-crg!csustan!casey Mod.sources: Volume 6, Issue 103 Archive-name: less2/Part02 #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # makefile.sys5 # makefile.xen # mkfuncs.awk # n10-diff # option.c # output.c # pager_patch.c # position.c # position.h # prim.c # prompt.c # screen.c # signal.c # ttyin.c # version.c export PATH; PATH=/bin:/usr/bin:$PATH if test -f 'makefile.sys5' then echo shar: "will not over-write existing file 'makefile.sys5'" else cat << \SHAR_EOF > 'makefile.sys5' # Makefile for "less" # # Invoked as: # make all # or make install # Plain "make" is equivalent to "make all". # # If you add or delete functions, remake funcs.h by doing: # make newfuncs # This depends on the coding convention of function headers looking like: # " \t public <function-type> \n <function-name> ( ... ) " # # Also provided: # make lint # Runs "lint" on all the sources. # make clean # Removes "less" and the .o files. # make clobber # Pretty much the same as make "clean". # # make pager_patch # makes PAGER environment variable # make install_pager_patch # catcher and installs it (see below) ########################################################################## # System-specific parameters ########################################################################## # Define XENIX if running under XENIX 3.0 XENIX = 0 # VOID is 1 if your C compiler supports the "void" type, # 0 if it does not. VOID = 1 # off_t is the type which lseek() returns. # It is also the type of lseek()'s second argument. off_t = long # TERMIO is 1 if your system has /usr/include/termio.h. # This is normally the case for System 5. # If TERMIO is 0 your system must have /usr/include/sgtty.h. # This is normally the case for BSD. TERMIO = 1 # SIGSETMASK is 1 if your system has the sigsetmask() call. # This is normally the case only for BSD 4.2, # not for BSD 4.1 or System 5. SIGSETMASK = 0 ########################################################################## # Optional and semi-optional features ########################################################################## # REGCMP is 1 if your system has the regcmp() function. # This is normally the case for System 5. # RECOMP is 1 if your system has the re_comp() function. # This is normally the case for BSD. # If neither is 1, pattern matching is supported, but without metacharacters. REGCMP = 1 RECOMP = 0 # SHELL_ESCAPE is 1 if you wish to allow shell escapes. # (This is possible only if your system supplies the system() function.) SHELL_ESCAPE = 0 # 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. EDITOR = 0 EDIT_PGM = /usr/ucb/vi # parameters to "make install_pager_patch". OLD_PAGER will be moved to # OLD_PAGER_NEW_LOCATION and pager_patch (in this directory) will be installed # as OLD_PAGER. This patch will allow you to set the environment variable # PAGER to specify your personal pager preference (is this a security hole?) OLD_PAGER = /usr/ucb/more OLD_PAGER_NEW_LOCATION = /usr/ucb/More # 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. ONLY_RETURN = 0 ########################################################################## # Compilation environment. ########################################################################## # LIBS is the list of libraries needed. LIBS = -lcurses -lPW # INSTALL_LESS is a list of the public versions of less. # INSTALL_MAN is a list of the public versions of the manual page. INSTALL_LESS = /usr/lbin/less INSTALL_MAN = /usr/man/manl/less.l # OPTIM is passed to the compiler and the loader. # It is normally "-O" but may be, for example, "-g". OPTIM = -O ########################################################################## # Files ########################################################################## SRC1 = main.c option.c prim.c SRC2 = ch.c position.c input.c output.c screen.c \ prompt.c line.c signal.c help.c ttyin.c command.c version.c SRC = $(SRC1) $(SRC2) OBJ = main.o option.o prim.o ch.o position.o input.o output.o screen.o \ prompt.o line.o signal.o help.o ttyin.o command.o version.o ########################################################################## # Rules ########################################################################## DEFS = "-DTERMIO=$(TERMIO)" \ "-DSIGSETMASK=$(SIGSETMASK)" \ "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \ "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \ "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \ "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \ "-DONLY_RETURN=$(ONLY_RETURN)" \ "-DXENIX=$(XENIX)" \ "-DOLD_PAGER_NEW_LOCATION=\"$(OLD_PAGER_NEW_LOCATION)\"" CFLAGS = $(OPTIM) $(DEFS) all: less less: $(OBJ) cc $(OPTIM) -o less $(OBJ) $(LIBS) install: install_man install_less install_man: less.l for f in $(INSTALL_MAN); do rm -f $$f; cp less.l $$f; done touch install_man install_less: less for f in $(INSTALL_LESS); do rm -f $$f; cp less $$f; done touch install_less pager_patch: pager_patch.c cc $(CFLAGS) -s -o pager_patch pager_patch.c install_pager_patch: pager_patch if [ -s $(OLD_PAGER) -a ! -s $(OLD_PAGER_NEW_LOCATION) ]; then \ mv $(OLD_PAGER) $(OLD_PAGER_NEW_LOCATION); \ cp pager_patch $(OLD_PAGER); \ fi touch install_pager_patch $(OBJ): less.h funcs.h lint: lint -hp $(DEFS) $(SRC) newfuncs: mv funcs.h funcs.h.OLD awk -f mkfuncs.awk $(SRC) >funcs.h clean: rm -f $(OBJ) less pager_patch clobber: rm -f *.o less pager_patch install_less install_man install_pager_patch shar: shar -v INSTALLATION less.l makefile.* *.h *.awk $(SRC1) > less.shar.a shar -v $(SRC2) pager_patch.c > less.shar.b SHAR_EOF fi if test -f 'makefile.xen' then echo shar: "will not over-write existing file 'makefile.xen'" else cat << \SHAR_EOF > 'makefile.xen' # Makefile for "less" # # Invoked as: # make all # or make install # Plain "make" is equivalent to "make all". # # If you add or delete functions, remake funcs.h by doing: # make newfuncs # This depends on the coding convention of function headers looking like: # " \t public <function-type> \n <function-name> ( ... ) " # # Also provided: # make lint # Runs "lint" on all the sources. # make clean # Removes "less" and the .o files. # make clobber # Pretty much the same as make "clean". # # make pager_patch # makes PAGER environment variable # make install_pager_patch # catcher and installs it (see below) ########################################################################## # System-specific parameters ########################################################################## # Define XENIX if running under XENIX 3.0 XENIX = 1 # VOID is 1 if your C compiler supports the "void" type, # 0 if it does not. VOID = 1 # off_t is the type which lseek() returns. # It is also the type of lseek()'s second argument. off_t = long # TERMIO is 1 if your system has /usr/include/termio.h. # This is normally the case for System 5. # If TERMIO is 0 your system must have /usr/include/sgtty.h. # This is normally the case for BSD. TERMIO = 1 # SIGSETMASK is 1 if your system has the sigsetmask() call. # This is normally the case only for BSD 4.2, # not for BSD 4.1 or System 5. SIGSETMASK = 0 ########################################################################## # Optional and semi-optional features ########################################################################## # REGCMP is 1 if your system has the regcmp() function. # This is normally the case for System 5. # RECOMP is 1 if your system has the re_comp() function. # This is normally the case for BSD. # If neither is 1, pattern matching is supported, but without metacharacters. REGCMP = 1 RECOMP = 0 # SHELL_ESCAPE is 1 if you wish to allow shell escapes. # (This is possible only if your system supplies the system() function.) SHELL_ESCAPE = 0 # 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. EDITOR = 0 EDIT_PGM = /usr/ucb/vi # parameters to "make install_pager_patch". OLD_PAGER will be moved to # OLD_PAGER_NEW_LOCATION and pager_patch (in this directory) will be installed # as OLD_PAGER. This patch will allow you to set the environment variable # PAGER to specify your personal pager preference (is this a security hole?) OLD_PAGER = /usr/ucb/more OLD_PAGER_NEW_LOCATION = /usr/ucb/More # 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. ONLY_RETURN = 0 ########################################################################## # Compilation environment. ########################################################################## # LIBS is the list of libraries needed. LIBS = -lcurses -ltermlib # INSTALL_LESS is a list of the public versions of less. # INSTALL_MAN is a list of the public versions of the manual page. INSTALL_LESS = /usr/lbin/less INSTALL_MAN = /usr/man/manl/less.l # OPTIM is passed to the compiler and the loader. # It is normally "-O" but may be, for example, "-g". OPTIM = -O ########################################################################## # Files ########################################################################## SRC1 = main.c option.c prim.c SRC2 = ch.c position.c input.c output.c screen.c \ prompt.c line.c signal.c help.c ttyin.c command.c version.c SRC = $(SRC1) $(SRC2) OBJ = main.o option.o prim.o ch.o position.o input.o output.o screen.o \ prompt.o line.o signal.o help.o ttyin.o command.o version.o ########################################################################## # Rules ########################################################################## DEFS = "-DTERMIO=$(TERMIO)" \ "-DSIGSETMASK=$(SIGSETMASK)" \ "-Doff_t=$(off_t)" "-DVOID=$(VOID)" \ "-DREGCMP=$(REGCMP)" "-DRECOMP=$(RECOMP)" \ "-DSHELL_ESCAPE=$(SHELL_ESCAPE)" \ "-DEDITOR=$(EDITOR)" "-DEDIT_PGM=\"$(EDIT_PGM)\"" \ "-DONLY_RETURN=$(ONLY_RETURN)" \ "-DXENIX=$(XENIX)" \ "-DOLD_PAGER_NEW_LOCATION=\"$(OLD_PAGER_NEW_LOCATION)\"" CFLAGS = $(OPTIM) $(DEFS) all: less less: $(OBJ) cc $(OPTIM) -o less $(OBJ) $(LIBS) install: install_man install_less install_man: less.l for f in $(INSTALL_MAN); do rm -f $$f; cp less.l $$f; done touch install_man install_less: less for f in $(INSTALL_LESS); do rm -f $$f; cp less $$f; done touch install_less pager_patch: pager_patch.c cc $(CFLAGS) -s -o pager_patch pager_patch.c install_pager_patch: pager_patch if [ -s $(OLD_PAGER) -a ! -s $(OLD_PAGER_NEW_LOCATION) ]; then \ mv $(OLD_PAGER) $(OLD_PAGER_NEW_LOCATION); \ cp pager_patch $(OLD_PAGER); \ fi touch install_pager_patch $(OBJ): less.h funcs.h lint: lint -hp $(DEFS) $(SRC) newfuncs: mv funcs.h funcs.h.OLD awk -f mkfuncs.awk $(SRC) >funcs.h clean: rm -f $(OBJ) less pager_patch clobber: rm -f *.o less pager_patch install_less install_man install_pager_patch shar: shar -v INSTALLATION less.l makefile.* *.h *.awk $(SRC1) > less.shar.a shar -v $(SRC2) pager_patch.c > less.shar.b SHAR_EOF fi if test -f 'mkfuncs.awk' then echo shar: "will not over-write existing file 'mkfuncs.awk'" else cat << \SHAR_EOF > 'mkfuncs.awk' BEGIN { FS="("; state = 0 } /^ public/ { ftype = $0; state = 1 } { if (state == 1) state = 2 else if (state == 2) { print ftype,$1,"();"; state = 0 } } SHAR_EOF fi if test -f 'n10-diff' then echo shar: "will not over-write existing file 'n10-diff'" else cat << \SHAR_EOF > 'n10-diff' *** n10-old.c Sun May 4 01:45:06 1986 --- n10.c Mon Jul 14 12:27:54 1986 *************** *** 137,151 if(*codep && (esc || lead))move(); esct += w; if(i&074000)xfont = (i>>9) & 03; ! if(*t.bdon & 0377){ ! if(!bdmode && (xfont == 2)){ ! oputs(t.bdon); ! bdmode++; ! } ! if(bdmode && (xfont != 2)){ ! oputs(t.bdoff); ! bdmode = 0; ! } } if(xfont == ulfont){ for(k=w/t.Char;k>0;k--)oput('_'); --- 137,145 ----- if(*codep && (esc || lead))move(); esct += w; if(i&074000)xfont = (i>>9) & 03; ! if(!bdmode && (xfont == 2)){ ! if(*t.bdon & 0377)oputs(t.bdon); ! bdmode++; } if(bdmode && (xfont != 2)){ if(*t.bdoff & 0377)oputs(t.bdoff); *************** *** 147,152 bdmode = 0; } } if(xfont == ulfont){ for(k=w/t.Char;k>0;k--)oput('_'); for(k=w/t.Char;k>0;k--)oput('\b'); --- 141,150 ----- if(*t.bdon & 0377)oputs(t.bdon); bdmode++; } + if(bdmode && (xfont != 2)){ + if(*t.bdoff & 0377)oputs(t.bdoff); + bdmode = 0; + } if(xfont == ulfont){ for(k=w/t.Char;k>0;k--)oput('_'); for(k=w/t.Char;k>0;k--)oput('\b'); *************** *** 158,163 oput(' '); }else{ if(plotmode)oputs(t.plotoff); *obufp++ = *codep++; if(obufp == (obuf + OBUFSZ + ascii - 1))flusho(); /* oput(*codep++);*/ --- 156,162 ----- oput(' '); }else{ if(plotmode)oputs(t.plotoff); + if(obufp >= (obuf + OBUFSZ + ascii - 1 - (bdmode?3:1)))flusho(); *obufp++ = *codep++; if(bdmode && !*t.bdon){ *obufp++ = '\b'; *************** *** 159,165 }else{ if(plotmode)oputs(t.plotoff); *obufp++ = *codep++; ! if(obufp == (obuf + OBUFSZ + ascii - 1))flusho(); /* oput(*codep++);*/ } } --- 158,167 ----- if(plotmode)oputs(t.plotoff); if(obufp >= (obuf + OBUFSZ + ascii - 1 - (bdmode?3:1)))flusho(); *obufp++ = *codep++; ! if(bdmode && !*t.bdon){ ! *obufp++ = '\b'; ! *obufp++ = codep[-1]; ! } /* oput(*codep++);*/ } } SHAR_EOF fi if test -f 'option.c' then echo shar: "will not over-write existing file 'option.c'" else cat << \SHAR_EOF > 'option.c' /* * 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, or toggled via the "-" command. */ #include "less.h" #define toupper(c) ((c)-'a'+'A') /* * 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 NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */ /* * Variables controlled by command line options. */ public int p_nbufs, f_nbufs; /* Number of buffers. There are two values, one used for input from a pipe and the other for input from a file. */ public int clean_data; /* Can we assume the data is "clean"? (That is, free of nulls, etc) */ public int quiet; /* Should we suppress the audible bell? */ public int top_search; /* Should forward searches start at the top of the screen? (alternative is bottom) */ 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 squeeze; /* Squeeze multiple blank lines into one */ public int tabstop; /* Tab settings */ public int back_scroll; /* Repaint screen on backwards movement */ public int twiddle; /* Display "~" for lines after EOF */ extern int nbufs; extern int sc_window; extern char *first_cmd; extern char *every_first_cmd; #define DEF_F_NBUFS 5 /* Default for f_nbufs */ #define DEF_P_NBUFS 12 /* Default for p_nbufs */ static struct option { char oletter; /* The controlling letter (a-z) */ char otype; /* Type of the option */ int odefault; /* Default value */ int *ovar; /* Pointer to the associated variable */ char *odesc[3]; /* Description of each value */ } option[] = { { 'c', BOOL, 0, &clean_data, { "Don't assume data is clean", "Assume data is clean", NULL } }, { 'd', BOOL|NO_TOGGLE, 0, &know_dumb, { NULL, NULL, NULL} }, { 'e', BOOL, 0, &quit_at_eof, { "Don't quit at end-of-file", "Quit at end-of-file", NULL } }, { 'h', NUMBER, -1, &back_scroll, { "Backwards scroll limit is %d lines", NULL, NULL } }, { 'p', BOOL, 0, &top_scroll, { "Repaint by scrolling from bottom of screen", "Repaint by painting from top of screen", NULL } }, { 'x', NUMBER, 8, &tabstop, { "Tab stops every %d spaces", NULL, NULL } }, { 's', BOOL, 0, &squeeze, { "Don't squeeze multiple blank lines", "Squeeze multiple blank lines", NULL } }, { 't', BOOL, 1, &top_search, { "Forward search starts from bottom of screen", "Forward search starts from top of screen", NULL } }, { 'w', BOOL, 1, &twiddle, { "Display nothing for lines after end-of-file", "Display ~ for lines after end-of-file", NULL } }, { 'm', TRIPLE, 0, &pr_type, { "Prompt with a colon", "Prompt with a message", "Prompt with a verbose message" } }, { 'q', TRIPLE, 0, &quiet, { "Ring the bell for errors AND at eof/bof", "Ring the bell for errors but not at eof/bof", "Never ring the bell" } }, { 'u', TRIPLE, 0, &bs_mode, { "Underlined text displayed in underline mode", "All backspaces cause overstrike", "Backspaces print as ^H" } }, { 'z', NUMBER, 24, &sc_window, { "Scroll window size is %d lines", NULL, NULL } }, { '\0' } }; public char all_options[64]; /* List of all valid options */ /* * Initialize each option to its default value. */ public void init_option() { register struct option *o; register char *p; /* * First do special cases, not in option table. */ first_cmd = every_first_cmd = NULL; f_nbufs = DEF_F_NBUFS; /* -bf */ p_nbufs = DEF_P_NBUFS; /* -bp */ p = all_options; *p++ = 'b'; for (o = option; o->oletter != '\0'; o++) { /* * Set each variable to its default. * Also make a list of all options, in "all_options". */ *(o->ovar) = o->odefault; *p++ = o->oletter; if (o->otype & TRIPLE) *p++ = toupper(o->oletter); } *p = '\0'; } /* * Toggle command line flags from within the program. * Used by the "-" command. */ public void toggle_option(c) int c; { register struct option *o; char message[100]; char buf[5]; /* * First check for special cases not handled by the option table. */ switch (c) { case 'b': sprintf(message, "%d buffers", nbufs); error(message); return; } for (o = option; o->oletter != '\0'; o++) { if ((o->otype & BOOL) && (o->oletter == c) && (o->otype & NO_TOGGLE) == 0) { /* * Boolean option: * just toggle it. */ *(o->ovar) = ! *(o->ovar); error(o->odesc[*(o->ovar)]); return; } else if ((o->otype & TRIPLE) && (o->oletter == c) && (o->otype & NO_TOGGLE) == 0) { /* * Triple-valued option with lower case letter: * make it 1 unless already 1, then make it 0. */ *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1; error(o->odesc[*(o->ovar)]); return; } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c) && (o->otype & NO_TOGGLE) == 0) { /* * Triple-valued option with upper case letter: * make it 2 unless already 2, then make it 0. */ *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2; error(o->odesc[*(o->ovar)]); return; } else if ((o->otype & NUMBER) && (o->oletter == c) && (o->otype & NO_TOGGLE) == 0) { sprintf(message, o->odesc[0], *(o->ovar)); error(message); return; } } if (control_char(c)) sprintf(buf, "^%c", carat_char(c)); else sprintf(buf, "%c", c); sprintf(message, "\"-%s\": no such flag. Use one of \"%s\"", buf, all_options); error(message); } /* * Scan an argument (either from command line or from LESS environment * variable) and process it. */ public void scan_option(s) char *s; { register struct option *o; register int c; if (s == NULL) return; next: if (*s == '\0') return; switch (c = *s++) { case '-': case ' ': case '\t': goto next; case '+': if (*s == '+') every_first_cmd = ++s; first_cmd = s; return; case 'b': switch (*s) { case 'f': s++; f_nbufs = getnum(&s, 'b'); break; case 'p': s++; p_nbufs = getnum(&s, 'b'); break; default: f_nbufs = p_nbufs = getnum(&s, 'b'); break; } goto next; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { /* * Handle special "more" compatibility form "-number" * to set the scrolling window size. */ s--; sc_window = getnum(&s, '-'); goto next; } } for (o = option; o->oletter != '\0'; o++) { if ((o->otype & BOOL) && (o->oletter == c)) { *(o->ovar) = ! o->odefault; goto next; } else if ((o->otype & TRIPLE) && (o->oletter == c)) { *(o->ovar) = (o->odefault == 1) ? 0 : 1; goto next; } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c)) { *(o->ovar) = (o->odefault == 2) ? 0 : 2; goto next; } else if ((o->otype & NUMBER) && (o->oletter == c)) { *(o->ovar) = getnum(&s, c); goto next; } } printf("\"-%c\": invalid flag\n", c); exit(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. */ static int getnum(sp, c) char **sp; int c; { register char *s; register int n; s = *sp; if (*s < '0' || *s > '9') { printf("number is required after -%c\n", c); exit(1); } n = 0; while (*s >= '0' && *s <= '9') n = 10 * n + *s++ - '0'; *sp = s; return (n); } SHAR_EOF fi if test -f 'output.c' then echo shar: "will not over-write existing file 'output.c'" else cat << \SHAR_EOF > 'output.c' /* * High level routines dealing with the output to the screen. */ #include "less.h" extern int sigs; extern int sc_width, sc_height; extern int bo_width, be_width; extern int ul_width, ue_width; extern int so_width, se_width; extern int tabstop; extern int twiddle; extern char *line; extern char *first_cmd; /* * Display the line which is in the line buffer. */ public void put_line() { register char *p; register int c; register int column; extern int auto_wrap, ignaw; if (sigs) /* * Don't output if a signal is pending. */ return; if (line == NULL) line = (twiddle) ? "~" : ""; column = 0; for (p = line; *p != '\0'; p++) { switch (c = *p) { case UL_CHAR: ul_enter(); column += ul_width; break; case UE_CHAR: ul_exit(); column += ue_width; break; case BO_CHAR: bo_enter(); column += bo_width; break; case BE_CHAR: bo_exit(); column += be_width; break; case '\t': do { putc(' '); column++; } while ((column % tabstop) != 0); break; case '\b': putbs(); column--; break; default: if (c & 0200) { putc('^'); putc(c & 0177); column += 2; } else { putc(c); column++; } } } if (column < sc_width || !auto_wrap || ignaw) putc('\n'); } /* * Is a given character a "control" character? * {{ ASCII DEPENDENT }} */ public int control_char(c) int c; { return (c < ' ' || c == '\177'); } /* * Return the printable character used to identify a control character * (printed after a carat; e.g. '\3' => "^C"). * {{ ASCII DEPENDENT }} */ public int carat_char(c) int c; { return ((c == '\177') ? '?' : (c | 0100)); } static char obuf[1024]; static char *ob = obuf; /* * Flush buffered output. */ public void flush() { write(1, obuf, ob-obuf); ob = obuf; } /* * Discard buffered output. */ public void dropout() { ob = obuf; } /* * Output a character. */ public void putc(c) int c; { if (ob >= &obuf[sizeof(obuf)]) flush(); *ob++ = c; } /* * Output a string. */ public void puts(s) register char *s; { while (*s != '\0') putc(*s++); } /* * Output a message in the lower left corner of the screen * and wait for carriage return. */ static char return_to_continue[] = " (press RETURN)"; public void error(s) char *s; { register int c; static char buf[2]; lower_left(); clear_eol(); so_enter(); puts(s); puts(return_to_continue); so_exit(); #if ONLY_RETURN while ((c = getc()) != '\n' && c != '\r') bell(); #else c = getc(); if (c != '\n' && c != '\r' && c != ' ') { buf[0] = c; first_cmd = buf; } #endif if (strlen(s) > sc_width) repaint(); } public int error_width() { /* * Don't use the last position, because some terminals * will scroll if you write in the last char of the last line. */ return (sc_width - (sizeof(return_to_continue) + so_width + se_width + 1)); } SHAR_EOF fi if test -f 'pager_patch.c' then echo shar: "will not over-write existing file 'pager_patch.c'" else cat << \SHAR_EOF > 'pager_patch.c' /* * Special interface that checks for the environment variable PAGER. If * present, the program specified is executed, otherwise OLD_PAGER_NEW_LOCATION * (specified below). This program should replace /usr/ucb/more (or whatever * your default pager is) and more should be moved to OLD_PAGER_NEW_LOCATION. * This is essentially a fix for all the programs which *should* check for the * environment variable PAGER, but don't - hopefully it will be obsoleted as * old programs are update to check for PAGER so we can loose the overhead of * reexecuting even this small program ... * * Casey Leedom (lll-crg.arpa!csustan!casey) - 5/29/86 */ #ifndef OLD_PAGER_NEW_LOCATION # define OLD_PAGER_NEW_LOCATION "/usr/ucb/More" #endif !OLD_PAGER_NEW_LOCATION void main(argc, argv) int argc; char **argv; { char *pager, *getenv(); if (!(pager = getenv("PAGER"))) pager = OLD_PAGER_NEW_LOCATION; (void) execv(pager, argv); } SHAR_EOF fi if test -f 'position.c' then echo shar: "will not over-write existing file 'position.c'" else cat << \SHAR_EOF > 'position.c' /* * 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" #define NPOS 100 /* {{ sc_height must be less than NPOS }} */ static POSITION table[NPOS]; /* The position table */ extern int sc_width, sc_height; /* * Return the position of one of: * the top (first) line on the screen * the second line on the screen * the bottom line on the screen * the line after the bottom line on the screen */ public POSITION position(where) int where; { switch (where) { case BOTTOM: where = sc_height - 2; break; case BOTTOM_PLUS_ONE: where = sc_height - 1; break; } return (table[where]); } /* * Add a new file position to the bottom of the position table. */ public void add_forw_pos(pos) POSITION pos; { register int i; /* * Scroll the position table up. */ for (i = 1; i < sc_height; i++) table[i-1] = table[i]; table[sc_height - 1] = pos; } /* * Add a new file position to the top of the position table. */ public void add_back_pos(pos) POSITION pos; { register 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() { register int i; for (i = 0; i < sc_height; i++) table[i] = NULL_POSITION; } /* * See if the byte at a specified position is currently on the screen. * Check the position table to see if the position falls within its range. * Return the position table entry if found, -1 if not. */ public int onscreen(pos) POSITION pos; { register int i; if (pos < table[0]) return (-1); for (i = 1; i < sc_height; i++) if (pos < table[i]) return (i-1); return (-1); } SHAR_EOF fi if test -f 'position.h' then echo shar: "will not over-write existing file 'position.h'" else cat << \SHAR_EOF > 'position.h' /* * Include file for interfacing to position.c modules. */ #define TOP 0 #define TOP_PLUS_ONE 1 #define BOTTOM -1 #define BOTTOM_PLUS_ONE -2 SHAR_EOF fi if test -f 'prim.c' then echo shar: "will not over-write existing file 'prim.c'" else cat << \SHAR_EOF > 'prim.c' /* * Primitives for displaying the file on the screen. */ #include "less.h" #include "position.h" public int hit_eof; /* Keeps track of how many times we hit end of file */ extern int quiet; extern int top_search; extern int top_scroll; extern int back_scroll; extern int sc_width, sc_height; extern int sigs; extern char *line; extern char *first_cmd; /* * Sound the bell to indicate he is trying to move past end of file. */ static void eof_bell() { if (quiet == NOT_QUIET) bell(); else vbell(); } /* * Check to see if the end of file is currently "displayed". */ static void eof_check() { POSITION pos; /* * 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); if (pos == NULL_POSITION || pos == ch_length()) hit_eof++; } /* * 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. */ static void forw(n, pos, force, only_last) register int n; POSITION pos; int force; int only_last; { int eof = 0; int nlines = 0; int repaint_flag; /* * repaint_flag tells us not to display anything till the end, * then just repaint the entire screen. */ repaint_flag = (only_last && n > sc_height-1); if (!repaint_flag) { if (top_scroll && n >= sc_height - 1) { /* * 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 know if that will happen now. }} */ clear(); home(); force = 1; } else { lower_left(); clear_eol(); } if (pos != position(BOTTOM_PLUS_ONE)) { /* * 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 { puts("...skipping...\n"); } } } while (--n >= 0) { /* * Read the next line of input. */ pos = forw_line(pos); if (pos == NULL_POSITION) { /* * End of file: stop here unless the top line * is still empty, or "force" is true. */ eof = 1; if (!force && position(TOP) != NULL_POSITION) break; line = NULL; } /* * Add the position of the next line to the position table. * Display the current line on the screen. */ add_forw_pos(pos); nlines++; if (!repaint_flag) put_line(); } if (eof) hit_eof++; else eof_check(); if (nlines == 0) eof_bell(); else if (repaint_flag) repaint(); } /* * Display n lines, scrolling backward. */ static void back(n, pos, force, only_last) register int n; POSITION pos; int force; int only_last; { int nlines = 0; int repaint_flag; repaint_flag = (n > back_scroll || (only_last && n > sc_height-1)); hit_eof = 0; while (--n >= 0) { /* * Get the previous line of input. */ pos = back_line(pos); if (pos == NULL_POSITION) { /* * Beginning of file: stop here unless "force" is true. */ if (!force) break; line = NULL; } /* * Add the position of the previous line to the position table. * Display the line on the screen. */ add_back_pos(pos); nlines++; if (!repaint_flag) { home(); add_line(); put_line(); } } eof_check(); if (nlines == 0) eof_bell(); else if (repaint_flag) repaint(); } /* * Display n more lines, forward. * Start just after the line currently displayed at the bottom of the screen. */ public void forward(n, only_last) int n; int only_last; { POSITION pos; pos = position(BOTTOM_PLUS_ONE); if (pos == NULL_POSITION) { eof_bell(); hit_eof++; return; } forw(n, pos, 0, only_last); } /* * Display n more lines, backward. * Start just before the line currently displayed at the top of the screen. */ public void backward(n, only_last) int n; int only_last; { POSITION pos; pos = position(TOP); if (pos == NULL_POSITION) { /* * This will almost never happen, * because the top line is almost never empty. */ eof_bell(); return; } back(n, pos, 0, only_last); } /* * Repaint the screen, starting from a specified position. */ static void prepaint(pos) POSITION pos; { hit_eof = 0; forw(sc_height-1, pos, 0, 0); } /* * Repaint the screen. */ public void repaint() { /* * Start at the line currently at the top of the screen * and redisplay the screen. */ prepaint(position(TOP)); } /* * Jump to the end of the file. * It is more convenient to paint the screen backward, * from the end of the file toward the beginning. */ public void jump_forw() { POSITION pos; if (ch_end_seek()) { error("Cannot seek to end of file"); return; } pos = ch_tell(); clear(); pos_clear(); add_back_pos(pos); back(sc_height - 1, pos, 0, 0); } /* * Jump to line n in the file. */ public void jump_back(n) register int n; { register int c; /* * This is done the slow way, by starting at the beginning * of the file and counting newlines. */ if (ch_seek((POSITION)0)) { /* * Probably a pipe with beginning of file no longer buffered. */ error("Cannot get to beginning of file"); return; } /* * Start counting lines. */ while (--n > 0) { while ((c = ch_forw_get()) != '\n') if (c == EOF) { error("File is not that long"); /* {{ Maybe tell him how long it is? }} */ return; } } /* * Finally found the place to start. * Clear and redisplay the screen from there. * * {{ We *could* figure out if the new position is * close enough to just scroll there without clearing * the screen, but it's not worth it. }} */ prepaint(ch_tell()); } /* * Jump to a specified percentage into the file. * This is a poor compensation for not being able to * quickly jump to a specific line number. */ public void jump_percent(percent) int percent; { POSITION pos, len; /* * Determine the position in the file * (the specified percentage of the file's length). */ if ((len = ch_length()) == NULL_POSITION) { error("Don't know length of file"); return; } pos = (percent * len) / 100; jump_loc(pos); } public void jump_loc(pos) POSITION pos; { register int c; register int nline; POSITION tpos; /* * See if the desired line is BEFORE the currently * displayed screen. If so, see if it is close enough * to scroll backwards to it. */ tpos = position(TOP); if (pos < tpos) { for (nline = 1; nline <= back_scroll; nline++) { tpos = back_line(tpos); if (tpos == NULL_POSITION || tpos <= pos) { back(nline, position(TOP), 1, 0); return; } } } else if ((nline = onscreen(pos)) >= 0) { /* * The line is currently displayed. * Just scroll there. */ forw(nline, position(BOTTOM_PLUS_ONE), 1, 0); return; } /* * Line is not on screen. * Back up to the beginning of the current line. */ if (ch_seek(pos)) { error("Cannot seek to that position"); return; } while ((c = ch_back_get()) != '\n' && c != EOF) ; if (c == '\n') (void) ch_forw_get(); /* * Clear and paint the screen. */ prepaint(ch_tell()); } /* * The table of marks. * A mark is simply a position in the file. */ static POSITION marks[26]; /* * Initialize the mark table to show no marks are set. */ public void init_mark() { int i; for (i = 0; i < 26; i++) marks[i] = NULL_POSITION; } /* * See if a mark letter is valid (between a and z). */ static int badmark(c) int c; { if (c < 'a' || c > 'z') { error("Choose a letter between 'a' and 'z'"); return (1); } return (0); } /* * Set a mark. */ public void setmark(c) int c; { if (badmark(c)) return; marks[c-'a'] = position(TOP); } /* * Go to a previously set mark. */ public void gomark(c) int c; { POSITION pos; if (badmark(c)) return; if ((pos = marks[c-'a']) == NULL_POSITION) error("mark not set"); else jump_loc(pos); } /* * Search for the n-th occurence of a specified pattern, * either forward (direction == '/'), or backwards (direction == '?'). */ public void search(direction, pattern, n) int direction; char *pattern; register int n; { register int search_forward = (direction == '/'); POSITION pos, linepos; #if RECOMP char *re_comp(); char *errmsg; /* * (re_comp handles a null pattern internally, * so there is no need to check for a null pattern here.) */ if ((errmsg = re_comp(pattern)) != NULL) { error(errmsg); return; } #else #if REGCMP char *regcmp(); static char *cpattern = NULL; if (pattern == NULL || *pattern == '\0') { /* * A null pattern means use the previous pattern. * The compiled previous pattern is in cpattern, so just use it. */ if (cpattern == NULL) { error("No previous regular expression"); return; } } else { /* * Otherwise compile the given pattern. */ char *s; if ((s = regcmp(pattern, 0)) == NULL) { error("Invalid pattern"); return; } if (cpattern != NULL) free(cpattern); cpattern = s; } #else static char lpbuf[100]; static char *last_pattern = NULL; if (pattern == NULL || *pattern == '\0') { /* * Null pattern means use the previous pattern. */ if (last_pattern == NULL) { error("No previous regular expression"); return; } pattern = last_pattern; } else { strcpy(lpbuf, pattern); last_pattern = lpbuf; } #endif #endif /* * Figure out where to start the search. */ if (position(TOP) == NULL_POSITION) { /* * Nothing is currently displayed. * Start at the beginning of the file. * (This case is mainly for first_cmd searches, * for example, "+/xyz" on the command line.) */ pos = (POSITION)0; } else if (!search_forward) { /* * Backward search: start just before the top line * displayed on the screen. */ pos = position(TOP); } else if (top_search) { /* * Forward search and "start from top". * Start at the second line displayed on the screen. */ pos = position(TOP_PLUS_ONE); } else { /* * Forward search but don't "start from top". * Start just after the bottom line displayed on the screen. */ pos = position(BOTTOM_PLUS_ONE); } if (pos == NULL_POSITION) { /* * Can't find anyplace to start searching from. */ error("Nothing to search"); return; } for (;;) { /* * Get lines until we find a matching one or * until we hit end-of-file (or beginning-of-file * if we're going backwards). */ if (sigs) /* * A signal aborts the search. */ return; if (search_forward) { /* * Read the next line, and save the * starting position of that line in linepos. */ linepos = pos; pos = forw_raw_line(pos); } else { /* * Read the previous line and save the * starting position of that line in linepos. */ pos = back_raw_line(pos); linepos = pos; } if (pos == NULL_POSITION) { /* * We hit EOF/BOF without a match. */ error("Pattern not found"); return; } /* * Test the next line to see if we have a match. * This is done in a variety of ways, depending * on what pattern matching functions are available. */ #if REGCMP if ( (regex(cpattern, line) != NULL) #else #if RECOMP if ( (re_exec(line) == 1) #else if ( (match(pattern, line)) #endif #endif && (--n <= 0) ) /* * Found the matching line. */ break; } jump_loc(linepos); } #if (!REGCMP) && (!RECOMP) /* * We have neither regcmp() nor re_comp(). * We use this function to do simple pattern matching. * It supports no metacharacters like *, etc. */ static int match(pattern, buf) char *pattern, *buf; { register char *pp, *lp; for ( ; *buf != '\0'; buf++) { for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) if (*pp == '\0' || *lp == '\0') break; if (*pp == '\0') return (1); } return (0); } #endif SHAR_EOF fi if test -f 'prompt.c' then echo shar: "will not over-write existing file 'prompt.c'" else cat << \SHAR_EOF > 'prompt.c' /* * Prompting and other messages. * There are three flavors of prompts, SHORT, MEDIUM and LONG, * selected by the -m/-M options. * A prompt is either a colon or 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 ispipe; extern int hit_eof; extern int new_file; extern int sc_width; extern char current_file[]; extern int ac; extern char **av; extern int curr_ac; static char message[500]; /* * Append the name of the current file (to the message buffer). */ static void ap_filename() { if (!ispipe) sprintf(message + strlen(message), "%s", current_file); } /* * Append the "file N of M" message. */ static void ap_of() { if (ac > 1) sprintf(message + strlen(message), " (file %d of %d)", curr_ac+1, ac); } /* * Append the byte offset into the current file. */ static void ap_byte() { POSITION pos, len; pos = position(BOTTOM_PLUS_ONE); if (pos != NULL_POSITION) { sprintf(message + strlen(message), " byte %ld", pos); len = ch_length(); if (len > 0) sprintf(message + strlen(message), "/%ld", len); } } /* * Append the percentage into the current file. * If we cannot find the percentage and must_print is true, * the use the byte offset. */ static void ap_percent(must_print) { POSITION pos,len; pos = position(BOTTOM_PLUS_ONE); len = ch_length(); if (len > 0 && pos != NULL_POSITION) sprintf(message + strlen(message), " (%ld%%)", (100 * pos) / len); else if (must_print) ap_byte(); } /* * Append the end-of-file message. */ static void ap_eof() { strcat(message, " END"); if (curr_ac + 1 < ac) sprintf(message + strlen(message), " - Next: %s", av[curr_ac+1]); } /* * Return a message suitable for printing by the "=" command. */ public char * eq_message() { message[0] = '\0'; ap_filename(); ap_of(); ap_byte(); ap_percent(0); /* * Truncate to the screen width. * {{ This isn't very nice. }} */ message[error_width()] = '\0'; return (message); } /* * 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() { message[0] = '\0'; switch (pr_type) { case PR_SHORT: if (new_file) { ap_filename(); ap_of(); } if (hit_eof) ap_eof(); break; case PR_MEDIUM: if (new_file) { ap_filename(); ap_of(); } if (hit_eof) ap_eof(); else ap_percent(1); break; case PR_LONG: ap_filename(); if (new_file) ap_of(); ap_byte(); if (hit_eof) ap_eof(); else ap_percent(0); break; } new_file = 0; if (message[0] == '\0') return (NULL); /* * Truncate to the screen width. * {{ This isn't very nice. }} */ message[sc_width-2] = '\0'; return (message); } SHAR_EOF fi if test -f 'screen.c' then echo shar: "will not over-write existing file 'screen.c'" else cat << \SHAR_EOF > 'screen.c' /* * Routines which deal with the characteristics of the terminal. * Uses termcap to be as terminal-independent as possible. * * {{ Someday this should be rewritten to use curses. }} */ #include "less.h" #if XENIX #include <sys/types.h> #include <sys/ioctl.h> #endif #if TERMIO #include <termio.h> #else #include <sgtty.h> #endif /* * Strings passed to tputs() to do various terminal functions. */ static char *sc_pad, /* Pad string */ *sc_home, /* Cursor home */ *sc_addline, /* Add line, scroll down following lines */ *sc_lower_left, /* Cursor to last line, first column */ *sc_move, /* General cursor positioning */ *sc_clear, /* Clear screen */ *sc_eol_clear, /* Clear to end of line */ *sc_s_in, /* Enter standout (highlighted) mode */ *sc_s_out, /* Exit standout mode */ *sc_u_in, /* Enter underline mode */ *sc_u_out, /* Exit underline mode */ *sc_b_in, /* Enter bold mode */ *sc_b_out, /* Exit bold mode */ *sc_visual_bell, /* Visual bell (flash screen) sequence */ *sc_backspace, /* Backspace cursor */ *sc_init, /* Startup terminal initialization */ *sc_deinit; /* Exit terminal de-intialization */ static int dumb; static int hard; public int auto_wrap; /* Terminal does \r\n when write past margin */ public int ignaw; /* Terminal ignores \n immediately after wrap */ public int erase_char, kill_char; /* The user's erase and line-kill chars */ public int sc_width, sc_height; /* Height & width of screen */ public int sc_window = -1; /* window size for forward and backward */ public int bo_width, be_width; /* Printing width of boldface sequences */ public int ul_width, ue_width; /* Printing width of underline sequences */ public int so_width, se_width; /* Printing width of standout sequences */ /* * These two variables are sometimes defined in, * and needed by, the termcap library. * It may be necessary on some systems to declare them extern here. */ /*extern*/ short ospeed; /* Terminal output baud rate */ /*extern*/ char PC; /* Pad character */ extern int quiet; /* If VERY_QUIET, use visual bell for bell */ extern int know_dumb; /* Don't complain about a dumb terminal */ extern int back_scroll; char *tgetstr(); char *tgoto(); /* * Change terminal to "raw mode", or restore to "normal" mode. * "Raw mode" means * 1. An outstanding read will complete on receipt of a single keystroke. * 2. Input is not echoed. * 3. On output, \n is mapped to \r\n. * 4. \t is NOT be expanded into spaces. * 5. Signal-causing characters such as ctrl-C (interrupt), * etc. are NOT disabled. * It doesn't matter whether an input \n is mapped to \r, or vice versa. */ public void raw_mode(on) int on; { #if TERMIO struct termio s; static struct termio save_term; if (on) { /* * Get terminal modes. */ ioctl(2, TCGETA, &s); /* * Save modes and set certain variables dependent on modes. */ save_term = s; ospeed = s.c_cflag & CBAUD; erase_char = s.c_cc[VERASE]; kill_char = s.c_cc[VKILL]; /* * Set the modes to the way we want them. */ s.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL); s.c_oflag |= (OPOST|ONLCR|TAB3); s.c_oflag &= ~(OCRNL|ONOCR|ONLRET); s.c_cc[VMIN] = 1; s.c_cc[VTIME] = 0; } else { /* * Restore saved modes. */ s = save_term; } ioctl(2, TCSETAW, &s); #else struct sgttyb s; static struct sgttyb save_term; if (on) { /* * Get terminal modes. */ ioctl(2, TIOCGETP, &s); /* * Save modes and set certain variables dependent on modes. */ save_term = s; ospeed = s.sg_ospeed; erase_char = s.sg_erase; kill_char = s.sg_kill; /* * Set the modes to the way we want them. */ s.sg_flags |= CBREAK; s.sg_flags &= ~(ECHO|XTABS); } else { /* * Restore saved modes. */ s = save_term; } ioctl(2, TIOCSETN, &s); #endif } static int couldnt = 0; static void cannot(s) char *s; { if (know_dumb) /* * He knows he has a dumb terminal, so don't tell him. */ return; printf("WARNING: terminal cannot \"%s\"\n", s); couldnt = 1; } /* * Get terminal capabilities via termcap. */ public void get_term() { char termbuf[1024]; char *sp; static char sbuf[150]; char *getenv(); /* * Find out what kind of terminal this is. */ if (tgetent(termbuf, getenv("TERM")) <= 0) dumb = 1; /* * Get size of the screen. */ if (dumb || (sc_height = tgetnum("li")) < 0 || tgetflag("hc")) { /* Oh no, this is a hardcopy terminal. */ hard = 1; sc_height = 24; } /* * This is terrible - the following if "knows" that it is being * executed *after* command line and environment options have * already been parsed. Should it be executed in the main program * instead? */ if ((sc_window <= 0) || (sc_window >= sc_height)) sc_window = sc_height-1; if (dumb || (sc_width = tgetnum("co")) < 0) sc_width = 80; auto_wrap = tgetflag("am"); ignaw = tgetflag("xn"); /* * Assumes termcap variable "sg" is the printing width of * the standout sequence, the end standout sequence, * the underline sequence, the end underline sequence, * the boldface sequence, and the end boldface sequence. */ if ((so_width = tgetnum("sg")) < 0) so_width = 0; be_width = bo_width = ue_width = ul_width = se_width = so_width; /* * Get various string-valued capabilities. */ sp = sbuf; sc_pad = (dumb) ? NULL : tgetstr("pc", &sp); if (sc_pad != NULL) PC = *sc_pad; sc_init = (dumb) ? NULL : tgetstr("ti", &sp); if (sc_init == NULL) sc_init = ""; sc_deinit= (dumb) ? NULL : tgetstr("te", &sp); if (sc_deinit == NULL) sc_deinit = ""; sc_eol_clear = (dumb) ? NULL : tgetstr("ce", &sp); if (hard || sc_eol_clear == NULL || *sc_eol_clear == '\0') { cannot("clear to end of line"); sc_eol_clear = ""; } sc_clear = (dumb) ? NULL : tgetstr("cl", &sp); if (hard || sc_clear == NULL || *sc_clear == '\0') { cannot("clear screen"); sc_clear = "\n\n"; } sc_move = (dumb) ? NULL : tgetstr("cm", &sp); if (hard || sc_move == NULL || *sc_move == '\0') { /* * This is not an error here, because we don't * always need sc_move. * We need it only if we don't have home or lower-left. */ sc_move = ""; } sc_s_in = (dumb) ? NULL : tgetstr("so", &sp); if (hard || sc_s_in == NULL) sc_s_in = ""; sc_s_out = (dumb) ? NULL : tgetstr("se", &sp); if (hard || sc_s_out == NULL) sc_s_out = ""; sc_u_in = (dumb) ? NULL : tgetstr("us", &sp); if (hard || sc_u_in == NULL) sc_u_in = sc_s_in; sc_u_out = (dumb) ? NULL : tgetstr("ue", &sp); if (hard || sc_u_out == NULL) sc_u_out = sc_s_out; sc_b_in = (dumb) ? NULL : tgetstr("md", &sp); if (hard || sc_b_in == NULL) { sc_b_in = sc_s_in; sc_b_out = sc_s_out; } else { sc_b_out = (dumb) ? NULL : tgetstr("me", &sp); if (hard || sc_b_out == NULL) sc_b_out = ""; } sc_visual_bell = (dumb) ? NULL : tgetstr("vb", &sp); if (hard || sc_visual_bell == NULL) sc_visual_bell = ""; sc_home = (dumb) ? NULL : tgetstr("ho", &sp); if (hard || sc_home == NULL || *sc_home == '\0') { if (*sc_move == '\0') { cannot("home cursor"); /* * This last resort for sc_home is supposed to * be an up-arrow suggesting moving to the * top of the "virtual screen". (The one in * your imagination as you try to use this on * a hard copy terminal.) */ sc_home = "|\b^"; } else { /* * No "home" string, * but we can use "move(0,0)". */ strcpy(sp, tgoto(sc_move, 0, 0)); sc_home = sp; sp += strlen(sp) + 1; } } sc_lower_left = (dumb) ? NULL : tgetstr("ll", &sp); if (hard || sc_lower_left == NULL || *sc_lower_left == '\0') { if (*sc_move == '\0') { cannot("move cursor to lower left of screen"); sc_lower_left = "\r"; } else { /* * No "lower-left" string, * but we can use "move(0,last-line)". */ strcpy(sp, tgoto(sc_move, 0, sc_height-1)); sc_lower_left = sp; sp += strlen(sp) + 1; } } /* * To add a line at top of screen and scroll the display down, * we use "al" (add line) or "sr" (scroll reverse). */ if (dumb) sc_addline = NULL; else if ((sc_addline = tgetstr("al", &sp)) == NULL || *sc_addline == '\0') sc_addline = tgetstr("sr", &sp); if (hard || sc_addline == NULL || *sc_addline == '\0') { cannot("scroll backwards"); sc_addline = ""; /* Force repaint on any backward movement */ back_scroll = 0; } if (dumb || tgetflag("bs")) sc_backspace = "\b"; else { sc_backspace = tgetstr("bc", &sp); if (sc_backspace == NULL || *sc_backspace == '\0') sc_backspace = "\b"; } if (couldnt) /* Give him time to read all the "cannot" messages. */ error(""); } /* * Below are the functions which perform all the * terminal-specific screen manipulation. */ /* * Initialize terminal */ public void init() { tputs(sc_init, sc_height, putc); } /* * Deinitialize terminal */ public void deinit() { tputs(sc_deinit, sc_height, putc); } /* * Home cursor (move to upper left corner of screen). */ public void home() { tputs(sc_home, 1, putc); } /* * Add a blank line (called with cursor at home). * Should scroll the display down. */ public void add_line() { tputs(sc_addline, sc_height, putc); } /* * Move cursor to lower left corner of screen. */ public void lower_left() { tputs(sc_lower_left, 1, putc); } /* * Ring the terminal bell. */ public void bell() { if (quiet == VERY_QUIET) vbell(); else putc('\7'); } /* * Output the "visual bell", if there is one. */ public void vbell() { if (*sc_visual_bell == '\0') return; tputs(sc_visual_bell, sc_height, putc); } /* * Clear the screen. */ public void clear() { tputs(sc_clear, sc_height, putc); } /* * Clear from the cursor to the end of the cursor's line. * {{ This must not move the cursor. }} */ public void clear_eol() { tputs(sc_eol_clear, 1, putc); } /* * Begin "standout" */ public void so_enter() { tputs(sc_s_in, 1, putc); } /* * End "standout". */ public void so_exit() { tputs(sc_s_out, 1, putc); } /* * Begin "underline" (hopefully real underlining, * otherwise whatever the terminal provides). */ public void ul_enter() { tputs(sc_u_in, 1, putc); } /* * End "underline". */ public void ul_exit() { tputs(sc_u_out, 1, putc); } /* * Begin "bold" */ public void bo_enter() { tputs(sc_b_in, 1, putc); } /* * End "bold". */ public void bo_exit() { tputs(sc_b_out, 1, putc); } /* * Erase the character to the left of the cursor * and move the cursor left. */ public void backspace() { /* * Try to erase the previous character by overstriking with a space. */ tputs(sc_backspace, 1, putc); putc(' '); tputs(sc_backspace, 1, putc); } /* * Output a plain backspace, without erasing the previous char. */ public void putbs() { tputs(sc_backspace, 1, putc); } SHAR_EOF fi if test -f 'signal.c' then echo shar: "will not over-write existing file 'signal.c'" else cat << \SHAR_EOF > 'signal.c' /* * 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(). * An exception is made if we are reading from the keyboard when the * signal is received. Some operating systems will simply call the * signal handler and NOT return from the read (with EINTR). * To handle this case, we service the interrupt directly from * the handler if we are reading from the keyboard. */ #include "less.h" #include <signal.h> #include <setjmp.h> /* * The type of signal handler functions. * Usually int, although it should be void. */ typedef int HANDLER; /* * "sigs" contains bits indicating signals which need to be processed. */ public int sigs; #define S_INTERRUPT 01 #ifdef SIGTSTP #define S_STOP 02 #endif extern int reading; extern char *first_cmd; extern jmp_buf main_loop; /* * Interrupt signal handler. */ static HANDLER interrupt() { SIGNAL(SIGINT, interrupt); sigs |= S_INTERRUPT; if (reading) psignals(); } #ifdef SIGTSTP /* * "Stop" (^Z) signal handler. */ static HANDLER stop() { SIGNAL(SIGTSTP, stop); sigs |= S_STOP; if (reading) psignals(); } #endif /* * Set up the signal handlers. */ public void init_signals() { (void) SIGNAL(SIGINT, interrupt); #ifdef SIGTSTP (void) SIGNAL(SIGTSTP, stop); #endif } /* * Process any signals we have recieved. * A received signal cause a bit to be set in "sigs". */ public void psignals() { register int tsignals; tsignals = sigs; sigs = 0; if (tsignals == 0) return; dropout(); /* Discard any buffered output */ #ifdef SIGTSTP if (tsignals & S_STOP) { /* * Clean up the terminal. */ #ifdef SIGTTOU SIGNAL(SIGTTOU, SIG_IGN); #endif lower_left(); clear_eol(); flush(); raw_mode(0); #ifdef SIGTTOU SIGNAL(SIGTTOU, SIG_DFL); #endif SIGNAL(SIGTSTP, SIG_DFL); #if SIGSETMASK /* * This system will not allow us to send a * stop signal (SIGTSTP) to ourself * while we are in the signal handler, like maybe now. * (This can be the case if we are reading; see comment above.) * So we ask the silly system for permission to do so. */ sigsetmask(0); #endif 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. */ SIGNAL(SIGTSTP, stop); raw_mode(1); first_cmd = "r"; longjmp(main_loop, 1); } #endif if (tsignals & S_INTERRUPT) { bell(); /* * {{ You may wish to replace the bell() with * error("Interrupt"); }} */ } longjmp(main_loop, 1); } /* * Pass the specified command to a shell to be executed. * Like plain "system()", but handles resetting terminal modes, etc. */ public void lsystem(cmd) char *cmd; { int inp; /* * Print the command which is to be executed. */ lower_left(); clear_eol(); puts("!"); puts(cmd); puts("\n"); /* * De-initialize the terminal and take out of raw mode. */ deinit(); flush(); raw_mode(0); /* * Restore signals to their defaults. */ SIGNAL(SIGINT, SIG_DFL); #ifdef SIGTSTP SIGNAL(SIGTSTP, SIG_DFL); #endif /* * Pass the command to the system to be executed. */ inp = dup(0); close(0); open("/dev/tty", 0); system(cmd); close(0); dup(inp); close(inp); /* * Reset signals, raw mode, etc. */ init_signals(); raw_mode(1); init(); } SHAR_EOF fi if test -f 'ttyin.c' then echo shar: "will not over-write existing file 'ttyin.c'" else cat << \SHAR_EOF > 'ttyin.c' /* * Routines dealing with getting input from the keyboard (i.e. from the user). */ #include "less.h" /* * The boolean "reading" is set true or false according to whether * we are currently reading from the keyboard. * This information is used by the signal handling stuff in signal.c. * {{ There are probably some race conditions here * involving the variable "reading". }} */ public int reading; static int tty; /* * Open keyboard for input. * (Just use file descriptor 2.) */ public void open_getc() { tty = 2; } /* * Get a character from the keyboard. */ public int getc() { char c; int result; reading = 1; do { flush(); result = read(tty, &c, 1); } while (result != 1); reading = 0; return (c & 0177); } SHAR_EOF fi if test -f 'version.c' then echo shar: "will not over-write existing file 'version.c'" else cat << \SHAR_EOF > 'version.c' /* * less * Copyright (c) 1984,1985 Mark Nudelman * * This program may be freely used and/or modified, * with the following provisions: * 1. This notice and the above copyright notice must remain intact. * 2. Neither this program, nor any modification of it, * may not be sold for profit without written consent of the author. * * ----------------------------------------------------------------- * * This program is a paginator similar to "more", * but allows you to move both forward and backward in the file. * Commands are based on "more" and "vi". * * ----------------------- CHANGES --------------------------------- * * Allowed use on standard input 1/29/84 markn * Added E, N, P commands 2/1/84 markn * Added '=' command, 'stop' signal handling 4/17/84 markn * Added line folding 4/20/84 markn * v2: Fixed '=' command to use BOTTOM_PLUS_ONE, * instead of TOP, added 'p' & 'v' commands 4/27/84 markn * v3: Added -m and -t options, '-' command 5/3/84 markn * v4: Added LESS environment variable 5/3/84 markn * v5: New comments, fixed '-' command slightly 5/3/84 markn * v6: Added -Q, visual bell 5/15/84 markn * v7: Fixed jump_back(n) bug: n should count real * lines, not folded lines. Also allow number * on G command. 5/24/84 markn * v8: Re-do -q and -Q commands 5/30/84 markn * v9: Added "+<cmd>" argument 9/25/84 markn * v10: Fixed bug in -b<n> argument processing 10/10/84 markn * v11: Made error() ring bell if \n not entered. 10/18/84 markn * ----------------------------------------------------------------- * v12: Reorganized signal handling and made * portable to 4.2bsd. 2/13/85 mark * v13: Reword error message for '-' command. 2/16/85 mark * v14: Added -bf and -bp variants of -b. 2/22/85 mark * v15: Miscellaneous changes. 2/25/85 mark * v16: Added -u flag for backspace processing. 3/13/85 mark * v17: Added j and k commands, * changed -t default. 4/13/85 mark * v18: Rewrote signal handling code. 4/20/85 mark * v19: Got rid of "verbose" eq_message(). 5/2/85 mark * Made search() scroll in some cases. * v20: Fixed screen.c ioctls for System V. 5/21/85 mark * v21: Fixed some first_cmd bugs. 5/23/85 mark * v22: Added support for no RECOMP nor REGCMP. 5/24/85 mark * v23: Miscellanous changes and prettying up. 5/25/85 mark * v24: Added ti,te terminal init & de-init 6/3/85 Mike Kersenbrock * v25: Added -U flag, standout mode underlining. 6/8/85 mark * v26: Added -M flag. 6/9/85 mark * Use underline termcap (us) if it exists. * v27: Renamed some variables to make unique in 6/15/85 mark * 6 chars. Minor fix to -m. * v28: Fixed right margin bug. 6/28/85 mark * v29: Incorporated M.Rose's changes to signal.c 6/28/85 mark * v30: Fixed stupid bug in argument processing. 6/29/85 mark * v31: Added -p flag, changed repaint algorithm. 7/15/85 mark * Added kludge for magic cookie terminals. * v32: Added cat_file if output not a tty. 7/16/85 mark * v33: Added -e flag and EDITOR. 7/23/85 mark * v34: Added -s flag. 7/26/85 mark * v35: Rewrote option handling; added option.c. 7/27/85 mark * v36: Fixed -e flag to work if not last file. 7/29/85 mark * v37: Added -x flag. 8/10/85 mark * v38: Changed prompting; created prompt.c. 8/19/85 mark * v39: (Not -p) does not initially clear screen. 8/24/85 mark * v40: Added "skipping" indicator in forw(). 8/26/85 mark * v41: ONLY_RETURN, control char commands, 9/17/85 mark * faster search, other minor fixes. * v42: Added ++ command line syntax; 9/25/85 mark * ch_fsize for pipes. * v43: Added -h flag, changed prim.c algorithms. 10/15/85 mark * v44: Made END print in all cases of eof; 10/16/85 mark * ignore SIGTTOU after receiving SIGTSTP. * v45: Never print backspaces unless -u. 10/16/85 mark * v46: Backwards scroll in jump_loc. 10/24/85 mark * v47: Fixed bug in edit(): *first_cmd==0 10/30/85 mark * v48: Use TIOCSETN instead of TIOCSETP. 11/16/85 mark * Added marks (m and ' commands). * ----------------------------------------------------------------- */ char version[] = "@(#) less version 48"; SHAR_EOF fi exit 0 # End of shell archive