1*48284Sbostic /*- 2*48284Sbostic * Copyright (c) 1980 The Regents of the University of California. 332736Sbostic * All rights reserved. 432736Sbostic * 5*48284Sbostic * %sccs.include.redist.c% 621981Sdist */ 721981Sdist 813615Ssam #ifndef lint 921981Sdist char copyright[] = 10*48284Sbostic "@(#) Copyright (c) 1980 The Regents of the University of California.\n\ 1121981Sdist All rights reserved.\n"; 1232736Sbostic #endif /* not lint */ 133594Sroot 1421981Sdist #ifndef lint 15*48284Sbostic static char sccsid[] = "@(#)more.c 5.26 (Berkeley) 04/18/91"; 1632736Sbostic #endif /* not lint */ 1721981Sdist 181500Serics /* 191500Serics ** more.c - General purpose tty output filter and file perusal program 201500Serics ** 211500Serics ** by Eric Shienbrood, UC Berkeley 223594Sroot ** 233594Sroot ** modified by Geoff Peck, UCB to add underlining, single spacing 243594Sroot ** modified by John Foderaro, UCB to add -c and MORE environment variable 251500Serics */ 261500Serics 2732736Sbostic #include <sys/param.h> 2846188Sbostic #include <sys/stat.h> 2946188Sbostic #include <sys/file.h> 301500Serics #include <signal.h> 311500Serics #include <errno.h> 321500Serics #include <sgtty.h> 331500Serics #include <setjmp.h> 3432736Sbostic #include <a.out.h> 3532736Sbostic #include <varargs.h> 3646188Sbostic #include <stdio.h> 3746188Sbostic #include <ctype.h> 3837943Sbostic #include "pathnames.h" 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 5133232Sbostic #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; 5946779Sbostic int dum_opt, dlines; 6046779Sbostic void chgwinsz(), end_it(), onquit(), 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 */ 1033455Sroot char *getenv(); 1041500Serics struct { 1051500Serics long chrctr, line; 1061500Serics } context, screen_start; 1071500Serics extern char PC; /* pad character */ 1081500Serics extern short ospeed; 1091500Serics 1101500Serics 1111500Serics main(argc, argv) 1121500Serics int argc; 1131500Serics char *argv[]; 1141500Serics { 1151500Serics register FILE *f; 1161500Serics register char *s; 1171500Serics register char *p; 1181500Serics register char ch; 1191500Serics register int left; 12016582Sleres int prnames = 0; 1211500Serics int initopt = 0; 1221500Serics int srchopt = 0; 1231500Serics int clearit = 0; 1241500Serics int initline; 1251500Serics char initbuf[80]; 1261500Serics FILE *checkf(); 1271500Serics 1281500Serics nfiles = argc; 1291500Serics fnames = argv; 1301500Serics initterm (); 13115813Sralph nscroll = Lpp/2 - 1; 13215813Sralph if (nscroll <= 0) 13315813Sralph nscroll = 1; 1343455Sroot if(s = getenv("MORE")) argscan(s); 1351500Serics while (--nfiles > 0) { 1361500Serics if ((ch = (*++fnames)[0]) == '-') { 1373455Sroot argscan(*fnames+1); 1381500Serics } 1391500Serics else if (ch == '+') { 1401500Serics s = *fnames; 1411500Serics if (*++s == '/') { 1421500Serics srchopt++; 1431500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1441500Serics *p++ = *s++; 1451500Serics *p = '\0'; 1461500Serics } 1471500Serics else { 1481500Serics initopt++; 1491500Serics for (initline = 0; *s != '\0'; s++) 1501500Serics if (isdigit (*s)) 1511500Serics initline = initline*10 + *s -'0'; 1521500Serics --initline; 1531500Serics } 1541500Serics } 1551500Serics else break; 1561500Serics } 1573594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1583455Sroot * defined, and in that case, make sure we are in noscroll mode 1593455Sroot */ 1603455Sroot if(clreol) 1613455Sroot { 16218608Sralph if((Home == NULL) || (*Home == '\0') || 16318608Sralph (eraseln == NULL) || (*eraseln == '\0') || 16418608Sralph (EodClr == NULL) || (*EodClr == '\0') ) 16518608Sralph clreol = 0; 1663455Sroot else noscroll = 1; 1673455Sroot } 1681500Serics if (dlines == 0) 1691500Serics dlines = Lpp - (noscroll ? 1 : 2); 1701500Serics left = dlines; 1711500Serics if (nfiles > 1) 1721500Serics prnames++; 1731500Serics if (!no_intty && nfiles == 0) { 17434104Sbostic char *rindex(); 17534104Sbostic 17634104Sbostic p = rindex(argv[0], '/'); 17734104Sbostic fputs("usage: ",stderr); 17834104Sbostic fputs(p ? p + 1 : argv[0],stderr); 1791500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1801500Serics exit(1); 1811500Serics } 1821500Serics else 1831500Serics f = stdin; 1841500Serics if (!no_tty) { 1851500Serics signal(SIGQUIT, onquit); 1861500Serics signal(SIGINT, end_it); 18727006Sdonn signal(SIGWINCH, chgwinsz); 1881500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1891500Serics signal(SIGTSTP, onsusp); 1901500Serics catch_susp++; 1911500Serics } 19216582Sleres stty (fileno(stderr), &otty); 1931500Serics } 1941500Serics if (no_intty) { 1951500Serics if (no_tty) 1961500Serics copy_file (stdin); 1971500Serics else { 1981500Serics if ((ch = Getc (f)) == '\f') 1993594Sroot doclear(); 2001500Serics else { 2011500Serics Ungetc (ch, f); 2023594Sroot if (noscroll && (ch != EOF)) { 2033594Sroot if (clreol) 2043594Sroot home (); 2053594Sroot else 2063594Sroot doclear (); 2073455Sroot } 2081500Serics } 2091500Serics if (srchopt) 2103455Sroot { 2111500Serics search (initbuf, stdin, 1); 2123594Sroot if (noscroll) 2133594Sroot left--; 2143455Sroot } 2151500Serics else if (initopt) 2161500Serics skiplns (initline, stdin); 2171500Serics screen (stdin, left); 2181500Serics } 2191500Serics no_intty = 0; 2201500Serics prnames++; 2211500Serics firstf = 0; 2221500Serics } 2231500Serics 2241500Serics while (fnum < nfiles) { 2251500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2261500Serics context.line = context.chrctr = 0; 2271500Serics Currline = 0; 2281500Serics if (firstf) setjmp (restore); 2291500Serics if (firstf) { 2301500Serics firstf = 0; 2311500Serics if (srchopt) 2323455Sroot { 2331500Serics search (initbuf, f, 1); 2343594Sroot if (noscroll) 2353594Sroot left--; 2363455Sroot } 2371500Serics else if (initopt) 2381500Serics skiplns (initline, f); 2391500Serics } 2401500Serics else if (fnum < nfiles && !no_tty) { 2411500Serics setjmp (restore); 2421500Serics left = command (fnames[fnum], f); 2431500Serics } 2441500Serics if (left != 0) { 24532736Sbostic if ((noscroll || clearit) && (file_size != LONG_MAX)) 2463594Sroot if (clreol) 2473594Sroot home (); 2483594Sroot else 2493594Sroot doclear (); 2501500Serics if (prnames) { 2511500Serics if (bad_so) 2521500Serics erase (0); 2533594Sroot if (clreol) 2543594Sroot cleareol (); 2551500Serics pr("::::::::::::::"); 2561500Serics if (promptlen > 14) 2571500Serics erase (14); 25846779Sbostic prtf ("\n"); 2593455Sroot if(clreol) cleareol(); 26046779Sbostic prtf("%s\n", fnames[fnum]); 2613455Sroot if(clreol) cleareol(); 26246779Sbostic prtf("::::::::::::::\n"); 2631500Serics if (left > Lpp - 4) 2641500Serics left = Lpp - 4; 2651500Serics } 2661500Serics if (no_tty) 2671500Serics copy_file (f); 2681500Serics else { 2691500Serics within++; 2701500Serics screen(f, left); 2711500Serics within = 0; 2721500Serics } 2731500Serics } 2741500Serics setjmp (restore); 2751500Serics fflush(stdout); 2761500Serics fclose(f); 2771500Serics screen_start.line = screen_start.chrctr = 0L; 2781500Serics context.line = context.chrctr = 0L; 2791500Serics } 2801500Serics fnum++; 2811500Serics firstf = 0; 2821500Serics } 2831500Serics reset_tty (); 2841500Serics exit(0); 2851500Serics } 2861500Serics 2873455Sroot argscan(s) 2883455Sroot char *s; 2893455Sroot { 29032273Sbostic int seen_num = 0; 29132273Sbostic 29232273Sbostic while (*s != '\0') { 29332273Sbostic switch (*s) { 29411604Slayer case '0': case '1': case '2': 29511604Slayer case '3': case '4': case '5': 29611604Slayer case '6': case '7': case '8': 29711604Slayer case '9': 29832273Sbostic if (!seen_num) { 29932273Sbostic dlines = 0; 30032273Sbostic seen_num = 1; 30132273Sbostic } 30211604Slayer dlines = dlines*10 + *s - '0'; 30311604Slayer break; 30411604Slayer case 'd': 30511604Slayer dum_opt = 1; 30611604Slayer break; 30711604Slayer case 'l': 30811604Slayer stop_opt = 0; 30911604Slayer break; 31011604Slayer case 'f': 31111604Slayer fold_opt = 0; 31211604Slayer break; 31311604Slayer case 'p': 31411604Slayer noscroll++; 31511604Slayer break; 31611604Slayer case 'c': 31711604Slayer clreol++; 31811604Slayer break; 31911604Slayer case 's': 32011604Slayer ssp_opt = 1; 32111604Slayer break; 32211604Slayer case 'u': 32311604Slayer ul_opt = 0; 32411604Slayer break; 32511604Slayer } 32632273Sbostic s++; 32711604Slayer } 3283455Sroot } 3293455Sroot 3303455Sroot 3311500Serics /* 3321500Serics ** Check whether the file named by fs is an ASCII file which the user may 3331500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3341500Serics */ 3351500Serics 3361500Serics FILE * 3371500Serics checkf (fs, clearfirst) 33832736Sbostic register char *fs; 33932736Sbostic int *clearfirst; 3401500Serics { 34132736Sbostic struct stat stbuf; 34232736Sbostic register FILE *f; 34332736Sbostic char c; 3441500Serics 34532736Sbostic if (stat (fs, &stbuf) == -1) { 34632736Sbostic (void)fflush(stdout); 34732736Sbostic if (clreol) 34832736Sbostic cleareol (); 34932736Sbostic perror(fs); 35032736Sbostic return((FILE *)NULL); 35132736Sbostic } 35232736Sbostic if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 35346779Sbostic prtf("\n*** %s: directory ***\n\n", fs); 35432736Sbostic return((FILE *)NULL); 35532736Sbostic } 35632736Sbostic if ((f = Fopen(fs, "r")) == NULL) { 35732736Sbostic (void)fflush(stdout); 35832736Sbostic perror(fs); 35932736Sbostic return((FILE *)NULL); 36032736Sbostic } 36132736Sbostic if (magic(f, fs)) 36232736Sbostic return((FILE *)NULL); 36332736Sbostic c = Getc(f); 36432736Sbostic *clearfirst = c == '\f'; 3651500Serics Ungetc (c, f); 36632736Sbostic if ((file_size = stbuf.st_size) == 0) 36732736Sbostic file_size = LONG_MAX; 36832736Sbostic return(f); 3691500Serics } 3701500Serics 3711500Serics /* 37232736Sbostic * magic -- 37332736Sbostic * check for file magic numbers. This code would best be shared with 37432736Sbostic * the file(1) program or, perhaps, more should not try and be so smart? 37529906Smckusick */ 37632736Sbostic magic(f, fs) 37732736Sbostic FILE *f; 37832736Sbostic char *fs; 37929906Smckusick { 38032736Sbostic struct exec ex; 38129906Smckusick 38232736Sbostic if (fread(&ex, sizeof(ex), 1, f) == 1) 38332736Sbostic switch(ex.a_magic) { 38432736Sbostic case OMAGIC: 38532736Sbostic case NMAGIC: 38632736Sbostic case ZMAGIC: 38732736Sbostic case 0405: 38832736Sbostic case 0411: 38932736Sbostic case 0177545: 39046779Sbostic prtf("\n******** %s: Not a text file ********\n\n", fs); 39132736Sbostic (void)fclose(f); 39232736Sbostic return(1); 39332736Sbostic } 39432736Sbostic (void)fseek(f, 0L, L_SET); /* rewind() not necessary */ 39533087Sbostic return(0); 39629906Smckusick } 39729906Smckusick 39829906Smckusick /* 3991500Serics ** A real function, for the tputs routine in termlib 4001500Serics */ 4011500Serics 4021500Serics putch (ch) 4031500Serics char ch; 4041500Serics { 4051500Serics putchar (ch); 4061500Serics } 4071500Serics 4081500Serics /* 4091500Serics ** Print out the contents of the file f, one screenful at a time. 4101500Serics */ 4111500Serics 4121500Serics #define STOP -10 4131500Serics 4141500Serics screen (f, num_lines) 4151500Serics register FILE *f; 4161500Serics register int num_lines; 4171500Serics { 4181500Serics register int c; 4191500Serics register int nchars; 4203594Sroot int length; /* length of current line */ 4213594Sroot static int prev_len = 1; /* length of previous line */ 4221500Serics 4231500Serics for (;;) { 4241500Serics while (num_lines > 0 && !Pause) { 4251500Serics if ((nchars = getline (f, &length)) == EOF) 4263455Sroot { 4273594Sroot if (clreol) 4283594Sroot clreos(); 4291500Serics return; 4303455Sroot } 4313594Sroot if (ssp_opt && length == 0 && prev_len == 0) 4323594Sroot continue; 4333594Sroot prev_len = length; 4341500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 4351500Serics erase (0); 4363594Sroot /* must clear before drawing line since tabs on some terminals 4373594Sroot * do not erase what they tab over. 4383594Sroot */ 4393594Sroot if (clreol) 4403594Sroot cleareol (); 4411500Serics prbuf (Line, length); 4421500Serics if (nchars < promptlen) 4431500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4441500Serics else promptlen = 0; 4453594Sroot /* is this needed? 4463594Sroot * if (clreol) 4473594Sroot * cleareol(); /* must clear again in case we wrapped * 4483594Sroot */ 4491500Serics if (nchars < Mcol || !fold_opt) 45016710Sjak prbuf("\n", 1); /* will turn off UL if necessary */ 4511500Serics if (nchars == STOP) 4521500Serics break; 4531500Serics num_lines--; 4541500Serics } 45516710Sjak if (pstate) { 45616710Sjak tputs(ULexit, 1, putch); 45716710Sjak pstate = 0; 45816710Sjak } 4591500Serics fflush(stdout); 4601500Serics if ((c = Getc(f)) == EOF) 4613455Sroot { 4623594Sroot if (clreol) 4633594Sroot clreos (); 4641500Serics return; 4653455Sroot } 4663455Sroot 4673594Sroot if (Pause && clreol) 4683594Sroot clreos (); 4691500Serics Ungetc (c, f); 4701500Serics setjmp (restore); 4711500Serics Pause = 0; startup = 0; 4721500Serics if ((num_lines = command (NULL, f)) == 0) 4731500Serics return; 4741500Serics if (hard && promptlen > 0) 4751500Serics erase (0); 47611123Slayer if (noscroll && num_lines >= dlines) 47716582Sleres { 4783594Sroot if (clreol) 4793594Sroot home(); 4803594Sroot else 4813594Sroot doclear (); 4823455Sroot } 4831500Serics screen_start.line = Currline; 4841500Serics screen_start.chrctr = Ftell (f); 4851500Serics } 4861500Serics } 4871500Serics 4881500Serics /* 4891500Serics ** Come here if a quit signal is received 4901500Serics */ 4911500Serics 49246779Sbostic void 4931500Serics onquit() 4941500Serics { 4951500Serics signal(SIGQUIT, SIG_IGN); 4961500Serics if (!inwait) { 4971500Serics putchar ('\n'); 4981500Serics if (!startup) { 4991500Serics signal(SIGQUIT, onquit); 5001500Serics longjmp (restore, 1); 5011500Serics } 5021500Serics else 5031500Serics Pause++; 5041500Serics } 5051500Serics else if (!dum_opt && notell) { 5061500Serics write (2, "[Use q or Q to quit]", 20); 5071500Serics promptlen += 20; 5081500Serics notell = 0; 5091500Serics } 5101500Serics signal(SIGQUIT, onquit); 5111500Serics } 5121500Serics 5131500Serics /* 51427006Sdonn ** Come here if a signal for a window size change is received 51527006Sdonn */ 51627006Sdonn 51746779Sbostic void 51827006Sdonn chgwinsz() 51927006Sdonn { 52027006Sdonn struct winsize win; 52127006Sdonn 52227006Sdonn (void) signal(SIGWINCH, SIG_IGN); 52327006Sdonn if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { 52427006Sdonn if (win.ws_row != 0) { 52527006Sdonn Lpp = win.ws_row; 52627006Sdonn nscroll = Lpp/2 - 1; 52727006Sdonn if (nscroll <= 0) 52827006Sdonn nscroll = 1; 52927006Sdonn dlines = Lpp - (noscroll ? 1 : 2); 53027006Sdonn } 53127006Sdonn if (win.ws_col != 0) 53227006Sdonn Mcol = win.ws_col; 53327006Sdonn } 53427006Sdonn (void) signal(SIGWINCH, chgwinsz); 53527006Sdonn } 53627006Sdonn 53727006Sdonn /* 5381500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 5391500Serics */ 5401500Serics 54146779Sbostic void 5421500Serics end_it () 5431500Serics { 5441500Serics 5451500Serics reset_tty (); 5463594Sroot if (clreol) { 5473594Sroot putchar ('\r'); 5483594Sroot clreos (); 5493594Sroot fflush (stdout); 5503594Sroot } 5513455Sroot else if (!clreol && (promptlen > 0)) { 5521500Serics kill_line (); 5531500Serics fflush (stdout); 5541500Serics } 5551500Serics else 5561500Serics write (2, "\n", 1); 5571500Serics _exit(0); 5581500Serics } 5591500Serics 5601500Serics copy_file(f) 5611500Serics register FILE *f; 5621500Serics { 5631500Serics register int c; 5641500Serics 5651500Serics while ((c = getc(f)) != EOF) 5661500Serics putchar(c); 5671500Serics } 5681500Serics 5691500Serics /* Simplified printf function */ 5701500Serics 57146779Sbostic prtf (fmt, va_alist) 5721500Serics register char *fmt; 57332737Sbostic va_dcl 5741500Serics { 57532737Sbostic va_list ap; 5761500Serics register char ch; 5771500Serics register int ccount; 5781500Serics 5791500Serics ccount = 0; 58032737Sbostic va_start(ap); 5811500Serics while (*fmt) { 5821500Serics while ((ch = *fmt++) != '%') { 5831500Serics if (ch == '\0') 5841500Serics return (ccount); 5851500Serics ccount++; 5861500Serics putchar (ch); 5871500Serics } 5881500Serics switch (*fmt++) { 5891500Serics case 'd': 59032737Sbostic ccount += printd (va_arg(ap, int)); 5911500Serics break; 5921500Serics case 's': 59332737Sbostic ccount += pr (va_arg(ap, char *)); 5941500Serics break; 5951500Serics case '%': 5961500Serics ccount++; 5971500Serics putchar ('%'); 5981500Serics break; 5991500Serics case '0': 6001500Serics return (ccount); 6011500Serics default: 6021500Serics break; 6031500Serics } 6041500Serics } 60532737Sbostic va_end(ap); 6061500Serics return (ccount); 6071500Serics 6081500Serics } 6091500Serics 6101500Serics /* 6111500Serics ** Print an integer as a string of decimal digits, 6121500Serics ** returning the length of the print representation. 6131500Serics */ 6141500Serics 6151500Serics printd (n) 6161500Serics int n; 6171500Serics { 6181500Serics int a, nchars; 6191500Serics 6201500Serics if (a = n/10) 6211500Serics nchars = 1 + printd(a); 6221500Serics else 6231500Serics nchars = 1; 6241500Serics putchar (n % 10 + '0'); 6251500Serics return (nchars); 6261500Serics } 6271500Serics 6281500Serics /* Put the print representation of an integer into a string */ 6291500Serics static char *sptr; 6301500Serics 6311500Serics scanstr (n, str) 6321500Serics int n; 6331500Serics char *str; 6341500Serics { 6351500Serics sptr = str; 63611604Slayer Sprintf (n); 6371500Serics *sptr = '\0'; 6381500Serics } 6391500Serics 64011604Slayer Sprintf (n) 6411500Serics { 6421500Serics int a; 6431500Serics 6441500Serics if (a = n/10) 64511604Slayer Sprintf (a); 6461500Serics *sptr++ = n % 10 + '0'; 6471500Serics } 6481500Serics 64933232Sbostic static char bell = ctrl('G'); 6501500Serics 6511500Serics strlen (s) 6521500Serics char *s; 6531500Serics { 6541500Serics register char *p; 6551500Serics 6561500Serics p = s; 6571500Serics while (*p++) 6581500Serics ; 6591500Serics return (p - s - 1); 6601500Serics } 6611500Serics 6621500Serics /* See whether the last component of the path name "path" is equal to the 6631500Serics ** string "string" 6641500Serics */ 6651500Serics 6661500Serics tailequ (path, string) 6671500Serics char *path; 6681500Serics register char *string; 6691500Serics { 6701500Serics register char *tail; 6711500Serics 6721500Serics tail = path + strlen(path); 6731500Serics while (tail >= path) 6741500Serics if (*(--tail) == '/') 6751500Serics break; 6761500Serics ++tail; 6771500Serics while (*tail++ == *string++) 6781500Serics if (*tail == '\0') 6791500Serics return(1); 6801500Serics return(0); 6811500Serics } 6821500Serics 6831500Serics prompt (filename) 6841500Serics char *filename; 6851500Serics { 6863594Sroot if (clreol) 6873594Sroot cleareol (); 6883455Sroot else if (promptlen > 0) 6891500Serics kill_line (); 6901500Serics if (!hard) { 6911500Serics promptlen = 8; 69216710Sjak if (Senter && Sexit) { 6931500Serics tputs (Senter, 1, putch); 69416710Sjak promptlen += (2 * soglitch); 69516710Sjak } 6963594Sroot if (clreol) 6973594Sroot cleareol (); 6981500Serics pr("--More--"); 6991500Serics if (filename != NULL) { 70046779Sbostic promptlen += prtf ("(Next file: %s)", filename); 7011500Serics } 7021500Serics else if (!no_intty) { 70346779Sbostic promptlen += prtf ("(%d%%)", (int)((file_pos * 100) / file_size)); 7041500Serics } 7051500Serics if (dum_opt) { 70616710Sjak promptlen += pr("[Press space to continue, 'q' to quit.]"); 7071500Serics } 7081500Serics if (Senter && Sexit) 7091500Serics tputs (Sexit, 1, putch); 7103594Sroot if (clreol) 7113594Sroot clreos (); 7121500Serics fflush(stdout); 7131500Serics } 7141500Serics else 7151500Serics write (2, &bell, 1); 7161500Serics inwait++; 7171500Serics } 7181500Serics 7191500Serics /* 7201500Serics ** Get a logical line 7211500Serics */ 7221500Serics 7231500Serics getline(f, length) 7241500Serics register FILE *f; 7251500Serics int *length; 7261500Serics { 7271500Serics register int c; 7281500Serics register char *p; 7291500Serics register int column; 7301500Serics static int colflg; 7311500Serics 7321500Serics p = Line; 7331500Serics column = 0; 7341500Serics c = Getc (f); 7351500Serics if (colflg && c == '\n') { 7361500Serics Currline++; 7371500Serics c = Getc (f); 7381500Serics } 7391500Serics while (p < &Line[LINSIZ - 1]) { 7401500Serics if (c == EOF) { 7411500Serics if (p > Line) { 7421500Serics *p = '\0'; 7431500Serics *length = p - Line; 7441500Serics return (column); 7451500Serics } 7461500Serics *length = p - Line; 7471500Serics return (EOF); 7481500Serics } 7491500Serics if (c == '\n') { 7501500Serics Currline++; 7511500Serics break; 7521500Serics } 7531500Serics *p++ = c; 7541500Serics if (c == '\t') 75529907Smckusick if (!hardtabs || column < promptlen && !hard) { 75629907Smckusick if (hardtabs && eraseln && !dumb) { 7571500Serics column = 1 + (column | 7); 7581500Serics tputs (eraseln, 1, putch); 7591500Serics promptlen = 0; 7601500Serics } 7611500Serics else { 76229907Smckusick for (--p; p < &Line[LINSIZ - 1];) { 7631500Serics *p++ = ' '; 76429907Smckusick if ((++column & 7) == 0) 76529907Smckusick break; 7661500Serics } 7671500Serics if (column >= promptlen) promptlen = 0; 7681500Serics } 7691500Serics } 7701500Serics else 7711500Serics column = 1 + (column | 7); 7729627Ssklower else if (c == '\b' && column > 0) 7731500Serics column--; 7741500Serics else if (c == '\r') 7751500Serics column = 0; 7761500Serics else if (c == '\f' && stop_opt) { 7771500Serics p[-1] = '^'; 7781500Serics *p++ = 'L'; 7791500Serics column += 2; 7801500Serics Pause++; 7811500Serics } 7821500Serics else if (c == EOF) { 7831500Serics *length = p - Line; 7841500Serics return (column); 7851500Serics } 7861500Serics else if (c >= ' ' && c != RUBOUT) 7871500Serics column++; 7881500Serics if (column >= Mcol && fold_opt) break; 7891500Serics c = Getc (f); 7901500Serics } 7911500Serics if (column >= Mcol && Mcol > 0) { 7921500Serics if (!Wrap) { 7931500Serics *p++ = '\n'; 7941500Serics } 7951500Serics } 7961500Serics colflg = column == Mcol && fold_opt; 79729907Smckusick if (colflg && eatnl && Wrap) { 79829907Smckusick *p++ = '\n'; /* simulate normal wrap */ 79929907Smckusick } 8001500Serics *length = p - Line; 8011500Serics *p = 0; 8021500Serics return (column); 8031500Serics } 8041500Serics 8051500Serics /* 8061500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 8071500Serics */ 8081500Serics 8091500Serics erase (col) 8101500Serics register int col; 8111500Serics { 8121500Serics 8131500Serics if (promptlen == 0) 8141500Serics return; 8151500Serics if (hard) { 8161500Serics putchar ('\n'); 8171500Serics } 8181500Serics else { 8191500Serics if (col == 0) 8201500Serics putchar ('\r'); 8211500Serics if (!dumb && eraseln) 8221500Serics tputs (eraseln, 1, putch); 8231500Serics else 8241500Serics for (col = promptlen - col; col > 0; col--) 8251500Serics putchar (' '); 8261500Serics } 8271500Serics promptlen = 0; 8281500Serics } 8291500Serics 8301500Serics /* 8311500Serics ** Erase the current line entirely 8321500Serics */ 8331500Serics 8341500Serics kill_line () 8351500Serics { 8361500Serics erase (0); 8371500Serics if (!eraseln || dumb) putchar ('\r'); 8381500Serics } 8391500Serics 8401500Serics /* 8413455Sroot * force clear to end of line 8423455Sroot */ 8433455Sroot cleareol() 8443455Sroot { 8453594Sroot tputs(eraseln, 1, putch); 8463455Sroot } 8473455Sroot 8483594Sroot clreos() 8493455Sroot { 8503594Sroot tputs(EodClr, 1, putch); 8513455Sroot } 8523455Sroot 8533455Sroot /* 8541500Serics ** Print string and return number of characters 8551500Serics */ 8561500Serics 8571500Serics pr(s1) 8581500Serics char *s1; 8591500Serics { 8601500Serics register char *s; 8611500Serics register char c; 8621500Serics 8631500Serics for (s = s1; c = *s++; ) 8641500Serics putchar(c); 8651500Serics return (s - s1 - 1); 8661500Serics } 8671500Serics 8681500Serics 8691500Serics /* Print a buffer of n characters */ 8701500Serics 8711500Serics prbuf (s, n) 8721500Serics register char *s; 8731500Serics register int n; 8741500Serics { 87516710Sjak register char c; /* next output character */ 8763594Sroot register int state; /* next output char's UL state */ 87716710Sjak #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 8783594Sroot 8793594Sroot while (--n >= 0) 8803594Sroot if (!ul_opt) 8813594Sroot putchar (*s++); 8823594Sroot else { 88316710Sjak if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 88416710Sjak s++; 88516710Sjak continue; 88616710Sjak } 88716710Sjak if (state = wouldul(s, n)) { 88816710Sjak c = (*s == '_')? s[2] : *s ; 8893594Sroot n -= 2; 89016710Sjak s += 3; 89116710Sjak } else 8923594Sroot c = *s++; 89316710Sjak if (state != pstate) { 89416710Sjak if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 89516710Sjak state = 1; 89616710Sjak else 89716710Sjak tputs(state ? ULenter : ULexit, 1, putch); 8983594Sroot } 89916710Sjak if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 90016710Sjak putchar(c); 9013594Sroot if (state && *chUL) { 9023594Sroot pr(chBS); 9033594Sroot tputs(chUL, 1, putch); 9043594Sroot } 90516710Sjak pstate = state; 9063594Sroot } 9071500Serics } 9081500Serics 9091500Serics /* 9101500Serics ** Clear the screen 9111500Serics */ 9121500Serics 9131500Serics doclear() 9141500Serics { 9151500Serics if (Clear && !hard) { 9161500Serics tputs(Clear, 1, putch); 9171500Serics 9181500Serics /* Put out carriage return so that system doesn't 9191500Serics ** get confused by escape sequences when expanding tabs 9201500Serics */ 9211500Serics putchar ('\r'); 9221500Serics promptlen = 0; 9231500Serics } 9241500Serics } 9251500Serics 9263455Sroot /* 9273455Sroot * Go to home position 9283455Sroot */ 9293455Sroot home() 9303455Sroot { 9313455Sroot tputs(Home,1,putch); 9323455Sroot } 9333455Sroot 9341500Serics static int lastcmd, lastarg, lastp; 9351500Serics static int lastcolon; 9361500Serics char shell_line[132]; 9371500Serics 9381500Serics /* 9391500Serics ** Read a command and do it. A command consists of an optional integer 9401500Serics ** argument followed by the command character. Return the number of lines 9411500Serics ** to display in the next screenful. If there is nothing more to display 9421500Serics ** in the current file, zero is returned. 9431500Serics */ 9441500Serics 9451500Serics command (filename, f) 9461500Serics char *filename; 9471500Serics register FILE *f; 9481500Serics { 9491500Serics register int nlines; 9501500Serics register int retval; 9511500Serics register char c; 9521500Serics char colonch; 9531500Serics FILE *helpf; 9541500Serics int done; 9551500Serics char comchar, cmdbuf[80], *p; 9561500Serics 9571500Serics #define ret(val) retval=val;done++;break 9581500Serics 9591500Serics done = 0; 9601500Serics if (!errors) 9611500Serics prompt (filename); 9621500Serics else 9631500Serics errors = 0; 9641500Serics if (MBIT == RAW && slow_tty) { 9651500Serics otty.sg_flags |= MBIT; 96616582Sleres stty(fileno(stderr), &otty); 9671500Serics } 9681500Serics for (;;) { 9691500Serics nlines = number (&comchar); 9701500Serics lastp = colonch = 0; 9711500Serics if (comchar == '.') { /* Repeat last command */ 9721500Serics lastp++; 9731500Serics comchar = lastcmd; 9741500Serics nlines = lastarg; 9751500Serics if (lastcmd == ':') 9761500Serics colonch = lastcolon; 9771500Serics } 9781500Serics lastcmd = comchar; 9791500Serics lastarg = nlines; 9801500Serics if (comchar == otty.sg_erase) { 9811500Serics kill_line (); 9821500Serics prompt (filename); 9831500Serics continue; 9841500Serics } 9851500Serics switch (comchar) { 9861500Serics case ':': 9871500Serics retval = colon (filename, colonch, nlines); 9881500Serics if (retval >= 0) 9891500Serics done++; 9901500Serics break; 99124490Sbloom case 'b': 99233232Sbostic case ctrl('B'): 99324490Sbloom { 99424490Sbloom register int initline; 99524490Sbloom 99624490Sbloom if (no_intty) { 99724490Sbloom write(2, &bell, 1); 99824490Sbloom return (-1); 99924490Sbloom } 100024490Sbloom 100124490Sbloom if (nlines == 0) nlines++; 100224490Sbloom 100324490Sbloom putchar ('\r'); 100424490Sbloom erase (0); 100546779Sbostic prtf ("\n"); 100624490Sbloom if (clreol) 100724490Sbloom cleareol (); 100846779Sbostic prtf ("...back %d page", nlines); 100924490Sbloom if (nlines > 1) 101024490Sbloom pr ("s\n"); 101124490Sbloom else 101224490Sbloom pr ("\n"); 101324490Sbloom 101424490Sbloom if (clreol) 101524490Sbloom cleareol (); 101624490Sbloom pr ("\n"); 101724490Sbloom 101824490Sbloom initline = Currline - dlines * (nlines + 1); 101924490Sbloom if (! noscroll) 102024490Sbloom --initline; 102124490Sbloom if (initline < 0) initline = 0; 102224490Sbloom Fseek(f, 0L); 102324490Sbloom Currline = 0; /* skiplns() will make Currline correct */ 102424490Sbloom skiplns(initline, f); 102524490Sbloom if (! noscroll) { 102624490Sbloom ret(dlines + 1); 102724490Sbloom } 102824490Sbloom else { 102924490Sbloom ret(dlines); 103024490Sbloom } 103124490Sbloom } 10321500Serics case ' ': 10331500Serics case 'z': 10341500Serics if (nlines == 0) nlines = dlines; 10351500Serics else if (comchar == 'z') dlines = nlines; 10361500Serics ret (nlines); 10371500Serics case 'd': 103833232Sbostic case ctrl('D'): 10391500Serics if (nlines != 0) nscroll = nlines; 10401500Serics ret (nscroll); 10411500Serics case 'q': 10421500Serics case 'Q': 10431500Serics end_it (); 10441500Serics case 's': 10451500Serics case 'f': 10461500Serics if (nlines == 0) nlines++; 10471500Serics if (comchar == 'f') 10481500Serics nlines *= dlines; 10491500Serics putchar ('\r'); 10501500Serics erase (0); 105146779Sbostic prtf ("\n"); 10523594Sroot if (clreol) 10533594Sroot cleareol (); 105446779Sbostic prtf ("...skipping %d line", nlines); 10551500Serics if (nlines > 1) 10563594Sroot pr ("s\n"); 10571500Serics else 10583594Sroot pr ("\n"); 10593594Sroot 10603594Sroot if (clreol) 10613594Sroot cleareol (); 10623594Sroot pr ("\n"); 10633594Sroot 10641500Serics while (nlines > 0) { 10651500Serics while ((c = Getc (f)) != '\n') 10661500Serics if (c == EOF) { 10671500Serics retval = 0; 10681500Serics done++; 10691500Serics goto endsw; 10701500Serics } 10711500Serics Currline++; 10721500Serics nlines--; 10731500Serics } 10741500Serics ret (dlines); 10751500Serics case '\n': 10761500Serics if (nlines != 0) 10771500Serics dlines = nlines; 10781500Serics else 10791500Serics nlines = 1; 10801500Serics ret (nlines); 10811500Serics case '\f': 10821500Serics if (!no_intty) { 10831500Serics doclear (); 10841500Serics Fseek (f, screen_start.chrctr); 10851500Serics Currline = screen_start.line; 10861500Serics ret (dlines); 10871500Serics } 10881500Serics else { 10891500Serics write (2, &bell, 1); 10901500Serics break; 10911500Serics } 10921500Serics case '\'': 10931500Serics if (!no_intty) { 10941500Serics kill_line (); 10951500Serics pr ("\n***Back***\n\n"); 10961500Serics Fseek (f, context.chrctr); 10971500Serics Currline = context.line; 10981500Serics ret (dlines); 10991500Serics } 11001500Serics else { 11011500Serics write (2, &bell, 1); 11021500Serics break; 11031500Serics } 11041500Serics case '=': 11051500Serics kill_line (); 11061500Serics promptlen = printd (Currline); 11071500Serics fflush (stdout); 11081500Serics break; 11091500Serics case 'n': 11101500Serics lastp++; 11111500Serics case '/': 11121500Serics if (nlines == 0) nlines++; 11131500Serics kill_line (); 11141500Serics pr ("/"); 11151500Serics promptlen = 1; 11161500Serics fflush (stdout); 11171500Serics if (lastp) { 11181500Serics write (2,"\r", 1); 11191500Serics search (NULL, f, nlines); /* Use previous r.e. */ 11201500Serics } 11211500Serics else { 11221500Serics ttyin (cmdbuf, 78, '/'); 11231500Serics write (2, "\r", 1); 11241500Serics search (cmdbuf, f, nlines); 11251500Serics } 11263455Sroot ret (dlines-1); 11271500Serics case '!': 11281500Serics do_shell (filename); 11291500Serics break; 113024490Sbloom case '?': 11311500Serics case 'h': 11321500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 11331500Serics error ("Can't open help file"); 11341500Serics if (noscroll) doclear (); 11351500Serics copy_file (helpf); 113627006Sdonn fclose (helpf); 11371500Serics prompt (filename); 11381500Serics break; 11391500Serics case 'v': /* This case should go right before default */ 11401500Serics if (!no_intty) { 11411500Serics kill_line (); 11421500Serics cmdbuf[0] = '+'; 114324490Sbloom scanstr (Currline - dlines < 0 ? 0 114424490Sbloom : Currline - (dlines + 1) / 2, &cmdbuf[1]); 11451500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 114638522Sbostic execute (filename, _PATH_VI, "vi", cmdbuf, fnames[fnum], 0); 11471500Serics break; 11481500Serics } 11491500Serics default: 115016710Sjak if (dum_opt) { 115116710Sjak kill_line (); 115216710Sjak if (Senter && Sexit) { 115316710Sjak tputs (Senter, 1, putch); 115416710Sjak promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 115516710Sjak tputs (Sexit, 1, putch); 115616710Sjak } 115716710Sjak else 115816710Sjak promptlen = pr ("[Press 'h' for instructions.]"); 115916710Sjak fflush (stdout); 116016710Sjak } 116116710Sjak else 116216710Sjak write (2, &bell, 1); 11631500Serics break; 11641500Serics } 11651500Serics if (done) break; 11661500Serics } 11671500Serics putchar ('\r'); 11681500Serics endsw: 11691500Serics inwait = 0; 11701500Serics notell++; 11711500Serics if (MBIT == RAW && slow_tty) { 11721500Serics otty.sg_flags &= ~MBIT; 117316582Sleres stty(fileno(stderr), &otty); 11741500Serics } 11751500Serics return (retval); 11761500Serics } 11771500Serics 11781500Serics char ch; 11791500Serics 11801500Serics /* 11811500Serics * Execute a colon-prefixed command. 11821500Serics * Returns <0 if not a command that should cause 11831500Serics * more of the file to be printed. 11841500Serics */ 11851500Serics 11861500Serics colon (filename, cmd, nlines) 11871500Serics char *filename; 11881500Serics int cmd; 11891500Serics int nlines; 11901500Serics { 11911500Serics if (cmd == 0) 11921500Serics ch = readch (); 11931500Serics else 11941500Serics ch = cmd; 11951500Serics lastcolon = ch; 11961500Serics switch (ch) { 11971500Serics case 'f': 11981500Serics kill_line (); 11991500Serics if (!no_intty) 120046779Sbostic promptlen = prtf ("\"%s\" line %d", fnames[fnum], Currline); 12011500Serics else 120246779Sbostic promptlen = prtf ("[Not a file] line %d", Currline); 12031500Serics fflush (stdout); 12041500Serics return (-1); 12051500Serics case 'n': 12061500Serics if (nlines == 0) { 12071500Serics if (fnum >= nfiles - 1) 12081500Serics end_it (); 12091500Serics nlines++; 12101500Serics } 12111500Serics putchar ('\r'); 12121500Serics erase (0); 12131500Serics skipf (nlines); 12141500Serics return (0); 12151500Serics case 'p': 12161500Serics if (no_intty) { 12171500Serics write (2, &bell, 1); 12181500Serics return (-1); 12191500Serics } 12201500Serics putchar ('\r'); 12211500Serics erase (0); 12221500Serics if (nlines == 0) 12231500Serics nlines++; 12241500Serics skipf (-nlines); 12251500Serics return (0); 12261500Serics case '!': 12271500Serics do_shell (filename); 12281500Serics return (-1); 12291500Serics case 'q': 12301500Serics case 'Q': 12311500Serics end_it (); 12321500Serics default: 12331500Serics write (2, &bell, 1); 12341500Serics return (-1); 12351500Serics } 12361500Serics } 12371500Serics 12381500Serics /* 12391500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 12401500Serics ** terminates the number. 12411500Serics */ 12421500Serics 12431500Serics number(cmd) 12441500Serics char *cmd; 12451500Serics { 12461500Serics register int i; 12471500Serics 12481500Serics i = 0; ch = otty.sg_kill; 12491500Serics for (;;) { 12501500Serics ch = readch (); 12511500Serics if (ch >= '0' && ch <= '9') 12521500Serics i = i*10 + ch - '0'; 12531500Serics else if (ch == otty.sg_kill) 12541500Serics i = 0; 12551500Serics else { 12561500Serics *cmd = ch; 12571500Serics break; 12581500Serics } 12591500Serics } 12601500Serics return (i); 12611500Serics } 12621500Serics 12631500Serics do_shell (filename) 12641500Serics char *filename; 12651500Serics { 12661500Serics char cmdbuf[80]; 12671500Serics 12681500Serics kill_line (); 12691500Serics pr ("!"); 12701500Serics fflush (stdout); 12711500Serics promptlen = 1; 12721500Serics if (lastp) 12731500Serics pr (shell_line); 12741500Serics else { 12751500Serics ttyin (cmdbuf, 78, '!'); 12761500Serics if (expand (shell_line, cmdbuf)) { 12771500Serics kill_line (); 127846779Sbostic promptlen = prtf ("!%s", shell_line); 12791500Serics } 12801500Serics } 12811500Serics fflush (stdout); 12821500Serics write (2, "\n", 1); 12831500Serics promptlen = 0; 12841500Serics shellp = 1; 12851500Serics execute (filename, shell, shell, "-c", shell_line, 0); 12861500Serics } 12871500Serics 12881500Serics /* 12891500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 12901500Serics */ 12911500Serics 12921500Serics search (buf, file, n) 12931500Serics char buf[]; 12941500Serics FILE *file; 12951500Serics register int n; 12961500Serics { 12971500Serics long startline = Ftell (file); 12981500Serics register long line1 = startline; 12991500Serics register long line2 = startline; 13001500Serics register long line3 = startline; 13011500Serics register int lncount; 13021500Serics int saveln, rv, re_exec(); 13031500Serics char *s, *re_comp(); 13041500Serics 13051500Serics context.line = saveln = Currline; 13061500Serics context.chrctr = startline; 13071500Serics lncount = 0; 13081500Serics if ((s = re_comp (buf)) != 0) 13091500Serics error (s); 13101500Serics while (!feof (file)) { 13111500Serics line3 = line2; 13121500Serics line2 = line1; 13131500Serics line1 = Ftell (file); 13141500Serics rdline (file); 13151500Serics lncount++; 13161500Serics if ((rv = re_exec (Line)) == 1) 13171500Serics if (--n == 0) { 13181500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 13193455Sroot { 13203455Sroot pr ("\n"); 13213594Sroot if (clreol) 13223594Sroot cleareol (); 13233455Sroot pr("...skipping\n"); 13243455Sroot } 13251500Serics if (!no_intty) { 13261500Serics Currline -= (lncount >= 3 ? 3 : lncount); 13271500Serics Fseek (file, line3); 13283594Sroot if (noscroll) 13293594Sroot if (clreol) { 13303594Sroot home (); 13313594Sroot cleareol (); 133216582Sleres } 13333594Sroot else 13343594Sroot doclear (); 13351500Serics } 13361500Serics else { 13371500Serics kill_line (); 13383594Sroot if (noscroll) 13393594Sroot if (clreol) { 134016582Sleres home (); 13413594Sroot cleareol (); 134216582Sleres } 13433594Sroot else 13443594Sroot doclear (); 13451500Serics pr (Line); 13461500Serics putchar ('\n'); 13471500Serics } 13481500Serics break; 13491500Serics } 13501500Serics else if (rv == -1) 13511500Serics error ("Regular expression botch"); 13521500Serics } 13531500Serics if (feof (file)) { 13541500Serics if (!no_intty) { 135546188Sbostic /* file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 13561500Serics Currline = saveln; 13571500Serics Fseek (file, startline); 13581500Serics } 13591500Serics else { 13601500Serics pr ("\nPattern not found\n"); 13611500Serics end_it (); 13621500Serics } 13631500Serics error ("Pattern not found"); 13641500Serics } 13651500Serics } 13661500Serics 136732737Sbostic /*VARARGS2*/ 136832737Sbostic execute (filename, cmd, va_alist) 13691500Serics char *filename; 137032737Sbostic char *cmd; 137132737Sbostic va_dcl 13721500Serics { 13731500Serics int id; 137416710Sjak int n; 137532737Sbostic va_list argp; 13761500Serics 13771500Serics fflush (stdout); 13781500Serics reset_tty (); 137916710Sjak for (n = 10; (id = fork ()) < 0 && n > 0; n--) 13801500Serics sleep (5); 13811500Serics if (id == 0) { 138216710Sjak if (!isatty(0)) { 138316710Sjak close(0); 138416710Sjak open("/dev/tty", 0); 138516710Sjak } 138632737Sbostic va_start(argp); 138732737Sbostic execv (cmd, argp); 13881500Serics write (2, "exec failed\n", 12); 13891500Serics exit (1); 139033087Sbostic va_end(argp); /* balance {}'s for some UNIX's */ 13911500Serics } 139216710Sjak if (id > 0) { 139316710Sjak signal (SIGINT, SIG_IGN); 139416710Sjak signal (SIGQUIT, SIG_IGN); 139516710Sjak if (catch_susp) 139616710Sjak signal(SIGTSTP, SIG_DFL); 139716710Sjak while (wait(0) > 0); 139816710Sjak signal (SIGINT, end_it); 139916710Sjak signal (SIGQUIT, onquit); 140016710Sjak if (catch_susp) 140116710Sjak signal(SIGTSTP, onsusp); 140216710Sjak } else 140316710Sjak write(2, "can't fork\n", 11); 14041500Serics set_tty (); 14051500Serics pr ("------------------------\n"); 14061500Serics prompt (filename); 14071500Serics } 14081500Serics /* 14091500Serics ** Skip n lines in the file f 14101500Serics */ 14111500Serics 14121500Serics skiplns (n, f) 14131500Serics register int n; 14141500Serics register FILE *f; 14151500Serics { 14161500Serics register char c; 14171500Serics 14181500Serics while (n > 0) { 14191500Serics while ((c = Getc (f)) != '\n') 14201500Serics if (c == EOF) 14211500Serics return; 14221500Serics n--; 14231500Serics Currline++; 14241500Serics } 14251500Serics } 14261500Serics 14271500Serics /* 14281500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 14291500Serics ** negative. 14301500Serics */ 14311500Serics 14321500Serics skipf (nskip) 14331500Serics register int nskip; 14341500Serics { 14351500Serics if (nskip == 0) return; 14361500Serics if (nskip > 0) { 14371500Serics if (fnum + nskip > nfiles - 1) 14381500Serics nskip = nfiles - fnum - 1; 14391500Serics } 14401500Serics else if (within) 14411500Serics ++fnum; 14421500Serics fnum += nskip; 14431500Serics if (fnum < 0) 14441500Serics fnum = 0; 14453594Sroot pr ("\n...Skipping "); 14463455Sroot pr ("\n"); 14473594Sroot if (clreol) 14483594Sroot cleareol (); 14493455Sroot pr ("...Skipping "); 14501500Serics pr (nskip > 0 ? "to file " : "back to file "); 14511500Serics pr (fnames[fnum]); 14523455Sroot pr ("\n"); 14533594Sroot if (clreol) 14543594Sroot cleareol (); 14553455Sroot pr ("\n"); 14561500Serics --fnum; 14571500Serics } 14581500Serics 14591500Serics /*----------------------------- Terminal I/O -------------------------------*/ 14601500Serics 14611500Serics initterm () 14621500Serics { 14631500Serics char buf[TBUFSIZ]; 146417195Sralph static char clearbuf[TBUFSIZ]; 14651500Serics char *clearptr, *padstr; 14661500Serics int ldisc; 146717592Sleres int lmode; 146810823Ssam char *term; 146916582Sleres int tgrp; 147018030Sbloom struct winsize win; 14711500Serics 147216582Sleres retry: 147316582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 147417592Sleres if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { 147517592Sleres perror("TIOCLGET"); 147617592Sleres exit(1); 147717592Sleres } 147817592Sleres docrterase = ((lmode & LCRTERA) != 0); 147917592Sleres docrtkill = ((lmode & LCRTKIL) != 0); 148016582Sleres /* 148117592Sleres * Wait until we're in the foreground before we save the 148217592Sleres * the terminal modes. 148316582Sleres */ 148416582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 148517592Sleres perror("TIOCGPGRP"); 148616582Sleres exit(1); 148716582Sleres } 148816582Sleres if (tgrp != getpgrp(0)) { 148916582Sleres kill(0, SIGTTOU); 149016582Sleres goto retry; 149116582Sleres } 149213830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 14933594Sroot dumb++; ul_opt = 0; 14941500Serics } 14951500Serics else { 149618030Sbloom if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { 149718030Sbloom Lpp = tgetnum("li"); 149818030Sbloom Mcol = tgetnum("co"); 149918030Sbloom } else { 150018030Sbloom if ((Lpp = win.ws_row) == 0) 150118030Sbloom Lpp = tgetnum("li"); 150218030Sbloom if ((Mcol = win.ws_col) == 0) 150318030Sbloom Mcol = tgetnum("co"); 150418030Sbloom } 150518030Sbloom if ((Lpp <= 0) || tgetflag("hc")) { 15061500Serics hard++; /* Hard copy terminal */ 15071500Serics Lpp = 24; 15081500Serics } 150929907Smckusick if (tgetflag("xn")) 151029907Smckusick eatnl++; /* Eat newline at last column + 1; dec, concept */ 151118030Sbloom if (Mcol <= 0) 151218030Sbloom Mcol = 80; 151318030Sbloom 15141500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 15151500Serics noscroll++; 15161500Serics Wrap = tgetflag("am"); 15171500Serics bad_so = tgetflag ("xs"); 15181500Serics clearptr = clearbuf; 15191500Serics eraseln = tgetstr("ce",&clearptr); 15201500Serics Clear = tgetstr("cl", &clearptr); 15211500Serics Senter = tgetstr("so", &clearptr); 15221500Serics Sexit = tgetstr("se", &clearptr); 152316710Sjak if ((soglitch = tgetnum("sg")) < 0) 152416710Sjak soglitch = 0; 15253594Sroot 15263594Sroot /* 15273594Sroot * Set up for underlining: some terminals don't need it; 15283594Sroot * others have start/stop sequences, still others have an 15293594Sroot * underline char sequence which is assumed to move the 15303594Sroot * cursor forward one character. If underline sequence 15313594Sroot * isn't available, settle for standout sequence. 15323594Sroot */ 15333594Sroot 15343594Sroot if (tgetflag("ul") || tgetflag("os")) 15353594Sroot ul_opt = 0; 15363594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 15373594Sroot chUL = ""; 153816710Sjak if (((ULenter = tgetstr("us", &clearptr)) == NULL || 153916710Sjak (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 154016710Sjak if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 154116710Sjak ULenter = ""; 154216710Sjak ULexit = ""; 154316710Sjak } else 154416710Sjak ulglitch = soglitch; 154516710Sjak } else { 154616710Sjak if ((ulglitch = tgetnum("ug")) < 0) 154716710Sjak ulglitch = 0; 154816710Sjak } 154916582Sleres 15501500Serics if (padstr = tgetstr("pc", &clearptr)) 15511500Serics PC = *padstr; 15523455Sroot Home = tgetstr("ho",&clearptr); 155313536Ssam if (Home == 0 || *Home == '\0') 15543455Sroot { 15553594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 15563594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 15573455Sroot Home = cursorhome; 15583455Sroot } 15593455Sroot } 15603594Sroot EodClr = tgetstr("cd", &clearptr); 156125540Smckusick if ((chBS = tgetstr("bc", &clearptr)) == NULL) 156225540Smckusick chBS = "\b"; 156325540Smckusick 15641500Serics } 15651500Serics if ((shell = getenv("SHELL")) == NULL) 15661500Serics shell = "/bin/sh"; 15671500Serics } 156816582Sleres no_intty = gtty(fileno(stdin), &otty); 156916582Sleres gtty(fileno(stderr), &otty); 157013830Skre savetty = otty; 15711500Serics ospeed = otty.sg_ospeed; 15721500Serics slow_tty = ospeed < B1200; 157327006Sdonn hardtabs = (otty.sg_flags & TBDELAY) != XTABS; 15741500Serics if (!no_tty) { 15751500Serics otty.sg_flags &= ~ECHO; 15761500Serics if (MBIT == CBREAK || !slow_tty) 15771500Serics otty.sg_flags |= MBIT; 15781500Serics } 15791500Serics } 15801500Serics 15811500Serics readch () 15821500Serics { 15831500Serics char ch; 15841500Serics extern int errno; 15851500Serics 158631089Skarels errno = 0; 15871500Serics if (read (2, &ch, 1) <= 0) 15881500Serics if (errno != EINTR) 158931089Skarels end_it(); 15901500Serics else 15911500Serics ch = otty.sg_kill; 15921500Serics return (ch); 15931500Serics } 15941500Serics 15951500Serics static char BS = '\b'; 159617592Sleres static char *BSB = "\b \b"; 15971500Serics static char CARAT = '^'; 159817592Sleres #define ERASEONECHAR \ 159917592Sleres if (docrterase) \ 160017592Sleres write (2, BSB, sizeof(BSB)); \ 160117592Sleres else \ 160217592Sleres write (2, &BS, sizeof(BS)); 16031500Serics 16041500Serics ttyin (buf, nmax, pchar) 16051500Serics char buf[]; 16061500Serics register int nmax; 16071500Serics char pchar; 16081500Serics { 16091500Serics register char *sptr; 16101500Serics register char ch; 16111500Serics register int slash = 0; 16121500Serics int maxlen; 16131500Serics char cbuf; 16141500Serics 16151500Serics sptr = buf; 16161500Serics maxlen = 0; 16171500Serics while (sptr - buf < nmax) { 16181500Serics if (promptlen > maxlen) maxlen = promptlen; 16191500Serics ch = readch (); 16201500Serics if (ch == '\\') { 16211500Serics slash++; 16221500Serics } 16231500Serics else if ((ch == otty.sg_erase) && !slash) { 16241500Serics if (sptr > buf) { 16251500Serics --promptlen; 162617592Sleres ERASEONECHAR 16271500Serics --sptr; 16281500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 16291500Serics --promptlen; 163017592Sleres ERASEONECHAR 16311500Serics } 16321500Serics continue; 16331500Serics } 16341500Serics else { 16351500Serics if (!eraseln) promptlen = maxlen; 16361500Serics longjmp (restore, 1); 16371500Serics } 16381500Serics } 16391500Serics else if ((ch == otty.sg_kill) && !slash) { 16401500Serics if (hard) { 16411500Serics show (ch); 16421500Serics putchar ('\n'); 16431500Serics putchar (pchar); 16441500Serics } 16451500Serics else { 16461500Serics putchar ('\r'); 16471500Serics putchar (pchar); 16481500Serics if (eraseln) 16491500Serics erase (1); 165017592Sleres else if (docrtkill) 165117592Sleres while (promptlen-- > 1) 165217592Sleres write (2, BSB, sizeof(BSB)); 16531500Serics promptlen = 1; 16541500Serics } 16551500Serics sptr = buf; 16561500Serics fflush (stdout); 16571500Serics continue; 16581500Serics } 16591500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 166017592Sleres ERASEONECHAR 16611500Serics --sptr; 16621500Serics } 16631500Serics if (ch != '\\') 16641500Serics slash = 0; 16651500Serics *sptr++ = ch; 16661500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 16671500Serics ch += ch == RUBOUT ? -0100 : 0100; 16681500Serics write (2, &CARAT, 1); 16691500Serics promptlen++; 16701500Serics } 16711500Serics cbuf = ch; 16721500Serics if (ch != '\n' && ch != ESC) { 16731500Serics write (2, &cbuf, 1); 16741500Serics promptlen++; 16751500Serics } 16761500Serics else 16771500Serics break; 16781500Serics } 16791500Serics *--sptr = '\0'; 16801500Serics if (!eraseln) promptlen = maxlen; 16811500Serics if (sptr - buf >= nmax - 1) 16821500Serics error ("Line too long"); 16831500Serics } 16841500Serics 16851500Serics expand (outbuf, inbuf) 16861500Serics char *outbuf; 16871500Serics char *inbuf; 16881500Serics { 16891500Serics register char *instr; 16901500Serics register char *outstr; 16911500Serics register char ch; 16921500Serics char temp[200]; 16931500Serics int changed = 0; 16941500Serics 16951500Serics instr = inbuf; 16961500Serics outstr = temp; 16971500Serics while ((ch = *instr++) != '\0') 16981500Serics switch (ch) { 16991500Serics case '%': 17001500Serics if (!no_intty) { 17011500Serics strcpy (outstr, fnames[fnum]); 17021500Serics outstr += strlen (fnames[fnum]); 17031500Serics changed++; 17041500Serics } 17051500Serics else 17061500Serics *outstr++ = ch; 17071500Serics break; 17081500Serics case '!': 17091500Serics if (!shellp) 17101500Serics error ("No previous command to substitute for"); 17111500Serics strcpy (outstr, shell_line); 17121500Serics outstr += strlen (shell_line); 17131500Serics changed++; 17141500Serics break; 17151500Serics case '\\': 17161500Serics if (*instr == '%' || *instr == '!') { 17171500Serics *outstr++ = *instr++; 17181500Serics break; 17191500Serics } 17201500Serics default: 17211500Serics *outstr++ = ch; 17221500Serics } 17231500Serics *outstr++ = '\0'; 17241500Serics strcpy (outbuf, temp); 17251500Serics return (changed); 17261500Serics } 17271500Serics 17281500Serics show (ch) 17291500Serics register char ch; 17301500Serics { 17311500Serics char cbuf; 17321500Serics 17331500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 17341500Serics ch += ch == RUBOUT ? -0100 : 0100; 17351500Serics write (2, &CARAT, 1); 17361500Serics promptlen++; 17371500Serics } 17381500Serics cbuf = ch; 17391500Serics write (2, &cbuf, 1); 17401500Serics promptlen++; 17411500Serics } 17421500Serics 17431500Serics error (mess) 17441500Serics char *mess; 17451500Serics { 17463594Sroot if (clreol) 17473594Sroot cleareol (); 17483594Sroot else 17493594Sroot kill_line (); 17501500Serics promptlen += strlen (mess); 17511500Serics if (Senter && Sexit) { 17521500Serics tputs (Senter, 1, putch); 17531500Serics pr(mess); 17541500Serics tputs (Sexit, 1, putch); 17551500Serics } 17561500Serics else 17571500Serics pr (mess); 17581500Serics fflush(stdout); 17591500Serics errors++; 17601500Serics longjmp (restore, 1); 17611500Serics } 17621500Serics 17631500Serics 17641500Serics set_tty () 17651500Serics { 17661500Serics otty.sg_flags |= MBIT; 17671500Serics otty.sg_flags &= ~ECHO; 176816582Sleres stty(fileno(stderr), &otty); 17691500Serics } 17701500Serics 17711500Serics reset_tty () 17721500Serics { 177331033Sbostic if (no_tty) 177431033Sbostic return; 177516710Sjak if (pstate) { 177616710Sjak tputs(ULexit, 1, putch); 177716710Sjak fflush(stdout); 177816710Sjak pstate = 0; 177916710Sjak } 17801500Serics otty.sg_flags |= ECHO; 17811500Serics otty.sg_flags &= ~MBIT; 178216582Sleres stty(fileno(stderr), &savetty); 17831500Serics } 17841500Serics 17851500Serics rdline (f) 17861500Serics register FILE *f; 17871500Serics { 17881500Serics register char c; 17891500Serics register char *p; 17901500Serics 17911500Serics p = Line; 17921500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 17931500Serics *p++ = c; 17941500Serics if (c == '\n') 17951500Serics Currline++; 17961500Serics *p = '\0'; 17971500Serics } 17981500Serics 17991500Serics /* Come here when we get a suspend signal from the terminal */ 18001500Serics 180146779Sbostic void 18021500Serics onsusp () 18031500Serics { 180414861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 180514861Skarels signal(SIGTTOU, SIG_IGN); 18061500Serics reset_tty (); 18071500Serics fflush (stdout); 180814861Skarels signal(SIGTTOU, SIG_DFL); 18091500Serics /* Send the TSTP signal to suspend our process group */ 181013289Ssam signal(SIGTSTP, SIG_DFL); 181113289Ssam sigsetmask(0); 18121500Serics kill (0, SIGTSTP); 18131500Serics /* Pause for station break */ 18141500Serics 18151500Serics /* We're back */ 18161500Serics signal (SIGTSTP, onsusp); 18171500Serics set_tty (); 18181500Serics if (inwait) 181946779Sbostic longjmp (restore, 1); 18201500Serics } 1821