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 1 of 3) Message-ID: <198@lcuxa.UUCP> Date: 22 Apr 88 18:16:20 GMT Organization: Bell Communications Research Lines: 2202 Keywords: Less For those who wish to rebuild and/or modify the posted executable 'less.com', I am posting the sources in three shar files. ---------------------Part 1 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: # # ch.c # command.c # dos_port.h # funcs.h # help.c # input.c # less.h # less.prj # line.c # setargv.c # # Created on April 22, 1988 # if test -f 'ch.c' then echo shar: will not over-write existing file "'ch.c'" else echo extracting "'ch.c'" sed 's/^X//' >ch.c <<'SHAR_EOF' X/* X * Low level character input from the input file. X * We use these special purpose routines which optimize moving X * both forward and backward from the current read pointer. X */ X X#include "less.h" X Xpublic int file = -1; /* File descriptor of the input file */ X X/* X * Pool of buffers holding the most recently used blocks of the input file. X */ X#define BUFSIZ 1024 Xstatic struct buf { X struct buf *next, *prev; X long block; X char data[BUFSIZ]; X}; Xstatic struct buf *bufs = NULL; Xpublic int nbufs; X X/* X * The buffer pool is kept as a doubly-linked circular list, X * in order from most- to least-recently used. X * The circular list is anchored by buf_anchor. X */ Xstatic struct { X struct buf *next, *prev; X} buf_anchor; X#define END_OF_CHAIN ((struct buf *)&buf_anchor) X#define buf_head buf_anchor.next X#define buf_tail buf_anchor.prev X X/* X * If we fail to allocate enough memory for buffers, we try to limp X * along with a minimum number of buffers. X */ X#define DEF_NBUFS 2 /* Minimum number of buffers */ X Xextern int clean_data; Xextern int ispipe; X X/* X * Current position in file. X * Stored as a block number and an offset into the block. X */ Xstatic long ch_block; Xstatic int ch_offset; X X/* X * Length of file, needed if input is a pipe. X */ Xstatic POSITION ch_fsize; X X/* X * Largest block number read if input is standard input (a pipe). X */ Xstatic long last_piped_block; X X/* X * Get the character pointed to by the read pointer. X * ch_get() is a macro which is more efficient to call X * than fch_get (the function), in the usual case X * that the block desired is at the head of the chain. X */ X#define ch_get() ((buf_head->block == ch_block) ? \ X buf_head->data[ch_offset] : fch_get()) X static int Xfch_get() X{ X register struct buf *bp; X register int n; X register int end; X POSITION pos; X X /* X * Look for a buffer holding the desired block. X */ X for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next) X if (bp->block == ch_block) X goto found; X /* X * Block is not in a buffer. X * Take the least recently used buffer X * and read the desired block into it. X */ X bp = buf_tail; X bp->block = ch_block; X pos = ch_block * BUFSIZ; X if (ispipe) X { X /* X * The block requested should be one more than X * the last block read. X */ X if (ch_block != ++last_piped_block) X { X /* This "should not happen". */ X char message[80]; X sprintf(message, "Pipe error: last %ld, want %ld\n", X last_piped_block-1, ch_block); X error(message); X quit(); X } X } else X lseek(file, pos, 0); X X /* X * Read the block. This may take several reads if the input X * is coming from standard input, due to the nature of pipes. X */ X end = 0; X while ((n = read(file, &bp->data[end], BUFSIZ-end)) > 0) X if ((end += n) >= BUFSIZ) X break; X X if (n < 0) X { X error("read error"); X quit(); X } X X /* X * Set an EOF marker in the buffered data itself. X * Then ensure the data is "clean": there are no X * extra EOF chars in the data and that the "meta" X * bit (the 0200 bit) is reset in each char. X */ X if (end < BUFSIZ) X { X ch_fsize = pos + end; X bp->data[end] = EOF; X } X X if (!clean_data) X while (--end >= 0) X { X bp->data[end] &= 0177; X if (bp->data[end] == EOF) X bp->data[end] = '@'; X } X X found: X /* if (buf_head != bp) {this is guaranteed by the ch_get macro} */ X { X /* X * Move the buffer to the head of the buffer chain. X * This orders the buffer chain, most- to least-recently used. X */ X bp->next->prev = bp->prev; X bp->prev->next = bp->next; X X bp->next = buf_head; X bp->prev = END_OF_CHAIN; X buf_head->prev = bp; X buf_head = bp; X } X return (bp->data[ch_offset]); X} X X/* X * Determine if a specific block is currently in one of the buffers. X */ X static int Xbuffered(block) X long block; X{ X register struct buf *bp; X X for (bp = buf_head; bp != END_OF_CHAIN; bp = bp->next) X if (bp->block == block) X return (1); X return (0); X} X X/* X * Seek to a specified position in the file. X * Return 0 if successful, non-zero if can't seek there. X */ X public int Xch_seek(pos) X register POSITION pos; X{ X long new_block; X X new_block = pos / BUFSIZ; X if (!ispipe || new_block == last_piped_block + 1 || buffered(new_block)) X { X /* X * Set read pointer. X */ X ch_block = new_block; X ch_offset = pos % BUFSIZ; X return (0); X } X return (1); X} X X/* X * Seek to the end of the file. X */ X public int Xch_end_seek() X{ X if (ispipe) X { X /* X * Do it the slow way: read till end of data. X */ X while (ch_forw_get() != EOF) X ; X } else X { X (void) ch_seek((POSITION)(lseek(file, (off_t)0, 2))); X } X return (0); X} X X/* X * Return the length of the file, if known. X */ X public POSITION Xch_length() X{ X if (ispipe) X return (ch_fsize); X return ((POSITION)(lseek(file, (off_t)0, 2))); X} X X/* X * Return the current position in the file. X */ X public POSITION Xch_tell() X{ X return (ch_block * BUFSIZ + ch_offset); X} X X/* X * Get the current char and post-increment the read pointer. X */ X public int Xch_forw_get() X{ X register int c; X X c = ch_get(); X if (c != EOF && ++ch_offset >= BUFSIZ) X { X ch_offset = 0; X ch_block ++; X } X return (c); X} X X/* X * Pre-decrement the read pointer and get the new current char. X */ X public int Xch_back_get() X{ X register int c; X X if (--ch_offset < 0) X { X if (ch_block <= 0 || (ispipe && !buffered(ch_block-1))) X { X ch_offset = 0; X return (EOF); X } X ch_offset = BUFSIZ - 1; X ch_block--; X } X c = ch_get(); X return (c); X} X X/* X * Initialize the buffer pool to all empty. X * Caller suggests that we use want_nbufs buffers. X */ X public void Xch_init(want_nbufs) X int want_nbufs; X{ X register struct buf *bp; X char *calloc(); X X if (nbufs < want_nbufs) X { X /* X * We don't have enough buffers. X * Free what we have (if any) and allocate some new ones. X */ X if (bufs != NULL) X free((char *)bufs); X bufs = (struct buf *) calloc(want_nbufs, sizeof(struct buf)); X nbufs = want_nbufs; X if (bufs == NULL) X { X /* X * Couldn't get that many. X * Try for a small default number of buffers. X */ X char message[80]; X sprintf(message, X "Cannot allocate %d buffers. Using %d buffers.", X nbufs, DEF_NBUFS); X error(message); X bufs = (struct buf *) calloc(DEF_NBUFS, sizeof(struct buf)); X nbufs = DEF_NBUFS; X if (bufs == NULL) X { X /* X * Couldn't even get the smaller number of bufs. X * Something is wrong here, don't continue. X */ X sprintf(message, X "Cannot even allocate %d buffers! Quitting.\n", X DEF_NBUFS); X error(message); X quit(); X /*NOTREACHED*/ X } X } X } X X /* X * Initialize the buffers to empty. X * Set up the circular list. X */ X for (bp = &bufs[0]; bp < &bufs[nbufs]; bp++) X { X bp->next = bp + 1; X bp->prev = bp - 1; X bp->block = (long)(-1); X } X bufs[0].prev = bufs[nbufs-1].next = END_OF_CHAIN; X buf_head = &bufs[0]; X buf_tail = &bufs[nbufs-1]; X last_piped_block = -1; X ch_fsize = NULL_POSITION; X (void) ch_seek((POSITION)0); X} SHAR_EOF if test 6841 -ne "`wc -c < 'ch.c'`" then echo shar: error transmitting "'ch.c'" '(should have been 6841 characters)' fi fi if test -f 'command.c' then echo shar: will not over-write existing file "'command.c'" else echo extracting "'command.c'" sed 's/^X//' >command.c <<'SHAR_EOF' X/* X * User-level command processor. X */ X X#include "less.h" X#include "position.h" X Xextern int erase_char, kill_char; Xextern int pr_type; Xextern int sigs; Xextern int ispipe; Xextern int quit_at_eof; Xextern int hit_eof; Xextern int sc_width, sc_height; Xextern char *first_cmd; Xextern char version[]; Xextern char current_file[]; Xextern char *editor; Xextern int onintr(); X Xstatic char cmdbuf[90]; /* Buffer for holding a multi-char command */ Xstatic char *cp; /* Pointer into cmdbuf */ Xstatic int cmd_col; /* Current column of the multi-char command */ Xstatic char mcc; /* The multi-char command letter (e.g. '/') */ Xstatic char last_mcc; /* The previous mcc */ X X/* X * Reset command buffer (to empty). X */ Xcmd_reset() X{ X cp = cmdbuf; X} X X/* X * Backspace in command buffer. X */ X static int Xcmd_erase() X{ X if (cp == cmdbuf) X /* X * Backspace past beginning of the string: X * this usually means abort the command. X */ X return (1); X X if (control_char(*--cp)) X { X /* X * Erase an extra character, for the carat. X */ X backspace(); X cmd_col--; X } X backspace(); X cmd_col--; X return (0); X} X X/* X * Set up the display to start a new multi-character command. X */ Xstart_mcc() X{ X lower_left(); X clear_eol(); X putc(mcc); X cmd_col = 1; X} X X/* X * Process a single character of a multi-character command, such as X * a number, or the pattern of a search command. X */ X static int Xcmd_char(c) X int c; X{ X if (c == erase_char) X { X if (cmd_erase()) X return (1); X } else if (c == kill_char) X { X /* {{ Could do this faster, but who cares? }} */ X while (cmd_erase() == 0) X ; X } else X { X /* X * Append the character to the string, X * if there is room in the buffer and on the screen. X */ X if (cp < &cmdbuf[sizeof(cmdbuf)-1] && cmd_col < sc_width-3) X { X *cp++ = c; X if (control_char(c)) X { X putc('^'); X cmd_col++; X c = carat_char(c); X } X putc(c); X cmd_col++; X } else X bell(); X } X return (0); X} X X/* X * Return the number currently in the command buffer. X */ X static int Xcmd_int() X{ X *cp = '\0'; X cp = cmdbuf; X return (atoi(cmdbuf)); X} X X/* X * Move the cursor to lower left before executing a command. X * This looks nicer if the command takes a long time before X * updating the screen. X */ X static void Xcmd_exec() X{ X lower_left(); X flush(); X} X X/* X * Display the appropriate prompt. X */ X static void Xprompt() X{ X register char *p; X X if (first_cmd != NULL && *first_cmd != '\0') X /* X * No prompt necessary if commands are from first_cmd X * rather than from the user. X */ X return; X X /* X * Select the proper prompt and display it. X */ X p = pr_string(); X if (p == NULL) X putc(':'); X else X { X so_enter(); X puts(p); X so_exit(); X } X} X X/* X * Get command character. X * The character normally comes from the keyboard, X * but may come from the "first_cmd" string. X */ X static int Xgetcc() X{ X if (first_cmd == NULL) X return (getc()); X X if (*first_cmd == '\0') X { X /* X * Reached end of first_cmd input. X */ X first_cmd = NULL; X if (cp > cmdbuf && position(TOP) == NULL_POSITION) X { X /* X * Command is incomplete, so try to complete it. X * There are only two cases: X * 1. We have "/string" but no newline. Add the \n. X * 2. We have a number but no command. Treat as #g. X * (This is all pretty hokey.) X */ X if (mcc != ':') X return ('\n'); X else X return ('g'); X } X return (getc()); X } X return (*first_cmd++); X} X X/* X * Main command processor. X * Accept and execute commands until a quit command, then return. X */ X public void Xcommands() X{ X register int c; X register int n; X register int scroll = 10; X X mcc = last_mcc = 0; X X for (;;) X { X /* X * Display prompt and accept a character. X */ X/* psignals(); */ /* See if any signals need processing */ X X if (quit_at_eof && hit_eof > 1) X /* X * After hitting end-of-file for the second time, X * automatically advance to the next file. X * If there are no more files, quit. X */ X next_file(1); X X cmd_reset(); X lower_left(); X clear_eol(); X prompt(); X c = getcc(); X X again: X if (sigs) X continue; X X if (mcc) X { X /* X * We are in a multi-character command. X * All chars until newline go into the command buffer. X * (Note that mcc == ':' is a special case that X * means a number is being entered.) X */ X if (mcc != ':' && (c == '\n' || c == '\r')) X { X /* X * Execute the command. X */ X *cp = '\0'; X cmd_exec(); X if (mcc == 'E') X { X char *p; X /* X * Ignore leading spaces X * in the filename. X */ X for (p = cmdbuf; *p == ' '; p++) ; X edit(p); X#if SHELL_ESCAPE X } else if (mcc == '!') X { X lsystem(cmdbuf); X error("!done"); X first_cmd = "r"; /* Repaint */ X#endif X } else X search(mcc, cmdbuf, n); X mcc = 0; X } else X { X if (mcc == ':' && (c < '0' || c > '9') && X c != erase_char && c != kill_char) X { X /* X * This is not part of the number X * we were entering. Process X * it as a regular character. X */ X mcc = 0; X goto again; X } X X /* X * Append the char to the command buffer. X */ X if (cmd_char(c)) X { X /* Abort the multi-char command. */ X mcc = 0; X continue; X } X c = getcc(); X goto again; X } X } else switch (c) X { X case '0': case '1': case '2': case '3': case '4': X case '5': case '6': case '7': case '8': case '9': X /* X * First digit of a number. X */ X mcc = ':'; X start_mcc(); X goto again; X X case 'f': X case ' ': X case CONTROL('F'): X /* X * Forward one screen. X */ X n = cmd_int(); X if (n <= 0) X n = sc_height - 1; X forward(n, 1); X break; X X case 'b': X case CONTROL('B'): X /* X * Backward one screen. X */ X n = cmd_int(); X if (n <= 0) X n = sc_height - 1; X backward(n, 1); X break; X X case 'e': X case 'j': X case '\r': X case '\n': X case CONTROL('E'): X /* X * Forward N (default 1) line. X */ X n = cmd_int(); X if (n <= 0) X n = 1; X forward(n, 0); X break; X X case 'y': X case 'k': X case CONTROL('K'): X case CONTROL('Y'): X /* X * Backward N (default 1) line. X */ X n = cmd_int(); X if (n <= 0) X n = 1; X backward(n, 0); X break; X X case 'd': X case CONTROL('D'): X /* X * Forward N lines X * (default same as last 'd' or 'u' command). X */ X n = cmd_int(); X if (n > 0) X scroll = n; X forward(scroll, 0); X break; X X case 'u': X case CONTROL('U'): X /* X * Forward N lines X * (default same as last 'd' or 'u' command). X */ X n = cmd_int(); X if (n > 0) X scroll = n; X backward(scroll, 0); X break; X X case 'R': X /* X * Flush buffers, then repaint screen. X */ X ch_init(0); X /* Fall thru */ X case 'r': X case CONTROL('R'): X case CONTROL('L'): X /* X * Repaint screen. X */ X repaint(); X break; X X case 'g': X /* X * Go to line N, default beginning of file. X */ X n = cmd_int(); X if (n <= 0) X n = 1; X cmd_exec(); X jump_back(n); X break; X X case 'p': X case '%': X /* X * Go to a specified percentage into the file. X */ X n = cmd_int(); X if (n < 0) X n = 0; X if (n > 100) X n = 100; X cmd_exec(); X jump_percent(n); X break; X X case 'G': X /* X * Go to line N, default end of file. X */ X n = cmd_int(); X cmd_exec(); X if (n <= 0) X jump_forw(); X else X jump_back(n); X break; X X case '=': X case CONTROL('G'): X /* X * Print file name, etc. X */ X error(eq_message()); X break; X X case 'L': X /* Print full prompt, including line number X * of the top line of the screen -- can be X * very slow! X */ X error(eq_mess2()); X break; X X case 'V': X /* X * Print version number, without the "@(#)". X */ X error(version+4); X break; X X case 'q': X case 'Q': X /* X * Exit. X */ X return; X X case '/': X case '?': X /* X * Search for a pattern. X * Accept chars of the pattern until \n. X */ X n = cmd_int(); X if (n <= 0) X n = 1; X mcc = last_mcc = c; X start_mcc(); X c = getcc(); X goto again; X X case 'n': X /* X * Repeat previous search. X */ X n = cmd_int(); X if (n <= 0) X n = 1; X mcc = last_mcc; X start_mcc(); X cmd_exec(); X search(mcc, (char *)NULL, n); X mcc = 0; X break; X X case 'h': X /* X * Help. X */ X help(); X repaint(); X break; X X case 'E': X /* X * Edit a new file. Get the filename. X */ X cmd_reset(); X mcc = 'E'; X start_mcc(); X#ifdef MSDOS X curs_l(1); X puts("Examine: "); X#else X puts("dit: "); /* This looks nicer */ X#endif X cmd_col += 5; X c = getcc(); X goto again; X X#if SHELL_ESCAPE X case '!': X /* X * Shell escape. X */ X cmd_reset(); X mcc = '!'; X start_mcc(); X c = getcc(); X goto again; X#endif X X#if EDITOR X case 'v': X if (ispipe) X { X error("Cannot edit standard input"); X break; X } X sprintf(cmdbuf, "%s %s", editor, current_file); X lsystem(cmdbuf); X first_cmd = "E\n"; X break; X#endif X X case 'N': X /* X * Examine next file. X */ X n = cmd_int(); X if (n <= 0) X n = 1; X next_file(n); X break; X X case 'P': X /* X * Examine previous file. X */ X n = cmd_int(); X if (n <= 0) X n = 1; X prev_file(n); X break; X X case '-': X /* X * Toggle a flag setting. X */ X mcc = '-'; X start_mcc(); X c = getcc(); X mcc = 0; X if (c == erase_char || c == kill_char) X break; X toggle_option(c); X break; X X case 'm': X /* X * Set a mark. X */ X lower_left(); X clear_eol(); X puts("mark: "); X c = getcc(); X if (c == erase_char || c == kill_char) X break; X setmark(c); X break; X X case '\'': X /* X * Go to a mark. X */ X lower_left(); X clear_eol(); X puts("goto mark: "); X c = getcc(); X if (c == erase_char || c == kill_char) X break; X gomark(c); X break; X X default: X bell(); X break; X } X } X} SHAR_EOF if test 9711 -ne "`wc -c < 'command.c'`" then echo shar: error transmitting "'command.c'" '(should have been 9711 characters)' fi fi if test -f 'dos_port.h' then echo shar: will not over-write existing file "'dos_port.h'" else echo extracting "'dos_port.h'" sed 's/^X//' >dos_port.h <<'SHAR_EOF' X/* this file is necessary to handle all the defines for building the program X using Microsoft C. The compiler will not accept them all on the command X line when they are included in the makefile. X */ X#ifdef DOSPORT X#define MSDOS 1 X#define MSC 1 /* only if using Microsoft C compiler */ X#define REGEXP 1 X#define EDITOR 1 X#define EDIT_PGM "memacs" X#define SHELL_ESCAPE 1 X#endif X SHAR_EOF if test 390 -ne "`wc -c < 'dos_port.h'`" then echo shar: error transmitting "'dos_port.h'" '(should have been 390 characters)' fi fi if test -f 'funcs.h' then echo shar: will not over-write existing file "'funcs.h'" else echo extracting "'funcs.h'" sed 's/^X//' >funcs.h <<'SHAR_EOF' X public void edit (); X public void next_file (); X public void prev_file (); X public void quit (); X public void init_option (); X public void toggle_option (); X public void scan_option (); X public void forward (); X public void backward (); X public void repaint (); X public void jump_forw (); X public void jump_back (); X public void jump_percent (); X public void jump_loc (); X public void init_mark (); X public void setmark (); X public void gomark (); X public void search (); X public int ch_seek (); X public int ch_end_seek (); X public POSITION ch_length (); X public POSITION ch_tell (); X public int ch_forw_get (); X public int ch_back_get (); X public void ch_init (); X public POSITION position (); X public void add_forw_pos (); X public void add_back_pos (); X public void pos_clear (); X public int onscreen (); X public POSITION forw_line (); X public POSITION back_line (); X public void put_line (); X public int control_char (); X public int carat_char (); X public void flush (); X public void dropout (); X public void putc (); X public void puts (); X public void error (); X public int error_width (); X public void raw_mode (); X public void get_term (); X public void init (); X public void deinit (); X public void home (); X public void add_line (); X public void lower_left (); X public void bell (); X public void vbell (); X public void clear (); X public void clear_eol (); X public void so_enter (); X public void so_exit (); X public void ul_enter (); X public void ul_exit (); X public void backspace (); X public void putbs (); X public char * eq_message (); X public char * eq_mess2 (); X public char * pr_string (); X public void prewind (); X public int pappend (); X public POSITION forw_raw_line (); X public POSITION back_raw_line (); X public void init_signals (); X public void psignals (); X public void lsystem (); X public void help (); X public void open_getc (); X public int getc (); X public void commands (); SHAR_EOF if test 1900 -ne "`wc -c < 'funcs.h'`" then echo shar: error transmitting "'funcs.h'" '(should have been 1900 characters)' fi fi if test -f 'help.c' then echo shar: will not over-write existing file "'help.c'" else echo extracting "'help.c'" sed 's/^X//' >help.c <<'SHAR_EOF' X#include "less.h" X X/* X * Display some help. X * Help is in two pages. X */ X static void Xhelp0() X{ X puts("f, SPACE Forward one screen.\n"); X puts("b Backward one screen.\n"); X puts("e, j, CR * Forward N lines, default 1.\n"); X puts("y, k * Backward N lines, default 1.\n"); X puts("d * Forward N lines, default 10 or last N to d or u command.\n"); X puts("u * Backward N lines, default 10 or last N to d or u command.\n"); X puts("r Repaint screen.\n"); X puts("g * Go to line N, default 1.\n"); X puts("G * Like g, but default is last line in file.\n"); X puts("= Print current file name\n"); X puts("L Print line number of 1st line -- CAN BE SLOW!\n"); X puts("/pattern * Search forward for N-th occurence of pattern.\n"); X puts("?pattern * Search backward for N-th occurence of pattern.\n"); X puts("n * Repeat previous search (for N-th occurence).\n"); X puts("q Exit.\n"); X error("More help..."); X} X X static void Xhelp1() X{ X char message[100]; X extern char all_options[]; X X puts("R Repaint screen, discarding buffered input.\n"); X puts("p, % * Position to N percent into the file.\n"); X puts("m Mark the current position with .\n"); X puts("' Return to a previously marked position.\n"); X sprintf(message, X "-X Toggle a flag (X may be one of \"%s\").\n", X all_options); X puts(message); X puts("E [file] Examine a new file.\n"); X puts("N Examine the next file (from the command line).\n"); X puts("P Examine the previous file (from the command line).\n"); X puts("V Print version number.\n"); X#if SHELL_ESCAPE X puts("!command Passes the command to a shell to be executed.\n"); X#endif X#if EDITOR X sprintf(message, X "v Edit the current file with $EDITOR (default %s).\n", X EDIT_PGM); X puts(message); X#endif X error(""); X} X X public void Xhelp() X{ X register int i; X X for (i = 0; i < 2; i++) X { X clear(); X puts("Commands marked with * may be preceeded by a number, N.\n\n"); X X switch (i) X { X case 0: help0(); break; X case 1: help1(); break; X } X } X} SHAR_EOF if test 2235 -ne "`wc -c < 'help.c'`" then echo shar: error transmitting "'help.c'" '(should have been 2235 characters)' fi fi if test -f 'input.c' then echo shar: will not over-write existing file "'input.c'" else echo extracting "'input.c'" sed 's/^X//' >input.c <<'SHAR_EOF' X/* X * High level routines dealing with getting lines of input X * from the file being viewed. X * X * When we speak of "lines" here, we mean PRINTABLE lines; X * lines processed with respect to the screen width. X * We use the term "raw line" to refer to lines simply X * delimited by newlines; not processed with respect to screen width. X */ X X#include "less.h" X Xextern int do_bs; Xextern int squeeze; Xextern char *line; X X/* X * Get the next line. X * A "current" position is passed and a "new" position is returned. X * The current position is the position of the first character of X * a line. The new position is the position of the first character X * of the NEXT line. The line obtained is the line starting at curr_pos. X */ X public POSITION Xforw_line(curr_pos) X POSITION curr_pos; X{ X POSITION new_pos; X register int c; X X if (curr_pos == NULL_POSITION || ch_seek(curr_pos)) X return (NULL_POSITION); X X c = ch_forw_get(); X if (c == EOF) X return (NULL_POSITION); X X prewind(); X for (;;) X { X if (c == '\n' || c == EOF) X { X /* X * End of the line. X */ X new_pos = ch_tell(); X break; X } X X /* X * Append the char to the line and get the next char. X */ X if (pappend(c)) X { X /* X * The char won't fit in the line; the line X * is too long to print in the screen width. X * End the line here. X */ X new_pos = ch_tell() - 1; X break; X } X c = ch_forw_get(); X } X (void) pappend('\0'); X X if (squeeze && *line == '\0') X { X /* X * This line is blank. X * Skip down to the last contiguous blank line X * and pretend it is the one which we are returning. X */ X while ((c = ch_forw_get()) == '\n') X ; X if (c != EOF) X (void) ch_back_get(); X new_pos = ch_tell(); X } X X return (new_pos); X} X X/* X * Get the previous line. X * A "current" position is passed and a "new" position is returned. X * The current position is the position of the first character of X * a line. The new position is the position of the first character X * of the PREVIOUS line. The line obtained is the one starting at new_pos. X */ X public POSITION Xback_line(curr_pos) X POSITION curr_pos; X{ X POSITION new_pos, begin_new_pos; X int c; X X if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 || X ch_seek(curr_pos-1)) X return (NULL_POSITION); X X if (squeeze) X { X /* X * Find out if the "current" line was blank. X */ X (void) ch_forw_get(); /* Skip the newline */ X c = ch_forw_get(); /* First char of "current" line */ X (void) ch_back_get(); /* Restore our position */ X (void) ch_back_get(); X X if (c == '\n') X { X /* X * The "current" line was blank. X * Skip over any preceeding blank lines, X * since we skipped them in forw_line(). X */ X while ((c = ch_back_get()) == '\n') X ; X if (c == EOF) X return (NULL_POSITION); X (void) ch_forw_get(); X } X } X X /* X * Scan backwards until we hit the beginning of the line. X */ X for (;;) X { X c = ch_back_get(); X if (c == '\n') X { X /* X * This is the newline ending the previous line. X * We have hit the beginning of the line. X */ X new_pos = ch_tell() + 1; X break; X } X if (c == EOF) X { X /* X * We have hit the beginning of the file. X * This must be the first line in the file. X * This must, of course, be the beginning of the line. X */ X new_pos = (POSITION)0; X break; X } X } X X /* X * Now scan forwards from the beginning of this line. X * We keep discarding "printable lines" (based on screen width) X * until we reach the curr_pos. X * X * {{ This algorithm is pretty inefficient if the lines X * are much longer than the screen width, X * but I don't know of any better way. }} X */ X if (ch_seek(new_pos)) X return (NULL_POSITION); X loop: X begin_new_pos = new_pos; X prewind(); X X do X { X c = ch_forw_get(); X new_pos++; X if (c == '\n') X break; X if (pappend(c)) X { X /* X * Got a full printable line, but we haven't X * reached our curr_pos yet. Discard the line X * and start a new one. X */ X (void) pappend('\0'); X (void) ch_back_get(); X new_pos--; X goto loop; X } X } while (new_pos < curr_pos); X X (void) pappend('\0'); X X return (begin_new_pos); X} SHAR_EOF if test 4079 -ne "`wc -c < 'input.c'`" then echo shar: error transmitting "'input.c'" '(should have been 4079 characters)' fi fi if test -f 'less.h' then echo shar: will not over-write existing file "'less.h'" else echo extracting "'less.h'" sed 's/^X//' >less.h <<'SHAR_EOF' X/* X * Standard include file for "less". X */ X X/* X * To get the required defs when porting less to msdos X */ X#ifdef DOSPORT X#include "dos_port.h" X#endif X X/* X * Language details. X */ X#if !VOID X#define void int X#endif X#define public /* PUBLIC FUNCTION */ X X/* X * Special types and constants. X */ Xtypedef long POSITION; X/* X * {{ Warning: if POSITION is changed to other than "long", X * you may have to change some of the printfs which use "%ld" X * to print a variable of type POSITION. }} X */ X X#define END_POSITION ((POSITION)(-2)) X#define NULL_POSITION ((POSITION)(-1)) X X#define EOF (0) X#define NULL (0) X X/* How quiet should we be? */ X#define NOT_QUIET 0 /* Ring bell at eof and for errors */ X#define LITTLE_QUIET 1 /* Ring bell only for errors */ X#define VERY_QUIET 2 /* Never ring bell */ X X/* How should we prompt? */ X#define PR_SHORT 0 /* Prompt with colon */ X#define PR_MEDIUM 1 /* Prompt with message */ X#define PR_LONG 2 /* Prompt with longer message */ X X/* How should we handle backspaces? */ X#define BS_UNDERLINE 0 /* Underlining converted to underline mode */ X#define BS_NORMAL 1 /* \b treated as normal char; actually output */ X#define BS_CONTROL 2 /* \b treated as control char; prints as ^H */ X X/* Flag to eq_message() telling what to put in the message */ X#define MNAME 001 /* File name */ X#define MOF 002 /* "file x of y" */ X#define MBYTE 004 /* "byte x/y" */ X#define MPCT 010 /* Percentage into the file */ X X/* Special chars used to tell put_line() to do something special */ X#define UL_CHAR '\201' /* Enter underline mode */ X#define UE_CHAR '\202' /* Exit underline mode */ X#define BO_CHAR '\203' /* Enter boldface mode */ X#define BE_CHAR '\204' /* Exit boldface mode */ X X#define CONTROL(c) ((c)&037) X#define SIGNAL(sig,func) signal(sig,func) X X/* Must locate the typedef of off_t in the Microsoft package. If using X * a different compiler --- typedef long off_t ---. X */ X X#ifdef MSDOS X#ifdef MSC /* Microsoft's types.h is needed */ X#endif X#endif X Xtypedef long off_t; Xextern off_t lseek(); X X#include "funcs.h" X SHAR_EOF if test 2051 -ne "`wc -c < 'less.h'`" then echo shar: error transmitting "'less.h'" '(should have been 2051 characters)' fi fi if test -f 'less.prj' then echo shar: will not over-write existing file "'less.prj'" else echo extracting "'less.prj'" sed 's/^X//' >less.prj <<'SHAR_EOF' XCH.C (dos_port.h funcs.h less.h) XCOMMAND.C (dos_port.h funcs.h less.h position.h) XHELP.C (dos_port.h funcs.h less.h) XINPUT.C (dos_port.h funcs.h less.h) XLINE.C (dos_port.h funcs.h less.h) XMAIN.C (dos_port.h funcs.h less.h position.h) XOPTION.C (dos_port.h funcs.h less.h) XOUTPUT.C (dos_port.h funcs.h less.h scrn.h) XPOSITION.C (dos_port.h funcs.h less.h position.h) XPRIM.C (dos_port.h funcs.h less.h position.h) XPROMPT.C (dos_port.h funcs.h less.h position.h) XREGERROR.C XREGEXP.C (regexp.h regmagic.h) XSCRN.C (scrn.h) XSETARGV.C XSIGNAL.C (dos_port.h funcs.h less.h) XTTYIN.C (dos_port.h funcs.h less.h) XVERSION.C SHAR_EOF if test 610 -ne "`wc -c < 'less.prj'`" then echo shar: error transmitting "'less.prj'" '(should have been 610 characters)' fi fi if test -f 'line.c' then echo shar: will not over-write existing file "'line.c'" else echo extracting "'line.c'" sed 's/^X//' >line.c <<'SHAR_EOF' X/* X * Routines to manipulate the "line buffer". X * The line buffer holds a line of output as it is being built X * in preparation for output to the screen. X * We keep track of the PRINTABLE length of the line as it is being built. X */ X X#include "less.h" X Xstatic char linebuf[1024]; /* Buffer which holds the current output line */ Xstatic char *curr; /* Pointer into linebuf */ Xstatic int column; /* Printable length, accounting for X backspaces, etc. */ X/* X * A ridiculously complex state machine takes care of backspaces X * when in BS_SPECIAL mode. The complexity arises from the attempt X * to deal with all cases, especially involving long lines with underlining, X * boldfacing or whatever. There are still some cases which will break it. X * X * There are four states: X * LN_NORMAL is the normal state (not in underline mode). X * LN_UNDERLINE means we are in underline mode. We expect to get X * either a sequence like "_\bX" or "X\b_" to continue X * underline mode, or anything else to end underline mode. X * LN_BOLDFACE means we are in boldface mode. We expect to get sequences X * like "X\bX\b...X\bX" to continue boldface mode, or anything X * else to end boldface mode. X * LN_UL_X means we are one character after LN_UNDERLINE X * (we have gotten the '_' in "_\bX" or the 'X' in "X\b_"). X * LN_UL_XB means we are one character after LN_UL_X X * (we have gotten the backspace in "_\bX" or "X\b_"; X * we expect one more ordinary character, X * which will put us back in state LN_UNDERLINE). X * LN_BO_X means we are one character after LN_BOLDFACE X * (we have gotten the 'X' in "X\bX"). X * LN_BO_XB means we are one character after LN_BO_X X * (we have gotten the backspace in "X\bX"; X * we expect one more 'X' which will put us back X * in LN_BOLDFACE). X */ Xstatic int ln_state; /* Currently in normal/underline/bold/etc mode? */ X#define LN_NORMAL 0 /* Not in underline, boldface or whatever mode */ X#define LN_UNDERLINE 1 /* In underline, need next char */ X#define LN_UL_X 2 /* In underline, got char, need \b */ X#define LN_UL_XB 3 /* In underline, got char & \b, need one more */ X#define LN_BOLDFACE 4 /* In boldface, need next char */ X#define LN_BO_X 5 /* In boldface, got char, need \b */ X#define LN_BO_XB 6 /* In boldface, got char & \b, need same char */ X Xpublic char *line; /* Pointer to the current line. X Usually points to linebuf. */ X Xextern int bs_mode; Xextern int tabstop; Xextern int bo_width, be_width; Xextern int ul_width, ue_width; Xextern int sc_width, sc_height; X X/* X * Rewind the line buffer. X */ X public void Xprewind() X{ X line = curr = linebuf; X ln_state = LN_NORMAL; X column = 0; X} X X/* X * Append a character to the line buffer. X * Expand tabs into spaces, handle underlining, boldfacing, etc. X * Returns 0 if ok, 1 if couldn't fit in buffer. X */ X X#define NEW_COLUMN(newcol) if ((newcol) + ((ln_state)?ue_width:0) > sc_width) \ X return (1); else column = (newcol) X X public int Xpappend(c) X int c; X{ X if (c == '\0') X { X /* X * Terminate any special modes, if necessary. X * Append a '\0' to the end of the line. X */ X switch (ln_state) X { X case LN_UL_X: X curr[0] = curr[-1]; X curr[-1] = UE_CHAR; X curr++; X break; X case LN_BO_X: X curr[0] = curr[-1]; X curr[-1] = BE_CHAR; X curr++; X break; X case LN_UL_XB: X case LN_UNDERLINE: X *curr++ = UE_CHAR; X break; X case LN_BO_XB: X case LN_BOLDFACE: X *curr++ = BE_CHAR; X break; X } X ln_state = LN_NORMAL; X *curr = '\0'; X return (0); X } X X if (curr > linebuf + sizeof(linebuf) - 12) X /* X * Almost out of room in the line buffer. X * Don't take any chances. X * {{ Linebuf is supposed to be big enough that this X * will never happen, but may need to be made X * bigger for wide screens or lots of backspaces. }} X */ X return (1); X X if (bs_mode == BS_UNDERLINE) X { X /* X * Advance the state machine. X */ X switch (ln_state) X { X case LN_NORMAL: X if (curr <= linebuf + 1 || curr[-1] != '\b') X break; X X if (c == curr[-2]) X goto enter_boldface; X if (c == '_' || curr[-2] == '_') X goto enter_underline; X curr -= 2; X break; X Xenter_boldface: X /* X * We have "X\bX" (including the current char). X * Switch into boldface mode. X */ X if (column + bo_width + be_width + 1 >= sc_width) X /* X * Not enough room left on the screen to X * enter and exit boldface mode. X */ X return (1); X X if (bo_width > 0 && X curr > linebuf + 2 && curr[-3] == ' ') X { X /* X * Special case for magic cookie terminals: X * if the previous char was a space, replace X * it with the "enter boldface" sequence. X */ X curr[-3] = BO_CHAR; X column += bo_width-1; X } else X { X curr[-1] = curr[-2]; X curr[-2] = BO_CHAR; X column += bo_width; X curr++; X } X goto ln_bo_xb_case; X Xenter_underline: X /* X * We have either "_\bX" or "X\b_" (including X * the current char). Switch into underline mode. X */ X if (column + ul_width + ue_width + 1 >= sc_width) X /* X * Not enough room left on the screen to X * enter and exit underline mode. X */ X return (1); X X if (ul_width > 0 && X curr > linebuf + 2 && curr[-3] == ' ') X { X /* X * Special case for magic cookie terminals: X * if the previous char was a space, replace X * it with the "enter underline" sequence. X */ X curr[-3] = UL_CHAR; X column += ul_width-1; X } else X { X curr[-1] = curr[-2]; X curr[-2] = UL_CHAR; X column += ul_width; X curr++; X } X goto ln_ul_xb_case; X /*NOTREACHED*/ X case LN_UL_XB: X /* X * Termination of a sequence "_\bX" or "X\b_". X */ X if (c != '_' && curr[-2] != '_' && c == curr[-2]) X { X /* X * We seem to have run on from underlining X * into boldfacing - this is a nasty fix, but X * until this whole routine is rewritten as a X * real DFA, ... well ... X */ X curr[0] = curr[-2]; X curr[-2] = UE_CHAR; X curr[-1] = BO_CHAR; X curr += 2; /* char & non-existent backspace */ X ln_state = LN_BO_XB; X goto ln_bo_xb_case; X } Xln_ul_xb_case: X if (c == '_') X c = curr[-2]; X curr -= 2; X ln_state = LN_UNDERLINE; X break; X case LN_BO_XB: X /* X * Termination of a sequnce "X\bX". X */ X if (c != curr[-2] && (c == '_' || curr[-2] == '_')) X { X /* X * We seem to have run on from X * boldfacing into underlining. X */ X curr[0] = curr[-2]; X curr[-2] = BE_CHAR; X curr[-1] = UL_CHAR; X curr += 2; /* char & non-existent backspace */ X ln_state = LN_UL_XB; X goto ln_ul_xb_case; X } Xln_bo_xb_case: X curr -= 2; X ln_state = LN_BOLDFACE; X break; X case LN_UNDERLINE: X if (column + ue_width + bo_width + 1 + be_width >= sc_width) X /* X * We have just barely enough room to X * exit underline mode and handle a possible X * underline/boldface run on mixup. X */ X return (1); X ln_state = LN_UL_X; X break; X case LN_BOLDFACE: X if (c == '\b') X { X ln_state = LN_BO_XB; X break; X } X if (column + be_width + ul_width + 1 + ue_width >= sc_width) X /* X * We have just barely enough room to X * exit underline mode and handle a possible X * underline/boldface run on mixup. X */ X return (1); X ln_state = LN_BO_X; X break; X case LN_UL_X: X if (c == '\b') X ln_state = LN_UL_XB; X else X { X /* X * Exit underline mode. X * We have to shuffle the chars a bit X * to make this work. X */ X curr[0] = curr[-1]; X curr[-1] = UE_CHAR; X column += ue_width; X if (ue_width > 0 && curr[0] == ' ') X /* X * Another special case for magic X * cookie terminals: if the next X * char is a space, replace it X * with the "exit underline" sequence. X */ X column--; X else X curr++; X ln_state = LN_NORMAL; X } X break; X case LN_BO_X: X if (c == '\b') X ln_state = LN_BO_XB; X else X { X /* X * Exit boldface mode. X * We have to shuffle the chars a bit X * to make this work. X */ X curr[0] = curr[-1]; X curr[-1] = BE_CHAR; X column += be_width; X if (be_width > 0 && curr[0] == ' ') X /* X * Another special case for magic X * cookie terminals: if the next X * char is a space, replace it X * with the "exit boldface" sequence. X */ X column--; X else X curr++; X ln_state = LN_NORMAL; X } X break; X } X } X X if (c == '\t') X { X /* X * Expand a tab into spaces. X */ X do X { X NEW_COLUMN(column+1); X } while ((column % tabstop) != 0); X *curr++ = '\t'; X return (0); X } X X if (c == '\b') X { X if (bs_mode == BS_CONTROL) X { X /* X * Treat backspace as a control char: output "^H". X */ X NEW_COLUMN(column+2); X *curr++ = ('H' | 0200); X } else X { X /* X * Output a real backspace. X */ X column--; X *curr++ = '\b'; X } X return (0); X } X X if (control_char(c)) X { X /* X * Put a "^X" into the buffer. X * The 0200 bit is used to tell put_line() to prefix X * the char with a ^. We don't actually put the ^ X * in the buffer because we sometimes need to move X * chars around, and such movement might separate X * the ^ from its following character. X * {{ This should be redone so that we can use an X * 8 bit (e.g. international) character set. }} X */ X NEW_COLUMN(column+2); X *curr++ = (carat_char(c) | 0200); X return (0); X } X X /* X * Ordinary character. Just put it in the buffer. X */ X NEW_COLUMN(column+1); X *curr++ = c; X return (0); X} X X/* X * Analogous to forw_line(), but deals with "raw lines": X * lines which are not split for screen width. X * {{ This is supposed to be more efficient than forw_line(). }} X */ X public POSITION Xforw_raw_line(curr_pos) X POSITION curr_pos; X{ X register char *p; X register int c; X POSITION new_pos; X X if (curr_pos == NULL_POSITION || ch_seek(curr_pos) || X (c = ch_forw_get()) == EOF) X return (NULL_POSITION); X X p = linebuf; X X for (;;) X { X if (c == '\n' || c == EOF) X { X new_pos = ch_tell(); X break; X } X if (p >= &linebuf[sizeof(linebuf)-1]) X { X /* X * Overflowed the input buffer. X * Pretend the line ended here. X * {{ The line buffer is supposed to be big X * enough that this never happens. }} X */ X new_pos = ch_tell() - 1; X break; X } X *p++ = c; X c = ch_forw_get(); X } X *p = '\0'; X line = linebuf; X return (new_pos); X} X X/* X * Analogous to back_line(), but deals with "raw lines". X * {{ This is supposed to be more efficient than back_line(). }} X */ X public POSITION Xback_raw_line(curr_pos) X POSITION curr_pos; X{ X register char *p; X register int c; X POSITION new_pos; X X if (curr_pos == NULL_POSITION || curr_pos <= (POSITION)0 || X ch_seek(curr_pos-1)) X return (NULL_POSITION); X X p = &linebuf[sizeof(linebuf)]; X *--p = '\0'; X X for (;;) X { X c = ch_back_get(); X if (c == '\n') X { X /* X * This is the newline ending the previous line. X * We have hit the beginning of the line. X */ X new_pos = ch_tell() + 1; X break; X } X if (c == EOF) X { X /* X * We have hit the beginning of the file. X * This must be the first line in the file. X * This must, of course, be the beginning of the line. X */ X new_pos = (POSITION)0; X break; X } X if (p <= linebuf) X { X /* X * Overflowed the input buffer. X * Pretend the line ended here. X */ X new_pos = ch_tell() + 1; X break; X } X *--p = c; X } X line = p; X return (new_pos); X} SHAR_EOF if test 11264 -ne "`wc -c < 'line.c'`" then echo shar: error transmitting "'line.c'" '(should have been 11264 characters)' fi fi if test -f 'setargv.c' then echo shar: will not over-write existing file "'setargv.c'" else echo extracting "'setargv.c'" sed 's/^X//' >setargv.c <<'SHAR_EOF' X/* setargv -- setup argv with wild card expansion */ X/* copyright 1987 Michael M Rubenstein */ X X/* This program may be freely distributed provided no fee is assessed. */ X X/* This file implements wild card expansion in argv for Turbo C 1.5. */ X/* Strings of characters in either quotes (") or appostrophes (') on the */ X/* command line are considered a single argument. However, backslash */ X/* escapes are not implemented. A quote may be included in an argument */ X/* which is enclosed in appostrophes and an appostrophe may be included */ X/* in an argument enclosed in quotes. Either may be included as an */ X/* in an argument starting with any other character. */ X X/* Any argument which is not enclosed in quotes or appostrophes, does not */ X/* begin with a hyphen (-), and which contains an asterisk (*) or question */ X/* mark (?) will be expanded. It is NOT an error for an argument to have a */ X/* null expansion (no matching files). Only ordinary files (not */ X/* directories or hidden or system files) will be included in the */ X/* expansion. */ X X/* To use this function, simply compile it with the appropriate memory */ X/* model and include in the link. This can be accomplished very simply */ X/* in the integrated environment by simply including this file in the */ X/* project file. In the command line version, simply include this file */ X/* (or a precompiled .OBJ version) on the command line. */ X X#include X#include X#include X#include X X#define FALSE 0 X#define TRUE 1 X Xvoid putarg(unsigned char far *, unsigned char far *); X Xextern int _argc; /* NB: for TC 1.0, change to __argc */ Xextern char **_argv; /* NB: for TC 1.0, change to __argv */ Xextern unsigned _psp; Xextern unsigned _envseg; Xextern unsigned _envLng; Xextern unsigned char _osmajor; Xextern void _abort(); Xextern char *sbrk(int); X Xvoid _setargv() X{ X unsigned char far *cmdtail; X unsigned char *firstarg; X unsigned char far *cmdarg; X int wild; X int c; X unsigned char buffer[129]; X unsigned char *p, *q; X unsigned char *lastdir; X char **wargv; X int i; X struct ffblk ffb; X X cmdtail = MK_FP(_psp, 0x81); X cmdtail[cmdtail[-1]] = '\0'; /* make sure null at end */ X firstarg = (unsigned char *) sbrk(0); X _argc = 1; X X while (*cmdtail != '\0') X { X /* skip white space */ X while (isascii(*cmdtail) && isspace(*cmdtail)) X ++cmdtail; X X /* done with command loop if end of command tail */ X if (*cmdtail == '\0') X break; X X /* if quoted string, just save the argument */ X if ((c = *cmdtail) == '"' || c == '\'') X { X cmdarg = ++cmdtail; X while (*cmdtail != c && *cmdtail != '\0') X ++cmdtail; X putarg(cmdarg, cmdtail); X if (*cmdtail != '\0') X ++cmdtail; X continue; X } X X /* find word */ X cmdarg = cmdtail; X wild = FALSE; X p = lastdir = buffer; X while ((c = *cmdtail) != '\0' X && (!isascii(c) || !isspace(c))) X { X /* wild is TRUE if word contains * or ? */ X wild |= (c == '*' || c == '?'); X/* Next line was added to make the treatment of / and \ alike */ X if (c == '/') c = '\\'; X *(p++) = c; X X /* lastdir points to the first character of the base file name */ X if (c == '\\' || c == ':') X lastdir = p; X ++cmdtail; X } X *p = '\0'; X X if (wild && *cmdarg != '-') X for (c = findfirst((char *) buffer, &ffb, 0); X c == 0; X c = findnext(&ffb)) X { X /* use lower case for wild card expanded names (my prejudice) */ X for (p = lastdir, q = (unsigned char *) ffb.ff_name; *q != '\0';) X *(p++) = tolower(*(q++)); X ; X putarg(buffer, p); X } X else X putarg(cmdarg, cmdtail); X } X X /* allocate argv */ X if ((wargv = (char **) sbrk(sizeof(char *) * (_argc + 1))) == (char **) -1) X abort(); X _argv = wargv; X X /* store program name */ X if (_osmajor < 3) X *(wargv++) = "C"; X else X { X cmdtail = cmdarg = MK_FP(_envseg, _envLng + 2); X# if defined(__TINY__) || defined(__SMALL__) || defined(__MEDIUM__) X *(wargv++) = sbrk(0); X while (*cmdtail != '\0') X ++cmdtail; X putarg(cmdarg, cmdtail); X --_argc; X# else X *(wargv++) = (char *) cmdarg; X# endif X } X X /* store arguments */ X for (i = _argc; --i;) X { X *(wargv++) = (char *) firstarg; X while(*++firstarg != '\0') X ; X ++firstarg; X } X *wargv = (char *) 0; X} X Xstatic void putarg(from, to) X unsigned char far *from, far *to; X{ X char *p; X X if ((p = sbrk(to - from + 1)) == (char *) -1) X abort(); X while (from < to) X *(p++) = *(from++); X *p = '\0'; X ++_argc; X} SHAR_EOF if test 5142 -ne "`wc -c < 'setargv.c'`" then echo shar: error transmitting "'setargv.c'" '(should have been 5142 characters)' fi fi # end of shell archive exit 0 --- No warranties whatsoever. Mike Slomin !bellcore!lcuxa!mike2