113615Ssam #ifndef lint 2*16582Sleres static char *sccsid = "@(#)more.c 4.18 (Berkeley) 84/06/07"; 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 42*16582Sleres struct sgttyb otty, savetty; 431500Serics long file_pos, file_size; 441500Serics int fnum, no_intty, no_tty, slow_tty; 451500Serics int dum_opt, dlines, onquit(), end_it(); 461500Serics int onsusp(); 471500Serics int nscroll = 11; /* Number of lines scrolled by 'd' */ 481500Serics int fold_opt = 1; /* Fold long lines */ 491500Serics int stop_opt = 1; /* Stop after form feeds */ 503594Sroot int ssp_opt = 0; /* Suppress white space */ 513594Sroot int ul_opt = 1; /* Underline as best we can */ 521500Serics int promptlen; 531500Serics int Currline; /* Line we are currently at */ 541500Serics int startup = 1; 551500Serics int firstf = 1; 561500Serics int notell = 1; 571500Serics int bad_so; /* True if overwriting does not turn off standout */ 581500Serics int inwait, Pause, errors; 591500Serics int within; /* true if we are within a file, 601500Serics false if we are between files */ 613594Sroot int hard, dumb, noscroll, hardtabs, clreol; 621500Serics int catch_susp; /* We should catch the SIGTSTP signal */ 631500Serics char **fnames; /* The list of file names */ 641500Serics int nfiles; /* Number of files left to process */ 651500Serics char *shell; /* The name of the shell to use */ 661500Serics int shellp; /* A previous shell command exists */ 671500Serics char ch; 681500Serics jmp_buf restore; 691500Serics char obuf[BUFSIZ]; /* stdout buffer */ 701500Serics char Line[LINSIZ]; /* Line buffer */ 711500Serics int Lpp = 24; /* lines per page */ 721500Serics char *Clear; /* clear screen */ 731500Serics char *eraseln; /* erase line */ 741500Serics char *Senter, *Sexit;/* enter and exit standout mode */ 753594Sroot char *ULenter, *ULexit; /* enter and exit underline mode */ 763594Sroot char *chUL; /* underline character */ 773594Sroot char *chBS; /* backspace character */ 783455Sroot char *Home; /* go to home */ 793455Sroot char *cursorm; /* cursor movement */ 803455Sroot char cursorhome[40]; /* contains cursor movement to home */ 813594Sroot char *EodClr; /* clear rest of screen */ 821500Serics char *tgetstr(); 831500Serics int Mcol = 80; /* number of columns */ 841500Serics int Wrap = 1; /* set if automargins */ 851500Serics long fseek(); 863455Sroot char *getenv(); 871500Serics struct { 881500Serics long chrctr, line; 891500Serics } context, screen_start; 901500Serics extern char PC; /* pad character */ 911500Serics extern short ospeed; 921500Serics 931500Serics 941500Serics main(argc, argv) 951500Serics int argc; 961500Serics char *argv[]; 971500Serics { 981500Serics register FILE *f; 991500Serics register char *s; 1001500Serics register char *p; 1011500Serics register char ch; 1021500Serics register int left; 103*16582Sleres int prnames = 0; 1041500Serics int initopt = 0; 1051500Serics int srchopt = 0; 1061500Serics int clearit = 0; 1071500Serics int initline; 1081500Serics char initbuf[80]; 1091500Serics FILE *checkf(); 1101500Serics 1111500Serics nfiles = argc; 1121500Serics fnames = argv; 1131500Serics initterm (); 11415813Sralph nscroll = Lpp/2 - 1; 11515813Sralph if (nscroll <= 0) 11615813Sralph nscroll = 1; 1173455Sroot if(s = getenv("MORE")) argscan(s); 1181500Serics while (--nfiles > 0) { 1191500Serics if ((ch = (*++fnames)[0]) == '-') { 1203455Sroot argscan(*fnames+1); 1211500Serics } 1221500Serics else if (ch == '+') { 1231500Serics s = *fnames; 1241500Serics if (*++s == '/') { 1251500Serics srchopt++; 1261500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1271500Serics *p++ = *s++; 1281500Serics *p = '\0'; 1291500Serics } 1301500Serics else { 1311500Serics initopt++; 1321500Serics for (initline = 0; *s != '\0'; s++) 1331500Serics if (isdigit (*s)) 1341500Serics initline = initline*10 + *s -'0'; 1351500Serics --initline; 1361500Serics } 1371500Serics } 1381500Serics else break; 1391500Serics } 1403594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1413455Sroot * defined, and in that case, make sure we are in noscroll mode 1423455Sroot */ 1433455Sroot if(clreol) 1443455Sroot { 1453594Sroot if ((*Home == '\0') || (*eraseln == '\0') || (*EodClr == '\0')) 1463594Sroot clreol = 0; 1473455Sroot else noscroll = 1; 1483455Sroot } 1493455Sroot 1501500Serics if (dlines == 0) 1511500Serics dlines = Lpp - (noscroll ? 1 : 2); 1521500Serics left = dlines; 1531500Serics if (nfiles > 1) 1541500Serics prnames++; 1551500Serics if (!no_intty && nfiles == 0) { 1561500Serics fputs("Usage: ",stderr); 1571500Serics fputs(argv[0],stderr); 1581500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1591500Serics exit(1); 1601500Serics } 1611500Serics else 1621500Serics f = stdin; 1631500Serics if (!no_tty) { 1641500Serics signal(SIGQUIT, onquit); 1651500Serics signal(SIGINT, end_it); 1661500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1671500Serics signal(SIGTSTP, onsusp); 1681500Serics catch_susp++; 1691500Serics } 170*16582Sleres stty (fileno(stderr), &otty); 1711500Serics } 1721500Serics if (no_intty) { 1731500Serics if (no_tty) 1741500Serics copy_file (stdin); 1751500Serics else { 1761500Serics if ((ch = Getc (f)) == '\f') 1773594Sroot doclear(); 1781500Serics else { 1791500Serics Ungetc (ch, f); 1803594Sroot if (noscroll && (ch != EOF)) { 1813594Sroot if (clreol) 1823594Sroot home (); 1833594Sroot else 1843594Sroot doclear (); 1853455Sroot } 1861500Serics } 1871500Serics if (srchopt) 1883455Sroot { 1891500Serics search (initbuf, stdin, 1); 1903594Sroot if (noscroll) 1913594Sroot left--; 1923455Sroot } 1931500Serics else if (initopt) 1941500Serics skiplns (initline, stdin); 1951500Serics screen (stdin, left); 1961500Serics } 1971500Serics no_intty = 0; 1981500Serics prnames++; 1991500Serics firstf = 0; 2001500Serics } 2011500Serics 2021500Serics while (fnum < nfiles) { 2031500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2041500Serics context.line = context.chrctr = 0; 2051500Serics Currline = 0; 2061500Serics if (firstf) setjmp (restore); 2071500Serics if (firstf) { 2081500Serics firstf = 0; 2091500Serics if (srchopt) 2103455Sroot { 2111500Serics search (initbuf, f, 1); 2123594Sroot if (noscroll) 2133594Sroot left--; 2143455Sroot } 2151500Serics else if (initopt) 2161500Serics skiplns (initline, f); 2171500Serics } 2181500Serics else if (fnum < nfiles && !no_tty) { 2191500Serics setjmp (restore); 2201500Serics left = command (fnames[fnum], f); 2211500Serics } 2221500Serics if (left != 0) { 2233594Sroot if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 2243594Sroot if (clreol) 2253594Sroot home (); 2263594Sroot else 2273594Sroot doclear (); 2281500Serics if (prnames) { 2291500Serics if (bad_so) 2301500Serics erase (0); 2313594Sroot if (clreol) 2323594Sroot cleareol (); 2331500Serics pr("::::::::::::::"); 2341500Serics if (promptlen > 14) 2351500Serics erase (14); 2363455Sroot printf ("\n"); 2373455Sroot if(clreol) cleareol(); 2383455Sroot printf("%s\n", fnames[fnum]); 2393455Sroot if(clreol) cleareol(); 2403455Sroot printf("::::::::::::::\n", fnames[fnum]); 2411500Serics if (left > Lpp - 4) 2421500Serics left = Lpp - 4; 2431500Serics } 2441500Serics if (no_tty) 2451500Serics copy_file (f); 2461500Serics else { 2471500Serics within++; 2481500Serics screen(f, left); 2491500Serics within = 0; 2501500Serics } 2511500Serics } 2521500Serics setjmp (restore); 2531500Serics fflush(stdout); 2541500Serics fclose(f); 2551500Serics screen_start.line = screen_start.chrctr = 0L; 2561500Serics context.line = context.chrctr = 0L; 2571500Serics } 2581500Serics fnum++; 2591500Serics firstf = 0; 2601500Serics } 2611500Serics reset_tty (); 2621500Serics exit(0); 2631500Serics } 2641500Serics 2653455Sroot argscan(s) 2663455Sroot char *s; 2673455Sroot { 26811604Slayer for (dlines = 0; *s != '\0'; s++) 26911604Slayer { 27011604Slayer switch (*s) 27111604Slayer { 27211604Slayer case '0': case '1': case '2': 27311604Slayer case '3': case '4': case '5': 27411604Slayer case '6': case '7': case '8': 27511604Slayer case '9': 27611604Slayer dlines = dlines*10 + *s - '0'; 27711604Slayer break; 27811604Slayer case 'd': 27911604Slayer dum_opt = 1; 28011604Slayer break; 28111604Slayer case 'l': 28211604Slayer stop_opt = 0; 28311604Slayer break; 28411604Slayer case 'f': 28511604Slayer fold_opt = 0; 28611604Slayer break; 28711604Slayer case 'p': 28811604Slayer noscroll++; 28911604Slayer break; 29011604Slayer case 'c': 29111604Slayer clreol++; 29211604Slayer break; 29311604Slayer case 's': 29411604Slayer ssp_opt = 1; 29511604Slayer break; 29611604Slayer case 'u': 29711604Slayer ul_opt = 0; 29811604Slayer break; 29911604Slayer } 30011604Slayer } 3013455Sroot } 3023455Sroot 3033455Sroot 3041500Serics /* 3051500Serics ** Check whether the file named by fs is an ASCII file which the user may 3061500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3071500Serics */ 3081500Serics 3091500Serics FILE * 3101500Serics checkf (fs, clearfirst) 3111500Serics register char *fs; 3121500Serics int *clearfirst; 3131500Serics { 3141500Serics struct stat stbuf; 3151500Serics register FILE *f; 3161500Serics char c; 3171500Serics 3181500Serics if (stat (fs, &stbuf) == -1) { 3191500Serics fflush(stdout); 3203594Sroot if (clreol) 3213594Sroot cleareol (); 3221500Serics perror(fs); 3231500Serics return (NULL); 3241500Serics } 3251500Serics if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3261500Serics printf("\n*** %s: directory ***\n\n", fs); 3271500Serics return (NULL); 3281500Serics } 3291500Serics if ((f=Fopen(fs, "r")) == NULL) { 3301500Serics fflush(stdout); 3311500Serics perror(fs); 3321500Serics return (NULL); 3331500Serics } 3341500Serics c = Getc(f); 3351500Serics 3361500Serics /* Try to see whether it is an ASCII file */ 3371500Serics 3381500Serics switch ((c | *f->_ptr << 8) & 0177777) { 3391500Serics case 0405: 3401500Serics case 0407: 3411500Serics case 0410: 3421500Serics case 0411: 3431500Serics case 0413: 3441500Serics case 0177545: 3451500Serics printf("\n******** %s: Not a text file ********\n\n", fs); 3461500Serics fclose (f); 3471500Serics return (NULL); 3481500Serics default: 3491500Serics break; 3501500Serics } 3511500Serics if (c == '\f') 3521500Serics *clearfirst = 1; 3531500Serics else { 3541500Serics *clearfirst = 0; 3551500Serics Ungetc (c, f); 3561500Serics } 3571500Serics if ((file_size = stbuf.st_size) == 0) 3581500Serics file_size = 0x7fffffffffffffffL; 3591500Serics return (f); 3601500Serics } 3611500Serics 3621500Serics /* 3631500Serics ** A real function, for the tputs routine in termlib 3641500Serics */ 3651500Serics 3661500Serics putch (ch) 3671500Serics char ch; 3681500Serics { 3691500Serics putchar (ch); 3701500Serics } 3711500Serics 3721500Serics /* 3731500Serics ** Print out the contents of the file f, one screenful at a time. 3741500Serics */ 3751500Serics 3761500Serics #define STOP -10 3771500Serics 3781500Serics screen (f, num_lines) 3791500Serics register FILE *f; 3801500Serics register int num_lines; 3811500Serics { 3821500Serics register int c; 3831500Serics register int nchars; 3843594Sroot int length; /* length of current line */ 3853594Sroot static int prev_len = 1; /* length of previous line */ 3861500Serics 3871500Serics for (;;) { 3881500Serics while (num_lines > 0 && !Pause) { 3891500Serics if ((nchars = getline (f, &length)) == EOF) 3903455Sroot { 3913594Sroot if (clreol) 3923594Sroot clreos(); 3931500Serics return; 3943455Sroot } 3953594Sroot if (ssp_opt && length == 0 && prev_len == 0) 3963594Sroot continue; 3973594Sroot prev_len = length; 3981500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 3991500Serics erase (0); 4003594Sroot /* must clear before drawing line since tabs on some terminals 4013594Sroot * do not erase what they tab over. 4023594Sroot */ 4033594Sroot if (clreol) 4043594Sroot cleareol (); 4051500Serics prbuf (Line, length); 4061500Serics if (nchars < promptlen) 4071500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4081500Serics else promptlen = 0; 4093594Sroot /* is this needed? 4103594Sroot * if (clreol) 4113594Sroot * cleareol(); /* must clear again in case we wrapped * 4123594Sroot */ 4131500Serics if (nchars < Mcol || !fold_opt) 4141500Serics putchar('\n'); 4151500Serics if (nchars == STOP) 4161500Serics break; 4171500Serics num_lines--; 4181500Serics } 4191500Serics fflush(stdout); 4201500Serics if ((c = Getc(f)) == EOF) 4213455Sroot { 4223594Sroot if (clreol) 4233594Sroot clreos (); 4241500Serics return; 4253455Sroot } 4263455Sroot 4273594Sroot if (Pause && clreol) 4283594Sroot clreos (); 4291500Serics Ungetc (c, f); 4301500Serics setjmp (restore); 4311500Serics Pause = 0; startup = 0; 4321500Serics if ((num_lines = command (NULL, f)) == 0) 4331500Serics return; 4341500Serics if (hard && promptlen > 0) 4351500Serics erase (0); 43611123Slayer if (noscroll && num_lines >= dlines) 437*16582Sleres { 4383594Sroot if (clreol) 4393594Sroot home(); 4403594Sroot else 4413594Sroot doclear (); 4423455Sroot } 4431500Serics screen_start.line = Currline; 4441500Serics screen_start.chrctr = Ftell (f); 4451500Serics } 4461500Serics } 4471500Serics 4481500Serics /* 4491500Serics ** Come here if a quit signal is received 4501500Serics */ 4511500Serics 4521500Serics onquit() 4531500Serics { 4541500Serics signal(SIGQUIT, SIG_IGN); 4551500Serics if (!inwait) { 4561500Serics putchar ('\n'); 4571500Serics if (!startup) { 4581500Serics signal(SIGQUIT, onquit); 4591500Serics longjmp (restore, 1); 4601500Serics } 4611500Serics else 4621500Serics Pause++; 4631500Serics } 4641500Serics else if (!dum_opt && notell) { 4651500Serics write (2, "[Use q or Q to quit]", 20); 4661500Serics promptlen += 20; 4671500Serics notell = 0; 4681500Serics } 4691500Serics signal(SIGQUIT, onquit); 4701500Serics } 4711500Serics 4721500Serics /* 4731500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 4741500Serics */ 4751500Serics 4761500Serics end_it () 4771500Serics { 4781500Serics 4791500Serics reset_tty (); 4803594Sroot if (clreol) { 4813594Sroot putchar ('\r'); 4823594Sroot clreos (); 4833594Sroot fflush (stdout); 4843594Sroot } 4853455Sroot else if (!clreol && (promptlen > 0)) { 4861500Serics kill_line (); 4871500Serics fflush (stdout); 4881500Serics } 4891500Serics else 4901500Serics write (2, "\n", 1); 4911500Serics _exit(0); 4921500Serics } 4931500Serics 4941500Serics copy_file(f) 4951500Serics register FILE *f; 4961500Serics { 4971500Serics register int c; 4981500Serics 4991500Serics while ((c = getc(f)) != EOF) 5001500Serics putchar(c); 5011500Serics } 5021500Serics 5031500Serics /* Simplified printf function */ 5041500Serics 5051500Serics printf (fmt, args) 5061500Serics register char *fmt; 5071500Serics int args; 5081500Serics { 5091500Serics register int *argp; 5101500Serics register char ch; 5111500Serics register int ccount; 5121500Serics 5131500Serics ccount = 0; 5141500Serics argp = &args; 5151500Serics while (*fmt) { 5161500Serics while ((ch = *fmt++) != '%') { 5171500Serics if (ch == '\0') 5181500Serics return (ccount); 5191500Serics ccount++; 5201500Serics putchar (ch); 5211500Serics } 5221500Serics switch (*fmt++) { 5231500Serics case 'd': 5241500Serics ccount += printd (*argp); 5251500Serics break; 5261500Serics case 's': 5271500Serics ccount += pr ((char *)*argp); 5281500Serics break; 5291500Serics case '%': 5301500Serics ccount++; 5311500Serics argp--; 5321500Serics putchar ('%'); 5331500Serics break; 5341500Serics case '0': 5351500Serics return (ccount); 5361500Serics default: 5371500Serics break; 5381500Serics } 5391500Serics ++argp; 5401500Serics } 5411500Serics return (ccount); 5421500Serics 5431500Serics } 5441500Serics 5451500Serics /* 5461500Serics ** Print an integer as a string of decimal digits, 5471500Serics ** returning the length of the print representation. 5481500Serics */ 5491500Serics 5501500Serics printd (n) 5511500Serics int n; 5521500Serics { 5531500Serics int a, nchars; 5541500Serics 5551500Serics if (a = n/10) 5561500Serics nchars = 1 + printd(a); 5571500Serics else 5581500Serics nchars = 1; 5591500Serics putchar (n % 10 + '0'); 5601500Serics return (nchars); 5611500Serics } 5621500Serics 5631500Serics /* Put the print representation of an integer into a string */ 5641500Serics static char *sptr; 5651500Serics 5661500Serics scanstr (n, str) 5671500Serics int n; 5681500Serics char *str; 5691500Serics { 5701500Serics sptr = str; 57111604Slayer Sprintf (n); 5721500Serics *sptr = '\0'; 5731500Serics } 5741500Serics 57511604Slayer Sprintf (n) 5761500Serics { 5771500Serics int a; 5781500Serics 5791500Serics if (a = n/10) 58011604Slayer Sprintf (a); 5811500Serics *sptr++ = n % 10 + '0'; 5821500Serics } 5831500Serics 5841500Serics static char bell = ctrl(G); 5851500Serics 5861500Serics strlen (s) 5871500Serics char *s; 5881500Serics { 5891500Serics register char *p; 5901500Serics 5911500Serics p = s; 5921500Serics while (*p++) 5931500Serics ; 5941500Serics return (p - s - 1); 5951500Serics } 5961500Serics 5971500Serics /* See whether the last component of the path name "path" is equal to the 5981500Serics ** string "string" 5991500Serics */ 6001500Serics 6011500Serics tailequ (path, string) 6021500Serics char *path; 6031500Serics register char *string; 6041500Serics { 6051500Serics register char *tail; 6061500Serics 6071500Serics tail = path + strlen(path); 6081500Serics while (tail >= path) 6091500Serics if (*(--tail) == '/') 6101500Serics break; 6111500Serics ++tail; 6121500Serics while (*tail++ == *string++) 6131500Serics if (*tail == '\0') 6141500Serics return(1); 6151500Serics return(0); 6161500Serics } 6171500Serics 6181500Serics prompt (filename) 6191500Serics char *filename; 6201500Serics { 6213594Sroot if (clreol) 6223594Sroot cleareol (); 6233455Sroot else if (promptlen > 0) 6241500Serics kill_line (); 6251500Serics if (!hard) { 6261500Serics promptlen = 8; 6271500Serics if (Senter && Sexit) 6281500Serics tputs (Senter, 1, putch); 6293594Sroot if (clreol) 6303594Sroot cleareol (); 6311500Serics pr("--More--"); 6321500Serics if (filename != NULL) { 6331500Serics promptlen += printf ("(Next file: %s)", filename); 6341500Serics } 6351500Serics else if (!no_intty) { 6361500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 6371500Serics } 6381500Serics if (dum_opt) { 6391500Serics promptlen += pr("[Hit space to continue, Rubout to abort]"); 6401500Serics } 6411500Serics if (Senter && Sexit) 6421500Serics tputs (Sexit, 1, putch); 6433594Sroot if (clreol) 6443594Sroot clreos (); 6451500Serics fflush(stdout); 6461500Serics } 6471500Serics else 6481500Serics write (2, &bell, 1); 6491500Serics inwait++; 6501500Serics } 6511500Serics 6521500Serics /* 6531500Serics ** Get a logical line 6541500Serics */ 6551500Serics 6561500Serics getline(f, length) 6571500Serics register FILE *f; 6581500Serics int *length; 6591500Serics { 6601500Serics register int c; 6611500Serics register char *p; 6621500Serics register int column; 6631500Serics static int colflg; 6641500Serics 6651500Serics p = Line; 6661500Serics column = 0; 6671500Serics c = Getc (f); 6681500Serics if (colflg && c == '\n') { 6691500Serics Currline++; 6701500Serics c = Getc (f); 6711500Serics } 6721500Serics while (p < &Line[LINSIZ - 1]) { 6731500Serics if (c == EOF) { 6741500Serics if (p > Line) { 6751500Serics *p = '\0'; 6761500Serics *length = p - Line; 6771500Serics return (column); 6781500Serics } 6791500Serics *length = p - Line; 6801500Serics return (EOF); 6811500Serics } 6821500Serics if (c == '\n') { 6831500Serics Currline++; 6841500Serics break; 6851500Serics } 6861500Serics *p++ = c; 6871500Serics if (c == '\t') 6881500Serics if (hardtabs && column < promptlen && !hard) { 6891500Serics if (eraseln && !dumb) { 6901500Serics column = 1 + (column | 7); 6911500Serics tputs (eraseln, 1, putch); 6921500Serics promptlen = 0; 6931500Serics } 6941500Serics else { 6951500Serics for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 6961500Serics *p++ = ' '; 6971500Serics } 6981500Serics if (column >= promptlen) promptlen = 0; 6991500Serics } 7001500Serics } 7011500Serics else 7021500Serics column = 1 + (column | 7); 7039627Ssklower else if (c == '\b' && column > 0) 7041500Serics column--; 7051500Serics else if (c == '\r') 7061500Serics column = 0; 7071500Serics else if (c == '\f' && stop_opt) { 7081500Serics p[-1] = '^'; 7091500Serics *p++ = 'L'; 7101500Serics column += 2; 7111500Serics Pause++; 7121500Serics } 7131500Serics else if (c == EOF) { 7141500Serics *length = p - Line; 7151500Serics return (column); 7161500Serics } 7171500Serics else if (c >= ' ' && c != RUBOUT) 7181500Serics column++; 7191500Serics if (column >= Mcol && fold_opt) break; 7201500Serics c = Getc (f); 7211500Serics } 7221500Serics if (column >= Mcol && Mcol > 0) { 7231500Serics if (!Wrap) { 7241500Serics *p++ = '\n'; 7251500Serics } 7261500Serics } 7271500Serics colflg = column == Mcol && fold_opt; 7281500Serics *length = p - Line; 7291500Serics *p = 0; 7301500Serics return (column); 7311500Serics } 7321500Serics 7331500Serics /* 7341500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 7351500Serics */ 7361500Serics 7371500Serics erase (col) 7381500Serics register int col; 7391500Serics { 7401500Serics 7411500Serics if (promptlen == 0) 7421500Serics return; 7431500Serics if (hard) { 7441500Serics putchar ('\n'); 7451500Serics } 7461500Serics else { 7471500Serics if (col == 0) 7481500Serics putchar ('\r'); 7491500Serics if (!dumb && eraseln) 7501500Serics tputs (eraseln, 1, putch); 7511500Serics else 7521500Serics for (col = promptlen - col; col > 0; col--) 7531500Serics putchar (' '); 7541500Serics } 7551500Serics promptlen = 0; 7561500Serics } 7571500Serics 7581500Serics /* 7591500Serics ** Erase the current line entirely 7601500Serics */ 7611500Serics 7621500Serics kill_line () 7631500Serics { 7641500Serics erase (0); 7651500Serics if (!eraseln || dumb) putchar ('\r'); 7661500Serics } 7671500Serics 7681500Serics /* 7693455Sroot * force clear to end of line 7703455Sroot */ 7713455Sroot cleareol() 7723455Sroot { 7733594Sroot tputs(eraseln, 1, putch); 7743455Sroot } 7753455Sroot 7763594Sroot clreos() 7773455Sroot { 7783594Sroot tputs(EodClr, 1, putch); 7793455Sroot } 7803455Sroot 7813455Sroot /* 7821500Serics ** Print string and return number of characters 7831500Serics */ 7841500Serics 7851500Serics pr(s1) 7861500Serics char *s1; 7871500Serics { 7881500Serics register char *s; 7891500Serics register char c; 7901500Serics 7911500Serics for (s = s1; c = *s++; ) 7921500Serics putchar(c); 7931500Serics return (s - s1 - 1); 7941500Serics } 7951500Serics 7961500Serics 7971500Serics /* Print a buffer of n characters */ 7981500Serics 7991500Serics prbuf (s, n) 8001500Serics register char *s; 8011500Serics register int n; 8021500Serics { 8033594Sroot char c; /* next ouput character */ 8043594Sroot register int state; /* next output char's UL state */ 8053594Sroot static int pstate = 0; /* current terminal UL state (off) */ 8063594Sroot 8073594Sroot while (--n >= 0) 8083594Sroot if (!ul_opt) 8093594Sroot putchar (*s++); 8103594Sroot else { 8113594Sroot if (n >= 2 && s[0] == '_' && s[1] == '\b') { 8123594Sroot n -= 2; 8133594Sroot s += 2; 8143594Sroot c = *s++; 8153594Sroot state = 1; 8163594Sroot } else if (n >= 2 && s[1] == '\b' && s[2] == '_') { 8173594Sroot n -= 2; 8183594Sroot c = *s++; 8193594Sroot s += 2; 8203594Sroot state = 1; 8213594Sroot } else { 8223594Sroot c = *s++; 8233594Sroot state = 0; 8243594Sroot } 8253594Sroot if (state != pstate) 8263594Sroot tputs(state ? ULenter : ULexit, 1, putch); 8273594Sroot pstate = state; 8283594Sroot putchar(c); 8293594Sroot if (state && *chUL) { 8303594Sroot pr(chBS); 8313594Sroot tputs(chUL, 1, putch); 8323594Sroot } 8333594Sroot } 8341500Serics } 8351500Serics 8361500Serics /* 8371500Serics ** Clear the screen 8381500Serics */ 8391500Serics 8401500Serics doclear() 8411500Serics { 8421500Serics if (Clear && !hard) { 8431500Serics tputs(Clear, 1, putch); 8441500Serics 8451500Serics /* Put out carriage return so that system doesn't 8461500Serics ** get confused by escape sequences when expanding tabs 8471500Serics */ 8481500Serics putchar ('\r'); 8491500Serics promptlen = 0; 8501500Serics } 8511500Serics } 8521500Serics 8533455Sroot /* 8543455Sroot * Go to home position 8553455Sroot */ 8563455Sroot home() 8573455Sroot { 8583455Sroot tputs(Home,1,putch); 8593455Sroot } 8603455Sroot 8611500Serics static int lastcmd, lastarg, lastp; 8621500Serics static int lastcolon; 8631500Serics char shell_line[132]; 8641500Serics 8651500Serics /* 8661500Serics ** Read a command and do it. A command consists of an optional integer 8671500Serics ** argument followed by the command character. Return the number of lines 8681500Serics ** to display in the next screenful. If there is nothing more to display 8691500Serics ** in the current file, zero is returned. 8701500Serics */ 8711500Serics 8721500Serics command (filename, f) 8731500Serics char *filename; 8741500Serics register FILE *f; 8751500Serics { 8761500Serics register int nlines; 8771500Serics register int retval; 8781500Serics register char c; 8791500Serics char colonch; 8801500Serics FILE *helpf; 8811500Serics int done; 8821500Serics char comchar, cmdbuf[80], *p; 8831500Serics 8841500Serics #define ret(val) retval=val;done++;break 8851500Serics 8861500Serics done = 0; 8871500Serics if (!errors) 8881500Serics prompt (filename); 8891500Serics else 8901500Serics errors = 0; 8911500Serics if (MBIT == RAW && slow_tty) { 8921500Serics otty.sg_flags |= MBIT; 893*16582Sleres stty(fileno(stderr), &otty); 8941500Serics } 8951500Serics for (;;) { 8961500Serics nlines = number (&comchar); 8971500Serics lastp = colonch = 0; 8981500Serics if (comchar == '.') { /* Repeat last command */ 8991500Serics lastp++; 9001500Serics comchar = lastcmd; 9011500Serics nlines = lastarg; 9021500Serics if (lastcmd == ':') 9031500Serics colonch = lastcolon; 9041500Serics } 9051500Serics lastcmd = comchar; 9061500Serics lastarg = nlines; 9071500Serics if (comchar == otty.sg_erase) { 9081500Serics kill_line (); 9091500Serics prompt (filename); 9101500Serics continue; 9111500Serics } 9121500Serics switch (comchar) { 9131500Serics case ':': 9141500Serics retval = colon (filename, colonch, nlines); 9151500Serics if (retval >= 0) 9161500Serics done++; 9171500Serics break; 9181500Serics case ' ': 9191500Serics case 'z': 9201500Serics if (nlines == 0) nlines = dlines; 9211500Serics else if (comchar == 'z') dlines = nlines; 9221500Serics ret (nlines); 9231500Serics case 'd': 9241500Serics case ctrl(D): 9251500Serics if (nlines != 0) nscroll = nlines; 9261500Serics ret (nscroll); 9271500Serics case RUBOUT: 9281500Serics case 'q': 9291500Serics case 'Q': 9301500Serics end_it (); 9311500Serics case 's': 9321500Serics case 'f': 9331500Serics if (nlines == 0) nlines++; 9341500Serics if (comchar == 'f') 9351500Serics nlines *= dlines; 9361500Serics putchar ('\r'); 9371500Serics erase (0); 9383594Sroot printf ("\n"); 9393594Sroot if (clreol) 9403594Sroot cleareol (); 9413594Sroot printf ("...skipping %d line", nlines); 9421500Serics if (nlines > 1) 9433594Sroot pr ("s\n"); 9441500Serics else 9453594Sroot pr ("\n"); 9463594Sroot 9473594Sroot if (clreol) 9483594Sroot cleareol (); 9493594Sroot pr ("\n"); 9503594Sroot 9511500Serics while (nlines > 0) { 9521500Serics while ((c = Getc (f)) != '\n') 9531500Serics if (c == EOF) { 9541500Serics retval = 0; 9551500Serics done++; 9561500Serics goto endsw; 9571500Serics } 9581500Serics Currline++; 9591500Serics nlines--; 9601500Serics } 9611500Serics ret (dlines); 9621500Serics case '\n': 9631500Serics if (nlines != 0) 9641500Serics dlines = nlines; 9651500Serics else 9661500Serics nlines = 1; 9671500Serics ret (nlines); 9681500Serics case '\f': 9691500Serics if (!no_intty) { 9701500Serics doclear (); 9711500Serics Fseek (f, screen_start.chrctr); 9721500Serics Currline = screen_start.line; 9731500Serics ret (dlines); 9741500Serics } 9751500Serics else { 9761500Serics write (2, &bell, 1); 9771500Serics break; 9781500Serics } 9791500Serics case '\'': 9801500Serics if (!no_intty) { 9811500Serics kill_line (); 9821500Serics pr ("\n***Back***\n\n"); 9831500Serics Fseek (f, context.chrctr); 9841500Serics Currline = context.line; 9851500Serics ret (dlines); 9861500Serics } 9871500Serics else { 9881500Serics write (2, &bell, 1); 9891500Serics break; 9901500Serics } 9911500Serics case '=': 9921500Serics kill_line (); 9931500Serics promptlen = printd (Currline); 9941500Serics fflush (stdout); 9951500Serics break; 9961500Serics case 'n': 9971500Serics lastp++; 9981500Serics case '/': 9991500Serics if (nlines == 0) nlines++; 10001500Serics kill_line (); 10011500Serics pr ("/"); 10021500Serics promptlen = 1; 10031500Serics fflush (stdout); 10041500Serics if (lastp) { 10051500Serics write (2,"\r", 1); 10061500Serics search (NULL, f, nlines); /* Use previous r.e. */ 10071500Serics } 10081500Serics else { 10091500Serics ttyin (cmdbuf, 78, '/'); 10101500Serics write (2, "\r", 1); 10111500Serics search (cmdbuf, f, nlines); 10121500Serics } 10133455Sroot ret (dlines-1); 10141500Serics case '!': 10151500Serics do_shell (filename); 10161500Serics break; 10171500Serics case 'h': 10181500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 10191500Serics error ("Can't open help file"); 10201500Serics if (noscroll) doclear (); 10211500Serics copy_file (helpf); 10221500Serics close (helpf); 10231500Serics prompt (filename); 10241500Serics break; 10251500Serics case 'v': /* This case should go right before default */ 10261500Serics if (!no_intty) { 10271500Serics kill_line (); 10281500Serics cmdbuf[0] = '+'; 10291500Serics scanstr (Currline, &cmdbuf[1]); 10301500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 10311500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 10321500Serics break; 10331500Serics } 10341500Serics default: 10351500Serics write (2, &bell, 1); 10361500Serics break; 10371500Serics } 10381500Serics if (done) break; 10391500Serics } 10401500Serics putchar ('\r'); 10411500Serics endsw: 10421500Serics inwait = 0; 10431500Serics notell++; 10441500Serics if (MBIT == RAW && slow_tty) { 10451500Serics otty.sg_flags &= ~MBIT; 1046*16582Sleres stty(fileno(stderr), &otty); 10471500Serics } 10481500Serics return (retval); 10491500Serics } 10501500Serics 10511500Serics char ch; 10521500Serics 10531500Serics /* 10541500Serics * Execute a colon-prefixed command. 10551500Serics * Returns <0 if not a command that should cause 10561500Serics * more of the file to be printed. 10571500Serics */ 10581500Serics 10591500Serics colon (filename, cmd, nlines) 10601500Serics char *filename; 10611500Serics int cmd; 10621500Serics int nlines; 10631500Serics { 10641500Serics if (cmd == 0) 10651500Serics ch = readch (); 10661500Serics else 10671500Serics ch = cmd; 10681500Serics lastcolon = ch; 10691500Serics switch (ch) { 10701500Serics case 'f': 10711500Serics kill_line (); 10721500Serics if (!no_intty) 10731500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 10741500Serics else 10751500Serics promptlen = printf ("[Not a file] line %d", Currline); 10761500Serics fflush (stdout); 10771500Serics return (-1); 10781500Serics case 'n': 10791500Serics if (nlines == 0) { 10801500Serics if (fnum >= nfiles - 1) 10811500Serics end_it (); 10821500Serics nlines++; 10831500Serics } 10841500Serics putchar ('\r'); 10851500Serics erase (0); 10861500Serics skipf (nlines); 10871500Serics return (0); 10881500Serics case 'p': 10891500Serics if (no_intty) { 10901500Serics write (2, &bell, 1); 10911500Serics return (-1); 10921500Serics } 10931500Serics putchar ('\r'); 10941500Serics erase (0); 10951500Serics if (nlines == 0) 10961500Serics nlines++; 10971500Serics skipf (-nlines); 10981500Serics return (0); 10991500Serics case '!': 11001500Serics do_shell (filename); 11011500Serics return (-1); 11021500Serics case 'q': 11031500Serics case 'Q': 11041500Serics end_it (); 11051500Serics default: 11061500Serics write (2, &bell, 1); 11071500Serics return (-1); 11081500Serics } 11091500Serics } 11101500Serics 11111500Serics /* 11121500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 11131500Serics ** terminates the number. 11141500Serics */ 11151500Serics 11161500Serics number(cmd) 11171500Serics char *cmd; 11181500Serics { 11191500Serics register int i; 11201500Serics 11211500Serics i = 0; ch = otty.sg_kill; 11221500Serics for (;;) { 11231500Serics ch = readch (); 11241500Serics if (ch >= '0' && ch <= '9') 11251500Serics i = i*10 + ch - '0'; 11261500Serics else if (ch == otty.sg_kill) 11271500Serics i = 0; 11281500Serics else { 11291500Serics *cmd = ch; 11301500Serics break; 11311500Serics } 11321500Serics } 11331500Serics return (i); 11341500Serics } 11351500Serics 11361500Serics do_shell (filename) 11371500Serics char *filename; 11381500Serics { 11391500Serics char cmdbuf[80]; 11401500Serics 11411500Serics kill_line (); 11421500Serics pr ("!"); 11431500Serics fflush (stdout); 11441500Serics promptlen = 1; 11451500Serics if (lastp) 11461500Serics pr (shell_line); 11471500Serics else { 11481500Serics ttyin (cmdbuf, 78, '!'); 11491500Serics if (expand (shell_line, cmdbuf)) { 11501500Serics kill_line (); 11511500Serics promptlen = printf ("!%s", shell_line); 11521500Serics } 11531500Serics } 11541500Serics fflush (stdout); 11551500Serics write (2, "\n", 1); 11561500Serics promptlen = 0; 11571500Serics shellp = 1; 11581500Serics execute (filename, shell, shell, "-c", shell_line, 0); 11591500Serics } 11601500Serics 11611500Serics /* 11621500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 11631500Serics */ 11641500Serics 11651500Serics search (buf, file, n) 11661500Serics char buf[]; 11671500Serics FILE *file; 11681500Serics register int n; 11691500Serics { 11701500Serics long startline = Ftell (file); 11711500Serics register long line1 = startline; 11721500Serics register long line2 = startline; 11731500Serics register long line3 = startline; 11741500Serics register int lncount; 11751500Serics int saveln, rv, re_exec(); 11761500Serics char *s, *re_comp(); 11771500Serics 11781500Serics context.line = saveln = Currline; 11791500Serics context.chrctr = startline; 11801500Serics lncount = 0; 11811500Serics if ((s = re_comp (buf)) != 0) 11821500Serics error (s); 11831500Serics while (!feof (file)) { 11841500Serics line3 = line2; 11851500Serics line2 = line1; 11861500Serics line1 = Ftell (file); 11871500Serics rdline (file); 11881500Serics lncount++; 11891500Serics if ((rv = re_exec (Line)) == 1) 11901500Serics if (--n == 0) { 11911500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 11923455Sroot { 11933455Sroot pr ("\n"); 11943594Sroot if (clreol) 11953594Sroot cleareol (); 11963455Sroot pr("...skipping\n"); 11973455Sroot } 11981500Serics if (!no_intty) { 11991500Serics Currline -= (lncount >= 3 ? 3 : lncount); 12001500Serics Fseek (file, line3); 12013594Sroot if (noscroll) 12023594Sroot if (clreol) { 12033594Sroot home (); 12043594Sroot cleareol (); 1205*16582Sleres } 12063594Sroot else 12073594Sroot doclear (); 12081500Serics } 12091500Serics else { 12101500Serics kill_line (); 12113594Sroot if (noscroll) 12123594Sroot if (clreol) { 1213*16582Sleres home (); 12143594Sroot cleareol (); 1215*16582Sleres } 12163594Sroot else 12173594Sroot doclear (); 12181500Serics pr (Line); 12191500Serics putchar ('\n'); 12201500Serics } 12211500Serics break; 12221500Serics } 12231500Serics else if (rv == -1) 12241500Serics error ("Regular expression botch"); 12251500Serics } 12261500Serics if (feof (file)) { 12271500Serics if (!no_intty) { 12281500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 12291500Serics Currline = saveln; 12301500Serics Fseek (file, startline); 12311500Serics } 12321500Serics else { 12331500Serics pr ("\nPattern not found\n"); 12341500Serics end_it (); 12351500Serics } 12361500Serics error ("Pattern not found"); 12371500Serics } 12381500Serics } 12391500Serics 12401500Serics execute (filename, cmd, args) 12411500Serics char *filename; 12421500Serics char *cmd, *args; 12431500Serics { 12441500Serics int id; 12451500Serics 12461500Serics fflush (stdout); 12471500Serics reset_tty (); 12481500Serics while ((id = fork ()) < 0) 12491500Serics sleep (5); 12501500Serics if (id == 0) { 12511500Serics execv (cmd, &args); 12521500Serics write (2, "exec failed\n", 12); 12531500Serics exit (1); 12541500Serics } 12551500Serics signal (SIGINT, SIG_IGN); 12561500Serics signal (SIGQUIT, SIG_IGN); 12571500Serics if (catch_susp) 12581500Serics signal(SIGTSTP, SIG_DFL); 12591500Serics wait (0); 12601500Serics signal (SIGINT, end_it); 12611500Serics signal (SIGQUIT, onquit); 12621500Serics if (catch_susp) 12631500Serics signal(SIGTSTP, onsusp); 12641500Serics set_tty (); 12651500Serics pr ("------------------------\n"); 12661500Serics prompt (filename); 12671500Serics } 12681500Serics /* 12691500Serics ** Skip n lines in the file f 12701500Serics */ 12711500Serics 12721500Serics skiplns (n, f) 12731500Serics register int n; 12741500Serics register FILE *f; 12751500Serics { 12761500Serics register char c; 12771500Serics 12781500Serics while (n > 0) { 12791500Serics while ((c = Getc (f)) != '\n') 12801500Serics if (c == EOF) 12811500Serics return; 12821500Serics n--; 12831500Serics Currline++; 12841500Serics } 12851500Serics } 12861500Serics 12871500Serics /* 12881500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 12891500Serics ** negative. 12901500Serics */ 12911500Serics 12921500Serics skipf (nskip) 12931500Serics register int nskip; 12941500Serics { 12951500Serics if (nskip == 0) return; 12961500Serics if (nskip > 0) { 12971500Serics if (fnum + nskip > nfiles - 1) 12981500Serics nskip = nfiles - fnum - 1; 12991500Serics } 13001500Serics else if (within) 13011500Serics ++fnum; 13021500Serics fnum += nskip; 13031500Serics if (fnum < 0) 13041500Serics fnum = 0; 13053594Sroot pr ("\n...Skipping "); 13063455Sroot pr ("\n"); 13073594Sroot if (clreol) 13083594Sroot cleareol (); 13093455Sroot pr ("...Skipping "); 13101500Serics pr (nskip > 0 ? "to file " : "back to file "); 13111500Serics pr (fnames[fnum]); 13123455Sroot pr ("\n"); 13133594Sroot if (clreol) 13143594Sroot cleareol (); 13153455Sroot pr ("\n"); 13161500Serics --fnum; 13171500Serics } 13181500Serics 13191500Serics /*----------------------------- Terminal I/O -------------------------------*/ 13201500Serics 13211500Serics initterm () 13221500Serics { 13231500Serics char buf[TBUFSIZ]; 13241500Serics char clearbuf[100]; 13251500Serics char *clearptr, *padstr; 13261500Serics int ldisc; 132710823Ssam char *term; 1328*16582Sleres int tgrp; 13291500Serics 13301500Serics setbuf(stdout, obuf); 1331*16582Sleres retry: 1332*16582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 1333*16582Sleres /* 1334*16582Sleres * Wait until we're in the foreground before we get the 1335*16582Sleres * save the terminal modes. 1336*16582Sleres */ 1337*16582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 1338*16582Sleres perror("ioctl"); 1339*16582Sleres exit(1); 1340*16582Sleres } 1341*16582Sleres if (tgrp != getpgrp(0)) { 1342*16582Sleres kill(0, SIGTTOU); 1343*16582Sleres goto retry; 1344*16582Sleres } 134513830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 13463594Sroot dumb++; ul_opt = 0; 13471500Serics } 13481500Serics else { 13491500Serics if (((Lpp = tgetnum("li")) < 0) || tgetflag("hc")) { 13501500Serics hard++; /* Hard copy terminal */ 13511500Serics Lpp = 24; 13521500Serics } 13531500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 13541500Serics noscroll++; 13551500Serics if ((Mcol = tgetnum("co")) < 0) 13561500Serics Mcol = 80; 13571500Serics Wrap = tgetflag("am"); 13581500Serics bad_so = tgetflag ("xs"); 13591500Serics clearptr = clearbuf; 13601500Serics eraseln = tgetstr("ce",&clearptr); 13611500Serics Clear = tgetstr("cl", &clearptr); 13621500Serics Senter = tgetstr("so", &clearptr); 13631500Serics Sexit = tgetstr("se", &clearptr); 13643594Sroot 13653594Sroot /* 13663594Sroot * Set up for underlining: some terminals don't need it; 13673594Sroot * others have start/stop sequences, still others have an 13683594Sroot * underline char sequence which is assumed to move the 13693594Sroot * cursor forward one character. If underline sequence 13703594Sroot * isn't available, settle for standout sequence. 13713594Sroot */ 13723594Sroot 13733594Sroot if (tgetflag("ul") || tgetflag("os")) 13743594Sroot ul_opt = 0; 13753594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 13763594Sroot chUL = ""; 13773594Sroot if ((ULenter = tgetstr("us", &clearptr)) == NULL && 13783594Sroot (!*chUL) && (ULenter = tgetstr("so", &clearptr)) == NULL) 13793594Sroot ULenter = ""; 13803594Sroot if ((ULexit = tgetstr("ue", &clearptr)) == NULL && 13813594Sroot (!*chUL) && (ULexit = tgetstr("se", &clearptr)) == NULL) 13823594Sroot ULexit = ""; 1383*16582Sleres 13841500Serics if (padstr = tgetstr("pc", &clearptr)) 13851500Serics PC = *padstr; 13863455Sroot Home = tgetstr("ho",&clearptr); 138713536Ssam if (Home == 0 || *Home == '\0') 13883455Sroot { 13893594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 13903594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 13913455Sroot Home = cursorhome; 13923455Sroot } 13933455Sroot } 13943594Sroot EodClr = tgetstr("cd", &clearptr); 13951500Serics } 13961500Serics if ((shell = getenv("SHELL")) == NULL) 13971500Serics shell = "/bin/sh"; 13981500Serics } 1399*16582Sleres no_intty = gtty(fileno(stdin), &otty); 1400*16582Sleres gtty(fileno(stderr), &otty); 140113830Skre savetty = otty; 14021500Serics ospeed = otty.sg_ospeed; 14031500Serics slow_tty = ospeed < B1200; 14041500Serics hardtabs = !(otty.sg_flags & XTABS); 14051500Serics if (!no_tty) { 14061500Serics otty.sg_flags &= ~ECHO; 14071500Serics if (MBIT == CBREAK || !slow_tty) 14081500Serics otty.sg_flags |= MBIT; 14091500Serics } 14101500Serics } 14111500Serics 14121500Serics readch () 14131500Serics { 14141500Serics char ch; 14151500Serics extern int errno; 14161500Serics 14171500Serics if (read (2, &ch, 1) <= 0) 14181500Serics if (errno != EINTR) 14191500Serics exit(0); 14201500Serics else 14211500Serics ch = otty.sg_kill; 14221500Serics return (ch); 14231500Serics } 14241500Serics 14251500Serics static char BS = '\b'; 14261500Serics static char CARAT = '^'; 14271500Serics 14281500Serics ttyin (buf, nmax, pchar) 14291500Serics char buf[]; 14301500Serics register int nmax; 14311500Serics char pchar; 14321500Serics { 14331500Serics register char *sptr; 14341500Serics register char ch; 14351500Serics register int slash = 0; 14361500Serics int maxlen; 14371500Serics char cbuf; 14381500Serics 14391500Serics sptr = buf; 14401500Serics maxlen = 0; 14411500Serics while (sptr - buf < nmax) { 14421500Serics if (promptlen > maxlen) maxlen = promptlen; 14431500Serics ch = readch (); 14441500Serics if (ch == '\\') { 14451500Serics slash++; 14461500Serics } 14471500Serics else if ((ch == otty.sg_erase) && !slash) { 14481500Serics if (sptr > buf) { 14491500Serics --promptlen; 14501500Serics write (2, &BS, 1); 14511500Serics --sptr; 14521500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 14531500Serics --promptlen; 14541500Serics write (2, &BS, 1); 14551500Serics } 14561500Serics continue; 14571500Serics } 14581500Serics else { 14591500Serics if (!eraseln) promptlen = maxlen; 14601500Serics longjmp (restore, 1); 14611500Serics } 14621500Serics } 14631500Serics else if ((ch == otty.sg_kill) && !slash) { 14641500Serics if (hard) { 14651500Serics show (ch); 14661500Serics putchar ('\n'); 14671500Serics putchar (pchar); 14681500Serics } 14691500Serics else { 14701500Serics putchar ('\r'); 14711500Serics putchar (pchar); 14721500Serics if (eraseln) 14731500Serics erase (1); 14741500Serics promptlen = 1; 14751500Serics } 14761500Serics sptr = buf; 14771500Serics fflush (stdout); 14781500Serics continue; 14791500Serics } 14801500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 14811500Serics write (2, &BS, 1); 14821500Serics --sptr; 14831500Serics } 14841500Serics if (ch != '\\') 14851500Serics slash = 0; 14861500Serics *sptr++ = ch; 14871500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 14881500Serics ch += ch == RUBOUT ? -0100 : 0100; 14891500Serics write (2, &CARAT, 1); 14901500Serics promptlen++; 14911500Serics } 14921500Serics cbuf = ch; 14931500Serics if (ch != '\n' && ch != ESC) { 14941500Serics write (2, &cbuf, 1); 14951500Serics promptlen++; 14961500Serics } 14971500Serics else 14981500Serics break; 14991500Serics } 15001500Serics *--sptr = '\0'; 15011500Serics if (!eraseln) promptlen = maxlen; 15021500Serics if (sptr - buf >= nmax - 1) 15031500Serics error ("Line too long"); 15041500Serics } 15051500Serics 15061500Serics expand (outbuf, inbuf) 15071500Serics char *outbuf; 15081500Serics char *inbuf; 15091500Serics { 15101500Serics register char *instr; 15111500Serics register char *outstr; 15121500Serics register char ch; 15131500Serics char temp[200]; 15141500Serics int changed = 0; 15151500Serics 15161500Serics instr = inbuf; 15171500Serics outstr = temp; 15181500Serics while ((ch = *instr++) != '\0') 15191500Serics switch (ch) { 15201500Serics case '%': 15211500Serics if (!no_intty) { 15221500Serics strcpy (outstr, fnames[fnum]); 15231500Serics outstr += strlen (fnames[fnum]); 15241500Serics changed++; 15251500Serics } 15261500Serics else 15271500Serics *outstr++ = ch; 15281500Serics break; 15291500Serics case '!': 15301500Serics if (!shellp) 15311500Serics error ("No previous command to substitute for"); 15321500Serics strcpy (outstr, shell_line); 15331500Serics outstr += strlen (shell_line); 15341500Serics changed++; 15351500Serics break; 15361500Serics case '\\': 15371500Serics if (*instr == '%' || *instr == '!') { 15381500Serics *outstr++ = *instr++; 15391500Serics break; 15401500Serics } 15411500Serics default: 15421500Serics *outstr++ = ch; 15431500Serics } 15441500Serics *outstr++ = '\0'; 15451500Serics strcpy (outbuf, temp); 15461500Serics return (changed); 15471500Serics } 15481500Serics 15491500Serics show (ch) 15501500Serics register char ch; 15511500Serics { 15521500Serics char cbuf; 15531500Serics 15541500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 15551500Serics ch += ch == RUBOUT ? -0100 : 0100; 15561500Serics write (2, &CARAT, 1); 15571500Serics promptlen++; 15581500Serics } 15591500Serics cbuf = ch; 15601500Serics write (2, &cbuf, 1); 15611500Serics promptlen++; 15621500Serics } 15631500Serics 15641500Serics error (mess) 15651500Serics char *mess; 15661500Serics { 15673594Sroot if (clreol) 15683594Sroot cleareol (); 15693594Sroot else 15703594Sroot kill_line (); 15711500Serics promptlen += strlen (mess); 15721500Serics if (Senter && Sexit) { 15731500Serics tputs (Senter, 1, putch); 15741500Serics pr(mess); 15751500Serics tputs (Sexit, 1, putch); 15761500Serics } 15771500Serics else 15781500Serics pr (mess); 15791500Serics fflush(stdout); 15801500Serics errors++; 15811500Serics longjmp (restore, 1); 15821500Serics } 15831500Serics 15841500Serics 15851500Serics set_tty () 15861500Serics { 15871500Serics otty.sg_flags |= MBIT; 15881500Serics otty.sg_flags &= ~ECHO; 1589*16582Sleres stty(fileno(stderr), &otty); 15901500Serics } 15911500Serics 15921500Serics reset_tty () 15931500Serics { 15941500Serics otty.sg_flags |= ECHO; 15951500Serics otty.sg_flags &= ~MBIT; 1596*16582Sleres stty(fileno(stderr), &savetty); 15971500Serics } 15981500Serics 15991500Serics rdline (f) 16001500Serics register FILE *f; 16011500Serics { 16021500Serics register char c; 16031500Serics register char *p; 16041500Serics 16051500Serics p = Line; 16061500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 16071500Serics *p++ = c; 16081500Serics if (c == '\n') 16091500Serics Currline++; 16101500Serics *p = '\0'; 16111500Serics } 16121500Serics 16131500Serics /* Come here when we get a suspend signal from the terminal */ 16141500Serics 16151500Serics onsusp () 16161500Serics { 161714861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 161814861Skarels signal(SIGTTOU, SIG_IGN); 16191500Serics reset_tty (); 16201500Serics fflush (stdout); 162114861Skarels signal(SIGTTOU, SIG_DFL); 16221500Serics /* Send the TSTP signal to suspend our process group */ 162313289Ssam signal(SIGTSTP, SIG_DFL); 162413289Ssam sigsetmask(0); 16251500Serics kill (0, SIGTSTP); 16261500Serics /* Pause for station break */ 16271500Serics 16281500Serics /* We're back */ 16291500Serics signal (SIGTSTP, onsusp); 16301500Serics set_tty (); 16311500Serics if (inwait) 16321500Serics longjmp (restore); 16331500Serics } 1634