121981Sdist /* 221981Sdist * Copyright (c) 1980 Regents of the University of California. 321981Sdist * All rights reserved. The Berkeley software License Agreement 421981Sdist * specifies the terms and conditions for redistribution. 521981Sdist */ 621981Sdist 713615Ssam #ifndef lint 821981Sdist char copyright[] = 921981Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1021981Sdist All rights reserved.\n"; 1121981Sdist #endif not lint 123594Sroot 1321981Sdist #ifndef lint 14*32273Sbostic static char sccsid[] = "@(#)more.c 5.13 (Berkeley) 09/28/87"; 1521981Sdist #endif not lint 1621981Sdist 171500Serics /* 181500Serics ** more.c - General purpose tty output filter and file perusal program 191500Serics ** 201500Serics ** by Eric Shienbrood, UC Berkeley 213594Sroot ** 223594Sroot ** modified by Geoff Peck, UCB to add underlining, single spacing 233594Sroot ** modified by John Foderaro, UCB to add -c and MORE environment variable 241500Serics */ 251500Serics 261500Serics #include <stdio.h> 2717592Sleres #include <sys/types.h> 281500Serics #include <ctype.h> 291500Serics #include <signal.h> 301500Serics #include <errno.h> 311500Serics #include <sgtty.h> 321500Serics #include <setjmp.h> 331500Serics #include <sys/stat.h> 3429906Smckusick #include <sys/file.h> 3529906Smckusick #include <sys/exec.h> 361500Serics 3713615Ssam #define HELPFILE "/usr/lib/more.help" 3813615Ssam #define VI "/usr/ucb/vi" 391500Serics 401500Serics #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) 411500Serics #define Ftell(f) file_pos 421500Serics #define Fseek(f,off) (file_pos=off,fseek(f,off,0)) 431500Serics #define Getc(f) (++file_pos, getc(f)) 441500Serics #define Ungetc(c,f) (--file_pos, ungetc(c,f)) 451500Serics 461500Serics #define MBIT CBREAK 471500Serics #define stty(fd,argp) ioctl(fd,TIOCSETN,argp) 481500Serics 491500Serics #define TBUFSIZ 1024 501500Serics #define LINSIZ 256 511500Serics #define ctrl(letter) ('letter' & 077) 521500Serics #define RUBOUT '\177' 531500Serics #define ESC '\033' 541500Serics #define QUIT '\034' 551500Serics 5616582Sleres struct sgttyb otty, savetty; 571500Serics long file_pos, file_size; 581500Serics int fnum, no_intty, no_tty, slow_tty; 5927006Sdonn int dum_opt, dlines, onquit(), end_it(), chgwinsz(); 601500Serics int onsusp(); 611500Serics int nscroll = 11; /* Number of lines scrolled by 'd' */ 621500Serics int fold_opt = 1; /* Fold long lines */ 631500Serics int stop_opt = 1; /* Stop after form feeds */ 643594Sroot int ssp_opt = 0; /* Suppress white space */ 653594Sroot int ul_opt = 1; /* Underline as best we can */ 661500Serics int promptlen; 671500Serics int Currline; /* Line we are currently at */ 681500Serics int startup = 1; 691500Serics int firstf = 1; 701500Serics int notell = 1; 7117592Sleres int docrterase = 0; 7217592Sleres int docrtkill = 0; 731500Serics int bad_so; /* True if overwriting does not turn off standout */ 741500Serics int inwait, Pause, errors; 751500Serics int within; /* true if we are within a file, 761500Serics false if we are between files */ 7729907Smckusick int hard, dumb, noscroll, hardtabs, clreol, eatnl; 781500Serics int catch_susp; /* We should catch the SIGTSTP signal */ 791500Serics char **fnames; /* The list of file names */ 801500Serics int nfiles; /* Number of files left to process */ 811500Serics char *shell; /* The name of the shell to use */ 821500Serics int shellp; /* A previous shell command exists */ 831500Serics char ch; 841500Serics jmp_buf restore; 851500Serics char Line[LINSIZ]; /* Line buffer */ 861500Serics int Lpp = 24; /* lines per page */ 871500Serics char *Clear; /* clear screen */ 881500Serics char *eraseln; /* erase line */ 891500Serics char *Senter, *Sexit;/* enter and exit standout mode */ 903594Sroot char *ULenter, *ULexit; /* enter and exit underline mode */ 913594Sroot char *chUL; /* underline character */ 923594Sroot char *chBS; /* backspace character */ 933455Sroot char *Home; /* go to home */ 943455Sroot char *cursorm; /* cursor movement */ 953455Sroot char cursorhome[40]; /* contains cursor movement to home */ 963594Sroot char *EodClr; /* clear rest of screen */ 971500Serics char *tgetstr(); 981500Serics int Mcol = 80; /* number of columns */ 991500Serics int Wrap = 1; /* set if automargins */ 10016710Sjak int soglitch; /* terminal has standout mode glitch */ 10116710Sjak int ulglitch; /* terminal has underline mode glitch */ 10216710Sjak int pstate = 0; /* current UL state */ 1031500Serics long fseek(); 1043455Sroot char *getenv(); 1051500Serics struct { 1061500Serics long chrctr, line; 1071500Serics } context, screen_start; 1081500Serics extern char PC; /* pad character */ 1091500Serics extern short ospeed; 1101500Serics 1111500Serics 1121500Serics main(argc, argv) 1131500Serics int argc; 1141500Serics char *argv[]; 1151500Serics { 1161500Serics register FILE *f; 1171500Serics register char *s; 1181500Serics register char *p; 1191500Serics register char ch; 1201500Serics register int left; 12116582Sleres int prnames = 0; 1221500Serics int initopt = 0; 1231500Serics int srchopt = 0; 1241500Serics int clearit = 0; 1251500Serics int initline; 1261500Serics char initbuf[80]; 1271500Serics FILE *checkf(); 1281500Serics 1291500Serics nfiles = argc; 1301500Serics fnames = argv; 1311500Serics initterm (); 13215813Sralph nscroll = Lpp/2 - 1; 13315813Sralph if (nscroll <= 0) 13415813Sralph nscroll = 1; 1353455Sroot if(s = getenv("MORE")) argscan(s); 1361500Serics while (--nfiles > 0) { 1371500Serics if ((ch = (*++fnames)[0]) == '-') { 1383455Sroot argscan(*fnames+1); 1391500Serics } 1401500Serics else if (ch == '+') { 1411500Serics s = *fnames; 1421500Serics if (*++s == '/') { 1431500Serics srchopt++; 1441500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1451500Serics *p++ = *s++; 1461500Serics *p = '\0'; 1471500Serics } 1481500Serics else { 1491500Serics initopt++; 1501500Serics for (initline = 0; *s != '\0'; s++) 1511500Serics if (isdigit (*s)) 1521500Serics initline = initline*10 + *s -'0'; 1531500Serics --initline; 1541500Serics } 1551500Serics } 1561500Serics else break; 1571500Serics } 1583594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1593455Sroot * defined, and in that case, make sure we are in noscroll mode 1603455Sroot */ 1613455Sroot if(clreol) 1623455Sroot { 16318608Sralph if((Home == NULL) || (*Home == '\0') || 16418608Sralph (eraseln == NULL) || (*eraseln == '\0') || 16518608Sralph (EodClr == NULL) || (*EodClr == '\0') ) 16618608Sralph clreol = 0; 1673455Sroot else noscroll = 1; 1683455Sroot } 1691500Serics if (dlines == 0) 1701500Serics dlines = Lpp - (noscroll ? 1 : 2); 1711500Serics left = dlines; 1721500Serics if (nfiles > 1) 1731500Serics prnames++; 1741500Serics if (!no_intty && nfiles == 0) { 1751500Serics fputs("Usage: ",stderr); 1761500Serics fputs(argv[0],stderr); 1771500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1781500Serics exit(1); 1791500Serics } 1801500Serics else 1811500Serics f = stdin; 1821500Serics if (!no_tty) { 1831500Serics signal(SIGQUIT, onquit); 1841500Serics signal(SIGINT, end_it); 18527006Sdonn signal(SIGWINCH, chgwinsz); 1861500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1871500Serics signal(SIGTSTP, onsusp); 1881500Serics catch_susp++; 1891500Serics } 19016582Sleres stty (fileno(stderr), &otty); 1911500Serics } 1921500Serics if (no_intty) { 1931500Serics if (no_tty) 1941500Serics copy_file (stdin); 1951500Serics else { 1961500Serics if ((ch = Getc (f)) == '\f') 1973594Sroot doclear(); 1981500Serics else { 1991500Serics Ungetc (ch, f); 2003594Sroot if (noscroll && (ch != EOF)) { 2013594Sroot if (clreol) 2023594Sroot home (); 2033594Sroot else 2043594Sroot doclear (); 2053455Sroot } 2061500Serics } 2071500Serics if (srchopt) 2083455Sroot { 2091500Serics search (initbuf, stdin, 1); 2103594Sroot if (noscroll) 2113594Sroot left--; 2123455Sroot } 2131500Serics else if (initopt) 2141500Serics skiplns (initline, stdin); 2151500Serics screen (stdin, left); 2161500Serics } 2171500Serics no_intty = 0; 2181500Serics prnames++; 2191500Serics firstf = 0; 2201500Serics } 2211500Serics 2221500Serics while (fnum < nfiles) { 2231500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2241500Serics context.line = context.chrctr = 0; 2251500Serics Currline = 0; 2261500Serics if (firstf) setjmp (restore); 2271500Serics if (firstf) { 2281500Serics firstf = 0; 2291500Serics if (srchopt) 2303455Sroot { 2311500Serics search (initbuf, f, 1); 2323594Sroot if (noscroll) 2333594Sroot left--; 2343455Sroot } 2351500Serics else if (initopt) 2361500Serics skiplns (initline, f); 2371500Serics } 2381500Serics else if (fnum < nfiles && !no_tty) { 2391500Serics setjmp (restore); 2401500Serics left = command (fnames[fnum], f); 2411500Serics } 2421500Serics if (left != 0) { 2433594Sroot if ((noscroll || clearit) && (file_size != 0x7fffffffffffffffL)) 2443594Sroot if (clreol) 2453594Sroot home (); 2463594Sroot else 2473594Sroot doclear (); 2481500Serics if (prnames) { 2491500Serics if (bad_so) 2501500Serics erase (0); 2513594Sroot if (clreol) 2523594Sroot cleareol (); 2531500Serics pr("::::::::::::::"); 2541500Serics if (promptlen > 14) 2551500Serics erase (14); 2563455Sroot printf ("\n"); 2573455Sroot if(clreol) cleareol(); 2583455Sroot printf("%s\n", fnames[fnum]); 2593455Sroot if(clreol) cleareol(); 26030931Sbostic printf("::::::::::::::\n"); 2611500Serics if (left > Lpp - 4) 2621500Serics left = Lpp - 4; 2631500Serics } 2641500Serics if (no_tty) 2651500Serics copy_file (f); 2661500Serics else { 2671500Serics within++; 2681500Serics screen(f, left); 2691500Serics within = 0; 2701500Serics } 2711500Serics } 2721500Serics setjmp (restore); 2731500Serics fflush(stdout); 2741500Serics fclose(f); 2751500Serics screen_start.line = screen_start.chrctr = 0L; 2761500Serics context.line = context.chrctr = 0L; 2771500Serics } 2781500Serics fnum++; 2791500Serics firstf = 0; 2801500Serics } 2811500Serics reset_tty (); 2821500Serics exit(0); 2831500Serics } 2841500Serics 2853455Sroot argscan(s) 2863455Sroot char *s; 2873455Sroot { 288*32273Sbostic int seen_num = 0; 289*32273Sbostic 290*32273Sbostic while (*s != '\0') { 291*32273Sbostic switch (*s) { 29211604Slayer case '0': case '1': case '2': 29311604Slayer case '3': case '4': case '5': 29411604Slayer case '6': case '7': case '8': 29511604Slayer case '9': 296*32273Sbostic if (!seen_num) { 297*32273Sbostic dlines = 0; 298*32273Sbostic seen_num = 1; 299*32273Sbostic } 30011604Slayer dlines = dlines*10 + *s - '0'; 30111604Slayer break; 30211604Slayer case 'd': 30311604Slayer dum_opt = 1; 30411604Slayer break; 30511604Slayer case 'l': 30611604Slayer stop_opt = 0; 30711604Slayer break; 30811604Slayer case 'f': 30911604Slayer fold_opt = 0; 31011604Slayer break; 31111604Slayer case 'p': 31211604Slayer noscroll++; 31311604Slayer break; 31411604Slayer case 'c': 31511604Slayer clreol++; 31611604Slayer break; 31711604Slayer case 's': 31811604Slayer ssp_opt = 1; 31911604Slayer break; 32011604Slayer case 'u': 32111604Slayer ul_opt = 0; 32211604Slayer break; 32311604Slayer } 324*32273Sbostic s++; 32511604Slayer } 3263455Sroot } 3273455Sroot 3283455Sroot 3291500Serics /* 3301500Serics ** Check whether the file named by fs is an ASCII file which the user may 3311500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3321500Serics */ 3331500Serics 3341500Serics FILE * 3351500Serics checkf (fs, clearfirst) 3361500Serics register char *fs; 3371500Serics int *clearfirst; 3381500Serics { 3391500Serics struct stat stbuf; 3401500Serics register FILE *f; 3411500Serics char c; 3421500Serics 3431500Serics if (stat (fs, &stbuf) == -1) { 3441500Serics fflush(stdout); 3453594Sroot if (clreol) 3463594Sroot cleareol (); 3471500Serics perror(fs); 3481500Serics return (NULL); 3491500Serics } 3501500Serics if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 3511500Serics printf("\n*** %s: directory ***\n\n", fs); 3521500Serics return (NULL); 3531500Serics } 3541500Serics if ((f=Fopen(fs, "r")) == NULL) { 3551500Serics fflush(stdout); 3561500Serics perror(fs); 3571500Serics return (NULL); 3581500Serics } 3591500Serics /* Try to see whether it is an ASCII file */ 36029906Smckusick if (magic(f)) { 3611500Serics printf("\n******** %s: Not a text file ********\n\n", fs); 3621500Serics fclose (f); 3631500Serics return (NULL); 3641500Serics } 36529906Smckusick c = Getc(f); 3661500Serics if (c == '\f') 3671500Serics *clearfirst = 1; 3681500Serics else { 3691500Serics *clearfirst = 0; 3701500Serics Ungetc (c, f); 3711500Serics } 3721500Serics if ((file_size = stbuf.st_size) == 0) 3731500Serics file_size = 0x7fffffffffffffffL; 3741500Serics return (f); 3751500Serics } 3761500Serics 3771500Serics /* 37829906Smckusick * Check for file magic numbers. This code would best 37929906Smckusick * be shared with the file(1) program or, perhaps, more 38029906Smckusick * should not try and be so smart? 38129906Smckusick */ 38229906Smckusick magic(f) 38329906Smckusick FILE *f; 38429906Smckusick { 38529906Smckusick long magic; 38629906Smckusick 38729906Smckusick magic = getw(f); 38831125Smckusick if (ftell(f) < sizeof magic) 38931125Smckusick rewind(f); /* reset file position */ 39031125Smckusick else 39131125Smckusick fseek(f, -sizeof (magic), L_INCR); /* reset file position */ 39229906Smckusick return (magic == 0405 || magic == OMAGIC || magic == NMAGIC || 39329906Smckusick magic == 0411 || magic == ZMAGIC || magic == 0177545); 39429906Smckusick } 39529906Smckusick 39629906Smckusick /* 3971500Serics ** A real function, for the tputs routine in termlib 3981500Serics */ 3991500Serics 4001500Serics putch (ch) 4011500Serics char ch; 4021500Serics { 4031500Serics putchar (ch); 4041500Serics } 4051500Serics 4061500Serics /* 4071500Serics ** Print out the contents of the file f, one screenful at a time. 4081500Serics */ 4091500Serics 4101500Serics #define STOP -10 4111500Serics 4121500Serics screen (f, num_lines) 4131500Serics register FILE *f; 4141500Serics register int num_lines; 4151500Serics { 4161500Serics register int c; 4171500Serics register int nchars; 4183594Sroot int length; /* length of current line */ 4193594Sroot static int prev_len = 1; /* length of previous line */ 4201500Serics 4211500Serics for (;;) { 4221500Serics while (num_lines > 0 && !Pause) { 4231500Serics if ((nchars = getline (f, &length)) == EOF) 4243455Sroot { 4253594Sroot if (clreol) 4263594Sroot clreos(); 4271500Serics return; 4283455Sroot } 4293594Sroot if (ssp_opt && length == 0 && prev_len == 0) 4303594Sroot continue; 4313594Sroot prev_len = length; 4321500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 4331500Serics erase (0); 4343594Sroot /* must clear before drawing line since tabs on some terminals 4353594Sroot * do not erase what they tab over. 4363594Sroot */ 4373594Sroot if (clreol) 4383594Sroot cleareol (); 4391500Serics prbuf (Line, length); 4401500Serics if (nchars < promptlen) 4411500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4421500Serics else promptlen = 0; 4433594Sroot /* is this needed? 4443594Sroot * if (clreol) 4453594Sroot * cleareol(); /* must clear again in case we wrapped * 4463594Sroot */ 4471500Serics if (nchars < Mcol || !fold_opt) 44816710Sjak prbuf("\n", 1); /* will turn off UL if necessary */ 4491500Serics if (nchars == STOP) 4501500Serics break; 4511500Serics num_lines--; 4521500Serics } 45316710Sjak if (pstate) { 45416710Sjak tputs(ULexit, 1, putch); 45516710Sjak pstate = 0; 45616710Sjak } 4571500Serics fflush(stdout); 4581500Serics if ((c = Getc(f)) == EOF) 4593455Sroot { 4603594Sroot if (clreol) 4613594Sroot clreos (); 4621500Serics return; 4633455Sroot } 4643455Sroot 4653594Sroot if (Pause && clreol) 4663594Sroot clreos (); 4671500Serics Ungetc (c, f); 4681500Serics setjmp (restore); 4691500Serics Pause = 0; startup = 0; 4701500Serics if ((num_lines = command (NULL, f)) == 0) 4711500Serics return; 4721500Serics if (hard && promptlen > 0) 4731500Serics erase (0); 47411123Slayer if (noscroll && num_lines >= dlines) 47516582Sleres { 4763594Sroot if (clreol) 4773594Sroot home(); 4783594Sroot else 4793594Sroot doclear (); 4803455Sroot } 4811500Serics screen_start.line = Currline; 4821500Serics screen_start.chrctr = Ftell (f); 4831500Serics } 4841500Serics } 4851500Serics 4861500Serics /* 4871500Serics ** Come here if a quit signal is received 4881500Serics */ 4891500Serics 4901500Serics onquit() 4911500Serics { 4921500Serics signal(SIGQUIT, SIG_IGN); 4931500Serics if (!inwait) { 4941500Serics putchar ('\n'); 4951500Serics if (!startup) { 4961500Serics signal(SIGQUIT, onquit); 4971500Serics longjmp (restore, 1); 4981500Serics } 4991500Serics else 5001500Serics Pause++; 5011500Serics } 5021500Serics else if (!dum_opt && notell) { 5031500Serics write (2, "[Use q or Q to quit]", 20); 5041500Serics promptlen += 20; 5051500Serics notell = 0; 5061500Serics } 5071500Serics signal(SIGQUIT, onquit); 5081500Serics } 5091500Serics 5101500Serics /* 51127006Sdonn ** Come here if a signal for a window size change is received 51227006Sdonn */ 51327006Sdonn 51427006Sdonn chgwinsz() 51527006Sdonn { 51627006Sdonn struct winsize win; 51727006Sdonn 51827006Sdonn (void) signal(SIGWINCH, SIG_IGN); 51927006Sdonn if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { 52027006Sdonn if (win.ws_row != 0) { 52127006Sdonn Lpp = win.ws_row; 52227006Sdonn nscroll = Lpp/2 - 1; 52327006Sdonn if (nscroll <= 0) 52427006Sdonn nscroll = 1; 52527006Sdonn dlines = Lpp - (noscroll ? 1 : 2); 52627006Sdonn } 52727006Sdonn if (win.ws_col != 0) 52827006Sdonn Mcol = win.ws_col; 52927006Sdonn } 53027006Sdonn (void) signal(SIGWINCH, chgwinsz); 53127006Sdonn } 53227006Sdonn 53327006Sdonn /* 5341500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 5351500Serics */ 5361500Serics 5371500Serics end_it () 5381500Serics { 5391500Serics 5401500Serics reset_tty (); 5413594Sroot if (clreol) { 5423594Sroot putchar ('\r'); 5433594Sroot clreos (); 5443594Sroot fflush (stdout); 5453594Sroot } 5463455Sroot else if (!clreol && (promptlen > 0)) { 5471500Serics kill_line (); 5481500Serics fflush (stdout); 5491500Serics } 5501500Serics else 5511500Serics write (2, "\n", 1); 5521500Serics _exit(0); 5531500Serics } 5541500Serics 5551500Serics copy_file(f) 5561500Serics register FILE *f; 5571500Serics { 5581500Serics register int c; 5591500Serics 5601500Serics while ((c = getc(f)) != EOF) 5611500Serics putchar(c); 5621500Serics } 5631500Serics 5641500Serics /* Simplified printf function */ 5651500Serics 5661500Serics printf (fmt, args) 5671500Serics register char *fmt; 5681500Serics int args; 5691500Serics { 5701500Serics register int *argp; 5711500Serics register char ch; 5721500Serics register int ccount; 5731500Serics 5741500Serics ccount = 0; 5751500Serics argp = &args; 5761500Serics while (*fmt) { 5771500Serics while ((ch = *fmt++) != '%') { 5781500Serics if (ch == '\0') 5791500Serics return (ccount); 5801500Serics ccount++; 5811500Serics putchar (ch); 5821500Serics } 5831500Serics switch (*fmt++) { 5841500Serics case 'd': 5851500Serics ccount += printd (*argp); 5861500Serics break; 5871500Serics case 's': 5881500Serics ccount += pr ((char *)*argp); 5891500Serics break; 5901500Serics case '%': 5911500Serics ccount++; 5921500Serics argp--; 5931500Serics putchar ('%'); 5941500Serics break; 5951500Serics case '0': 5961500Serics return (ccount); 5971500Serics default: 5981500Serics break; 5991500Serics } 6001500Serics ++argp; 6011500Serics } 6021500Serics return (ccount); 6031500Serics 6041500Serics } 6051500Serics 6061500Serics /* 6071500Serics ** Print an integer as a string of decimal digits, 6081500Serics ** returning the length of the print representation. 6091500Serics */ 6101500Serics 6111500Serics printd (n) 6121500Serics int n; 6131500Serics { 6141500Serics int a, nchars; 6151500Serics 6161500Serics if (a = n/10) 6171500Serics nchars = 1 + printd(a); 6181500Serics else 6191500Serics nchars = 1; 6201500Serics putchar (n % 10 + '0'); 6211500Serics return (nchars); 6221500Serics } 6231500Serics 6241500Serics /* Put the print representation of an integer into a string */ 6251500Serics static char *sptr; 6261500Serics 6271500Serics scanstr (n, str) 6281500Serics int n; 6291500Serics char *str; 6301500Serics { 6311500Serics sptr = str; 63211604Slayer Sprintf (n); 6331500Serics *sptr = '\0'; 6341500Serics } 6351500Serics 63611604Slayer Sprintf (n) 6371500Serics { 6381500Serics int a; 6391500Serics 6401500Serics if (a = n/10) 64111604Slayer Sprintf (a); 6421500Serics *sptr++ = n % 10 + '0'; 6431500Serics } 6441500Serics 6451500Serics static char bell = ctrl(G); 6461500Serics 6471500Serics strlen (s) 6481500Serics char *s; 6491500Serics { 6501500Serics register char *p; 6511500Serics 6521500Serics p = s; 6531500Serics while (*p++) 6541500Serics ; 6551500Serics return (p - s - 1); 6561500Serics } 6571500Serics 6581500Serics /* See whether the last component of the path name "path" is equal to the 6591500Serics ** string "string" 6601500Serics */ 6611500Serics 6621500Serics tailequ (path, string) 6631500Serics char *path; 6641500Serics register char *string; 6651500Serics { 6661500Serics register char *tail; 6671500Serics 6681500Serics tail = path + strlen(path); 6691500Serics while (tail >= path) 6701500Serics if (*(--tail) == '/') 6711500Serics break; 6721500Serics ++tail; 6731500Serics while (*tail++ == *string++) 6741500Serics if (*tail == '\0') 6751500Serics return(1); 6761500Serics return(0); 6771500Serics } 6781500Serics 6791500Serics prompt (filename) 6801500Serics char *filename; 6811500Serics { 6823594Sroot if (clreol) 6833594Sroot cleareol (); 6843455Sroot else if (promptlen > 0) 6851500Serics kill_line (); 6861500Serics if (!hard) { 6871500Serics promptlen = 8; 68816710Sjak if (Senter && Sexit) { 6891500Serics tputs (Senter, 1, putch); 69016710Sjak promptlen += (2 * soglitch); 69116710Sjak } 6923594Sroot if (clreol) 6933594Sroot cleareol (); 6941500Serics pr("--More--"); 6951500Serics if (filename != NULL) { 6961500Serics promptlen += printf ("(Next file: %s)", filename); 6971500Serics } 6981500Serics else if (!no_intty) { 6991500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 7001500Serics } 7011500Serics if (dum_opt) { 70216710Sjak promptlen += pr("[Press space to continue, 'q' to quit.]"); 7031500Serics } 7041500Serics if (Senter && Sexit) 7051500Serics tputs (Sexit, 1, putch); 7063594Sroot if (clreol) 7073594Sroot clreos (); 7081500Serics fflush(stdout); 7091500Serics } 7101500Serics else 7111500Serics write (2, &bell, 1); 7121500Serics inwait++; 7131500Serics } 7141500Serics 7151500Serics /* 7161500Serics ** Get a logical line 7171500Serics */ 7181500Serics 7191500Serics getline(f, length) 7201500Serics register FILE *f; 7211500Serics int *length; 7221500Serics { 7231500Serics register int c; 7241500Serics register char *p; 7251500Serics register int column; 7261500Serics static int colflg; 7271500Serics 7281500Serics p = Line; 7291500Serics column = 0; 7301500Serics c = Getc (f); 7311500Serics if (colflg && c == '\n') { 7321500Serics Currline++; 7331500Serics c = Getc (f); 7341500Serics } 7351500Serics while (p < &Line[LINSIZ - 1]) { 7361500Serics if (c == EOF) { 7371500Serics if (p > Line) { 7381500Serics *p = '\0'; 7391500Serics *length = p - Line; 7401500Serics return (column); 7411500Serics } 7421500Serics *length = p - Line; 7431500Serics return (EOF); 7441500Serics } 7451500Serics if (c == '\n') { 7461500Serics Currline++; 7471500Serics break; 7481500Serics } 7491500Serics *p++ = c; 7501500Serics if (c == '\t') 75129907Smckusick if (!hardtabs || column < promptlen && !hard) { 75229907Smckusick if (hardtabs && eraseln && !dumb) { 7531500Serics column = 1 + (column | 7); 7541500Serics tputs (eraseln, 1, putch); 7551500Serics promptlen = 0; 7561500Serics } 7571500Serics else { 75829907Smckusick for (--p; p < &Line[LINSIZ - 1];) { 7591500Serics *p++ = ' '; 76029907Smckusick if ((++column & 7) == 0) 76129907Smckusick break; 7621500Serics } 7631500Serics if (column >= promptlen) promptlen = 0; 7641500Serics } 7651500Serics } 7661500Serics else 7671500Serics column = 1 + (column | 7); 7689627Ssklower else if (c == '\b' && column > 0) 7691500Serics column--; 7701500Serics else if (c == '\r') 7711500Serics column = 0; 7721500Serics else if (c == '\f' && stop_opt) { 7731500Serics p[-1] = '^'; 7741500Serics *p++ = 'L'; 7751500Serics column += 2; 7761500Serics Pause++; 7771500Serics } 7781500Serics else if (c == EOF) { 7791500Serics *length = p - Line; 7801500Serics return (column); 7811500Serics } 7821500Serics else if (c >= ' ' && c != RUBOUT) 7831500Serics column++; 7841500Serics if (column >= Mcol && fold_opt) break; 7851500Serics c = Getc (f); 7861500Serics } 7871500Serics if (column >= Mcol && Mcol > 0) { 7881500Serics if (!Wrap) { 7891500Serics *p++ = '\n'; 7901500Serics } 7911500Serics } 7921500Serics colflg = column == Mcol && fold_opt; 79329907Smckusick if (colflg && eatnl && Wrap) { 79429907Smckusick *p++ = '\n'; /* simulate normal wrap */ 79529907Smckusick } 7961500Serics *length = p - Line; 7971500Serics *p = 0; 7981500Serics return (column); 7991500Serics } 8001500Serics 8011500Serics /* 8021500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 8031500Serics */ 8041500Serics 8051500Serics erase (col) 8061500Serics register int col; 8071500Serics { 8081500Serics 8091500Serics if (promptlen == 0) 8101500Serics return; 8111500Serics if (hard) { 8121500Serics putchar ('\n'); 8131500Serics } 8141500Serics else { 8151500Serics if (col == 0) 8161500Serics putchar ('\r'); 8171500Serics if (!dumb && eraseln) 8181500Serics tputs (eraseln, 1, putch); 8191500Serics else 8201500Serics for (col = promptlen - col; col > 0; col--) 8211500Serics putchar (' '); 8221500Serics } 8231500Serics promptlen = 0; 8241500Serics } 8251500Serics 8261500Serics /* 8271500Serics ** Erase the current line entirely 8281500Serics */ 8291500Serics 8301500Serics kill_line () 8311500Serics { 8321500Serics erase (0); 8331500Serics if (!eraseln || dumb) putchar ('\r'); 8341500Serics } 8351500Serics 8361500Serics /* 8373455Sroot * force clear to end of line 8383455Sroot */ 8393455Sroot cleareol() 8403455Sroot { 8413594Sroot tputs(eraseln, 1, putch); 8423455Sroot } 8433455Sroot 8443594Sroot clreos() 8453455Sroot { 8463594Sroot tputs(EodClr, 1, putch); 8473455Sroot } 8483455Sroot 8493455Sroot /* 8501500Serics ** Print string and return number of characters 8511500Serics */ 8521500Serics 8531500Serics pr(s1) 8541500Serics char *s1; 8551500Serics { 8561500Serics register char *s; 8571500Serics register char c; 8581500Serics 8591500Serics for (s = s1; c = *s++; ) 8601500Serics putchar(c); 8611500Serics return (s - s1 - 1); 8621500Serics } 8631500Serics 8641500Serics 8651500Serics /* Print a buffer of n characters */ 8661500Serics 8671500Serics prbuf (s, n) 8681500Serics register char *s; 8691500Serics register int n; 8701500Serics { 87116710Sjak register char c; /* next output character */ 8723594Sroot register int state; /* next output char's UL state */ 87316710Sjak #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 8743594Sroot 8753594Sroot while (--n >= 0) 8763594Sroot if (!ul_opt) 8773594Sroot putchar (*s++); 8783594Sroot else { 87916710Sjak if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 88016710Sjak s++; 88116710Sjak continue; 88216710Sjak } 88316710Sjak if (state = wouldul(s, n)) { 88416710Sjak c = (*s == '_')? s[2] : *s ; 8853594Sroot n -= 2; 88616710Sjak s += 3; 88716710Sjak } else 8883594Sroot c = *s++; 88916710Sjak if (state != pstate) { 89016710Sjak if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 89116710Sjak state = 1; 89216710Sjak else 89316710Sjak tputs(state ? ULenter : ULexit, 1, putch); 8943594Sroot } 89516710Sjak if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 89616710Sjak putchar(c); 8973594Sroot if (state && *chUL) { 8983594Sroot pr(chBS); 8993594Sroot tputs(chUL, 1, putch); 9003594Sroot } 90116710Sjak pstate = state; 9023594Sroot } 9031500Serics } 9041500Serics 9051500Serics /* 9061500Serics ** Clear the screen 9071500Serics */ 9081500Serics 9091500Serics doclear() 9101500Serics { 9111500Serics if (Clear && !hard) { 9121500Serics tputs(Clear, 1, putch); 9131500Serics 9141500Serics /* Put out carriage return so that system doesn't 9151500Serics ** get confused by escape sequences when expanding tabs 9161500Serics */ 9171500Serics putchar ('\r'); 9181500Serics promptlen = 0; 9191500Serics } 9201500Serics } 9211500Serics 9223455Sroot /* 9233455Sroot * Go to home position 9243455Sroot */ 9253455Sroot home() 9263455Sroot { 9273455Sroot tputs(Home,1,putch); 9283455Sroot } 9293455Sroot 9301500Serics static int lastcmd, lastarg, lastp; 9311500Serics static int lastcolon; 9321500Serics char shell_line[132]; 9331500Serics 9341500Serics /* 9351500Serics ** Read a command and do it. A command consists of an optional integer 9361500Serics ** argument followed by the command character. Return the number of lines 9371500Serics ** to display in the next screenful. If there is nothing more to display 9381500Serics ** in the current file, zero is returned. 9391500Serics */ 9401500Serics 9411500Serics command (filename, f) 9421500Serics char *filename; 9431500Serics register FILE *f; 9441500Serics { 9451500Serics register int nlines; 9461500Serics register int retval; 9471500Serics register char c; 9481500Serics char colonch; 9491500Serics FILE *helpf; 9501500Serics int done; 9511500Serics char comchar, cmdbuf[80], *p; 9521500Serics 9531500Serics #define ret(val) retval=val;done++;break 9541500Serics 9551500Serics done = 0; 9561500Serics if (!errors) 9571500Serics prompt (filename); 9581500Serics else 9591500Serics errors = 0; 9601500Serics if (MBIT == RAW && slow_tty) { 9611500Serics otty.sg_flags |= MBIT; 96216582Sleres stty(fileno(stderr), &otty); 9631500Serics } 9641500Serics for (;;) { 9651500Serics nlines = number (&comchar); 9661500Serics lastp = colonch = 0; 9671500Serics if (comchar == '.') { /* Repeat last command */ 9681500Serics lastp++; 9691500Serics comchar = lastcmd; 9701500Serics nlines = lastarg; 9711500Serics if (lastcmd == ':') 9721500Serics colonch = lastcolon; 9731500Serics } 9741500Serics lastcmd = comchar; 9751500Serics lastarg = nlines; 9761500Serics if (comchar == otty.sg_erase) { 9771500Serics kill_line (); 9781500Serics prompt (filename); 9791500Serics continue; 9801500Serics } 9811500Serics switch (comchar) { 9821500Serics case ':': 9831500Serics retval = colon (filename, colonch, nlines); 9841500Serics if (retval >= 0) 9851500Serics done++; 9861500Serics break; 98724490Sbloom case 'b': 98824490Sbloom case ctrl(B): 98924490Sbloom { 99024490Sbloom register int initline; 99124490Sbloom 99224490Sbloom if (no_intty) { 99324490Sbloom write(2, &bell, 1); 99424490Sbloom return (-1); 99524490Sbloom } 99624490Sbloom 99724490Sbloom if (nlines == 0) nlines++; 99824490Sbloom 99924490Sbloom putchar ('\r'); 100024490Sbloom erase (0); 100124490Sbloom printf ("\n"); 100224490Sbloom if (clreol) 100324490Sbloom cleareol (); 100424490Sbloom printf ("...back %d page", nlines); 100524490Sbloom if (nlines > 1) 100624490Sbloom pr ("s\n"); 100724490Sbloom else 100824490Sbloom pr ("\n"); 100924490Sbloom 101024490Sbloom if (clreol) 101124490Sbloom cleareol (); 101224490Sbloom pr ("\n"); 101324490Sbloom 101424490Sbloom initline = Currline - dlines * (nlines + 1); 101524490Sbloom if (! noscroll) 101624490Sbloom --initline; 101724490Sbloom if (initline < 0) initline = 0; 101824490Sbloom Fseek(f, 0L); 101924490Sbloom Currline = 0; /* skiplns() will make Currline correct */ 102024490Sbloom skiplns(initline, f); 102124490Sbloom if (! noscroll) { 102224490Sbloom ret(dlines + 1); 102324490Sbloom } 102424490Sbloom else { 102524490Sbloom ret(dlines); 102624490Sbloom } 102724490Sbloom } 10281500Serics case ' ': 10291500Serics case 'z': 10301500Serics if (nlines == 0) nlines = dlines; 10311500Serics else if (comchar == 'z') dlines = nlines; 10321500Serics ret (nlines); 10331500Serics case 'd': 10341500Serics case ctrl(D): 10351500Serics if (nlines != 0) nscroll = nlines; 10361500Serics ret (nscroll); 10371500Serics case 'q': 10381500Serics case 'Q': 10391500Serics end_it (); 10401500Serics case 's': 10411500Serics case 'f': 10421500Serics if (nlines == 0) nlines++; 10431500Serics if (comchar == 'f') 10441500Serics nlines *= dlines; 10451500Serics putchar ('\r'); 10461500Serics erase (0); 10473594Sroot printf ("\n"); 10483594Sroot if (clreol) 10493594Sroot cleareol (); 10503594Sroot printf ("...skipping %d line", nlines); 10511500Serics if (nlines > 1) 10523594Sroot pr ("s\n"); 10531500Serics else 10543594Sroot pr ("\n"); 10553594Sroot 10563594Sroot if (clreol) 10573594Sroot cleareol (); 10583594Sroot pr ("\n"); 10593594Sroot 10601500Serics while (nlines > 0) { 10611500Serics while ((c = Getc (f)) != '\n') 10621500Serics if (c == EOF) { 10631500Serics retval = 0; 10641500Serics done++; 10651500Serics goto endsw; 10661500Serics } 10671500Serics Currline++; 10681500Serics nlines--; 10691500Serics } 10701500Serics ret (dlines); 10711500Serics case '\n': 10721500Serics if (nlines != 0) 10731500Serics dlines = nlines; 10741500Serics else 10751500Serics nlines = 1; 10761500Serics ret (nlines); 10771500Serics case '\f': 10781500Serics if (!no_intty) { 10791500Serics doclear (); 10801500Serics Fseek (f, screen_start.chrctr); 10811500Serics Currline = screen_start.line; 10821500Serics ret (dlines); 10831500Serics } 10841500Serics else { 10851500Serics write (2, &bell, 1); 10861500Serics break; 10871500Serics } 10881500Serics case '\'': 10891500Serics if (!no_intty) { 10901500Serics kill_line (); 10911500Serics pr ("\n***Back***\n\n"); 10921500Serics Fseek (f, context.chrctr); 10931500Serics Currline = context.line; 10941500Serics ret (dlines); 10951500Serics } 10961500Serics else { 10971500Serics write (2, &bell, 1); 10981500Serics break; 10991500Serics } 11001500Serics case '=': 11011500Serics kill_line (); 11021500Serics promptlen = printd (Currline); 11031500Serics fflush (stdout); 11041500Serics break; 11051500Serics case 'n': 11061500Serics lastp++; 11071500Serics case '/': 11081500Serics if (nlines == 0) nlines++; 11091500Serics kill_line (); 11101500Serics pr ("/"); 11111500Serics promptlen = 1; 11121500Serics fflush (stdout); 11131500Serics if (lastp) { 11141500Serics write (2,"\r", 1); 11151500Serics search (NULL, f, nlines); /* Use previous r.e. */ 11161500Serics } 11171500Serics else { 11181500Serics ttyin (cmdbuf, 78, '/'); 11191500Serics write (2, "\r", 1); 11201500Serics search (cmdbuf, f, nlines); 11211500Serics } 11223455Sroot ret (dlines-1); 11231500Serics case '!': 11241500Serics do_shell (filename); 11251500Serics break; 112624490Sbloom case '?': 11271500Serics case 'h': 11281500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 11291500Serics error ("Can't open help file"); 11301500Serics if (noscroll) doclear (); 11311500Serics copy_file (helpf); 113227006Sdonn fclose (helpf); 11331500Serics prompt (filename); 11341500Serics break; 11351500Serics case 'v': /* This case should go right before default */ 11361500Serics if (!no_intty) { 11371500Serics kill_line (); 11381500Serics cmdbuf[0] = '+'; 113924490Sbloom scanstr (Currline - dlines < 0 ? 0 114024490Sbloom : Currline - (dlines + 1) / 2, &cmdbuf[1]); 11411500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 11421500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 11431500Serics break; 11441500Serics } 11451500Serics default: 114616710Sjak if (dum_opt) { 114716710Sjak kill_line (); 114816710Sjak if (Senter && Sexit) { 114916710Sjak tputs (Senter, 1, putch); 115016710Sjak promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 115116710Sjak tputs (Sexit, 1, putch); 115216710Sjak } 115316710Sjak else 115416710Sjak promptlen = pr ("[Press 'h' for instructions.]"); 115516710Sjak fflush (stdout); 115616710Sjak } 115716710Sjak else 115816710Sjak write (2, &bell, 1); 11591500Serics break; 11601500Serics } 11611500Serics if (done) break; 11621500Serics } 11631500Serics putchar ('\r'); 11641500Serics endsw: 11651500Serics inwait = 0; 11661500Serics notell++; 11671500Serics if (MBIT == RAW && slow_tty) { 11681500Serics otty.sg_flags &= ~MBIT; 116916582Sleres stty(fileno(stderr), &otty); 11701500Serics } 11711500Serics return (retval); 11721500Serics } 11731500Serics 11741500Serics char ch; 11751500Serics 11761500Serics /* 11771500Serics * Execute a colon-prefixed command. 11781500Serics * Returns <0 if not a command that should cause 11791500Serics * more of the file to be printed. 11801500Serics */ 11811500Serics 11821500Serics colon (filename, cmd, nlines) 11831500Serics char *filename; 11841500Serics int cmd; 11851500Serics int nlines; 11861500Serics { 11871500Serics if (cmd == 0) 11881500Serics ch = readch (); 11891500Serics else 11901500Serics ch = cmd; 11911500Serics lastcolon = ch; 11921500Serics switch (ch) { 11931500Serics case 'f': 11941500Serics kill_line (); 11951500Serics if (!no_intty) 11961500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 11971500Serics else 11981500Serics promptlen = printf ("[Not a file] line %d", Currline); 11991500Serics fflush (stdout); 12001500Serics return (-1); 12011500Serics case 'n': 12021500Serics if (nlines == 0) { 12031500Serics if (fnum >= nfiles - 1) 12041500Serics end_it (); 12051500Serics nlines++; 12061500Serics } 12071500Serics putchar ('\r'); 12081500Serics erase (0); 12091500Serics skipf (nlines); 12101500Serics return (0); 12111500Serics case 'p': 12121500Serics if (no_intty) { 12131500Serics write (2, &bell, 1); 12141500Serics return (-1); 12151500Serics } 12161500Serics putchar ('\r'); 12171500Serics erase (0); 12181500Serics if (nlines == 0) 12191500Serics nlines++; 12201500Serics skipf (-nlines); 12211500Serics return (0); 12221500Serics case '!': 12231500Serics do_shell (filename); 12241500Serics return (-1); 12251500Serics case 'q': 12261500Serics case 'Q': 12271500Serics end_it (); 12281500Serics default: 12291500Serics write (2, &bell, 1); 12301500Serics return (-1); 12311500Serics } 12321500Serics } 12331500Serics 12341500Serics /* 12351500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 12361500Serics ** terminates the number. 12371500Serics */ 12381500Serics 12391500Serics number(cmd) 12401500Serics char *cmd; 12411500Serics { 12421500Serics register int i; 12431500Serics 12441500Serics i = 0; ch = otty.sg_kill; 12451500Serics for (;;) { 12461500Serics ch = readch (); 12471500Serics if (ch >= '0' && ch <= '9') 12481500Serics i = i*10 + ch - '0'; 12491500Serics else if (ch == otty.sg_kill) 12501500Serics i = 0; 12511500Serics else { 12521500Serics *cmd = ch; 12531500Serics break; 12541500Serics } 12551500Serics } 12561500Serics return (i); 12571500Serics } 12581500Serics 12591500Serics do_shell (filename) 12601500Serics char *filename; 12611500Serics { 12621500Serics char cmdbuf[80]; 12631500Serics 12641500Serics kill_line (); 12651500Serics pr ("!"); 12661500Serics fflush (stdout); 12671500Serics promptlen = 1; 12681500Serics if (lastp) 12691500Serics pr (shell_line); 12701500Serics else { 12711500Serics ttyin (cmdbuf, 78, '!'); 12721500Serics if (expand (shell_line, cmdbuf)) { 12731500Serics kill_line (); 12741500Serics promptlen = printf ("!%s", shell_line); 12751500Serics } 12761500Serics } 12771500Serics fflush (stdout); 12781500Serics write (2, "\n", 1); 12791500Serics promptlen = 0; 12801500Serics shellp = 1; 12811500Serics execute (filename, shell, shell, "-c", shell_line, 0); 12821500Serics } 12831500Serics 12841500Serics /* 12851500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 12861500Serics */ 12871500Serics 12881500Serics search (buf, file, n) 12891500Serics char buf[]; 12901500Serics FILE *file; 12911500Serics register int n; 12921500Serics { 12931500Serics long startline = Ftell (file); 12941500Serics register long line1 = startline; 12951500Serics register long line2 = startline; 12961500Serics register long line3 = startline; 12971500Serics register int lncount; 12981500Serics int saveln, rv, re_exec(); 12991500Serics char *s, *re_comp(); 13001500Serics 13011500Serics context.line = saveln = Currline; 13021500Serics context.chrctr = startline; 13031500Serics lncount = 0; 13041500Serics if ((s = re_comp (buf)) != 0) 13051500Serics error (s); 13061500Serics while (!feof (file)) { 13071500Serics line3 = line2; 13081500Serics line2 = line1; 13091500Serics line1 = Ftell (file); 13101500Serics rdline (file); 13111500Serics lncount++; 13121500Serics if ((rv = re_exec (Line)) == 1) 13131500Serics if (--n == 0) { 13141500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 13153455Sroot { 13163455Sroot pr ("\n"); 13173594Sroot if (clreol) 13183594Sroot cleareol (); 13193455Sroot pr("...skipping\n"); 13203455Sroot } 13211500Serics if (!no_intty) { 13221500Serics Currline -= (lncount >= 3 ? 3 : lncount); 13231500Serics Fseek (file, line3); 13243594Sroot if (noscroll) 13253594Sroot if (clreol) { 13263594Sroot home (); 13273594Sroot cleareol (); 132816582Sleres } 13293594Sroot else 13303594Sroot doclear (); 13311500Serics } 13321500Serics else { 13331500Serics kill_line (); 13343594Sroot if (noscroll) 13353594Sroot if (clreol) { 133616582Sleres home (); 13373594Sroot cleareol (); 133816582Sleres } 13393594Sroot else 13403594Sroot doclear (); 13411500Serics pr (Line); 13421500Serics putchar ('\n'); 13431500Serics } 13441500Serics break; 13451500Serics } 13461500Serics else if (rv == -1) 13471500Serics error ("Regular expression botch"); 13481500Serics } 13491500Serics if (feof (file)) { 13501500Serics if (!no_intty) { 13511500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 13521500Serics Currline = saveln; 13531500Serics Fseek (file, startline); 13541500Serics } 13551500Serics else { 13561500Serics pr ("\nPattern not found\n"); 13571500Serics end_it (); 13581500Serics } 13591500Serics error ("Pattern not found"); 13601500Serics } 13611500Serics } 13621500Serics 13631500Serics execute (filename, cmd, args) 13641500Serics char *filename; 13651500Serics char *cmd, *args; 13661500Serics { 13671500Serics int id; 136816710Sjak int n; 13691500Serics 13701500Serics fflush (stdout); 13711500Serics reset_tty (); 137216710Sjak for (n = 10; (id = fork ()) < 0 && n > 0; n--) 13731500Serics sleep (5); 13741500Serics if (id == 0) { 137516710Sjak if (!isatty(0)) { 137616710Sjak close(0); 137716710Sjak open("/dev/tty", 0); 137816710Sjak } 13791500Serics execv (cmd, &args); 13801500Serics write (2, "exec failed\n", 12); 13811500Serics exit (1); 13821500Serics } 138316710Sjak if (id > 0) { 138416710Sjak signal (SIGINT, SIG_IGN); 138516710Sjak signal (SIGQUIT, SIG_IGN); 138616710Sjak if (catch_susp) 138716710Sjak signal(SIGTSTP, SIG_DFL); 138816710Sjak while (wait(0) > 0); 138916710Sjak signal (SIGINT, end_it); 139016710Sjak signal (SIGQUIT, onquit); 139116710Sjak if (catch_susp) 139216710Sjak signal(SIGTSTP, onsusp); 139316710Sjak } else 139416710Sjak write(2, "can't fork\n", 11); 13951500Serics set_tty (); 13961500Serics pr ("------------------------\n"); 13971500Serics prompt (filename); 13981500Serics } 13991500Serics /* 14001500Serics ** Skip n lines in the file f 14011500Serics */ 14021500Serics 14031500Serics skiplns (n, f) 14041500Serics register int n; 14051500Serics register FILE *f; 14061500Serics { 14071500Serics register char c; 14081500Serics 14091500Serics while (n > 0) { 14101500Serics while ((c = Getc (f)) != '\n') 14111500Serics if (c == EOF) 14121500Serics return; 14131500Serics n--; 14141500Serics Currline++; 14151500Serics } 14161500Serics } 14171500Serics 14181500Serics /* 14191500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 14201500Serics ** negative. 14211500Serics */ 14221500Serics 14231500Serics skipf (nskip) 14241500Serics register int nskip; 14251500Serics { 14261500Serics if (nskip == 0) return; 14271500Serics if (nskip > 0) { 14281500Serics if (fnum + nskip > nfiles - 1) 14291500Serics nskip = nfiles - fnum - 1; 14301500Serics } 14311500Serics else if (within) 14321500Serics ++fnum; 14331500Serics fnum += nskip; 14341500Serics if (fnum < 0) 14351500Serics fnum = 0; 14363594Sroot pr ("\n...Skipping "); 14373455Sroot pr ("\n"); 14383594Sroot if (clreol) 14393594Sroot cleareol (); 14403455Sroot pr ("...Skipping "); 14411500Serics pr (nskip > 0 ? "to file " : "back to file "); 14421500Serics pr (fnames[fnum]); 14433455Sroot pr ("\n"); 14443594Sroot if (clreol) 14453594Sroot cleareol (); 14463455Sroot pr ("\n"); 14471500Serics --fnum; 14481500Serics } 14491500Serics 14501500Serics /*----------------------------- Terminal I/O -------------------------------*/ 14511500Serics 14521500Serics initterm () 14531500Serics { 14541500Serics char buf[TBUFSIZ]; 145517195Sralph static char clearbuf[TBUFSIZ]; 14561500Serics char *clearptr, *padstr; 14571500Serics int ldisc; 145817592Sleres int lmode; 145910823Ssam char *term; 146016582Sleres int tgrp; 146118030Sbloom struct winsize win; 14621500Serics 146316582Sleres retry: 146416582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 146517592Sleres if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { 146617592Sleres perror("TIOCLGET"); 146717592Sleres exit(1); 146817592Sleres } 146917592Sleres docrterase = ((lmode & LCRTERA) != 0); 147017592Sleres docrtkill = ((lmode & LCRTKIL) != 0); 147116582Sleres /* 147217592Sleres * Wait until we're in the foreground before we save the 147317592Sleres * the terminal modes. 147416582Sleres */ 147516582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 147617592Sleres perror("TIOCGPGRP"); 147716582Sleres exit(1); 147816582Sleres } 147916582Sleres if (tgrp != getpgrp(0)) { 148016582Sleres kill(0, SIGTTOU); 148116582Sleres goto retry; 148216582Sleres } 148313830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 14843594Sroot dumb++; ul_opt = 0; 14851500Serics } 14861500Serics else { 148718030Sbloom if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { 148818030Sbloom Lpp = tgetnum("li"); 148918030Sbloom Mcol = tgetnum("co"); 149018030Sbloom } else { 149118030Sbloom if ((Lpp = win.ws_row) == 0) 149218030Sbloom Lpp = tgetnum("li"); 149318030Sbloom if ((Mcol = win.ws_col) == 0) 149418030Sbloom Mcol = tgetnum("co"); 149518030Sbloom } 149618030Sbloom if ((Lpp <= 0) || tgetflag("hc")) { 14971500Serics hard++; /* Hard copy terminal */ 14981500Serics Lpp = 24; 14991500Serics } 150029907Smckusick if (tgetflag("xn")) 150129907Smckusick eatnl++; /* Eat newline at last column + 1; dec, concept */ 150218030Sbloom if (Mcol <= 0) 150318030Sbloom Mcol = 80; 150418030Sbloom 15051500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 15061500Serics noscroll++; 15071500Serics Wrap = tgetflag("am"); 15081500Serics bad_so = tgetflag ("xs"); 15091500Serics clearptr = clearbuf; 15101500Serics eraseln = tgetstr("ce",&clearptr); 15111500Serics Clear = tgetstr("cl", &clearptr); 15121500Serics Senter = tgetstr("so", &clearptr); 15131500Serics Sexit = tgetstr("se", &clearptr); 151416710Sjak if ((soglitch = tgetnum("sg")) < 0) 151516710Sjak soglitch = 0; 15163594Sroot 15173594Sroot /* 15183594Sroot * Set up for underlining: some terminals don't need it; 15193594Sroot * others have start/stop sequences, still others have an 15203594Sroot * underline char sequence which is assumed to move the 15213594Sroot * cursor forward one character. If underline sequence 15223594Sroot * isn't available, settle for standout sequence. 15233594Sroot */ 15243594Sroot 15253594Sroot if (tgetflag("ul") || tgetflag("os")) 15263594Sroot ul_opt = 0; 15273594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 15283594Sroot chUL = ""; 152916710Sjak if (((ULenter = tgetstr("us", &clearptr)) == NULL || 153016710Sjak (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 153116710Sjak if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 153216710Sjak ULenter = ""; 153316710Sjak ULexit = ""; 153416710Sjak } else 153516710Sjak ulglitch = soglitch; 153616710Sjak } else { 153716710Sjak if ((ulglitch = tgetnum("ug")) < 0) 153816710Sjak ulglitch = 0; 153916710Sjak } 154016582Sleres 15411500Serics if (padstr = tgetstr("pc", &clearptr)) 15421500Serics PC = *padstr; 15433455Sroot Home = tgetstr("ho",&clearptr); 154413536Ssam if (Home == 0 || *Home == '\0') 15453455Sroot { 15463594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 15473594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 15483455Sroot Home = cursorhome; 15493455Sroot } 15503455Sroot } 15513594Sroot EodClr = tgetstr("cd", &clearptr); 155225540Smckusick if ((chBS = tgetstr("bc", &clearptr)) == NULL) 155325540Smckusick chBS = "\b"; 155425540Smckusick 15551500Serics } 15561500Serics if ((shell = getenv("SHELL")) == NULL) 15571500Serics shell = "/bin/sh"; 15581500Serics } 155916582Sleres no_intty = gtty(fileno(stdin), &otty); 156016582Sleres gtty(fileno(stderr), &otty); 156113830Skre savetty = otty; 15621500Serics ospeed = otty.sg_ospeed; 15631500Serics slow_tty = ospeed < B1200; 156427006Sdonn hardtabs = (otty.sg_flags & TBDELAY) != XTABS; 15651500Serics if (!no_tty) { 15661500Serics otty.sg_flags &= ~ECHO; 15671500Serics if (MBIT == CBREAK || !slow_tty) 15681500Serics otty.sg_flags |= MBIT; 15691500Serics } 15701500Serics } 15711500Serics 15721500Serics readch () 15731500Serics { 15741500Serics char ch; 15751500Serics extern int errno; 15761500Serics 157731089Skarels errno = 0; 15781500Serics if (read (2, &ch, 1) <= 0) 15791500Serics if (errno != EINTR) 158031089Skarels end_it(); 15811500Serics else 15821500Serics ch = otty.sg_kill; 15831500Serics return (ch); 15841500Serics } 15851500Serics 15861500Serics static char BS = '\b'; 158717592Sleres static char *BSB = "\b \b"; 15881500Serics static char CARAT = '^'; 158917592Sleres #define ERASEONECHAR \ 159017592Sleres if (docrterase) \ 159117592Sleres write (2, BSB, sizeof(BSB)); \ 159217592Sleres else \ 159317592Sleres write (2, &BS, sizeof(BS)); 15941500Serics 15951500Serics ttyin (buf, nmax, pchar) 15961500Serics char buf[]; 15971500Serics register int nmax; 15981500Serics char pchar; 15991500Serics { 16001500Serics register char *sptr; 16011500Serics register char ch; 16021500Serics register int slash = 0; 16031500Serics int maxlen; 16041500Serics char cbuf; 16051500Serics 16061500Serics sptr = buf; 16071500Serics maxlen = 0; 16081500Serics while (sptr - buf < nmax) { 16091500Serics if (promptlen > maxlen) maxlen = promptlen; 16101500Serics ch = readch (); 16111500Serics if (ch == '\\') { 16121500Serics slash++; 16131500Serics } 16141500Serics else if ((ch == otty.sg_erase) && !slash) { 16151500Serics if (sptr > buf) { 16161500Serics --promptlen; 161717592Sleres ERASEONECHAR 16181500Serics --sptr; 16191500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 16201500Serics --promptlen; 162117592Sleres ERASEONECHAR 16221500Serics } 16231500Serics continue; 16241500Serics } 16251500Serics else { 16261500Serics if (!eraseln) promptlen = maxlen; 16271500Serics longjmp (restore, 1); 16281500Serics } 16291500Serics } 16301500Serics else if ((ch == otty.sg_kill) && !slash) { 16311500Serics if (hard) { 16321500Serics show (ch); 16331500Serics putchar ('\n'); 16341500Serics putchar (pchar); 16351500Serics } 16361500Serics else { 16371500Serics putchar ('\r'); 16381500Serics putchar (pchar); 16391500Serics if (eraseln) 16401500Serics erase (1); 164117592Sleres else if (docrtkill) 164217592Sleres while (promptlen-- > 1) 164317592Sleres write (2, BSB, sizeof(BSB)); 16441500Serics promptlen = 1; 16451500Serics } 16461500Serics sptr = buf; 16471500Serics fflush (stdout); 16481500Serics continue; 16491500Serics } 16501500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 165117592Sleres ERASEONECHAR 16521500Serics --sptr; 16531500Serics } 16541500Serics if (ch != '\\') 16551500Serics slash = 0; 16561500Serics *sptr++ = ch; 16571500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 16581500Serics ch += ch == RUBOUT ? -0100 : 0100; 16591500Serics write (2, &CARAT, 1); 16601500Serics promptlen++; 16611500Serics } 16621500Serics cbuf = ch; 16631500Serics if (ch != '\n' && ch != ESC) { 16641500Serics write (2, &cbuf, 1); 16651500Serics promptlen++; 16661500Serics } 16671500Serics else 16681500Serics break; 16691500Serics } 16701500Serics *--sptr = '\0'; 16711500Serics if (!eraseln) promptlen = maxlen; 16721500Serics if (sptr - buf >= nmax - 1) 16731500Serics error ("Line too long"); 16741500Serics } 16751500Serics 16761500Serics expand (outbuf, inbuf) 16771500Serics char *outbuf; 16781500Serics char *inbuf; 16791500Serics { 16801500Serics register char *instr; 16811500Serics register char *outstr; 16821500Serics register char ch; 16831500Serics char temp[200]; 16841500Serics int changed = 0; 16851500Serics 16861500Serics instr = inbuf; 16871500Serics outstr = temp; 16881500Serics while ((ch = *instr++) != '\0') 16891500Serics switch (ch) { 16901500Serics case '%': 16911500Serics if (!no_intty) { 16921500Serics strcpy (outstr, fnames[fnum]); 16931500Serics outstr += strlen (fnames[fnum]); 16941500Serics changed++; 16951500Serics } 16961500Serics else 16971500Serics *outstr++ = ch; 16981500Serics break; 16991500Serics case '!': 17001500Serics if (!shellp) 17011500Serics error ("No previous command to substitute for"); 17021500Serics strcpy (outstr, shell_line); 17031500Serics outstr += strlen (shell_line); 17041500Serics changed++; 17051500Serics break; 17061500Serics case '\\': 17071500Serics if (*instr == '%' || *instr == '!') { 17081500Serics *outstr++ = *instr++; 17091500Serics break; 17101500Serics } 17111500Serics default: 17121500Serics *outstr++ = ch; 17131500Serics } 17141500Serics *outstr++ = '\0'; 17151500Serics strcpy (outbuf, temp); 17161500Serics return (changed); 17171500Serics } 17181500Serics 17191500Serics show (ch) 17201500Serics register char ch; 17211500Serics { 17221500Serics char cbuf; 17231500Serics 17241500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 17251500Serics ch += ch == RUBOUT ? -0100 : 0100; 17261500Serics write (2, &CARAT, 1); 17271500Serics promptlen++; 17281500Serics } 17291500Serics cbuf = ch; 17301500Serics write (2, &cbuf, 1); 17311500Serics promptlen++; 17321500Serics } 17331500Serics 17341500Serics error (mess) 17351500Serics char *mess; 17361500Serics { 17373594Sroot if (clreol) 17383594Sroot cleareol (); 17393594Sroot else 17403594Sroot kill_line (); 17411500Serics promptlen += strlen (mess); 17421500Serics if (Senter && Sexit) { 17431500Serics tputs (Senter, 1, putch); 17441500Serics pr(mess); 17451500Serics tputs (Sexit, 1, putch); 17461500Serics } 17471500Serics else 17481500Serics pr (mess); 17491500Serics fflush(stdout); 17501500Serics errors++; 17511500Serics longjmp (restore, 1); 17521500Serics } 17531500Serics 17541500Serics 17551500Serics set_tty () 17561500Serics { 17571500Serics otty.sg_flags |= MBIT; 17581500Serics otty.sg_flags &= ~ECHO; 175916582Sleres stty(fileno(stderr), &otty); 17601500Serics } 17611500Serics 17621500Serics reset_tty () 17631500Serics { 176431033Sbostic if (no_tty) 176531033Sbostic return; 176616710Sjak if (pstate) { 176716710Sjak tputs(ULexit, 1, putch); 176816710Sjak fflush(stdout); 176916710Sjak pstate = 0; 177016710Sjak } 17711500Serics otty.sg_flags |= ECHO; 17721500Serics otty.sg_flags &= ~MBIT; 177316582Sleres stty(fileno(stderr), &savetty); 17741500Serics } 17751500Serics 17761500Serics rdline (f) 17771500Serics register FILE *f; 17781500Serics { 17791500Serics register char c; 17801500Serics register char *p; 17811500Serics 17821500Serics p = Line; 17831500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 17841500Serics *p++ = c; 17851500Serics if (c == '\n') 17861500Serics Currline++; 17871500Serics *p = '\0'; 17881500Serics } 17891500Serics 17901500Serics /* Come here when we get a suspend signal from the terminal */ 17911500Serics 17921500Serics onsusp () 17931500Serics { 179414861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 179514861Skarels signal(SIGTTOU, SIG_IGN); 17961500Serics reset_tty (); 17971500Serics fflush (stdout); 179814861Skarels signal(SIGTTOU, SIG_DFL); 17991500Serics /* Send the TSTP signal to suspend our process group */ 180013289Ssam signal(SIGTSTP, SIG_DFL); 180113289Ssam sigsetmask(0); 18021500Serics kill (0, SIGTSTP); 18031500Serics /* Pause for station break */ 18041500Serics 18051500Serics /* We're back */ 18061500Serics signal (SIGTSTP, onsusp); 18071500Serics set_tty (); 18081500Serics if (inwait) 18091500Serics longjmp (restore); 18101500Serics } 1811