113615Ssam #ifndef lint 2*16710Sjak static char *sccsid = "@(#)more.c 4.19 (Berkeley) 84/07/12"; 313615Ssam #endif 43594Sroot 51500Serics /* 61500Serics ** more.c - General purpose tty output filter and file perusal program 71500Serics ** 81500Serics ** by Eric Shienbrood, UC Berkeley 93594Sroot ** 103594Sroot ** modified by Geoff Peck, UCB to add underlining, single spacing 113594Sroot ** modified by John Foderaro, UCB to add -c and MORE environment variable 121500Serics */ 131500Serics 141500Serics #include <stdio.h> 151500Serics #include <ctype.h> 161500Serics #include <signal.h> 171500Serics #include <errno.h> 181500Serics #include <sgtty.h> 191500Serics #include <setjmp.h> 201500Serics #include <sys/types.h> 211500Serics #include <sys/stat.h> 221500Serics 2313615Ssam #define HELPFILE "/usr/lib/more.help" 2413615Ssam #define VI "/usr/ucb/vi" 251500Serics 261500Serics #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) 271500Serics #define Ftell(f) file_pos 281500Serics #define Fseek(f,off) (file_pos=off,fseek(f,off,0)) 291500Serics #define Getc(f) (++file_pos, getc(f)) 301500Serics #define Ungetc(c,f) (--file_pos, ungetc(c,f)) 311500Serics 321500Serics #define MBIT CBREAK 331500Serics #define stty(fd,argp) ioctl(fd,TIOCSETN,argp) 341500Serics 351500Serics #define TBUFSIZ 1024 361500Serics #define LINSIZ 256 371500Serics #define ctrl(letter) ('letter' & 077) 381500Serics #define RUBOUT '\177' 391500Serics #define ESC '\033' 401500Serics #define QUIT '\034' 411500Serics 4216582Sleres struct sgttyb otty, savetty; 431500Serics long file_pos, file_size; 441500Serics int fnum, no_intty, no_tty, slow_tty; 451500Serics int dum_opt, dlines, onquit(), end_it(); 461500Serics int onsusp(); 471500Serics int nscroll = 11; /* Number of lines scrolled by 'd' */ 481500Serics int fold_opt = 1; /* Fold long lines */ 491500Serics int stop_opt = 1; /* Stop after form feeds */ 503594Sroot int ssp_opt = 0; /* Suppress white space */ 513594Sroot int ul_opt = 1; /* Underline as best we can */ 521500Serics int promptlen; 531500Serics int Currline; /* Line we are currently at */ 541500Serics int startup = 1; 551500Serics int firstf = 1; 561500Serics int notell = 1; 571500Serics int bad_so; /* True if overwriting does not turn off standout */ 581500Serics int inwait, Pause, errors; 591500Serics int within; /* true if we are within a file, 601500Serics false if we are between files */ 613594Sroot int hard, dumb, noscroll, hardtabs, clreol; 621500Serics int catch_susp; /* We should catch the SIGTSTP signal */ 631500Serics char **fnames; /* The list of file names */ 641500Serics int nfiles; /* Number of files left to process */ 651500Serics char *shell; /* The name of the shell to use */ 661500Serics int shellp; /* A previous shell command exists */ 671500Serics char ch; 681500Serics jmp_buf restore; 691500Serics char obuf[BUFSIZ]; /* stdout buffer */ 701500Serics char Line[LINSIZ]; /* Line buffer */ 711500Serics int Lpp = 24; /* lines per page */ 721500Serics char *Clear; /* clear screen */ 731500Serics char *eraseln; /* erase line */ 741500Serics char *Senter, *Sexit;/* enter and exit standout mode */ 753594Sroot char *ULenter, *ULexit; /* enter and exit underline mode */ 763594Sroot char *chUL; /* underline character */ 773594Sroot char *chBS; /* backspace character */ 783455Sroot char *Home; /* go to home */ 793455Sroot char *cursorm; /* cursor movement */ 803455Sroot char cursorhome[40]; /* contains cursor movement to home */ 813594Sroot char *EodClr; /* clear rest of screen */ 821500Serics char *tgetstr(); 831500Serics int Mcol = 80; /* number of columns */ 841500Serics int Wrap = 1; /* set if automargins */ 85*16710Sjak int soglitch; /* terminal has standout mode glitch */ 86*16710Sjak int ulglitch; /* terminal has underline mode glitch */ 87*16710Sjak int pstate = 0; /* current UL state */ 881500Serics long fseek(); 893455Sroot char *getenv(); 901500Serics struct { 911500Serics long chrctr, line; 921500Serics } context, screen_start; 931500Serics extern char PC; /* pad character */ 941500Serics extern short ospeed; 951500Serics 961500Serics 971500Serics main(argc, argv) 981500Serics int argc; 991500Serics char *argv[]; 1001500Serics { 1011500Serics register FILE *f; 1021500Serics register char *s; 1031500Serics register char *p; 1041500Serics register char ch; 1051500Serics register int left; 10616582Sleres int prnames = 0; 1071500Serics int initopt = 0; 1081500Serics int srchopt = 0; 1091500Serics int clearit = 0; 1101500Serics int initline; 1111500Serics char initbuf[80]; 1121500Serics FILE *checkf(); 1131500Serics 1141500Serics nfiles = argc; 1151500Serics fnames = argv; 1161500Serics initterm (); 11715813Sralph nscroll = Lpp/2 - 1; 11815813Sralph if (nscroll <= 0) 11915813Sralph nscroll = 1; 1203455Sroot if(s = getenv("MORE")) argscan(s); 1211500Serics while (--nfiles > 0) { 1221500Serics if ((ch = (*++fnames)[0]) == '-') { 1233455Sroot argscan(*fnames+1); 1241500Serics } 1251500Serics else if (ch == '+') { 1261500Serics s = *fnames; 1271500Serics if (*++s == '/') { 1281500Serics srchopt++; 1291500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1301500Serics *p++ = *s++; 1311500Serics *p = '\0'; 1321500Serics } 1331500Serics else { 1341500Serics initopt++; 1351500Serics for (initline = 0; *s != '\0'; s++) 1361500Serics if (isdigit (*s)) 1371500Serics initline = initline*10 + *s -'0'; 1381500Serics --initline; 1391500Serics } 1401500Serics } 1411500Serics else break; 1421500Serics } 1433594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1443455Sroot * defined, and in that case, make sure we are in noscroll mode 1453455Sroot */ 1463455Sroot if(clreol) 1473455Sroot { 1483594Sroot if ((*Home == '\0') || (*eraseln == '\0') || (*EodClr == '\0')) 1493594Sroot clreol = 0; 1503455Sroot else noscroll = 1; 1513455Sroot } 1523455Sroot 1531500Serics if (dlines == 0) 1541500Serics dlines = Lpp - (noscroll ? 1 : 2); 1551500Serics left = dlines; 1561500Serics if (nfiles > 1) 1571500Serics prnames++; 1581500Serics if (!no_intty && nfiles == 0) { 1591500Serics fputs("Usage: ",stderr); 1601500Serics fputs(argv[0],stderr); 1611500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1621500Serics exit(1); 1631500Serics } 1641500Serics else 1651500Serics f = stdin; 1661500Serics if (!no_tty) { 1671500Serics signal(SIGQUIT, onquit); 1681500Serics signal(SIGINT, end_it); 1691500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1701500Serics signal(SIGTSTP, onsusp); 1711500Serics catch_susp++; 1721500Serics } 17316582Sleres stty (fileno(stderr), &otty); 1741500Serics } 1751500Serics if (no_intty) { 1761500Serics if (no_tty) 1771500Serics copy_file (stdin); 1781500Serics else { 1791500Serics if ((ch = Getc (f)) == '\f') 1803594Sroot doclear(); 1811500Serics else { 1821500Serics Ungetc (ch, f); 1833594Sroot if (noscroll && (ch != EOF)) { 1843594Sroot if (clreol) 1853594Sroot home (); 1863594Sroot else 1873594Sroot doclear (); 1883455Sroot } 1891500Serics } 1901500Serics if (srchopt) 1913455Sroot { 1921500Serics search (initbuf, stdin, 1); 1933594Sroot if (noscroll) 1943594Sroot left--; 1953455Sroot } 1961500Serics else if (initopt) 1971500Serics skiplns (initline, stdin); 1981500Serics screen (stdin, left); 1991500Serics } 2001500Serics no_intty = 0; 2011500Serics prnames++; 2021500Serics firstf = 0; 2031500Serics } 2041500Serics 2051500Serics while (fnum < nfiles) { 2061500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2071500Serics context.line = context.chrctr = 0; 2081500Serics Currline = 0; 2091500Serics if (firstf) setjmp (restore); 2101500Serics if (firstf) { 2111500Serics firstf = 0; 2121500Serics if (srchopt) 2133455Sroot { 2141500Serics search (initbuf, f, 1); 2153594Sroot if (noscroll) 2163594Sroot left--; 2173455Sroot } 2181500Serics else if (initopt) 2191500Serics skiplns (initline, f); 2201500Serics } 2211500Serics else if (fnum < nfiles && !no_tty) { 2221500Serics setjmp (restore); 2231500Serics left = command (fnames[fnum], f); 2241500Serics } 2251500Serics if (left != 0) { 2263594Sroot if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 2273594Sroot if (clreol) 2283594Sroot home (); 2293594Sroot else 2303594Sroot doclear (); 2311500Serics if (prnames) { 2321500Serics if (bad_so) 2331500Serics erase (0); 2343594Sroot if (clreol) 2353594Sroot cleareol (); 2361500Serics pr("::::::::::::::"); 2371500Serics if (promptlen > 14) 2381500Serics erase (14); 2393455Sroot printf ("\n"); 2403455Sroot if(clreol) cleareol(); 2413455Sroot printf("%s\n", fnames[fnum]); 2423455Sroot if(clreol) cleareol(); 2433455Sroot printf("::::::::::::::\n", fnames[fnum]); 2441500Serics if (left > Lpp - 4) 2451500Serics left = Lpp - 4; 2461500Serics } 2471500Serics if (no_tty) 2481500Serics copy_file (f); 2491500Serics else { 2501500Serics within++; 2511500Serics screen(f, left); 2521500Serics within = 0; 2531500Serics } 2541500Serics } 2551500Serics setjmp (restore); 2561500Serics fflush(stdout); 2571500Serics fclose(f); 2581500Serics screen_start.line = screen_start.chrctr = 0L; 2591500Serics context.line = context.chrctr = 0L; 2601500Serics } 2611500Serics fnum++; 2621500Serics firstf = 0; 2631500Serics } 2641500Serics reset_tty (); 2651500Serics exit(0); 2661500Serics } 2671500Serics 2683455Sroot argscan(s) 2693455Sroot char *s; 2703455Sroot { 27111604Slayer for (dlines = 0; *s != '\0'; s++) 27211604Slayer { 27311604Slayer switch (*s) 27411604Slayer { 27511604Slayer case '0': case '1': case '2': 27611604Slayer case '3': case '4': case '5': 27711604Slayer case '6': case '7': case '8': 27811604Slayer case '9': 27911604Slayer dlines = dlines*10 + *s - '0'; 28011604Slayer break; 28111604Slayer case 'd': 28211604Slayer dum_opt = 1; 28311604Slayer break; 28411604Slayer case 'l': 28511604Slayer stop_opt = 0; 28611604Slayer break; 28711604Slayer case 'f': 28811604Slayer fold_opt = 0; 28911604Slayer break; 29011604Slayer case 'p': 29111604Slayer noscroll++; 29211604Slayer break; 29311604Slayer case 'c': 29411604Slayer clreol++; 29511604Slayer break; 29611604Slayer case 's': 29711604Slayer ssp_opt = 1; 29811604Slayer break; 29911604Slayer case 'u': 30011604Slayer ul_opt = 0; 30111604Slayer break; 30211604Slayer } 30311604Slayer } 3043455Sroot } 3053455Sroot 3063455Sroot 3071500Serics /* 3081500Serics ** Check whether the file named by fs is an ASCII file which the user may 3091500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3101500Serics */ 3111500Serics 3121500Serics FILE * 3131500Serics checkf (fs, clearfirst) 3141500Serics register char *fs; 3151500Serics int *clearfirst; 3161500Serics { 3171500Serics struct stat stbuf; 3181500Serics register FILE *f; 3191500Serics char c; 3201500Serics 3211500Serics if (stat (fs, &stbuf) == -1) { 3221500Serics fflush(stdout); 3233594Sroot if (clreol) 3243594Sroot cleareol (); 3251500Serics perror(fs); 3261500Serics return (NULL); 3271500Serics } 3281500Serics if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3291500Serics printf("\n*** %s: directory ***\n\n", fs); 3301500Serics return (NULL); 3311500Serics } 3321500Serics if ((f=Fopen(fs, "r")) == NULL) { 3331500Serics fflush(stdout); 3341500Serics perror(fs); 3351500Serics return (NULL); 3361500Serics } 3371500Serics c = Getc(f); 3381500Serics 3391500Serics /* Try to see whether it is an ASCII file */ 3401500Serics 3411500Serics switch ((c | *f->_ptr << 8) & 0177777) { 3421500Serics case 0405: 3431500Serics case 0407: 3441500Serics case 0410: 3451500Serics case 0411: 3461500Serics case 0413: 3471500Serics case 0177545: 3481500Serics printf("\n******** %s: Not a text file ********\n\n", fs); 3491500Serics fclose (f); 3501500Serics return (NULL); 3511500Serics default: 3521500Serics break; 3531500Serics } 3541500Serics if (c == '\f') 3551500Serics *clearfirst = 1; 3561500Serics else { 3571500Serics *clearfirst = 0; 3581500Serics Ungetc (c, f); 3591500Serics } 3601500Serics if ((file_size = stbuf.st_size) == 0) 3611500Serics file_size = 0x7fffffffffffffffL; 3621500Serics return (f); 3631500Serics } 3641500Serics 3651500Serics /* 3661500Serics ** A real function, for the tputs routine in termlib 3671500Serics */ 3681500Serics 3691500Serics putch (ch) 3701500Serics char ch; 3711500Serics { 3721500Serics putchar (ch); 3731500Serics } 3741500Serics 3751500Serics /* 3761500Serics ** Print out the contents of the file f, one screenful at a time. 3771500Serics */ 3781500Serics 3791500Serics #define STOP -10 3801500Serics 3811500Serics screen (f, num_lines) 3821500Serics register FILE *f; 3831500Serics register int num_lines; 3841500Serics { 3851500Serics register int c; 3861500Serics register int nchars; 3873594Sroot int length; /* length of current line */ 3883594Sroot static int prev_len = 1; /* length of previous line */ 3891500Serics 3901500Serics for (;;) { 3911500Serics while (num_lines > 0 && !Pause) { 3921500Serics if ((nchars = getline (f, &length)) == EOF) 3933455Sroot { 3943594Sroot if (clreol) 3953594Sroot clreos(); 3961500Serics return; 3973455Sroot } 3983594Sroot if (ssp_opt && length == 0 && prev_len == 0) 3993594Sroot continue; 4003594Sroot prev_len = length; 4011500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 4021500Serics erase (0); 4033594Sroot /* must clear before drawing line since tabs on some terminals 4043594Sroot * do not erase what they tab over. 4053594Sroot */ 4063594Sroot if (clreol) 4073594Sroot cleareol (); 4081500Serics prbuf (Line, length); 4091500Serics if (nchars < promptlen) 4101500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4111500Serics else promptlen = 0; 4123594Sroot /* is this needed? 4133594Sroot * if (clreol) 4143594Sroot * cleareol(); /* must clear again in case we wrapped * 4153594Sroot */ 4161500Serics if (nchars < Mcol || !fold_opt) 417*16710Sjak prbuf("\n", 1); /* will turn off UL if necessary */ 4181500Serics if (nchars == STOP) 4191500Serics break; 4201500Serics num_lines--; 4211500Serics } 422*16710Sjak if (pstate) { 423*16710Sjak tputs(ULexit, 1, putch); 424*16710Sjak pstate = 0; 425*16710Sjak } 4261500Serics fflush(stdout); 4271500Serics if ((c = Getc(f)) == EOF) 4283455Sroot { 4293594Sroot if (clreol) 4303594Sroot clreos (); 4311500Serics return; 4323455Sroot } 4333455Sroot 4343594Sroot if (Pause && clreol) 4353594Sroot clreos (); 4361500Serics Ungetc (c, f); 4371500Serics setjmp (restore); 4381500Serics Pause = 0; startup = 0; 4391500Serics if ((num_lines = command (NULL, f)) == 0) 4401500Serics return; 4411500Serics if (hard && promptlen > 0) 4421500Serics erase (0); 44311123Slayer if (noscroll && num_lines >= dlines) 44416582Sleres { 4453594Sroot if (clreol) 4463594Sroot home(); 4473594Sroot else 4483594Sroot doclear (); 4493455Sroot } 4501500Serics screen_start.line = Currline; 4511500Serics screen_start.chrctr = Ftell (f); 4521500Serics } 4531500Serics } 4541500Serics 4551500Serics /* 4561500Serics ** Come here if a quit signal is received 4571500Serics */ 4581500Serics 4591500Serics onquit() 4601500Serics { 4611500Serics signal(SIGQUIT, SIG_IGN); 4621500Serics if (!inwait) { 4631500Serics putchar ('\n'); 4641500Serics if (!startup) { 4651500Serics signal(SIGQUIT, onquit); 4661500Serics longjmp (restore, 1); 4671500Serics } 4681500Serics else 4691500Serics Pause++; 4701500Serics } 4711500Serics else if (!dum_opt && notell) { 4721500Serics write (2, "[Use q or Q to quit]", 20); 4731500Serics promptlen += 20; 4741500Serics notell = 0; 4751500Serics } 4761500Serics signal(SIGQUIT, onquit); 4771500Serics } 4781500Serics 4791500Serics /* 4801500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 4811500Serics */ 4821500Serics 4831500Serics end_it () 4841500Serics { 4851500Serics 4861500Serics reset_tty (); 4873594Sroot if (clreol) { 4883594Sroot putchar ('\r'); 4893594Sroot clreos (); 4903594Sroot fflush (stdout); 4913594Sroot } 4923455Sroot else if (!clreol && (promptlen > 0)) { 4931500Serics kill_line (); 4941500Serics fflush (stdout); 4951500Serics } 4961500Serics else 4971500Serics write (2, "\n", 1); 4981500Serics _exit(0); 4991500Serics } 5001500Serics 5011500Serics copy_file(f) 5021500Serics register FILE *f; 5031500Serics { 5041500Serics register int c; 5051500Serics 5061500Serics while ((c = getc(f)) != EOF) 5071500Serics putchar(c); 5081500Serics } 5091500Serics 5101500Serics /* Simplified printf function */ 5111500Serics 5121500Serics printf (fmt, args) 5131500Serics register char *fmt; 5141500Serics int args; 5151500Serics { 5161500Serics register int *argp; 5171500Serics register char ch; 5181500Serics register int ccount; 5191500Serics 5201500Serics ccount = 0; 5211500Serics argp = &args; 5221500Serics while (*fmt) { 5231500Serics while ((ch = *fmt++) != '%') { 5241500Serics if (ch == '\0') 5251500Serics return (ccount); 5261500Serics ccount++; 5271500Serics putchar (ch); 5281500Serics } 5291500Serics switch (*fmt++) { 5301500Serics case 'd': 5311500Serics ccount += printd (*argp); 5321500Serics break; 5331500Serics case 's': 5341500Serics ccount += pr ((char *)*argp); 5351500Serics break; 5361500Serics case '%': 5371500Serics ccount++; 5381500Serics argp--; 5391500Serics putchar ('%'); 5401500Serics break; 5411500Serics case '0': 5421500Serics return (ccount); 5431500Serics default: 5441500Serics break; 5451500Serics } 5461500Serics ++argp; 5471500Serics } 5481500Serics return (ccount); 5491500Serics 5501500Serics } 5511500Serics 5521500Serics /* 5531500Serics ** Print an integer as a string of decimal digits, 5541500Serics ** returning the length of the print representation. 5551500Serics */ 5561500Serics 5571500Serics printd (n) 5581500Serics int n; 5591500Serics { 5601500Serics int a, nchars; 5611500Serics 5621500Serics if (a = n/10) 5631500Serics nchars = 1 + printd(a); 5641500Serics else 5651500Serics nchars = 1; 5661500Serics putchar (n % 10 + '0'); 5671500Serics return (nchars); 5681500Serics } 5691500Serics 5701500Serics /* Put the print representation of an integer into a string */ 5711500Serics static char *sptr; 5721500Serics 5731500Serics scanstr (n, str) 5741500Serics int n; 5751500Serics char *str; 5761500Serics { 5771500Serics sptr = str; 57811604Slayer Sprintf (n); 5791500Serics *sptr = '\0'; 5801500Serics } 5811500Serics 58211604Slayer Sprintf (n) 5831500Serics { 5841500Serics int a; 5851500Serics 5861500Serics if (a = n/10) 58711604Slayer Sprintf (a); 5881500Serics *sptr++ = n % 10 + '0'; 5891500Serics } 5901500Serics 5911500Serics static char bell = ctrl(G); 5921500Serics 5931500Serics strlen (s) 5941500Serics char *s; 5951500Serics { 5961500Serics register char *p; 5971500Serics 5981500Serics p = s; 5991500Serics while (*p++) 6001500Serics ; 6011500Serics return (p - s - 1); 6021500Serics } 6031500Serics 6041500Serics /* See whether the last component of the path name "path" is equal to the 6051500Serics ** string "string" 6061500Serics */ 6071500Serics 6081500Serics tailequ (path, string) 6091500Serics char *path; 6101500Serics register char *string; 6111500Serics { 6121500Serics register char *tail; 6131500Serics 6141500Serics tail = path + strlen(path); 6151500Serics while (tail >= path) 6161500Serics if (*(--tail) == '/') 6171500Serics break; 6181500Serics ++tail; 6191500Serics while (*tail++ == *string++) 6201500Serics if (*tail == '\0') 6211500Serics return(1); 6221500Serics return(0); 6231500Serics } 6241500Serics 6251500Serics prompt (filename) 6261500Serics char *filename; 6271500Serics { 6283594Sroot if (clreol) 6293594Sroot cleareol (); 6303455Sroot else if (promptlen > 0) 6311500Serics kill_line (); 6321500Serics if (!hard) { 6331500Serics promptlen = 8; 634*16710Sjak if (Senter && Sexit) { 6351500Serics tputs (Senter, 1, putch); 636*16710Sjak promptlen += (2 * soglitch); 637*16710Sjak } 6383594Sroot if (clreol) 6393594Sroot cleareol (); 6401500Serics pr("--More--"); 6411500Serics if (filename != NULL) { 6421500Serics promptlen += printf ("(Next file: %s)", filename); 6431500Serics } 6441500Serics else if (!no_intty) { 6451500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 6461500Serics } 6471500Serics if (dum_opt) { 648*16710Sjak promptlen += pr("[Press space to continue, 'q' to quit.]"); 6491500Serics } 6501500Serics if (Senter && Sexit) 6511500Serics tputs (Sexit, 1, putch); 6523594Sroot if (clreol) 6533594Sroot clreos (); 6541500Serics fflush(stdout); 6551500Serics } 6561500Serics else 6571500Serics write (2, &bell, 1); 6581500Serics inwait++; 6591500Serics } 6601500Serics 6611500Serics /* 6621500Serics ** Get a logical line 6631500Serics */ 6641500Serics 6651500Serics getline(f, length) 6661500Serics register FILE *f; 6671500Serics int *length; 6681500Serics { 6691500Serics register int c; 6701500Serics register char *p; 6711500Serics register int column; 6721500Serics static int colflg; 6731500Serics 6741500Serics p = Line; 6751500Serics column = 0; 6761500Serics c = Getc (f); 6771500Serics if (colflg && c == '\n') { 6781500Serics Currline++; 6791500Serics c = Getc (f); 6801500Serics } 6811500Serics while (p < &Line[LINSIZ - 1]) { 6821500Serics if (c == EOF) { 6831500Serics if (p > Line) { 6841500Serics *p = '\0'; 6851500Serics *length = p - Line; 6861500Serics return (column); 6871500Serics } 6881500Serics *length = p - Line; 6891500Serics return (EOF); 6901500Serics } 6911500Serics if (c == '\n') { 6921500Serics Currline++; 6931500Serics break; 6941500Serics } 6951500Serics *p++ = c; 6961500Serics if (c == '\t') 6971500Serics if (hardtabs && column < promptlen && !hard) { 6981500Serics if (eraseln && !dumb) { 6991500Serics column = 1 + (column | 7); 7001500Serics tputs (eraseln, 1, putch); 7011500Serics promptlen = 0; 7021500Serics } 7031500Serics else { 7041500Serics for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 7051500Serics *p++ = ' '; 7061500Serics } 7071500Serics if (column >= promptlen) promptlen = 0; 7081500Serics } 7091500Serics } 7101500Serics else 7111500Serics column = 1 + (column | 7); 7129627Ssklower else if (c == '\b' && column > 0) 7131500Serics column--; 7141500Serics else if (c == '\r') 7151500Serics column = 0; 7161500Serics else if (c == '\f' && stop_opt) { 7171500Serics p[-1] = '^'; 7181500Serics *p++ = 'L'; 7191500Serics column += 2; 7201500Serics Pause++; 7211500Serics } 7221500Serics else if (c == EOF) { 7231500Serics *length = p - Line; 7241500Serics return (column); 7251500Serics } 7261500Serics else if (c >= ' ' && c != RUBOUT) 7271500Serics column++; 7281500Serics if (column >= Mcol && fold_opt) break; 7291500Serics c = Getc (f); 7301500Serics } 7311500Serics if (column >= Mcol && Mcol > 0) { 7321500Serics if (!Wrap) { 7331500Serics *p++ = '\n'; 7341500Serics } 7351500Serics } 7361500Serics colflg = column == Mcol && fold_opt; 7371500Serics *length = p - Line; 7381500Serics *p = 0; 7391500Serics return (column); 7401500Serics } 7411500Serics 7421500Serics /* 7431500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 7441500Serics */ 7451500Serics 7461500Serics erase (col) 7471500Serics register int col; 7481500Serics { 7491500Serics 7501500Serics if (promptlen == 0) 7511500Serics return; 7521500Serics if (hard) { 7531500Serics putchar ('\n'); 7541500Serics } 7551500Serics else { 7561500Serics if (col == 0) 7571500Serics putchar ('\r'); 7581500Serics if (!dumb && eraseln) 7591500Serics tputs (eraseln, 1, putch); 7601500Serics else 7611500Serics for (col = promptlen - col; col > 0; col--) 7621500Serics putchar (' '); 7631500Serics } 7641500Serics promptlen = 0; 7651500Serics } 7661500Serics 7671500Serics /* 7681500Serics ** Erase the current line entirely 7691500Serics */ 7701500Serics 7711500Serics kill_line () 7721500Serics { 7731500Serics erase (0); 7741500Serics if (!eraseln || dumb) putchar ('\r'); 7751500Serics } 7761500Serics 7771500Serics /* 7783455Sroot * force clear to end of line 7793455Sroot */ 7803455Sroot cleareol() 7813455Sroot { 7823594Sroot tputs(eraseln, 1, putch); 7833455Sroot } 7843455Sroot 7853594Sroot clreos() 7863455Sroot { 7873594Sroot tputs(EodClr, 1, putch); 7883455Sroot } 7893455Sroot 7903455Sroot /* 7911500Serics ** Print string and return number of characters 7921500Serics */ 7931500Serics 7941500Serics pr(s1) 7951500Serics char *s1; 7961500Serics { 7971500Serics register char *s; 7981500Serics register char c; 7991500Serics 8001500Serics for (s = s1; c = *s++; ) 8011500Serics putchar(c); 8021500Serics return (s - s1 - 1); 8031500Serics } 8041500Serics 8051500Serics 8061500Serics /* Print a buffer of n characters */ 8071500Serics 8081500Serics prbuf (s, n) 8091500Serics register char *s; 8101500Serics register int n; 8111500Serics { 812*16710Sjak register char c; /* next output character */ 8133594Sroot register int state; /* next output char's UL state */ 814*16710Sjak #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 8153594Sroot 8163594Sroot while (--n >= 0) 8173594Sroot if (!ul_opt) 8183594Sroot putchar (*s++); 8193594Sroot else { 820*16710Sjak if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 821*16710Sjak s++; 822*16710Sjak continue; 823*16710Sjak } 824*16710Sjak if (state = wouldul(s, n)) { 825*16710Sjak c = (*s == '_')? s[2] : *s ; 8263594Sroot n -= 2; 827*16710Sjak s += 3; 828*16710Sjak } else 8293594Sroot c = *s++; 830*16710Sjak if (state != pstate) { 831*16710Sjak if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 832*16710Sjak state = 1; 833*16710Sjak else 834*16710Sjak tputs(state ? ULenter : ULexit, 1, putch); 8353594Sroot } 836*16710Sjak if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 837*16710Sjak putchar(c); 8383594Sroot if (state && *chUL) { 8393594Sroot pr(chBS); 8403594Sroot tputs(chUL, 1, putch); 8413594Sroot } 842*16710Sjak pstate = state; 8433594Sroot } 8441500Serics } 8451500Serics 8461500Serics /* 8471500Serics ** Clear the screen 8481500Serics */ 8491500Serics 8501500Serics doclear() 8511500Serics { 8521500Serics if (Clear && !hard) { 8531500Serics tputs(Clear, 1, putch); 8541500Serics 8551500Serics /* Put out carriage return so that system doesn't 8561500Serics ** get confused by escape sequences when expanding tabs 8571500Serics */ 8581500Serics putchar ('\r'); 8591500Serics promptlen = 0; 8601500Serics } 8611500Serics } 8621500Serics 8633455Sroot /* 8643455Sroot * Go to home position 8653455Sroot */ 8663455Sroot home() 8673455Sroot { 8683455Sroot tputs(Home,1,putch); 8693455Sroot } 8703455Sroot 8711500Serics static int lastcmd, lastarg, lastp; 8721500Serics static int lastcolon; 8731500Serics char shell_line[132]; 8741500Serics 8751500Serics /* 8761500Serics ** Read a command and do it. A command consists of an optional integer 8771500Serics ** argument followed by the command character. Return the number of lines 8781500Serics ** to display in the next screenful. If there is nothing more to display 8791500Serics ** in the current file, zero is returned. 8801500Serics */ 8811500Serics 8821500Serics command (filename, f) 8831500Serics char *filename; 8841500Serics register FILE *f; 8851500Serics { 8861500Serics register int nlines; 8871500Serics register int retval; 8881500Serics register char c; 8891500Serics char colonch; 8901500Serics FILE *helpf; 8911500Serics int done; 8921500Serics char comchar, cmdbuf[80], *p; 8931500Serics 8941500Serics #define ret(val) retval=val;done++;break 8951500Serics 8961500Serics done = 0; 8971500Serics if (!errors) 8981500Serics prompt (filename); 8991500Serics else 9001500Serics errors = 0; 9011500Serics if (MBIT == RAW && slow_tty) { 9021500Serics otty.sg_flags |= MBIT; 90316582Sleres stty(fileno(stderr), &otty); 9041500Serics } 9051500Serics for (;;) { 9061500Serics nlines = number (&comchar); 9071500Serics lastp = colonch = 0; 9081500Serics if (comchar == '.') { /* Repeat last command */ 9091500Serics lastp++; 9101500Serics comchar = lastcmd; 9111500Serics nlines = lastarg; 9121500Serics if (lastcmd == ':') 9131500Serics colonch = lastcolon; 9141500Serics } 9151500Serics lastcmd = comchar; 9161500Serics lastarg = nlines; 9171500Serics if (comchar == otty.sg_erase) { 9181500Serics kill_line (); 9191500Serics prompt (filename); 9201500Serics continue; 9211500Serics } 9221500Serics switch (comchar) { 9231500Serics case ':': 9241500Serics retval = colon (filename, colonch, nlines); 9251500Serics if (retval >= 0) 9261500Serics done++; 9271500Serics break; 9281500Serics case ' ': 9291500Serics case 'z': 9301500Serics if (nlines == 0) nlines = dlines; 9311500Serics else if (comchar == 'z') dlines = nlines; 9321500Serics ret (nlines); 9331500Serics case 'd': 9341500Serics case ctrl(D): 9351500Serics if (nlines != 0) nscroll = nlines; 9361500Serics ret (nscroll); 9371500Serics case RUBOUT: 9381500Serics case 'q': 9391500Serics case 'Q': 9401500Serics end_it (); 9411500Serics case 's': 9421500Serics case 'f': 9431500Serics if (nlines == 0) nlines++; 9441500Serics if (comchar == 'f') 9451500Serics nlines *= dlines; 9461500Serics putchar ('\r'); 9471500Serics erase (0); 9483594Sroot printf ("\n"); 9493594Sroot if (clreol) 9503594Sroot cleareol (); 9513594Sroot printf ("...skipping %d line", nlines); 9521500Serics if (nlines > 1) 9533594Sroot pr ("s\n"); 9541500Serics else 9553594Sroot pr ("\n"); 9563594Sroot 9573594Sroot if (clreol) 9583594Sroot cleareol (); 9593594Sroot pr ("\n"); 9603594Sroot 9611500Serics while (nlines > 0) { 9621500Serics while ((c = Getc (f)) != '\n') 9631500Serics if (c == EOF) { 9641500Serics retval = 0; 9651500Serics done++; 9661500Serics goto endsw; 9671500Serics } 9681500Serics Currline++; 9691500Serics nlines--; 9701500Serics } 9711500Serics ret (dlines); 9721500Serics case '\n': 9731500Serics if (nlines != 0) 9741500Serics dlines = nlines; 9751500Serics else 9761500Serics nlines = 1; 9771500Serics ret (nlines); 9781500Serics case '\f': 9791500Serics if (!no_intty) { 9801500Serics doclear (); 9811500Serics Fseek (f, screen_start.chrctr); 9821500Serics Currline = screen_start.line; 9831500Serics ret (dlines); 9841500Serics } 9851500Serics else { 9861500Serics write (2, &bell, 1); 9871500Serics break; 9881500Serics } 9891500Serics case '\'': 9901500Serics if (!no_intty) { 9911500Serics kill_line (); 9921500Serics pr ("\n***Back***\n\n"); 9931500Serics Fseek (f, context.chrctr); 9941500Serics Currline = context.line; 9951500Serics ret (dlines); 9961500Serics } 9971500Serics else { 9981500Serics write (2, &bell, 1); 9991500Serics break; 10001500Serics } 10011500Serics case '=': 10021500Serics kill_line (); 10031500Serics promptlen = printd (Currline); 10041500Serics fflush (stdout); 10051500Serics break; 10061500Serics case 'n': 10071500Serics lastp++; 10081500Serics case '/': 10091500Serics if (nlines == 0) nlines++; 10101500Serics kill_line (); 10111500Serics pr ("/"); 10121500Serics promptlen = 1; 10131500Serics fflush (stdout); 10141500Serics if (lastp) { 10151500Serics write (2,"\r", 1); 10161500Serics search (NULL, f, nlines); /* Use previous r.e. */ 10171500Serics } 10181500Serics else { 10191500Serics ttyin (cmdbuf, 78, '/'); 10201500Serics write (2, "\r", 1); 10211500Serics search (cmdbuf, f, nlines); 10221500Serics } 10233455Sroot ret (dlines-1); 10241500Serics case '!': 10251500Serics do_shell (filename); 10261500Serics break; 10271500Serics case 'h': 10281500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 10291500Serics error ("Can't open help file"); 10301500Serics if (noscroll) doclear (); 10311500Serics copy_file (helpf); 10321500Serics close (helpf); 10331500Serics prompt (filename); 10341500Serics break; 10351500Serics case 'v': /* This case should go right before default */ 10361500Serics if (!no_intty) { 10371500Serics kill_line (); 10381500Serics cmdbuf[0] = '+'; 10391500Serics scanstr (Currline, &cmdbuf[1]); 10401500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 10411500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 10421500Serics break; 10431500Serics } 10441500Serics default: 1045*16710Sjak if (dum_opt) { 1046*16710Sjak kill_line (); 1047*16710Sjak if (Senter && Sexit) { 1048*16710Sjak tputs (Senter, 1, putch); 1049*16710Sjak promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 1050*16710Sjak tputs (Sexit, 1, putch); 1051*16710Sjak } 1052*16710Sjak else 1053*16710Sjak promptlen = pr ("[Press 'h' for instructions.]"); 1054*16710Sjak fflush (stdout); 1055*16710Sjak } 1056*16710Sjak else 1057*16710Sjak write (2, &bell, 1); 10581500Serics break; 10591500Serics } 10601500Serics if (done) break; 10611500Serics } 10621500Serics putchar ('\r'); 10631500Serics endsw: 10641500Serics inwait = 0; 10651500Serics notell++; 10661500Serics if (MBIT == RAW && slow_tty) { 10671500Serics otty.sg_flags &= ~MBIT; 106816582Sleres stty(fileno(stderr), &otty); 10691500Serics } 10701500Serics return (retval); 10711500Serics } 10721500Serics 10731500Serics char ch; 10741500Serics 10751500Serics /* 10761500Serics * Execute a colon-prefixed command. 10771500Serics * Returns <0 if not a command that should cause 10781500Serics * more of the file to be printed. 10791500Serics */ 10801500Serics 10811500Serics colon (filename, cmd, nlines) 10821500Serics char *filename; 10831500Serics int cmd; 10841500Serics int nlines; 10851500Serics { 10861500Serics if (cmd == 0) 10871500Serics ch = readch (); 10881500Serics else 10891500Serics ch = cmd; 10901500Serics lastcolon = ch; 10911500Serics switch (ch) { 10921500Serics case 'f': 10931500Serics kill_line (); 10941500Serics if (!no_intty) 10951500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 10961500Serics else 10971500Serics promptlen = printf ("[Not a file] line %d", Currline); 10981500Serics fflush (stdout); 10991500Serics return (-1); 11001500Serics case 'n': 11011500Serics if (nlines == 0) { 11021500Serics if (fnum >= nfiles - 1) 11031500Serics end_it (); 11041500Serics nlines++; 11051500Serics } 11061500Serics putchar ('\r'); 11071500Serics erase (0); 11081500Serics skipf (nlines); 11091500Serics return (0); 11101500Serics case 'p': 11111500Serics if (no_intty) { 11121500Serics write (2, &bell, 1); 11131500Serics return (-1); 11141500Serics } 11151500Serics putchar ('\r'); 11161500Serics erase (0); 11171500Serics if (nlines == 0) 11181500Serics nlines++; 11191500Serics skipf (-nlines); 11201500Serics return (0); 11211500Serics case '!': 11221500Serics do_shell (filename); 11231500Serics return (-1); 11241500Serics case 'q': 11251500Serics case 'Q': 11261500Serics end_it (); 11271500Serics default: 11281500Serics write (2, &bell, 1); 11291500Serics return (-1); 11301500Serics } 11311500Serics } 11321500Serics 11331500Serics /* 11341500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 11351500Serics ** terminates the number. 11361500Serics */ 11371500Serics 11381500Serics number(cmd) 11391500Serics char *cmd; 11401500Serics { 11411500Serics register int i; 11421500Serics 11431500Serics i = 0; ch = otty.sg_kill; 11441500Serics for (;;) { 11451500Serics ch = readch (); 11461500Serics if (ch >= '0' && ch <= '9') 11471500Serics i = i*10 + ch - '0'; 11481500Serics else if (ch == otty.sg_kill) 11491500Serics i = 0; 11501500Serics else { 11511500Serics *cmd = ch; 11521500Serics break; 11531500Serics } 11541500Serics } 11551500Serics return (i); 11561500Serics } 11571500Serics 11581500Serics do_shell (filename) 11591500Serics char *filename; 11601500Serics { 11611500Serics char cmdbuf[80]; 11621500Serics 11631500Serics kill_line (); 11641500Serics pr ("!"); 11651500Serics fflush (stdout); 11661500Serics promptlen = 1; 11671500Serics if (lastp) 11681500Serics pr (shell_line); 11691500Serics else { 11701500Serics ttyin (cmdbuf, 78, '!'); 11711500Serics if (expand (shell_line, cmdbuf)) { 11721500Serics kill_line (); 11731500Serics promptlen = printf ("!%s", shell_line); 11741500Serics } 11751500Serics } 11761500Serics fflush (stdout); 11771500Serics write (2, "\n", 1); 11781500Serics promptlen = 0; 11791500Serics shellp = 1; 11801500Serics execute (filename, shell, shell, "-c", shell_line, 0); 11811500Serics } 11821500Serics 11831500Serics /* 11841500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 11851500Serics */ 11861500Serics 11871500Serics search (buf, file, n) 11881500Serics char buf[]; 11891500Serics FILE *file; 11901500Serics register int n; 11911500Serics { 11921500Serics long startline = Ftell (file); 11931500Serics register long line1 = startline; 11941500Serics register long line2 = startline; 11951500Serics register long line3 = startline; 11961500Serics register int lncount; 11971500Serics int saveln, rv, re_exec(); 11981500Serics char *s, *re_comp(); 11991500Serics 12001500Serics context.line = saveln = Currline; 12011500Serics context.chrctr = startline; 12021500Serics lncount = 0; 12031500Serics if ((s = re_comp (buf)) != 0) 12041500Serics error (s); 12051500Serics while (!feof (file)) { 12061500Serics line3 = line2; 12071500Serics line2 = line1; 12081500Serics line1 = Ftell (file); 12091500Serics rdline (file); 12101500Serics lncount++; 12111500Serics if ((rv = re_exec (Line)) == 1) 12121500Serics if (--n == 0) { 12131500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 12143455Sroot { 12153455Sroot pr ("\n"); 12163594Sroot if (clreol) 12173594Sroot cleareol (); 12183455Sroot pr("...skipping\n"); 12193455Sroot } 12201500Serics if (!no_intty) { 12211500Serics Currline -= (lncount >= 3 ? 3 : lncount); 12221500Serics Fseek (file, line3); 12233594Sroot if (noscroll) 12243594Sroot if (clreol) { 12253594Sroot home (); 12263594Sroot cleareol (); 122716582Sleres } 12283594Sroot else 12293594Sroot doclear (); 12301500Serics } 12311500Serics else { 12321500Serics kill_line (); 12333594Sroot if (noscroll) 12343594Sroot if (clreol) { 123516582Sleres home (); 12363594Sroot cleareol (); 123716582Sleres } 12383594Sroot else 12393594Sroot doclear (); 12401500Serics pr (Line); 12411500Serics putchar ('\n'); 12421500Serics } 12431500Serics break; 12441500Serics } 12451500Serics else if (rv == -1) 12461500Serics error ("Regular expression botch"); 12471500Serics } 12481500Serics if (feof (file)) { 12491500Serics if (!no_intty) { 12501500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 12511500Serics Currline = saveln; 12521500Serics Fseek (file, startline); 12531500Serics } 12541500Serics else { 12551500Serics pr ("\nPattern not found\n"); 12561500Serics end_it (); 12571500Serics } 12581500Serics error ("Pattern not found"); 12591500Serics } 12601500Serics } 12611500Serics 12621500Serics execute (filename, cmd, args) 12631500Serics char *filename; 12641500Serics char *cmd, *args; 12651500Serics { 12661500Serics int id; 1267*16710Sjak int n; 12681500Serics 12691500Serics fflush (stdout); 12701500Serics reset_tty (); 1271*16710Sjak for (n = 10; (id = fork ()) < 0 && n > 0; n--) 12721500Serics sleep (5); 12731500Serics if (id == 0) { 1274*16710Sjak if (!isatty(0)) { 1275*16710Sjak close(0); 1276*16710Sjak open("/dev/tty", 0); 1277*16710Sjak } 12781500Serics execv (cmd, &args); 12791500Serics write (2, "exec failed\n", 12); 12801500Serics exit (1); 12811500Serics } 1282*16710Sjak if (id > 0) { 1283*16710Sjak signal (SIGINT, SIG_IGN); 1284*16710Sjak signal (SIGQUIT, SIG_IGN); 1285*16710Sjak if (catch_susp) 1286*16710Sjak signal(SIGTSTP, SIG_DFL); 1287*16710Sjak while (wait(0) > 0); 1288*16710Sjak signal (SIGINT, end_it); 1289*16710Sjak signal (SIGQUIT, onquit); 1290*16710Sjak if (catch_susp) 1291*16710Sjak signal(SIGTSTP, onsusp); 1292*16710Sjak } else 1293*16710Sjak write(2, "can't fork\n", 11); 12941500Serics set_tty (); 12951500Serics pr ("------------------------\n"); 12961500Serics prompt (filename); 12971500Serics } 12981500Serics /* 12991500Serics ** Skip n lines in the file f 13001500Serics */ 13011500Serics 13021500Serics skiplns (n, f) 13031500Serics register int n; 13041500Serics register FILE *f; 13051500Serics { 13061500Serics register char c; 13071500Serics 13081500Serics while (n > 0) { 13091500Serics while ((c = Getc (f)) != '\n') 13101500Serics if (c == EOF) 13111500Serics return; 13121500Serics n--; 13131500Serics Currline++; 13141500Serics } 13151500Serics } 13161500Serics 13171500Serics /* 13181500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 13191500Serics ** negative. 13201500Serics */ 13211500Serics 13221500Serics skipf (nskip) 13231500Serics register int nskip; 13241500Serics { 13251500Serics if (nskip == 0) return; 13261500Serics if (nskip > 0) { 13271500Serics if (fnum + nskip > nfiles - 1) 13281500Serics nskip = nfiles - fnum - 1; 13291500Serics } 13301500Serics else if (within) 13311500Serics ++fnum; 13321500Serics fnum += nskip; 13331500Serics if (fnum < 0) 13341500Serics fnum = 0; 13353594Sroot pr ("\n...Skipping "); 13363455Sroot pr ("\n"); 13373594Sroot if (clreol) 13383594Sroot cleareol (); 13393455Sroot pr ("...Skipping "); 13401500Serics pr (nskip > 0 ? "to file " : "back to file "); 13411500Serics pr (fnames[fnum]); 13423455Sroot pr ("\n"); 13433594Sroot if (clreol) 13443594Sroot cleareol (); 13453455Sroot pr ("\n"); 13461500Serics --fnum; 13471500Serics } 13481500Serics 13491500Serics /*----------------------------- Terminal I/O -------------------------------*/ 13501500Serics 13511500Serics initterm () 13521500Serics { 13531500Serics char buf[TBUFSIZ]; 13541500Serics char clearbuf[100]; 13551500Serics char *clearptr, *padstr; 13561500Serics int ldisc; 135710823Ssam char *term; 135816582Sleres int tgrp; 13591500Serics 13601500Serics setbuf(stdout, obuf); 136116582Sleres retry: 136216582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 136316582Sleres /* 136416582Sleres * Wait until we're in the foreground before we get the 136516582Sleres * save the terminal modes. 136616582Sleres */ 136716582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 136816582Sleres perror("ioctl"); 136916582Sleres exit(1); 137016582Sleres } 137116582Sleres if (tgrp != getpgrp(0)) { 137216582Sleres kill(0, SIGTTOU); 137316582Sleres goto retry; 137416582Sleres } 137513830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 13763594Sroot dumb++; ul_opt = 0; 13771500Serics } 13781500Serics else { 13791500Serics if (((Lpp = tgetnum("li")) < 0) || tgetflag("hc")) { 13801500Serics hard++; /* Hard copy terminal */ 13811500Serics Lpp = 24; 13821500Serics } 13831500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 13841500Serics noscroll++; 13851500Serics if ((Mcol = tgetnum("co")) < 0) 13861500Serics Mcol = 80; 13871500Serics Wrap = tgetflag("am"); 13881500Serics bad_so = tgetflag ("xs"); 13891500Serics clearptr = clearbuf; 13901500Serics eraseln = tgetstr("ce",&clearptr); 13911500Serics Clear = tgetstr("cl", &clearptr); 13921500Serics Senter = tgetstr("so", &clearptr); 13931500Serics Sexit = tgetstr("se", &clearptr); 1394*16710Sjak if ((soglitch = tgetnum("sg")) < 0) 1395*16710Sjak soglitch = 0; 13963594Sroot 13973594Sroot /* 13983594Sroot * Set up for underlining: some terminals don't need it; 13993594Sroot * others have start/stop sequences, still others have an 14003594Sroot * underline char sequence which is assumed to move the 14013594Sroot * cursor forward one character. If underline sequence 14023594Sroot * isn't available, settle for standout sequence. 14033594Sroot */ 14043594Sroot 14053594Sroot if (tgetflag("ul") || tgetflag("os")) 14063594Sroot ul_opt = 0; 14073594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 14083594Sroot chUL = ""; 1409*16710Sjak if (((ULenter = tgetstr("us", &clearptr)) == NULL || 1410*16710Sjak (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 1411*16710Sjak if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 1412*16710Sjak ULenter = ""; 1413*16710Sjak ULexit = ""; 1414*16710Sjak } else 1415*16710Sjak ulglitch = soglitch; 1416*16710Sjak } else { 1417*16710Sjak if ((ulglitch = tgetnum("ug")) < 0) 1418*16710Sjak ulglitch = 0; 1419*16710Sjak } 142016582Sleres 14211500Serics if (padstr = tgetstr("pc", &clearptr)) 14221500Serics PC = *padstr; 14233455Sroot Home = tgetstr("ho",&clearptr); 142413536Ssam if (Home == 0 || *Home == '\0') 14253455Sroot { 14263594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 14273594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 14283455Sroot Home = cursorhome; 14293455Sroot } 14303455Sroot } 14313594Sroot EodClr = tgetstr("cd", &clearptr); 14321500Serics } 14331500Serics if ((shell = getenv("SHELL")) == NULL) 14341500Serics shell = "/bin/sh"; 14351500Serics } 143616582Sleres no_intty = gtty(fileno(stdin), &otty); 143716582Sleres gtty(fileno(stderr), &otty); 143813830Skre savetty = otty; 14391500Serics ospeed = otty.sg_ospeed; 14401500Serics slow_tty = ospeed < B1200; 14411500Serics hardtabs = !(otty.sg_flags & XTABS); 14421500Serics if (!no_tty) { 14431500Serics otty.sg_flags &= ~ECHO; 14441500Serics if (MBIT == CBREAK || !slow_tty) 14451500Serics otty.sg_flags |= MBIT; 14461500Serics } 14471500Serics } 14481500Serics 14491500Serics readch () 14501500Serics { 14511500Serics char ch; 14521500Serics extern int errno; 14531500Serics 14541500Serics if (read (2, &ch, 1) <= 0) 14551500Serics if (errno != EINTR) 14561500Serics exit(0); 14571500Serics else 14581500Serics ch = otty.sg_kill; 14591500Serics return (ch); 14601500Serics } 14611500Serics 14621500Serics static char BS = '\b'; 14631500Serics static char CARAT = '^'; 14641500Serics 14651500Serics ttyin (buf, nmax, pchar) 14661500Serics char buf[]; 14671500Serics register int nmax; 14681500Serics char pchar; 14691500Serics { 14701500Serics register char *sptr; 14711500Serics register char ch; 14721500Serics register int slash = 0; 14731500Serics int maxlen; 14741500Serics char cbuf; 14751500Serics 14761500Serics sptr = buf; 14771500Serics maxlen = 0; 14781500Serics while (sptr - buf < nmax) { 14791500Serics if (promptlen > maxlen) maxlen = promptlen; 14801500Serics ch = readch (); 14811500Serics if (ch == '\\') { 14821500Serics slash++; 14831500Serics } 14841500Serics else if ((ch == otty.sg_erase) && !slash) { 14851500Serics if (sptr > buf) { 14861500Serics --promptlen; 14871500Serics write (2, &BS, 1); 14881500Serics --sptr; 14891500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 14901500Serics --promptlen; 14911500Serics write (2, &BS, 1); 14921500Serics } 14931500Serics continue; 14941500Serics } 14951500Serics else { 14961500Serics if (!eraseln) promptlen = maxlen; 14971500Serics longjmp (restore, 1); 14981500Serics } 14991500Serics } 15001500Serics else if ((ch == otty.sg_kill) && !slash) { 15011500Serics if (hard) { 15021500Serics show (ch); 15031500Serics putchar ('\n'); 15041500Serics putchar (pchar); 15051500Serics } 15061500Serics else { 15071500Serics putchar ('\r'); 15081500Serics putchar (pchar); 15091500Serics if (eraseln) 15101500Serics erase (1); 15111500Serics promptlen = 1; 15121500Serics } 15131500Serics sptr = buf; 15141500Serics fflush (stdout); 15151500Serics continue; 15161500Serics } 15171500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 15181500Serics write (2, &BS, 1); 15191500Serics --sptr; 15201500Serics } 15211500Serics if (ch != '\\') 15221500Serics slash = 0; 15231500Serics *sptr++ = ch; 15241500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 15251500Serics ch += ch == RUBOUT ? -0100 : 0100; 15261500Serics write (2, &CARAT, 1); 15271500Serics promptlen++; 15281500Serics } 15291500Serics cbuf = ch; 15301500Serics if (ch != '\n' && ch != ESC) { 15311500Serics write (2, &cbuf, 1); 15321500Serics promptlen++; 15331500Serics } 15341500Serics else 15351500Serics break; 15361500Serics } 15371500Serics *--sptr = '\0'; 15381500Serics if (!eraseln) promptlen = maxlen; 15391500Serics if (sptr - buf >= nmax - 1) 15401500Serics error ("Line too long"); 15411500Serics } 15421500Serics 15431500Serics expand (outbuf, inbuf) 15441500Serics char *outbuf; 15451500Serics char *inbuf; 15461500Serics { 15471500Serics register char *instr; 15481500Serics register char *outstr; 15491500Serics register char ch; 15501500Serics char temp[200]; 15511500Serics int changed = 0; 15521500Serics 15531500Serics instr = inbuf; 15541500Serics outstr = temp; 15551500Serics while ((ch = *instr++) != '\0') 15561500Serics switch (ch) { 15571500Serics case '%': 15581500Serics if (!no_intty) { 15591500Serics strcpy (outstr, fnames[fnum]); 15601500Serics outstr += strlen (fnames[fnum]); 15611500Serics changed++; 15621500Serics } 15631500Serics else 15641500Serics *outstr++ = ch; 15651500Serics break; 15661500Serics case '!': 15671500Serics if (!shellp) 15681500Serics error ("No previous command to substitute for"); 15691500Serics strcpy (outstr, shell_line); 15701500Serics outstr += strlen (shell_line); 15711500Serics changed++; 15721500Serics break; 15731500Serics case '\\': 15741500Serics if (*instr == '%' || *instr == '!') { 15751500Serics *outstr++ = *instr++; 15761500Serics break; 15771500Serics } 15781500Serics default: 15791500Serics *outstr++ = ch; 15801500Serics } 15811500Serics *outstr++ = '\0'; 15821500Serics strcpy (outbuf, temp); 15831500Serics return (changed); 15841500Serics } 15851500Serics 15861500Serics show (ch) 15871500Serics register char ch; 15881500Serics { 15891500Serics char cbuf; 15901500Serics 15911500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 15921500Serics ch += ch == RUBOUT ? -0100 : 0100; 15931500Serics write (2, &CARAT, 1); 15941500Serics promptlen++; 15951500Serics } 15961500Serics cbuf = ch; 15971500Serics write (2, &cbuf, 1); 15981500Serics promptlen++; 15991500Serics } 16001500Serics 16011500Serics error (mess) 16021500Serics char *mess; 16031500Serics { 16043594Sroot if (clreol) 16053594Sroot cleareol (); 16063594Sroot else 16073594Sroot kill_line (); 16081500Serics promptlen += strlen (mess); 16091500Serics if (Senter && Sexit) { 16101500Serics tputs (Senter, 1, putch); 16111500Serics pr(mess); 16121500Serics tputs (Sexit, 1, putch); 16131500Serics } 16141500Serics else 16151500Serics pr (mess); 16161500Serics fflush(stdout); 16171500Serics errors++; 16181500Serics longjmp (restore, 1); 16191500Serics } 16201500Serics 16211500Serics 16221500Serics set_tty () 16231500Serics { 16241500Serics otty.sg_flags |= MBIT; 16251500Serics otty.sg_flags &= ~ECHO; 162616582Sleres stty(fileno(stderr), &otty); 16271500Serics } 16281500Serics 16291500Serics reset_tty () 16301500Serics { 1631*16710Sjak if (pstate) { 1632*16710Sjak tputs(ULexit, 1, putch); 1633*16710Sjak fflush(stdout); 1634*16710Sjak pstate = 0; 1635*16710Sjak } 16361500Serics otty.sg_flags |= ECHO; 16371500Serics otty.sg_flags &= ~MBIT; 163816582Sleres stty(fileno(stderr), &savetty); 16391500Serics } 16401500Serics 16411500Serics rdline (f) 16421500Serics register FILE *f; 16431500Serics { 16441500Serics register char c; 16451500Serics register char *p; 16461500Serics 16471500Serics p = Line; 16481500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 16491500Serics *p++ = c; 16501500Serics if (c == '\n') 16511500Serics Currline++; 16521500Serics *p = '\0'; 16531500Serics } 16541500Serics 16551500Serics /* Come here when we get a suspend signal from the terminal */ 16561500Serics 16571500Serics onsusp () 16581500Serics { 165914861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 166014861Skarels signal(SIGTTOU, SIG_IGN); 16611500Serics reset_tty (); 16621500Serics fflush (stdout); 166314861Skarels signal(SIGTTOU, SIG_DFL); 16641500Serics /* Send the TSTP signal to suspend our process group */ 166513289Ssam signal(SIGTSTP, SIG_DFL); 166613289Ssam sigsetmask(0); 16671500Serics kill (0, SIGTSTP); 16681500Serics /* Pause for station break */ 16691500Serics 16701500Serics /* We're back */ 16711500Serics signal (SIGTSTP, onsusp); 16721500Serics set_tty (); 16731500Serics if (inwait) 16741500Serics longjmp (restore); 16751500Serics } 1676