113615Ssam #ifndef lint 2*17195Sralph static char *sccsid = "@(#)more.c 4.20 (Berkeley) 84/09/17"; 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 Line[LINSIZ]; /* Line buffer */ 701500Serics int Lpp = 24; /* lines per page */ 711500Serics char *Clear; /* clear screen */ 721500Serics char *eraseln; /* erase line */ 731500Serics char *Senter, *Sexit;/* enter and exit standout mode */ 743594Sroot char *ULenter, *ULexit; /* enter and exit underline mode */ 753594Sroot char *chUL; /* underline character */ 763594Sroot char *chBS; /* backspace character */ 773455Sroot char *Home; /* go to home */ 783455Sroot char *cursorm; /* cursor movement */ 793455Sroot char cursorhome[40]; /* contains cursor movement to home */ 803594Sroot char *EodClr; /* clear rest of screen */ 811500Serics char *tgetstr(); 821500Serics int Mcol = 80; /* number of columns */ 831500Serics int Wrap = 1; /* set if automargins */ 8416710Sjak int soglitch; /* terminal has standout mode glitch */ 8516710Sjak int ulglitch; /* terminal has underline mode glitch */ 8616710Sjak int pstate = 0; /* current UL state */ 871500Serics long fseek(); 883455Sroot char *getenv(); 891500Serics struct { 901500Serics long chrctr, line; 911500Serics } context, screen_start; 921500Serics extern char PC; /* pad character */ 931500Serics extern short ospeed; 941500Serics 951500Serics 961500Serics main(argc, argv) 971500Serics int argc; 981500Serics char *argv[]; 991500Serics { 1001500Serics register FILE *f; 1011500Serics register char *s; 1021500Serics register char *p; 1031500Serics register char ch; 1041500Serics register int left; 10516582Sleres int prnames = 0; 1061500Serics int initopt = 0; 1071500Serics int srchopt = 0; 1081500Serics int clearit = 0; 1091500Serics int initline; 1101500Serics char initbuf[80]; 1111500Serics FILE *checkf(); 1121500Serics 1131500Serics nfiles = argc; 1141500Serics fnames = argv; 1151500Serics initterm (); 11615813Sralph nscroll = Lpp/2 - 1; 11715813Sralph if (nscroll <= 0) 11815813Sralph nscroll = 1; 1193455Sroot if(s = getenv("MORE")) argscan(s); 1201500Serics while (--nfiles > 0) { 1211500Serics if ((ch = (*++fnames)[0]) == '-') { 1223455Sroot argscan(*fnames+1); 1231500Serics } 1241500Serics else if (ch == '+') { 1251500Serics s = *fnames; 1261500Serics if (*++s == '/') { 1271500Serics srchopt++; 1281500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1291500Serics *p++ = *s++; 1301500Serics *p = '\0'; 1311500Serics } 1321500Serics else { 1331500Serics initopt++; 1341500Serics for (initline = 0; *s != '\0'; s++) 1351500Serics if (isdigit (*s)) 1361500Serics initline = initline*10 + *s -'0'; 1371500Serics --initline; 1381500Serics } 1391500Serics } 1401500Serics else break; 1411500Serics } 1423594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1433455Sroot * defined, and in that case, make sure we are in noscroll mode 1443455Sroot */ 1453455Sroot if(clreol) 1463455Sroot { 1473594Sroot if ((*Home == '\0') || (*eraseln == '\0') || (*EodClr == '\0')) 1483594Sroot clreol = 0; 1493455Sroot else noscroll = 1; 1503455Sroot } 1513455Sroot 1521500Serics if (dlines == 0) 1531500Serics dlines = Lpp - (noscroll ? 1 : 2); 1541500Serics left = dlines; 1551500Serics if (nfiles > 1) 1561500Serics prnames++; 1571500Serics if (!no_intty && nfiles == 0) { 1581500Serics fputs("Usage: ",stderr); 1591500Serics fputs(argv[0],stderr); 1601500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1611500Serics exit(1); 1621500Serics } 1631500Serics else 1641500Serics f = stdin; 1651500Serics if (!no_tty) { 1661500Serics signal(SIGQUIT, onquit); 1671500Serics signal(SIGINT, end_it); 1681500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1691500Serics signal(SIGTSTP, onsusp); 1701500Serics catch_susp++; 1711500Serics } 17216582Sleres stty (fileno(stderr), &otty); 1731500Serics } 1741500Serics if (no_intty) { 1751500Serics if (no_tty) 1761500Serics copy_file (stdin); 1771500Serics else { 1781500Serics if ((ch = Getc (f)) == '\f') 1793594Sroot doclear(); 1801500Serics else { 1811500Serics Ungetc (ch, f); 1823594Sroot if (noscroll && (ch != EOF)) { 1833594Sroot if (clreol) 1843594Sroot home (); 1853594Sroot else 1863594Sroot doclear (); 1873455Sroot } 1881500Serics } 1891500Serics if (srchopt) 1903455Sroot { 1911500Serics search (initbuf, stdin, 1); 1923594Sroot if (noscroll) 1933594Sroot left--; 1943455Sroot } 1951500Serics else if (initopt) 1961500Serics skiplns (initline, stdin); 1971500Serics screen (stdin, left); 1981500Serics } 1991500Serics no_intty = 0; 2001500Serics prnames++; 2011500Serics firstf = 0; 2021500Serics } 2031500Serics 2041500Serics while (fnum < nfiles) { 2051500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2061500Serics context.line = context.chrctr = 0; 2071500Serics Currline = 0; 2081500Serics if (firstf) setjmp (restore); 2091500Serics if (firstf) { 2101500Serics firstf = 0; 2111500Serics if (srchopt) 2123455Sroot { 2131500Serics search (initbuf, f, 1); 2143594Sroot if (noscroll) 2153594Sroot left--; 2163455Sroot } 2171500Serics else if (initopt) 2181500Serics skiplns (initline, f); 2191500Serics } 2201500Serics else if (fnum < nfiles && !no_tty) { 2211500Serics setjmp (restore); 2221500Serics left = command (fnames[fnum], f); 2231500Serics } 2241500Serics if (left != 0) { 2253594Sroot if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 2263594Sroot if (clreol) 2273594Sroot home (); 2283594Sroot else 2293594Sroot doclear (); 2301500Serics if (prnames) { 2311500Serics if (bad_so) 2321500Serics erase (0); 2333594Sroot if (clreol) 2343594Sroot cleareol (); 2351500Serics pr("::::::::::::::"); 2361500Serics if (promptlen > 14) 2371500Serics erase (14); 2383455Sroot printf ("\n"); 2393455Sroot if(clreol) cleareol(); 2403455Sroot printf("%s\n", fnames[fnum]); 2413455Sroot if(clreol) cleareol(); 2423455Sroot printf("::::::::::::::\n", fnames[fnum]); 2431500Serics if (left > Lpp - 4) 2441500Serics left = Lpp - 4; 2451500Serics } 2461500Serics if (no_tty) 2471500Serics copy_file (f); 2481500Serics else { 2491500Serics within++; 2501500Serics screen(f, left); 2511500Serics within = 0; 2521500Serics } 2531500Serics } 2541500Serics setjmp (restore); 2551500Serics fflush(stdout); 2561500Serics fclose(f); 2571500Serics screen_start.line = screen_start.chrctr = 0L; 2581500Serics context.line = context.chrctr = 0L; 2591500Serics } 2601500Serics fnum++; 2611500Serics firstf = 0; 2621500Serics } 2631500Serics reset_tty (); 2641500Serics exit(0); 2651500Serics } 2661500Serics 2673455Sroot argscan(s) 2683455Sroot char *s; 2693455Sroot { 27011604Slayer for (dlines = 0; *s != '\0'; s++) 27111604Slayer { 27211604Slayer switch (*s) 27311604Slayer { 27411604Slayer case '0': case '1': case '2': 27511604Slayer case '3': case '4': case '5': 27611604Slayer case '6': case '7': case '8': 27711604Slayer case '9': 27811604Slayer dlines = dlines*10 + *s - '0'; 27911604Slayer break; 28011604Slayer case 'd': 28111604Slayer dum_opt = 1; 28211604Slayer break; 28311604Slayer case 'l': 28411604Slayer stop_opt = 0; 28511604Slayer break; 28611604Slayer case 'f': 28711604Slayer fold_opt = 0; 28811604Slayer break; 28911604Slayer case 'p': 29011604Slayer noscroll++; 29111604Slayer break; 29211604Slayer case 'c': 29311604Slayer clreol++; 29411604Slayer break; 29511604Slayer case 's': 29611604Slayer ssp_opt = 1; 29711604Slayer break; 29811604Slayer case 'u': 29911604Slayer ul_opt = 0; 30011604Slayer break; 30111604Slayer } 30211604Slayer } 3033455Sroot } 3043455Sroot 3053455Sroot 3061500Serics /* 3071500Serics ** Check whether the file named by fs is an ASCII file which the user may 3081500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3091500Serics */ 3101500Serics 3111500Serics FILE * 3121500Serics checkf (fs, clearfirst) 3131500Serics register char *fs; 3141500Serics int *clearfirst; 3151500Serics { 3161500Serics struct stat stbuf; 3171500Serics register FILE *f; 3181500Serics char c; 3191500Serics 3201500Serics if (stat (fs, &stbuf) == -1) { 3211500Serics fflush(stdout); 3223594Sroot if (clreol) 3233594Sroot cleareol (); 3241500Serics perror(fs); 3251500Serics return (NULL); 3261500Serics } 3271500Serics if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3281500Serics printf("\n*** %s: directory ***\n\n", fs); 3291500Serics return (NULL); 3301500Serics } 3311500Serics if ((f=Fopen(fs, "r")) == NULL) { 3321500Serics fflush(stdout); 3331500Serics perror(fs); 3341500Serics return (NULL); 3351500Serics } 3361500Serics c = Getc(f); 3371500Serics 3381500Serics /* Try to see whether it is an ASCII file */ 3391500Serics 3401500Serics switch ((c | *f->_ptr << 8) & 0177777) { 3411500Serics case 0405: 3421500Serics case 0407: 3431500Serics case 0410: 3441500Serics case 0411: 3451500Serics case 0413: 3461500Serics case 0177545: 3471500Serics printf("\n******** %s: Not a text file ********\n\n", fs); 3481500Serics fclose (f); 3491500Serics return (NULL); 3501500Serics default: 3511500Serics break; 3521500Serics } 3531500Serics if (c == '\f') 3541500Serics *clearfirst = 1; 3551500Serics else { 3561500Serics *clearfirst = 0; 3571500Serics Ungetc (c, f); 3581500Serics } 3591500Serics if ((file_size = stbuf.st_size) == 0) 3601500Serics file_size = 0x7fffffffffffffffL; 3611500Serics return (f); 3621500Serics } 3631500Serics 3641500Serics /* 3651500Serics ** A real function, for the tputs routine in termlib 3661500Serics */ 3671500Serics 3681500Serics putch (ch) 3691500Serics char ch; 3701500Serics { 3711500Serics putchar (ch); 3721500Serics } 3731500Serics 3741500Serics /* 3751500Serics ** Print out the contents of the file f, one screenful at a time. 3761500Serics */ 3771500Serics 3781500Serics #define STOP -10 3791500Serics 3801500Serics screen (f, num_lines) 3811500Serics register FILE *f; 3821500Serics register int num_lines; 3831500Serics { 3841500Serics register int c; 3851500Serics register int nchars; 3863594Sroot int length; /* length of current line */ 3873594Sroot static int prev_len = 1; /* length of previous line */ 3881500Serics 3891500Serics for (;;) { 3901500Serics while (num_lines > 0 && !Pause) { 3911500Serics if ((nchars = getline (f, &length)) == EOF) 3923455Sroot { 3933594Sroot if (clreol) 3943594Sroot clreos(); 3951500Serics return; 3963455Sroot } 3973594Sroot if (ssp_opt && length == 0 && prev_len == 0) 3983594Sroot continue; 3993594Sroot prev_len = length; 4001500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 4011500Serics erase (0); 4023594Sroot /* must clear before drawing line since tabs on some terminals 4033594Sroot * do not erase what they tab over. 4043594Sroot */ 4053594Sroot if (clreol) 4063594Sroot cleareol (); 4071500Serics prbuf (Line, length); 4081500Serics if (nchars < promptlen) 4091500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4101500Serics else promptlen = 0; 4113594Sroot /* is this needed? 4123594Sroot * if (clreol) 4133594Sroot * cleareol(); /* must clear again in case we wrapped * 4143594Sroot */ 4151500Serics if (nchars < Mcol || !fold_opt) 41616710Sjak prbuf("\n", 1); /* will turn off UL if necessary */ 4171500Serics if (nchars == STOP) 4181500Serics break; 4191500Serics num_lines--; 4201500Serics } 42116710Sjak if (pstate) { 42216710Sjak tputs(ULexit, 1, putch); 42316710Sjak pstate = 0; 42416710Sjak } 4251500Serics fflush(stdout); 4261500Serics if ((c = Getc(f)) == EOF) 4273455Sroot { 4283594Sroot if (clreol) 4293594Sroot clreos (); 4301500Serics return; 4313455Sroot } 4323455Sroot 4333594Sroot if (Pause && clreol) 4343594Sroot clreos (); 4351500Serics Ungetc (c, f); 4361500Serics setjmp (restore); 4371500Serics Pause = 0; startup = 0; 4381500Serics if ((num_lines = command (NULL, f)) == 0) 4391500Serics return; 4401500Serics if (hard && promptlen > 0) 4411500Serics erase (0); 44211123Slayer if (noscroll && num_lines >= dlines) 44316582Sleres { 4443594Sroot if (clreol) 4453594Sroot home(); 4463594Sroot else 4473594Sroot doclear (); 4483455Sroot } 4491500Serics screen_start.line = Currline; 4501500Serics screen_start.chrctr = Ftell (f); 4511500Serics } 4521500Serics } 4531500Serics 4541500Serics /* 4551500Serics ** Come here if a quit signal is received 4561500Serics */ 4571500Serics 4581500Serics onquit() 4591500Serics { 4601500Serics signal(SIGQUIT, SIG_IGN); 4611500Serics if (!inwait) { 4621500Serics putchar ('\n'); 4631500Serics if (!startup) { 4641500Serics signal(SIGQUIT, onquit); 4651500Serics longjmp (restore, 1); 4661500Serics } 4671500Serics else 4681500Serics Pause++; 4691500Serics } 4701500Serics else if (!dum_opt && notell) { 4711500Serics write (2, "[Use q or Q to quit]", 20); 4721500Serics promptlen += 20; 4731500Serics notell = 0; 4741500Serics } 4751500Serics signal(SIGQUIT, onquit); 4761500Serics } 4771500Serics 4781500Serics /* 4791500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 4801500Serics */ 4811500Serics 4821500Serics end_it () 4831500Serics { 4841500Serics 4851500Serics reset_tty (); 4863594Sroot if (clreol) { 4873594Sroot putchar ('\r'); 4883594Sroot clreos (); 4893594Sroot fflush (stdout); 4903594Sroot } 4913455Sroot else if (!clreol && (promptlen > 0)) { 4921500Serics kill_line (); 4931500Serics fflush (stdout); 4941500Serics } 4951500Serics else 4961500Serics write (2, "\n", 1); 4971500Serics _exit(0); 4981500Serics } 4991500Serics 5001500Serics copy_file(f) 5011500Serics register FILE *f; 5021500Serics { 5031500Serics register int c; 5041500Serics 5051500Serics while ((c = getc(f)) != EOF) 5061500Serics putchar(c); 5071500Serics } 5081500Serics 5091500Serics /* Simplified printf function */ 5101500Serics 5111500Serics printf (fmt, args) 5121500Serics register char *fmt; 5131500Serics int args; 5141500Serics { 5151500Serics register int *argp; 5161500Serics register char ch; 5171500Serics register int ccount; 5181500Serics 5191500Serics ccount = 0; 5201500Serics argp = &args; 5211500Serics while (*fmt) { 5221500Serics while ((ch = *fmt++) != '%') { 5231500Serics if (ch == '\0') 5241500Serics return (ccount); 5251500Serics ccount++; 5261500Serics putchar (ch); 5271500Serics } 5281500Serics switch (*fmt++) { 5291500Serics case 'd': 5301500Serics ccount += printd (*argp); 5311500Serics break; 5321500Serics case 's': 5331500Serics ccount += pr ((char *)*argp); 5341500Serics break; 5351500Serics case '%': 5361500Serics ccount++; 5371500Serics argp--; 5381500Serics putchar ('%'); 5391500Serics break; 5401500Serics case '0': 5411500Serics return (ccount); 5421500Serics default: 5431500Serics break; 5441500Serics } 5451500Serics ++argp; 5461500Serics } 5471500Serics return (ccount); 5481500Serics 5491500Serics } 5501500Serics 5511500Serics /* 5521500Serics ** Print an integer as a string of decimal digits, 5531500Serics ** returning the length of the print representation. 5541500Serics */ 5551500Serics 5561500Serics printd (n) 5571500Serics int n; 5581500Serics { 5591500Serics int a, nchars; 5601500Serics 5611500Serics if (a = n/10) 5621500Serics nchars = 1 + printd(a); 5631500Serics else 5641500Serics nchars = 1; 5651500Serics putchar (n % 10 + '0'); 5661500Serics return (nchars); 5671500Serics } 5681500Serics 5691500Serics /* Put the print representation of an integer into a string */ 5701500Serics static char *sptr; 5711500Serics 5721500Serics scanstr (n, str) 5731500Serics int n; 5741500Serics char *str; 5751500Serics { 5761500Serics sptr = str; 57711604Slayer Sprintf (n); 5781500Serics *sptr = '\0'; 5791500Serics } 5801500Serics 58111604Slayer Sprintf (n) 5821500Serics { 5831500Serics int a; 5841500Serics 5851500Serics if (a = n/10) 58611604Slayer Sprintf (a); 5871500Serics *sptr++ = n % 10 + '0'; 5881500Serics } 5891500Serics 5901500Serics static char bell = ctrl(G); 5911500Serics 5921500Serics strlen (s) 5931500Serics char *s; 5941500Serics { 5951500Serics register char *p; 5961500Serics 5971500Serics p = s; 5981500Serics while (*p++) 5991500Serics ; 6001500Serics return (p - s - 1); 6011500Serics } 6021500Serics 6031500Serics /* See whether the last component of the path name "path" is equal to the 6041500Serics ** string "string" 6051500Serics */ 6061500Serics 6071500Serics tailequ (path, string) 6081500Serics char *path; 6091500Serics register char *string; 6101500Serics { 6111500Serics register char *tail; 6121500Serics 6131500Serics tail = path + strlen(path); 6141500Serics while (tail >= path) 6151500Serics if (*(--tail) == '/') 6161500Serics break; 6171500Serics ++tail; 6181500Serics while (*tail++ == *string++) 6191500Serics if (*tail == '\0') 6201500Serics return(1); 6211500Serics return(0); 6221500Serics } 6231500Serics 6241500Serics prompt (filename) 6251500Serics char *filename; 6261500Serics { 6273594Sroot if (clreol) 6283594Sroot cleareol (); 6293455Sroot else if (promptlen > 0) 6301500Serics kill_line (); 6311500Serics if (!hard) { 6321500Serics promptlen = 8; 63316710Sjak if (Senter && Sexit) { 6341500Serics tputs (Senter, 1, putch); 63516710Sjak promptlen += (2 * soglitch); 63616710Sjak } 6373594Sroot if (clreol) 6383594Sroot cleareol (); 6391500Serics pr("--More--"); 6401500Serics if (filename != NULL) { 6411500Serics promptlen += printf ("(Next file: %s)", filename); 6421500Serics } 6431500Serics else if (!no_intty) { 6441500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 6451500Serics } 6461500Serics if (dum_opt) { 64716710Sjak promptlen += pr("[Press space to continue, 'q' to quit.]"); 6481500Serics } 6491500Serics if (Senter && Sexit) 6501500Serics tputs (Sexit, 1, putch); 6513594Sroot if (clreol) 6523594Sroot clreos (); 6531500Serics fflush(stdout); 6541500Serics } 6551500Serics else 6561500Serics write (2, &bell, 1); 6571500Serics inwait++; 6581500Serics } 6591500Serics 6601500Serics /* 6611500Serics ** Get a logical line 6621500Serics */ 6631500Serics 6641500Serics getline(f, length) 6651500Serics register FILE *f; 6661500Serics int *length; 6671500Serics { 6681500Serics register int c; 6691500Serics register char *p; 6701500Serics register int column; 6711500Serics static int colflg; 6721500Serics 6731500Serics p = Line; 6741500Serics column = 0; 6751500Serics c = Getc (f); 6761500Serics if (colflg && c == '\n') { 6771500Serics Currline++; 6781500Serics c = Getc (f); 6791500Serics } 6801500Serics while (p < &Line[LINSIZ - 1]) { 6811500Serics if (c == EOF) { 6821500Serics if (p > Line) { 6831500Serics *p = '\0'; 6841500Serics *length = p - Line; 6851500Serics return (column); 6861500Serics } 6871500Serics *length = p - Line; 6881500Serics return (EOF); 6891500Serics } 6901500Serics if (c == '\n') { 6911500Serics Currline++; 6921500Serics break; 6931500Serics } 6941500Serics *p++ = c; 6951500Serics if (c == '\t') 6961500Serics if (hardtabs && column < promptlen && !hard) { 6971500Serics if (eraseln && !dumb) { 6981500Serics column = 1 + (column | 7); 6991500Serics tputs (eraseln, 1, putch); 7001500Serics promptlen = 0; 7011500Serics } 7021500Serics else { 7031500Serics for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 7041500Serics *p++ = ' '; 7051500Serics } 7061500Serics if (column >= promptlen) promptlen = 0; 7071500Serics } 7081500Serics } 7091500Serics else 7101500Serics column = 1 + (column | 7); 7119627Ssklower else if (c == '\b' && column > 0) 7121500Serics column--; 7131500Serics else if (c == '\r') 7141500Serics column = 0; 7151500Serics else if (c == '\f' && stop_opt) { 7161500Serics p[-1] = '^'; 7171500Serics *p++ = 'L'; 7181500Serics column += 2; 7191500Serics Pause++; 7201500Serics } 7211500Serics else if (c == EOF) { 7221500Serics *length = p - Line; 7231500Serics return (column); 7241500Serics } 7251500Serics else if (c >= ' ' && c != RUBOUT) 7261500Serics column++; 7271500Serics if (column >= Mcol && fold_opt) break; 7281500Serics c = Getc (f); 7291500Serics } 7301500Serics if (column >= Mcol && Mcol > 0) { 7311500Serics if (!Wrap) { 7321500Serics *p++ = '\n'; 7331500Serics } 7341500Serics } 7351500Serics colflg = column == Mcol && fold_opt; 7361500Serics *length = p - Line; 7371500Serics *p = 0; 7381500Serics return (column); 7391500Serics } 7401500Serics 7411500Serics /* 7421500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 7431500Serics */ 7441500Serics 7451500Serics erase (col) 7461500Serics register int col; 7471500Serics { 7481500Serics 7491500Serics if (promptlen == 0) 7501500Serics return; 7511500Serics if (hard) { 7521500Serics putchar ('\n'); 7531500Serics } 7541500Serics else { 7551500Serics if (col == 0) 7561500Serics putchar ('\r'); 7571500Serics if (!dumb && eraseln) 7581500Serics tputs (eraseln, 1, putch); 7591500Serics else 7601500Serics for (col = promptlen - col; col > 0; col--) 7611500Serics putchar (' '); 7621500Serics } 7631500Serics promptlen = 0; 7641500Serics } 7651500Serics 7661500Serics /* 7671500Serics ** Erase the current line entirely 7681500Serics */ 7691500Serics 7701500Serics kill_line () 7711500Serics { 7721500Serics erase (0); 7731500Serics if (!eraseln || dumb) putchar ('\r'); 7741500Serics } 7751500Serics 7761500Serics /* 7773455Sroot * force clear to end of line 7783455Sroot */ 7793455Sroot cleareol() 7803455Sroot { 7813594Sroot tputs(eraseln, 1, putch); 7823455Sroot } 7833455Sroot 7843594Sroot clreos() 7853455Sroot { 7863594Sroot tputs(EodClr, 1, putch); 7873455Sroot } 7883455Sroot 7893455Sroot /* 7901500Serics ** Print string and return number of characters 7911500Serics */ 7921500Serics 7931500Serics pr(s1) 7941500Serics char *s1; 7951500Serics { 7961500Serics register char *s; 7971500Serics register char c; 7981500Serics 7991500Serics for (s = s1; c = *s++; ) 8001500Serics putchar(c); 8011500Serics return (s - s1 - 1); 8021500Serics } 8031500Serics 8041500Serics 8051500Serics /* Print a buffer of n characters */ 8061500Serics 8071500Serics prbuf (s, n) 8081500Serics register char *s; 8091500Serics register int n; 8101500Serics { 81116710Sjak register char c; /* next output character */ 8123594Sroot register int state; /* next output char's UL state */ 81316710Sjak #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 8143594Sroot 8153594Sroot while (--n >= 0) 8163594Sroot if (!ul_opt) 8173594Sroot putchar (*s++); 8183594Sroot else { 81916710Sjak if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 82016710Sjak s++; 82116710Sjak continue; 82216710Sjak } 82316710Sjak if (state = wouldul(s, n)) { 82416710Sjak c = (*s == '_')? s[2] : *s ; 8253594Sroot n -= 2; 82616710Sjak s += 3; 82716710Sjak } else 8283594Sroot c = *s++; 82916710Sjak if (state != pstate) { 83016710Sjak if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 83116710Sjak state = 1; 83216710Sjak else 83316710Sjak tputs(state ? ULenter : ULexit, 1, putch); 8343594Sroot } 83516710Sjak if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 83616710Sjak putchar(c); 8373594Sroot if (state && *chUL) { 8383594Sroot pr(chBS); 8393594Sroot tputs(chUL, 1, putch); 8403594Sroot } 84116710Sjak pstate = state; 8423594Sroot } 8431500Serics } 8441500Serics 8451500Serics /* 8461500Serics ** Clear the screen 8471500Serics */ 8481500Serics 8491500Serics doclear() 8501500Serics { 8511500Serics if (Clear && !hard) { 8521500Serics tputs(Clear, 1, putch); 8531500Serics 8541500Serics /* Put out carriage return so that system doesn't 8551500Serics ** get confused by escape sequences when expanding tabs 8561500Serics */ 8571500Serics putchar ('\r'); 8581500Serics promptlen = 0; 8591500Serics } 8601500Serics } 8611500Serics 8623455Sroot /* 8633455Sroot * Go to home position 8643455Sroot */ 8653455Sroot home() 8663455Sroot { 8673455Sroot tputs(Home,1,putch); 8683455Sroot } 8693455Sroot 8701500Serics static int lastcmd, lastarg, lastp; 8711500Serics static int lastcolon; 8721500Serics char shell_line[132]; 8731500Serics 8741500Serics /* 8751500Serics ** Read a command and do it. A command consists of an optional integer 8761500Serics ** argument followed by the command character. Return the number of lines 8771500Serics ** to display in the next screenful. If there is nothing more to display 8781500Serics ** in the current file, zero is returned. 8791500Serics */ 8801500Serics 8811500Serics command (filename, f) 8821500Serics char *filename; 8831500Serics register FILE *f; 8841500Serics { 8851500Serics register int nlines; 8861500Serics register int retval; 8871500Serics register char c; 8881500Serics char colonch; 8891500Serics FILE *helpf; 8901500Serics int done; 8911500Serics char comchar, cmdbuf[80], *p; 8921500Serics 8931500Serics #define ret(val) retval=val;done++;break 8941500Serics 8951500Serics done = 0; 8961500Serics if (!errors) 8971500Serics prompt (filename); 8981500Serics else 8991500Serics errors = 0; 9001500Serics if (MBIT == RAW && slow_tty) { 9011500Serics otty.sg_flags |= MBIT; 90216582Sleres stty(fileno(stderr), &otty); 9031500Serics } 9041500Serics for (;;) { 9051500Serics nlines = number (&comchar); 9061500Serics lastp = colonch = 0; 9071500Serics if (comchar == '.') { /* Repeat last command */ 9081500Serics lastp++; 9091500Serics comchar = lastcmd; 9101500Serics nlines = lastarg; 9111500Serics if (lastcmd == ':') 9121500Serics colonch = lastcolon; 9131500Serics } 9141500Serics lastcmd = comchar; 9151500Serics lastarg = nlines; 9161500Serics if (comchar == otty.sg_erase) { 9171500Serics kill_line (); 9181500Serics prompt (filename); 9191500Serics continue; 9201500Serics } 9211500Serics switch (comchar) { 9221500Serics case ':': 9231500Serics retval = colon (filename, colonch, nlines); 9241500Serics if (retval >= 0) 9251500Serics done++; 9261500Serics break; 9271500Serics case ' ': 9281500Serics case 'z': 9291500Serics if (nlines == 0) nlines = dlines; 9301500Serics else if (comchar == 'z') dlines = nlines; 9311500Serics ret (nlines); 9321500Serics case 'd': 9331500Serics case ctrl(D): 9341500Serics if (nlines != 0) nscroll = nlines; 9351500Serics ret (nscroll); 9361500Serics case RUBOUT: 9371500Serics case 'q': 9381500Serics case 'Q': 9391500Serics end_it (); 9401500Serics case 's': 9411500Serics case 'f': 9421500Serics if (nlines == 0) nlines++; 9431500Serics if (comchar == 'f') 9441500Serics nlines *= dlines; 9451500Serics putchar ('\r'); 9461500Serics erase (0); 9473594Sroot printf ("\n"); 9483594Sroot if (clreol) 9493594Sroot cleareol (); 9503594Sroot printf ("...skipping %d line", nlines); 9511500Serics if (nlines > 1) 9523594Sroot pr ("s\n"); 9531500Serics else 9543594Sroot pr ("\n"); 9553594Sroot 9563594Sroot if (clreol) 9573594Sroot cleareol (); 9583594Sroot pr ("\n"); 9593594Sroot 9601500Serics while (nlines > 0) { 9611500Serics while ((c = Getc (f)) != '\n') 9621500Serics if (c == EOF) { 9631500Serics retval = 0; 9641500Serics done++; 9651500Serics goto endsw; 9661500Serics } 9671500Serics Currline++; 9681500Serics nlines--; 9691500Serics } 9701500Serics ret (dlines); 9711500Serics case '\n': 9721500Serics if (nlines != 0) 9731500Serics dlines = nlines; 9741500Serics else 9751500Serics nlines = 1; 9761500Serics ret (nlines); 9771500Serics case '\f': 9781500Serics if (!no_intty) { 9791500Serics doclear (); 9801500Serics Fseek (f, screen_start.chrctr); 9811500Serics Currline = screen_start.line; 9821500Serics ret (dlines); 9831500Serics } 9841500Serics else { 9851500Serics write (2, &bell, 1); 9861500Serics break; 9871500Serics } 9881500Serics case '\'': 9891500Serics if (!no_intty) { 9901500Serics kill_line (); 9911500Serics pr ("\n***Back***\n\n"); 9921500Serics Fseek (f, context.chrctr); 9931500Serics Currline = context.line; 9941500Serics ret (dlines); 9951500Serics } 9961500Serics else { 9971500Serics write (2, &bell, 1); 9981500Serics break; 9991500Serics } 10001500Serics case '=': 10011500Serics kill_line (); 10021500Serics promptlen = printd (Currline); 10031500Serics fflush (stdout); 10041500Serics break; 10051500Serics case 'n': 10061500Serics lastp++; 10071500Serics case '/': 10081500Serics if (nlines == 0) nlines++; 10091500Serics kill_line (); 10101500Serics pr ("/"); 10111500Serics promptlen = 1; 10121500Serics fflush (stdout); 10131500Serics if (lastp) { 10141500Serics write (2,"\r", 1); 10151500Serics search (NULL, f, nlines); /* Use previous r.e. */ 10161500Serics } 10171500Serics else { 10181500Serics ttyin (cmdbuf, 78, '/'); 10191500Serics write (2, "\r", 1); 10201500Serics search (cmdbuf, f, nlines); 10211500Serics } 10223455Sroot ret (dlines-1); 10231500Serics case '!': 10241500Serics do_shell (filename); 10251500Serics break; 10261500Serics case 'h': 10271500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 10281500Serics error ("Can't open help file"); 10291500Serics if (noscroll) doclear (); 10301500Serics copy_file (helpf); 10311500Serics close (helpf); 10321500Serics prompt (filename); 10331500Serics break; 10341500Serics case 'v': /* This case should go right before default */ 10351500Serics if (!no_intty) { 10361500Serics kill_line (); 10371500Serics cmdbuf[0] = '+'; 10381500Serics scanstr (Currline, &cmdbuf[1]); 10391500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 10401500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 10411500Serics break; 10421500Serics } 10431500Serics default: 104416710Sjak if (dum_opt) { 104516710Sjak kill_line (); 104616710Sjak if (Senter && Sexit) { 104716710Sjak tputs (Senter, 1, putch); 104816710Sjak promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 104916710Sjak tputs (Sexit, 1, putch); 105016710Sjak } 105116710Sjak else 105216710Sjak promptlen = pr ("[Press 'h' for instructions.]"); 105316710Sjak fflush (stdout); 105416710Sjak } 105516710Sjak else 105616710Sjak write (2, &bell, 1); 10571500Serics break; 10581500Serics } 10591500Serics if (done) break; 10601500Serics } 10611500Serics putchar ('\r'); 10621500Serics endsw: 10631500Serics inwait = 0; 10641500Serics notell++; 10651500Serics if (MBIT == RAW && slow_tty) { 10661500Serics otty.sg_flags &= ~MBIT; 106716582Sleres stty(fileno(stderr), &otty); 10681500Serics } 10691500Serics return (retval); 10701500Serics } 10711500Serics 10721500Serics char ch; 10731500Serics 10741500Serics /* 10751500Serics * Execute a colon-prefixed command. 10761500Serics * Returns <0 if not a command that should cause 10771500Serics * more of the file to be printed. 10781500Serics */ 10791500Serics 10801500Serics colon (filename, cmd, nlines) 10811500Serics char *filename; 10821500Serics int cmd; 10831500Serics int nlines; 10841500Serics { 10851500Serics if (cmd == 0) 10861500Serics ch = readch (); 10871500Serics else 10881500Serics ch = cmd; 10891500Serics lastcolon = ch; 10901500Serics switch (ch) { 10911500Serics case 'f': 10921500Serics kill_line (); 10931500Serics if (!no_intty) 10941500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 10951500Serics else 10961500Serics promptlen = printf ("[Not a file] line %d", Currline); 10971500Serics fflush (stdout); 10981500Serics return (-1); 10991500Serics case 'n': 11001500Serics if (nlines == 0) { 11011500Serics if (fnum >= nfiles - 1) 11021500Serics end_it (); 11031500Serics nlines++; 11041500Serics } 11051500Serics putchar ('\r'); 11061500Serics erase (0); 11071500Serics skipf (nlines); 11081500Serics return (0); 11091500Serics case 'p': 11101500Serics if (no_intty) { 11111500Serics write (2, &bell, 1); 11121500Serics return (-1); 11131500Serics } 11141500Serics putchar ('\r'); 11151500Serics erase (0); 11161500Serics if (nlines == 0) 11171500Serics nlines++; 11181500Serics skipf (-nlines); 11191500Serics return (0); 11201500Serics case '!': 11211500Serics do_shell (filename); 11221500Serics return (-1); 11231500Serics case 'q': 11241500Serics case 'Q': 11251500Serics end_it (); 11261500Serics default: 11271500Serics write (2, &bell, 1); 11281500Serics return (-1); 11291500Serics } 11301500Serics } 11311500Serics 11321500Serics /* 11331500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 11341500Serics ** terminates the number. 11351500Serics */ 11361500Serics 11371500Serics number(cmd) 11381500Serics char *cmd; 11391500Serics { 11401500Serics register int i; 11411500Serics 11421500Serics i = 0; ch = otty.sg_kill; 11431500Serics for (;;) { 11441500Serics ch = readch (); 11451500Serics if (ch >= '0' && ch <= '9') 11461500Serics i = i*10 + ch - '0'; 11471500Serics else if (ch == otty.sg_kill) 11481500Serics i = 0; 11491500Serics else { 11501500Serics *cmd = ch; 11511500Serics break; 11521500Serics } 11531500Serics } 11541500Serics return (i); 11551500Serics } 11561500Serics 11571500Serics do_shell (filename) 11581500Serics char *filename; 11591500Serics { 11601500Serics char cmdbuf[80]; 11611500Serics 11621500Serics kill_line (); 11631500Serics pr ("!"); 11641500Serics fflush (stdout); 11651500Serics promptlen = 1; 11661500Serics if (lastp) 11671500Serics pr (shell_line); 11681500Serics else { 11691500Serics ttyin (cmdbuf, 78, '!'); 11701500Serics if (expand (shell_line, cmdbuf)) { 11711500Serics kill_line (); 11721500Serics promptlen = printf ("!%s", shell_line); 11731500Serics } 11741500Serics } 11751500Serics fflush (stdout); 11761500Serics write (2, "\n", 1); 11771500Serics promptlen = 0; 11781500Serics shellp = 1; 11791500Serics execute (filename, shell, shell, "-c", shell_line, 0); 11801500Serics } 11811500Serics 11821500Serics /* 11831500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 11841500Serics */ 11851500Serics 11861500Serics search (buf, file, n) 11871500Serics char buf[]; 11881500Serics FILE *file; 11891500Serics register int n; 11901500Serics { 11911500Serics long startline = Ftell (file); 11921500Serics register long line1 = startline; 11931500Serics register long line2 = startline; 11941500Serics register long line3 = startline; 11951500Serics register int lncount; 11961500Serics int saveln, rv, re_exec(); 11971500Serics char *s, *re_comp(); 11981500Serics 11991500Serics context.line = saveln = Currline; 12001500Serics context.chrctr = startline; 12011500Serics lncount = 0; 12021500Serics if ((s = re_comp (buf)) != 0) 12031500Serics error (s); 12041500Serics while (!feof (file)) { 12051500Serics line3 = line2; 12061500Serics line2 = line1; 12071500Serics line1 = Ftell (file); 12081500Serics rdline (file); 12091500Serics lncount++; 12101500Serics if ((rv = re_exec (Line)) == 1) 12111500Serics if (--n == 0) { 12121500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 12133455Sroot { 12143455Sroot pr ("\n"); 12153594Sroot if (clreol) 12163594Sroot cleareol (); 12173455Sroot pr("...skipping\n"); 12183455Sroot } 12191500Serics if (!no_intty) { 12201500Serics Currline -= (lncount >= 3 ? 3 : lncount); 12211500Serics Fseek (file, line3); 12223594Sroot if (noscroll) 12233594Sroot if (clreol) { 12243594Sroot home (); 12253594Sroot cleareol (); 122616582Sleres } 12273594Sroot else 12283594Sroot doclear (); 12291500Serics } 12301500Serics else { 12311500Serics kill_line (); 12323594Sroot if (noscroll) 12333594Sroot if (clreol) { 123416582Sleres home (); 12353594Sroot cleareol (); 123616582Sleres } 12373594Sroot else 12383594Sroot doclear (); 12391500Serics pr (Line); 12401500Serics putchar ('\n'); 12411500Serics } 12421500Serics break; 12431500Serics } 12441500Serics else if (rv == -1) 12451500Serics error ("Regular expression botch"); 12461500Serics } 12471500Serics if (feof (file)) { 12481500Serics if (!no_intty) { 12491500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 12501500Serics Currline = saveln; 12511500Serics Fseek (file, startline); 12521500Serics } 12531500Serics else { 12541500Serics pr ("\nPattern not found\n"); 12551500Serics end_it (); 12561500Serics } 12571500Serics error ("Pattern not found"); 12581500Serics } 12591500Serics } 12601500Serics 12611500Serics execute (filename, cmd, args) 12621500Serics char *filename; 12631500Serics char *cmd, *args; 12641500Serics { 12651500Serics int id; 126616710Sjak int n; 12671500Serics 12681500Serics fflush (stdout); 12691500Serics reset_tty (); 127016710Sjak for (n = 10; (id = fork ()) < 0 && n > 0; n--) 12711500Serics sleep (5); 12721500Serics if (id == 0) { 127316710Sjak if (!isatty(0)) { 127416710Sjak close(0); 127516710Sjak open("/dev/tty", 0); 127616710Sjak } 12771500Serics execv (cmd, &args); 12781500Serics write (2, "exec failed\n", 12); 12791500Serics exit (1); 12801500Serics } 128116710Sjak if (id > 0) { 128216710Sjak signal (SIGINT, SIG_IGN); 128316710Sjak signal (SIGQUIT, SIG_IGN); 128416710Sjak if (catch_susp) 128516710Sjak signal(SIGTSTP, SIG_DFL); 128616710Sjak while (wait(0) > 0); 128716710Sjak signal (SIGINT, end_it); 128816710Sjak signal (SIGQUIT, onquit); 128916710Sjak if (catch_susp) 129016710Sjak signal(SIGTSTP, onsusp); 129116710Sjak } else 129216710Sjak write(2, "can't fork\n", 11); 12931500Serics set_tty (); 12941500Serics pr ("------------------------\n"); 12951500Serics prompt (filename); 12961500Serics } 12971500Serics /* 12981500Serics ** Skip n lines in the file f 12991500Serics */ 13001500Serics 13011500Serics skiplns (n, f) 13021500Serics register int n; 13031500Serics register FILE *f; 13041500Serics { 13051500Serics register char c; 13061500Serics 13071500Serics while (n > 0) { 13081500Serics while ((c = Getc (f)) != '\n') 13091500Serics if (c == EOF) 13101500Serics return; 13111500Serics n--; 13121500Serics Currline++; 13131500Serics } 13141500Serics } 13151500Serics 13161500Serics /* 13171500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 13181500Serics ** negative. 13191500Serics */ 13201500Serics 13211500Serics skipf (nskip) 13221500Serics register int nskip; 13231500Serics { 13241500Serics if (nskip == 0) return; 13251500Serics if (nskip > 0) { 13261500Serics if (fnum + nskip > nfiles - 1) 13271500Serics nskip = nfiles - fnum - 1; 13281500Serics } 13291500Serics else if (within) 13301500Serics ++fnum; 13311500Serics fnum += nskip; 13321500Serics if (fnum < 0) 13331500Serics fnum = 0; 13343594Sroot pr ("\n...Skipping "); 13353455Sroot pr ("\n"); 13363594Sroot if (clreol) 13373594Sroot cleareol (); 13383455Sroot pr ("...Skipping "); 13391500Serics pr (nskip > 0 ? "to file " : "back to file "); 13401500Serics pr (fnames[fnum]); 13413455Sroot pr ("\n"); 13423594Sroot if (clreol) 13433594Sroot cleareol (); 13443455Sroot pr ("\n"); 13451500Serics --fnum; 13461500Serics } 13471500Serics 13481500Serics /*----------------------------- Terminal I/O -------------------------------*/ 13491500Serics 13501500Serics initterm () 13511500Serics { 13521500Serics char buf[TBUFSIZ]; 1353*17195Sralph static char clearbuf[TBUFSIZ]; 13541500Serics char *clearptr, *padstr; 13551500Serics int ldisc; 135610823Ssam char *term; 135716582Sleres int tgrp; 13581500Serics 135916582Sleres retry: 136016582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 136116582Sleres /* 136216582Sleres * Wait until we're in the foreground before we get the 136316582Sleres * save the terminal modes. 136416582Sleres */ 136516582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 136616582Sleres perror("ioctl"); 136716582Sleres exit(1); 136816582Sleres } 136916582Sleres if (tgrp != getpgrp(0)) { 137016582Sleres kill(0, SIGTTOU); 137116582Sleres goto retry; 137216582Sleres } 137313830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 13743594Sroot dumb++; ul_opt = 0; 13751500Serics } 13761500Serics else { 13771500Serics if (((Lpp = tgetnum("li")) < 0) || tgetflag("hc")) { 13781500Serics hard++; /* Hard copy terminal */ 13791500Serics Lpp = 24; 13801500Serics } 13811500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 13821500Serics noscroll++; 13831500Serics if ((Mcol = tgetnum("co")) < 0) 13841500Serics Mcol = 80; 13851500Serics Wrap = tgetflag("am"); 13861500Serics bad_so = tgetflag ("xs"); 13871500Serics clearptr = clearbuf; 13881500Serics eraseln = tgetstr("ce",&clearptr); 13891500Serics Clear = tgetstr("cl", &clearptr); 13901500Serics Senter = tgetstr("so", &clearptr); 13911500Serics Sexit = tgetstr("se", &clearptr); 139216710Sjak if ((soglitch = tgetnum("sg")) < 0) 139316710Sjak soglitch = 0; 13943594Sroot 13953594Sroot /* 13963594Sroot * Set up for underlining: some terminals don't need it; 13973594Sroot * others have start/stop sequences, still others have an 13983594Sroot * underline char sequence which is assumed to move the 13993594Sroot * cursor forward one character. If underline sequence 14003594Sroot * isn't available, settle for standout sequence. 14013594Sroot */ 14023594Sroot 14033594Sroot if (tgetflag("ul") || tgetflag("os")) 14043594Sroot ul_opt = 0; 14053594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 14063594Sroot chUL = ""; 140716710Sjak if (((ULenter = tgetstr("us", &clearptr)) == NULL || 140816710Sjak (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 140916710Sjak if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 141016710Sjak ULenter = ""; 141116710Sjak ULexit = ""; 141216710Sjak } else 141316710Sjak ulglitch = soglitch; 141416710Sjak } else { 141516710Sjak if ((ulglitch = tgetnum("ug")) < 0) 141616710Sjak ulglitch = 0; 141716710Sjak } 141816582Sleres 14191500Serics if (padstr = tgetstr("pc", &clearptr)) 14201500Serics PC = *padstr; 14213455Sroot Home = tgetstr("ho",&clearptr); 142213536Ssam if (Home == 0 || *Home == '\0') 14233455Sroot { 14243594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 14253594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 14263455Sroot Home = cursorhome; 14273455Sroot } 14283455Sroot } 14293594Sroot EodClr = tgetstr("cd", &clearptr); 14301500Serics } 14311500Serics if ((shell = getenv("SHELL")) == NULL) 14321500Serics shell = "/bin/sh"; 14331500Serics } 143416582Sleres no_intty = gtty(fileno(stdin), &otty); 143516582Sleres gtty(fileno(stderr), &otty); 143613830Skre savetty = otty; 14371500Serics ospeed = otty.sg_ospeed; 14381500Serics slow_tty = ospeed < B1200; 14391500Serics hardtabs = !(otty.sg_flags & XTABS); 14401500Serics if (!no_tty) { 14411500Serics otty.sg_flags &= ~ECHO; 14421500Serics if (MBIT == CBREAK || !slow_tty) 14431500Serics otty.sg_flags |= MBIT; 14441500Serics } 14451500Serics } 14461500Serics 14471500Serics readch () 14481500Serics { 14491500Serics char ch; 14501500Serics extern int errno; 14511500Serics 14521500Serics if (read (2, &ch, 1) <= 0) 14531500Serics if (errno != EINTR) 14541500Serics exit(0); 14551500Serics else 14561500Serics ch = otty.sg_kill; 14571500Serics return (ch); 14581500Serics } 14591500Serics 14601500Serics static char BS = '\b'; 14611500Serics static char CARAT = '^'; 14621500Serics 14631500Serics ttyin (buf, nmax, pchar) 14641500Serics char buf[]; 14651500Serics register int nmax; 14661500Serics char pchar; 14671500Serics { 14681500Serics register char *sptr; 14691500Serics register char ch; 14701500Serics register int slash = 0; 14711500Serics int maxlen; 14721500Serics char cbuf; 14731500Serics 14741500Serics sptr = buf; 14751500Serics maxlen = 0; 14761500Serics while (sptr - buf < nmax) { 14771500Serics if (promptlen > maxlen) maxlen = promptlen; 14781500Serics ch = readch (); 14791500Serics if (ch == '\\') { 14801500Serics slash++; 14811500Serics } 14821500Serics else if ((ch == otty.sg_erase) && !slash) { 14831500Serics if (sptr > buf) { 14841500Serics --promptlen; 14851500Serics write (2, &BS, 1); 14861500Serics --sptr; 14871500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 14881500Serics --promptlen; 14891500Serics write (2, &BS, 1); 14901500Serics } 14911500Serics continue; 14921500Serics } 14931500Serics else { 14941500Serics if (!eraseln) promptlen = maxlen; 14951500Serics longjmp (restore, 1); 14961500Serics } 14971500Serics } 14981500Serics else if ((ch == otty.sg_kill) && !slash) { 14991500Serics if (hard) { 15001500Serics show (ch); 15011500Serics putchar ('\n'); 15021500Serics putchar (pchar); 15031500Serics } 15041500Serics else { 15051500Serics putchar ('\r'); 15061500Serics putchar (pchar); 15071500Serics if (eraseln) 15081500Serics erase (1); 15091500Serics promptlen = 1; 15101500Serics } 15111500Serics sptr = buf; 15121500Serics fflush (stdout); 15131500Serics continue; 15141500Serics } 15151500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 15161500Serics write (2, &BS, 1); 15171500Serics --sptr; 15181500Serics } 15191500Serics if (ch != '\\') 15201500Serics slash = 0; 15211500Serics *sptr++ = ch; 15221500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 15231500Serics ch += ch == RUBOUT ? -0100 : 0100; 15241500Serics write (2, &CARAT, 1); 15251500Serics promptlen++; 15261500Serics } 15271500Serics cbuf = ch; 15281500Serics if (ch != '\n' && ch != ESC) { 15291500Serics write (2, &cbuf, 1); 15301500Serics promptlen++; 15311500Serics } 15321500Serics else 15331500Serics break; 15341500Serics } 15351500Serics *--sptr = '\0'; 15361500Serics if (!eraseln) promptlen = maxlen; 15371500Serics if (sptr - buf >= nmax - 1) 15381500Serics error ("Line too long"); 15391500Serics } 15401500Serics 15411500Serics expand (outbuf, inbuf) 15421500Serics char *outbuf; 15431500Serics char *inbuf; 15441500Serics { 15451500Serics register char *instr; 15461500Serics register char *outstr; 15471500Serics register char ch; 15481500Serics char temp[200]; 15491500Serics int changed = 0; 15501500Serics 15511500Serics instr = inbuf; 15521500Serics outstr = temp; 15531500Serics while ((ch = *instr++) != '\0') 15541500Serics switch (ch) { 15551500Serics case '%': 15561500Serics if (!no_intty) { 15571500Serics strcpy (outstr, fnames[fnum]); 15581500Serics outstr += strlen (fnames[fnum]); 15591500Serics changed++; 15601500Serics } 15611500Serics else 15621500Serics *outstr++ = ch; 15631500Serics break; 15641500Serics case '!': 15651500Serics if (!shellp) 15661500Serics error ("No previous command to substitute for"); 15671500Serics strcpy (outstr, shell_line); 15681500Serics outstr += strlen (shell_line); 15691500Serics changed++; 15701500Serics break; 15711500Serics case '\\': 15721500Serics if (*instr == '%' || *instr == '!') { 15731500Serics *outstr++ = *instr++; 15741500Serics break; 15751500Serics } 15761500Serics default: 15771500Serics *outstr++ = ch; 15781500Serics } 15791500Serics *outstr++ = '\0'; 15801500Serics strcpy (outbuf, temp); 15811500Serics return (changed); 15821500Serics } 15831500Serics 15841500Serics show (ch) 15851500Serics register char ch; 15861500Serics { 15871500Serics char cbuf; 15881500Serics 15891500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 15901500Serics ch += ch == RUBOUT ? -0100 : 0100; 15911500Serics write (2, &CARAT, 1); 15921500Serics promptlen++; 15931500Serics } 15941500Serics cbuf = ch; 15951500Serics write (2, &cbuf, 1); 15961500Serics promptlen++; 15971500Serics } 15981500Serics 15991500Serics error (mess) 16001500Serics char *mess; 16011500Serics { 16023594Sroot if (clreol) 16033594Sroot cleareol (); 16043594Sroot else 16053594Sroot kill_line (); 16061500Serics promptlen += strlen (mess); 16071500Serics if (Senter && Sexit) { 16081500Serics tputs (Senter, 1, putch); 16091500Serics pr(mess); 16101500Serics tputs (Sexit, 1, putch); 16111500Serics } 16121500Serics else 16131500Serics pr (mess); 16141500Serics fflush(stdout); 16151500Serics errors++; 16161500Serics longjmp (restore, 1); 16171500Serics } 16181500Serics 16191500Serics 16201500Serics set_tty () 16211500Serics { 16221500Serics otty.sg_flags |= MBIT; 16231500Serics otty.sg_flags &= ~ECHO; 162416582Sleres stty(fileno(stderr), &otty); 16251500Serics } 16261500Serics 16271500Serics reset_tty () 16281500Serics { 162916710Sjak if (pstate) { 163016710Sjak tputs(ULexit, 1, putch); 163116710Sjak fflush(stdout); 163216710Sjak pstate = 0; 163316710Sjak } 16341500Serics otty.sg_flags |= ECHO; 16351500Serics otty.sg_flags &= ~MBIT; 163616582Sleres stty(fileno(stderr), &savetty); 16371500Serics } 16381500Serics 16391500Serics rdline (f) 16401500Serics register FILE *f; 16411500Serics { 16421500Serics register char c; 16431500Serics register char *p; 16441500Serics 16451500Serics p = Line; 16461500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 16471500Serics *p++ = c; 16481500Serics if (c == '\n') 16491500Serics Currline++; 16501500Serics *p = '\0'; 16511500Serics } 16521500Serics 16531500Serics /* Come here when we get a suspend signal from the terminal */ 16541500Serics 16551500Serics onsusp () 16561500Serics { 165714861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 165814861Skarels signal(SIGTTOU, SIG_IGN); 16591500Serics reset_tty (); 16601500Serics fflush (stdout); 166114861Skarels signal(SIGTTOU, SIG_DFL); 16621500Serics /* Send the TSTP signal to suspend our process group */ 166313289Ssam signal(SIGTSTP, SIG_DFL); 166413289Ssam sigsetmask(0); 16651500Serics kill (0, SIGTSTP); 16661500Serics /* Pause for station break */ 16671500Serics 16681500Serics /* We're back */ 16691500Serics signal (SIGTSTP, onsusp); 16701500Serics set_tty (); 16711500Serics if (inwait) 16721500Serics longjmp (restore); 16731500Serics } 1674