housel@en.ecn.purdue.edu (Peter S. Housel) (11/29/88)
The 'more' program distributed with the BSD 4.3-Tahoe Unix release is marked as freely redistributable, and didn't require much hacking to adapt for Minix. Among its advantages: - The source is not nearly as large as the 'less' source. (140K of 'less' source didn't seem worth the effort to me to transfer it at 1200 baud.) - It only requires about twice what the Minix 'more' takes up in memory (about 40K). - It starts up faster than the Minix 'more'. (Don't know why this is.) - All the usual features - percentages, underlining/standout, backing up, regular expression searches, skipping forwards/backwards, next/previous file, starting up 'vi' (if you have such a thing), a help file, etc. - I'm used to it. You probably are too. The version included here will still compile under BSD, and will probably work on most V7 or SysV machines. When installing, be sure to put 'more.help' in /usr/lib. Also make sure 'varargs.h' is in /usr/include. Except for the last two lines, which I added, it is the same as the one in EFTH Minix report #47. The file 'regcompat.c' will work for any programs using the BSD regular expression routines when all you have is Henry Spencer's regexp(3) routines. Also included here is a version of 'mkdep' for Minix. This is actually a merged version based on the Berkeley version and Chris Torek's 'getdep'. He posted both of these to comp.unix.questions this summer. Enjoy! -Peter S. Housel- housel@en.ecn.purdue.edu ...!pur-ee!housel -------------------------------------------------------------------------- #!/bin/sh echo 'x - Makefile' sed 's/^X//' <<'**-Makefile-EOF-**' >Makefile X# X# Copyright (c) 1988 Regents of the University of California. X# All rights reserved. X# X# Redistribution and use in source and binary forms are permitted X# provided that the above copyright notice and this paragraph are X# duplicated in all such forms and that any documentation, X# advertising materials, and other materials related to such X# distribution and use acknowledge that the software was developed X# by the University of California, Berkeley. The name of the X# University may not be used to endorse or promote products derived X# from this software without specific prior written permission. X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X# X# @(#)Makefile 5.5 (Berkeley) 6/29/88 X# XCFLAGS= -DMINIX XLIBC= /usr/lib/libc.a XSRCS= more.c regcompat.c tcvars.c XOBJS= more.s regcompat.s tcvars.s X Xall: more X Xmore: ${OBJS} ${LIBC} X ${CC} -o $@ ${CFLAGS} ${OBJS} -ltermcap X chmem =4096 $@ X Xclean: FRC X rm -f ${OBJS} core more X Xdepend: FRC X mkdep ${CFLAGS} ${SRCS} X Xinstall: FRC X install -s -o bin -g bin -m 755 more ${DESTDIR}/usr/ucb/more X rm -f ${DESTDIR}/usr/ucb/page X ln ${DESTDIR}/usr/ucb/more ${DESTDIR}/usr/ucb/page X install -c -o bin -g bin -m 644 more.help ${DESTDIR}/usr/lib/more.help X Xlint: FRC X lint ${CFLAGS} ${SRCS} X Xtags: FRC X ctags ${SRCS} X XFRC: X X# DO NOT DELETE THIS LINE -- mkdep uses it. X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. X Xmore.s: /usr/include/a.out.h Xmore.s: /usr/include/ctype.h Xmore.s: /usr/include/errno.h Xmore.s: /usr/include/limits.h Xmore.s: /usr/include/setjmp.h Xmore.s: /usr/include/sgtty.h Xmore.s: /usr/include/signal.h Xmore.s: /usr/include/stdio.h Xmore.s: /usr/include/sys/stat.h Xmore.s: /usr/include/varargs.h Xmore.s: more.c Xregcompat.s: /usr/include/regexp.h Xregcompat.s: /usr/include/stdio.h Xregcompat.s: regcompat.c Xtcvars.s: tcvars.c X X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY **-Makefile-EOF-** echo 'x - Makefile.BSD' sed 's/^X//' <<'**-Makefile.BSD-EOF-**' >Makefile.BSD X# X# Copyright (c) 1988 Regents of the University of California. X# All rights reserved. X# X# Redistribution and use in source and binary forms are permitted X# provided that the above copyright notice and this paragraph are X# duplicated in all such forms and that any documentation, X# advertising materials, and other materials related to such X# distribution and use acknowledge that the software was developed X# by the University of California, Berkeley. The name of the X# University may not be used to endorse or promote products derived X# from this software without specific prior written permission. X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X# X# @(#)Makefile 5.5 (Berkeley) 6/29/88 X# XCFLAGS= -O XLIBC= /lib/libc.a XSRCS= more.c XOBJS= more.o X Xall: more X Xmore: ${OBJS} ${LIBC} X ${CC} -o $@ ${CFLAGS} ${OBJS} -ltermcap X Xclean: FRC X rm -f ${OBJS} core more X Xdepend: FRC X mkdep ${CFLAGS} ${SRCS} X Xinstall: FRC X install -s -o bin -g bin -m 755 more ${DESTDIR}/usr/ucb/more X rm -f ${DESTDIR}/usr/ucb/page X ln ${DESTDIR}/usr/ucb/more ${DESTDIR}/usr/ucb/page X install -c -o bin -g bin -m 644 more.help ${DESTDIR}/usr/lib/more.help X Xlint: FRC X lint ${CFLAGS} ${SRCS} X Xtags: FRC X ctags ${SRCS} X XFRC: X X# DO NOT DELETE THIS LINE -- mkdep uses it. X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. X Xmore.o: more.c /usr/include/stdio.h /usr/include/sys/param.h Xmore.o: /usr/include/sys/types.h /usr/include/signal.h Xmore.o: /usr/include/machine/trap.h /usr/include/machine/machparam.h Xmore.o: /usr/include/machine/endian.h /usr/include/ctype.h Xmore.o: /usr/include/signal.h /usr/include/errno.h /usr/include/sgtty.h Xmore.o: /usr/include/sys/ioctl.h /usr/include/sys/ttychars.h Xmore.o: /usr/include/sys/ttydev.h /usr/include/setjmp.h /usr/include/sys/stat.h Xmore.o: /usr/include/sys/file.h /usr/include/a.out.h /usr/include/sys/exec.h Xmore.o: /usr/include/varargs.h X X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY **-Makefile.BSD-EOF-** echo 'x - more.c' sed 's/^X//' <<'**-more.c-EOF-**' >more.c X/* X * Copyright (c) 1980 Regents of the University of California. X * All rights reserved. X * X * Redistribution and use in source and binary forms are permitted X * provided that the above copyright notice and this paragraph are X * duplicated in all such forms and that any documentation, X * advertising materials, and other materials related to such X * distribution and use acknowledge that the software was developed X * by the University of California, Berkeley. The name of the X * University may not be used to endorse or promote products derived X * from this software without specific prior written permission. X * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X */ X X#ifndef lint Xchar copyright[] = X"@(#) Copyright (c) 1980 Regents of the University of California.\n\ X All rights reserved.\n"; X#endif /* not lint */ X X#ifndef lint Xstatic char sccsid[] = "@(#)more.c 5.19 (Berkeley) 6/29/88"; X#endif /* not lint */ X X/* X** more.c - General purpose tty output filter and file perusal program X** X** by Eric Shienbrood, UC Berkeley X** X** modified by Geoff Peck, UCB to add underlining, single spacing X** modified by John Foderaro, UCB to add -c and MORE environment variable X*/ X X#include <stdio.h> X#include <ctype.h> X#include <signal.h> X#include <errno.h> X#include <sgtty.h> X#include <setjmp.h> X#include <sys/stat.h> X#ifndef MINIX X#include <sys/param.h> X#include <sys/file.h> X#endif X#include <a.out.h> X#include <varargs.h> X X#ifdef MINIX X#include <limits.h> X#endif MINIX X X#define HELPFILE "/usr/lib/more.help" X#define VI "/usr/ucb/vi" X X#define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) X#define Ftell(f) file_pos X#define Fseek(f,off) (file_pos=off,fseek(f,off,0)) X#define Getc(f) (++file_pos, getc(f)) X#define Ungetc(c,f) (--file_pos, ungetc(c,f)) X X#ifndef TIOCSETN X#define TIOCSETN TIOCSETP /* Minix doesn't have SETN */ X#endif X#ifndef TBDELAY X#define TBDELAY 0006000 /* Minix doesn't have TBDELAY */ X#endif X X#define MBIT CBREAK X#define stty(fd,argp) ioctl(fd,TIOCSETN,argp) X X#define TBUFSIZ 1024 X#define LINSIZ 256 X#define ctrl(letter) (letter & 077) X#define RUBOUT '\177' X#define ESC '\033' X#define QUIT '\034' X Xstruct sgttyb otty, savetty; Xlong file_pos, file_size; Xint fnum, no_intty, no_tty, slow_tty; Xint dum_opt, dlines, onquit(), end_it(), chgwinsz(); Xint onsusp(); Xint nscroll = 11; /* Number of lines scrolled by 'd' */ Xint fold_opt = 1; /* Fold long lines */ Xint stop_opt = 1; /* Stop after form feeds */ Xint ssp_opt = 0; /* Suppress white space */ Xint ul_opt = 1; /* Underline as best we can */ Xint promptlen; Xint Currline; /* Line we are currently at */ Xint startup = 1; Xint firstf = 1; Xint notell = 1; Xint docrterase = 0; Xint docrtkill = 0; Xint bad_so; /* True if overwriting does not turn off standout */ Xint inwait, Pause, errors; Xint within; /* true if we are within a file, X false if we are between files */ Xint hard, dumb, noscroll, hardtabs, clreol, eatnl; Xint catch_susp; /* We should catch the SIGTSTP signal */ Xchar **fnames; /* The list of file names */ Xint nfiles; /* Number of files left to process */ Xchar *shell; /* The name of the shell to use */ Xint shellp; /* A previous shell command exists */ Xchar ch; Xjmp_buf restore; Xchar Line[LINSIZ]; /* Line buffer */ Xint Lpp = 24; /* lines per page */ Xchar *Clear; /* clear screen */ Xchar *eraseln; /* erase line */ Xchar *Senter, *Sexit;/* enter and exit standout mode */ Xchar *ULenter, *ULexit; /* enter and exit underline mode */ Xchar *chUL; /* underline character */ Xchar *chBS; /* backspace character */ Xchar *Home; /* go to home */ Xchar *cursorm; /* cursor movement */ Xchar cursorhome[40]; /* contains cursor movement to home */ Xchar *EodClr; /* clear rest of screen */ Xchar *tgetstr(); Xint Mcol = 80; /* number of columns */ Xint Wrap = 1; /* set if automargins */ Xint soglitch; /* terminal has standout mode glitch */ Xint ulglitch; /* terminal has underline mode glitch */ Xint pstate = 0; /* current UL state */ Xlong fseek(); Xchar *getenv(); Xstruct { X long chrctr, line; X} context, screen_start; Xextern char PC; /* pad character */ Xextern short ospeed; X X Xmain(argc, argv) Xint argc; Xchar *argv[]; X{ X register FILE *f; X register char *s; X register char *p; X register char ch; X register int left; X int prnames = 0; X int initopt = 0; X int srchopt = 0; X int clearit = 0; X int initline; X char initbuf[80]; X FILE *checkf(); X X nfiles = argc; X fnames = argv; X initterm (); X nscroll = Lpp/2 - 1; X if (nscroll <= 0) X nscroll = 1; X if(s = getenv("MORE")) argscan(s); X while (--nfiles > 0) { X if ((ch = (*++fnames)[0]) == '-') { X argscan(*fnames+1); X } X else if (ch == '+') { X s = *fnames; X if (*++s == '/') { X srchopt++; X for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) X *p++ = *s++; X *p = '\0'; X } X else { X initopt++; X for (initline = 0; *s != '\0'; s++) X if (isdigit (*s)) X initline = initline*10 + *s -'0'; X --initline; X } X } X else break; X } X /* allow clreol only if Home and eraseln and EodClr strings are X * defined, and in that case, make sure we are in noscroll mode X */ X if(clreol) X { X if((Home == NULL) || (*Home == '\0') || X (eraseln == NULL) || (*eraseln == '\0') || X (EodClr == NULL) || (*EodClr == '\0') ) X clreol = 0; X else noscroll = 1; X } X if (dlines == 0) X dlines = Lpp - (noscroll ? 1 : 2); X left = dlines; X if (nfiles > 1) X prnames++; X if (!no_intty && nfiles == 0) { X char *rindex(); X X p = rindex(argv[0], '/'); X fputs("usage: ",stderr); X fputs(p ? p + 1 : argv[0],stderr); X fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); X exit(1); X } X else X f = stdin; X if (!no_tty) { X signal(SIGQUIT, onquit); X signal(SIGINT, end_it); X#ifdef SIGWINCH X signal(SIGWINCH, chgwinsz); X#endif X#ifdef SIGTSTP X if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { X signal(SIGTSTP, onsusp); X catch_susp++; X } X#endif SIGTSTP X stty (fileno(stderr), &otty); X } X if (no_intty) { X if (no_tty) X copy_file (stdin); X else { X if ((ch = Getc (f)) == '\f') X doclear(); X else { X Ungetc (ch, f); X if (noscroll && (ch != EOF)) { X if (clreol) X home (); X else X doclear (); X } X } X if (srchopt) X { X search (initbuf, stdin, 1); X if (noscroll) X left--; X } X else if (initopt) X skiplns (initline, stdin); X screen (stdin, left); X } X no_intty = 0; X prnames++; X firstf = 0; X } X X while (fnum < nfiles) { X if ((f = checkf (fnames[fnum], &clearit)) != NULL) { X context.line = context.chrctr = 0; X Currline = 0; X if (firstf) setjmp (restore); X if (firstf) { X firstf = 0; X if (srchopt) X { X search (initbuf, f, 1); X if (noscroll) X left--; X } X else if (initopt) X skiplns (initline, f); X } X else if (fnum < nfiles && !no_tty) { X setjmp (restore); X left = command (fnames[fnum], f); X } X if (left != 0) { X if ((noscroll || clearit) && (file_size != LONG_MAX)) X if (clreol) X home (); X else X doclear (); X if (prnames) { X if (bad_so) X erase (0); X if (clreol) X cleareol (); X pr("::::::::::::::"); X if (promptlen > 14) X erase (14); X printf ("\n"); X if(clreol) cleareol(); X printf("%s\n", fnames[fnum]); X if(clreol) cleareol(); X printf("::::::::::::::\n"); X if (left > Lpp - 4) X left = Lpp - 4; X } X if (no_tty) X copy_file (f); X else { X within++; X screen(f, left); X within = 0; X } X } X setjmp (restore); X fflush(stdout); X fclose(f); X screen_start.line = screen_start.chrctr = 0L; X context.line = context.chrctr = 0L; X } X fnum++; X firstf = 0; X } X reset_tty (); X exit(0); X} X Xargscan(s) Xchar *s; X{ X int seen_num = 0; X X while (*s != '\0') { X switch (*s) { X case '0': case '1': case '2': X case '3': case '4': case '5': X case '6': case '7': case '8': X case '9': X if (!seen_num) { X dlines = 0; X seen_num = 1; X } X dlines = dlines*10 + *s - '0'; X break; X case 'd': X dum_opt = 1; X break; X case 'l': X stop_opt = 0; X break; X case 'f': X fold_opt = 0; X break; X case 'p': X noscroll++; X break; X case 'c': X clreol++; X break; X case 's': X ssp_opt = 1; X break; X case 'u': X ul_opt = 0; X break; X } X s++; X } X} X X X/* X** Check whether the file named by fs is an ASCII file which the user may X** access. If it is, return the opened file. Otherwise return NULL. X*/ X XFILE * Xcheckf (fs, clearfirst) X register char *fs; X int *clearfirst; X{ X struct stat stbuf; X register FILE *f; X char c; X X if (stat (fs, &stbuf) == -1) { X (void)fflush(stdout); X if (clreol) X cleareol (); X perror(fs); X return((FILE *)NULL); X } X if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { X printf("\n*** %s: directory ***\n\n", fs); X return((FILE *)NULL); X } X if ((f = Fopen(fs, "r")) == NULL) { X (void)fflush(stdout); X perror(fs); X return((FILE *)NULL); X } X#ifndef MINIX X if (magic(f, fs)) X return((FILE *)NULL); X#endif !MINIX X c = Getc(f); X *clearfirst = c == '\f'; X Ungetc (c, f); X if ((file_size = stbuf.st_size) == 0) X file_size = LONG_MAX; X return(f); X} X X#ifndef MINIX X/* X * magic -- X * check for file magic numbers. This code would best be shared with X * the file(1) program or, perhaps, more should not try and be so smart? X */ Xstatic Xmagic(f, fs) X FILE *f; X char *fs; X{ X struct exec ex; X X if (fread(&ex, sizeof(ex), 1, f) == 1) X switch(ex.a_magic) { X case OMAGIC: X case NMAGIC: X case ZMAGIC: X case 0405: X case 0411: X case 0177545: X printf("\n******** %s: Not a text file ********\n\n", fs); X (void)fclose(f); X return(1); X } X (void)fseek(f, 0L, L_SET); /* rewind() not necessary */ X return(0); X} X#endif !MINIX X X/* X** A real function, for the tputs routine in termlib X*/ X Xputch (ch) Xchar ch; X{ X putchar (ch); X} X X/* X** Print out the contents of the file f, one screenful at a time. X*/ X X#define STOP -10 X Xscreen (f, num_lines) Xregister FILE *f; Xregister int num_lines; X{ X register int c; X register int nchars; X int length; /* length of current line */ X static int prev_len = 1; /* length of previous line */ X X for (;;) { X while (num_lines > 0 && !Pause) { X if ((nchars = getline (f, &length)) == EOF) X { X if (clreol) X clreos(); X return; X } X if (ssp_opt && length == 0 && prev_len == 0) X continue; X prev_len = length; X if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) X erase (0); X /* must clear before drawing line since tabs on some terminals X * do not erase what they tab over. X */ X if (clreol) X cleareol (); X prbuf (Line, length); X if (nchars < promptlen) X erase (nchars); /* erase () sets promptlen to 0 */ X else promptlen = 0; X /* is this needed? X * if (clreol) X * cleareol(); /* must clear again in case we wrapped * X */ X if (nchars < Mcol || !fold_opt) X prbuf("\n", 1); /* will turn off UL if necessary */ X if (nchars == STOP) X break; X num_lines--; X } X if (pstate) { X tputs(ULexit, 1, putch); X pstate = 0; X } X fflush(stdout); X if ((c = Getc(f)) == EOF) X { X if (clreol) X clreos (); X return; X } X X if (Pause && clreol) X clreos (); X Ungetc (c, f); X setjmp (restore); X Pause = 0; startup = 0; X if ((num_lines = command (NULL, f)) == 0) X return; X if (hard && promptlen > 0) X erase (0); X if (noscroll && num_lines >= dlines) X { X if (clreol) X home(); X else X doclear (); X } X screen_start.line = Currline; X screen_start.chrctr = Ftell (f); X } X} X X/* X** Come here if a quit signal is received X*/ X Xonquit() X{ X signal(SIGQUIT, SIG_IGN); X if (!inwait) { X putchar ('\n'); X if (!startup) { X signal(SIGQUIT, onquit); X longjmp (restore, 1); X } X else X Pause++; X } X else if (!dum_opt && notell) { X write (2, "[Use q or Q to quit]", 20); X promptlen += 20; X notell = 0; X } X signal(SIGQUIT, onquit); X} X X#ifdef SIGWINCH X/* X** Come here if a signal for a window size change is received X*/ X Xchgwinsz() X{ X struct winsize win; X X (void) signal(SIGWINCH, SIG_IGN); X if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { X if (win.ws_row != 0) { X Lpp = win.ws_row; X nscroll = Lpp/2 - 1; X if (nscroll <= 0) X nscroll = 1; X dlines = Lpp - (noscroll ? 1 : 2); X } X if (win.ws_col != 0) X Mcol = win.ws_col; X } X (void) signal(SIGWINCH, chgwinsz); X} X#endif SIGWINCH X X/* X** Clean up terminal state and exit. Also come here if interrupt signal received X*/ X Xend_it () X{ X X reset_tty (); X if (clreol) { X putchar ('\r'); X clreos (); X fflush (stdout); X } X else if (!clreol && (promptlen > 0)) { X kill_line (); X fflush (stdout); X } X else X write (2, "\n", 1); X _exit(0); X} X Xcopy_file(f) Xregister FILE *f; X{ X register int c; X X while ((c = getc(f)) != EOF) X putchar(c); X} X X/* Simplified printf function */ X Xprintf (fmt, va_alist) Xregister char *fmt; Xva_dcl X{ X va_list ap; X register char ch; X register int ccount; X X ccount = 0; X va_start(ap); X while (*fmt) { X while ((ch = *fmt++) != '%') { X if (ch == '\0') X return (ccount); X ccount++; X putchar (ch); X } X switch (*fmt++) { X case 'd': X ccount += printd (va_arg(ap, int)); X break; X case 's': X ccount += pr (va_arg(ap, char *)); X break; X case '%': X ccount++; X putchar ('%'); X break; X case '0': X return (ccount); X default: X break; X } X } X va_end(ap); X return (ccount); X X} X X/* X** Print an integer as a string of decimal digits, X** returning the length of the print representation. X*/ X Xprintd (n) Xint n; X{ X int a, nchars; X X if (a = n/10) X nchars = 1 + printd(a); X else X nchars = 1; X putchar (n % 10 + '0'); X return (nchars); X} X X/* Put the print representation of an integer into a string */ Xstatic char *sptr; X Xscanstr (n, str) Xint n; Xchar *str; X{ X sptr = str; X Sprintf (n); X *sptr = '\0'; X} X XSprintf (n) X{ X int a; X X if (a = n/10) X Sprintf (a); X *sptr++ = n % 10 + '0'; X} X Xstatic char bell = ctrl('G'); X Xstrlen (s) Xchar *s; X{ X register char *p; X X p = s; X while (*p++) X ; X return (p - s - 1); X} X X/* See whether the last component of the path name "path" is equal to the X** string "string" X*/ X Xtailequ (path, string) Xchar *path; Xregister char *string; X{ X register char *tail; X X tail = path + strlen(path); X while (tail >= path) X if (*(--tail) == '/') X break; X ++tail; X while (*tail++ == *string++) X if (*tail == '\0') X return(1); X return(0); X} X Xprompt (filename) Xchar *filename; X{ X if (clreol) X cleareol (); X else if (promptlen > 0) X kill_line (); X if (!hard) { X promptlen = 8; X if (Senter && Sexit) { X tputs (Senter, 1, putch); X promptlen += (2 * soglitch); X } X if (clreol) X cleareol (); X pr("--More--"); X if (filename != NULL) { X promptlen += printf ("(Next file: %s)", filename); X } X else if (!no_intty) { X promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); X } X if (dum_opt) { X promptlen += pr("[Press space to continue, 'q' to quit.]"); X } X if (Senter && Sexit) X tputs (Sexit, 1, putch); X if (clreol) X clreos (); X fflush(stdout); X } X else X write (2, &bell, 1); X inwait++; X} X X/* X** Get a logical line X*/ X Xgetline(f, length) Xregister FILE *f; Xint *length; X{ X register int c; X register char *p; X register int column; X static int colflg; X X p = Line; X column = 0; X c = Getc (f); X if (colflg && c == '\n') { X Currline++; X c = Getc (f); X } X while (p < &Line[LINSIZ - 1]) { X if (c == EOF) { X if (p > Line) { X *p = '\0'; X *length = p - Line; X return (column); X } X *length = p - Line; X return (EOF); X } X if (c == '\n') { X Currline++; X break; X } X *p++ = c; X if (c == '\t') X if (!hardtabs || column < promptlen && !hard) { X if (hardtabs && eraseln && !dumb) { X column = 1 + (column | 7); X tputs (eraseln, 1, putch); X promptlen = 0; X } X else { X for (--p; p < &Line[LINSIZ - 1];) { X *p++ = ' '; X if ((++column & 7) == 0) X break; X } X if (column >= promptlen) promptlen = 0; X } X } X else X column = 1 + (column | 7); X else if (c == '\b' && column > 0) X column--; X else if (c == '\r') X column = 0; X else if (c == '\f' && stop_opt) { X p[-1] = '^'; X *p++ = 'L'; X column += 2; X Pause++; X } X else if (c == EOF) { X *length = p - Line; X return (column); X } X else if (c >= ' ' && c != RUBOUT) X column++; X if (column >= Mcol && fold_opt) break; X c = Getc (f); X } X if (column >= Mcol && Mcol > 0) { X if (!Wrap) { X *p++ = '\n'; X } X } X colflg = column == Mcol && fold_opt; X if (colflg && eatnl && Wrap) { X *p++ = '\n'; /* simulate normal wrap */ X } X *length = p - Line; X *p = 0; X return (column); X} X X/* X** Erase the rest of the prompt, assuming we are starting at column col. X*/ X Xerase (col) Xregister int col; X{ X X if (promptlen == 0) X return; X if (hard) { X putchar ('\n'); X } X else { X if (col == 0) X putchar ('\r'); X if (!dumb && eraseln) X tputs (eraseln, 1, putch); X else X for (col = promptlen - col; col > 0; col--) X putchar (' '); X } X promptlen = 0; X} X X/* X** Erase the current line entirely X*/ X Xkill_line () X{ X erase (0); X if (!eraseln || dumb) putchar ('\r'); X} X X/* X * force clear to end of line X */ Xcleareol() X{ X tputs(eraseln, 1, putch); X} X Xclreos() X{ X tputs(EodClr, 1, putch); X} X X/* X** Print string and return number of characters X*/ X Xpr(s1) Xchar *s1; X{ X register char *s; X register char c; X X for (s = s1; c = *s++; ) X putchar(c); X return (s - s1 - 1); X} X X X/* Print a buffer of n characters */ X Xprbuf (s, n) Xregister char *s; Xregister int n; X{ X register char c; /* next output character */ X register int state; /* next output char's UL state */ X#define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) X X while (--n >= 0) X if (!ul_opt) X putchar (*s++); X else { X if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { X s++; X continue; X } X if (state = wouldul(s, n)) { X c = (*s == '_')? s[2] : *s ; X n -= 2; X s += 3; X } else X c = *s++; X if (state != pstate) { X if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) X state = 1; X else X tputs(state ? ULenter : ULexit, 1, putch); X } X if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) X putchar(c); X if (state && *chUL) { X pr(chBS); X tputs(chUL, 1, putch); X } X pstate = state; X } X} X X/* X** Clear the screen X*/ X Xdoclear() X{ X if (Clear && !hard) { X tputs(Clear, 1, putch); X X /* Put out carriage return so that system doesn't X ** get confused by escape sequences when expanding tabs X */ X putchar ('\r'); X promptlen = 0; X } X} X X/* X * Go to home position X */ Xhome() X{ X tputs(Home,1,putch); X} X Xstatic int lastcmd, lastarg, lastp; Xstatic int lastcolon; Xchar shell_line[132]; X X/* X** Read a command and do it. A command consists of an optional integer X** argument followed by the command character. Return the number of lines X** to display in the next screenful. If there is nothing more to display X** in the current file, zero is returned. X*/ X Xcommand (filename, f) Xchar *filename; Xregister FILE *f; X{ X register int nlines; X register int retval; X register char c; X char colonch; X FILE *helpf; X int done; X char comchar, cmdbuf[80], *p; X X#define ret(val) retval=val;done++;break X X done = 0; X if (!errors) X prompt (filename); X else X errors = 0; X if (MBIT == RAW && slow_tty) { X otty.sg_flags |= MBIT; X stty(fileno(stderr), &otty); X } X for (;;) { X nlines = number (&comchar); X lastp = colonch = 0; X if (comchar == '.') { /* Repeat last command */ X lastp++; X comchar = lastcmd; X nlines = lastarg; X if (lastcmd == ':') X colonch = lastcolon; X } X lastcmd = comchar; X lastarg = nlines; X if (comchar == otty.sg_erase) { X kill_line (); X prompt (filename); X continue; X } X switch (comchar) { X case ':': X retval = colon (filename, colonch, nlines); X if (retval >= 0) X done++; X break; X case 'b': X case ctrl('B'): X { X register int initline; X X if (no_intty) { X write(2, &bell, 1); X return (-1); X } X X if (nlines == 0) nlines++; X X putchar ('\r'); X erase (0); X printf ("\n"); X if (clreol) X cleareol (); X printf ("...back %d page", nlines); X if (nlines > 1) X pr ("s\n"); X else X pr ("\n"); X X if (clreol) X cleareol (); X pr ("\n"); X X initline = Currline - dlines * (nlines + 1); X if (! noscroll) X --initline; X if (initline < 0) initline = 0; X Fseek(f, 0L); X Currline = 0; /* skiplns() will make Currline correct */ X skiplns(initline, f); X if (! noscroll) { X ret(dlines + 1); X } X else { X ret(dlines); X } X } X case ' ': X case 'z': X if (nlines == 0) nlines = dlines; X else if (comchar == 'z') dlines = nlines; X ret (nlines); X case 'd': X case ctrl('D'): X if (nlines != 0) nscroll = nlines; X ret (nscroll); X case 'q': X case 'Q': X end_it (); X case 's': X case 'f': X if (nlines == 0) nlines++; X if (comchar == 'f') X nlines *= dlines; X putchar ('\r'); X erase (0); X printf ("\n"); X if (clreol) X cleareol (); X printf ("...skipping %d line", nlines); X if (nlines > 1) X pr ("s\n"); X else X pr ("\n"); X X if (clreol) X cleareol (); X pr ("\n"); X X while (nlines > 0) { X while ((c = Getc (f)) != '\n') X if (c == EOF) { X retval = 0; X done++; X goto endsw; X } X Currline++; X nlines--; X } X ret (dlines); X case '\n': X if (nlines != 0) X dlines = nlines; X else X nlines = 1; X ret (nlines); X case '\f': X if (!no_intty) { X doclear (); X Fseek (f, screen_start.chrctr); X Currline = screen_start.line; X ret (dlines); X } X else { X write (2, &bell, 1); X break; X } X case '\'': X if (!no_intty) { X kill_line (); X pr ("\n***Back***\n\n"); X Fseek (f, context.chrctr); X Currline = context.line; X ret (dlines); X } X else { X write (2, &bell, 1); X break; X } X case '=': X kill_line (); X promptlen = printd (Currline); X fflush (stdout); X break; X case 'n': X lastp++; X case '/': X if (nlines == 0) nlines++; X kill_line (); X pr ("/"); X promptlen = 1; X fflush (stdout); X if (lastp) { X write (2,"\r", 1); X search (NULL, f, nlines); /* Use previous r.e. */ X } X else { X ttyin (cmdbuf, 78, '/'); X write (2, "\r", 1); X search (cmdbuf, f, nlines); X } X ret (dlines-1); X case '!': X do_shell (filename); X break; X case '?': X case 'h': X if ((helpf = fopen (HELPFILE, "r")) == NULL) X error ("Can't open help file"); X if (noscroll) doclear (); X copy_file (helpf); X fclose (helpf); X prompt (filename); X break; X case 'v': /* This case should go right before default */ X if (!no_intty) { X kill_line (); X cmdbuf[0] = '+'; X scanstr (Currline - dlines < 0 ? 0 X : Currline - (dlines + 1) / 2, &cmdbuf[1]); X pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); X execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); X break; X } X default: X if (dum_opt) { X kill_line (); X if (Senter && Sexit) { X tputs (Senter, 1, putch); X promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); X tputs (Sexit, 1, putch); X } X else X promptlen = pr ("[Press 'h' for instructions.]"); X fflush (stdout); X } X else X write (2, &bell, 1); X break; X } X if (done) break; X } X putchar ('\r'); Xendsw: X inwait = 0; X notell++; X if (MBIT == RAW && slow_tty) { X otty.sg_flags &= ~MBIT; X stty(fileno(stderr), &otty); X } X return (retval); X} X Xchar ch; X X/* X * Execute a colon-prefixed command. X * Returns <0 if not a command that should cause X * more of the file to be printed. X */ X Xcolon (filename, cmd, nlines) Xchar *filename; Xint cmd; Xint nlines; X{ X if (cmd == 0) X ch = readch (); X else X ch = cmd; X lastcolon = ch; X switch (ch) { X case 'f': X kill_line (); X if (!no_intty) X promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); X else X promptlen = printf ("[Not a file] line %d", Currline); X fflush (stdout); X return (-1); X case 'n': X if (nlines == 0) { X if (fnum >= nfiles - 1) X end_it (); X nlines++; X } X putchar ('\r'); X erase (0); X skipf (nlines); X return (0); X case 'p': X if (no_intty) { X write (2, &bell, 1); X return (-1); X } X putchar ('\r'); X erase (0); X if (nlines == 0) X nlines++; X skipf (-nlines); X return (0); X case '!': X do_shell (filename); X return (-1); X case 'q': X case 'Q': X end_it (); X default: X write (2, &bell, 1); X return (-1); X } X} X X/* X** Read a decimal number from the terminal. Set cmd to the non-digit which X** terminates the number. X*/ X Xnumber(cmd) Xchar *cmd; X{ X register int i; X X i = 0; ch = otty.sg_kill; X for (;;) { X ch = readch (); X if (ch >= '0' && ch <= '9') X i = i*10 + ch - '0'; X else if (ch == otty.sg_kill) X i = 0; X else { X *cmd = ch; X break; X } X } X return (i); X} X Xdo_shell (filename) Xchar *filename; X{ X char cmdbuf[80]; X X kill_line (); X pr ("!"); X fflush (stdout); X promptlen = 1; X if (lastp) X pr (shell_line); X else { X ttyin (cmdbuf, 78, '!'); X if (expand (shell_line, cmdbuf)) { X kill_line (); X promptlen = printf ("!%s", shell_line); X } X } X fflush (stdout); X write (2, "\n", 1); X promptlen = 0; X shellp = 1; X execute (filename, shell, shell, "-c", shell_line, 0); X} X X/* X** Search for nth ocurrence of regular expression contained in buf in the file X*/ X Xsearch (buf, file, n) Xchar buf[]; XFILE *file; Xregister int n; X{ X long startline = Ftell (file); X register long line1 = startline; X register long line2 = startline; X register long line3 = startline; X register int lncount; X int saveln, rv, re_exec(); X char *s, *re_comp(); X X context.line = saveln = Currline; X context.chrctr = startline; X lncount = 0; X if ((s = re_comp (buf)) != 0) X error (s); X while (!feof (file)) { X line3 = line2; X line2 = line1; X line1 = Ftell (file); X rdline (file); X lncount++; X if ((rv = re_exec (Line)) == 1) X if (--n == 0) { X if (lncount > 3 || (lncount > 1 && no_intty)) X { X pr ("\n"); X if (clreol) X cleareol (); X pr("...skipping\n"); X } X if (!no_intty) { X Currline -= (lncount >= 3 ? 3 : lncount); X Fseek (file, line3); X if (noscroll) X if (clreol) { X home (); X cleareol (); X } X else X doclear (); X } X else { X kill_line (); X if (noscroll) X if (clreol) { X home (); X cleareol (); X } X else X doclear (); X pr (Line); X putchar ('\n'); X } X break; X } X else if (rv == -1) X error ("Regular expression botch"); X } X if (feof (file)) { X if (!no_intty) { X Currline = saveln; X Fseek (file, startline); X } X else { X pr ("\nPattern not found\n"); X end_it (); X } X error ("Pattern not found"); X } X} X X/*VARARGS2*/ Xexecute (filename, cmd, va_alist) Xchar *filename; Xchar *cmd; Xva_dcl X{ X int id; X int n; X va_list argp; X X fflush (stdout); X reset_tty (); X for (n = 10; (id = fork ()) < 0 && n > 0; n--) X sleep (5); X if (id == 0) { X if (!isatty(0)) { X close(0); X open("/dev/tty", 0); X } X va_start(argp); X execv (cmd, argp); X write (2, "exec failed\n", 12); X exit (1); X va_end(argp); /* balance {}'s for some UNIX's */ X } X if (id > 0) { X signal (SIGINT, SIG_IGN); X signal (SIGQUIT, SIG_IGN); X#ifdef SIGTSTP X if (catch_susp) X signal(SIGTSTP, SIG_DFL); X#endif SIGTSTP X while (wait(0) > 0); X signal (SIGINT, end_it); X signal (SIGQUIT, onquit); X#ifdef SIGTSTP X if (catch_susp) X signal(SIGTSTP, onsusp); X#endif SIGTSTP X } else X write(2, "can't fork\n", 11); X set_tty (); X pr ("------------------------\n"); X prompt (filename); X} X/* X** Skip n lines in the file f X*/ X Xskiplns (n, f) Xregister int n; Xregister FILE *f; X{ X register char c; X X while (n > 0) { X while ((c = Getc (f)) != '\n') X if (c == EOF) X return; X n--; X Currline++; X } X} X X/* X** Skip nskip files in the file list (from the command line). Nskip may be X** negative. X*/ X Xskipf (nskip) Xregister int nskip; X{ X if (nskip == 0) return; X if (nskip > 0) { X if (fnum + nskip > nfiles - 1) X nskip = nfiles - fnum - 1; X } X else if (within) X ++fnum; X fnum += nskip; X if (fnum < 0) X fnum = 0; X pr ("\n...Skipping "); X pr ("\n"); X if (clreol) X cleareol (); X pr ("...Skipping "); X pr (nskip > 0 ? "to file " : "back to file "); X pr (fnames[fnum]); X pr ("\n"); X if (clreol) X cleareol (); X pr ("\n"); X --fnum; X} X X/*----------------------------- Terminal I/O -------------------------------*/ X Xinitterm () X{ X char buf[TBUFSIZ]; X static char clearbuf[TBUFSIZ]; X char *clearptr, *padstr; X int ldisc; X int lmode; X char *term; X int tgrp; X#ifdef TIOCGWINSZ X struct winsize win; X#endif X Xretry: X if (!(no_tty = gtty(fileno(stdout), &otty))) { X#ifdef TIOCLGET X if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { X perror("TIOCLGET"); X exit(1); X } X X docrterase = ((lmode & LCRTERA) != 0); X docrtkill = ((lmode & LCRTKIL) != 0); X#endif TIOCLGET X#ifdef TIOCGPGRP X /* X * Wait until we're in the foreground before we save the X * the terminal modes. X */ X if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { X perror("TIOCGPGRP"); X exit(1); X } X if (tgrp != getpgrp(0)) { X kill(0, SIGTTOU); X goto retry; X } X#endif TIOCGPGRP X if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { X dumb++; ul_opt = 0; X } X else { X#ifdef TIOCGWINSZ X if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { X Lpp = tgetnum("li"); X Mcol = tgetnum("co"); X } else { X if ((Lpp = win.ws_row) == 0) X Lpp = tgetnum("li"); X if ((Mcol = win.ws_col) == 0) X Mcol = tgetnum("co"); X } X#else X Lpp = tgetnum("li"); X Mcol = tgetnum("co"); X#endif TIOCGWINSZ X if ((Lpp <= 0) || tgetflag("hc")) { X hard++; /* Hard copy terminal */ X Lpp = 24; X } X if (tgetflag("xn")) X eatnl++; /* Eat newline at last column + 1; dec, concept */ X if (Mcol <= 0) X Mcol = 80; X X if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) X noscroll++; X Wrap = tgetflag("am"); X bad_so = tgetflag ("xs"); X clearptr = clearbuf; X eraseln = tgetstr("ce",&clearptr); X Clear = tgetstr("cl", &clearptr); X Senter = tgetstr("so", &clearptr); X Sexit = tgetstr("se", &clearptr); X if ((soglitch = tgetnum("sg")) < 0) X soglitch = 0; X X /* X * Set up for underlining: some terminals don't need it; X * others have start/stop sequences, still others have an X * underline char sequence which is assumed to move the X * cursor forward one character. If underline sequence X * isn't available, settle for standout sequence. X */ X X if (tgetflag("ul") || tgetflag("os")) X ul_opt = 0; X if ((chUL = tgetstr("uc", &clearptr)) == NULL ) X chUL = ""; X if (((ULenter = tgetstr("us", &clearptr)) == NULL || X (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { X if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { X ULenter = ""; X ULexit = ""; X } else X ulglitch = soglitch; X } else { X if ((ulglitch = tgetnum("ug")) < 0) X ulglitch = 0; X } X X if (padstr = tgetstr("pc", &clearptr)) X PC = *padstr; X Home = tgetstr("ho",&clearptr); X if (Home == 0 || *Home == '\0') X { X if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { X strcpy(cursorhome, tgoto(cursorm, 0, 0)); X Home = cursorhome; X } X } X EodClr = tgetstr("cd", &clearptr); X if ((chBS = tgetstr("bc", &clearptr)) == NULL) X chBS = "\b"; X X } X if ((shell = getenv("SHELL")) == NULL) X shell = "/bin/sh"; X } X no_intty = gtty(fileno(stdin), &otty); X gtty(fileno(stderr), &otty); X savetty = otty; X ospeed = otty.sg_ospeed; X slow_tty = ospeed < B1200; X hardtabs = (otty.sg_flags & TBDELAY) != XTABS; X if (!no_tty) { X otty.sg_flags &= ~ECHO; X if (MBIT == CBREAK || !slow_tty) X otty.sg_flags |= MBIT; X } X} X Xreadch () X{ X char ch; X extern int errno; X X errno = 0; X if (read (2, &ch, 1) <= 0) X if (errno != EINTR) X end_it(); X else X ch = otty.sg_kill; X return (ch); X} X Xstatic char BS = '\b'; Xstatic char *BSB = "\b \b"; Xstatic char CARAT = '^'; X#define ERASEONECHAR \ X if (docrterase) \ X write (2, BSB, sizeof(BSB)); \ X else \ X write (2, &BS, sizeof(BS)); X Xttyin (buf, nmax, pchar) Xchar buf[]; Xregister int nmax; Xchar pchar; X{ X register char *sptr; X register char ch; X register int slash = 0; X int maxlen; X char cbuf; X X sptr = buf; X maxlen = 0; X while (sptr - buf < nmax) { X if (promptlen > maxlen) maxlen = promptlen; X ch = readch (); X if (ch == '\\') { X slash++; X } X else if ((ch == otty.sg_erase) && !slash) { X if (sptr > buf) { X --promptlen; X ERASEONECHAR X --sptr; X if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { X --promptlen; X ERASEONECHAR X } X continue; X } X else { X if (!eraseln) promptlen = maxlen; X longjmp (restore, 1); X } X } X else if ((ch == otty.sg_kill) && !slash) { X if (hard) { X show (ch); X putchar ('\n'); X putchar (pchar); X } X else { X putchar ('\r'); X putchar (pchar); X if (eraseln) X erase (1); X else if (docrtkill) X while (promptlen-- > 1) X write (2, BSB, sizeof(BSB)); X promptlen = 1; X } X sptr = buf; X fflush (stdout); X continue; X } X if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { X ERASEONECHAR X --sptr; X } X if (ch != '\\') X slash = 0; X *sptr++ = ch; X if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { X ch += ch == RUBOUT ? -0100 : 0100; X write (2, &CARAT, 1); X promptlen++; X } X cbuf = ch; X if (ch != '\n' && ch != ESC) { X write (2, &cbuf, 1); X promptlen++; X } X else X break; X } X *--sptr = '\0'; X if (!eraseln) promptlen = maxlen; X if (sptr - buf >= nmax - 1) X error ("Line too long"); X} X Xexpand (outbuf, inbuf) Xchar *outbuf; Xchar *inbuf; X{ X register char *instr; X register char *outstr; X register char ch; X char temp[200]; X int changed = 0; X X instr = inbuf; X outstr = temp; X while ((ch = *instr++) != '\0') X switch (ch) { X case '%': X if (!no_intty) { X strcpy (outstr, fnames[fnum]); X outstr += strlen (fnames[fnum]); X changed++; X } X else X *outstr++ = ch; X break; X case '!': X if (!shellp) X error ("No previous command to substitute for"); X strcpy (outstr, shell_line); X outstr += strlen (shell_line); X changed++; X break; X case '\\': X if (*instr == '%' || *instr == '!') { X *outstr++ = *instr++; X break; X } X default: X *outstr++ = ch; X } X *outstr++ = '\0'; X strcpy (outbuf, temp); X return (changed); X} X Xshow (ch) Xregister char ch; X{ X char cbuf; X X if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { X ch += ch == RUBOUT ? -0100 : 0100; X write (2, &CARAT, 1); X promptlen++; X } X cbuf = ch; X write (2, &cbuf, 1); X promptlen++; X} X Xerror (mess) Xchar *mess; X{ X if (clreol) X cleareol (); X else X kill_line (); X promptlen += strlen (mess); X if (Senter && Sexit) { X tputs (Senter, 1, putch); X pr(mess); X tputs (Sexit, 1, putch); X } X else X pr (mess); X fflush(stdout); X errors++; X longjmp (restore, 1); X} X X Xset_tty () X{ X otty.sg_flags |= MBIT; X otty.sg_flags &= ~ECHO; X stty(fileno(stderr), &otty); X} X Xreset_tty () X{ X if (no_tty) X return; X if (pstate) { X tputs(ULexit, 1, putch); X fflush(stdout); X pstate = 0; X } X otty.sg_flags |= ECHO; X otty.sg_flags &= ~MBIT; X stty(fileno(stderr), &savetty); X} X Xrdline (f) Xregister FILE *f; X{ X register char c; X register char *p; X X p = Line; X while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) X *p++ = c; X if (c == '\n') X Currline++; X *p = '\0'; X} X X/* Come here when we get a suspend signal from the terminal */ X X#ifdef SIGTSTP Xonsusp () X{ X /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ X signal(SIGTTOU, SIG_IGN); X reset_tty (); X fflush (stdout); X signal(SIGTTOU, SIG_DFL); X /* Send the TSTP signal to suspend our process group */ X signal(SIGTSTP, SIG_DFL); X sigsetmask(0); X kill (0, SIGTSTP); X /* Pause for station break */ X X /* We're back */ X signal (SIGTSTP, onsusp); X set_tty (); X if (inwait) X longjmp (restore); X} X#endif SIGTSTP **-more.c-EOF-** echo 'x - more.help' sed 's/^X//' <<'**-more.help-EOF-**' >more.help X XMost commands optionally preceded by integer argument k. Defaults in brackets. XStar (*) indicates argument becomes new default. X------------------------------------------------------------------------------- X<space> Display next k lines of text [current screen size] Xz Display next k lines of text [current screen size]* X<return> Display next k lines of text [1]* Xd or ctrl-D Scroll k lines [current scroll size, initially 11]* Xq or Q or <interrupt> Exit from more Xs Skip forward k lines of text [1] Xf Skip forward k screenfuls of text [1] Xb or ctrl-B Skip backwards k screenfuls of text [1] X' Go to place where previous search started X= Display current line number X/<regular expression> Search for kth occurrence of regular expression [1] Xn Search for kth occurrence of last r.e [1] X!<cmd> or :!<cmd> Execute <cmd> in a subshell Xv Start up /usr/ucb/vi at current line Xctrl-L Redraw screen X:n Go to kth next file [1] X:p Go to kth previous file [1] X:f Display current file name and line number X. Repeat previous command X------------------------------------------------------------------------------- **-more.help-EOF-** echo 'x - regcompat.c' sed 's/^X//' <<'**-regcompat.c-EOF-**' >regcompat.c X/* file: regcompat.c X** author: Peter S. Housel 11/21/88 X** Compatibility routines for regular expressions. more.c uses the X** re_comp() and re_exec() routines, while Minix only has regcomp() and X** regexec() (from Henry Spencer's freely redistributable regexp package). X** Note that the third argument to regexec() is a beginning-of-line flag X** and was probably added by Andrew Tannenbaum. It will probably be ignored X** if your copy of the regexp routines only expects two args. X**/ X X#include <stdio.h> X#include <regexp.h> X Xstatic regexp *re_exp = NULL; /* currently compiled regular expression */ Xstatic char *re_err = NULL; /* current regexp error */ X Xchar *re_comp(str) Xchar *str; X{ X if(str == NULL) X return NULL; X X if(re_exp != NULL) X free(re_exp); X X if((re_exp = regcomp(str)) != NULL) X return NULL; X X return re_err != NULL ? re_err : "string didn't compile"; X} X Xint re_exec(str) Xchar *str; X{ X if(re_exp == NULL) X return -1; X return regexec(re_exp, str, 1); X} X Xregerror(str) Xchar *str; X{ X re_err = str; X} **-regcompat.c-EOF-** echo 'x - tcvars.c' sed 's/^X//' <<'**-tcvars.c-EOF-**' >tcvars.c X/* X * For some reason (probably because it doesn't support padding), the Minix X * termcap routines don't define these variables. X */ Xint ospeed; Xchar PC; **-tcvars.c-EOF-** echo 'x - varargs.h' sed 's/^X//' <<'**-varargs.h-EOF-**' >varargs.h X/* varargs.h */ X Xtypedef char *va_list; X X#define va_dcl int va_alist; X#define va_start(p) (p) = (va_list) &va_alist; X#define va_arg(p,type) ( (type *) ((p)+=sizeof(type)) )[-1] X#define va_end(p) X X#define vfprintf _doprintf X#define vprintf(fmt,args) vfprintf(stdout,fmt,args) **-varargs.h-EOF-** echo 'x - mkdep.sh' sed 's/^X//' <<'**-mkdep.sh-EOF-**' >mkdep.sh X#!/bin/sh - X# X# Copyright (c) 1987 Regents of the University of California. X# All rights reserved. X# X# Redistribution and use in source and binary forms are permitted X# provided that the above copyright notice and this paragraph are X# duplicated in all such forms and that any documentation, X# advertising materials, and other materials related to such X# distribution and use acknowledge that the software was developed X# by the University of California, Berkeley. The name of the X# University may not be used to endorse or promote products derived X# from this software without specific prior written permission. X# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR X# IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED X# WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. X# X# @(#)mkdep.sh 5.12 (Berkeley) 6/30/88 X# XPATH=/bin:/usr/bin:/usr/ucb Xexport PATH X XMAKE=Makefile # default makefile name is "Makefile" X Xopts="" X Xwhile : X do case "$1" in X # -f allows you to select a makefile name X -f) X MAKE=$2 X shift; shift ;; X X # the -p flag produces "program: program.c" style dependencies X # so .s's don't get produced X -p) X SED='s/\.s//' X shift ;; X -D*|-I*|-U*) X opts="$opts $1" X shift ;; X -*) X shift;; X *) X break ;; X esac Xdone X Xif test $# = 0 ; then X echo 'usage: mkdep [-p] [-f makefile] [flags] file ...' X exit 1 Xfi X Xif test ! -w $MAKE ; then X echo "mkdep: no writeable file \"$MAKE\"" X exit 1 Xfi X XTMP=/tmp/mkdep$$ XTMP1=/tmp/Mkdep$$ X Xtrap 'rm -f $TMP $TMP1; exit 1' 1 2 3 13 15 X Xcp $MAKE ${MAKE}.bak X Xsed -e '/DO NOT DELETE THIS LINE/,$d' < $MAKE > $TMP X Xcat << _EOF_ >> $TMP X# DO NOT DELETE THIS LINE -- mkdep uses it. X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY. X X_EOF_ X X Xfor f; do X dep=`echo "$f" | sed -e 's,/,\\\\/,g' -e 's/\.c$/.s/'` X /lib/cpp $opts "$f" | X sed -e '/^#/!d' \ X -e 's/#line [0-9]* //' \ X -e 's,"\./,",' \ X -e 's/"\(.*\)"/\1/' \ X -e "$SED" > $TMP1 X sort -u $TMP1 | sed -e "s/^/$dep: /" >> $TMP Xdone Xcat << _EOF_ >> $TMP X X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY X_EOF_ X X# copy to preserve permissions Xcp $TMP $MAKE Xrm -f ${MAKE}.bak $TMP $TMP1 Xexit 0 **-mkdep.sh-EOF-**