121981Sdist /* 221981Sdist * Copyright (c) 1980 Regents of the University of California. 321981Sdist * All rights reserved. The Berkeley software License Agreement 421981Sdist * specifies the terms and conditions for redistribution. 521981Sdist */ 621981Sdist 713615Ssam #ifndef lint 821981Sdist char copyright[] = 921981Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1021981Sdist All rights reserved.\n"; 1121981Sdist #endif not lint 123594Sroot 1321981Sdist #ifndef lint 14*27006Sdonn static char sccsid[] = "@(#)more.c 5.4 (Berkeley) 04/03/86"; 1521981Sdist #endif not lint 1621981Sdist 171500Serics /* 181500Serics ** more.c - General purpose tty output filter and file perusal program 191500Serics ** 201500Serics ** by Eric Shienbrood, UC Berkeley 213594Sroot ** 223594Sroot ** modified by Geoff Peck, UCB to add underlining, single spacing 233594Sroot ** modified by John Foderaro, UCB to add -c and MORE environment variable 241500Serics */ 251500Serics 261500Serics #include <stdio.h> 2717592Sleres #include <sys/types.h> 281500Serics #include <ctype.h> 291500Serics #include <signal.h> 301500Serics #include <errno.h> 311500Serics #include <sgtty.h> 321500Serics #include <setjmp.h> 331500Serics #include <sys/stat.h> 341500Serics 3513615Ssam #define HELPFILE "/usr/lib/more.help" 3613615Ssam #define VI "/usr/ucb/vi" 371500Serics 381500Serics #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) 391500Serics #define Ftell(f) file_pos 401500Serics #define Fseek(f,off) (file_pos=off,fseek(f,off,0)) 411500Serics #define Getc(f) (++file_pos, getc(f)) 421500Serics #define Ungetc(c,f) (--file_pos, ungetc(c,f)) 431500Serics 441500Serics #define MBIT CBREAK 451500Serics #define stty(fd,argp) ioctl(fd,TIOCSETN,argp) 461500Serics 471500Serics #define TBUFSIZ 1024 481500Serics #define LINSIZ 256 491500Serics #define ctrl(letter) ('letter' & 077) 501500Serics #define RUBOUT '\177' 511500Serics #define ESC '\033' 521500Serics #define QUIT '\034' 531500Serics 5416582Sleres struct sgttyb otty, savetty; 551500Serics long file_pos, file_size; 561500Serics int fnum, no_intty, no_tty, slow_tty; 57*27006Sdonn int dum_opt, dlines, onquit(), end_it(), chgwinsz(); 581500Serics int onsusp(); 591500Serics int nscroll = 11; /* Number of lines scrolled by 'd' */ 601500Serics int fold_opt = 1; /* Fold long lines */ 611500Serics int stop_opt = 1; /* Stop after form feeds */ 623594Sroot int ssp_opt = 0; /* Suppress white space */ 633594Sroot int ul_opt = 1; /* Underline as best we can */ 641500Serics int promptlen; 651500Serics int Currline; /* Line we are currently at */ 661500Serics int startup = 1; 671500Serics int firstf = 1; 681500Serics int notell = 1; 6917592Sleres int docrterase = 0; 7017592Sleres int docrtkill = 0; 711500Serics int bad_so; /* True if overwriting does not turn off standout */ 721500Serics int inwait, Pause, errors; 731500Serics int within; /* true if we are within a file, 741500Serics false if we are between files */ 753594Sroot int hard, dumb, noscroll, hardtabs, clreol; 761500Serics int catch_susp; /* We should catch the SIGTSTP signal */ 771500Serics char **fnames; /* The list of file names */ 781500Serics int nfiles; /* Number of files left to process */ 791500Serics char *shell; /* The name of the shell to use */ 801500Serics int shellp; /* A previous shell command exists */ 811500Serics char ch; 821500Serics jmp_buf restore; 831500Serics char Line[LINSIZ]; /* Line buffer */ 841500Serics int Lpp = 24; /* lines per page */ 851500Serics char *Clear; /* clear screen */ 861500Serics char *eraseln; /* erase line */ 871500Serics char *Senter, *Sexit;/* enter and exit standout mode */ 883594Sroot char *ULenter, *ULexit; /* enter and exit underline mode */ 893594Sroot char *chUL; /* underline character */ 903594Sroot char *chBS; /* backspace character */ 913455Sroot char *Home; /* go to home */ 923455Sroot char *cursorm; /* cursor movement */ 933455Sroot char cursorhome[40]; /* contains cursor movement to home */ 943594Sroot char *EodClr; /* clear rest of screen */ 951500Serics char *tgetstr(); 961500Serics int Mcol = 80; /* number of columns */ 971500Serics int Wrap = 1; /* set if automargins */ 9816710Sjak int soglitch; /* terminal has standout mode glitch */ 9916710Sjak int ulglitch; /* terminal has underline mode glitch */ 10016710Sjak int pstate = 0; /* current UL state */ 1011500Serics long fseek(); 1023455Sroot char *getenv(); 1031500Serics struct { 1041500Serics long chrctr, line; 1051500Serics } context, screen_start; 1061500Serics extern char PC; /* pad character */ 1071500Serics extern short ospeed; 1081500Serics 1091500Serics 1101500Serics main(argc, argv) 1111500Serics int argc; 1121500Serics char *argv[]; 1131500Serics { 1141500Serics register FILE *f; 1151500Serics register char *s; 1161500Serics register char *p; 1171500Serics register char ch; 1181500Serics register int left; 11916582Sleres int prnames = 0; 1201500Serics int initopt = 0; 1211500Serics int srchopt = 0; 1221500Serics int clearit = 0; 1231500Serics int initline; 1241500Serics char initbuf[80]; 1251500Serics FILE *checkf(); 1261500Serics 1271500Serics nfiles = argc; 1281500Serics fnames = argv; 1291500Serics initterm (); 13015813Sralph nscroll = Lpp/2 - 1; 13115813Sralph if (nscroll <= 0) 13215813Sralph nscroll = 1; 1333455Sroot if(s = getenv("MORE")) argscan(s); 1341500Serics while (--nfiles > 0) { 1351500Serics if ((ch = (*++fnames)[0]) == '-') { 1363455Sroot argscan(*fnames+1); 1371500Serics } 1381500Serics else if (ch == '+') { 1391500Serics s = *fnames; 1401500Serics if (*++s == '/') { 1411500Serics srchopt++; 1421500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1431500Serics *p++ = *s++; 1441500Serics *p = '\0'; 1451500Serics } 1461500Serics else { 1471500Serics initopt++; 1481500Serics for (initline = 0; *s != '\0'; s++) 1491500Serics if (isdigit (*s)) 1501500Serics initline = initline*10 + *s -'0'; 1511500Serics --initline; 1521500Serics } 1531500Serics } 1541500Serics else break; 1551500Serics } 1563594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1573455Sroot * defined, and in that case, make sure we are in noscroll mode 1583455Sroot */ 1593455Sroot if(clreol) 1603455Sroot { 16118608Sralph if((Home == NULL) || (*Home == '\0') || 16218608Sralph (eraseln == NULL) || (*eraseln == '\0') || 16318608Sralph (EodClr == NULL) || (*EodClr == '\0') ) 16418608Sralph clreol = 0; 1653455Sroot else noscroll = 1; 1663455Sroot } 1671500Serics if (dlines == 0) 1681500Serics dlines = Lpp - (noscroll ? 1 : 2); 1691500Serics left = dlines; 1701500Serics if (nfiles > 1) 1711500Serics prnames++; 1721500Serics if (!no_intty && nfiles == 0) { 1731500Serics fputs("Usage: ",stderr); 1741500Serics fputs(argv[0],stderr); 1751500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1761500Serics exit(1); 1771500Serics } 1781500Serics else 1791500Serics f = stdin; 1801500Serics if (!no_tty) { 1811500Serics signal(SIGQUIT, onquit); 1821500Serics signal(SIGINT, end_it); 183*27006Sdonn signal(SIGWINCH, chgwinsz); 1841500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1851500Serics signal(SIGTSTP, onsusp); 1861500Serics catch_susp++; 1871500Serics } 18816582Sleres stty (fileno(stderr), &otty); 1891500Serics } 1901500Serics if (no_intty) { 1911500Serics if (no_tty) 1921500Serics copy_file (stdin); 1931500Serics else { 1941500Serics if ((ch = Getc (f)) == '\f') 1953594Sroot doclear(); 1961500Serics else { 1971500Serics Ungetc (ch, f); 1983594Sroot if (noscroll && (ch != EOF)) { 1993594Sroot if (clreol) 2003594Sroot home (); 2013594Sroot else 2023594Sroot doclear (); 2033455Sroot } 2041500Serics } 2051500Serics if (srchopt) 2063455Sroot { 2071500Serics search (initbuf, stdin, 1); 2083594Sroot if (noscroll) 2093594Sroot left--; 2103455Sroot } 2111500Serics else if (initopt) 2121500Serics skiplns (initline, stdin); 2131500Serics screen (stdin, left); 2141500Serics } 2151500Serics no_intty = 0; 2161500Serics prnames++; 2171500Serics firstf = 0; 2181500Serics } 2191500Serics 2201500Serics while (fnum < nfiles) { 2211500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2221500Serics context.line = context.chrctr = 0; 2231500Serics Currline = 0; 2241500Serics if (firstf) setjmp (restore); 2251500Serics if (firstf) { 2261500Serics firstf = 0; 2271500Serics if (srchopt) 2283455Sroot { 2291500Serics search (initbuf, f, 1); 2303594Sroot if (noscroll) 2313594Sroot left--; 2323455Sroot } 2331500Serics else if (initopt) 2341500Serics skiplns (initline, f); 2351500Serics } 2361500Serics else if (fnum < nfiles && !no_tty) { 2371500Serics setjmp (restore); 2381500Serics left = command (fnames[fnum], f); 2391500Serics } 2401500Serics if (left != 0) { 2413594Sroot if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 2423594Sroot if (clreol) 2433594Sroot home (); 2443594Sroot else 2453594Sroot doclear (); 2461500Serics if (prnames) { 2471500Serics if (bad_so) 2481500Serics erase (0); 2493594Sroot if (clreol) 2503594Sroot cleareol (); 2511500Serics pr("::::::::::::::"); 2521500Serics if (promptlen > 14) 2531500Serics erase (14); 2543455Sroot printf ("\n"); 2553455Sroot if(clreol) cleareol(); 2563455Sroot printf("%s\n", fnames[fnum]); 2573455Sroot if(clreol) cleareol(); 2583455Sroot printf("::::::::::::::\n", fnames[fnum]); 2591500Serics if (left > Lpp - 4) 2601500Serics left = Lpp - 4; 2611500Serics } 2621500Serics if (no_tty) 2631500Serics copy_file (f); 2641500Serics else { 2651500Serics within++; 2661500Serics screen(f, left); 2671500Serics within = 0; 2681500Serics } 2691500Serics } 2701500Serics setjmp (restore); 2711500Serics fflush(stdout); 2721500Serics fclose(f); 2731500Serics screen_start.line = screen_start.chrctr = 0L; 2741500Serics context.line = context.chrctr = 0L; 2751500Serics } 2761500Serics fnum++; 2771500Serics firstf = 0; 2781500Serics } 2791500Serics reset_tty (); 2801500Serics exit(0); 2811500Serics } 2821500Serics 2833455Sroot argscan(s) 2843455Sroot char *s; 2853455Sroot { 28611604Slayer for (dlines = 0; *s != '\0'; s++) 28711604Slayer { 28811604Slayer switch (*s) 28911604Slayer { 29011604Slayer case '0': case '1': case '2': 29111604Slayer case '3': case '4': case '5': 29211604Slayer case '6': case '7': case '8': 29311604Slayer case '9': 29411604Slayer dlines = dlines*10 + *s - '0'; 29511604Slayer break; 29611604Slayer case 'd': 29711604Slayer dum_opt = 1; 29811604Slayer break; 29911604Slayer case 'l': 30011604Slayer stop_opt = 0; 30111604Slayer break; 30211604Slayer case 'f': 30311604Slayer fold_opt = 0; 30411604Slayer break; 30511604Slayer case 'p': 30611604Slayer noscroll++; 30711604Slayer break; 30811604Slayer case 'c': 30911604Slayer clreol++; 31011604Slayer break; 31111604Slayer case 's': 31211604Slayer ssp_opt = 1; 31311604Slayer break; 31411604Slayer case 'u': 31511604Slayer ul_opt = 0; 31611604Slayer break; 31711604Slayer } 31811604Slayer } 3193455Sroot } 3203455Sroot 3213455Sroot 3221500Serics /* 3231500Serics ** Check whether the file named by fs is an ASCII file which the user may 3241500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3251500Serics */ 3261500Serics 3271500Serics FILE * 3281500Serics checkf (fs, clearfirst) 3291500Serics register char *fs; 3301500Serics int *clearfirst; 3311500Serics { 3321500Serics struct stat stbuf; 3331500Serics register FILE *f; 3341500Serics char c; 3351500Serics 3361500Serics if (stat (fs, &stbuf) == -1) { 3371500Serics fflush(stdout); 3383594Sroot if (clreol) 3393594Sroot cleareol (); 3401500Serics perror(fs); 3411500Serics return (NULL); 3421500Serics } 3431500Serics if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3441500Serics printf("\n*** %s: directory ***\n\n", fs); 3451500Serics return (NULL); 3461500Serics } 3471500Serics if ((f=Fopen(fs, "r")) == NULL) { 3481500Serics fflush(stdout); 3491500Serics perror(fs); 3501500Serics return (NULL); 3511500Serics } 3521500Serics c = Getc(f); 3531500Serics 3541500Serics /* Try to see whether it is an ASCII file */ 3551500Serics 3561500Serics switch ((c | *f->_ptr << 8) & 0177777) { 3571500Serics case 0405: 3581500Serics case 0407: 3591500Serics case 0410: 3601500Serics case 0411: 3611500Serics case 0413: 3621500Serics case 0177545: 3631500Serics printf("\n******** %s: Not a text file ********\n\n", fs); 3641500Serics fclose (f); 3651500Serics return (NULL); 3661500Serics default: 3671500Serics break; 3681500Serics } 3691500Serics if (c == '\f') 3701500Serics *clearfirst = 1; 3711500Serics else { 3721500Serics *clearfirst = 0; 3731500Serics Ungetc (c, f); 3741500Serics } 3751500Serics if ((file_size = stbuf.st_size) == 0) 3761500Serics file_size = 0x7fffffffffffffffL; 3771500Serics return (f); 3781500Serics } 3791500Serics 3801500Serics /* 3811500Serics ** A real function, for the tputs routine in termlib 3821500Serics */ 3831500Serics 3841500Serics putch (ch) 3851500Serics char ch; 3861500Serics { 3871500Serics putchar (ch); 3881500Serics } 3891500Serics 3901500Serics /* 3911500Serics ** Print out the contents of the file f, one screenful at a time. 3921500Serics */ 3931500Serics 3941500Serics #define STOP -10 3951500Serics 3961500Serics screen (f, num_lines) 3971500Serics register FILE *f; 3981500Serics register int num_lines; 3991500Serics { 4001500Serics register int c; 4011500Serics register int nchars; 4023594Sroot int length; /* length of current line */ 4033594Sroot static int prev_len = 1; /* length of previous line */ 4041500Serics 4051500Serics for (;;) { 4061500Serics while (num_lines > 0 && !Pause) { 4071500Serics if ((nchars = getline (f, &length)) == EOF) 4083455Sroot { 4093594Sroot if (clreol) 4103594Sroot clreos(); 4111500Serics return; 4123455Sroot } 4133594Sroot if (ssp_opt && length == 0 && prev_len == 0) 4143594Sroot continue; 4153594Sroot prev_len = length; 4161500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 4171500Serics erase (0); 4183594Sroot /* must clear before drawing line since tabs on some terminals 4193594Sroot * do not erase what they tab over. 4203594Sroot */ 4213594Sroot if (clreol) 4223594Sroot cleareol (); 4231500Serics prbuf (Line, length); 4241500Serics if (nchars < promptlen) 4251500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4261500Serics else promptlen = 0; 4273594Sroot /* is this needed? 4283594Sroot * if (clreol) 4293594Sroot * cleareol(); /* must clear again in case we wrapped * 4303594Sroot */ 4311500Serics if (nchars < Mcol || !fold_opt) 43216710Sjak prbuf("\n", 1); /* will turn off UL if necessary */ 4331500Serics if (nchars == STOP) 4341500Serics break; 4351500Serics num_lines--; 4361500Serics } 43716710Sjak if (pstate) { 43816710Sjak tputs(ULexit, 1, putch); 43916710Sjak pstate = 0; 44016710Sjak } 4411500Serics fflush(stdout); 4421500Serics if ((c = Getc(f)) == EOF) 4433455Sroot { 4443594Sroot if (clreol) 4453594Sroot clreos (); 4461500Serics return; 4473455Sroot } 4483455Sroot 4493594Sroot if (Pause && clreol) 4503594Sroot clreos (); 4511500Serics Ungetc (c, f); 4521500Serics setjmp (restore); 4531500Serics Pause = 0; startup = 0; 4541500Serics if ((num_lines = command (NULL, f)) == 0) 4551500Serics return; 4561500Serics if (hard && promptlen > 0) 4571500Serics erase (0); 45811123Slayer if (noscroll && num_lines >= dlines) 45916582Sleres { 4603594Sroot if (clreol) 4613594Sroot home(); 4623594Sroot else 4633594Sroot doclear (); 4643455Sroot } 4651500Serics screen_start.line = Currline; 4661500Serics screen_start.chrctr = Ftell (f); 4671500Serics } 4681500Serics } 4691500Serics 4701500Serics /* 4711500Serics ** Come here if a quit signal is received 4721500Serics */ 4731500Serics 4741500Serics onquit() 4751500Serics { 4761500Serics signal(SIGQUIT, SIG_IGN); 4771500Serics if (!inwait) { 4781500Serics putchar ('\n'); 4791500Serics if (!startup) { 4801500Serics signal(SIGQUIT, onquit); 4811500Serics longjmp (restore, 1); 4821500Serics } 4831500Serics else 4841500Serics Pause++; 4851500Serics } 4861500Serics else if (!dum_opt && notell) { 4871500Serics write (2, "[Use q or Q to quit]", 20); 4881500Serics promptlen += 20; 4891500Serics notell = 0; 4901500Serics } 4911500Serics signal(SIGQUIT, onquit); 4921500Serics } 4931500Serics 4941500Serics /* 495*27006Sdonn ** Come here if a signal for a window size change is received 496*27006Sdonn */ 497*27006Sdonn 498*27006Sdonn chgwinsz() 499*27006Sdonn { 500*27006Sdonn struct winsize win; 501*27006Sdonn 502*27006Sdonn (void) signal(SIGWINCH, SIG_IGN); 503*27006Sdonn if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { 504*27006Sdonn if (win.ws_row != 0) { 505*27006Sdonn Lpp = win.ws_row; 506*27006Sdonn nscroll = Lpp/2 - 1; 507*27006Sdonn if (nscroll <= 0) 508*27006Sdonn nscroll = 1; 509*27006Sdonn dlines = Lpp - (noscroll ? 1 : 2); 510*27006Sdonn } 511*27006Sdonn if (win.ws_col != 0) 512*27006Sdonn Mcol = win.ws_col; 513*27006Sdonn } 514*27006Sdonn (void) signal(SIGWINCH, chgwinsz); 515*27006Sdonn } 516*27006Sdonn 517*27006Sdonn /* 5181500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 5191500Serics */ 5201500Serics 5211500Serics end_it () 5221500Serics { 5231500Serics 5241500Serics reset_tty (); 5253594Sroot if (clreol) { 5263594Sroot putchar ('\r'); 5273594Sroot clreos (); 5283594Sroot fflush (stdout); 5293594Sroot } 5303455Sroot else if (!clreol && (promptlen > 0)) { 5311500Serics kill_line (); 5321500Serics fflush (stdout); 5331500Serics } 5341500Serics else 5351500Serics write (2, "\n", 1); 5361500Serics _exit(0); 5371500Serics } 5381500Serics 5391500Serics copy_file(f) 5401500Serics register FILE *f; 5411500Serics { 5421500Serics register int c; 5431500Serics 5441500Serics while ((c = getc(f)) != EOF) 5451500Serics putchar(c); 5461500Serics } 5471500Serics 5481500Serics /* Simplified printf function */ 5491500Serics 5501500Serics printf (fmt, args) 5511500Serics register char *fmt; 5521500Serics int args; 5531500Serics { 5541500Serics register int *argp; 5551500Serics register char ch; 5561500Serics register int ccount; 5571500Serics 5581500Serics ccount = 0; 5591500Serics argp = &args; 5601500Serics while (*fmt) { 5611500Serics while ((ch = *fmt++) != '%') { 5621500Serics if (ch == '\0') 5631500Serics return (ccount); 5641500Serics ccount++; 5651500Serics putchar (ch); 5661500Serics } 5671500Serics switch (*fmt++) { 5681500Serics case 'd': 5691500Serics ccount += printd (*argp); 5701500Serics break; 5711500Serics case 's': 5721500Serics ccount += pr ((char *)*argp); 5731500Serics break; 5741500Serics case '%': 5751500Serics ccount++; 5761500Serics argp--; 5771500Serics putchar ('%'); 5781500Serics break; 5791500Serics case '0': 5801500Serics return (ccount); 5811500Serics default: 5821500Serics break; 5831500Serics } 5841500Serics ++argp; 5851500Serics } 5861500Serics return (ccount); 5871500Serics 5881500Serics } 5891500Serics 5901500Serics /* 5911500Serics ** Print an integer as a string of decimal digits, 5921500Serics ** returning the length of the print representation. 5931500Serics */ 5941500Serics 5951500Serics printd (n) 5961500Serics int n; 5971500Serics { 5981500Serics int a, nchars; 5991500Serics 6001500Serics if (a = n/10) 6011500Serics nchars = 1 + printd(a); 6021500Serics else 6031500Serics nchars = 1; 6041500Serics putchar (n % 10 + '0'); 6051500Serics return (nchars); 6061500Serics } 6071500Serics 6081500Serics /* Put the print representation of an integer into a string */ 6091500Serics static char *sptr; 6101500Serics 6111500Serics scanstr (n, str) 6121500Serics int n; 6131500Serics char *str; 6141500Serics { 6151500Serics sptr = str; 61611604Slayer Sprintf (n); 6171500Serics *sptr = '\0'; 6181500Serics } 6191500Serics 62011604Slayer Sprintf (n) 6211500Serics { 6221500Serics int a; 6231500Serics 6241500Serics if (a = n/10) 62511604Slayer Sprintf (a); 6261500Serics *sptr++ = n % 10 + '0'; 6271500Serics } 6281500Serics 6291500Serics static char bell = ctrl(G); 6301500Serics 6311500Serics strlen (s) 6321500Serics char *s; 6331500Serics { 6341500Serics register char *p; 6351500Serics 6361500Serics p = s; 6371500Serics while (*p++) 6381500Serics ; 6391500Serics return (p - s - 1); 6401500Serics } 6411500Serics 6421500Serics /* See whether the last component of the path name "path" is equal to the 6431500Serics ** string "string" 6441500Serics */ 6451500Serics 6461500Serics tailequ (path, string) 6471500Serics char *path; 6481500Serics register char *string; 6491500Serics { 6501500Serics register char *tail; 6511500Serics 6521500Serics tail = path + strlen(path); 6531500Serics while (tail >= path) 6541500Serics if (*(--tail) == '/') 6551500Serics break; 6561500Serics ++tail; 6571500Serics while (*tail++ == *string++) 6581500Serics if (*tail == '\0') 6591500Serics return(1); 6601500Serics return(0); 6611500Serics } 6621500Serics 6631500Serics prompt (filename) 6641500Serics char *filename; 6651500Serics { 6663594Sroot if (clreol) 6673594Sroot cleareol (); 6683455Sroot else if (promptlen > 0) 6691500Serics kill_line (); 6701500Serics if (!hard) { 6711500Serics promptlen = 8; 67216710Sjak if (Senter && Sexit) { 6731500Serics tputs (Senter, 1, putch); 67416710Sjak promptlen += (2 * soglitch); 67516710Sjak } 6763594Sroot if (clreol) 6773594Sroot cleareol (); 6781500Serics pr("--More--"); 6791500Serics if (filename != NULL) { 6801500Serics promptlen += printf ("(Next file: %s)", filename); 6811500Serics } 6821500Serics else if (!no_intty) { 6831500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 6841500Serics } 6851500Serics if (dum_opt) { 68616710Sjak promptlen += pr("[Press space to continue, 'q' to quit.]"); 6871500Serics } 6881500Serics if (Senter && Sexit) 6891500Serics tputs (Sexit, 1, putch); 6903594Sroot if (clreol) 6913594Sroot clreos (); 6921500Serics fflush(stdout); 6931500Serics } 6941500Serics else 6951500Serics write (2, &bell, 1); 6961500Serics inwait++; 6971500Serics } 6981500Serics 6991500Serics /* 7001500Serics ** Get a logical line 7011500Serics */ 7021500Serics 7031500Serics getline(f, length) 7041500Serics register FILE *f; 7051500Serics int *length; 7061500Serics { 7071500Serics register int c; 7081500Serics register char *p; 7091500Serics register int column; 7101500Serics static int colflg; 7111500Serics 7121500Serics p = Line; 7131500Serics column = 0; 7141500Serics c = Getc (f); 7151500Serics if (colflg && c == '\n') { 7161500Serics Currline++; 7171500Serics c = Getc (f); 7181500Serics } 7191500Serics while (p < &Line[LINSIZ - 1]) { 7201500Serics if (c == EOF) { 7211500Serics if (p > Line) { 7221500Serics *p = '\0'; 7231500Serics *length = p - Line; 7241500Serics return (column); 7251500Serics } 7261500Serics *length = p - Line; 7271500Serics return (EOF); 7281500Serics } 7291500Serics if (c == '\n') { 7301500Serics Currline++; 7311500Serics break; 7321500Serics } 7331500Serics *p++ = c; 7341500Serics if (c == '\t') 7351500Serics if (hardtabs && column < promptlen && !hard) { 7361500Serics if (eraseln && !dumb) { 7371500Serics column = 1 + (column | 7); 7381500Serics tputs (eraseln, 1, putch); 7391500Serics promptlen = 0; 7401500Serics } 7411500Serics else { 7421500Serics for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 7431500Serics *p++ = ' '; 7441500Serics } 7451500Serics if (column >= promptlen) promptlen = 0; 7461500Serics } 7471500Serics } 7481500Serics else 7491500Serics column = 1 + (column | 7); 7509627Ssklower else if (c == '\b' && column > 0) 7511500Serics column--; 7521500Serics else if (c == '\r') 7531500Serics column = 0; 7541500Serics else if (c == '\f' && stop_opt) { 7551500Serics p[-1] = '^'; 7561500Serics *p++ = 'L'; 7571500Serics column += 2; 7581500Serics Pause++; 7591500Serics } 7601500Serics else if (c == EOF) { 7611500Serics *length = p - Line; 7621500Serics return (column); 7631500Serics } 7641500Serics else if (c >= ' ' && c != RUBOUT) 7651500Serics column++; 7661500Serics if (column >= Mcol && fold_opt) break; 7671500Serics c = Getc (f); 7681500Serics } 7691500Serics if (column >= Mcol && Mcol > 0) { 7701500Serics if (!Wrap) { 7711500Serics *p++ = '\n'; 7721500Serics } 7731500Serics } 7741500Serics colflg = column == Mcol && fold_opt; 7751500Serics *length = p - Line; 7761500Serics *p = 0; 7771500Serics return (column); 7781500Serics } 7791500Serics 7801500Serics /* 7811500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 7821500Serics */ 7831500Serics 7841500Serics erase (col) 7851500Serics register int col; 7861500Serics { 7871500Serics 7881500Serics if (promptlen == 0) 7891500Serics return; 7901500Serics if (hard) { 7911500Serics putchar ('\n'); 7921500Serics } 7931500Serics else { 7941500Serics if (col == 0) 7951500Serics putchar ('\r'); 7961500Serics if (!dumb && eraseln) 7971500Serics tputs (eraseln, 1, putch); 7981500Serics else 7991500Serics for (col = promptlen - col; col > 0; col--) 8001500Serics putchar (' '); 8011500Serics } 8021500Serics promptlen = 0; 8031500Serics } 8041500Serics 8051500Serics /* 8061500Serics ** Erase the current line entirely 8071500Serics */ 8081500Serics 8091500Serics kill_line () 8101500Serics { 8111500Serics erase (0); 8121500Serics if (!eraseln || dumb) putchar ('\r'); 8131500Serics } 8141500Serics 8151500Serics /* 8163455Sroot * force clear to end of line 8173455Sroot */ 8183455Sroot cleareol() 8193455Sroot { 8203594Sroot tputs(eraseln, 1, putch); 8213455Sroot } 8223455Sroot 8233594Sroot clreos() 8243455Sroot { 8253594Sroot tputs(EodClr, 1, putch); 8263455Sroot } 8273455Sroot 8283455Sroot /* 8291500Serics ** Print string and return number of characters 8301500Serics */ 8311500Serics 8321500Serics pr(s1) 8331500Serics char *s1; 8341500Serics { 8351500Serics register char *s; 8361500Serics register char c; 8371500Serics 8381500Serics for (s = s1; c = *s++; ) 8391500Serics putchar(c); 8401500Serics return (s - s1 - 1); 8411500Serics } 8421500Serics 8431500Serics 8441500Serics /* Print a buffer of n characters */ 8451500Serics 8461500Serics prbuf (s, n) 8471500Serics register char *s; 8481500Serics register int n; 8491500Serics { 85016710Sjak register char c; /* next output character */ 8513594Sroot register int state; /* next output char's UL state */ 85216710Sjak #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 8533594Sroot 8543594Sroot while (--n >= 0) 8553594Sroot if (!ul_opt) 8563594Sroot putchar (*s++); 8573594Sroot else { 85816710Sjak if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 85916710Sjak s++; 86016710Sjak continue; 86116710Sjak } 86216710Sjak if (state = wouldul(s, n)) { 86316710Sjak c = (*s == '_')? s[2] : *s ; 8643594Sroot n -= 2; 86516710Sjak s += 3; 86616710Sjak } else 8673594Sroot c = *s++; 86816710Sjak if (state != pstate) { 86916710Sjak if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 87016710Sjak state = 1; 87116710Sjak else 87216710Sjak tputs(state ? ULenter : ULexit, 1, putch); 8733594Sroot } 87416710Sjak if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 87516710Sjak putchar(c); 8763594Sroot if (state && *chUL) { 8773594Sroot pr(chBS); 8783594Sroot tputs(chUL, 1, putch); 8793594Sroot } 88016710Sjak pstate = state; 8813594Sroot } 8821500Serics } 8831500Serics 8841500Serics /* 8851500Serics ** Clear the screen 8861500Serics */ 8871500Serics 8881500Serics doclear() 8891500Serics { 8901500Serics if (Clear && !hard) { 8911500Serics tputs(Clear, 1, putch); 8921500Serics 8931500Serics /* Put out carriage return so that system doesn't 8941500Serics ** get confused by escape sequences when expanding tabs 8951500Serics */ 8961500Serics putchar ('\r'); 8971500Serics promptlen = 0; 8981500Serics } 8991500Serics } 9001500Serics 9013455Sroot /* 9023455Sroot * Go to home position 9033455Sroot */ 9043455Sroot home() 9053455Sroot { 9063455Sroot tputs(Home,1,putch); 9073455Sroot } 9083455Sroot 9091500Serics static int lastcmd, lastarg, lastp; 9101500Serics static int lastcolon; 9111500Serics char shell_line[132]; 9121500Serics 9131500Serics /* 9141500Serics ** Read a command and do it. A command consists of an optional integer 9151500Serics ** argument followed by the command character. Return the number of lines 9161500Serics ** to display in the next screenful. If there is nothing more to display 9171500Serics ** in the current file, zero is returned. 9181500Serics */ 9191500Serics 9201500Serics command (filename, f) 9211500Serics char *filename; 9221500Serics register FILE *f; 9231500Serics { 9241500Serics register int nlines; 9251500Serics register int retval; 9261500Serics register char c; 9271500Serics char colonch; 9281500Serics FILE *helpf; 9291500Serics int done; 9301500Serics char comchar, cmdbuf[80], *p; 9311500Serics 9321500Serics #define ret(val) retval=val;done++;break 9331500Serics 9341500Serics done = 0; 9351500Serics if (!errors) 9361500Serics prompt (filename); 9371500Serics else 9381500Serics errors = 0; 9391500Serics if (MBIT == RAW && slow_tty) { 9401500Serics otty.sg_flags |= MBIT; 94116582Sleres stty(fileno(stderr), &otty); 9421500Serics } 9431500Serics for (;;) { 9441500Serics nlines = number (&comchar); 9451500Serics lastp = colonch = 0; 9461500Serics if (comchar == '.') { /* Repeat last command */ 9471500Serics lastp++; 9481500Serics comchar = lastcmd; 9491500Serics nlines = lastarg; 9501500Serics if (lastcmd == ':') 9511500Serics colonch = lastcolon; 9521500Serics } 9531500Serics lastcmd = comchar; 9541500Serics lastarg = nlines; 9551500Serics if (comchar == otty.sg_erase) { 9561500Serics kill_line (); 9571500Serics prompt (filename); 9581500Serics continue; 9591500Serics } 9601500Serics switch (comchar) { 9611500Serics case ':': 9621500Serics retval = colon (filename, colonch, nlines); 9631500Serics if (retval >= 0) 9641500Serics done++; 9651500Serics break; 96624490Sbloom case 'b': 96724490Sbloom case ctrl(B): 96824490Sbloom { 96924490Sbloom register int initline; 97024490Sbloom 97124490Sbloom if (no_intty) { 97224490Sbloom write(2, &bell, 1); 97324490Sbloom return (-1); 97424490Sbloom } 97524490Sbloom 97624490Sbloom if (nlines == 0) nlines++; 97724490Sbloom 97824490Sbloom putchar ('\r'); 97924490Sbloom erase (0); 98024490Sbloom printf ("\n"); 98124490Sbloom if (clreol) 98224490Sbloom cleareol (); 98324490Sbloom printf ("...back %d page", nlines); 98424490Sbloom if (nlines > 1) 98524490Sbloom pr ("s\n"); 98624490Sbloom else 98724490Sbloom pr ("\n"); 98824490Sbloom 98924490Sbloom if (clreol) 99024490Sbloom cleareol (); 99124490Sbloom pr ("\n"); 99224490Sbloom 99324490Sbloom initline = Currline - dlines * (nlines + 1); 99424490Sbloom if (! noscroll) 99524490Sbloom --initline; 99624490Sbloom if (initline < 0) initline = 0; 99724490Sbloom Fseek(f, 0L); 99824490Sbloom Currline = 0; /* skiplns() will make Currline correct */ 99924490Sbloom skiplns(initline, f); 100024490Sbloom if (! noscroll) { 100124490Sbloom ret(dlines + 1); 100224490Sbloom } 100324490Sbloom else { 100424490Sbloom ret(dlines); 100524490Sbloom } 100624490Sbloom } 10071500Serics case ' ': 10081500Serics case 'z': 10091500Serics if (nlines == 0) nlines = dlines; 10101500Serics else if (comchar == 'z') dlines = nlines; 10111500Serics ret (nlines); 10121500Serics case 'd': 10131500Serics case ctrl(D): 10141500Serics if (nlines != 0) nscroll = nlines; 10151500Serics ret (nscroll); 10161500Serics case 'q': 10171500Serics case 'Q': 10181500Serics end_it (); 10191500Serics case 's': 10201500Serics case 'f': 10211500Serics if (nlines == 0) nlines++; 10221500Serics if (comchar == 'f') 10231500Serics nlines *= dlines; 10241500Serics putchar ('\r'); 10251500Serics erase (0); 10263594Sroot printf ("\n"); 10273594Sroot if (clreol) 10283594Sroot cleareol (); 10293594Sroot printf ("...skipping %d line", nlines); 10301500Serics if (nlines > 1) 10313594Sroot pr ("s\n"); 10321500Serics else 10333594Sroot pr ("\n"); 10343594Sroot 10353594Sroot if (clreol) 10363594Sroot cleareol (); 10373594Sroot pr ("\n"); 10383594Sroot 10391500Serics while (nlines > 0) { 10401500Serics while ((c = Getc (f)) != '\n') 10411500Serics if (c == EOF) { 10421500Serics retval = 0; 10431500Serics done++; 10441500Serics goto endsw; 10451500Serics } 10461500Serics Currline++; 10471500Serics nlines--; 10481500Serics } 10491500Serics ret (dlines); 10501500Serics case '\n': 10511500Serics if (nlines != 0) 10521500Serics dlines = nlines; 10531500Serics else 10541500Serics nlines = 1; 10551500Serics ret (nlines); 10561500Serics case '\f': 10571500Serics if (!no_intty) { 10581500Serics doclear (); 10591500Serics Fseek (f, screen_start.chrctr); 10601500Serics Currline = screen_start.line; 10611500Serics ret (dlines); 10621500Serics } 10631500Serics else { 10641500Serics write (2, &bell, 1); 10651500Serics break; 10661500Serics } 10671500Serics case '\'': 10681500Serics if (!no_intty) { 10691500Serics kill_line (); 10701500Serics pr ("\n***Back***\n\n"); 10711500Serics Fseek (f, context.chrctr); 10721500Serics Currline = context.line; 10731500Serics ret (dlines); 10741500Serics } 10751500Serics else { 10761500Serics write (2, &bell, 1); 10771500Serics break; 10781500Serics } 10791500Serics case '=': 10801500Serics kill_line (); 10811500Serics promptlen = printd (Currline); 10821500Serics fflush (stdout); 10831500Serics break; 10841500Serics case 'n': 10851500Serics lastp++; 10861500Serics case '/': 10871500Serics if (nlines == 0) nlines++; 10881500Serics kill_line (); 10891500Serics pr ("/"); 10901500Serics promptlen = 1; 10911500Serics fflush (stdout); 10921500Serics if (lastp) { 10931500Serics write (2,"\r", 1); 10941500Serics search (NULL, f, nlines); /* Use previous r.e. */ 10951500Serics } 10961500Serics else { 10971500Serics ttyin (cmdbuf, 78, '/'); 10981500Serics write (2, "\r", 1); 10991500Serics search (cmdbuf, f, nlines); 11001500Serics } 11013455Sroot ret (dlines-1); 11021500Serics case '!': 11031500Serics do_shell (filename); 11041500Serics break; 110524490Sbloom case '?': 11061500Serics case 'h': 11071500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 11081500Serics error ("Can't open help file"); 11091500Serics if (noscroll) doclear (); 11101500Serics copy_file (helpf); 1111*27006Sdonn fclose (helpf); 11121500Serics prompt (filename); 11131500Serics break; 11141500Serics case 'v': /* This case should go right before default */ 11151500Serics if (!no_intty) { 11161500Serics kill_line (); 11171500Serics cmdbuf[0] = '+'; 111824490Sbloom scanstr (Currline - dlines < 0 ? 0 111924490Sbloom : Currline - (dlines + 1) / 2, &cmdbuf[1]); 11201500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 11211500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 11221500Serics break; 11231500Serics } 11241500Serics default: 112516710Sjak if (dum_opt) { 112616710Sjak kill_line (); 112716710Sjak if (Senter && Sexit) { 112816710Sjak tputs (Senter, 1, putch); 112916710Sjak promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 113016710Sjak tputs (Sexit, 1, putch); 113116710Sjak } 113216710Sjak else 113316710Sjak promptlen = pr ("[Press 'h' for instructions.]"); 113416710Sjak fflush (stdout); 113516710Sjak } 113616710Sjak else 113716710Sjak write (2, &bell, 1); 11381500Serics break; 11391500Serics } 11401500Serics if (done) break; 11411500Serics } 11421500Serics putchar ('\r'); 11431500Serics endsw: 11441500Serics inwait = 0; 11451500Serics notell++; 11461500Serics if (MBIT == RAW && slow_tty) { 11471500Serics otty.sg_flags &= ~MBIT; 114816582Sleres stty(fileno(stderr), &otty); 11491500Serics } 11501500Serics return (retval); 11511500Serics } 11521500Serics 11531500Serics char ch; 11541500Serics 11551500Serics /* 11561500Serics * Execute a colon-prefixed command. 11571500Serics * Returns <0 if not a command that should cause 11581500Serics * more of the file to be printed. 11591500Serics */ 11601500Serics 11611500Serics colon (filename, cmd, nlines) 11621500Serics char *filename; 11631500Serics int cmd; 11641500Serics int nlines; 11651500Serics { 11661500Serics if (cmd == 0) 11671500Serics ch = readch (); 11681500Serics else 11691500Serics ch = cmd; 11701500Serics lastcolon = ch; 11711500Serics switch (ch) { 11721500Serics case 'f': 11731500Serics kill_line (); 11741500Serics if (!no_intty) 11751500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 11761500Serics else 11771500Serics promptlen = printf ("[Not a file] line %d", Currline); 11781500Serics fflush (stdout); 11791500Serics return (-1); 11801500Serics case 'n': 11811500Serics if (nlines == 0) { 11821500Serics if (fnum >= nfiles - 1) 11831500Serics end_it (); 11841500Serics nlines++; 11851500Serics } 11861500Serics putchar ('\r'); 11871500Serics erase (0); 11881500Serics skipf (nlines); 11891500Serics return (0); 11901500Serics case 'p': 11911500Serics if (no_intty) { 11921500Serics write (2, &bell, 1); 11931500Serics return (-1); 11941500Serics } 11951500Serics putchar ('\r'); 11961500Serics erase (0); 11971500Serics if (nlines == 0) 11981500Serics nlines++; 11991500Serics skipf (-nlines); 12001500Serics return (0); 12011500Serics case '!': 12021500Serics do_shell (filename); 12031500Serics return (-1); 12041500Serics case 'q': 12051500Serics case 'Q': 12061500Serics end_it (); 12071500Serics default: 12081500Serics write (2, &bell, 1); 12091500Serics return (-1); 12101500Serics } 12111500Serics } 12121500Serics 12131500Serics /* 12141500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 12151500Serics ** terminates the number. 12161500Serics */ 12171500Serics 12181500Serics number(cmd) 12191500Serics char *cmd; 12201500Serics { 12211500Serics register int i; 12221500Serics 12231500Serics i = 0; ch = otty.sg_kill; 12241500Serics for (;;) { 12251500Serics ch = readch (); 12261500Serics if (ch >= '0' && ch <= '9') 12271500Serics i = i*10 + ch - '0'; 12281500Serics else if (ch == otty.sg_kill) 12291500Serics i = 0; 12301500Serics else { 12311500Serics *cmd = ch; 12321500Serics break; 12331500Serics } 12341500Serics } 12351500Serics return (i); 12361500Serics } 12371500Serics 12381500Serics do_shell (filename) 12391500Serics char *filename; 12401500Serics { 12411500Serics char cmdbuf[80]; 12421500Serics 12431500Serics kill_line (); 12441500Serics pr ("!"); 12451500Serics fflush (stdout); 12461500Serics promptlen = 1; 12471500Serics if (lastp) 12481500Serics pr (shell_line); 12491500Serics else { 12501500Serics ttyin (cmdbuf, 78, '!'); 12511500Serics if (expand (shell_line, cmdbuf)) { 12521500Serics kill_line (); 12531500Serics promptlen = printf ("!%s", shell_line); 12541500Serics } 12551500Serics } 12561500Serics fflush (stdout); 12571500Serics write (2, "\n", 1); 12581500Serics promptlen = 0; 12591500Serics shellp = 1; 12601500Serics execute (filename, shell, shell, "-c", shell_line, 0); 12611500Serics } 12621500Serics 12631500Serics /* 12641500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 12651500Serics */ 12661500Serics 12671500Serics search (buf, file, n) 12681500Serics char buf[]; 12691500Serics FILE *file; 12701500Serics register int n; 12711500Serics { 12721500Serics long startline = Ftell (file); 12731500Serics register long line1 = startline; 12741500Serics register long line2 = startline; 12751500Serics register long line3 = startline; 12761500Serics register int lncount; 12771500Serics int saveln, rv, re_exec(); 12781500Serics char *s, *re_comp(); 12791500Serics 12801500Serics context.line = saveln = Currline; 12811500Serics context.chrctr = startline; 12821500Serics lncount = 0; 12831500Serics if ((s = re_comp (buf)) != 0) 12841500Serics error (s); 12851500Serics while (!feof (file)) { 12861500Serics line3 = line2; 12871500Serics line2 = line1; 12881500Serics line1 = Ftell (file); 12891500Serics rdline (file); 12901500Serics lncount++; 12911500Serics if ((rv = re_exec (Line)) == 1) 12921500Serics if (--n == 0) { 12931500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 12943455Sroot { 12953455Sroot pr ("\n"); 12963594Sroot if (clreol) 12973594Sroot cleareol (); 12983455Sroot pr("...skipping\n"); 12993455Sroot } 13001500Serics if (!no_intty) { 13011500Serics Currline -= (lncount >= 3 ? 3 : lncount); 13021500Serics Fseek (file, line3); 13033594Sroot if (noscroll) 13043594Sroot if (clreol) { 13053594Sroot home (); 13063594Sroot cleareol (); 130716582Sleres } 13083594Sroot else 13093594Sroot doclear (); 13101500Serics } 13111500Serics else { 13121500Serics kill_line (); 13133594Sroot if (noscroll) 13143594Sroot if (clreol) { 131516582Sleres home (); 13163594Sroot cleareol (); 131716582Sleres } 13183594Sroot else 13193594Sroot doclear (); 13201500Serics pr (Line); 13211500Serics putchar ('\n'); 13221500Serics } 13231500Serics break; 13241500Serics } 13251500Serics else if (rv == -1) 13261500Serics error ("Regular expression botch"); 13271500Serics } 13281500Serics if (feof (file)) { 13291500Serics if (!no_intty) { 13301500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 13311500Serics Currline = saveln; 13321500Serics Fseek (file, startline); 13331500Serics } 13341500Serics else { 13351500Serics pr ("\nPattern not found\n"); 13361500Serics end_it (); 13371500Serics } 13381500Serics error ("Pattern not found"); 13391500Serics } 13401500Serics } 13411500Serics 13421500Serics execute (filename, cmd, args) 13431500Serics char *filename; 13441500Serics char *cmd, *args; 13451500Serics { 13461500Serics int id; 134716710Sjak int n; 13481500Serics 13491500Serics fflush (stdout); 13501500Serics reset_tty (); 135116710Sjak for (n = 10; (id = fork ()) < 0 && n > 0; n--) 13521500Serics sleep (5); 13531500Serics if (id == 0) { 135416710Sjak if (!isatty(0)) { 135516710Sjak close(0); 135616710Sjak open("/dev/tty", 0); 135716710Sjak } 13581500Serics execv (cmd, &args); 13591500Serics write (2, "exec failed\n", 12); 13601500Serics exit (1); 13611500Serics } 136216710Sjak if (id > 0) { 136316710Sjak signal (SIGINT, SIG_IGN); 136416710Sjak signal (SIGQUIT, SIG_IGN); 136516710Sjak if (catch_susp) 136616710Sjak signal(SIGTSTP, SIG_DFL); 136716710Sjak while (wait(0) > 0); 136816710Sjak signal (SIGINT, end_it); 136916710Sjak signal (SIGQUIT, onquit); 137016710Sjak if (catch_susp) 137116710Sjak signal(SIGTSTP, onsusp); 137216710Sjak } else 137316710Sjak write(2, "can't fork\n", 11); 13741500Serics set_tty (); 13751500Serics pr ("------------------------\n"); 13761500Serics prompt (filename); 13771500Serics } 13781500Serics /* 13791500Serics ** Skip n lines in the file f 13801500Serics */ 13811500Serics 13821500Serics skiplns (n, f) 13831500Serics register int n; 13841500Serics register FILE *f; 13851500Serics { 13861500Serics register char c; 13871500Serics 13881500Serics while (n > 0) { 13891500Serics while ((c = Getc (f)) != '\n') 13901500Serics if (c == EOF) 13911500Serics return; 13921500Serics n--; 13931500Serics Currline++; 13941500Serics } 13951500Serics } 13961500Serics 13971500Serics /* 13981500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 13991500Serics ** negative. 14001500Serics */ 14011500Serics 14021500Serics skipf (nskip) 14031500Serics register int nskip; 14041500Serics { 14051500Serics if (nskip == 0) return; 14061500Serics if (nskip > 0) { 14071500Serics if (fnum + nskip > nfiles - 1) 14081500Serics nskip = nfiles - fnum - 1; 14091500Serics } 14101500Serics else if (within) 14111500Serics ++fnum; 14121500Serics fnum += nskip; 14131500Serics if (fnum < 0) 14141500Serics fnum = 0; 14153594Sroot pr ("\n...Skipping "); 14163455Sroot pr ("\n"); 14173594Sroot if (clreol) 14183594Sroot cleareol (); 14193455Sroot pr ("...Skipping "); 14201500Serics pr (nskip > 0 ? "to file " : "back to file "); 14211500Serics pr (fnames[fnum]); 14223455Sroot pr ("\n"); 14233594Sroot if (clreol) 14243594Sroot cleareol (); 14253455Sroot pr ("\n"); 14261500Serics --fnum; 14271500Serics } 14281500Serics 14291500Serics /*----------------------------- Terminal I/O -------------------------------*/ 14301500Serics 14311500Serics initterm () 14321500Serics { 14331500Serics char buf[TBUFSIZ]; 143417195Sralph static char clearbuf[TBUFSIZ]; 14351500Serics char *clearptr, *padstr; 14361500Serics int ldisc; 143717592Sleres int lmode; 143810823Ssam char *term; 143916582Sleres int tgrp; 144018030Sbloom struct winsize win; 14411500Serics 144216582Sleres retry: 144316582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 144417592Sleres if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { 144517592Sleres perror("TIOCLGET"); 144617592Sleres exit(1); 144717592Sleres } 144817592Sleres docrterase = ((lmode & LCRTERA) != 0); 144917592Sleres docrtkill = ((lmode & LCRTKIL) != 0); 145016582Sleres /* 145117592Sleres * Wait until we're in the foreground before we save the 145217592Sleres * the terminal modes. 145316582Sleres */ 145416582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 145517592Sleres perror("TIOCGPGRP"); 145616582Sleres exit(1); 145716582Sleres } 145816582Sleres if (tgrp != getpgrp(0)) { 145916582Sleres kill(0, SIGTTOU); 146016582Sleres goto retry; 146116582Sleres } 146213830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 14633594Sroot dumb++; ul_opt = 0; 14641500Serics } 14651500Serics else { 146618030Sbloom if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { 146718030Sbloom Lpp = tgetnum("li"); 146818030Sbloom Mcol = tgetnum("co"); 146918030Sbloom } else { 147018030Sbloom if ((Lpp = win.ws_row) == 0) 147118030Sbloom Lpp = tgetnum("li"); 147218030Sbloom if ((Mcol = win.ws_col) == 0) 147318030Sbloom Mcol = tgetnum("co"); 147418030Sbloom } 147518030Sbloom if ((Lpp <= 0) || tgetflag("hc")) { 14761500Serics hard++; /* Hard copy terminal */ 14771500Serics Lpp = 24; 14781500Serics } 147918030Sbloom if (Mcol <= 0) 148018030Sbloom Mcol = 80; 148118030Sbloom 14821500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 14831500Serics noscroll++; 14841500Serics Wrap = tgetflag("am"); 14851500Serics bad_so = tgetflag ("xs"); 14861500Serics clearptr = clearbuf; 14871500Serics eraseln = tgetstr("ce",&clearptr); 14881500Serics Clear = tgetstr("cl", &clearptr); 14891500Serics Senter = tgetstr("so", &clearptr); 14901500Serics Sexit = tgetstr("se", &clearptr); 149116710Sjak if ((soglitch = tgetnum("sg")) < 0) 149216710Sjak soglitch = 0; 14933594Sroot 14943594Sroot /* 14953594Sroot * Set up for underlining: some terminals don't need it; 14963594Sroot * others have start/stop sequences, still others have an 14973594Sroot * underline char sequence which is assumed to move the 14983594Sroot * cursor forward one character. If underline sequence 14993594Sroot * isn't available, settle for standout sequence. 15003594Sroot */ 15013594Sroot 15023594Sroot if (tgetflag("ul") || tgetflag("os")) 15033594Sroot ul_opt = 0; 15043594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 15053594Sroot chUL = ""; 150616710Sjak if (((ULenter = tgetstr("us", &clearptr)) == NULL || 150716710Sjak (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 150816710Sjak if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 150916710Sjak ULenter = ""; 151016710Sjak ULexit = ""; 151116710Sjak } else 151216710Sjak ulglitch = soglitch; 151316710Sjak } else { 151416710Sjak if ((ulglitch = tgetnum("ug")) < 0) 151516710Sjak ulglitch = 0; 151616710Sjak } 151716582Sleres 15181500Serics if (padstr = tgetstr("pc", &clearptr)) 15191500Serics PC = *padstr; 15203455Sroot Home = tgetstr("ho",&clearptr); 152113536Ssam if (Home == 0 || *Home == '\0') 15223455Sroot { 15233594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 15243594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 15253455Sroot Home = cursorhome; 15263455Sroot } 15273455Sroot } 15283594Sroot EodClr = tgetstr("cd", &clearptr); 152925540Smckusick if ((chBS = tgetstr("bc", &clearptr)) == NULL) 153025540Smckusick chBS = "\b"; 153125540Smckusick 15321500Serics } 15331500Serics if ((shell = getenv("SHELL")) == NULL) 15341500Serics shell = "/bin/sh"; 15351500Serics } 153616582Sleres no_intty = gtty(fileno(stdin), &otty); 153716582Sleres gtty(fileno(stderr), &otty); 153813830Skre savetty = otty; 15391500Serics ospeed = otty.sg_ospeed; 15401500Serics slow_tty = ospeed < B1200; 1541*27006Sdonn hardtabs = (otty.sg_flags & TBDELAY) != XTABS; 15421500Serics if (!no_tty) { 15431500Serics otty.sg_flags &= ~ECHO; 15441500Serics if (MBIT == CBREAK || !slow_tty) 15451500Serics otty.sg_flags |= MBIT; 15461500Serics } 15471500Serics } 15481500Serics 15491500Serics readch () 15501500Serics { 15511500Serics char ch; 15521500Serics extern int errno; 15531500Serics 15541500Serics if (read (2, &ch, 1) <= 0) 15551500Serics if (errno != EINTR) 15561500Serics exit(0); 15571500Serics else 15581500Serics ch = otty.sg_kill; 15591500Serics return (ch); 15601500Serics } 15611500Serics 15621500Serics static char BS = '\b'; 156317592Sleres static char *BSB = "\b \b"; 15641500Serics static char CARAT = '^'; 156517592Sleres #define ERASEONECHAR \ 156617592Sleres if (docrterase) \ 156717592Sleres write (2, BSB, sizeof(BSB)); \ 156817592Sleres else \ 156917592Sleres write (2, &BS, sizeof(BS)); 15701500Serics 15711500Serics ttyin (buf, nmax, pchar) 15721500Serics char buf[]; 15731500Serics register int nmax; 15741500Serics char pchar; 15751500Serics { 15761500Serics register char *sptr; 15771500Serics register char ch; 15781500Serics register int slash = 0; 15791500Serics int maxlen; 15801500Serics char cbuf; 15811500Serics 15821500Serics sptr = buf; 15831500Serics maxlen = 0; 15841500Serics while (sptr - buf < nmax) { 15851500Serics if (promptlen > maxlen) maxlen = promptlen; 15861500Serics ch = readch (); 15871500Serics if (ch == '\\') { 15881500Serics slash++; 15891500Serics } 15901500Serics else if ((ch == otty.sg_erase) && !slash) { 15911500Serics if (sptr > buf) { 15921500Serics --promptlen; 159317592Sleres ERASEONECHAR 15941500Serics --sptr; 15951500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 15961500Serics --promptlen; 159717592Sleres ERASEONECHAR 15981500Serics } 15991500Serics continue; 16001500Serics } 16011500Serics else { 16021500Serics if (!eraseln) promptlen = maxlen; 16031500Serics longjmp (restore, 1); 16041500Serics } 16051500Serics } 16061500Serics else if ((ch == otty.sg_kill) && !slash) { 16071500Serics if (hard) { 16081500Serics show (ch); 16091500Serics putchar ('\n'); 16101500Serics putchar (pchar); 16111500Serics } 16121500Serics else { 16131500Serics putchar ('\r'); 16141500Serics putchar (pchar); 16151500Serics if (eraseln) 16161500Serics erase (1); 161717592Sleres else if (docrtkill) 161817592Sleres while (promptlen-- > 1) 161917592Sleres write (2, BSB, sizeof(BSB)); 16201500Serics promptlen = 1; 16211500Serics } 16221500Serics sptr = buf; 16231500Serics fflush (stdout); 16241500Serics continue; 16251500Serics } 16261500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 162717592Sleres ERASEONECHAR 16281500Serics --sptr; 16291500Serics } 16301500Serics if (ch != '\\') 16311500Serics slash = 0; 16321500Serics *sptr++ = ch; 16331500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 16341500Serics ch += ch == RUBOUT ? -0100 : 0100; 16351500Serics write (2, &CARAT, 1); 16361500Serics promptlen++; 16371500Serics } 16381500Serics cbuf = ch; 16391500Serics if (ch != '\n' && ch != ESC) { 16401500Serics write (2, &cbuf, 1); 16411500Serics promptlen++; 16421500Serics } 16431500Serics else 16441500Serics break; 16451500Serics } 16461500Serics *--sptr = '\0'; 16471500Serics if (!eraseln) promptlen = maxlen; 16481500Serics if (sptr - buf >= nmax - 1) 16491500Serics error ("Line too long"); 16501500Serics } 16511500Serics 16521500Serics expand (outbuf, inbuf) 16531500Serics char *outbuf; 16541500Serics char *inbuf; 16551500Serics { 16561500Serics register char *instr; 16571500Serics register char *outstr; 16581500Serics register char ch; 16591500Serics char temp[200]; 16601500Serics int changed = 0; 16611500Serics 16621500Serics instr = inbuf; 16631500Serics outstr = temp; 16641500Serics while ((ch = *instr++) != '\0') 16651500Serics switch (ch) { 16661500Serics case '%': 16671500Serics if (!no_intty) { 16681500Serics strcpy (outstr, fnames[fnum]); 16691500Serics outstr += strlen (fnames[fnum]); 16701500Serics changed++; 16711500Serics } 16721500Serics else 16731500Serics *outstr++ = ch; 16741500Serics break; 16751500Serics case '!': 16761500Serics if (!shellp) 16771500Serics error ("No previous command to substitute for"); 16781500Serics strcpy (outstr, shell_line); 16791500Serics outstr += strlen (shell_line); 16801500Serics changed++; 16811500Serics break; 16821500Serics case '\\': 16831500Serics if (*instr == '%' || *instr == '!') { 16841500Serics *outstr++ = *instr++; 16851500Serics break; 16861500Serics } 16871500Serics default: 16881500Serics *outstr++ = ch; 16891500Serics } 16901500Serics *outstr++ = '\0'; 16911500Serics strcpy (outbuf, temp); 16921500Serics return (changed); 16931500Serics } 16941500Serics 16951500Serics show (ch) 16961500Serics register char ch; 16971500Serics { 16981500Serics char cbuf; 16991500Serics 17001500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 17011500Serics ch += ch == RUBOUT ? -0100 : 0100; 17021500Serics write (2, &CARAT, 1); 17031500Serics promptlen++; 17041500Serics } 17051500Serics cbuf = ch; 17061500Serics write (2, &cbuf, 1); 17071500Serics promptlen++; 17081500Serics } 17091500Serics 17101500Serics error (mess) 17111500Serics char *mess; 17121500Serics { 17133594Sroot if (clreol) 17143594Sroot cleareol (); 17153594Sroot else 17163594Sroot kill_line (); 17171500Serics promptlen += strlen (mess); 17181500Serics if (Senter && Sexit) { 17191500Serics tputs (Senter, 1, putch); 17201500Serics pr(mess); 17211500Serics tputs (Sexit, 1, putch); 17221500Serics } 17231500Serics else 17241500Serics pr (mess); 17251500Serics fflush(stdout); 17261500Serics errors++; 17271500Serics longjmp (restore, 1); 17281500Serics } 17291500Serics 17301500Serics 17311500Serics set_tty () 17321500Serics { 17331500Serics otty.sg_flags |= MBIT; 17341500Serics otty.sg_flags &= ~ECHO; 173516582Sleres stty(fileno(stderr), &otty); 17361500Serics } 17371500Serics 17381500Serics reset_tty () 17391500Serics { 174016710Sjak if (pstate) { 174116710Sjak tputs(ULexit, 1, putch); 174216710Sjak fflush(stdout); 174316710Sjak pstate = 0; 174416710Sjak } 17451500Serics otty.sg_flags |= ECHO; 17461500Serics otty.sg_flags &= ~MBIT; 174716582Sleres stty(fileno(stderr), &savetty); 17481500Serics } 17491500Serics 17501500Serics rdline (f) 17511500Serics register FILE *f; 17521500Serics { 17531500Serics register char c; 17541500Serics register char *p; 17551500Serics 17561500Serics p = Line; 17571500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 17581500Serics *p++ = c; 17591500Serics if (c == '\n') 17601500Serics Currline++; 17611500Serics *p = '\0'; 17621500Serics } 17631500Serics 17641500Serics /* Come here when we get a suspend signal from the terminal */ 17651500Serics 17661500Serics onsusp () 17671500Serics { 176814861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 176914861Skarels signal(SIGTTOU, SIG_IGN); 17701500Serics reset_tty (); 17711500Serics fflush (stdout); 177214861Skarels signal(SIGTTOU, SIG_DFL); 17731500Serics /* Send the TSTP signal to suspend our process group */ 177413289Ssam signal(SIGTSTP, SIG_DFL); 177513289Ssam sigsetmask(0); 17761500Serics kill (0, SIGTSTP); 17771500Serics /* Pause for station break */ 17781500Serics 17791500Serics /* We're back */ 17801500Serics signal (SIGTSTP, onsusp); 17811500Serics set_tty (); 17821500Serics if (inwait) 17831500Serics longjmp (restore); 17841500Serics } 1785