Path: utzoo!mnetor!uunet!lll-winken!lll-tis!ames!mailrus!umix!umich!mibte!gamma!pyuxp!lcuxb!lcuxa!mike2 From: mike2@lcuxa.UUCP (M S Slomin) Newsgroups: comp.binaries.ibm.pc Subject: Less for DOS (source 2 of 3) Message-ID: <199@lcuxa.UUCP> Date: 22 Apr 88 18:19:06 GMT Organization: Bell Communications Research Lines: 2219 Keywords: Less ------------------Part 2 of 3--------------------------- #! /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 the files: # # main.c # option.c # output.c # position.c # position.h # prim.c # prompt.c # ttyin.c # version.c # # Created on 'date' # if test -f 'main.c' then echo shar: will not over-write existing file "'main.c'" else echo extracting "'main.c'" sed 's/^X//' >main.c <<'SHAR_EOF' X/* X * Entry point, initialization, miscellaneous routines. X */ X X#include "less.h" X#include "position.h" X#ifdef MSDOS X#ifdef MSC X#include /* needed to open file in untranslated mode */ X#endif X#endif X#include X Xextern unsigned _stklen = 4096; /* TurboC ver. 1.5 stack adjuster */ X Xpublic int ispipe; Xpublic char * first_cmd; Xpublic char * every_first_cmd; Xpublic int new_file; Xpublic int is_tty; Xpublic char current_file[128]; Xpublic int ac; Xpublic char **av; Xpublic int curr_ac; X#if EDITOR Xpublic char * editor; X#endif X Xextern int onintr(); Xextern int file; Xextern int nbufs; Xextern int sigs; Xextern int quit_at_eof; Xextern int p_nbufs, f_nbufs; Xextern int back_scroll; Xextern int top_scroll; Xextern int sc_height; X X X/* X * Edit a new file. X * Filename "-" means standard input. X * No filename means the "current" file, from the command line. X */ X public void Xedit(filename) X char *filename; X{ X register int f; X char message[100]; X static int any_edited = 0; X static int hold_scroll = 0; X X if (filename == NULL || *filename == '\0') X { X if (curr_ac >= ac) X { X error("No current file"); X return; X } X filename = av[curr_ac]; X } X if (strcmp(filename, "-") == 0) X f = 0; /* Standard input */ X#ifdef MSDOS X#ifdef MSC X else if ((f = open(filename, O_BINARY)) < 0) X /* untranslated mode */ X /* needed for MSDOS so that cr-lf translations do not */ X /* cause problems in the position calculations */ X#else X else if ((f = open(filename, 0)) < 0) X#endif X#endif X { X sprintf(message, "Cannot open %.*s", X error_width()-13, filename); X if (any_edited) X error(message); X else X { X puts(message); X hold_scroll = 1; X#ifdef MSDOS X exit(0); X#endif X } X return; X } X if (isatty(f)) X { X /* X * Not really necessary to call this an error, X * but if the control terminal (for commands) X * and the input file (for data) are the same, X * we get weird results at best. X */ X error("Can't take input from a terminal"); X if (f > 0) X close(f); X return; X } X X /* X * Close the current input file and set up to use the new one. X */ X if (file > 0) X close(file); X new_file = 1; X strcpy(current_file, filename); X ispipe = (f == 0); X file = f; X ch_init( (ispipe) ? p_nbufs : f_nbufs ); X init_mark(); X if (every_first_cmd != NULL) X first_cmd = every_first_cmd; X if (is_tty) X { X any_edited = 1; X if (hold_scroll) X { X /* X * Before erasing the screen contents, X * display the file name and ask for a keystroke. X */ X error(filename); X hold_scroll = 0; X } X if (first_cmd == NULL || *first_cmd == '\0') X { X /* X * Display the first screen. X */ X jump_back(1); X } else X { X /* X * The first_cmd will hopefully redisplay the X * screen, so we need not display anything yet. X * Indicate there is nothing yet on the screen. X */ X pos_clear(); X } X } X} X X/* X * Edit the next file in the command line list. X */ X public void Xnext_file(n) X int n; X{ X if (curr_ac + n >= ac) X { X if (quit_at_eof) X quit(); X error("No (N-th) next file"); X } else X edit(av[curr_ac += n]); X} X X/* X * Edit the previous file in the command line list. X */ X public void Xprev_file(n) X int n; X{ X if (curr_ac - n < 0) X error("No (N-th) previous file"); X else X edit(av[curr_ac -= n]); X} X X/* X * Copy a file directly to standard output. X * Used if standard output is not a tty. X */ X static void Xcat_file() X{ X register int c; X X while ((c = ch_forw_get()) != EOF) X putc(c); X flush(); X} X X/* X * Entry point. X */ Xmain(argc, argv) X int argc; X char *argv[]; X{ X char *getenv(); X X X /* X * Process command line arguments and LESS environment arguments. X * Command line arguments override environment arguments. X */ X init_option(); X scan_option(getenv("LESS")); X argv++; X while ( (--argc > 0) && X (argv[0][0] == '-' || argv[0][0] == '+') && X argv[0][1] != '\0') X scan_option(*argv++); X X#if EDITOR X editor = getenv("EDITOR"); X if (editor == NULL || *editor == '\0') X editor = EDIT_PGM; X#endif X X /* X * Set up list of files to be examined. X */ X ac = argc; X av = argv; X curr_ac = 0; X X /* X * Set up terminal, etc. X */ X is_tty = isatty(1); X if (!is_tty) X { X /* X * Output is not a tty. X * Just copy the input file(s) to output. X */ X if (ac < 1) X { X edit("-"); X cat_file(); X } else X { X do X { X edit((char *)NULL); X if (file >= 0) X cat_file(); X } while (++curr_ac < ac); X } X exit(0); X } X X raw_mode(1); X get_term(); X open_getc(); X init(); X X if (back_scroll < 0) X { X /* {{ KLUDGE }} */ X back_scroll = sc_height-1; X if (top_scroll) X back_scroll--; X } X X X /* X * Select the first file to examine. X */ X if (ac < 1) X edit("-"); /* Standard input */ X else X { X /* X * Try all the files named as command arguments. X * We are simply looking for one which can be X * opened without error. X */ X do X { X edit((char *)NULL); X if (file >= 0) X /* We can open this file. */ X break; X putc('\n'); flush(); X } while (++curr_ac < ac); X } X ctrlbrk(onintr); X if (file >= 0) X commands(); X quit(); X} X X/* X * Exit the program. X */ X public void Xquit() X{ X /* X * Put cursor at bottom left corner, clear the line, X * reset the terminal modes, and exit. X */ X lower_left(); X clear_eol(); X deinit(); X flush(); X raw_mode(0); X exit(0); X} X Xonintr() X{ X return(1); X} X SHAR_EOF if test 5217 -ne "`wc -c < 'main.c'`" then echo shar: error transmitting "'main.c'" '(should have been 5217 characters)' fi fi if test -f 'option.c' then echo shar: will not over-write existing file "'option.c'" else echo extracting "'option.c'" sed 's/^X//' >option.c <<'SHAR_EOF' X/* X * Process command line options. X * Each option is a single letter which controls a program variable. X * The options have defaults which may be changed via X * the command line option, or toggled via the "-" command. X */ X X#include "less.h" X X#define toupper(c) ((c)-'a'+'A') X X/* X * Types of options. X */ X#define BOOL 01 /* Boolean option: 0 or 1 */ X#define TRIPLE 02 /* Triple-valued option: 0, 1 or 2 */ X#define NUMBER 04 /* Numeric option */ X#define NO_TOGGLE 0100 /* Option cannot be toggled with "-" cmd */ X X/* X * Variables controlled by command line options. X */ Xpublic int p_nbufs, f_nbufs; /* Number of buffers. There are two values, X one used for input from a pipe and X the other for input from a file. */ Xpublic int clean_data; /* Can we assume the data is "clean"? X (That is, free of nulls, etc) */ Xpublic int quiet; /* Should we suppress the audible bell? */ Xpublic int top_search; /* Should forward searches start at the top X of the screen? (alternative is bottom) */ Xpublic int top_scroll; /* Repaint screen from top? X (alternative is scroll from bottom) */ Xpublic int pr_type; /* Type of prompt (short, medium, long) */ Xpublic int bs_mode; /* How to process backspaces */ Xpublic int know_dumb; /* Don't complain about dumb terminals */ Xpublic int quit_at_eof; /* Quit after hitting end of file twice */ Xpublic int squeeze; /* Squeeze multiple blank lines into one */ Xpublic int tabstop; /* Tab settings */ Xpublic int back_scroll; /* Repaint screen on backwards movement */ Xpublic int twiddle; /* Display "~" for lines after EOF */ X#ifdef MSDOS Xpublic int scrn_in_color; /* When using color monitor */ X#endif X Xextern int nbufs; Xextern char *first_cmd; Xextern char *every_first_cmd; X X#define DEF_F_NBUFS 5 /* Default for f_nbufs */ X#define DEF_P_NBUFS 12 /* Default for p_nbufs */ X Xstatic struct option X{ X char oletter; /* The controlling letter (a-z) */ X char otype; /* Type of the option */ X int odefault; /* Default value */ X int *ovar; /* Pointer to the associated variable */ X char *odesc[3]; /* Description of each value */ X} option[] = X{ X { 'c', BOOL, 0, &clean_data, X { "Don't assume data is clean", X "Assume data is clean", X NULL X } X }, X { 'd', BOOL|NO_TOGGLE, 0, &know_dumb, X { NULL, NULL, NULL} X }, X { 'e', BOOL, 0, &quit_at_eof, X { "Don't quit at end-of-file", X "Quit at end-of-file", X NULL X } X }, X { 'h', NUMBER, -1, &back_scroll, X { "Backwards scroll limit is %d lines", X NULL, NULL X } X }, X { 'p', BOOL, 0, &top_scroll, X { "Repaint by scrolling from bottom of screen", X "Repaint by painting from top of screen", X NULL X } X }, X { 'x', NUMBER, 8, &tabstop, X { "Tab stops every %d spaces", X NULL, NULL X } X }, X { 's', BOOL, 0, &squeeze, X { "Don't squeeze multiple blank lines", X "Squeeze multiple blank lines", X NULL X } X }, X { 't', BOOL, 1, &top_search, X { "Forward search starts from bottom of screen", X "Forward search starts from top of screen", X NULL X } X }, X { 'w', BOOL, 1, &twiddle, X { "Display nothing for lines after end-of-file", X "Display ~ for lines after end-of-file", X NULL X } X }, X { 'm', TRIPLE, 0, &pr_type, X { "Prompt with a colon", X "Prompt with a message", X "Prompt with a verbose message" X } X }, X { 'q', TRIPLE, 0, &quiet, X { "Ring the bell for errors AND at eof/bof", X "Ring the bell for errors but not at eof/bof", X "Never ring the bell" X } X }, X { 'u', TRIPLE, 0, &bs_mode, X { "Underlined text displayed in underline mode", X "All backspaces cause overstrike", X "Backspaces print as ^H" X } X }, X#ifdef MSDOS X { 'C', BOOL|NO_TOGGLE, 0, &scrn_in_color, X { NULL, NULL, NULL} X }, X#endif X { '\0' } X}; X Xpublic char all_options[64]; /* List of all valid options */ X X/* X * Initialize each option to its default value. X */ X public void Xinit_option() X{ X register struct option *o; X register char *p; X X /* X * First do special cases, not in option table. X */ X first_cmd = every_first_cmd = NULL; X f_nbufs = DEF_F_NBUFS; /* -bf */ X p_nbufs = DEF_P_NBUFS; /* -bp */ X X p = all_options; X *p++ = 'b'; X X for (o = option; o->oletter != '\0'; o++) X { X /* X * Set each variable to its default. X * Also make a list of all options, in "all_options". X */ X *(o->ovar) = o->odefault; X *p++ = o->oletter; X if (o->otype & TRIPLE) X *p++ = toupper(o->oletter); X } X *p = '\0'; X} X X/* X * Toggle command line flags from within the program. X * Used by the "-" command. X */ X public void Xtoggle_option(c) X int c; X{ X register struct option *o; X char message[100]; X char buf[5]; X X /* X * First check for special cases not handled by the option table. X */ X switch (c) X { X case 'b': X sprintf(message, "%d buffers", nbufs); X error(message); X return; X } X X X for (o = option; o->oletter != '\0'; o++) X { X if ((o->otype & BOOL) && (o->oletter == c) && X (o->otype & NO_TOGGLE) == 0) X { X /* X * Boolean option: X * just toggle it. X */ X *(o->ovar) = ! *(o->ovar); X error(o->odesc[*(o->ovar)]); X return; X } else if ((o->otype & TRIPLE) && (o->oletter == c) && X (o->otype & NO_TOGGLE) == 0) X { X /* X * Triple-valued option with lower case letter: X * make it 1 unless already 1, then make it 0. X */ X *(o->ovar) = (*(o->ovar) == 1) ? 0 : 1; X error(o->odesc[*(o->ovar)]); X return; X } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c) && X (o->otype & NO_TOGGLE) == 0) X { X /* X * Triple-valued option with upper case letter: X * make it 2 unless already 2, then make it 0. X */ X *(o->ovar) = (*(o->ovar) == 2) ? 0 : 2; X error(o->odesc[*(o->ovar)]); X return; X } else if ((o->otype & NUMBER) && (o->oletter == c) && X (o->otype & NO_TOGGLE) == 0) X { X sprintf(message, o->odesc[0], *(o->ovar)); X error(message); X return; X } X } X X if (control_char(c)) X sprintf(buf, "^%c", carat_char(c)); X else X sprintf(buf, "%c", c); X sprintf(message, "\"-%s\": no such flag. Use one of \"%s\"", X buf, all_options); X error(message); X} X X/* X * Scan an argument (either from command line or from LESS environment X * variable) and process it. X */ X public void Xscan_option(s) X char *s; X{ X register struct option *o; X register int c; X X if (s == NULL) X return; X X next: X if (*s == '\0') X return; X switch (c = *s++) X { X case '-': X case ' ': X case '\t': X goto next; X case '+': X if (*s == '+') X every_first_cmd = ++s; X first_cmd = s; X return; X case 'b': X switch (*s) X { X case 'f': X s++; X f_nbufs = getnum(&s, 'b'); X break; X case 'p': X s++; X p_nbufs = getnum(&s, 'b'); X break; X default: X f_nbufs = p_nbufs = getnum(&s, 'b'); X break; X } X goto next; X } X X for (o = option; o->oletter != '\0'; o++) X { X if ((o->otype & BOOL) && (o->oletter == c)) X { X *(o->ovar) = ! o->odefault; X goto next; X } else if ((o->otype & TRIPLE) && (o->oletter == c)) X { X *(o->ovar) = (o->odefault == 1) ? 0 : 1; X goto next; X } else if ((o->otype & TRIPLE) && (toupper(o->oletter) == c)) X { X *(o->ovar) = (o->odefault == 2) ? 0 : 2; X goto next; X } else if ((o->otype & NUMBER) && (o->oletter == c)) X { X *(o->ovar) = getnum(&s, c); X goto next; X } X } X X printf("\"-%c\": invalid flag\n", c); X exit(1); X} X X/* X * Translate a string into a number. X * Like atoi(), but takes a pointer to a char *, and updates X * the char * to point after the translated number. X */ X static int Xgetnum(sp, c) X char **sp; X int c; X{ X register char *s; X register int n; X X s = *sp; X if (*s < '0' || *s > '9') X { X printf("number is required after -%c\n", c); X exit(1); X } X X n = 0; X while (*s >= '0' && *s <= '9') X n = 10 * n + *s++ - '0'; X *sp = s; X return (n); X} X SHAR_EOF if test 7572 -ne "`wc -c < 'option.c'`" then echo shar: error transmitting "'option.c'" '(should have been 7572 characters)' fi fi if test -f 'output.c' then echo shar: will not over-write existing file "'output.c'" else echo extracting "'output.c'" sed 's/^X//' >output.c <<'SHAR_EOF' X/* X * High level routines dealing with the output to the screen. X */ X X#include "less.h" X#ifdef MSDOS X#include "scrn.h" X#endif X Xextern int sigs; Xextern int sc_width, sc_height; Xextern int ul_width, ue_width; Xextern int so_width, se_width; Xextern int bo_width, be_width; Xextern int tabstop; Xextern int twiddle; Xextern char *line; Xextern char *first_cmd; X#ifdef MSDOS Xextern int scrn_in_color; X#endif X X/* X * Display the line which is in the line buffer. X */ X public void Xput_line() X{ X register char *p; X register int c; X register int column; X extern int auto_wrap, ignaw; X X if (sigs) X /* X * Don't output if a signal is pending. X */ X return; X X if (line == NULL) X line = (twiddle) ? "~" : ""; X X column = 0; X for (p = line; *p != '\0'; p++) X { X switch (c = *p) X { X case UL_CHAR: X ul_enter(); X column += ul_width; X break; X case UE_CHAR: X ul_exit(); X column += ue_width; X break; X case BO_CHAR: X bo_enter(); X column += bo_width; X break; X case BE_CHAR: X bo_exit(); X column += be_width; X break; X X case '\t': X do X { X putc(' '); X column++; X } while ((column % tabstop) != 0); X break; X case '\b': X putbs(); X column--; X break; X default: X if (c & 0200) X { X#ifndef MSDOS X putc('^'); X putc(c & 0177); X column += 2; X#endif X } else X { X putc(c); X column++; X } X } X } X if (column < sc_width || !auto_wrap || ignaw) X putc('\n'); X} X X/* X * Is a given character a "control" character? X * {{ ASCII DEPENDENT }} X */ X public int Xcontrol_char(c) X int c; X{ X return (c < ' ' || c == '\177'); X} X X/* X * Return the printable character used to identify a control character X * (printed after a carat; e.g. '\3' => "^C"). X * {{ ASCII DEPENDENT }} X */ X public int Xcarat_char(c) X int c; X{ X return ((c == '\177') ? '?' : (c | 0100)); X} X X Xstatic char obuf[1024]; Xstatic char *ob = obuf; X X/* X * Flush buffered output. X */ X public void Xflush() X{ X#ifndef MSDOS X write(1, obuf, ob-obuf); X ob = obuf; X#else X int chr_cnt; X int i; X X chr_cnt = ob-obuf; X i = 0; X do X { X if (scrn_in_color == 1) X chr_put(*(obuf + i++), WHITE_ON_BLUE); X else X chr_put(*(obuf + i++), BW); X --chr_cnt; X } X while (chr_cnt > 0); X ob = obuf; X#endif X} X X/* X * Discard buffered output. X */ X public void Xdropout() X{ X ob = obuf; X} X X/* X * Output a character. X */ X public void Xputc(c) X int c; X{ X if (ob >= &obuf[sizeof(obuf)]) X flush(); X *ob++ = c; X#ifdef MSDOS X flush(); X#endif X} X X/* X * Output a string. X */ X public void Xputs(s) X register char *s; X{ X#ifndef MSDOS X while (*s != '\0') X putc(*s++); X#else X str_put(s, WHITE_ON_RED); X#endif X} X X/* X * Output a message in the lower left corner of the screen X * and wait for carriage return. X */ X Xstatic char return_to_continue[] = " (press RETURN)"; X X public void Xerror(s) X char *s; X{ X register int c; X static char buf[2]; X X lower_left(); X clear_eol(); X so_enter(); X#ifndef MSDOS X puts(s); X puts(return_to_continue); X#else X str_put(s, WHITE_ON_RED); X str_put(return_to_continue, WHITE_ON_RED); X#endif X so_exit(); X X#if ONLY_RETURN X while ((c = getc()) != '\n' && c != '\r') X bell(); X#else X c = getc(); X if (c != '\n' && c != '\r' && c != ' ') X { X buf[0] = c; X first_cmd = buf; X } X#endif X X if (strlen(s) > sc_width) X repaint(); X} X X public int Xerror_width() X{ X /* X * Don't use the last position, because some terminals X * will scroll if you write in the last char of the last line. X */ X return (sc_width - X (sizeof(return_to_continue) + so_width + se_width + 1)); X} X SHAR_EOF if test 3436 -ne "`wc -c < 'output.c'`" then echo shar: error transmitting "'output.c'" '(should have been 3436 characters)' fi fi if test -f 'position.c' then echo shar: will not over-write existing file "'position.c'" else echo extracting "'position.c'" sed 's/^X//' >position.c <<'SHAR_EOF' X/* X * Routines dealing with the "position" table. X * This is a table which tells the position (in the input file) of the X * first char on each currently displayed line. X * X * {{ The position table is scrolled by moving all the entries. X * Would be better to have a circular table X * and just change a couple of pointers. }} X */ X X#include "less.h" X#include "position.h" X X#define NPOS 100 /* {{ sc_height must be less than NPOS }} */ Xstatic POSITION table[NPOS]; /* The position table */ X Xextern int sc_width, sc_height; X X/* X * Return the position of one of: X * the top (first) line on the screen X * the second line on the screen X * the bottom line on the screen X * the line after the bottom line on the screen X */ X public POSITION Xposition(where) X int where; X{ X switch (where) X { X case BOTTOM: X where = sc_height - 2; X break; X case BOTTOM_PLUS_ONE: X where = sc_height - 1; X break; X } X return (table[where]); X} X X/* X * Add a new file position to the bottom of the position table. X */ X public void Xadd_forw_pos(pos) X POSITION pos; X{ X register int i; X X /* X * Scroll the position table up. X */ X for (i = 1; i < sc_height; i++) X table[i-1] = table[i]; X table[sc_height - 1] = pos; X} X X/* X * Add a new file position to the top of the position table. X */ X public void Xadd_back_pos(pos) X POSITION pos; X{ X register int i; X X /* X * Scroll the position table down. X */ X for (i = sc_height - 1; i > 0; i--) X table[i] = table[i-1]; X table[0] = pos; X} X X/* X * Initialize the position table, done whenever we clear the screen. X */ X public void Xpos_clear() X{ X register int i; X X for (i = 0; i < sc_height; i++) X table[i] = NULL_POSITION; X} X X/* X * See if the byte at a specified position is currently on the screen. X * Check the position table to see if the position falls within its range. X * Return the position table entry if found, -1 if not. X */ X public int Xonscreen(pos) X POSITION pos; X{ X register int i; X X if (pos < table[0]) X return (-1); X for (i = 1; i < sc_height; i++) X if (pos < table[i]) X return (i-1); X return (-1); X} SHAR_EOF if test 2040 -ne "`wc -c < 'position.c'`" then echo shar: error transmitting "'position.c'" '(should have been 2040 characters)' fi fi if test -f 'position.h' then echo shar: will not over-write existing file "'position.h'" else echo extracting "'position.h'" sed 's/^X//' >position.h <<'SHAR_EOF' X/* X * Include file for interfacing to position.c modules. X */ X#define TOP 0 X#define TOP_PLUS_ONE 1 X#define BOTTOM -1 X#define BOTTOM_PLUS_ONE -2 SHAR_EOF if test 146 -ne "`wc -c < 'position.h'`" then echo shar: error transmitting "'position.h'" '(should have been 146 characters)' fi fi if test -f 'prim.c' then echo shar: will not over-write existing file "'prim.c'" else echo extracting "'prim.c'" sed 's/^X//' >prim.c <<'SHAR_EOF' X/* X * Primitives for displaying the file on the screen. X */ X X#include "less.h" X#include "position.h" X Xpublic int hit_eof; /* Keeps track of how many times we hit end of file */ X Xextern int quiet; Xextern int top_search; Xextern int top_scroll; Xextern int back_scroll; Xextern int sc_width, sc_height; Xextern int sigs; Xextern char *line; Xextern char *first_cmd; X X/* X * Sound the bell to indicate he is trying to move past end of file. X */ X static void Xeof_bell() X{ X if (quiet == NOT_QUIET) X bell(); X else X vbell(); X} X X/* X * Check to see if the end of file is currently "displayed". X */ X static void Xeof_check() X{ X POSITION pos; X X /* X * If the bottom line is empty, we are at EOF. X * If the bottom line ends at the file length, X * we must be just at EOF. X */ X pos = position(BOTTOM_PLUS_ONE); X if (pos == NULL_POSITION || pos == ch_length()) X hit_eof++; X} X X/* X * Display n lines, scrolling forward, X * starting at position pos in the input file. X * "force" means display the n lines even if we hit end of file. X * "only_last" means display only the last screenful if n > screen size. X */ X static void Xforw(n, pos, force, only_last) X register int n; X POSITION pos; X int force; X int only_last; X{ X int eof = 0; X int nlines = 0; X int repaint_flag; X X /* X * repaint_flag tells us not to display anything till the end, X * then just repaint the entire screen. X */ X repaint_flag = (only_last && n > sc_height-1); X X if (!repaint_flag) X { X if (top_scroll && n >= sc_height - 1) X { X /* X * Start a new screen. X * {{ This is not really desirable if we happen X * to hit eof in the middle of this screen, X * but we don't know if that will happen now. }} X */ X clear(); X home(); X force = 1; X } else X { X lower_left(); X clear_eol(); X } X X if (pos != position(BOTTOM_PLUS_ONE)) X { X /* X * This is not contiguous with what is X * currently displayed. Clear the screen image X * (position table) and start a new screen. X */ X pos_clear(); X add_forw_pos(pos); X force = 1; X if (top_scroll) X { X clear(); X home(); X } else X { X puts("...skipping...\n"); X } X } X } X X while (--n >= 0) X { X /* X * Read the next line of input. X */ X pos = forw_line(pos); X if (pos == NULL_POSITION) X { X /* X * End of file: stop here unless the top line X * is still empty, or "force" is true. X */ X eof = 1; X if (!force && position(TOP) != NULL_POSITION) X break; X line = NULL; X } X /* X * Add the position of the next line to the position table. X * Display the current line on the screen. X */ X add_forw_pos(pos); X nlines++; X if (!repaint_flag) X put_line(); X } X X if (eof) X hit_eof++; X else X eof_check(); X if (nlines == 0) X eof_bell(); X else if (repaint_flag) X repaint(); X} X X/* X * Display n lines, scrolling backward. X */ X static void Xback(n, pos, force, only_last) X register int n; X POSITION pos; X int force; X int only_last; X{ X int nlines = 0; X int repaint_flag; X X repaint_flag = (n > back_scroll || (only_last && n > sc_height-1)); X hit_eof = 0; X while (--n >= 0) X { X /* X * Get the previous line of input. X */ X pos = back_line(pos); X if (pos == NULL_POSITION) X { X /* X * Beginning of file: stop here unless "force" is true. X */ X if (!force) X break; X line = NULL; X } X /* X * Add the position of the previous line to the position table. X * Display the line on the screen. X */ X add_back_pos(pos); X nlines++; X if (!repaint_flag) X { X home(); X add_line(); X put_line(); X } X } X X eof_check(); X if (nlines == 0) X eof_bell(); X else if (repaint_flag) X repaint(); X} X X X /* X Find the current line number X */ X X public int curln() X { X int n; X POSITION pos; X n=0; X pos = position(TOP); X while (pos!=NULL_POSITION) X { X pos = back_line(pos); X n++; X } X return(n); X } X X X X/* X * Display n more lines, forward. X * Start just after the line currently displayed at the bottom of the screen. X */ X public void Xforward(n, only_last) X int n; X int only_last; X{ X POSITION pos; X X pos = position(BOTTOM_PLUS_ONE); X if (pos == NULL_POSITION) X { X eof_bell(); X hit_eof++; X return; X } X forw(n, pos, 0, only_last); X} X X/* X * Display n more lines, backward. X * Start just before the line currently displayed at the top of the screen. X */ X public void Xbackward(n, only_last) X int n; X int only_last; X{ X POSITION pos; X X pos = position(TOP); X if (pos == NULL_POSITION) X { X /* X * This will almost never happen, X * because the top line is almost never empty. X */ X eof_bell(); X return; X } X back(n, pos, 0, only_last); X} X X/* X * Repaint the screen, starting from a specified position. X */ X static void Xprepaint(pos) X POSITION pos; X{ X hit_eof = 0; X forw(sc_height-1, pos, 0, 0); X} X X/* X * Repaint the screen. X */ X public void Xrepaint() X{ X /* X * Start at the line currently at the top of the screen X * and redisplay the screen. X */ X prepaint(position(TOP)); X} X X/* X * Jump to the end of the file. X * It is more convenient to paint the screen backward, X * from the end of the file toward the beginning. X */ X public void Xjump_forw() X{ X POSITION pos; X X if (ch_end_seek()) X { X error("Cannot seek to end of file"); X return; X } X pos = ch_tell(); X clear(); X pos_clear(); X add_back_pos(pos); X back(sc_height - 1, pos, 0, 0); X} X X/* X * Jump to line n in the file. X */ X public void Xjump_back(n) X register int n; X{ X register int c; X X /* X * This is done the slow way, by starting at the beginning X * of the file and counting newlines. X */ X if (ch_seek((POSITION)0)) X { X /* X * Probably a pipe with beginning of file no longer buffered. X */ X error("Cannot get to beginning of file"); X return; X } X X /* X * Start counting lines. X */ X while (--n > 0) X { X while ((c = ch_forw_get()) != '\n') X if (c == EOF) X { X error("File is not that long"); X /* {{ Maybe tell him how long it is? }} */ X return; X } X } X X /* X * Finally found the place to start. X * Clear and redisplay the screen from there. X * X * {{ We *could* figure out if the new position is X * close enough to just scroll there without clearing X * the screen, but it's not worth it. }} X */ X prepaint(ch_tell()); X} X X/* X * Jump to a specified percentage into the file. X * This is a poor compensation for not being able to X * quickly jump to a specific line number. X */ X public void Xjump_percent(percent) X int percent; X{ X POSITION pos, len; X X /* X * Determine the position in the file X * (the specified percentage of the file's length). X */ X if ((len = ch_length()) == NULL_POSITION) X { X error("Don't know length of file"); X return; X } X pos = (percent * len) / 100; X jump_loc(pos); X} X X public void Xjump_loc(pos) X POSITION pos; X{ X register int c; X register int nline; X POSITION tpos; X X /* X * See if the desired line is BEFORE the currently X * displayed screen. If so, see if it is close enough X * to scroll backwards to it. X */ X tpos = position(TOP); X if (pos < tpos) X { X for (nline = 1; nline <= back_scroll; nline++) X { X tpos = back_line(tpos); X if (tpos == NULL_POSITION || tpos <= pos) X { X back(nline, position(TOP), 1, 0); X return; X } X } X } else if ((nline = onscreen(pos)) >= 0) X { X /* X * The line is currently displayed. X * Just scroll there. X */ X forw(nline, position(BOTTOM_PLUS_ONE), 1, 0); X return; X } X X /* X * Line is not on screen. X * Back up to the beginning of the current line. X */ X if (ch_seek(pos)) X { X error("Cannot seek to that position"); X return; X } X while ((c = ch_back_get()) != '\n' && c != EOF) X ; X if (c == '\n') X (void) ch_forw_get(); X X /* X * Clear and paint the screen. X */ X prepaint(ch_tell()); X} X X/* X * The table of marks. X * A mark is simply a position in the file. X */ Xstatic POSITION marks[26]; X X/* X * Initialize the mark table to show no marks are set. X */ X public void Xinit_mark() X{ X int i; X X for (i = 0; i < 26; i++) X marks[i] = NULL_POSITION; X} X X/* X * See if a mark letter is valid (between a and z). X */ X static int Xbadmark(c) X int c; X{ X if (c < 'a' || c > 'z') X { X error("Choose a letter between 'a' and 'z'"); X return (1); X } X return (0); X} X X/* X * Set a mark. X */ X public void Xsetmark(c) X int c; X{ X if (badmark(c)) X return; X marks[c-'a'] = position(TOP); X} X X/* X * Go to a previously set mark. X */ X public void Xgomark(c) X int c; X{ X POSITION pos; X X if (badmark(c)) X return; X if ((pos = marks[c-'a']) == NULL_POSITION) X error("mark not set"); X else X jump_loc(pos); X} X X/* X * Search for the n-th occurence of a specified pattern, X * either forward (direction == '/'), or backwards (direction == '?'). X */ X public void Xsearch(direction, pattern, n) X int direction; X char *pattern; X register int n; X{ X register int search_forward = (direction == '/'); X POSITION pos, linepos; X X#if RECOMP X char *re_comp(); X char *errmsg; X X /* X * (re_comp handles a null pattern internally, X * so there is no need to check for a null pattern here.) X */ X if ((errmsg = re_comp(pattern)) != NULL) X { X error(errmsg); X return; X } X#else X#if REGCMP | REGEXP X#if REGEXP /* Use Harry Spencer's regexpression source */ X char *regcomp(); X#else X char *regcmp(); X#endif X static char *cpattern = NULL; X X if (pattern == NULL || *pattern == '\0') X { X /* X * A null pattern means use the previous pattern. X * The compiled previous pattern is in cpattern, so just use it. X */ X if (cpattern == NULL) X { X error("No previous regular expression"); X return; X } X } else X { X /* X * Otherwise compile the given pattern. X */ X char *s; X#if REGEXP X if ((s = regcomp(pattern, 0)) == NULL) X#else X if ((s = regcmp(pattern, 0)) == NULL) X#endif X { X error("Invalid pattern"); X return; X } X if (cpattern != NULL) X free(cpattern); X cpattern = s; X } X#else X static char lpbuf[100]; X static char *last_pattern = NULL; X X if (pattern == NULL || *pattern == '\0') X { X /* X * Null pattern means use the previous pattern. X */ X if (last_pattern == NULL) X { X error("No previous regular expression"); X return; X } X pattern = last_pattern; X } else X { X strcpy(lpbuf, pattern); X last_pattern = lpbuf; X } X#endif X#endif X X /* X * Figure out where to start the search. X */ X X if (position(TOP) == NULL_POSITION) X { X /* X * Nothing is currently displayed. X * Start at the beginning of the file. X * (This case is mainly for first_cmd searches, X * for example, "+/xyz" on the command line.) X */ X pos = (POSITION)0; X } else if (!search_forward) X { X /* X * Backward search: start just before the top line X * displayed on the screen. X */ X pos = position(TOP); X } else if (top_search) X { X /* X * Forward search and "start from top". X * Start at the second line displayed on the screen. X */ X pos = position(TOP_PLUS_ONE); X } else X { X /* X * Forward search but don't "start from top". X * Start just after the bottom line displayed on the screen. X */ X pos = position(BOTTOM_PLUS_ONE); X } X X if (pos == NULL_POSITION) X { X /* X * Can't find anyplace to start searching from. X */ X error("Nothing to search"); X return; X } X X for (;;) X { X /* X * Get lines until we find a matching one or X * until we hit end-of-file (or beginning-of-file X * if we're going backwards). X */ X if (sigs) X /* X * A signal aborts the search. X */ X return; X X if (search_forward) X { X /* X * Read the next line, and save the X * starting position of that line in linepos. X */ X linepos = pos; X pos = forw_raw_line(pos); X } else X { X /* X * Read the previous line and save the X * starting position of that line in linepos. X */ X pos = back_raw_line(pos); X linepos = pos; X } X X if (pos == NULL_POSITION) X { X /* X * We hit EOF/BOF without a match. X */ X error("Pattern not found"); X return; X } X X /* X * Test the next line to see if we have a match. X * This is done in a variety of ways, depending X * on what pattern matching functions are available. X */ X#if REGCMP | REGEXP X#if REGEXP X if ( (regexec(cpattern, line) != NULL) X#else X if ( (regex(cpattern, line) != NULL) X#endif X#else X#if RECOMP X if ( (re_exec(line) == 1) X#else X if ( (match(pattern, line)) X#endif X#endif X && (--n <= 0) ) X /* X * Found the matching line. X */ X break; X } X jump_loc(linepos); X} X X#if (!REGCMP) && (!RECOMP) X/* X * We have neither regcmp() nor re_comp(). X * We use this function to do simple pattern matching. X * It supports no metacharacters like *, etc. X */ X static int Xmatch(pattern, buf) X char *pattern, *buf; X{ X register char *pp, *lp; X X for ( ; *buf != '\0'; buf++) X { X for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) X if (*pp == '\0' || *lp == '\0') X break; X if (*pp == '\0') X return (1); X } X return (0); X} X#endif SHAR_EOF if test 12563 -ne "`wc -c < 'prim.c'`" then echo shar: error transmitting "'prim.c'" '(should have been 12563 characters)' fi fi if test -f 'prompt.c' then echo shar: will not over-write existing file "'prompt.c'" else echo extracting "'prompt.c'" sed 's/^X//' >prompt.c <<'SHAR_EOF' X/* X * Prompting and other messages. X * There are three flavors of prompts, SHORT, MEDIUM and LONG, X * selected by the -m/-M options. X * A prompt is either a colon or a message composed of various X * pieces, such as the name of the file being viewed, the percentage X * into the file, etc. X */ X X#include "less.h" X#include "position.h" X Xextern int pr_type; Xextern int ispipe; Xextern int hit_eof; Xextern int new_file; Xextern int sc_width; Xextern char current_file[]; Xextern int ac; Xextern char **av; Xextern int curr_ac; X Xstatic char message[500]; X X/* X * Append the name of the current file (to the message buffer). X */ X static void Xap_filename() X{ X if (!ispipe) X sprintf(message + strlen(message), X "%s", current_file); X} X X/* X * Append the "file N of M" message. X */ X static void Xap_of() X{ X if (ac > 1) X sprintf(message + strlen(message), X " (file %d of %d)", curr_ac+1, ac); X} X X/* Append the line number */ X X static void Xap_ln() X{ X sprintf(message + strlen(message), X " Line %d,", curln()); X} X X/* X * Append the byte offset into the current file. X */ X static void Xap_byte() X{ X POSITION pos, len; X X pos = position(BOTTOM_PLUS_ONE); X if (pos != NULL_POSITION) X { X sprintf(message + strlen(message), X " byte %ld", pos); X len = ch_length(); X if (len > 0) X sprintf(message + strlen(message), X "/%ld", len); X } X} X X/* X * Append the percentage into the current file. X * If we cannot find the percentage and must_print is true, X * the use the byte offset. X */ X static void Xap_percent(must_print) X{ X POSITION pos,len; X X pos = position(BOTTOM_PLUS_ONE); X len = ch_length(); X if (len > 0 && pos != NULL_POSITION) X sprintf(message + strlen(message), X " (%ld%%)", (100 * pos) / len); X else if (must_print) X ap_byte(); X} X X/* X * Append the end-of-file message. X */ X static void Xap_eof() X{ X strcat(message, " END"); X if (curr_ac + 1 < ac) X sprintf(message + strlen(message), X " - Next: %s", av[curr_ac+1]); X} X X/* X * Return a message suitable for printing by the "l" command. X */ X public char * X Xeq_mess2() X{ X message[0] = '\0'; X ap_filename(); X ap_ln(); X ap_of(); X ap_byte(); X ap_percent(0); X /* X * Truncate to the screen width. X * {{ This isn't very nice. }} X */ X message[error_width()] = '\0'; X return (message); X} X/* X * Return a message suitable for printing by the "=" command. X */ X public char * X Xeq_message() X{ X message[0] = '\0'; X ap_filename(); X ap_of(); X ap_byte(); X ap_percent(0); X /* X * Truncate to the screen width. X * {{ This isn't very nice. }} X */ X message[error_width()] = '\0'; X return (message); X} X X/* X * Return a prompt. X * This depends on the prompt type (SHORT, MEDIUM, LONG), etc. X * If we can't come up with an appropriate prompt, return NULL X * and the caller will prompt with a colon. X */ X public char * Xpr_string() X{ X message[0] = '\0'; X switch (pr_type) X { X case PR_SHORT: X if (new_file) X { X ap_filename(); X ap_of(); X } X if (hit_eof) X ap_eof(); X break; X case PR_MEDIUM: X if (new_file) X { X ap_filename(); X ap_of(); X } X if (hit_eof) X ap_eof(); X else X ap_percent(1); X break; X case PR_LONG: X ap_filename(); X if (new_file) X ap_of(); X ap_byte(); X if (hit_eof) X ap_eof(); X else X ap_percent(0); X break; X } X new_file = 0; X if (message[0] == '\0') X return (NULL); X /* X * Truncate to the screen width. X * {{ This isn't very nice. }} X */ X message[sc_width-2] = '\0'; X return (message); X} SHAR_EOF if test 3358 -ne "`wc -c < 'prompt.c'`" then echo shar: error transmitting "'prompt.c'" '(should have been 3358 characters)' fi fi if test -f 'ttyin.c' then echo shar: will not over-write existing file "'ttyin.c'" else echo extracting "'ttyin.c'" sed 's/^X//' >ttyin.c <<'SHAR_EOF' X/* X * Routines dealing with getting input from the keyboard (i.e. from the user). X */ X X#include "less.h" X X/* X * The boolean "reading" is set true or false according to whether X * we are currently reading from the keyboard. X * This information is used by the signal handling stuff in signal.c. X * {{ There are probably some race conditions here X * involving the variable "reading". }} X */ Xpublic int reading; X Xstatic int tty; X X/* X * Open keyboard for input. X * (Just use file descriptor 2.) X */ X public void Xopen_getc() X{ X tty = 2; X} X X/* X * Get a character from the keyboard. X */ X public int Xgetc() X{ X#if MSDOS X#if MSC X int c; X struct regs { X int ax, bx, cx, dx, si, di, ds, es; X } cregs, rregs; X int intno = 0x016; X#else X char c; X#endif X#endif X int result; X X reading = 1; X#if MSDOS X#if MSC X cregs.ax = 0x0000; /* set registers */ X int86(0x16, &cregs, &cregs); /* call BIOS - INT 16h */ X c = (cregs.ax & 0x00ff); X reading = 0; X return(c & 0177); X#else X do X { X flush(); X result = read(tty, &c, 1); X } while (result != 1); X reading = 0; X return (c & 0177); X#endif X#endif X} X SHAR_EOF if test 1080 -ne "`wc -c < 'ttyin.c'`" then echo shar: error transmitting "'ttyin.c'" '(should have been 1080 characters)' fi fi if test -f 'version.c' then echo shar: will not over-write existing file "'version.c'" else echo extracting "'version.c'" sed 's/^X//' >version.c <<'SHAR_EOF' X/* X * less X * Copyright (c) 1984,1985 Mark Nudelman X * X * This program may be freely used and/or modified, X * with the following provisions: X * 1. This notice and the above copyright notice must remain intact. X * 2. Neither this program, nor any modification of it, X * may not be sold for profit without written consent of the author. X * X * ----------------------------------------------------------------- X * X * This program is a paginator similar to "more", X * but allows you to move both forward and backward in the file. X * Commands are based on "more" and "vi". X * X * ----------------------- CHANGES --------------------------------- X * X * Allowed use on standard input 1/29/84 markn X * Added E, N, P commands 2/1/84 markn X * Added '=' command, 'stop' signal handling 4/17/84 markn X * Added line folding 4/20/84 markn X * v2: Fixed '=' command to use BOTTOM_PLUS_ONE, X * instead of TOP, added 'p' & 'v' commands 4/27/84 markn X * v3: Added -m and -t options, '-' command 5/3/84 markn X * v4: Added LESS environment variable 5/3/84 markn X * v5: New comments, fixed '-' command slightly 5/3/84 markn X * v6: Added -Q, visual bell 5/15/84 markn X * v7: Fixed jump_back(n) bug: n should count real X * lines, not folded lines. Also allow number X * on G command. 5/24/84 markn X * v8: Re-do -q and -Q commands 5/30/84 markn X * v9: Added "+" argument 9/25/84 markn X * v10: Fixed bug in -b argument processing 10/10/84 markn X * v11: Made error() ring bell if \n not entered. 10/18/84 markn X * ----------------------------------------------------------------- X * v12: Reorganized signal handling and made X * portable to 4.2bsd. 2/13/85 mark X * v13: Reword error message for '-' command. 2/16/85 mark X * v14: Added -bf and -bp variants of -b. 2/22/85 mark X * v15: Miscellaneous changes. 2/25/85 mark X * v16: Added -u flag for backspace processing. 3/13/85 mark X * v17: Added j and k commands, X * changed -t default. 4/13/85 mark X * v18: Rewrote signal handling code. 4/20/85 mark X * v19: Got rid of "verbose" eq_message(). 5/2/85 mark X * Made search() scroll in some cases. X * v20: Fixed screen.c ioctls for System V. 5/21/85 mark X * v21: Fixed some first_cmd bugs. 5/23/85 mark X * v22: Added support for no RECOMP nor REGCMP. 5/24/85 mark X * v23: Miscellanous changes and prettying up. 5/25/85 mark X * v24: Added ti,te terminal init & de-init 6/3/85 Mike Kersenbrock X * v25: Added -U flag, standout mode underlining. 6/8/85 mark X * v26: Added -M flag. 6/9/85 mark X * Use underline termcap (us) if it exists. X * v27: Renamed some variables to make unique in 6/15/85 mark X * 6 chars. Minor fix to -m. X * v28: Fixed right margin bug. 6/28/85 mark X * v29: Incorporated M.Rose's changes to signal.c 6/28/85 mark X * v30: Fixed stupid bug in argument processing. 6/29/85 mark X * v31: Added -p flag, changed repaint algorithm. 7/15/85 mark X * Added kludge for magic cookie terminals. X * v32: Added cat_file if output not a tty. 7/16/85 mark X * v33: Added -e flag and EDITOR. 7/23/85 mark X * v34: Added -s flag. 7/26/85 mark X * v35: Rewrote option handling; added option.c. 7/27/85 mark X * v36: Fixed -e flag to work if not last file. 7/29/85 mark X * v37: Added -x flag. 8/10/85 mark X * v38: Changed prompting; created prompt.c. 8/19/85 mark X * v39: (Not -p) does not initially clear screen. 8/24/85 mark X * v40: Added "skipping" indicator in forw(). 8/26/85 mark X * v41: ONLY_RETURN, control char commands, 9/17/85 mark X * faster search, other minor fixes. X * v42: Added ++ command line syntax; 9/25/85 mark X * ch_fsize for pipes. X * v43: Added -h flag, changed prim.c algorithms. 10/15/85 mark X * v44: Made END print in all cases of eof; 10/16/85 mark X * ignore SIGTTOU after receiving SIGTSTP. X * v45: Never print backspaces unless -u. 10/16/85 mark X * v46: Backwards scroll in jump_loc. 10/24/85 mark X * v47: Fixed bug in edit(): *first_cmd==0 10/30/85 mark X * v48: Use TIOCSETN instead of TIOCSETP. 11/16/85 mark X * Added marks (m and ' commands). X * v48+: Added 'L' command to show number of line 7/23/87 m.slomin X * at top of the screen. X * ----------------------------------------------------------------- X */ X Xchar version[] = "@(#) less version 48+/MS-DOS"; SHAR_EOF if test 4414 -ne "`wc -c < 'version.c'`" then echo shar: error transmitting "'version.c'" '(should have been 4414 characters)' fi fi # end of shell archive exit 0 --- No warranties whatsoever. Mike Slomin !bellcore!lcuxa!mike2