113615Ssam #ifndef lint 2*18608Sralph static char *sccsid = "@(#)more.c 4.23 (Berkeley) 85/04/10"; 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> 1517592Sleres #include <sys/types.h> 161500Serics #include <ctype.h> 171500Serics #include <signal.h> 181500Serics #include <errno.h> 191500Serics #include <sgtty.h> 201500Serics #include <setjmp.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; 5717592Sleres int docrterase = 0; 5817592Sleres int docrtkill = 0; 591500Serics int bad_so; /* True if overwriting does not turn off standout */ 601500Serics int inwait, Pause, errors; 611500Serics int within; /* true if we are within a file, 621500Serics false if we are between files */ 633594Sroot int hard, dumb, noscroll, hardtabs, clreol; 641500Serics int catch_susp; /* We should catch the SIGTSTP signal */ 651500Serics char **fnames; /* The list of file names */ 661500Serics int nfiles; /* Number of files left to process */ 671500Serics char *shell; /* The name of the shell to use */ 681500Serics int shellp; /* A previous shell command exists */ 691500Serics char ch; 701500Serics jmp_buf restore; 711500Serics char Line[LINSIZ]; /* Line buffer */ 721500Serics int Lpp = 24; /* lines per page */ 731500Serics char *Clear; /* clear screen */ 741500Serics char *eraseln; /* erase line */ 751500Serics char *Senter, *Sexit;/* enter and exit standout mode */ 763594Sroot char *ULenter, *ULexit; /* enter and exit underline mode */ 773594Sroot char *chUL; /* underline character */ 783594Sroot char *chBS; /* backspace character */ 793455Sroot char *Home; /* go to home */ 803455Sroot char *cursorm; /* cursor movement */ 813455Sroot char cursorhome[40]; /* contains cursor movement to home */ 823594Sroot char *EodClr; /* clear rest of screen */ 831500Serics char *tgetstr(); 841500Serics int Mcol = 80; /* number of columns */ 851500Serics int Wrap = 1; /* set if automargins */ 8616710Sjak int soglitch; /* terminal has standout mode glitch */ 8716710Sjak int ulglitch; /* terminal has underline mode glitch */ 8816710Sjak int pstate = 0; /* current UL state */ 891500Serics long fseek(); 903455Sroot char *getenv(); 911500Serics struct { 921500Serics long chrctr, line; 931500Serics } context, screen_start; 941500Serics extern char PC; /* pad character */ 951500Serics extern short ospeed; 961500Serics 971500Serics 981500Serics main(argc, argv) 991500Serics int argc; 1001500Serics char *argv[]; 1011500Serics { 1021500Serics register FILE *f; 1031500Serics register char *s; 1041500Serics register char *p; 1051500Serics register char ch; 1061500Serics register int left; 10716582Sleres int prnames = 0; 1081500Serics int initopt = 0; 1091500Serics int srchopt = 0; 1101500Serics int clearit = 0; 1111500Serics int initline; 1121500Serics char initbuf[80]; 1131500Serics FILE *checkf(); 1141500Serics 1151500Serics nfiles = argc; 1161500Serics fnames = argv; 1171500Serics initterm (); 11815813Sralph nscroll = Lpp/2 - 1; 11915813Sralph if (nscroll <= 0) 12015813Sralph nscroll = 1; 1213455Sroot if(s = getenv("MORE")) argscan(s); 1221500Serics while (--nfiles > 0) { 1231500Serics if ((ch = (*++fnames)[0]) == '-') { 1243455Sroot argscan(*fnames+1); 1251500Serics } 1261500Serics else if (ch == '+') { 1271500Serics s = *fnames; 1281500Serics if (*++s == '/') { 1291500Serics srchopt++; 1301500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1311500Serics *p++ = *s++; 1321500Serics *p = '\0'; 1331500Serics } 1341500Serics else { 1351500Serics initopt++; 1361500Serics for (initline = 0; *s != '\0'; s++) 1371500Serics if (isdigit (*s)) 1381500Serics initline = initline*10 + *s -'0'; 1391500Serics --initline; 1401500Serics } 1411500Serics } 1421500Serics else break; 1431500Serics } 1443594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1453455Sroot * defined, and in that case, make sure we are in noscroll mode 1463455Sroot */ 1473455Sroot if(clreol) 1483455Sroot { 149*18608Sralph if((Home == NULL) || (*Home == '\0') || 150*18608Sralph (eraseln == NULL) || (*eraseln == '\0') || 151*18608Sralph (EodClr == NULL) || (*EodClr == '\0') ) 152*18608Sralph clreol = 0; 1533455Sroot else noscroll = 1; 1543455Sroot } 1551500Serics if (dlines == 0) 1561500Serics dlines = Lpp - (noscroll ? 1 : 2); 1571500Serics left = dlines; 1581500Serics if (nfiles > 1) 1591500Serics prnames++; 1601500Serics if (!no_intty && nfiles == 0) { 1611500Serics fputs("Usage: ",stderr); 1621500Serics fputs(argv[0],stderr); 1631500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1641500Serics exit(1); 1651500Serics } 1661500Serics else 1671500Serics f = stdin; 1681500Serics if (!no_tty) { 1691500Serics signal(SIGQUIT, onquit); 1701500Serics signal(SIGINT, end_it); 1711500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1721500Serics signal(SIGTSTP, onsusp); 1731500Serics catch_susp++; 1741500Serics } 17516582Sleres stty (fileno(stderr), &otty); 1761500Serics } 1771500Serics if (no_intty) { 1781500Serics if (no_tty) 1791500Serics copy_file (stdin); 1801500Serics else { 1811500Serics if ((ch = Getc (f)) == '\f') 1823594Sroot doclear(); 1831500Serics else { 1841500Serics Ungetc (ch, f); 1853594Sroot if (noscroll && (ch != EOF)) { 1863594Sroot if (clreol) 1873594Sroot home (); 1883594Sroot else 1893594Sroot doclear (); 1903455Sroot } 1911500Serics } 1921500Serics if (srchopt) 1933455Sroot { 1941500Serics search (initbuf, stdin, 1); 1953594Sroot if (noscroll) 1963594Sroot left--; 1973455Sroot } 1981500Serics else if (initopt) 1991500Serics skiplns (initline, stdin); 2001500Serics screen (stdin, left); 2011500Serics } 2021500Serics no_intty = 0; 2031500Serics prnames++; 2041500Serics firstf = 0; 2051500Serics } 2061500Serics 2071500Serics while (fnum < nfiles) { 2081500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2091500Serics context.line = context.chrctr = 0; 2101500Serics Currline = 0; 2111500Serics if (firstf) setjmp (restore); 2121500Serics if (firstf) { 2131500Serics firstf = 0; 2141500Serics if (srchopt) 2153455Sroot { 2161500Serics search (initbuf, f, 1); 2173594Sroot if (noscroll) 2183594Sroot left--; 2193455Sroot } 2201500Serics else if (initopt) 2211500Serics skiplns (initline, f); 2221500Serics } 2231500Serics else if (fnum < nfiles && !no_tty) { 2241500Serics setjmp (restore); 2251500Serics left = command (fnames[fnum], f); 2261500Serics } 2271500Serics if (left != 0) { 2283594Sroot if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 2293594Sroot if (clreol) 2303594Sroot home (); 2313594Sroot else 2323594Sroot doclear (); 2331500Serics if (prnames) { 2341500Serics if (bad_so) 2351500Serics erase (0); 2363594Sroot if (clreol) 2373594Sroot cleareol (); 2381500Serics pr("::::::::::::::"); 2391500Serics if (promptlen > 14) 2401500Serics erase (14); 2413455Sroot printf ("\n"); 2423455Sroot if(clreol) cleareol(); 2433455Sroot printf("%s\n", fnames[fnum]); 2443455Sroot if(clreol) cleareol(); 2453455Sroot printf("::::::::::::::\n", fnames[fnum]); 2461500Serics if (left > Lpp - 4) 2471500Serics left = Lpp - 4; 2481500Serics } 2491500Serics if (no_tty) 2501500Serics copy_file (f); 2511500Serics else { 2521500Serics within++; 2531500Serics screen(f, left); 2541500Serics within = 0; 2551500Serics } 2561500Serics } 2571500Serics setjmp (restore); 2581500Serics fflush(stdout); 2591500Serics fclose(f); 2601500Serics screen_start.line = screen_start.chrctr = 0L; 2611500Serics context.line = context.chrctr = 0L; 2621500Serics } 2631500Serics fnum++; 2641500Serics firstf = 0; 2651500Serics } 2661500Serics reset_tty (); 2671500Serics exit(0); 2681500Serics } 2691500Serics 2703455Sroot argscan(s) 2713455Sroot char *s; 2723455Sroot { 27311604Slayer for (dlines = 0; *s != '\0'; s++) 27411604Slayer { 27511604Slayer switch (*s) 27611604Slayer { 27711604Slayer case '0': case '1': case '2': 27811604Slayer case '3': case '4': case '5': 27911604Slayer case '6': case '7': case '8': 28011604Slayer case '9': 28111604Slayer dlines = dlines*10 + *s - '0'; 28211604Slayer break; 28311604Slayer case 'd': 28411604Slayer dum_opt = 1; 28511604Slayer break; 28611604Slayer case 'l': 28711604Slayer stop_opt = 0; 28811604Slayer break; 28911604Slayer case 'f': 29011604Slayer fold_opt = 0; 29111604Slayer break; 29211604Slayer case 'p': 29311604Slayer noscroll++; 29411604Slayer break; 29511604Slayer case 'c': 29611604Slayer clreol++; 29711604Slayer break; 29811604Slayer case 's': 29911604Slayer ssp_opt = 1; 30011604Slayer break; 30111604Slayer case 'u': 30211604Slayer ul_opt = 0; 30311604Slayer break; 30411604Slayer } 30511604Slayer } 3063455Sroot } 3073455Sroot 3083455Sroot 3091500Serics /* 3101500Serics ** Check whether the file named by fs is an ASCII file which the user may 3111500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3121500Serics */ 3131500Serics 3141500Serics FILE * 3151500Serics checkf (fs, clearfirst) 3161500Serics register char *fs; 3171500Serics int *clearfirst; 3181500Serics { 3191500Serics struct stat stbuf; 3201500Serics register FILE *f; 3211500Serics char c; 3221500Serics 3231500Serics if (stat (fs, &stbuf) == -1) { 3241500Serics fflush(stdout); 3253594Sroot if (clreol) 3263594Sroot cleareol (); 3271500Serics perror(fs); 3281500Serics return (NULL); 3291500Serics } 3301500Serics if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3311500Serics printf("\n*** %s: directory ***\n\n", fs); 3321500Serics return (NULL); 3331500Serics } 3341500Serics if ((f=Fopen(fs, "r")) == NULL) { 3351500Serics fflush(stdout); 3361500Serics perror(fs); 3371500Serics return (NULL); 3381500Serics } 3391500Serics c = Getc(f); 3401500Serics 3411500Serics /* Try to see whether it is an ASCII file */ 3421500Serics 3431500Serics switch ((c | *f->_ptr << 8) & 0177777) { 3441500Serics case 0405: 3451500Serics case 0407: 3461500Serics case 0410: 3471500Serics case 0411: 3481500Serics case 0413: 3491500Serics case 0177545: 3501500Serics printf("\n******** %s: Not a text file ********\n\n", fs); 3511500Serics fclose (f); 3521500Serics return (NULL); 3531500Serics default: 3541500Serics break; 3551500Serics } 3561500Serics if (c == '\f') 3571500Serics *clearfirst = 1; 3581500Serics else { 3591500Serics *clearfirst = 0; 3601500Serics Ungetc (c, f); 3611500Serics } 3621500Serics if ((file_size = stbuf.st_size) == 0) 3631500Serics file_size = 0x7fffffffffffffffL; 3641500Serics return (f); 3651500Serics } 3661500Serics 3671500Serics /* 3681500Serics ** A real function, for the tputs routine in termlib 3691500Serics */ 3701500Serics 3711500Serics putch (ch) 3721500Serics char ch; 3731500Serics { 3741500Serics putchar (ch); 3751500Serics } 3761500Serics 3771500Serics /* 3781500Serics ** Print out the contents of the file f, one screenful at a time. 3791500Serics */ 3801500Serics 3811500Serics #define STOP -10 3821500Serics 3831500Serics screen (f, num_lines) 3841500Serics register FILE *f; 3851500Serics register int num_lines; 3861500Serics { 3871500Serics register int c; 3881500Serics register int nchars; 3893594Sroot int length; /* length of current line */ 3903594Sroot static int prev_len = 1; /* length of previous line */ 3911500Serics 3921500Serics for (;;) { 3931500Serics while (num_lines > 0 && !Pause) { 3941500Serics if ((nchars = getline (f, &length)) == EOF) 3953455Sroot { 3963594Sroot if (clreol) 3973594Sroot clreos(); 3981500Serics return; 3993455Sroot } 4003594Sroot if (ssp_opt && length == 0 && prev_len == 0) 4013594Sroot continue; 4023594Sroot prev_len = length; 4031500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 4041500Serics erase (0); 4053594Sroot /* must clear before drawing line since tabs on some terminals 4063594Sroot * do not erase what they tab over. 4073594Sroot */ 4083594Sroot if (clreol) 4093594Sroot cleareol (); 4101500Serics prbuf (Line, length); 4111500Serics if (nchars < promptlen) 4121500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4131500Serics else promptlen = 0; 4143594Sroot /* is this needed? 4153594Sroot * if (clreol) 4163594Sroot * cleareol(); /* must clear again in case we wrapped * 4173594Sroot */ 4181500Serics if (nchars < Mcol || !fold_opt) 41916710Sjak prbuf("\n", 1); /* will turn off UL if necessary */ 4201500Serics if (nchars == STOP) 4211500Serics break; 4221500Serics num_lines--; 4231500Serics } 42416710Sjak if (pstate) { 42516710Sjak tputs(ULexit, 1, putch); 42616710Sjak pstate = 0; 42716710Sjak } 4281500Serics fflush(stdout); 4291500Serics if ((c = Getc(f)) == EOF) 4303455Sroot { 4313594Sroot if (clreol) 4323594Sroot clreos (); 4331500Serics return; 4343455Sroot } 4353455Sroot 4363594Sroot if (Pause && clreol) 4373594Sroot clreos (); 4381500Serics Ungetc (c, f); 4391500Serics setjmp (restore); 4401500Serics Pause = 0; startup = 0; 4411500Serics if ((num_lines = command (NULL, f)) == 0) 4421500Serics return; 4431500Serics if (hard && promptlen > 0) 4441500Serics erase (0); 44511123Slayer if (noscroll && num_lines >= dlines) 44616582Sleres { 4473594Sroot if (clreol) 4483594Sroot home(); 4493594Sroot else 4503594Sroot doclear (); 4513455Sroot } 4521500Serics screen_start.line = Currline; 4531500Serics screen_start.chrctr = Ftell (f); 4541500Serics } 4551500Serics } 4561500Serics 4571500Serics /* 4581500Serics ** Come here if a quit signal is received 4591500Serics */ 4601500Serics 4611500Serics onquit() 4621500Serics { 4631500Serics signal(SIGQUIT, SIG_IGN); 4641500Serics if (!inwait) { 4651500Serics putchar ('\n'); 4661500Serics if (!startup) { 4671500Serics signal(SIGQUIT, onquit); 4681500Serics longjmp (restore, 1); 4691500Serics } 4701500Serics else 4711500Serics Pause++; 4721500Serics } 4731500Serics else if (!dum_opt && notell) { 4741500Serics write (2, "[Use q or Q to quit]", 20); 4751500Serics promptlen += 20; 4761500Serics notell = 0; 4771500Serics } 4781500Serics signal(SIGQUIT, onquit); 4791500Serics } 4801500Serics 4811500Serics /* 4821500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 4831500Serics */ 4841500Serics 4851500Serics end_it () 4861500Serics { 4871500Serics 4881500Serics reset_tty (); 4893594Sroot if (clreol) { 4903594Sroot putchar ('\r'); 4913594Sroot clreos (); 4923594Sroot fflush (stdout); 4933594Sroot } 4943455Sroot else if (!clreol && (promptlen > 0)) { 4951500Serics kill_line (); 4961500Serics fflush (stdout); 4971500Serics } 4981500Serics else 4991500Serics write (2, "\n", 1); 5001500Serics _exit(0); 5011500Serics } 5021500Serics 5031500Serics copy_file(f) 5041500Serics register FILE *f; 5051500Serics { 5061500Serics register int c; 5071500Serics 5081500Serics while ((c = getc(f)) != EOF) 5091500Serics putchar(c); 5101500Serics } 5111500Serics 5121500Serics /* Simplified printf function */ 5131500Serics 5141500Serics printf (fmt, args) 5151500Serics register char *fmt; 5161500Serics int args; 5171500Serics { 5181500Serics register int *argp; 5191500Serics register char ch; 5201500Serics register int ccount; 5211500Serics 5221500Serics ccount = 0; 5231500Serics argp = &args; 5241500Serics while (*fmt) { 5251500Serics while ((ch = *fmt++) != '%') { 5261500Serics if (ch == '\0') 5271500Serics return (ccount); 5281500Serics ccount++; 5291500Serics putchar (ch); 5301500Serics } 5311500Serics switch (*fmt++) { 5321500Serics case 'd': 5331500Serics ccount += printd (*argp); 5341500Serics break; 5351500Serics case 's': 5361500Serics ccount += pr ((char *)*argp); 5371500Serics break; 5381500Serics case '%': 5391500Serics ccount++; 5401500Serics argp--; 5411500Serics putchar ('%'); 5421500Serics break; 5431500Serics case '0': 5441500Serics return (ccount); 5451500Serics default: 5461500Serics break; 5471500Serics } 5481500Serics ++argp; 5491500Serics } 5501500Serics return (ccount); 5511500Serics 5521500Serics } 5531500Serics 5541500Serics /* 5551500Serics ** Print an integer as a string of decimal digits, 5561500Serics ** returning the length of the print representation. 5571500Serics */ 5581500Serics 5591500Serics printd (n) 5601500Serics int n; 5611500Serics { 5621500Serics int a, nchars; 5631500Serics 5641500Serics if (a = n/10) 5651500Serics nchars = 1 + printd(a); 5661500Serics else 5671500Serics nchars = 1; 5681500Serics putchar (n % 10 + '0'); 5691500Serics return (nchars); 5701500Serics } 5711500Serics 5721500Serics /* Put the print representation of an integer into a string */ 5731500Serics static char *sptr; 5741500Serics 5751500Serics scanstr (n, str) 5761500Serics int n; 5771500Serics char *str; 5781500Serics { 5791500Serics sptr = str; 58011604Slayer Sprintf (n); 5811500Serics *sptr = '\0'; 5821500Serics } 5831500Serics 58411604Slayer Sprintf (n) 5851500Serics { 5861500Serics int a; 5871500Serics 5881500Serics if (a = n/10) 58911604Slayer Sprintf (a); 5901500Serics *sptr++ = n % 10 + '0'; 5911500Serics } 5921500Serics 5931500Serics static char bell = ctrl(G); 5941500Serics 5951500Serics strlen (s) 5961500Serics char *s; 5971500Serics { 5981500Serics register char *p; 5991500Serics 6001500Serics p = s; 6011500Serics while (*p++) 6021500Serics ; 6031500Serics return (p - s - 1); 6041500Serics } 6051500Serics 6061500Serics /* See whether the last component of the path name "path" is equal to the 6071500Serics ** string "string" 6081500Serics */ 6091500Serics 6101500Serics tailequ (path, string) 6111500Serics char *path; 6121500Serics register char *string; 6131500Serics { 6141500Serics register char *tail; 6151500Serics 6161500Serics tail = path + strlen(path); 6171500Serics while (tail >= path) 6181500Serics if (*(--tail) == '/') 6191500Serics break; 6201500Serics ++tail; 6211500Serics while (*tail++ == *string++) 6221500Serics if (*tail == '\0') 6231500Serics return(1); 6241500Serics return(0); 6251500Serics } 6261500Serics 6271500Serics prompt (filename) 6281500Serics char *filename; 6291500Serics { 6303594Sroot if (clreol) 6313594Sroot cleareol (); 6323455Sroot else if (promptlen > 0) 6331500Serics kill_line (); 6341500Serics if (!hard) { 6351500Serics promptlen = 8; 63616710Sjak if (Senter && Sexit) { 6371500Serics tputs (Senter, 1, putch); 63816710Sjak promptlen += (2 * soglitch); 63916710Sjak } 6403594Sroot if (clreol) 6413594Sroot cleareol (); 6421500Serics pr("--More--"); 6431500Serics if (filename != NULL) { 6441500Serics promptlen += printf ("(Next file: %s)", filename); 6451500Serics } 6461500Serics else if (!no_intty) { 6471500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 6481500Serics } 6491500Serics if (dum_opt) { 65016710Sjak promptlen += pr("[Press space to continue, 'q' to quit.]"); 6511500Serics } 6521500Serics if (Senter && Sexit) 6531500Serics tputs (Sexit, 1, putch); 6543594Sroot if (clreol) 6553594Sroot clreos (); 6561500Serics fflush(stdout); 6571500Serics } 6581500Serics else 6591500Serics write (2, &bell, 1); 6601500Serics inwait++; 6611500Serics } 6621500Serics 6631500Serics /* 6641500Serics ** Get a logical line 6651500Serics */ 6661500Serics 6671500Serics getline(f, length) 6681500Serics register FILE *f; 6691500Serics int *length; 6701500Serics { 6711500Serics register int c; 6721500Serics register char *p; 6731500Serics register int column; 6741500Serics static int colflg; 6751500Serics 6761500Serics p = Line; 6771500Serics column = 0; 6781500Serics c = Getc (f); 6791500Serics if (colflg && c == '\n') { 6801500Serics Currline++; 6811500Serics c = Getc (f); 6821500Serics } 6831500Serics while (p < &Line[LINSIZ - 1]) { 6841500Serics if (c == EOF) { 6851500Serics if (p > Line) { 6861500Serics *p = '\0'; 6871500Serics *length = p - Line; 6881500Serics return (column); 6891500Serics } 6901500Serics *length = p - Line; 6911500Serics return (EOF); 6921500Serics } 6931500Serics if (c == '\n') { 6941500Serics Currline++; 6951500Serics break; 6961500Serics } 6971500Serics *p++ = c; 6981500Serics if (c == '\t') 6991500Serics if (hardtabs && column < promptlen && !hard) { 7001500Serics if (eraseln && !dumb) { 7011500Serics column = 1 + (column | 7); 7021500Serics tputs (eraseln, 1, putch); 7031500Serics promptlen = 0; 7041500Serics } 7051500Serics else { 7061500Serics for (--p; column & 7 && p < &Line[LINSIZ - 1]; column++) { 7071500Serics *p++ = ' '; 7081500Serics } 7091500Serics if (column >= promptlen) promptlen = 0; 7101500Serics } 7111500Serics } 7121500Serics else 7131500Serics column = 1 + (column | 7); 7149627Ssklower else if (c == '\b' && column > 0) 7151500Serics column--; 7161500Serics else if (c == '\r') 7171500Serics column = 0; 7181500Serics else if (c == '\f' && stop_opt) { 7191500Serics p[-1] = '^'; 7201500Serics *p++ = 'L'; 7211500Serics column += 2; 7221500Serics Pause++; 7231500Serics } 7241500Serics else if (c == EOF) { 7251500Serics *length = p - Line; 7261500Serics return (column); 7271500Serics } 7281500Serics else if (c >= ' ' && c != RUBOUT) 7291500Serics column++; 7301500Serics if (column >= Mcol && fold_opt) break; 7311500Serics c = Getc (f); 7321500Serics } 7331500Serics if (column >= Mcol && Mcol > 0) { 7341500Serics if (!Wrap) { 7351500Serics *p++ = '\n'; 7361500Serics } 7371500Serics } 7381500Serics colflg = column == Mcol && fold_opt; 7391500Serics *length = p - Line; 7401500Serics *p = 0; 7411500Serics return (column); 7421500Serics } 7431500Serics 7441500Serics /* 7451500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 7461500Serics */ 7471500Serics 7481500Serics erase (col) 7491500Serics register int col; 7501500Serics { 7511500Serics 7521500Serics if (promptlen == 0) 7531500Serics return; 7541500Serics if (hard) { 7551500Serics putchar ('\n'); 7561500Serics } 7571500Serics else { 7581500Serics if (col == 0) 7591500Serics putchar ('\r'); 7601500Serics if (!dumb && eraseln) 7611500Serics tputs (eraseln, 1, putch); 7621500Serics else 7631500Serics for (col = promptlen - col; col > 0; col--) 7641500Serics putchar (' '); 7651500Serics } 7661500Serics promptlen = 0; 7671500Serics } 7681500Serics 7691500Serics /* 7701500Serics ** Erase the current line entirely 7711500Serics */ 7721500Serics 7731500Serics kill_line () 7741500Serics { 7751500Serics erase (0); 7761500Serics if (!eraseln || dumb) putchar ('\r'); 7771500Serics } 7781500Serics 7791500Serics /* 7803455Sroot * force clear to end of line 7813455Sroot */ 7823455Sroot cleareol() 7833455Sroot { 7843594Sroot tputs(eraseln, 1, putch); 7853455Sroot } 7863455Sroot 7873594Sroot clreos() 7883455Sroot { 7893594Sroot tputs(EodClr, 1, putch); 7903455Sroot } 7913455Sroot 7923455Sroot /* 7931500Serics ** Print string and return number of characters 7941500Serics */ 7951500Serics 7961500Serics pr(s1) 7971500Serics char *s1; 7981500Serics { 7991500Serics register char *s; 8001500Serics register char c; 8011500Serics 8021500Serics for (s = s1; c = *s++; ) 8031500Serics putchar(c); 8041500Serics return (s - s1 - 1); 8051500Serics } 8061500Serics 8071500Serics 8081500Serics /* Print a buffer of n characters */ 8091500Serics 8101500Serics prbuf (s, n) 8111500Serics register char *s; 8121500Serics register int n; 8131500Serics { 81416710Sjak register char c; /* next output character */ 8153594Sroot register int state; /* next output char's UL state */ 81616710Sjak #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 8173594Sroot 8183594Sroot while (--n >= 0) 8193594Sroot if (!ul_opt) 8203594Sroot putchar (*s++); 8213594Sroot else { 82216710Sjak if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 82316710Sjak s++; 82416710Sjak continue; 82516710Sjak } 82616710Sjak if (state = wouldul(s, n)) { 82716710Sjak c = (*s == '_')? s[2] : *s ; 8283594Sroot n -= 2; 82916710Sjak s += 3; 83016710Sjak } else 8313594Sroot c = *s++; 83216710Sjak if (state != pstate) { 83316710Sjak if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 83416710Sjak state = 1; 83516710Sjak else 83616710Sjak tputs(state ? ULenter : ULexit, 1, putch); 8373594Sroot } 83816710Sjak if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 83916710Sjak putchar(c); 8403594Sroot if (state && *chUL) { 8413594Sroot pr(chBS); 8423594Sroot tputs(chUL, 1, putch); 8433594Sroot } 84416710Sjak pstate = state; 8453594Sroot } 8461500Serics } 8471500Serics 8481500Serics /* 8491500Serics ** Clear the screen 8501500Serics */ 8511500Serics 8521500Serics doclear() 8531500Serics { 8541500Serics if (Clear && !hard) { 8551500Serics tputs(Clear, 1, putch); 8561500Serics 8571500Serics /* Put out carriage return so that system doesn't 8581500Serics ** get confused by escape sequences when expanding tabs 8591500Serics */ 8601500Serics putchar ('\r'); 8611500Serics promptlen = 0; 8621500Serics } 8631500Serics } 8641500Serics 8653455Sroot /* 8663455Sroot * Go to home position 8673455Sroot */ 8683455Sroot home() 8693455Sroot { 8703455Sroot tputs(Home,1,putch); 8713455Sroot } 8723455Sroot 8731500Serics static int lastcmd, lastarg, lastp; 8741500Serics static int lastcolon; 8751500Serics char shell_line[132]; 8761500Serics 8771500Serics /* 8781500Serics ** Read a command and do it. A command consists of an optional integer 8791500Serics ** argument followed by the command character. Return the number of lines 8801500Serics ** to display in the next screenful. If there is nothing more to display 8811500Serics ** in the current file, zero is returned. 8821500Serics */ 8831500Serics 8841500Serics command (filename, f) 8851500Serics char *filename; 8861500Serics register FILE *f; 8871500Serics { 8881500Serics register int nlines; 8891500Serics register int retval; 8901500Serics register char c; 8911500Serics char colonch; 8921500Serics FILE *helpf; 8931500Serics int done; 8941500Serics char comchar, cmdbuf[80], *p; 8951500Serics 8961500Serics #define ret(val) retval=val;done++;break 8971500Serics 8981500Serics done = 0; 8991500Serics if (!errors) 9001500Serics prompt (filename); 9011500Serics else 9021500Serics errors = 0; 9031500Serics if (MBIT == RAW && slow_tty) { 9041500Serics otty.sg_flags |= MBIT; 90516582Sleres stty(fileno(stderr), &otty); 9061500Serics } 9071500Serics for (;;) { 9081500Serics nlines = number (&comchar); 9091500Serics lastp = colonch = 0; 9101500Serics if (comchar == '.') { /* Repeat last command */ 9111500Serics lastp++; 9121500Serics comchar = lastcmd; 9131500Serics nlines = lastarg; 9141500Serics if (lastcmd == ':') 9151500Serics colonch = lastcolon; 9161500Serics } 9171500Serics lastcmd = comchar; 9181500Serics lastarg = nlines; 9191500Serics if (comchar == otty.sg_erase) { 9201500Serics kill_line (); 9211500Serics prompt (filename); 9221500Serics continue; 9231500Serics } 9241500Serics switch (comchar) { 9251500Serics case ':': 9261500Serics retval = colon (filename, colonch, nlines); 9271500Serics if (retval >= 0) 9281500Serics done++; 9291500Serics break; 9301500Serics case ' ': 9311500Serics case 'z': 9321500Serics if (nlines == 0) nlines = dlines; 9331500Serics else if (comchar == 'z') dlines = nlines; 9341500Serics ret (nlines); 9351500Serics case 'd': 9361500Serics case ctrl(D): 9371500Serics if (nlines != 0) nscroll = nlines; 9381500Serics ret (nscroll); 9391500Serics case RUBOUT: 9401500Serics case 'q': 9411500Serics case 'Q': 9421500Serics end_it (); 9431500Serics case 's': 9441500Serics case 'f': 9451500Serics if (nlines == 0) nlines++; 9461500Serics if (comchar == 'f') 9471500Serics nlines *= dlines; 9481500Serics putchar ('\r'); 9491500Serics erase (0); 9503594Sroot printf ("\n"); 9513594Sroot if (clreol) 9523594Sroot cleareol (); 9533594Sroot printf ("...skipping %d line", nlines); 9541500Serics if (nlines > 1) 9553594Sroot pr ("s\n"); 9561500Serics else 9573594Sroot pr ("\n"); 9583594Sroot 9593594Sroot if (clreol) 9603594Sroot cleareol (); 9613594Sroot pr ("\n"); 9623594Sroot 9631500Serics while (nlines > 0) { 9641500Serics while ((c = Getc (f)) != '\n') 9651500Serics if (c == EOF) { 9661500Serics retval = 0; 9671500Serics done++; 9681500Serics goto endsw; 9691500Serics } 9701500Serics Currline++; 9711500Serics nlines--; 9721500Serics } 9731500Serics ret (dlines); 9741500Serics case '\n': 9751500Serics if (nlines != 0) 9761500Serics dlines = nlines; 9771500Serics else 9781500Serics nlines = 1; 9791500Serics ret (nlines); 9801500Serics case '\f': 9811500Serics if (!no_intty) { 9821500Serics doclear (); 9831500Serics Fseek (f, screen_start.chrctr); 9841500Serics Currline = screen_start.line; 9851500Serics ret (dlines); 9861500Serics } 9871500Serics else { 9881500Serics write (2, &bell, 1); 9891500Serics break; 9901500Serics } 9911500Serics case '\'': 9921500Serics if (!no_intty) { 9931500Serics kill_line (); 9941500Serics pr ("\n***Back***\n\n"); 9951500Serics Fseek (f, context.chrctr); 9961500Serics Currline = context.line; 9971500Serics ret (dlines); 9981500Serics } 9991500Serics else { 10001500Serics write (2, &bell, 1); 10011500Serics break; 10021500Serics } 10031500Serics case '=': 10041500Serics kill_line (); 10051500Serics promptlen = printd (Currline); 10061500Serics fflush (stdout); 10071500Serics break; 10081500Serics case 'n': 10091500Serics lastp++; 10101500Serics case '/': 10111500Serics if (nlines == 0) nlines++; 10121500Serics kill_line (); 10131500Serics pr ("/"); 10141500Serics promptlen = 1; 10151500Serics fflush (stdout); 10161500Serics if (lastp) { 10171500Serics write (2,"\r", 1); 10181500Serics search (NULL, f, nlines); /* Use previous r.e. */ 10191500Serics } 10201500Serics else { 10211500Serics ttyin (cmdbuf, 78, '/'); 10221500Serics write (2, "\r", 1); 10231500Serics search (cmdbuf, f, nlines); 10241500Serics } 10253455Sroot ret (dlines-1); 10261500Serics case '!': 10271500Serics do_shell (filename); 10281500Serics break; 10291500Serics case 'h': 10301500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 10311500Serics error ("Can't open help file"); 10321500Serics if (noscroll) doclear (); 10331500Serics copy_file (helpf); 10341500Serics close (helpf); 10351500Serics prompt (filename); 10361500Serics break; 10371500Serics case 'v': /* This case should go right before default */ 10381500Serics if (!no_intty) { 10391500Serics kill_line (); 10401500Serics cmdbuf[0] = '+'; 10411500Serics scanstr (Currline, &cmdbuf[1]); 10421500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 10431500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 10441500Serics break; 10451500Serics } 10461500Serics default: 104716710Sjak if (dum_opt) { 104816710Sjak kill_line (); 104916710Sjak if (Senter && Sexit) { 105016710Sjak tputs (Senter, 1, putch); 105116710Sjak promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 105216710Sjak tputs (Sexit, 1, putch); 105316710Sjak } 105416710Sjak else 105516710Sjak promptlen = pr ("[Press 'h' for instructions.]"); 105616710Sjak fflush (stdout); 105716710Sjak } 105816710Sjak else 105916710Sjak write (2, &bell, 1); 10601500Serics break; 10611500Serics } 10621500Serics if (done) break; 10631500Serics } 10641500Serics putchar ('\r'); 10651500Serics endsw: 10661500Serics inwait = 0; 10671500Serics notell++; 10681500Serics if (MBIT == RAW && slow_tty) { 10691500Serics otty.sg_flags &= ~MBIT; 107016582Sleres stty(fileno(stderr), &otty); 10711500Serics } 10721500Serics return (retval); 10731500Serics } 10741500Serics 10751500Serics char ch; 10761500Serics 10771500Serics /* 10781500Serics * Execute a colon-prefixed command. 10791500Serics * Returns <0 if not a command that should cause 10801500Serics * more of the file to be printed. 10811500Serics */ 10821500Serics 10831500Serics colon (filename, cmd, nlines) 10841500Serics char *filename; 10851500Serics int cmd; 10861500Serics int nlines; 10871500Serics { 10881500Serics if (cmd == 0) 10891500Serics ch = readch (); 10901500Serics else 10911500Serics ch = cmd; 10921500Serics lastcolon = ch; 10931500Serics switch (ch) { 10941500Serics case 'f': 10951500Serics kill_line (); 10961500Serics if (!no_intty) 10971500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 10981500Serics else 10991500Serics promptlen = printf ("[Not a file] line %d", Currline); 11001500Serics fflush (stdout); 11011500Serics return (-1); 11021500Serics case 'n': 11031500Serics if (nlines == 0) { 11041500Serics if (fnum >= nfiles - 1) 11051500Serics end_it (); 11061500Serics nlines++; 11071500Serics } 11081500Serics putchar ('\r'); 11091500Serics erase (0); 11101500Serics skipf (nlines); 11111500Serics return (0); 11121500Serics case 'p': 11131500Serics if (no_intty) { 11141500Serics write (2, &bell, 1); 11151500Serics return (-1); 11161500Serics } 11171500Serics putchar ('\r'); 11181500Serics erase (0); 11191500Serics if (nlines == 0) 11201500Serics nlines++; 11211500Serics skipf (-nlines); 11221500Serics return (0); 11231500Serics case '!': 11241500Serics do_shell (filename); 11251500Serics return (-1); 11261500Serics case 'q': 11271500Serics case 'Q': 11281500Serics end_it (); 11291500Serics default: 11301500Serics write (2, &bell, 1); 11311500Serics return (-1); 11321500Serics } 11331500Serics } 11341500Serics 11351500Serics /* 11361500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 11371500Serics ** terminates the number. 11381500Serics */ 11391500Serics 11401500Serics number(cmd) 11411500Serics char *cmd; 11421500Serics { 11431500Serics register int i; 11441500Serics 11451500Serics i = 0; ch = otty.sg_kill; 11461500Serics for (;;) { 11471500Serics ch = readch (); 11481500Serics if (ch >= '0' && ch <= '9') 11491500Serics i = i*10 + ch - '0'; 11501500Serics else if (ch == otty.sg_kill) 11511500Serics i = 0; 11521500Serics else { 11531500Serics *cmd = ch; 11541500Serics break; 11551500Serics } 11561500Serics } 11571500Serics return (i); 11581500Serics } 11591500Serics 11601500Serics do_shell (filename) 11611500Serics char *filename; 11621500Serics { 11631500Serics char cmdbuf[80]; 11641500Serics 11651500Serics kill_line (); 11661500Serics pr ("!"); 11671500Serics fflush (stdout); 11681500Serics promptlen = 1; 11691500Serics if (lastp) 11701500Serics pr (shell_line); 11711500Serics else { 11721500Serics ttyin (cmdbuf, 78, '!'); 11731500Serics if (expand (shell_line, cmdbuf)) { 11741500Serics kill_line (); 11751500Serics promptlen = printf ("!%s", shell_line); 11761500Serics } 11771500Serics } 11781500Serics fflush (stdout); 11791500Serics write (2, "\n", 1); 11801500Serics promptlen = 0; 11811500Serics shellp = 1; 11821500Serics execute (filename, shell, shell, "-c", shell_line, 0); 11831500Serics } 11841500Serics 11851500Serics /* 11861500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 11871500Serics */ 11881500Serics 11891500Serics search (buf, file, n) 11901500Serics char buf[]; 11911500Serics FILE *file; 11921500Serics register int n; 11931500Serics { 11941500Serics long startline = Ftell (file); 11951500Serics register long line1 = startline; 11961500Serics register long line2 = startline; 11971500Serics register long line3 = startline; 11981500Serics register int lncount; 11991500Serics int saveln, rv, re_exec(); 12001500Serics char *s, *re_comp(); 12011500Serics 12021500Serics context.line = saveln = Currline; 12031500Serics context.chrctr = startline; 12041500Serics lncount = 0; 12051500Serics if ((s = re_comp (buf)) != 0) 12061500Serics error (s); 12071500Serics while (!feof (file)) { 12081500Serics line3 = line2; 12091500Serics line2 = line1; 12101500Serics line1 = Ftell (file); 12111500Serics rdline (file); 12121500Serics lncount++; 12131500Serics if ((rv = re_exec (Line)) == 1) 12141500Serics if (--n == 0) { 12151500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 12163455Sroot { 12173455Sroot pr ("\n"); 12183594Sroot if (clreol) 12193594Sroot cleareol (); 12203455Sroot pr("...skipping\n"); 12213455Sroot } 12221500Serics if (!no_intty) { 12231500Serics Currline -= (lncount >= 3 ? 3 : lncount); 12241500Serics Fseek (file, line3); 12253594Sroot if (noscroll) 12263594Sroot if (clreol) { 12273594Sroot home (); 12283594Sroot cleareol (); 122916582Sleres } 12303594Sroot else 12313594Sroot doclear (); 12321500Serics } 12331500Serics else { 12341500Serics kill_line (); 12353594Sroot if (noscroll) 12363594Sroot if (clreol) { 123716582Sleres home (); 12383594Sroot cleareol (); 123916582Sleres } 12403594Sroot else 12413594Sroot doclear (); 12421500Serics pr (Line); 12431500Serics putchar ('\n'); 12441500Serics } 12451500Serics break; 12461500Serics } 12471500Serics else if (rv == -1) 12481500Serics error ("Regular expression botch"); 12491500Serics } 12501500Serics if (feof (file)) { 12511500Serics if (!no_intty) { 12521500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 12531500Serics Currline = saveln; 12541500Serics Fseek (file, startline); 12551500Serics } 12561500Serics else { 12571500Serics pr ("\nPattern not found\n"); 12581500Serics end_it (); 12591500Serics } 12601500Serics error ("Pattern not found"); 12611500Serics } 12621500Serics } 12631500Serics 12641500Serics execute (filename, cmd, args) 12651500Serics char *filename; 12661500Serics char *cmd, *args; 12671500Serics { 12681500Serics int id; 126916710Sjak int n; 12701500Serics 12711500Serics fflush (stdout); 12721500Serics reset_tty (); 127316710Sjak for (n = 10; (id = fork ()) < 0 && n > 0; n--) 12741500Serics sleep (5); 12751500Serics if (id == 0) { 127616710Sjak if (!isatty(0)) { 127716710Sjak close(0); 127816710Sjak open("/dev/tty", 0); 127916710Sjak } 12801500Serics execv (cmd, &args); 12811500Serics write (2, "exec failed\n", 12); 12821500Serics exit (1); 12831500Serics } 128416710Sjak if (id > 0) { 128516710Sjak signal (SIGINT, SIG_IGN); 128616710Sjak signal (SIGQUIT, SIG_IGN); 128716710Sjak if (catch_susp) 128816710Sjak signal(SIGTSTP, SIG_DFL); 128916710Sjak while (wait(0) > 0); 129016710Sjak signal (SIGINT, end_it); 129116710Sjak signal (SIGQUIT, onquit); 129216710Sjak if (catch_susp) 129316710Sjak signal(SIGTSTP, onsusp); 129416710Sjak } else 129516710Sjak write(2, "can't fork\n", 11); 12961500Serics set_tty (); 12971500Serics pr ("------------------------\n"); 12981500Serics prompt (filename); 12991500Serics } 13001500Serics /* 13011500Serics ** Skip n lines in the file f 13021500Serics */ 13031500Serics 13041500Serics skiplns (n, f) 13051500Serics register int n; 13061500Serics register FILE *f; 13071500Serics { 13081500Serics register char c; 13091500Serics 13101500Serics while (n > 0) { 13111500Serics while ((c = Getc (f)) != '\n') 13121500Serics if (c == EOF) 13131500Serics return; 13141500Serics n--; 13151500Serics Currline++; 13161500Serics } 13171500Serics } 13181500Serics 13191500Serics /* 13201500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 13211500Serics ** negative. 13221500Serics */ 13231500Serics 13241500Serics skipf (nskip) 13251500Serics register int nskip; 13261500Serics { 13271500Serics if (nskip == 0) return; 13281500Serics if (nskip > 0) { 13291500Serics if (fnum + nskip > nfiles - 1) 13301500Serics nskip = nfiles - fnum - 1; 13311500Serics } 13321500Serics else if (within) 13331500Serics ++fnum; 13341500Serics fnum += nskip; 13351500Serics if (fnum < 0) 13361500Serics fnum = 0; 13373594Sroot pr ("\n...Skipping "); 13383455Sroot pr ("\n"); 13393594Sroot if (clreol) 13403594Sroot cleareol (); 13413455Sroot pr ("...Skipping "); 13421500Serics pr (nskip > 0 ? "to file " : "back to file "); 13431500Serics pr (fnames[fnum]); 13443455Sroot pr ("\n"); 13453594Sroot if (clreol) 13463594Sroot cleareol (); 13473455Sroot pr ("\n"); 13481500Serics --fnum; 13491500Serics } 13501500Serics 13511500Serics /*----------------------------- Terminal I/O -------------------------------*/ 13521500Serics 13531500Serics initterm () 13541500Serics { 13551500Serics char buf[TBUFSIZ]; 135617195Sralph static char clearbuf[TBUFSIZ]; 13571500Serics char *clearptr, *padstr; 13581500Serics int ldisc; 135917592Sleres int lmode; 136010823Ssam char *term; 136116582Sleres int tgrp; 136218030Sbloom struct winsize win; 13631500Serics 136416582Sleres retry: 136516582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 136617592Sleres if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { 136717592Sleres perror("TIOCLGET"); 136817592Sleres exit(1); 136917592Sleres } 137017592Sleres docrterase = ((lmode & LCRTERA) != 0); 137117592Sleres docrtkill = ((lmode & LCRTKIL) != 0); 137216582Sleres /* 137317592Sleres * Wait until we're in the foreground before we save the 137417592Sleres * the terminal modes. 137516582Sleres */ 137616582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 137717592Sleres perror("TIOCGPGRP"); 137816582Sleres exit(1); 137916582Sleres } 138016582Sleres if (tgrp != getpgrp(0)) { 138116582Sleres kill(0, SIGTTOU); 138216582Sleres goto retry; 138316582Sleres } 138413830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 13853594Sroot dumb++; ul_opt = 0; 13861500Serics } 13871500Serics else { 138818030Sbloom if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { 138918030Sbloom Lpp = tgetnum("li"); 139018030Sbloom Mcol = tgetnum("co"); 139118030Sbloom } else { 139218030Sbloom if ((Lpp = win.ws_row) == 0) 139318030Sbloom Lpp = tgetnum("li"); 139418030Sbloom if ((Mcol = win.ws_col) == 0) 139518030Sbloom Mcol = tgetnum("co"); 139618030Sbloom } 139718030Sbloom if ((Lpp <= 0) || tgetflag("hc")) { 13981500Serics hard++; /* Hard copy terminal */ 13991500Serics Lpp = 24; 14001500Serics } 140118030Sbloom if (Mcol <= 0) 140218030Sbloom Mcol = 80; 140318030Sbloom 14041500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 14051500Serics noscroll++; 14061500Serics Wrap = tgetflag("am"); 14071500Serics bad_so = tgetflag ("xs"); 14081500Serics clearptr = clearbuf; 14091500Serics eraseln = tgetstr("ce",&clearptr); 14101500Serics Clear = tgetstr("cl", &clearptr); 14111500Serics Senter = tgetstr("so", &clearptr); 14121500Serics Sexit = tgetstr("se", &clearptr); 141316710Sjak if ((soglitch = tgetnum("sg")) < 0) 141416710Sjak soglitch = 0; 14153594Sroot 14163594Sroot /* 14173594Sroot * Set up for underlining: some terminals don't need it; 14183594Sroot * others have start/stop sequences, still others have an 14193594Sroot * underline char sequence which is assumed to move the 14203594Sroot * cursor forward one character. If underline sequence 14213594Sroot * isn't available, settle for standout sequence. 14223594Sroot */ 14233594Sroot 14243594Sroot if (tgetflag("ul") || tgetflag("os")) 14253594Sroot ul_opt = 0; 14263594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 14273594Sroot chUL = ""; 142816710Sjak if (((ULenter = tgetstr("us", &clearptr)) == NULL || 142916710Sjak (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 143016710Sjak if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 143116710Sjak ULenter = ""; 143216710Sjak ULexit = ""; 143316710Sjak } else 143416710Sjak ulglitch = soglitch; 143516710Sjak } else { 143616710Sjak if ((ulglitch = tgetnum("ug")) < 0) 143716710Sjak ulglitch = 0; 143816710Sjak } 143916582Sleres 14401500Serics if (padstr = tgetstr("pc", &clearptr)) 14411500Serics PC = *padstr; 14423455Sroot Home = tgetstr("ho",&clearptr); 144313536Ssam if (Home == 0 || *Home == '\0') 14443455Sroot { 14453594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 14463594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 14473455Sroot Home = cursorhome; 14483455Sroot } 14493455Sroot } 14503594Sroot EodClr = tgetstr("cd", &clearptr); 14511500Serics } 14521500Serics if ((shell = getenv("SHELL")) == NULL) 14531500Serics shell = "/bin/sh"; 14541500Serics } 145516582Sleres no_intty = gtty(fileno(stdin), &otty); 145616582Sleres gtty(fileno(stderr), &otty); 145713830Skre savetty = otty; 14581500Serics ospeed = otty.sg_ospeed; 14591500Serics slow_tty = ospeed < B1200; 14601500Serics hardtabs = !(otty.sg_flags & XTABS); 14611500Serics if (!no_tty) { 14621500Serics otty.sg_flags &= ~ECHO; 14631500Serics if (MBIT == CBREAK || !slow_tty) 14641500Serics otty.sg_flags |= MBIT; 14651500Serics } 14661500Serics } 14671500Serics 14681500Serics readch () 14691500Serics { 14701500Serics char ch; 14711500Serics extern int errno; 14721500Serics 14731500Serics if (read (2, &ch, 1) <= 0) 14741500Serics if (errno != EINTR) 14751500Serics exit(0); 14761500Serics else 14771500Serics ch = otty.sg_kill; 14781500Serics return (ch); 14791500Serics } 14801500Serics 14811500Serics static char BS = '\b'; 148217592Sleres static char *BSB = "\b \b"; 14831500Serics static char CARAT = '^'; 148417592Sleres #define ERASEONECHAR \ 148517592Sleres if (docrterase) \ 148617592Sleres write (2, BSB, sizeof(BSB)); \ 148717592Sleres else \ 148817592Sleres write (2, &BS, sizeof(BS)); 14891500Serics 14901500Serics ttyin (buf, nmax, pchar) 14911500Serics char buf[]; 14921500Serics register int nmax; 14931500Serics char pchar; 14941500Serics { 14951500Serics register char *sptr; 14961500Serics register char ch; 14971500Serics register int slash = 0; 14981500Serics int maxlen; 14991500Serics char cbuf; 15001500Serics 15011500Serics sptr = buf; 15021500Serics maxlen = 0; 15031500Serics while (sptr - buf < nmax) { 15041500Serics if (promptlen > maxlen) maxlen = promptlen; 15051500Serics ch = readch (); 15061500Serics if (ch == '\\') { 15071500Serics slash++; 15081500Serics } 15091500Serics else if ((ch == otty.sg_erase) && !slash) { 15101500Serics if (sptr > buf) { 15111500Serics --promptlen; 151217592Sleres ERASEONECHAR 15131500Serics --sptr; 15141500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 15151500Serics --promptlen; 151617592Sleres ERASEONECHAR 15171500Serics } 15181500Serics continue; 15191500Serics } 15201500Serics else { 15211500Serics if (!eraseln) promptlen = maxlen; 15221500Serics longjmp (restore, 1); 15231500Serics } 15241500Serics } 15251500Serics else if ((ch == otty.sg_kill) && !slash) { 15261500Serics if (hard) { 15271500Serics show (ch); 15281500Serics putchar ('\n'); 15291500Serics putchar (pchar); 15301500Serics } 15311500Serics else { 15321500Serics putchar ('\r'); 15331500Serics putchar (pchar); 15341500Serics if (eraseln) 15351500Serics erase (1); 153617592Sleres else if (docrtkill) 153717592Sleres while (promptlen-- > 1) 153817592Sleres write (2, BSB, sizeof(BSB)); 15391500Serics promptlen = 1; 15401500Serics } 15411500Serics sptr = buf; 15421500Serics fflush (stdout); 15431500Serics continue; 15441500Serics } 15451500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 154617592Sleres ERASEONECHAR 15471500Serics --sptr; 15481500Serics } 15491500Serics if (ch != '\\') 15501500Serics slash = 0; 15511500Serics *sptr++ = ch; 15521500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 15531500Serics ch += ch == RUBOUT ? -0100 : 0100; 15541500Serics write (2, &CARAT, 1); 15551500Serics promptlen++; 15561500Serics } 15571500Serics cbuf = ch; 15581500Serics if (ch != '\n' && ch != ESC) { 15591500Serics write (2, &cbuf, 1); 15601500Serics promptlen++; 15611500Serics } 15621500Serics else 15631500Serics break; 15641500Serics } 15651500Serics *--sptr = '\0'; 15661500Serics if (!eraseln) promptlen = maxlen; 15671500Serics if (sptr - buf >= nmax - 1) 15681500Serics error ("Line too long"); 15691500Serics } 15701500Serics 15711500Serics expand (outbuf, inbuf) 15721500Serics char *outbuf; 15731500Serics char *inbuf; 15741500Serics { 15751500Serics register char *instr; 15761500Serics register char *outstr; 15771500Serics register char ch; 15781500Serics char temp[200]; 15791500Serics int changed = 0; 15801500Serics 15811500Serics instr = inbuf; 15821500Serics outstr = temp; 15831500Serics while ((ch = *instr++) != '\0') 15841500Serics switch (ch) { 15851500Serics case '%': 15861500Serics if (!no_intty) { 15871500Serics strcpy (outstr, fnames[fnum]); 15881500Serics outstr += strlen (fnames[fnum]); 15891500Serics changed++; 15901500Serics } 15911500Serics else 15921500Serics *outstr++ = ch; 15931500Serics break; 15941500Serics case '!': 15951500Serics if (!shellp) 15961500Serics error ("No previous command to substitute for"); 15971500Serics strcpy (outstr, shell_line); 15981500Serics outstr += strlen (shell_line); 15991500Serics changed++; 16001500Serics break; 16011500Serics case '\\': 16021500Serics if (*instr == '%' || *instr == '!') { 16031500Serics *outstr++ = *instr++; 16041500Serics break; 16051500Serics } 16061500Serics default: 16071500Serics *outstr++ = ch; 16081500Serics } 16091500Serics *outstr++ = '\0'; 16101500Serics strcpy (outbuf, temp); 16111500Serics return (changed); 16121500Serics } 16131500Serics 16141500Serics show (ch) 16151500Serics register char ch; 16161500Serics { 16171500Serics char cbuf; 16181500Serics 16191500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 16201500Serics ch += ch == RUBOUT ? -0100 : 0100; 16211500Serics write (2, &CARAT, 1); 16221500Serics promptlen++; 16231500Serics } 16241500Serics cbuf = ch; 16251500Serics write (2, &cbuf, 1); 16261500Serics promptlen++; 16271500Serics } 16281500Serics 16291500Serics error (mess) 16301500Serics char *mess; 16311500Serics { 16323594Sroot if (clreol) 16333594Sroot cleareol (); 16343594Sroot else 16353594Sroot kill_line (); 16361500Serics promptlen += strlen (mess); 16371500Serics if (Senter && Sexit) { 16381500Serics tputs (Senter, 1, putch); 16391500Serics pr(mess); 16401500Serics tputs (Sexit, 1, putch); 16411500Serics } 16421500Serics else 16431500Serics pr (mess); 16441500Serics fflush(stdout); 16451500Serics errors++; 16461500Serics longjmp (restore, 1); 16471500Serics } 16481500Serics 16491500Serics 16501500Serics set_tty () 16511500Serics { 16521500Serics otty.sg_flags |= MBIT; 16531500Serics otty.sg_flags &= ~ECHO; 165416582Sleres stty(fileno(stderr), &otty); 16551500Serics } 16561500Serics 16571500Serics reset_tty () 16581500Serics { 165916710Sjak if (pstate) { 166016710Sjak tputs(ULexit, 1, putch); 166116710Sjak fflush(stdout); 166216710Sjak pstate = 0; 166316710Sjak } 16641500Serics otty.sg_flags |= ECHO; 16651500Serics otty.sg_flags &= ~MBIT; 166616582Sleres stty(fileno(stderr), &savetty); 16671500Serics } 16681500Serics 16691500Serics rdline (f) 16701500Serics register FILE *f; 16711500Serics { 16721500Serics register char c; 16731500Serics register char *p; 16741500Serics 16751500Serics p = Line; 16761500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 16771500Serics *p++ = c; 16781500Serics if (c == '\n') 16791500Serics Currline++; 16801500Serics *p = '\0'; 16811500Serics } 16821500Serics 16831500Serics /* Come here when we get a suspend signal from the terminal */ 16841500Serics 16851500Serics onsusp () 16861500Serics { 168714861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 168814861Skarels signal(SIGTTOU, SIG_IGN); 16891500Serics reset_tty (); 16901500Serics fflush (stdout); 169114861Skarels signal(SIGTTOU, SIG_DFL); 16921500Serics /* Send the TSTP signal to suspend our process group */ 169313289Ssam signal(SIGTSTP, SIG_DFL); 169413289Ssam sigsetmask(0); 16951500Serics kill (0, SIGTSTP); 16961500Serics /* Pause for station break */ 16971500Serics 16981500Serics /* We're back */ 16991500Serics signal (SIGTSTP, onsusp); 17001500Serics set_tty (); 17011500Serics if (inwait) 17021500Serics longjmp (restore); 17031500Serics } 1704