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*25540Smckusick static char sccsid[] = "@(#)more.c 5.3 (Berkeley) 11/27/85"; 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; 571500Serics int dum_opt, dlines, onquit(), end_it(); 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); 1831500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1841500Serics signal(SIGTSTP, onsusp); 1851500Serics catch_susp++; 1861500Serics } 18716582Sleres stty (fileno(stderr), &otty); 1881500Serics } 1891500Serics if (no_intty) { 1901500Serics if (no_tty) 1911500Serics copy_file (stdin); 1921500Serics else { 1931500Serics if ((ch = Getc (f)) == '\f') 1943594Sroot doclear(); 1951500Serics else { 1961500Serics Ungetc (ch, f); 1973594Sroot if (noscroll && (ch != EOF)) { 1983594Sroot if (clreol) 1993594Sroot home (); 2003594Sroot else 2013594Sroot doclear (); 2023455Sroot } 2031500Serics } 2041500Serics if (srchopt) 2053455Sroot { 2061500Serics search (initbuf, stdin, 1); 2073594Sroot if (noscroll) 2083594Sroot left--; 2093455Sroot } 2101500Serics else if (initopt) 2111500Serics skiplns (initline, stdin); 2121500Serics screen (stdin, left); 2131500Serics } 2141500Serics no_intty = 0; 2151500Serics prnames++; 2161500Serics firstf = 0; 2171500Serics } 2181500Serics 2191500Serics while (fnum < nfiles) { 2201500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2211500Serics context.line = context.chrctr = 0; 2221500Serics Currline = 0; 2231500Serics if (firstf) setjmp (restore); 2241500Serics if (firstf) { 2251500Serics firstf = 0; 2261500Serics if (srchopt) 2273455Sroot { 2281500Serics search (initbuf, f, 1); 2293594Sroot if (noscroll) 2303594Sroot left--; 2313455Sroot } 2321500Serics else if (initopt) 2331500Serics skiplns (initline, f); 2341500Serics } 2351500Serics else if (fnum < nfiles && !no_tty) { 2361500Serics setjmp (restore); 2371500Serics left = command (fnames[fnum], f); 2381500Serics } 2391500Serics if (left != 0) { 2403594Sroot if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 2413594Sroot if (clreol) 2423594Sroot home (); 2433594Sroot else 2443594Sroot doclear (); 2451500Serics if (prnames) { 2461500Serics if (bad_so) 2471500Serics erase (0); 2483594Sroot if (clreol) 2493594Sroot cleareol (); 2501500Serics pr("::::::::::::::"); 2511500Serics if (promptlen > 14) 2521500Serics erase (14); 2533455Sroot printf ("\n"); 2543455Sroot if(clreol) cleareol(); 2553455Sroot printf("%s\n", fnames[fnum]); 2563455Sroot if(clreol) cleareol(); 2573455Sroot printf("::::::::::::::\n", fnames[fnum]); 2581500Serics if (left > Lpp - 4) 2591500Serics left = Lpp - 4; 2601500Serics } 2611500Serics if (no_tty) 2621500Serics copy_file (f); 2631500Serics else { 2641500Serics within++; 2651500Serics screen(f, left); 2661500Serics within = 0; 2671500Serics } 2681500Serics } 2691500Serics setjmp (restore); 2701500Serics fflush(stdout); 2711500Serics fclose(f); 2721500Serics screen_start.line = screen_start.chrctr = 0L; 2731500Serics context.line = context.chrctr = 0L; 2741500Serics } 2751500Serics fnum++; 2761500Serics firstf = 0; 2771500Serics } 2781500Serics reset_tty (); 2791500Serics exit(0); 2801500Serics } 2811500Serics 2823455Sroot argscan(s) 2833455Sroot char *s; 2843455Sroot { 28511604Slayer for (dlines = 0; *s != '\0'; s++) 28611604Slayer { 28711604Slayer switch (*s) 28811604Slayer { 28911604Slayer case '0': case '1': case '2': 29011604Slayer case '3': case '4': case '5': 29111604Slayer case '6': case '7': case '8': 29211604Slayer case '9': 29311604Slayer dlines = dlines*10 + *s - '0'; 29411604Slayer break; 29511604Slayer case 'd': 29611604Slayer dum_opt = 1; 29711604Slayer break; 29811604Slayer case 'l': 29911604Slayer stop_opt = 0; 30011604Slayer break; 30111604Slayer case 'f': 30211604Slayer fold_opt = 0; 30311604Slayer break; 30411604Slayer case 'p': 30511604Slayer noscroll++; 30611604Slayer break; 30711604Slayer case 'c': 30811604Slayer clreol++; 30911604Slayer break; 31011604Slayer case 's': 31111604Slayer ssp_opt = 1; 31211604Slayer break; 31311604Slayer case 'u': 31411604Slayer ul_opt = 0; 31511604Slayer break; 31611604Slayer } 31711604Slayer } 3183455Sroot } 3193455Sroot 3203455Sroot 3211500Serics /* 3221500Serics ** Check whether the file named by fs is an ASCII file which the user may 3231500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3241500Serics */ 3251500Serics 3261500Serics FILE * 3271500Serics checkf (fs, clearfirst) 3281500Serics register char *fs; 3291500Serics int *clearfirst; 3301500Serics { 3311500Serics struct stat stbuf; 3321500Serics register FILE *f; 3331500Serics char c; 3341500Serics 3351500Serics if (stat (fs, &stbuf) == -1) { 3361500Serics fflush(stdout); 3373594Sroot if (clreol) 3383594Sroot cleareol (); 3391500Serics perror(fs); 3401500Serics return (NULL); 3411500Serics } 3421500Serics if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3431500Serics printf("\n*** %s: directory ***\n\n", fs); 3441500Serics return (NULL); 3451500Serics } 3461500Serics if ((f=Fopen(fs, "r")) == NULL) { 3471500Serics fflush(stdout); 3481500Serics perror(fs); 3491500Serics return (NULL); 3501500Serics } 3511500Serics c = Getc(f); 3521500Serics 3531500Serics /* Try to see whether it is an ASCII file */ 3541500Serics 3551500Serics switch ((c | *f->_ptr << 8) & 0177777) { 3561500Serics case 0405: 3571500Serics case 0407: 3581500Serics case 0410: 3591500Serics case 0411: 3601500Serics case 0413: 3611500Serics case 0177545: 3621500Serics printf("\n******** %s: Not a text file ********\n\n", fs); 3631500Serics fclose (f); 3641500Serics return (NULL); 3651500Serics default: 3661500Serics break; 3671500Serics } 3681500Serics if (c == '\f') 3691500Serics *clearfirst = 1; 3701500Serics else { 3711500Serics *clearfirst = 0; 3721500Serics Ungetc (c, f); 3731500Serics } 3741500Serics if ((file_size = stbuf.st_size) == 0) 3751500Serics file_size = 0x7fffffffffffffffL; 3761500Serics return (f); 3771500Serics } 3781500Serics 3791500Serics /* 3801500Serics ** A real function, for the tputs routine in termlib 3811500Serics */ 3821500Serics 3831500Serics putch (ch) 3841500Serics char ch; 3851500Serics { 3861500Serics putchar (ch); 3871500Serics } 3881500Serics 3891500Serics /* 3901500Serics ** Print out the contents of the file f, one screenful at a time. 3911500Serics */ 3921500Serics 3931500Serics #define STOP -10 3941500Serics 3951500Serics screen (f, num_lines) 3961500Serics register FILE *f; 3971500Serics register int num_lines; 3981500Serics { 3991500Serics register int c; 4001500Serics register int nchars; 4013594Sroot int length; /* length of current line */ 4023594Sroot static int prev_len = 1; /* length of previous line */ 4031500Serics 4041500Serics for (;;) { 4051500Serics while (num_lines > 0 && !Pause) { 4061500Serics if ((nchars = getline (f, &length)) == EOF) 4073455Sroot { 4083594Sroot if (clreol) 4093594Sroot clreos(); 4101500Serics return; 4113455Sroot } 4123594Sroot if (ssp_opt && length == 0 && prev_len == 0) 4133594Sroot continue; 4143594Sroot prev_len = length; 4151500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 4161500Serics erase (0); 4173594Sroot /* must clear before drawing line since tabs on some terminals 4183594Sroot * do not erase what they tab over. 4193594Sroot */ 4203594Sroot if (clreol) 4213594Sroot cleareol (); 4221500Serics prbuf (Line, length); 4231500Serics if (nchars < promptlen) 4241500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4251500Serics else promptlen = 0; 4263594Sroot /* is this needed? 4273594Sroot * if (clreol) 4283594Sroot * cleareol(); /* must clear again in case we wrapped * 4293594Sroot */ 4301500Serics if (nchars < Mcol || !fold_opt) 43116710Sjak prbuf("\n", 1); /* will turn off UL if necessary */ 4321500Serics if (nchars == STOP) 4331500Serics break; 4341500Serics num_lines--; 4351500Serics } 43616710Sjak if (pstate) { 43716710Sjak tputs(ULexit, 1, putch); 43816710Sjak pstate = 0; 43916710Sjak } 4401500Serics fflush(stdout); 4411500Serics if ((c = Getc(f)) == EOF) 4423455Sroot { 4433594Sroot if (clreol) 4443594Sroot clreos (); 4451500Serics return; 4463455Sroot } 4473455Sroot 4483594Sroot if (Pause && clreol) 4493594Sroot clreos (); 4501500Serics Ungetc (c, f); 4511500Serics setjmp (restore); 4521500Serics Pause = 0; startup = 0; 4531500Serics if ((num_lines = command (NULL, f)) == 0) 4541500Serics return; 4551500Serics if (hard && promptlen > 0) 4561500Serics erase (0); 45711123Slayer if (noscroll && num_lines >= dlines) 45816582Sleres { 4593594Sroot if (clreol) 4603594Sroot home(); 4613594Sroot else 4623594Sroot doclear (); 4633455Sroot } 4641500Serics screen_start.line = Currline; 4651500Serics screen_start.chrctr = Ftell (f); 4661500Serics } 4671500Serics } 4681500Serics 4691500Serics /* 4701500Serics ** Come here if a quit signal is received 4711500Serics */ 4721500Serics 4731500Serics onquit() 4741500Serics { 4751500Serics signal(SIGQUIT, SIG_IGN); 4761500Serics if (!inwait) { 4771500Serics putchar ('\n'); 4781500Serics if (!startup) { 4791500Serics signal(SIGQUIT, onquit); 4801500Serics longjmp (restore, 1); 4811500Serics } 4821500Serics else 4831500Serics Pause++; 4841500Serics } 4851500Serics else if (!dum_opt && notell) { 4861500Serics write (2, "[Use q or Q to quit]", 20); 4871500Serics promptlen += 20; 4881500Serics notell = 0; 4891500Serics } 4901500Serics signal(SIGQUIT, onquit); 4911500Serics } 4921500Serics 4931500Serics /* 4941500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 4951500Serics */ 4961500Serics 4971500Serics end_it () 4981500Serics { 4991500Serics 5001500Serics reset_tty (); 5013594Sroot if (clreol) { 5023594Sroot putchar ('\r'); 5033594Sroot clreos (); 5043594Sroot fflush (stdout); 5053594Sroot } 5063455Sroot else if (!clreol && (promptlen > 0)) { 5071500Serics kill_line (); 5081500Serics fflush (stdout); 5091500Serics } 5101500Serics else 5111500Serics write (2, "\n", 1); 5121500Serics _exit(0); 5131500Serics } 5141500Serics 5151500Serics copy_file(f) 5161500Serics register FILE *f; 5171500Serics { 5181500Serics register int c; 5191500Serics 5201500Serics while ((c = getc(f)) != EOF) 5211500Serics putchar(c); 5221500Serics } 5231500Serics 5241500Serics /* Simplified printf function */ 5251500Serics 5261500Serics printf (fmt, args) 5271500Serics register char *fmt; 5281500Serics int args; 5291500Serics { 5301500Serics register int *argp; 5311500Serics register char ch; 5321500Serics register int ccount; 5331500Serics 5341500Serics ccount = 0; 5351500Serics argp = &args; 5361500Serics while (*fmt) { 5371500Serics while ((ch = *fmt++) != '%') { 5381500Serics if (ch == '\0') 5391500Serics return (ccount); 5401500Serics ccount++; 5411500Serics putchar (ch); 5421500Serics } 5431500Serics switch (*fmt++) { 5441500Serics case 'd': 5451500Serics ccount += printd (*argp); 5461500Serics break; 5471500Serics case 's': 5481500Serics ccount += pr ((char *)*argp); 5491500Serics break; 5501500Serics case '%': 5511500Serics ccount++; 5521500Serics argp--; 5531500Serics putchar ('%'); 5541500Serics break; 5551500Serics case '0': 5561500Serics return (ccount); 5571500Serics default: 5581500Serics break; 5591500Serics } 5601500Serics ++argp; 5611500Serics } 5621500Serics return (ccount); 5631500Serics 5641500Serics } 5651500Serics 5661500Serics /* 5671500Serics ** Print an integer as a string of decimal digits, 5681500Serics ** returning the length of the print representation. 5691500Serics */ 5701500Serics 5711500Serics printd (n) 5721500Serics int n; 5731500Serics { 5741500Serics int a, nchars; 5751500Serics 5761500Serics if (a = n/10) 5771500Serics nchars = 1 + printd(a); 5781500Serics else 5791500Serics nchars = 1; 5801500Serics putchar (n % 10 + '0'); 5811500Serics return (nchars); 5821500Serics } 5831500Serics 5841500Serics /* Put the print representation of an integer into a string */ 5851500Serics static char *sptr; 5861500Serics 5871500Serics scanstr (n, str) 5881500Serics int n; 5891500Serics char *str; 5901500Serics { 5911500Serics sptr = str; 59211604Slayer Sprintf (n); 5931500Serics *sptr = '\0'; 5941500Serics } 5951500Serics 59611604Slayer Sprintf (n) 5971500Serics { 5981500Serics int a; 5991500Serics 6001500Serics if (a = n/10) 60111604Slayer Sprintf (a); 6021500Serics *sptr++ = n % 10 + '0'; 6031500Serics } 6041500Serics 6051500Serics static char bell = ctrl(G); 6061500Serics 6071500Serics strlen (s) 6081500Serics char *s; 6091500Serics { 6101500Serics register char *p; 6111500Serics 6121500Serics p = s; 6131500Serics while (*p++) 6141500Serics ; 6151500Serics return (p - s - 1); 6161500Serics } 6171500Serics 6181500Serics /* See whether the last component of the path name "path" is equal to the 6191500Serics ** string "string" 6201500Serics */ 6211500Serics 6221500Serics tailequ (path, string) 6231500Serics char *path; 6241500Serics register char *string; 6251500Serics { 6261500Serics register char *tail; 6271500Serics 6281500Serics tail = path + strlen(path); 6291500Serics while (tail >= path) 6301500Serics if (*(--tail) == '/') 6311500Serics break; 6321500Serics ++tail; 6331500Serics while (*tail++ == *string++) 6341500Serics if (*tail == '\0') 6351500Serics return(1); 6361500Serics return(0); 6371500Serics } 6381500Serics 6391500Serics prompt (filename) 6401500Serics char *filename; 6411500Serics { 6423594Sroot if (clreol) 6433594Sroot cleareol (); 6443455Sroot else if (promptlen > 0) 6451500Serics kill_line (); 6461500Serics if (!hard) { 6471500Serics promptlen = 8; 64816710Sjak if (Senter && Sexit) { 6491500Serics tputs (Senter, 1, putch); 65016710Sjak promptlen += (2 * soglitch); 65116710Sjak } 6523594Sroot if (clreol) 6533594Sroot cleareol (); 6541500Serics pr("--More--"); 6551500Serics if (filename != NULL) { 6561500Serics promptlen += printf ("(Next file: %s)", filename); 6571500Serics } 6581500Serics else if (!no_intty) { 6591500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 6601500Serics } 6611500Serics if (dum_opt) { 66216710Sjak promptlen += pr("[Press space to continue, 'q' to quit.]"); 6631500Serics } 6641500Serics if (Senter && Sexit) 6651500Serics tputs (Sexit, 1, putch); 6663594Sroot if (clreol) 6673594Sroot clreos (); 6681500Serics fflush(stdout); 6691500Serics } 6701500Serics else 6711500Serics write (2, &bell, 1); 6721500Serics inwait++; 6731500Serics } 6741500Serics 6751500Serics /* 6761500Serics ** Get a logical line 6771500Serics */ 6781500Serics 6791500Serics getline(f, length) 6801500Serics register FILE *f; 6811500Serics int *length; 6821500Serics { 6831500Serics register int c; 6841500Serics register char *p; 6851500Serics register int column; 6861500Serics static int colflg; 6871500Serics 6881500Serics p = Line; 6891500Serics column = 0; 6901500Serics c = Getc (f); 6911500Serics if (colflg && c == '\n') { 6921500Serics Currline++; 6931500Serics c = Getc (f); 6941500Serics } 6951500Serics while (p < &Line[LINSIZ - 1]) { 6961500Serics if (c == EOF) { 6971500Serics if (p > Line) { 6981500Serics *p = '\0'; 6991500Serics *length = p - Line; 7001500Serics return (column); 7011500Serics } 7021500Serics *length = p - Line; 7031500Serics return (EOF); 7041500Serics } 7051500Serics if (c == '\n') { 7061500Serics Currline++; 7071500Serics break; 7081500Serics } 7091500Serics *p++ = c; 7101500Serics if (c == '\t') 7111500Serics if (hardtabs && column < promptlen && !hard) { 7121500Serics if (eraseln && !dumb) { 7131500Serics column = 1 + (column | 7); 7141500Serics tputs (eraseln, 1, putch); 7151500Serics promptlen = 0; 7161500Serics } 7171500Serics else { 7181500Serics for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 7191500Serics *p++ = ' '; 7201500Serics } 7211500Serics if (column >= promptlen) promptlen = 0; 7221500Serics } 7231500Serics } 7241500Serics else 7251500Serics column = 1 + (column | 7); 7269627Ssklower else if (c == '\b' && column > 0) 7271500Serics column--; 7281500Serics else if (c == '\r') 7291500Serics column = 0; 7301500Serics else if (c == '\f' && stop_opt) { 7311500Serics p[-1] = '^'; 7321500Serics *p++ = 'L'; 7331500Serics column += 2; 7341500Serics Pause++; 7351500Serics } 7361500Serics else if (c == EOF) { 7371500Serics *length = p - Line; 7381500Serics return (column); 7391500Serics } 7401500Serics else if (c >= ' ' && c != RUBOUT) 7411500Serics column++; 7421500Serics if (column >= Mcol && fold_opt) break; 7431500Serics c = Getc (f); 7441500Serics } 7451500Serics if (column >= Mcol && Mcol > 0) { 7461500Serics if (!Wrap) { 7471500Serics *p++ = '\n'; 7481500Serics } 7491500Serics } 7501500Serics colflg = column == Mcol && fold_opt; 7511500Serics *length = p - Line; 7521500Serics *p = 0; 7531500Serics return (column); 7541500Serics } 7551500Serics 7561500Serics /* 7571500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 7581500Serics */ 7591500Serics 7601500Serics erase (col) 7611500Serics register int col; 7621500Serics { 7631500Serics 7641500Serics if (promptlen == 0) 7651500Serics return; 7661500Serics if (hard) { 7671500Serics putchar ('\n'); 7681500Serics } 7691500Serics else { 7701500Serics if (col == 0) 7711500Serics putchar ('\r'); 7721500Serics if (!dumb && eraseln) 7731500Serics tputs (eraseln, 1, putch); 7741500Serics else 7751500Serics for (col = promptlen - col; col > 0; col--) 7761500Serics putchar (' '); 7771500Serics } 7781500Serics promptlen = 0; 7791500Serics } 7801500Serics 7811500Serics /* 7821500Serics ** Erase the current line entirely 7831500Serics */ 7841500Serics 7851500Serics kill_line () 7861500Serics { 7871500Serics erase (0); 7881500Serics if (!eraseln || dumb) putchar ('\r'); 7891500Serics } 7901500Serics 7911500Serics /* 7923455Sroot * force clear to end of line 7933455Sroot */ 7943455Sroot cleareol() 7953455Sroot { 7963594Sroot tputs(eraseln, 1, putch); 7973455Sroot } 7983455Sroot 7993594Sroot clreos() 8003455Sroot { 8013594Sroot tputs(EodClr, 1, putch); 8023455Sroot } 8033455Sroot 8043455Sroot /* 8051500Serics ** Print string and return number of characters 8061500Serics */ 8071500Serics 8081500Serics pr(s1) 8091500Serics char *s1; 8101500Serics { 8111500Serics register char *s; 8121500Serics register char c; 8131500Serics 8141500Serics for (s = s1; c = *s++; ) 8151500Serics putchar(c); 8161500Serics return (s - s1 - 1); 8171500Serics } 8181500Serics 8191500Serics 8201500Serics /* Print a buffer of n characters */ 8211500Serics 8221500Serics prbuf (s, n) 8231500Serics register char *s; 8241500Serics register int n; 8251500Serics { 82616710Sjak register char c; /* next output character */ 8273594Sroot register int state; /* next output char's UL state */ 82816710Sjak #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 8293594Sroot 8303594Sroot while (--n >= 0) 8313594Sroot if (!ul_opt) 8323594Sroot putchar (*s++); 8333594Sroot else { 83416710Sjak if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 83516710Sjak s++; 83616710Sjak continue; 83716710Sjak } 83816710Sjak if (state = wouldul(s, n)) { 83916710Sjak c = (*s == '_')? s[2] : *s ; 8403594Sroot n -= 2; 84116710Sjak s += 3; 84216710Sjak } else 8433594Sroot c = *s++; 84416710Sjak if (state != pstate) { 84516710Sjak if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 84616710Sjak state = 1; 84716710Sjak else 84816710Sjak tputs(state ? ULenter : ULexit, 1, putch); 8493594Sroot } 85016710Sjak if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 85116710Sjak putchar(c); 8523594Sroot if (state && *chUL) { 8533594Sroot pr(chBS); 8543594Sroot tputs(chUL, 1, putch); 8553594Sroot } 85616710Sjak pstate = state; 8573594Sroot } 8581500Serics } 8591500Serics 8601500Serics /* 8611500Serics ** Clear the screen 8621500Serics */ 8631500Serics 8641500Serics doclear() 8651500Serics { 8661500Serics if (Clear && !hard) { 8671500Serics tputs(Clear, 1, putch); 8681500Serics 8691500Serics /* Put out carriage return so that system doesn't 8701500Serics ** get confused by escape sequences when expanding tabs 8711500Serics */ 8721500Serics putchar ('\r'); 8731500Serics promptlen = 0; 8741500Serics } 8751500Serics } 8761500Serics 8773455Sroot /* 8783455Sroot * Go to home position 8793455Sroot */ 8803455Sroot home() 8813455Sroot { 8823455Sroot tputs(Home,1,putch); 8833455Sroot } 8843455Sroot 8851500Serics static int lastcmd, lastarg, lastp; 8861500Serics static int lastcolon; 8871500Serics char shell_line[132]; 8881500Serics 8891500Serics /* 8901500Serics ** Read a command and do it. A command consists of an optional integer 8911500Serics ** argument followed by the command character. Return the number of lines 8921500Serics ** to display in the next screenful. If there is nothing more to display 8931500Serics ** in the current file, zero is returned. 8941500Serics */ 8951500Serics 8961500Serics command (filename, f) 8971500Serics char *filename; 8981500Serics register FILE *f; 8991500Serics { 9001500Serics register int nlines; 9011500Serics register int retval; 9021500Serics register char c; 9031500Serics char colonch; 9041500Serics FILE *helpf; 9051500Serics int done; 9061500Serics char comchar, cmdbuf[80], *p; 9071500Serics 9081500Serics #define ret(val) retval=val;done++;break 9091500Serics 9101500Serics done = 0; 9111500Serics if (!errors) 9121500Serics prompt (filename); 9131500Serics else 9141500Serics errors = 0; 9151500Serics if (MBIT == RAW && slow_tty) { 9161500Serics otty.sg_flags |= MBIT; 91716582Sleres stty(fileno(stderr), &otty); 9181500Serics } 9191500Serics for (;;) { 9201500Serics nlines = number (&comchar); 9211500Serics lastp = colonch = 0; 9221500Serics if (comchar == '.') { /* Repeat last command */ 9231500Serics lastp++; 9241500Serics comchar = lastcmd; 9251500Serics nlines = lastarg; 9261500Serics if (lastcmd == ':') 9271500Serics colonch = lastcolon; 9281500Serics } 9291500Serics lastcmd = comchar; 9301500Serics lastarg = nlines; 9311500Serics if (comchar == otty.sg_erase) { 9321500Serics kill_line (); 9331500Serics prompt (filename); 9341500Serics continue; 9351500Serics } 9361500Serics switch (comchar) { 9371500Serics case ':': 9381500Serics retval = colon (filename, colonch, nlines); 9391500Serics if (retval >= 0) 9401500Serics done++; 9411500Serics break; 94224490Sbloom case 'b': 94324490Sbloom case ctrl(B): 94424490Sbloom { 94524490Sbloom register int initline; 94624490Sbloom 94724490Sbloom if (no_intty) { 94824490Sbloom write(2, &bell, 1); 94924490Sbloom return (-1); 95024490Sbloom } 95124490Sbloom 95224490Sbloom if (nlines == 0) nlines++; 95324490Sbloom 95424490Sbloom putchar ('\r'); 95524490Sbloom erase (0); 95624490Sbloom printf ("\n"); 95724490Sbloom if (clreol) 95824490Sbloom cleareol (); 95924490Sbloom printf ("...back %d page", nlines); 96024490Sbloom if (nlines > 1) 96124490Sbloom pr ("s\n"); 96224490Sbloom else 96324490Sbloom pr ("\n"); 96424490Sbloom 96524490Sbloom if (clreol) 96624490Sbloom cleareol (); 96724490Sbloom pr ("\n"); 96824490Sbloom 96924490Sbloom initline = Currline - dlines * (nlines + 1); 97024490Sbloom if (! noscroll) 97124490Sbloom --initline; 97224490Sbloom if (initline < 0) initline = 0; 97324490Sbloom Fseek(f, 0L); 97424490Sbloom Currline = 0; /* skiplns() will make Currline correct */ 97524490Sbloom skiplns(initline, f); 97624490Sbloom if (! noscroll) { 97724490Sbloom ret(dlines + 1); 97824490Sbloom } 97924490Sbloom else { 98024490Sbloom ret(dlines); 98124490Sbloom } 98224490Sbloom } 9831500Serics case ' ': 9841500Serics case 'z': 9851500Serics if (nlines == 0) nlines = dlines; 9861500Serics else if (comchar == 'z') dlines = nlines; 9871500Serics ret (nlines); 9881500Serics case 'd': 9891500Serics case ctrl(D): 9901500Serics if (nlines != 0) nscroll = nlines; 9911500Serics ret (nscroll); 9921500Serics case 'q': 9931500Serics case 'Q': 9941500Serics end_it (); 9951500Serics case 's': 9961500Serics case 'f': 9971500Serics if (nlines == 0) nlines++; 9981500Serics if (comchar == 'f') 9991500Serics nlines *= dlines; 10001500Serics putchar ('\r'); 10011500Serics erase (0); 10023594Sroot printf ("\n"); 10033594Sroot if (clreol) 10043594Sroot cleareol (); 10053594Sroot printf ("...skipping %d line", nlines); 10061500Serics if (nlines > 1) 10073594Sroot pr ("s\n"); 10081500Serics else 10093594Sroot pr ("\n"); 10103594Sroot 10113594Sroot if (clreol) 10123594Sroot cleareol (); 10133594Sroot pr ("\n"); 10143594Sroot 10151500Serics while (nlines > 0) { 10161500Serics while ((c = Getc (f)) != '\n') 10171500Serics if (c == EOF) { 10181500Serics retval = 0; 10191500Serics done++; 10201500Serics goto endsw; 10211500Serics } 10221500Serics Currline++; 10231500Serics nlines--; 10241500Serics } 10251500Serics ret (dlines); 10261500Serics case '\n': 10271500Serics if (nlines != 0) 10281500Serics dlines = nlines; 10291500Serics else 10301500Serics nlines = 1; 10311500Serics ret (nlines); 10321500Serics case '\f': 10331500Serics if (!no_intty) { 10341500Serics doclear (); 10351500Serics Fseek (f, screen_start.chrctr); 10361500Serics Currline = screen_start.line; 10371500Serics ret (dlines); 10381500Serics } 10391500Serics else { 10401500Serics write (2, &bell, 1); 10411500Serics break; 10421500Serics } 10431500Serics case '\'': 10441500Serics if (!no_intty) { 10451500Serics kill_line (); 10461500Serics pr ("\n***Back***\n\n"); 10471500Serics Fseek (f, context.chrctr); 10481500Serics Currline = context.line; 10491500Serics ret (dlines); 10501500Serics } 10511500Serics else { 10521500Serics write (2, &bell, 1); 10531500Serics break; 10541500Serics } 10551500Serics case '=': 10561500Serics kill_line (); 10571500Serics promptlen = printd (Currline); 10581500Serics fflush (stdout); 10591500Serics break; 10601500Serics case 'n': 10611500Serics lastp++; 10621500Serics case '/': 10631500Serics if (nlines == 0) nlines++; 10641500Serics kill_line (); 10651500Serics pr ("/"); 10661500Serics promptlen = 1; 10671500Serics fflush (stdout); 10681500Serics if (lastp) { 10691500Serics write (2,"\r", 1); 10701500Serics search (NULL, f, nlines); /* Use previous r.e. */ 10711500Serics } 10721500Serics else { 10731500Serics ttyin (cmdbuf, 78, '/'); 10741500Serics write (2, "\r", 1); 10751500Serics search (cmdbuf, f, nlines); 10761500Serics } 10773455Sroot ret (dlines-1); 10781500Serics case '!': 10791500Serics do_shell (filename); 10801500Serics break; 108124490Sbloom case '?': 10821500Serics case 'h': 10831500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 10841500Serics error ("Can't open help file"); 10851500Serics if (noscroll) doclear (); 10861500Serics copy_file (helpf); 10871500Serics close (helpf); 10881500Serics prompt (filename); 10891500Serics break; 10901500Serics case 'v': /* This case should go right before default */ 10911500Serics if (!no_intty) { 10921500Serics kill_line (); 10931500Serics cmdbuf[0] = '+'; 109424490Sbloom scanstr (Currline - dlines < 0 ? 0 109524490Sbloom : Currline - (dlines + 1) / 2, &cmdbuf[1]); 10961500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 10971500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 10981500Serics break; 10991500Serics } 11001500Serics default: 110116710Sjak if (dum_opt) { 110216710Sjak kill_line (); 110316710Sjak if (Senter && Sexit) { 110416710Sjak tputs (Senter, 1, putch); 110516710Sjak promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 110616710Sjak tputs (Sexit, 1, putch); 110716710Sjak } 110816710Sjak else 110916710Sjak promptlen = pr ("[Press 'h' for instructions.]"); 111016710Sjak fflush (stdout); 111116710Sjak } 111216710Sjak else 111316710Sjak write (2, &bell, 1); 11141500Serics break; 11151500Serics } 11161500Serics if (done) break; 11171500Serics } 11181500Serics putchar ('\r'); 11191500Serics endsw: 11201500Serics inwait = 0; 11211500Serics notell++; 11221500Serics if (MBIT == RAW && slow_tty) { 11231500Serics otty.sg_flags &= ~MBIT; 112416582Sleres stty(fileno(stderr), &otty); 11251500Serics } 11261500Serics return (retval); 11271500Serics } 11281500Serics 11291500Serics char ch; 11301500Serics 11311500Serics /* 11321500Serics * Execute a colon-prefixed command. 11331500Serics * Returns <0 if not a command that should cause 11341500Serics * more of the file to be printed. 11351500Serics */ 11361500Serics 11371500Serics colon (filename, cmd, nlines) 11381500Serics char *filename; 11391500Serics int cmd; 11401500Serics int nlines; 11411500Serics { 11421500Serics if (cmd == 0) 11431500Serics ch = readch (); 11441500Serics else 11451500Serics ch = cmd; 11461500Serics lastcolon = ch; 11471500Serics switch (ch) { 11481500Serics case 'f': 11491500Serics kill_line (); 11501500Serics if (!no_intty) 11511500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 11521500Serics else 11531500Serics promptlen = printf ("[Not a file] line %d", Currline); 11541500Serics fflush (stdout); 11551500Serics return (-1); 11561500Serics case 'n': 11571500Serics if (nlines == 0) { 11581500Serics if (fnum >= nfiles - 1) 11591500Serics end_it (); 11601500Serics nlines++; 11611500Serics } 11621500Serics putchar ('\r'); 11631500Serics erase (0); 11641500Serics skipf (nlines); 11651500Serics return (0); 11661500Serics case 'p': 11671500Serics if (no_intty) { 11681500Serics write (2, &bell, 1); 11691500Serics return (-1); 11701500Serics } 11711500Serics putchar ('\r'); 11721500Serics erase (0); 11731500Serics if (nlines == 0) 11741500Serics nlines++; 11751500Serics skipf (-nlines); 11761500Serics return (0); 11771500Serics case '!': 11781500Serics do_shell (filename); 11791500Serics return (-1); 11801500Serics case 'q': 11811500Serics case 'Q': 11821500Serics end_it (); 11831500Serics default: 11841500Serics write (2, &bell, 1); 11851500Serics return (-1); 11861500Serics } 11871500Serics } 11881500Serics 11891500Serics /* 11901500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 11911500Serics ** terminates the number. 11921500Serics */ 11931500Serics 11941500Serics number(cmd) 11951500Serics char *cmd; 11961500Serics { 11971500Serics register int i; 11981500Serics 11991500Serics i = 0; ch = otty.sg_kill; 12001500Serics for (;;) { 12011500Serics ch = readch (); 12021500Serics if (ch >= '0' && ch <= '9') 12031500Serics i = i*10 + ch - '0'; 12041500Serics else if (ch == otty.sg_kill) 12051500Serics i = 0; 12061500Serics else { 12071500Serics *cmd = ch; 12081500Serics break; 12091500Serics } 12101500Serics } 12111500Serics return (i); 12121500Serics } 12131500Serics 12141500Serics do_shell (filename) 12151500Serics char *filename; 12161500Serics { 12171500Serics char cmdbuf[80]; 12181500Serics 12191500Serics kill_line (); 12201500Serics pr ("!"); 12211500Serics fflush (stdout); 12221500Serics promptlen = 1; 12231500Serics if (lastp) 12241500Serics pr (shell_line); 12251500Serics else { 12261500Serics ttyin (cmdbuf, 78, '!'); 12271500Serics if (expand (shell_line, cmdbuf)) { 12281500Serics kill_line (); 12291500Serics promptlen = printf ("!%s", shell_line); 12301500Serics } 12311500Serics } 12321500Serics fflush (stdout); 12331500Serics write (2, "\n", 1); 12341500Serics promptlen = 0; 12351500Serics shellp = 1; 12361500Serics execute (filename, shell, shell, "-c", shell_line, 0); 12371500Serics } 12381500Serics 12391500Serics /* 12401500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 12411500Serics */ 12421500Serics 12431500Serics search (buf, file, n) 12441500Serics char buf[]; 12451500Serics FILE *file; 12461500Serics register int n; 12471500Serics { 12481500Serics long startline = Ftell (file); 12491500Serics register long line1 = startline; 12501500Serics register long line2 = startline; 12511500Serics register long line3 = startline; 12521500Serics register int lncount; 12531500Serics int saveln, rv, re_exec(); 12541500Serics char *s, *re_comp(); 12551500Serics 12561500Serics context.line = saveln = Currline; 12571500Serics context.chrctr = startline; 12581500Serics lncount = 0; 12591500Serics if ((s = re_comp (buf)) != 0) 12601500Serics error (s); 12611500Serics while (!feof (file)) { 12621500Serics line3 = line2; 12631500Serics line2 = line1; 12641500Serics line1 = Ftell (file); 12651500Serics rdline (file); 12661500Serics lncount++; 12671500Serics if ((rv = re_exec (Line)) == 1) 12681500Serics if (--n == 0) { 12691500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 12703455Sroot { 12713455Sroot pr ("\n"); 12723594Sroot if (clreol) 12733594Sroot cleareol (); 12743455Sroot pr("...skipping\n"); 12753455Sroot } 12761500Serics if (!no_intty) { 12771500Serics Currline -= (lncount >= 3 ? 3 : lncount); 12781500Serics Fseek (file, line3); 12793594Sroot if (noscroll) 12803594Sroot if (clreol) { 12813594Sroot home (); 12823594Sroot cleareol (); 128316582Sleres } 12843594Sroot else 12853594Sroot doclear (); 12861500Serics } 12871500Serics else { 12881500Serics kill_line (); 12893594Sroot if (noscroll) 12903594Sroot if (clreol) { 129116582Sleres home (); 12923594Sroot cleareol (); 129316582Sleres } 12943594Sroot else 12953594Sroot doclear (); 12961500Serics pr (Line); 12971500Serics putchar ('\n'); 12981500Serics } 12991500Serics break; 13001500Serics } 13011500Serics else if (rv == -1) 13021500Serics error ("Regular expression botch"); 13031500Serics } 13041500Serics if (feof (file)) { 13051500Serics if (!no_intty) { 13061500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 13071500Serics Currline = saveln; 13081500Serics Fseek (file, startline); 13091500Serics } 13101500Serics else { 13111500Serics pr ("\nPattern not found\n"); 13121500Serics end_it (); 13131500Serics } 13141500Serics error ("Pattern not found"); 13151500Serics } 13161500Serics } 13171500Serics 13181500Serics execute (filename, cmd, args) 13191500Serics char *filename; 13201500Serics char *cmd, *args; 13211500Serics { 13221500Serics int id; 132316710Sjak int n; 13241500Serics 13251500Serics fflush (stdout); 13261500Serics reset_tty (); 132716710Sjak for (n = 10; (id = fork ()) < 0 && n > 0; n--) 13281500Serics sleep (5); 13291500Serics if (id == 0) { 133016710Sjak if (!isatty(0)) { 133116710Sjak close(0); 133216710Sjak open("/dev/tty", 0); 133316710Sjak } 13341500Serics execv (cmd, &args); 13351500Serics write (2, "exec failed\n", 12); 13361500Serics exit (1); 13371500Serics } 133816710Sjak if (id > 0) { 133916710Sjak signal (SIGINT, SIG_IGN); 134016710Sjak signal (SIGQUIT, SIG_IGN); 134116710Sjak if (catch_susp) 134216710Sjak signal(SIGTSTP, SIG_DFL); 134316710Sjak while (wait(0) > 0); 134416710Sjak signal (SIGINT, end_it); 134516710Sjak signal (SIGQUIT, onquit); 134616710Sjak if (catch_susp) 134716710Sjak signal(SIGTSTP, onsusp); 134816710Sjak } else 134916710Sjak write(2, "can't fork\n", 11); 13501500Serics set_tty (); 13511500Serics pr ("------------------------\n"); 13521500Serics prompt (filename); 13531500Serics } 13541500Serics /* 13551500Serics ** Skip n lines in the file f 13561500Serics */ 13571500Serics 13581500Serics skiplns (n, f) 13591500Serics register int n; 13601500Serics register FILE *f; 13611500Serics { 13621500Serics register char c; 13631500Serics 13641500Serics while (n > 0) { 13651500Serics while ((c = Getc (f)) != '\n') 13661500Serics if (c == EOF) 13671500Serics return; 13681500Serics n--; 13691500Serics Currline++; 13701500Serics } 13711500Serics } 13721500Serics 13731500Serics /* 13741500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 13751500Serics ** negative. 13761500Serics */ 13771500Serics 13781500Serics skipf (nskip) 13791500Serics register int nskip; 13801500Serics { 13811500Serics if (nskip == 0) return; 13821500Serics if (nskip > 0) { 13831500Serics if (fnum + nskip > nfiles - 1) 13841500Serics nskip = nfiles - fnum - 1; 13851500Serics } 13861500Serics else if (within) 13871500Serics ++fnum; 13881500Serics fnum += nskip; 13891500Serics if (fnum < 0) 13901500Serics fnum = 0; 13913594Sroot pr ("\n...Skipping "); 13923455Sroot pr ("\n"); 13933594Sroot if (clreol) 13943594Sroot cleareol (); 13953455Sroot pr ("...Skipping "); 13961500Serics pr (nskip > 0 ? "to file " : "back to file "); 13971500Serics pr (fnames[fnum]); 13983455Sroot pr ("\n"); 13993594Sroot if (clreol) 14003594Sroot cleareol (); 14013455Sroot pr ("\n"); 14021500Serics --fnum; 14031500Serics } 14041500Serics 14051500Serics /*----------------------------- Terminal I/O -------------------------------*/ 14061500Serics 14071500Serics initterm () 14081500Serics { 14091500Serics char buf[TBUFSIZ]; 141017195Sralph static char clearbuf[TBUFSIZ]; 14111500Serics char *clearptr, *padstr; 14121500Serics int ldisc; 141317592Sleres int lmode; 141410823Ssam char *term; 141516582Sleres int tgrp; 141618030Sbloom struct winsize win; 14171500Serics 141816582Sleres retry: 141916582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 142017592Sleres if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { 142117592Sleres perror("TIOCLGET"); 142217592Sleres exit(1); 142317592Sleres } 142417592Sleres docrterase = ((lmode & LCRTERA) != 0); 142517592Sleres docrtkill = ((lmode & LCRTKIL) != 0); 142616582Sleres /* 142717592Sleres * Wait until we're in the foreground before we save the 142817592Sleres * the terminal modes. 142916582Sleres */ 143016582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 143117592Sleres perror("TIOCGPGRP"); 143216582Sleres exit(1); 143316582Sleres } 143416582Sleres if (tgrp != getpgrp(0)) { 143516582Sleres kill(0, SIGTTOU); 143616582Sleres goto retry; 143716582Sleres } 143813830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 14393594Sroot dumb++; ul_opt = 0; 14401500Serics } 14411500Serics else { 144218030Sbloom if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { 144318030Sbloom Lpp = tgetnum("li"); 144418030Sbloom Mcol = tgetnum("co"); 144518030Sbloom } else { 144618030Sbloom if ((Lpp = win.ws_row) == 0) 144718030Sbloom Lpp = tgetnum("li"); 144818030Sbloom if ((Mcol = win.ws_col) == 0) 144918030Sbloom Mcol = tgetnum("co"); 145018030Sbloom } 145118030Sbloom if ((Lpp <= 0) || tgetflag("hc")) { 14521500Serics hard++; /* Hard copy terminal */ 14531500Serics Lpp = 24; 14541500Serics } 145518030Sbloom if (Mcol <= 0) 145618030Sbloom Mcol = 80; 145718030Sbloom 14581500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 14591500Serics noscroll++; 14601500Serics Wrap = tgetflag("am"); 14611500Serics bad_so = tgetflag ("xs"); 14621500Serics clearptr = clearbuf; 14631500Serics eraseln = tgetstr("ce",&clearptr); 14641500Serics Clear = tgetstr("cl", &clearptr); 14651500Serics Senter = tgetstr("so", &clearptr); 14661500Serics Sexit = tgetstr("se", &clearptr); 146716710Sjak if ((soglitch = tgetnum("sg")) < 0) 146816710Sjak soglitch = 0; 14693594Sroot 14703594Sroot /* 14713594Sroot * Set up for underlining: some terminals don't need it; 14723594Sroot * others have start/stop sequences, still others have an 14733594Sroot * underline char sequence which is assumed to move the 14743594Sroot * cursor forward one character. If underline sequence 14753594Sroot * isn't available, settle for standout sequence. 14763594Sroot */ 14773594Sroot 14783594Sroot if (tgetflag("ul") || tgetflag("os")) 14793594Sroot ul_opt = 0; 14803594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 14813594Sroot chUL = ""; 148216710Sjak if (((ULenter = tgetstr("us", &clearptr)) == NULL || 148316710Sjak (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 148416710Sjak if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 148516710Sjak ULenter = ""; 148616710Sjak ULexit = ""; 148716710Sjak } else 148816710Sjak ulglitch = soglitch; 148916710Sjak } else { 149016710Sjak if ((ulglitch = tgetnum("ug")) < 0) 149116710Sjak ulglitch = 0; 149216710Sjak } 149316582Sleres 14941500Serics if (padstr = tgetstr("pc", &clearptr)) 14951500Serics PC = *padstr; 14963455Sroot Home = tgetstr("ho",&clearptr); 149713536Ssam if (Home == 0 || *Home == '\0') 14983455Sroot { 14993594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 15003594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 15013455Sroot Home = cursorhome; 15023455Sroot } 15033455Sroot } 15043594Sroot EodClr = tgetstr("cd", &clearptr); 1505*25540Smckusick if ((chBS = tgetstr("bc", &clearptr)) == NULL) 1506*25540Smckusick chBS = "\b"; 1507*25540Smckusick 15081500Serics } 15091500Serics if ((shell = getenv("SHELL")) == NULL) 15101500Serics shell = "/bin/sh"; 15111500Serics } 151216582Sleres no_intty = gtty(fileno(stdin), &otty); 151316582Sleres gtty(fileno(stderr), &otty); 151413830Skre savetty = otty; 15151500Serics ospeed = otty.sg_ospeed; 15161500Serics slow_tty = ospeed < B1200; 15171500Serics hardtabs = !(otty.sg_flags & XTABS); 15181500Serics if (!no_tty) { 15191500Serics otty.sg_flags &= ~ECHO; 15201500Serics if (MBIT == CBREAK || !slow_tty) 15211500Serics otty.sg_flags |= MBIT; 15221500Serics } 15231500Serics } 15241500Serics 15251500Serics readch () 15261500Serics { 15271500Serics char ch; 15281500Serics extern int errno; 15291500Serics 15301500Serics if (read (2, &ch, 1) <= 0) 15311500Serics if (errno != EINTR) 15321500Serics exit(0); 15331500Serics else 15341500Serics ch = otty.sg_kill; 15351500Serics return (ch); 15361500Serics } 15371500Serics 15381500Serics static char BS = '\b'; 153917592Sleres static char *BSB = "\b \b"; 15401500Serics static char CARAT = '^'; 154117592Sleres #define ERASEONECHAR \ 154217592Sleres if (docrterase) \ 154317592Sleres write (2, BSB, sizeof(BSB)); \ 154417592Sleres else \ 154517592Sleres write (2, &BS, sizeof(BS)); 15461500Serics 15471500Serics ttyin (buf, nmax, pchar) 15481500Serics char buf[]; 15491500Serics register int nmax; 15501500Serics char pchar; 15511500Serics { 15521500Serics register char *sptr; 15531500Serics register char ch; 15541500Serics register int slash = 0; 15551500Serics int maxlen; 15561500Serics char cbuf; 15571500Serics 15581500Serics sptr = buf; 15591500Serics maxlen = 0; 15601500Serics while (sptr - buf < nmax) { 15611500Serics if (promptlen > maxlen) maxlen = promptlen; 15621500Serics ch = readch (); 15631500Serics if (ch == '\\') { 15641500Serics slash++; 15651500Serics } 15661500Serics else if ((ch == otty.sg_erase) && !slash) { 15671500Serics if (sptr > buf) { 15681500Serics --promptlen; 156917592Sleres ERASEONECHAR 15701500Serics --sptr; 15711500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 15721500Serics --promptlen; 157317592Sleres ERASEONECHAR 15741500Serics } 15751500Serics continue; 15761500Serics } 15771500Serics else { 15781500Serics if (!eraseln) promptlen = maxlen; 15791500Serics longjmp (restore, 1); 15801500Serics } 15811500Serics } 15821500Serics else if ((ch == otty.sg_kill) && !slash) { 15831500Serics if (hard) { 15841500Serics show (ch); 15851500Serics putchar ('\n'); 15861500Serics putchar (pchar); 15871500Serics } 15881500Serics else { 15891500Serics putchar ('\r'); 15901500Serics putchar (pchar); 15911500Serics if (eraseln) 15921500Serics erase (1); 159317592Sleres else if (docrtkill) 159417592Sleres while (promptlen-- > 1) 159517592Sleres write (2, BSB, sizeof(BSB)); 15961500Serics promptlen = 1; 15971500Serics } 15981500Serics sptr = buf; 15991500Serics fflush (stdout); 16001500Serics continue; 16011500Serics } 16021500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 160317592Sleres ERASEONECHAR 16041500Serics --sptr; 16051500Serics } 16061500Serics if (ch != '\\') 16071500Serics slash = 0; 16081500Serics *sptr++ = ch; 16091500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 16101500Serics ch += ch == RUBOUT ? -0100 : 0100; 16111500Serics write (2, &CARAT, 1); 16121500Serics promptlen++; 16131500Serics } 16141500Serics cbuf = ch; 16151500Serics if (ch != '\n' && ch != ESC) { 16161500Serics write (2, &cbuf, 1); 16171500Serics promptlen++; 16181500Serics } 16191500Serics else 16201500Serics break; 16211500Serics } 16221500Serics *--sptr = '\0'; 16231500Serics if (!eraseln) promptlen = maxlen; 16241500Serics if (sptr - buf >= nmax - 1) 16251500Serics error ("Line too long"); 16261500Serics } 16271500Serics 16281500Serics expand (outbuf, inbuf) 16291500Serics char *outbuf; 16301500Serics char *inbuf; 16311500Serics { 16321500Serics register char *instr; 16331500Serics register char *outstr; 16341500Serics register char ch; 16351500Serics char temp[200]; 16361500Serics int changed = 0; 16371500Serics 16381500Serics instr = inbuf; 16391500Serics outstr = temp; 16401500Serics while ((ch = *instr++) != '\0') 16411500Serics switch (ch) { 16421500Serics case '%': 16431500Serics if (!no_intty) { 16441500Serics strcpy (outstr, fnames[fnum]); 16451500Serics outstr += strlen (fnames[fnum]); 16461500Serics changed++; 16471500Serics } 16481500Serics else 16491500Serics *outstr++ = ch; 16501500Serics break; 16511500Serics case '!': 16521500Serics if (!shellp) 16531500Serics error ("No previous command to substitute for"); 16541500Serics strcpy (outstr, shell_line); 16551500Serics outstr += strlen (shell_line); 16561500Serics changed++; 16571500Serics break; 16581500Serics case '\\': 16591500Serics if (*instr == '%' || *instr == '!') { 16601500Serics *outstr++ = *instr++; 16611500Serics break; 16621500Serics } 16631500Serics default: 16641500Serics *outstr++ = ch; 16651500Serics } 16661500Serics *outstr++ = '\0'; 16671500Serics strcpy (outbuf, temp); 16681500Serics return (changed); 16691500Serics } 16701500Serics 16711500Serics show (ch) 16721500Serics register char ch; 16731500Serics { 16741500Serics char cbuf; 16751500Serics 16761500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 16771500Serics ch += ch == RUBOUT ? -0100 : 0100; 16781500Serics write (2, &CARAT, 1); 16791500Serics promptlen++; 16801500Serics } 16811500Serics cbuf = ch; 16821500Serics write (2, &cbuf, 1); 16831500Serics promptlen++; 16841500Serics } 16851500Serics 16861500Serics error (mess) 16871500Serics char *mess; 16881500Serics { 16893594Sroot if (clreol) 16903594Sroot cleareol (); 16913594Sroot else 16923594Sroot kill_line (); 16931500Serics promptlen += strlen (mess); 16941500Serics if (Senter && Sexit) { 16951500Serics tputs (Senter, 1, putch); 16961500Serics pr(mess); 16971500Serics tputs (Sexit, 1, putch); 16981500Serics } 16991500Serics else 17001500Serics pr (mess); 17011500Serics fflush(stdout); 17021500Serics errors++; 17031500Serics longjmp (restore, 1); 17041500Serics } 17051500Serics 17061500Serics 17071500Serics set_tty () 17081500Serics { 17091500Serics otty.sg_flags |= MBIT; 17101500Serics otty.sg_flags &= ~ECHO; 171116582Sleres stty(fileno(stderr), &otty); 17121500Serics } 17131500Serics 17141500Serics reset_tty () 17151500Serics { 171616710Sjak if (pstate) { 171716710Sjak tputs(ULexit, 1, putch); 171816710Sjak fflush(stdout); 171916710Sjak pstate = 0; 172016710Sjak } 17211500Serics otty.sg_flags |= ECHO; 17221500Serics otty.sg_flags &= ~MBIT; 172316582Sleres stty(fileno(stderr), &savetty); 17241500Serics } 17251500Serics 17261500Serics rdline (f) 17271500Serics register FILE *f; 17281500Serics { 17291500Serics register char c; 17301500Serics register char *p; 17311500Serics 17321500Serics p = Line; 17331500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 17341500Serics *p++ = c; 17351500Serics if (c == '\n') 17361500Serics Currline++; 17371500Serics *p = '\0'; 17381500Serics } 17391500Serics 17401500Serics /* Come here when we get a suspend signal from the terminal */ 17411500Serics 17421500Serics onsusp () 17431500Serics { 174414861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 174514861Skarels signal(SIGTTOU, SIG_IGN); 17461500Serics reset_tty (); 17471500Serics fflush (stdout); 174814861Skarels signal(SIGTTOU, SIG_DFL); 17491500Serics /* Send the TSTP signal to suspend our process group */ 175013289Ssam signal(SIGTSTP, SIG_DFL); 175113289Ssam sigsetmask(0); 17521500Serics kill (0, SIGTSTP); 17531500Serics /* Pause for station break */ 17541500Serics 17551500Serics /* We're back */ 17561500Serics signal (SIGTSTP, onsusp); 17571500Serics set_tty (); 17581500Serics if (inwait) 17591500Serics longjmp (restore); 17601500Serics } 1761