1*9627Ssklower static char *sccsid = "@(#)more.c 4.7 (Berkeley) 82/12/14"; 23594Sroot 31500Serics /* 41500Serics ** more.c - General purpose tty output filter and file perusal program 51500Serics ** 61500Serics ** by Eric Shienbrood, UC Berkeley 73594Sroot ** 83594Sroot ** modified by Geoff Peck, UCB to add underlining, single spacing 93594Sroot ** modified by John Foderaro, UCB to add -c and MORE environment variable 101500Serics */ 111500Serics 121500Serics #include <stdio.h> 131500Serics #include <ctype.h> 141500Serics #include <signal.h> 151500Serics #include <errno.h> 161500Serics #include <sgtty.h> 171500Serics #include <setjmp.h> 181500Serics #include <sys/types.h> 191500Serics #include <sys/stat.h> 201500Serics #include <local/uparm.h> 211500Serics 221500Serics /* Help file will eventually go in libpath(more.help) on all systems */ 231500Serics 241500Serics #define HELPFILE libpath(more.help) 251500Serics #define VI binpath(vi) 261500Serics 271500Serics #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) 281500Serics #define Ftell(f) file_pos 291500Serics #define Fseek(f,off) (file_pos=off,fseek(f,off,0)) 301500Serics #define Getc(f) (++file_pos, getc(f)) 311500Serics #define Ungetc(c,f) (--file_pos, ungetc(c,f)) 321500Serics 331500Serics #define MBIT CBREAK 341500Serics #define stty(fd,argp) ioctl(fd,TIOCSETN,argp) 351500Serics 361500Serics #define TBUFSIZ 1024 371500Serics #define LINSIZ 256 381500Serics #define ctrl(letter) ('letter' & 077) 391500Serics #define RUBOUT '\177' 401500Serics #define ESC '\033' 411500Serics #define QUIT '\034' 421500Serics 431500Serics struct sgttyb otty; 441500Serics long file_pos, file_size; 451500Serics int fnum, no_intty, no_tty, slow_tty; 461500Serics int dum_opt, dlines, onquit(), end_it(); 471500Serics int onsusp(); 481500Serics int nscroll = 11; /* Number of lines scrolled by 'd' */ 491500Serics int fold_opt = 1; /* Fold long lines */ 501500Serics int stop_opt = 1; /* Stop after form feeds */ 513594Sroot int ssp_opt = 0; /* Suppress white space */ 523594Sroot int ul_opt = 1; /* Underline as best we can */ 531500Serics int promptlen; 541500Serics int Currline; /* Line we are currently at */ 551500Serics int startup = 1; 561500Serics int firstf = 1; 571500Serics int notell = 1; 581500Serics int bad_so; /* True if overwriting does not turn off standout */ 591500Serics int inwait, Pause, errors; 601500Serics int within; /* true if we are within a file, 611500Serics false if we are between files */ 623594Sroot int hard, dumb, noscroll, hardtabs, clreol; 631500Serics int catch_susp; /* We should catch the SIGTSTP signal */ 641500Serics char **fnames; /* The list of file names */ 651500Serics int nfiles; /* Number of files left to process */ 661500Serics char *shell; /* The name of the shell to use */ 671500Serics int shellp; /* A previous shell command exists */ 681500Serics char ch; 691500Serics jmp_buf restore; 701500Serics char obuf[BUFSIZ]; /* stdout buffer */ 711500Serics char Line[LINSIZ]; /* Line buffer */ 721500Serics int Lpp = 24; /* lines per page */ 731500Serics char *Clear; /* clear screen */ 741500Serics char *eraseln; /* erase line */ 751500Serics char *Senter, *Sexit;/* enter and exit standout mode */ 763594Sroot char *ULenter, *ULexit; /* enter and exit underline mode */ 773594Sroot char *chUL; /* underline character */ 783594Sroot char *chBS; /* backspace character */ 793455Sroot char *Home; /* go to home */ 803455Sroot char *cursorm; /* cursor movement */ 813455Sroot char cursorhome[40]; /* contains cursor movement to home */ 823594Sroot char *EodClr; /* clear rest of screen */ 831500Serics char *tgetstr(); 841500Serics int Mcol = 80; /* number of columns */ 851500Serics int Wrap = 1; /* set if automargins */ 861500Serics long fseek(); 873455Sroot char *getenv(); 881500Serics struct { 891500Serics long chrctr, line; 901500Serics } context, screen_start; 911500Serics extern char PC; /* pad character */ 921500Serics extern short ospeed; 931500Serics 941500Serics 951500Serics main(argc, argv) 961500Serics int argc; 971500Serics char *argv[]; 981500Serics { 991500Serics register FILE *f; 1001500Serics register char *s; 1011500Serics register char *p; 1021500Serics register char ch; 1031500Serics register int left; 1041500Serics int prnames = 0; 1051500Serics int initopt = 0; 1061500Serics int srchopt = 0; 1071500Serics int clearit = 0; 1081500Serics int initline; 1091500Serics char initbuf[80]; 1101500Serics FILE *checkf(); 1111500Serics 1121500Serics nfiles = argc; 1131500Serics fnames = argv; 1141500Serics initterm (); 1153455Sroot if(s = getenv("MORE")) argscan(s); 1161500Serics while (--nfiles > 0) { 1171500Serics if ((ch = (*++fnames)[0]) == '-') { 1183455Sroot argscan(*fnames+1); 1191500Serics } 1201500Serics else if (ch == '+') { 1211500Serics s = *fnames; 1221500Serics if (*++s == '/') { 1231500Serics srchopt++; 1241500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1251500Serics *p++ = *s++; 1261500Serics *p = '\0'; 1271500Serics } 1281500Serics else { 1291500Serics initopt++; 1301500Serics for (initline = 0; *s != '\0'; s++) 1311500Serics if (isdigit (*s)) 1321500Serics initline = initline*10 + *s -'0'; 1331500Serics --initline; 1341500Serics } 1351500Serics } 1361500Serics else break; 1371500Serics } 1383594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1393455Sroot * defined, and in that case, make sure we are in noscroll mode 1403455Sroot */ 1413455Sroot if(clreol) 1423455Sroot { 1433594Sroot if ((*Home == '\0') || (*eraseln == '\0') || (*EodClr == '\0')) 1443594Sroot clreol = 0; 1453455Sroot else noscroll = 1; 1463455Sroot } 1473455Sroot 1481500Serics if (dlines == 0) 1491500Serics dlines = Lpp - (noscroll ? 1 : 2); 1501500Serics left = dlines; 1511500Serics if (nfiles > 1) 1521500Serics prnames++; 1531500Serics if (!no_intty && nfiles == 0) { 1541500Serics fputs("Usage: ",stderr); 1551500Serics fputs(argv[0],stderr); 1561500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1571500Serics exit(1); 1581500Serics } 1591500Serics else 1601500Serics f = stdin; 1611500Serics if (!no_tty) { 1621500Serics signal(SIGQUIT, onquit); 1631500Serics signal(SIGINT, end_it); 1641500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1651500Serics signal(SIGTSTP, onsusp); 1661500Serics catch_susp++; 1671500Serics } 1681500Serics stty (2, &otty); 1691500Serics } 1701500Serics if (no_intty) { 1711500Serics if (no_tty) 1721500Serics copy_file (stdin); 1731500Serics else { 1741500Serics if ((ch = Getc (f)) == '\f') 1753594Sroot doclear(); 1761500Serics else { 1771500Serics Ungetc (ch, f); 1783594Sroot if (noscroll && (ch != EOF)) { 1793594Sroot if (clreol) 1803594Sroot home (); 1813594Sroot else 1823594Sroot doclear (); 1833455Sroot } 1841500Serics } 1851500Serics if (srchopt) 1863455Sroot { 1871500Serics search (initbuf, stdin, 1); 1883594Sroot if (noscroll) 1893594Sroot left--; 1903455Sroot } 1911500Serics else if (initopt) 1921500Serics skiplns (initline, stdin); 1931500Serics screen (stdin, left); 1941500Serics } 1951500Serics no_intty = 0; 1961500Serics prnames++; 1971500Serics firstf = 0; 1981500Serics } 1991500Serics 2001500Serics while (fnum < nfiles) { 2011500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2021500Serics context.line = context.chrctr = 0; 2031500Serics Currline = 0; 2041500Serics if (firstf) setjmp (restore); 2051500Serics if (firstf) { 2061500Serics firstf = 0; 2071500Serics if (srchopt) 2083455Sroot { 2091500Serics search (initbuf, f, 1); 2103594Sroot if (noscroll) 2113594Sroot left--; 2123455Sroot } 2131500Serics else if (initopt) 2141500Serics skiplns (initline, f); 2151500Serics } 2161500Serics else if (fnum < nfiles && !no_tty) { 2171500Serics setjmp (restore); 2181500Serics left = command (fnames[fnum], f); 2191500Serics } 2201500Serics if (left != 0) { 2213594Sroot if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 2223594Sroot if (clreol) 2233594Sroot home (); 2243594Sroot else 2253594Sroot doclear (); 2261500Serics if (prnames) { 2271500Serics if (bad_so) 2281500Serics erase (0); 2293594Sroot if (clreol) 2303594Sroot cleareol (); 2311500Serics pr("::::::::::::::"); 2321500Serics if (promptlen > 14) 2331500Serics erase (14); 2343455Sroot printf ("\n"); 2353455Sroot if(clreol) cleareol(); 2363455Sroot printf("%s\n", fnames[fnum]); 2373455Sroot if(clreol) cleareol(); 2383455Sroot printf("::::::::::::::\n", fnames[fnum]); 2391500Serics if (left > Lpp - 4) 2401500Serics left = Lpp - 4; 2411500Serics } 2421500Serics if (no_tty) 2431500Serics copy_file (f); 2441500Serics else { 2451500Serics within++; 2461500Serics screen(f, left); 2471500Serics within = 0; 2481500Serics } 2491500Serics } 2501500Serics setjmp (restore); 2511500Serics fflush(stdout); 2521500Serics fclose(f); 2531500Serics screen_start.line = screen_start.chrctr = 0L; 2541500Serics context.line = context.chrctr = 0L; 2551500Serics } 2561500Serics fnum++; 2571500Serics firstf = 0; 2581500Serics } 2591500Serics reset_tty (); 2601500Serics exit(0); 2611500Serics } 2621500Serics 2633455Sroot argscan(s) 2643455Sroot char *s; 2653455Sroot { 2663455Sroot for (dlines = 0; *s != '\0'; s++) 2673455Sroot if (isdigit(*s)) 2683455Sroot dlines = dlines*10 + *s - '0'; 2693455Sroot else if (*s == 'd') 2703455Sroot dum_opt = 1; 2713455Sroot else if (*s == 'l') 2723455Sroot stop_opt = 0; 2733455Sroot else if (*s == 'f') 2743455Sroot fold_opt = 0; 2753455Sroot else if (*s == 'p') 2763455Sroot noscroll++; 2773455Sroot else if (*s == 'c') 2783455Sroot clreol++; 2793594Sroot else if (*s == 's') 2803594Sroot ssp_opt = 1; 2813594Sroot else if (*s == 'u') 2823594Sroot ul_opt = 0; 2833455Sroot } 2843455Sroot 2853455Sroot 2861500Serics /* 2871500Serics ** Check whether the file named by fs is an ASCII file which the user may 2881500Serics ** access. If it is, return the opened file. Otherwise return NULL. 2891500Serics */ 2901500Serics 2911500Serics FILE * 2921500Serics checkf (fs, clearfirst) 2931500Serics register char *fs; 2941500Serics int *clearfirst; 2951500Serics { 2961500Serics struct stat stbuf; 2971500Serics register FILE *f; 2981500Serics char c; 2991500Serics 3001500Serics if (stat (fs, &stbuf) == -1) { 3011500Serics fflush(stdout); 3023594Sroot if (clreol) 3033594Sroot cleareol (); 3041500Serics perror(fs); 3051500Serics return (NULL); 3061500Serics } 3071500Serics if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3081500Serics printf("\n*** %s: directory ***\n\n", fs); 3091500Serics return (NULL); 3101500Serics } 3111500Serics if ((f=Fopen(fs, "r")) == NULL) { 3121500Serics fflush(stdout); 3131500Serics perror(fs); 3141500Serics return (NULL); 3151500Serics } 3161500Serics c = Getc(f); 3171500Serics 3181500Serics /* Try to see whether it is an ASCII file */ 3191500Serics 3201500Serics switch ((c | *f->_ptr << 8) & 0177777) { 3211500Serics case 0405: 3221500Serics case 0407: 3231500Serics case 0410: 3241500Serics case 0411: 3251500Serics case 0413: 3261500Serics case 0177545: 3271500Serics printf("\n******** %s: Not a text file ********\n\n", fs); 3281500Serics fclose (f); 3291500Serics return (NULL); 3301500Serics default: 3311500Serics break; 3321500Serics } 3331500Serics if (c == '\f') 3341500Serics *clearfirst = 1; 3351500Serics else { 3361500Serics *clearfirst = 0; 3371500Serics Ungetc (c, f); 3381500Serics } 3391500Serics if ((file_size = stbuf.st_size) == 0) 3401500Serics file_size = 0x7fffffffffffffffL; 3411500Serics return (f); 3421500Serics } 3431500Serics 3441500Serics /* 3451500Serics ** A real function, for the tputs routine in termlib 3461500Serics */ 3471500Serics 3481500Serics putch (ch) 3491500Serics char ch; 3501500Serics { 3511500Serics putchar (ch); 3521500Serics } 3531500Serics 3541500Serics /* 3551500Serics ** Print out the contents of the file f, one screenful at a time. 3561500Serics */ 3571500Serics 3581500Serics #define STOP -10 3591500Serics 3601500Serics screen (f, num_lines) 3611500Serics register FILE *f; 3621500Serics register int num_lines; 3631500Serics { 3641500Serics register int c; 3651500Serics register int nchars; 3663594Sroot int length; /* length of current line */ 3673594Sroot static int prev_len = 1; /* length of previous line */ 3681500Serics 3691500Serics for (;;) { 3701500Serics while (num_lines > 0 && !Pause) { 3711500Serics if ((nchars = getline (f, &length)) == EOF) 3723455Sroot { 3733594Sroot if (clreol) 3743594Sroot clreos(); 3751500Serics return; 3763455Sroot } 3773594Sroot if (ssp_opt && length == 0 && prev_len == 0) 3783594Sroot continue; 3793594Sroot prev_len = length; 3801500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 3811500Serics erase (0); 3823594Sroot /* must clear before drawing line since tabs on some terminals 3833594Sroot * do not erase what they tab over. 3843594Sroot */ 3853594Sroot if (clreol) 3863594Sroot cleareol (); 3871500Serics prbuf (Line, length); 3881500Serics if (nchars < promptlen) 3891500Serics erase (nchars); /* erase () sets promptlen to 0 */ 3901500Serics else promptlen = 0; 3913594Sroot /* is this needed? 3923594Sroot * if (clreol) 3933594Sroot * cleareol(); /* must clear again in case we wrapped * 3943594Sroot */ 3951500Serics if (nchars < Mcol || !fold_opt) 3961500Serics putchar('\n'); 3971500Serics if (nchars == STOP) 3981500Serics break; 3991500Serics num_lines--; 4001500Serics } 4011500Serics fflush(stdout); 4021500Serics if ((c = Getc(f)) == EOF) 4033455Sroot { 4043594Sroot if (clreol) 4053594Sroot clreos (); 4061500Serics return; 4073455Sroot } 4083455Sroot 4093594Sroot if (Pause && clreol) 4103594Sroot clreos (); 4111500Serics Ungetc (c, f); 4121500Serics setjmp (restore); 4131500Serics Pause = 0; startup = 0; 4141500Serics if ((num_lines = command (NULL, f)) == 0) 4151500Serics return; 4161500Serics if (hard && promptlen > 0) 4171500Serics erase (0); 4181500Serics if (noscroll && num_lines == dlines) 4193455Sroot { 4203594Sroot if (clreol) 4213594Sroot home(); 4223594Sroot else 4233594Sroot doclear (); 4243455Sroot } 4251500Serics screen_start.line = Currline; 4261500Serics screen_start.chrctr = Ftell (f); 4271500Serics } 4281500Serics } 4291500Serics 4301500Serics /* 4311500Serics ** Come here if a quit signal is received 4321500Serics */ 4331500Serics 4341500Serics onquit() 4351500Serics { 4361500Serics signal(SIGQUIT, SIG_IGN); 4371500Serics if (!inwait) { 4381500Serics putchar ('\n'); 4391500Serics if (!startup) { 4401500Serics signal(SIGQUIT, onquit); 4411500Serics longjmp (restore, 1); 4421500Serics } 4431500Serics else 4441500Serics Pause++; 4451500Serics } 4461500Serics else if (!dum_opt && notell) { 4471500Serics write (2, "[Use q or Q to quit]", 20); 4481500Serics promptlen += 20; 4491500Serics notell = 0; 4501500Serics } 4511500Serics signal(SIGQUIT, onquit); 4521500Serics } 4531500Serics 4541500Serics /* 4551500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 4561500Serics */ 4571500Serics 4581500Serics end_it () 4591500Serics { 4601500Serics 4611500Serics reset_tty (); 4623594Sroot if (clreol) { 4633594Sroot putchar ('\r'); 4643594Sroot clreos (); 4653594Sroot fflush (stdout); 4663594Sroot } 4673455Sroot else if (!clreol && (promptlen > 0)) { 4681500Serics kill_line (); 4691500Serics fflush (stdout); 4701500Serics } 4711500Serics else 4721500Serics write (2, "\n", 1); 4731500Serics _exit(0); 4741500Serics } 4751500Serics 4761500Serics copy_file(f) 4771500Serics register FILE *f; 4781500Serics { 4791500Serics register int c; 4801500Serics 4811500Serics while ((c = getc(f)) != EOF) 4821500Serics putchar(c); 4831500Serics } 4841500Serics 4851500Serics /* Simplified printf function */ 4861500Serics 4871500Serics printf (fmt, args) 4881500Serics register char *fmt; 4891500Serics int args; 4901500Serics { 4911500Serics register int *argp; 4921500Serics register char ch; 4931500Serics register int ccount; 4941500Serics 4951500Serics ccount = 0; 4961500Serics argp = &args; 4971500Serics while (*fmt) { 4981500Serics while ((ch = *fmt++) != '%') { 4991500Serics if (ch == '\0') 5001500Serics return (ccount); 5011500Serics ccount++; 5021500Serics putchar (ch); 5031500Serics } 5041500Serics switch (*fmt++) { 5051500Serics case 'd': 5061500Serics ccount += printd (*argp); 5071500Serics break; 5081500Serics case 's': 5091500Serics ccount += pr ((char *)*argp); 5101500Serics break; 5111500Serics case '%': 5121500Serics ccount++; 5131500Serics argp--; 5141500Serics putchar ('%'); 5151500Serics break; 5161500Serics case '0': 5171500Serics return (ccount); 5181500Serics default: 5191500Serics break; 5201500Serics } 5211500Serics ++argp; 5221500Serics } 5231500Serics return (ccount); 5241500Serics 5251500Serics } 5261500Serics 5271500Serics /* 5281500Serics ** Print an integer as a string of decimal digits, 5291500Serics ** returning the length of the print representation. 5301500Serics */ 5311500Serics 5321500Serics printd (n) 5331500Serics int n; 5341500Serics { 5351500Serics int a, nchars; 5361500Serics 5371500Serics if (a = n/10) 5381500Serics nchars = 1 + printd(a); 5391500Serics else 5401500Serics nchars = 1; 5411500Serics putchar (n % 10 + '0'); 5421500Serics return (nchars); 5431500Serics } 5441500Serics 5451500Serics /* Put the print representation of an integer into a string */ 5461500Serics static char *sptr; 5471500Serics 5481500Serics scanstr (n, str) 5491500Serics int n; 5501500Serics char *str; 5511500Serics { 5521500Serics sptr = str; 5531500Serics sprintf (n); 5541500Serics *sptr = '\0'; 5551500Serics } 5561500Serics 5571500Serics sprintf (n) 5581500Serics { 5591500Serics int a; 5601500Serics 5611500Serics if (a = n/10) 5621500Serics sprintf (a); 5631500Serics *sptr++ = n % 10 + '0'; 5641500Serics } 5651500Serics 5661500Serics static char bell = ctrl(G); 5671500Serics 5681500Serics strlen (s) 5691500Serics char *s; 5701500Serics { 5711500Serics register char *p; 5721500Serics 5731500Serics p = s; 5741500Serics while (*p++) 5751500Serics ; 5761500Serics return (p - s - 1); 5771500Serics } 5781500Serics 5791500Serics /* See whether the last component of the path name "path" is equal to the 5801500Serics ** string "string" 5811500Serics */ 5821500Serics 5831500Serics tailequ (path, string) 5841500Serics char *path; 5851500Serics register char *string; 5861500Serics { 5871500Serics register char *tail; 5881500Serics 5891500Serics tail = path + strlen(path); 5901500Serics while (tail >= path) 5911500Serics if (*(--tail) == '/') 5921500Serics break; 5931500Serics ++tail; 5941500Serics while (*tail++ == *string++) 5951500Serics if (*tail == '\0') 5961500Serics return(1); 5971500Serics return(0); 5981500Serics } 5991500Serics 6001500Serics prompt (filename) 6011500Serics char *filename; 6021500Serics { 6033594Sroot if (clreol) 6043594Sroot cleareol (); 6053455Sroot else if (promptlen > 0) 6061500Serics kill_line (); 6071500Serics if (!hard) { 6081500Serics promptlen = 8; 6091500Serics if (Senter && Sexit) 6101500Serics tputs (Senter, 1, putch); 6113594Sroot if (clreol) 6123594Sroot cleareol (); 6131500Serics pr("--More--"); 6141500Serics if (filename != NULL) { 6151500Serics promptlen += printf ("(Next file: %s)", filename); 6161500Serics } 6171500Serics else if (!no_intty) { 6181500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 6191500Serics } 6201500Serics if (dum_opt) { 6211500Serics promptlen += pr("[Hit space to continue, Rubout to abort]"); 6221500Serics } 6231500Serics if (Senter && Sexit) 6241500Serics tputs (Sexit, 1, putch); 6253594Sroot if (clreol) 6263594Sroot clreos (); 6271500Serics fflush(stdout); 6281500Serics } 6291500Serics else 6301500Serics write (2, &bell, 1); 6311500Serics inwait++; 6321500Serics } 6331500Serics 6341500Serics /* 6351500Serics ** Get a logical line 6361500Serics */ 6371500Serics 6381500Serics getline(f, length) 6391500Serics register FILE *f; 6401500Serics int *length; 6411500Serics { 6421500Serics register int c; 6431500Serics register char *p; 6441500Serics register int column; 6451500Serics static int colflg; 6461500Serics 6471500Serics p = Line; 6481500Serics column = 0; 6491500Serics c = Getc (f); 6501500Serics if (colflg && c == '\n') { 6511500Serics Currline++; 6521500Serics c = Getc (f); 6531500Serics } 6541500Serics while (p < &Line[LINSIZ - 1]) { 6551500Serics if (c == EOF) { 6561500Serics if (p > Line) { 6571500Serics *p = '\0'; 6581500Serics *length = p - Line; 6591500Serics return (column); 6601500Serics } 6611500Serics *length = p - Line; 6621500Serics return (EOF); 6631500Serics } 6641500Serics if (c == '\n') { 6651500Serics Currline++; 6661500Serics break; 6671500Serics } 6681500Serics *p++ = c; 6691500Serics if (c == '\t') 6701500Serics if (hardtabs && column < promptlen && !hard) { 6711500Serics if (eraseln && !dumb) { 6721500Serics column = 1 + (column | 7); 6731500Serics tputs (eraseln, 1, putch); 6741500Serics promptlen = 0; 6751500Serics } 6761500Serics else { 6771500Serics for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 6781500Serics *p++ = ' '; 6791500Serics } 6801500Serics if (column >= promptlen) promptlen = 0; 6811500Serics } 6821500Serics } 6831500Serics else 6841500Serics column = 1 + (column | 7); 685*9627Ssklower else if (c == '\b' && column > 0) 6861500Serics column--; 6871500Serics else if (c == '\r') 6881500Serics column = 0; 6891500Serics else if (c == '\f' && stop_opt) { 6901500Serics p[-1] = '^'; 6911500Serics *p++ = 'L'; 6921500Serics column += 2; 6931500Serics Pause++; 6941500Serics } 6951500Serics else if (c == EOF) { 6961500Serics *length = p - Line; 6971500Serics return (column); 6981500Serics } 6991500Serics else if (c >= ' ' && c != RUBOUT) 7001500Serics column++; 7011500Serics if (column >= Mcol && fold_opt) break; 7021500Serics c = Getc (f); 7031500Serics } 7041500Serics if (column >= Mcol && Mcol > 0) { 7051500Serics if (!Wrap) { 7061500Serics *p++ = '\n'; 7071500Serics } 7081500Serics } 7091500Serics colflg = column == Mcol && fold_opt; 7101500Serics *length = p - Line; 7111500Serics *p = 0; 7121500Serics return (column); 7131500Serics } 7141500Serics 7151500Serics /* 7161500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 7171500Serics */ 7181500Serics 7191500Serics erase (col) 7201500Serics register int col; 7211500Serics { 7221500Serics 7231500Serics if (promptlen == 0) 7241500Serics return; 7251500Serics if (hard) { 7261500Serics putchar ('\n'); 7271500Serics } 7281500Serics else { 7291500Serics if (col == 0) 7301500Serics putchar ('\r'); 7311500Serics if (!dumb && eraseln) 7321500Serics tputs (eraseln, 1, putch); 7331500Serics else 7341500Serics for (col = promptlen - col; col > 0; col--) 7351500Serics putchar (' '); 7361500Serics } 7371500Serics promptlen = 0; 7381500Serics } 7391500Serics 7401500Serics /* 7411500Serics ** Erase the current line entirely 7421500Serics */ 7431500Serics 7441500Serics kill_line () 7451500Serics { 7461500Serics erase (0); 7471500Serics if (!eraseln || dumb) putchar ('\r'); 7481500Serics } 7491500Serics 7501500Serics /* 7513455Sroot * force clear to end of line 7523455Sroot */ 7533455Sroot cleareol() 7543455Sroot { 7553594Sroot tputs(eraseln, 1, putch); 7563455Sroot } 7573455Sroot 7583594Sroot clreos() 7593455Sroot { 7603594Sroot tputs(EodClr, 1, putch); 7613455Sroot } 7623455Sroot 7633455Sroot /* 7641500Serics ** Print string and return number of characters 7651500Serics */ 7661500Serics 7671500Serics pr(s1) 7681500Serics char *s1; 7691500Serics { 7701500Serics register char *s; 7711500Serics register char c; 7721500Serics 7731500Serics for (s = s1; c = *s++; ) 7741500Serics putchar(c); 7751500Serics return (s - s1 - 1); 7761500Serics } 7771500Serics 7781500Serics 7791500Serics /* Print a buffer of n characters */ 7801500Serics 7811500Serics prbuf (s, n) 7821500Serics register char *s; 7831500Serics register int n; 7841500Serics { 7853594Sroot char c; /* next ouput character */ 7863594Sroot register int state; /* next output char's UL state */ 7873594Sroot static int pstate = 0; /* current terminal UL state (off) */ 7883594Sroot 7893594Sroot while (--n >= 0) 7903594Sroot if (!ul_opt) 7913594Sroot putchar (*s++); 7923594Sroot else { 7933594Sroot if (n >= 2 && s[0] == '_' && s[1] == '\b') { 7943594Sroot n -= 2; 7953594Sroot s += 2; 7963594Sroot c = *s++; 7973594Sroot state = 1; 7983594Sroot } else if (n >= 2 && s[1] == '\b' && s[2] == '_') { 7993594Sroot n -= 2; 8003594Sroot c = *s++; 8013594Sroot s += 2; 8023594Sroot state = 1; 8033594Sroot } else { 8043594Sroot c = *s++; 8053594Sroot state = 0; 8063594Sroot } 8073594Sroot if (state != pstate) 8083594Sroot tputs(state ? ULenter : ULexit, 1, putch); 8093594Sroot pstate = state; 8103594Sroot putchar(c); 8113594Sroot if (state && *chUL) { 8123594Sroot pr(chBS); 8133594Sroot tputs(chUL, 1, putch); 8143594Sroot } 8153594Sroot } 8161500Serics } 8171500Serics 8181500Serics /* 8191500Serics ** Clear the screen 8201500Serics */ 8211500Serics 8221500Serics doclear() 8231500Serics { 8241500Serics if (Clear && !hard) { 8251500Serics tputs(Clear, 1, putch); 8261500Serics 8271500Serics /* Put out carriage return so that system doesn't 8281500Serics ** get confused by escape sequences when expanding tabs 8291500Serics */ 8301500Serics putchar ('\r'); 8311500Serics promptlen = 0; 8321500Serics } 8331500Serics } 8341500Serics 8353455Sroot /* 8363455Sroot * Go to home position 8373455Sroot */ 8383455Sroot home() 8393455Sroot { 8403455Sroot tputs(Home,1,putch); 8413455Sroot } 8423455Sroot 8431500Serics static int lastcmd, lastarg, lastp; 8441500Serics static int lastcolon; 8451500Serics char shell_line[132]; 8461500Serics 8471500Serics /* 8481500Serics ** Read a command and do it. A command consists of an optional integer 8491500Serics ** argument followed by the command character. Return the number of lines 8501500Serics ** to display in the next screenful. If there is nothing more to display 8511500Serics ** in the current file, zero is returned. 8521500Serics */ 8531500Serics 8541500Serics command (filename, f) 8551500Serics char *filename; 8561500Serics register FILE *f; 8571500Serics { 8581500Serics register int nlines; 8591500Serics register int retval; 8601500Serics register char c; 8611500Serics char colonch; 8621500Serics FILE *helpf; 8631500Serics int done; 8641500Serics char comchar, cmdbuf[80], *p; 8651500Serics 8661500Serics #define ret(val) retval=val;done++;break 8671500Serics 8681500Serics done = 0; 8691500Serics if (!errors) 8701500Serics prompt (filename); 8711500Serics else 8721500Serics errors = 0; 8731500Serics if (MBIT == RAW && slow_tty) { 8741500Serics otty.sg_flags |= MBIT; 8751500Serics stty(2, &otty); 8761500Serics } 8771500Serics for (;;) { 8781500Serics nlines = number (&comchar); 8791500Serics lastp = colonch = 0; 8801500Serics if (comchar == '.') { /* Repeat last command */ 8811500Serics lastp++; 8821500Serics comchar = lastcmd; 8831500Serics nlines = lastarg; 8841500Serics if (lastcmd == ':') 8851500Serics colonch = lastcolon; 8861500Serics } 8871500Serics lastcmd = comchar; 8881500Serics lastarg = nlines; 8891500Serics if (comchar == otty.sg_erase) { 8901500Serics kill_line (); 8911500Serics prompt (filename); 8921500Serics continue; 8931500Serics } 8941500Serics switch (comchar) { 8951500Serics case ':': 8961500Serics retval = colon (filename, colonch, nlines); 8971500Serics if (retval >= 0) 8981500Serics done++; 8991500Serics break; 9001500Serics case ' ': 9011500Serics case 'z': 9021500Serics if (nlines == 0) nlines = dlines; 9031500Serics else if (comchar == 'z') dlines = nlines; 9041500Serics ret (nlines); 9051500Serics case 'd': 9061500Serics case ctrl(D): 9071500Serics if (nlines != 0) nscroll = nlines; 9081500Serics ret (nscroll); 9091500Serics case RUBOUT: 9101500Serics case 'q': 9111500Serics case 'Q': 9121500Serics end_it (); 9131500Serics case 's': 9141500Serics case 'f': 9151500Serics if (nlines == 0) nlines++; 9161500Serics if (comchar == 'f') 9171500Serics nlines *= dlines; 9181500Serics putchar ('\r'); 9191500Serics erase (0); 9203594Sroot printf ("\n"); 9213594Sroot if (clreol) 9223594Sroot cleareol (); 9233594Sroot printf ("...skipping %d line", nlines); 9241500Serics if (nlines > 1) 9253594Sroot pr ("s\n"); 9261500Serics else 9273594Sroot pr ("\n"); 9283594Sroot 9293594Sroot if (clreol) 9303594Sroot cleareol (); 9313594Sroot pr ("\n"); 9323594Sroot 9331500Serics while (nlines > 0) { 9341500Serics while ((c = Getc (f)) != '\n') 9351500Serics if (c == EOF) { 9361500Serics retval = 0; 9371500Serics done++; 9381500Serics goto endsw; 9391500Serics } 9401500Serics Currline++; 9411500Serics nlines--; 9421500Serics } 9431500Serics ret (dlines); 9441500Serics case '\n': 9451500Serics if (nlines != 0) 9461500Serics dlines = nlines; 9471500Serics else 9481500Serics nlines = 1; 9491500Serics ret (nlines); 9501500Serics case '\f': 9511500Serics if (!no_intty) { 9521500Serics doclear (); 9531500Serics Fseek (f, screen_start.chrctr); 9541500Serics Currline = screen_start.line; 9551500Serics ret (dlines); 9561500Serics } 9571500Serics else { 9581500Serics write (2, &bell, 1); 9591500Serics break; 9601500Serics } 9611500Serics case '\'': 9621500Serics if (!no_intty) { 9631500Serics kill_line (); 9641500Serics pr ("\n***Back***\n\n"); 9651500Serics Fseek (f, context.chrctr); 9661500Serics Currline = context.line; 9671500Serics ret (dlines); 9681500Serics } 9691500Serics else { 9701500Serics write (2, &bell, 1); 9711500Serics break; 9721500Serics } 9731500Serics case '=': 9741500Serics kill_line (); 9751500Serics promptlen = printd (Currline); 9761500Serics fflush (stdout); 9771500Serics break; 9781500Serics case 'n': 9791500Serics lastp++; 9801500Serics case '/': 9811500Serics if (nlines == 0) nlines++; 9821500Serics kill_line (); 9831500Serics pr ("/"); 9841500Serics promptlen = 1; 9851500Serics fflush (stdout); 9861500Serics if (lastp) { 9871500Serics write (2,"\r", 1); 9881500Serics search (NULL, f, nlines); /* Use previous r.e. */ 9891500Serics } 9901500Serics else { 9911500Serics ttyin (cmdbuf, 78, '/'); 9921500Serics write (2, "\r", 1); 9931500Serics search (cmdbuf, f, nlines); 9941500Serics } 9953455Sroot ret (dlines-1); 9961500Serics case '!': 9971500Serics do_shell (filename); 9981500Serics break; 9991500Serics case 'h': 10001500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 10011500Serics error ("Can't open help file"); 10021500Serics if (noscroll) doclear (); 10031500Serics copy_file (helpf); 10041500Serics close (helpf); 10051500Serics prompt (filename); 10061500Serics break; 10071500Serics case 'v': /* This case should go right before default */ 10081500Serics if (!no_intty) { 10091500Serics kill_line (); 10101500Serics cmdbuf[0] = '+'; 10111500Serics scanstr (Currline, &cmdbuf[1]); 10121500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 10131500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 10141500Serics break; 10151500Serics } 10161500Serics default: 10171500Serics write (2, &bell, 1); 10181500Serics break; 10191500Serics } 10201500Serics if (done) break; 10211500Serics } 10221500Serics putchar ('\r'); 10231500Serics endsw: 10241500Serics inwait = 0; 10251500Serics notell++; 10261500Serics if (MBIT == RAW && slow_tty) { 10271500Serics otty.sg_flags &= ~MBIT; 10281500Serics stty(2, &otty); 10291500Serics } 10301500Serics return (retval); 10311500Serics } 10321500Serics 10331500Serics char ch; 10341500Serics 10351500Serics /* 10361500Serics * Execute a colon-prefixed command. 10371500Serics * Returns <0 if not a command that should cause 10381500Serics * more of the file to be printed. 10391500Serics */ 10401500Serics 10411500Serics colon (filename, cmd, nlines) 10421500Serics char *filename; 10431500Serics int cmd; 10441500Serics int nlines; 10451500Serics { 10461500Serics if (cmd == 0) 10471500Serics ch = readch (); 10481500Serics else 10491500Serics ch = cmd; 10501500Serics lastcolon = ch; 10511500Serics switch (ch) { 10521500Serics case 'f': 10531500Serics kill_line (); 10541500Serics if (!no_intty) 10551500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 10561500Serics else 10571500Serics promptlen = printf ("[Not a file] line %d", Currline); 10581500Serics fflush (stdout); 10591500Serics return (-1); 10601500Serics case 'n': 10611500Serics if (nlines == 0) { 10621500Serics if (fnum >= nfiles - 1) 10631500Serics end_it (); 10641500Serics nlines++; 10651500Serics } 10661500Serics putchar ('\r'); 10671500Serics erase (0); 10681500Serics skipf (nlines); 10691500Serics return (0); 10701500Serics case 'p': 10711500Serics if (no_intty) { 10721500Serics write (2, &bell, 1); 10731500Serics return (-1); 10741500Serics } 10751500Serics putchar ('\r'); 10761500Serics erase (0); 10771500Serics if (nlines == 0) 10781500Serics nlines++; 10791500Serics skipf (-nlines); 10801500Serics return (0); 10811500Serics case '!': 10821500Serics do_shell (filename); 10831500Serics return (-1); 10841500Serics case 'q': 10851500Serics case 'Q': 10861500Serics end_it (); 10871500Serics default: 10881500Serics write (2, &bell, 1); 10891500Serics return (-1); 10901500Serics } 10911500Serics } 10921500Serics 10931500Serics /* 10941500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 10951500Serics ** terminates the number. 10961500Serics */ 10971500Serics 10981500Serics number(cmd) 10991500Serics char *cmd; 11001500Serics { 11011500Serics register int i; 11021500Serics 11031500Serics i = 0; ch = otty.sg_kill; 11041500Serics for (;;) { 11051500Serics ch = readch (); 11061500Serics if (ch >= '0' && ch <= '9') 11071500Serics i = i*10 + ch - '0'; 11081500Serics else if (ch == otty.sg_kill) 11091500Serics i = 0; 11101500Serics else { 11111500Serics *cmd = ch; 11121500Serics break; 11131500Serics } 11141500Serics } 11151500Serics return (i); 11161500Serics } 11171500Serics 11181500Serics do_shell (filename) 11191500Serics char *filename; 11201500Serics { 11211500Serics char cmdbuf[80]; 11221500Serics 11231500Serics kill_line (); 11241500Serics pr ("!"); 11251500Serics fflush (stdout); 11261500Serics promptlen = 1; 11271500Serics if (lastp) 11281500Serics pr (shell_line); 11291500Serics else { 11301500Serics ttyin (cmdbuf, 78, '!'); 11311500Serics if (expand (shell_line, cmdbuf)) { 11321500Serics kill_line (); 11331500Serics promptlen = printf ("!%s", shell_line); 11341500Serics } 11351500Serics } 11361500Serics fflush (stdout); 11371500Serics write (2, "\n", 1); 11381500Serics promptlen = 0; 11391500Serics shellp = 1; 11401500Serics execute (filename, shell, shell, "-c", shell_line, 0); 11411500Serics } 11421500Serics 11431500Serics /* 11441500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 11451500Serics */ 11461500Serics 11471500Serics search (buf, file, n) 11481500Serics char buf[]; 11491500Serics FILE *file; 11501500Serics register int n; 11511500Serics { 11521500Serics long startline = Ftell (file); 11531500Serics register long line1 = startline; 11541500Serics register long line2 = startline; 11551500Serics register long line3 = startline; 11561500Serics register int lncount; 11571500Serics int saveln, rv, re_exec(); 11581500Serics char *s, *re_comp(); 11591500Serics 11601500Serics context.line = saveln = Currline; 11611500Serics context.chrctr = startline; 11621500Serics lncount = 0; 11631500Serics if ((s = re_comp (buf)) != 0) 11641500Serics error (s); 11651500Serics while (!feof (file)) { 11661500Serics line3 = line2; 11671500Serics line2 = line1; 11681500Serics line1 = Ftell (file); 11691500Serics rdline (file); 11701500Serics lncount++; 11711500Serics if ((rv = re_exec (Line)) == 1) 11721500Serics if (--n == 0) { 11731500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 11743455Sroot { 11753455Sroot pr ("\n"); 11763594Sroot if (clreol) 11773594Sroot cleareol (); 11783455Sroot pr("...skipping\n"); 11793455Sroot } 11801500Serics if (!no_intty) { 11811500Serics Currline -= (lncount >= 3 ? 3 : lncount); 11821500Serics Fseek (file, line3); 11833594Sroot if (noscroll) 11843594Sroot if (clreol) { 11853594Sroot home (); 11863594Sroot cleareol (); 11873594Sroot } 11883594Sroot else 11893594Sroot doclear (); 11901500Serics } 11911500Serics else { 11921500Serics kill_line (); 11933594Sroot if (noscroll) 11943594Sroot if (clreol) { 11953594Sroot home (); 11963594Sroot cleareol (); 11973594Sroot } 11983594Sroot else 11993594Sroot doclear (); 12001500Serics pr (Line); 12011500Serics putchar ('\n'); 12021500Serics } 12031500Serics break; 12041500Serics } 12051500Serics else if (rv == -1) 12061500Serics error ("Regular expression botch"); 12071500Serics } 12081500Serics if (feof (file)) { 12091500Serics if (!no_intty) { 12101500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 12111500Serics Currline = saveln; 12121500Serics Fseek (file, startline); 12131500Serics } 12141500Serics else { 12151500Serics pr ("\nPattern not found\n"); 12161500Serics end_it (); 12171500Serics } 12181500Serics error ("Pattern not found"); 12191500Serics } 12201500Serics } 12211500Serics 12221500Serics execute (filename, cmd, args) 12231500Serics char *filename; 12241500Serics char *cmd, *args; 12251500Serics { 12261500Serics int id; 12271500Serics 12281500Serics fflush (stdout); 12291500Serics reset_tty (); 12301500Serics while ((id = fork ()) < 0) 12311500Serics sleep (5); 12321500Serics if (id == 0) { 12331500Serics execv (cmd, &args); 12341500Serics write (2, "exec failed\n", 12); 12351500Serics exit (1); 12361500Serics } 12371500Serics signal (SIGINT, SIG_IGN); 12381500Serics signal (SIGQUIT, SIG_IGN); 12391500Serics if (catch_susp) 12401500Serics signal(SIGTSTP, SIG_DFL); 12411500Serics wait (0); 12421500Serics signal (SIGINT, end_it); 12431500Serics signal (SIGQUIT, onquit); 12441500Serics if (catch_susp) 12451500Serics signal(SIGTSTP, onsusp); 12461500Serics set_tty (); 12471500Serics pr ("------------------------\n"); 12481500Serics prompt (filename); 12491500Serics } 12501500Serics /* 12511500Serics ** Skip n lines in the file f 12521500Serics */ 12531500Serics 12541500Serics skiplns (n, f) 12551500Serics register int n; 12561500Serics register FILE *f; 12571500Serics { 12581500Serics register char c; 12591500Serics 12601500Serics while (n > 0) { 12611500Serics while ((c = Getc (f)) != '\n') 12621500Serics if (c == EOF) 12631500Serics return; 12641500Serics n--; 12651500Serics Currline++; 12661500Serics } 12671500Serics } 12681500Serics 12691500Serics /* 12701500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 12711500Serics ** negative. 12721500Serics */ 12731500Serics 12741500Serics skipf (nskip) 12751500Serics register int nskip; 12761500Serics { 12771500Serics if (nskip == 0) return; 12781500Serics if (nskip > 0) { 12791500Serics if (fnum + nskip > nfiles - 1) 12801500Serics nskip = nfiles - fnum - 1; 12811500Serics } 12821500Serics else if (within) 12831500Serics ++fnum; 12841500Serics fnum += nskip; 12851500Serics if (fnum < 0) 12861500Serics fnum = 0; 12873594Sroot pr ("\n...Skipping "); 12883455Sroot pr ("\n"); 12893594Sroot if (clreol) 12903594Sroot cleareol (); 12913455Sroot pr ("...Skipping "); 12921500Serics pr (nskip > 0 ? "to file " : "back to file "); 12931500Serics pr (fnames[fnum]); 12943455Sroot pr ("\n"); 12953594Sroot if (clreol) 12963594Sroot cleareol (); 12973455Sroot pr ("\n"); 12981500Serics --fnum; 12991500Serics } 13001500Serics 13011500Serics /*----------------------------- Terminal I/O -------------------------------*/ 13021500Serics 13031500Serics initterm () 13041500Serics { 13051500Serics char buf[TBUFSIZ]; 13061500Serics char clearbuf[100]; 13071500Serics char *clearptr, *padstr; 13081500Serics int ldisc; 13091500Serics 13101500Serics setbuf(stdout, obuf); 13111500Serics if (!(no_tty = gtty(1, &otty))) { 13121500Serics if (tgetent(buf, getenv("TERM")) <= 0) { 13133594Sroot dumb++; ul_opt = 0; 13141500Serics } 13151500Serics else { 13161500Serics if (((Lpp = tgetnum("li")) < 0) || tgetflag("hc")) { 13171500Serics hard++; /* Hard copy terminal */ 13181500Serics Lpp = 24; 13191500Serics } 13201500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 13211500Serics noscroll++; 13221500Serics if ((Mcol = tgetnum("co")) < 0) 13231500Serics Mcol = 80; 13241500Serics Wrap = tgetflag("am"); 13251500Serics bad_so = tgetflag ("xs"); 13261500Serics clearptr = clearbuf; 13271500Serics eraseln = tgetstr("ce",&clearptr); 13281500Serics Clear = tgetstr("cl", &clearptr); 13291500Serics Senter = tgetstr("so", &clearptr); 13301500Serics Sexit = tgetstr("se", &clearptr); 13313594Sroot 13323594Sroot /* 13333594Sroot * Set up for underlining: some terminals don't need it; 13343594Sroot * others have start/stop sequences, still others have an 13353594Sroot * underline char sequence which is assumed to move the 13363594Sroot * cursor forward one character. If underline sequence 13373594Sroot * isn't available, settle for standout sequence. 13383594Sroot */ 13393594Sroot 13403594Sroot if (tgetflag("ul") || tgetflag("os")) 13413594Sroot ul_opt = 0; 13423594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 13433594Sroot chUL = ""; 13443594Sroot if ((ULenter = tgetstr("us", &clearptr)) == NULL && 13453594Sroot (!*chUL) && (ULenter = tgetstr("so", &clearptr)) == NULL) 13463594Sroot ULenter = ""; 13473594Sroot if ((ULexit = tgetstr("ue", &clearptr)) == NULL && 13483594Sroot (!*chUL) && (ULexit = tgetstr("se", &clearptr)) == NULL) 13493594Sroot ULexit = ""; 13503594Sroot 13511500Serics if (padstr = tgetstr("pc", &clearptr)) 13521500Serics PC = *padstr; 13533455Sroot Home = tgetstr("ho",&clearptr); 13543594Sroot if (*Home == '\0') 13553455Sroot { 13563594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 13573594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 13583455Sroot Home = cursorhome; 13593455Sroot } 13603455Sroot } 13613594Sroot EodClr = tgetstr("cd", &clearptr); 13621500Serics } 13631500Serics if ((shell = getenv("SHELL")) == NULL) 13641500Serics shell = "/bin/sh"; 13651500Serics } 13661500Serics no_intty = gtty(0, &otty); 13671500Serics gtty(2, &otty); 13681500Serics ospeed = otty.sg_ospeed; 13691500Serics slow_tty = ospeed < B1200; 13701500Serics hardtabs = !(otty.sg_flags & XTABS); 13711500Serics if (!no_tty) { 13721500Serics otty.sg_flags &= ~ECHO; 13731500Serics if (MBIT == CBREAK || !slow_tty) 13741500Serics otty.sg_flags |= MBIT; 13751500Serics } 13761500Serics } 13771500Serics 13781500Serics readch () 13791500Serics { 13801500Serics char ch; 13811500Serics extern int errno; 13821500Serics 13831500Serics if (read (2, &ch, 1) <= 0) 13841500Serics if (errno != EINTR) 13851500Serics exit(0); 13861500Serics else 13871500Serics ch = otty.sg_kill; 13881500Serics return (ch); 13891500Serics } 13901500Serics 13911500Serics static char BS = '\b'; 13921500Serics static char CARAT = '^'; 13931500Serics 13941500Serics ttyin (buf, nmax, pchar) 13951500Serics char buf[]; 13961500Serics register int nmax; 13971500Serics char pchar; 13981500Serics { 13991500Serics register char *sptr; 14001500Serics register char ch; 14011500Serics register int slash = 0; 14021500Serics int maxlen; 14031500Serics char cbuf; 14041500Serics 14051500Serics sptr = buf; 14061500Serics maxlen = 0; 14071500Serics while (sptr - buf < nmax) { 14081500Serics if (promptlen > maxlen) maxlen = promptlen; 14091500Serics ch = readch (); 14101500Serics if (ch == '\\') { 14111500Serics slash++; 14121500Serics } 14131500Serics else if ((ch == otty.sg_erase) && !slash) { 14141500Serics if (sptr > buf) { 14151500Serics --promptlen; 14161500Serics write (2, &BS, 1); 14171500Serics --sptr; 14181500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 14191500Serics --promptlen; 14201500Serics write (2, &BS, 1); 14211500Serics } 14221500Serics continue; 14231500Serics } 14241500Serics else { 14251500Serics if (!eraseln) promptlen = maxlen; 14261500Serics longjmp (restore, 1); 14271500Serics } 14281500Serics } 14291500Serics else if ((ch == otty.sg_kill) && !slash) { 14301500Serics if (hard) { 14311500Serics show (ch); 14321500Serics putchar ('\n'); 14331500Serics putchar (pchar); 14341500Serics } 14351500Serics else { 14361500Serics putchar ('\r'); 14371500Serics putchar (pchar); 14381500Serics if (eraseln) 14391500Serics erase (1); 14401500Serics promptlen = 1; 14411500Serics } 14421500Serics sptr = buf; 14431500Serics fflush (stdout); 14441500Serics continue; 14451500Serics } 14461500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 14471500Serics write (2, &BS, 1); 14481500Serics --sptr; 14491500Serics } 14501500Serics if (ch != '\\') 14511500Serics slash = 0; 14521500Serics *sptr++ = ch; 14531500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 14541500Serics ch += ch == RUBOUT ? -0100 : 0100; 14551500Serics write (2, &CARAT, 1); 14561500Serics promptlen++; 14571500Serics } 14581500Serics cbuf = ch; 14591500Serics if (ch != '\n' && ch != ESC) { 14601500Serics write (2, &cbuf, 1); 14611500Serics promptlen++; 14621500Serics } 14631500Serics else 14641500Serics break; 14651500Serics } 14661500Serics *--sptr = '\0'; 14671500Serics if (!eraseln) promptlen = maxlen; 14681500Serics if (sptr - buf >= nmax - 1) 14691500Serics error ("Line too long"); 14701500Serics } 14711500Serics 14721500Serics expand (outbuf, inbuf) 14731500Serics char *outbuf; 14741500Serics char *inbuf; 14751500Serics { 14761500Serics register char *instr; 14771500Serics register char *outstr; 14781500Serics register char ch; 14791500Serics char temp[200]; 14801500Serics int changed = 0; 14811500Serics 14821500Serics instr = inbuf; 14831500Serics outstr = temp; 14841500Serics while ((ch = *instr++) != '\0') 14851500Serics switch (ch) { 14861500Serics case '%': 14871500Serics if (!no_intty) { 14881500Serics strcpy (outstr, fnames[fnum]); 14891500Serics outstr += strlen (fnames[fnum]); 14901500Serics changed++; 14911500Serics } 14921500Serics else 14931500Serics *outstr++ = ch; 14941500Serics break; 14951500Serics case '!': 14961500Serics if (!shellp) 14971500Serics error ("No previous command to substitute for"); 14981500Serics strcpy (outstr, shell_line); 14991500Serics outstr += strlen (shell_line); 15001500Serics changed++; 15011500Serics break; 15021500Serics case '\\': 15031500Serics if (*instr == '%' || *instr == '!') { 15041500Serics *outstr++ = *instr++; 15051500Serics break; 15061500Serics } 15071500Serics default: 15081500Serics *outstr++ = ch; 15091500Serics } 15101500Serics *outstr++ = '\0'; 15111500Serics strcpy (outbuf, temp); 15121500Serics return (changed); 15131500Serics } 15141500Serics 15151500Serics show (ch) 15161500Serics register char ch; 15171500Serics { 15181500Serics char cbuf; 15191500Serics 15201500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 15211500Serics ch += ch == RUBOUT ? -0100 : 0100; 15221500Serics write (2, &CARAT, 1); 15231500Serics promptlen++; 15241500Serics } 15251500Serics cbuf = ch; 15261500Serics write (2, &cbuf, 1); 15271500Serics promptlen++; 15281500Serics } 15291500Serics 15301500Serics error (mess) 15311500Serics char *mess; 15321500Serics { 15333594Sroot if (clreol) 15343594Sroot cleareol (); 15353594Sroot else 15363594Sroot kill_line (); 15371500Serics promptlen += strlen (mess); 15381500Serics if (Senter && Sexit) { 15391500Serics tputs (Senter, 1, putch); 15401500Serics pr(mess); 15411500Serics tputs (Sexit, 1, putch); 15421500Serics } 15431500Serics else 15441500Serics pr (mess); 15451500Serics fflush(stdout); 15461500Serics errors++; 15471500Serics longjmp (restore, 1); 15481500Serics } 15491500Serics 15501500Serics 15511500Serics set_tty () 15521500Serics { 15531500Serics otty.sg_flags |= MBIT; 15541500Serics otty.sg_flags &= ~ECHO; 15551500Serics stty(2, &otty); 15561500Serics } 15571500Serics 15581500Serics reset_tty () 15591500Serics { 15601500Serics otty.sg_flags |= ECHO; 15611500Serics otty.sg_flags &= ~MBIT; 15621500Serics stty(2, &otty); 15631500Serics } 15641500Serics 15651500Serics rdline (f) 15661500Serics register FILE *f; 15671500Serics { 15681500Serics register char c; 15691500Serics register char *p; 15701500Serics 15711500Serics p = Line; 15721500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 15731500Serics *p++ = c; 15741500Serics if (c == '\n') 15751500Serics Currline++; 15761500Serics *p = '\0'; 15771500Serics } 15781500Serics 15791500Serics /* Come here when we get a suspend signal from the terminal */ 15801500Serics 15811500Serics onsusp () 15821500Serics { 15831500Serics reset_tty (); 15841500Serics fflush (stdout); 15851500Serics /* Send the TSTP signal to suspend our process group */ 15861500Serics kill (0, SIGTSTP); 15871500Serics /* Pause for station break */ 15881500Serics 15891500Serics /* We're back */ 15901500Serics signal (SIGTSTP, onsusp); 15911500Serics set_tty (); 15921500Serics if (inwait) 15931500Serics longjmp (restore); 15941500Serics } 1595