121981Sdist /* 221981Sdist * Copyright (c) 1980 Regents of the University of California. 332736Sbostic * All rights reserved. 432736Sbostic * 532736Sbostic * Redistribution and use in source and binary forms are permitted 632736Sbostic * provided that this notice is preserved and that due credit is given 732736Sbostic * to the University of California at Berkeley. The name of the University 832736Sbostic * may not be used to endorse or promote products derived from this 932736Sbostic * software without specific written prior permission. This software 1032736Sbostic * is provided ``as is'' without express or implied warranty. 1121981Sdist */ 1221981Sdist 1313615Ssam #ifndef lint 1421981Sdist char copyright[] = 1521981Sdist "@(#) Copyright (c) 1980 Regents of the University of California.\n\ 1621981Sdist All rights reserved.\n"; 1732736Sbostic #endif /* not lint */ 183594Sroot 1921981Sdist #ifndef lint 20*34104Sbostic static char sccsid[] = "@(#)more.c 5.18 (Berkeley) 04/25/88"; 2132736Sbostic #endif /* not lint */ 2221981Sdist 231500Serics /* 241500Serics ** more.c - General purpose tty output filter and file perusal program 251500Serics ** 261500Serics ** by Eric Shienbrood, UC Berkeley 273594Sroot ** 283594Sroot ** modified by Geoff Peck, UCB to add underlining, single spacing 293594Sroot ** modified by John Foderaro, UCB to add -c and MORE environment variable 301500Serics */ 311500Serics 321500Serics #include <stdio.h> 3332736Sbostic #include <sys/param.h> 341500Serics #include <ctype.h> 351500Serics #include <signal.h> 361500Serics #include <errno.h> 371500Serics #include <sgtty.h> 381500Serics #include <setjmp.h> 391500Serics #include <sys/stat.h> 4029906Smckusick #include <sys/file.h> 4132736Sbostic #include <a.out.h> 4232736Sbostic #include <varargs.h> 431500Serics 4413615Ssam #define HELPFILE "/usr/lib/more.help" 4513615Ssam #define VI "/usr/ucb/vi" 461500Serics 471500Serics #define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m)) 481500Serics #define Ftell(f) file_pos 491500Serics #define Fseek(f,off) (file_pos=off,fseek(f,off,0)) 501500Serics #define Getc(f) (++file_pos, getc(f)) 511500Serics #define Ungetc(c,f) (--file_pos, ungetc(c,f)) 521500Serics 531500Serics #define MBIT CBREAK 541500Serics #define stty(fd,argp) ioctl(fd,TIOCSETN,argp) 551500Serics 561500Serics #define TBUFSIZ 1024 571500Serics #define LINSIZ 256 5833232Sbostic #define ctrl(letter) (letter & 077) 591500Serics #define RUBOUT '\177' 601500Serics #define ESC '\033' 611500Serics #define QUIT '\034' 621500Serics 6316582Sleres struct sgttyb otty, savetty; 641500Serics long file_pos, file_size; 651500Serics int fnum, no_intty, no_tty, slow_tty; 6627006Sdonn int dum_opt, dlines, onquit(), end_it(), chgwinsz(); 671500Serics int onsusp(); 681500Serics int nscroll = 11; /* Number of lines scrolled by 'd' */ 691500Serics int fold_opt = 1; /* Fold long lines */ 701500Serics int stop_opt = 1; /* Stop after form feeds */ 713594Sroot int ssp_opt = 0; /* Suppress white space */ 723594Sroot int ul_opt = 1; /* Underline as best we can */ 731500Serics int promptlen; 741500Serics int Currline; /* Line we are currently at */ 751500Serics int startup = 1; 761500Serics int firstf = 1; 771500Serics int notell = 1; 7817592Sleres int docrterase = 0; 7917592Sleres int docrtkill = 0; 801500Serics int bad_so; /* True if overwriting does not turn off standout */ 811500Serics int inwait, Pause, errors; 821500Serics int within; /* true if we are within a file, 831500Serics false if we are between files */ 8429907Smckusick int hard, dumb, noscroll, hardtabs, clreol, eatnl; 851500Serics int catch_susp; /* We should catch the SIGTSTP signal */ 861500Serics char **fnames; /* The list of file names */ 871500Serics int nfiles; /* Number of files left to process */ 881500Serics char *shell; /* The name of the shell to use */ 891500Serics int shellp; /* A previous shell command exists */ 901500Serics char ch; 911500Serics jmp_buf restore; 921500Serics char Line[LINSIZ]; /* Line buffer */ 931500Serics int Lpp = 24; /* lines per page */ 941500Serics char *Clear; /* clear screen */ 951500Serics char *eraseln; /* erase line */ 961500Serics char *Senter, *Sexit;/* enter and exit standout mode */ 973594Sroot char *ULenter, *ULexit; /* enter and exit underline mode */ 983594Sroot char *chUL; /* underline character */ 993594Sroot char *chBS; /* backspace character */ 1003455Sroot char *Home; /* go to home */ 1013455Sroot char *cursorm; /* cursor movement */ 1023455Sroot char cursorhome[40]; /* contains cursor movement to home */ 1033594Sroot char *EodClr; /* clear rest of screen */ 1041500Serics char *tgetstr(); 1051500Serics int Mcol = 80; /* number of columns */ 1061500Serics int Wrap = 1; /* set if automargins */ 10716710Sjak int soglitch; /* terminal has standout mode glitch */ 10816710Sjak int ulglitch; /* terminal has underline mode glitch */ 10916710Sjak int pstate = 0; /* current UL state */ 1101500Serics long fseek(); 1113455Sroot char *getenv(); 1121500Serics struct { 1131500Serics long chrctr, line; 1141500Serics } context, screen_start; 1151500Serics extern char PC; /* pad character */ 1161500Serics extern short ospeed; 1171500Serics 1181500Serics 1191500Serics main(argc, argv) 1201500Serics int argc; 1211500Serics char *argv[]; 1221500Serics { 1231500Serics register FILE *f; 1241500Serics register char *s; 1251500Serics register char *p; 1261500Serics register char ch; 1271500Serics register int left; 12816582Sleres int prnames = 0; 1291500Serics int initopt = 0; 1301500Serics int srchopt = 0; 1311500Serics int clearit = 0; 1321500Serics int initline; 1331500Serics char initbuf[80]; 1341500Serics FILE *checkf(); 1351500Serics 1361500Serics nfiles = argc; 1371500Serics fnames = argv; 1381500Serics initterm (); 13915813Sralph nscroll = Lpp/2 - 1; 14015813Sralph if (nscroll <= 0) 14115813Sralph nscroll = 1; 1423455Sroot if(s = getenv("MORE")) argscan(s); 1431500Serics while (--nfiles > 0) { 1441500Serics if ((ch = (*++fnames)[0]) == '-') { 1453455Sroot argscan(*fnames+1); 1461500Serics } 1471500Serics else if (ch == '+') { 1481500Serics s = *fnames; 1491500Serics if (*++s == '/') { 1501500Serics srchopt++; 1511500Serics for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) 1521500Serics *p++ = *s++; 1531500Serics *p = '\0'; 1541500Serics } 1551500Serics else { 1561500Serics initopt++; 1571500Serics for (initline = 0; *s != '\0'; s++) 1581500Serics if (isdigit (*s)) 1591500Serics initline = initline*10 + *s -'0'; 1601500Serics --initline; 1611500Serics } 1621500Serics } 1631500Serics else break; 1641500Serics } 1653594Sroot /* allow clreol only if Home and eraseln and EodClr strings are 1663455Sroot * defined, and in that case, make sure we are in noscroll mode 1673455Sroot */ 1683455Sroot if(clreol) 1693455Sroot { 17018608Sralph if((Home == NULL) || (*Home == '\0') || 17118608Sralph (eraseln == NULL) || (*eraseln == '\0') || 17218608Sralph (EodClr == NULL) || (*EodClr == '\0') ) 17318608Sralph clreol = 0; 1743455Sroot else noscroll = 1; 1753455Sroot } 1761500Serics if (dlines == 0) 1771500Serics dlines = Lpp - (noscroll ? 1 : 2); 1781500Serics left = dlines; 1791500Serics if (nfiles > 1) 1801500Serics prnames++; 1811500Serics if (!no_intty && nfiles == 0) { 182*34104Sbostic char *rindex(); 183*34104Sbostic 184*34104Sbostic p = rindex(argv[0], '/'); 185*34104Sbostic fputs("usage: ",stderr); 186*34104Sbostic fputs(p ? p + 1 : argv[0],stderr); 1871500Serics fputs(" [-dfln] [+linenum | +/pattern] name1 name2 ...\n",stderr); 1881500Serics exit(1); 1891500Serics } 1901500Serics else 1911500Serics f = stdin; 1921500Serics if (!no_tty) { 1931500Serics signal(SIGQUIT, onquit); 1941500Serics signal(SIGINT, end_it); 19527006Sdonn signal(SIGWINCH, chgwinsz); 1961500Serics if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { 1971500Serics signal(SIGTSTP, onsusp); 1981500Serics catch_susp++; 1991500Serics } 20016582Sleres stty (fileno(stderr), &otty); 2011500Serics } 2021500Serics if (no_intty) { 2031500Serics if (no_tty) 2041500Serics copy_file (stdin); 2051500Serics else { 2061500Serics if ((ch = Getc (f)) == '\f') 2073594Sroot doclear(); 2081500Serics else { 2091500Serics Ungetc (ch, f); 2103594Sroot if (noscroll && (ch != EOF)) { 2113594Sroot if (clreol) 2123594Sroot home (); 2133594Sroot else 2143594Sroot doclear (); 2153455Sroot } 2161500Serics } 2171500Serics if (srchopt) 2183455Sroot { 2191500Serics search (initbuf, stdin, 1); 2203594Sroot if (noscroll) 2213594Sroot left--; 2223455Sroot } 2231500Serics else if (initopt) 2241500Serics skiplns (initline, stdin); 2251500Serics screen (stdin, left); 2261500Serics } 2271500Serics no_intty = 0; 2281500Serics prnames++; 2291500Serics firstf = 0; 2301500Serics } 2311500Serics 2321500Serics while (fnum < nfiles) { 2331500Serics if ((f = checkf (fnames[fnum], &clearit)) != NULL) { 2341500Serics context.line = context.chrctr = 0; 2351500Serics Currline = 0; 2361500Serics if (firstf) setjmp (restore); 2371500Serics if (firstf) { 2381500Serics firstf = 0; 2391500Serics if (srchopt) 2403455Sroot { 2411500Serics search (initbuf, f, 1); 2423594Sroot if (noscroll) 2433594Sroot left--; 2443455Sroot } 2451500Serics else if (initopt) 2461500Serics skiplns (initline, f); 2471500Serics } 2481500Serics else if (fnum < nfiles && !no_tty) { 2491500Serics setjmp (restore); 2501500Serics left = command (fnames[fnum], f); 2511500Serics } 2521500Serics if (left != 0) { 25332736Sbostic if ((noscroll || clearit) && (file_size != LONG_MAX)) 2543594Sroot if (clreol) 2553594Sroot home (); 2563594Sroot else 2573594Sroot doclear (); 2581500Serics if (prnames) { 2591500Serics if (bad_so) 2601500Serics erase (0); 2613594Sroot if (clreol) 2623594Sroot cleareol (); 2631500Serics pr("::::::::::::::"); 2641500Serics if (promptlen > 14) 2651500Serics erase (14); 2663455Sroot printf ("\n"); 2673455Sroot if(clreol) cleareol(); 2683455Sroot printf("%s\n", fnames[fnum]); 2693455Sroot if(clreol) cleareol(); 27030931Sbostic printf("::::::::::::::\n"); 2711500Serics if (left > Lpp - 4) 2721500Serics left = Lpp - 4; 2731500Serics } 2741500Serics if (no_tty) 2751500Serics copy_file (f); 2761500Serics else { 2771500Serics within++; 2781500Serics screen(f, left); 2791500Serics within = 0; 2801500Serics } 2811500Serics } 2821500Serics setjmp (restore); 2831500Serics fflush(stdout); 2841500Serics fclose(f); 2851500Serics screen_start.line = screen_start.chrctr = 0L; 2861500Serics context.line = context.chrctr = 0L; 2871500Serics } 2881500Serics fnum++; 2891500Serics firstf = 0; 2901500Serics } 2911500Serics reset_tty (); 2921500Serics exit(0); 2931500Serics } 2941500Serics 2953455Sroot argscan(s) 2963455Sroot char *s; 2973455Sroot { 29832273Sbostic int seen_num = 0; 29932273Sbostic 30032273Sbostic while (*s != '\0') { 30132273Sbostic switch (*s) { 30211604Slayer case '0': case '1': case '2': 30311604Slayer case '3': case '4': case '5': 30411604Slayer case '6': case '7': case '8': 30511604Slayer case '9': 30632273Sbostic if (!seen_num) { 30732273Sbostic dlines = 0; 30832273Sbostic seen_num = 1; 30932273Sbostic } 31011604Slayer dlines = dlines*10 + *s - '0'; 31111604Slayer break; 31211604Slayer case 'd': 31311604Slayer dum_opt = 1; 31411604Slayer break; 31511604Slayer case 'l': 31611604Slayer stop_opt = 0; 31711604Slayer break; 31811604Slayer case 'f': 31911604Slayer fold_opt = 0; 32011604Slayer break; 32111604Slayer case 'p': 32211604Slayer noscroll++; 32311604Slayer break; 32411604Slayer case 'c': 32511604Slayer clreol++; 32611604Slayer break; 32711604Slayer case 's': 32811604Slayer ssp_opt = 1; 32911604Slayer break; 33011604Slayer case 'u': 33111604Slayer ul_opt = 0; 33211604Slayer break; 33311604Slayer } 33432273Sbostic s++; 33511604Slayer } 3363455Sroot } 3373455Sroot 3383455Sroot 3391500Serics /* 3401500Serics ** Check whether the file named by fs is an ASCII file which the user may 3411500Serics ** access. If it is, return the opened file. Otherwise return NULL. 3421500Serics */ 3431500Serics 3441500Serics FILE * 3451500Serics checkf (fs, clearfirst) 34632736Sbostic register char *fs; 34732736Sbostic int *clearfirst; 3481500Serics { 34932736Sbostic struct stat stbuf; 35032736Sbostic register FILE *f; 35132736Sbostic char c; 3521500Serics 35332736Sbostic if (stat (fs, &stbuf) == -1) { 35432736Sbostic (void)fflush(stdout); 35532736Sbostic if (clreol) 35632736Sbostic cleareol (); 35732736Sbostic perror(fs); 35832736Sbostic return((FILE *)NULL); 35932736Sbostic } 36032736Sbostic if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { 36132736Sbostic printf("\n*** %s: directory ***\n\n", fs); 36232736Sbostic return((FILE *)NULL); 36332736Sbostic } 36432736Sbostic if ((f = Fopen(fs, "r")) == NULL) { 36532736Sbostic (void)fflush(stdout); 36632736Sbostic perror(fs); 36732736Sbostic return((FILE *)NULL); 36832736Sbostic } 36932736Sbostic if (magic(f, fs)) 37032736Sbostic return((FILE *)NULL); 37132736Sbostic c = Getc(f); 37232736Sbostic *clearfirst = c == '\f'; 3731500Serics Ungetc (c, f); 37432736Sbostic if ((file_size = stbuf.st_size) == 0) 37532736Sbostic file_size = LONG_MAX; 37632736Sbostic return(f); 3771500Serics } 3781500Serics 3791500Serics /* 38032736Sbostic * magic -- 38132736Sbostic * check for file magic numbers. This code would best be shared with 38232736Sbostic * the file(1) program or, perhaps, more should not try and be so smart? 38329906Smckusick */ 38432736Sbostic static 38532736Sbostic magic(f, fs) 38632736Sbostic FILE *f; 38732736Sbostic char *fs; 38829906Smckusick { 38932736Sbostic struct exec ex; 39029906Smckusick 39132736Sbostic if (fread(&ex, sizeof(ex), 1, f) == 1) 39232736Sbostic switch(ex.a_magic) { 39332736Sbostic case OMAGIC: 39432736Sbostic case NMAGIC: 39532736Sbostic case ZMAGIC: 39632736Sbostic case 0405: 39732736Sbostic case 0411: 39832736Sbostic case 0177545: 39932736Sbostic printf("\n******** %s: Not a text file ********\n\n", fs); 40032736Sbostic (void)fclose(f); 40132736Sbostic return(1); 40232736Sbostic } 40332736Sbostic (void)fseek(f, 0L, L_SET); /* rewind() not necessary */ 40433087Sbostic return(0); 40529906Smckusick } 40629906Smckusick 40729906Smckusick /* 4081500Serics ** A real function, for the tputs routine in termlib 4091500Serics */ 4101500Serics 4111500Serics putch (ch) 4121500Serics char ch; 4131500Serics { 4141500Serics putchar (ch); 4151500Serics } 4161500Serics 4171500Serics /* 4181500Serics ** Print out the contents of the file f, one screenful at a time. 4191500Serics */ 4201500Serics 4211500Serics #define STOP -10 4221500Serics 4231500Serics screen (f, num_lines) 4241500Serics register FILE *f; 4251500Serics register int num_lines; 4261500Serics { 4271500Serics register int c; 4281500Serics register int nchars; 4293594Sroot int length; /* length of current line */ 4303594Sroot static int prev_len = 1; /* length of previous line */ 4311500Serics 4321500Serics for (;;) { 4331500Serics while (num_lines > 0 && !Pause) { 4341500Serics if ((nchars = getline (f, &length)) == EOF) 4353455Sroot { 4363594Sroot if (clreol) 4373594Sroot clreos(); 4381500Serics return; 4393455Sroot } 4403594Sroot if (ssp_opt && length == 0 && prev_len == 0) 4413594Sroot continue; 4423594Sroot prev_len = length; 4431500Serics if (bad_so || (Senter && *Senter == ' ') && promptlen > 0) 4441500Serics erase (0); 4453594Sroot /* must clear before drawing line since tabs on some terminals 4463594Sroot * do not erase what they tab over. 4473594Sroot */ 4483594Sroot if (clreol) 4493594Sroot cleareol (); 4501500Serics prbuf (Line, length); 4511500Serics if (nchars < promptlen) 4521500Serics erase (nchars); /* erase () sets promptlen to 0 */ 4531500Serics else promptlen = 0; 4543594Sroot /* is this needed? 4553594Sroot * if (clreol) 4563594Sroot * cleareol(); /* must clear again in case we wrapped * 4573594Sroot */ 4581500Serics if (nchars < Mcol || !fold_opt) 45916710Sjak prbuf("\n", 1); /* will turn off UL if necessary */ 4601500Serics if (nchars == STOP) 4611500Serics break; 4621500Serics num_lines--; 4631500Serics } 46416710Sjak if (pstate) { 46516710Sjak tputs(ULexit, 1, putch); 46616710Sjak pstate = 0; 46716710Sjak } 4681500Serics fflush(stdout); 4691500Serics if ((c = Getc(f)) == EOF) 4703455Sroot { 4713594Sroot if (clreol) 4723594Sroot clreos (); 4731500Serics return; 4743455Sroot } 4753455Sroot 4763594Sroot if (Pause && clreol) 4773594Sroot clreos (); 4781500Serics Ungetc (c, f); 4791500Serics setjmp (restore); 4801500Serics Pause = 0; startup = 0; 4811500Serics if ((num_lines = command (NULL, f)) == 0) 4821500Serics return; 4831500Serics if (hard && promptlen > 0) 4841500Serics erase (0); 48511123Slayer if (noscroll && num_lines >= dlines) 48616582Sleres { 4873594Sroot if (clreol) 4883594Sroot home(); 4893594Sroot else 4903594Sroot doclear (); 4913455Sroot } 4921500Serics screen_start.line = Currline; 4931500Serics screen_start.chrctr = Ftell (f); 4941500Serics } 4951500Serics } 4961500Serics 4971500Serics /* 4981500Serics ** Come here if a quit signal is received 4991500Serics */ 5001500Serics 5011500Serics onquit() 5021500Serics { 5031500Serics signal(SIGQUIT, SIG_IGN); 5041500Serics if (!inwait) { 5051500Serics putchar ('\n'); 5061500Serics if (!startup) { 5071500Serics signal(SIGQUIT, onquit); 5081500Serics longjmp (restore, 1); 5091500Serics } 5101500Serics else 5111500Serics Pause++; 5121500Serics } 5131500Serics else if (!dum_opt && notell) { 5141500Serics write (2, "[Use q or Q to quit]", 20); 5151500Serics promptlen += 20; 5161500Serics notell = 0; 5171500Serics } 5181500Serics signal(SIGQUIT, onquit); 5191500Serics } 5201500Serics 5211500Serics /* 52227006Sdonn ** Come here if a signal for a window size change is received 52327006Sdonn */ 52427006Sdonn 52527006Sdonn chgwinsz() 52627006Sdonn { 52727006Sdonn struct winsize win; 52827006Sdonn 52927006Sdonn (void) signal(SIGWINCH, SIG_IGN); 53027006Sdonn if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { 53127006Sdonn if (win.ws_row != 0) { 53227006Sdonn Lpp = win.ws_row; 53327006Sdonn nscroll = Lpp/2 - 1; 53427006Sdonn if (nscroll <= 0) 53527006Sdonn nscroll = 1; 53627006Sdonn dlines = Lpp - (noscroll ? 1 : 2); 53727006Sdonn } 53827006Sdonn if (win.ws_col != 0) 53927006Sdonn Mcol = win.ws_col; 54027006Sdonn } 54127006Sdonn (void) signal(SIGWINCH, chgwinsz); 54227006Sdonn } 54327006Sdonn 54427006Sdonn /* 5451500Serics ** Clean up terminal state and exit. Also come here if interrupt signal received 5461500Serics */ 5471500Serics 5481500Serics end_it () 5491500Serics { 5501500Serics 5511500Serics reset_tty (); 5523594Sroot if (clreol) { 5533594Sroot putchar ('\r'); 5543594Sroot clreos (); 5553594Sroot fflush (stdout); 5563594Sroot } 5573455Sroot else if (!clreol && (promptlen > 0)) { 5581500Serics kill_line (); 5591500Serics fflush (stdout); 5601500Serics } 5611500Serics else 5621500Serics write (2, "\n", 1); 5631500Serics _exit(0); 5641500Serics } 5651500Serics 5661500Serics copy_file(f) 5671500Serics register FILE *f; 5681500Serics { 5691500Serics register int c; 5701500Serics 5711500Serics while ((c = getc(f)) != EOF) 5721500Serics putchar(c); 5731500Serics } 5741500Serics 5751500Serics /* Simplified printf function */ 5761500Serics 57732737Sbostic printf (fmt, va_alist) 5781500Serics register char *fmt; 57932737Sbostic va_dcl 5801500Serics { 58132737Sbostic va_list ap; 5821500Serics register char ch; 5831500Serics register int ccount; 5841500Serics 5851500Serics ccount = 0; 58632737Sbostic va_start(ap); 5871500Serics while (*fmt) { 5881500Serics while ((ch = *fmt++) != '%') { 5891500Serics if (ch == '\0') 5901500Serics return (ccount); 5911500Serics ccount++; 5921500Serics putchar (ch); 5931500Serics } 5941500Serics switch (*fmt++) { 5951500Serics case 'd': 59632737Sbostic ccount += printd (va_arg(ap, int)); 5971500Serics break; 5981500Serics case 's': 59932737Sbostic ccount += pr (va_arg(ap, char *)); 6001500Serics break; 6011500Serics case '%': 6021500Serics ccount++; 6031500Serics putchar ('%'); 6041500Serics break; 6051500Serics case '0': 6061500Serics return (ccount); 6071500Serics default: 6081500Serics break; 6091500Serics } 6101500Serics } 61132737Sbostic va_end(ap); 6121500Serics return (ccount); 6131500Serics 6141500Serics } 6151500Serics 6161500Serics /* 6171500Serics ** Print an integer as a string of decimal digits, 6181500Serics ** returning the length of the print representation. 6191500Serics */ 6201500Serics 6211500Serics printd (n) 6221500Serics int n; 6231500Serics { 6241500Serics int a, nchars; 6251500Serics 6261500Serics if (a = n/10) 6271500Serics nchars = 1 + printd(a); 6281500Serics else 6291500Serics nchars = 1; 6301500Serics putchar (n % 10 + '0'); 6311500Serics return (nchars); 6321500Serics } 6331500Serics 6341500Serics /* Put the print representation of an integer into a string */ 6351500Serics static char *sptr; 6361500Serics 6371500Serics scanstr (n, str) 6381500Serics int n; 6391500Serics char *str; 6401500Serics { 6411500Serics sptr = str; 64211604Slayer Sprintf (n); 6431500Serics *sptr = '\0'; 6441500Serics } 6451500Serics 64611604Slayer Sprintf (n) 6471500Serics { 6481500Serics int a; 6491500Serics 6501500Serics if (a = n/10) 65111604Slayer Sprintf (a); 6521500Serics *sptr++ = n % 10 + '0'; 6531500Serics } 6541500Serics 65533232Sbostic static char bell = ctrl('G'); 6561500Serics 6571500Serics strlen (s) 6581500Serics char *s; 6591500Serics { 6601500Serics register char *p; 6611500Serics 6621500Serics p = s; 6631500Serics while (*p++) 6641500Serics ; 6651500Serics return (p - s - 1); 6661500Serics } 6671500Serics 6681500Serics /* See whether the last component of the path name "path" is equal to the 6691500Serics ** string "string" 6701500Serics */ 6711500Serics 6721500Serics tailequ (path, string) 6731500Serics char *path; 6741500Serics register char *string; 6751500Serics { 6761500Serics register char *tail; 6771500Serics 6781500Serics tail = path + strlen(path); 6791500Serics while (tail >= path) 6801500Serics if (*(--tail) == '/') 6811500Serics break; 6821500Serics ++tail; 6831500Serics while (*tail++ == *string++) 6841500Serics if (*tail == '\0') 6851500Serics return(1); 6861500Serics return(0); 6871500Serics } 6881500Serics 6891500Serics prompt (filename) 6901500Serics char *filename; 6911500Serics { 6923594Sroot if (clreol) 6933594Sroot cleareol (); 6943455Sroot else if (promptlen > 0) 6951500Serics kill_line (); 6961500Serics if (!hard) { 6971500Serics promptlen = 8; 69816710Sjak if (Senter && Sexit) { 6991500Serics tputs (Senter, 1, putch); 70016710Sjak promptlen += (2 * soglitch); 70116710Sjak } 7023594Sroot if (clreol) 7033594Sroot cleareol (); 7041500Serics pr("--More--"); 7051500Serics if (filename != NULL) { 7061500Serics promptlen += printf ("(Next file: %s)", filename); 7071500Serics } 7081500Serics else if (!no_intty) { 7091500Serics promptlen += printf ("(%d%%)", (int)((file_pos * 100) / file_size)); 7101500Serics } 7111500Serics if (dum_opt) { 71216710Sjak promptlen += pr("[Press space to continue, 'q' to quit.]"); 7131500Serics } 7141500Serics if (Senter && Sexit) 7151500Serics tputs (Sexit, 1, putch); 7163594Sroot if (clreol) 7173594Sroot clreos (); 7181500Serics fflush(stdout); 7191500Serics } 7201500Serics else 7211500Serics write (2, &bell, 1); 7221500Serics inwait++; 7231500Serics } 7241500Serics 7251500Serics /* 7261500Serics ** Get a logical line 7271500Serics */ 7281500Serics 7291500Serics getline(f, length) 7301500Serics register FILE *f; 7311500Serics int *length; 7321500Serics { 7331500Serics register int c; 7341500Serics register char *p; 7351500Serics register int column; 7361500Serics static int colflg; 7371500Serics 7381500Serics p = Line; 7391500Serics column = 0; 7401500Serics c = Getc (f); 7411500Serics if (colflg && c == '\n') { 7421500Serics Currline++; 7431500Serics c = Getc (f); 7441500Serics } 7451500Serics while (p < &Line[LINSIZ - 1]) { 7461500Serics if (c == EOF) { 7471500Serics if (p > Line) { 7481500Serics *p = '\0'; 7491500Serics *length = p - Line; 7501500Serics return (column); 7511500Serics } 7521500Serics *length = p - Line; 7531500Serics return (EOF); 7541500Serics } 7551500Serics if (c == '\n') { 7561500Serics Currline++; 7571500Serics break; 7581500Serics } 7591500Serics *p++ = c; 7601500Serics if (c == '\t') 76129907Smckusick if (!hardtabs || column < promptlen && !hard) { 76229907Smckusick if (hardtabs && eraseln && !dumb) { 7631500Serics column = 1 + (column | 7); 7641500Serics tputs (eraseln, 1, putch); 7651500Serics promptlen = 0; 7661500Serics } 7671500Serics else { 76829907Smckusick for (--p; p < &Line[LINSIZ - 1];) { 7691500Serics *p++ = ' '; 77029907Smckusick if ((++column & 7) == 0) 77129907Smckusick break; 7721500Serics } 7731500Serics if (column >= promptlen) promptlen = 0; 7741500Serics } 7751500Serics } 7761500Serics else 7771500Serics column = 1 + (column | 7); 7789627Ssklower else if (c == '\b' && column > 0) 7791500Serics column--; 7801500Serics else if (c == '\r') 7811500Serics column = 0; 7821500Serics else if (c == '\f' && stop_opt) { 7831500Serics p[-1] = '^'; 7841500Serics *p++ = 'L'; 7851500Serics column += 2; 7861500Serics Pause++; 7871500Serics } 7881500Serics else if (c == EOF) { 7891500Serics *length = p - Line; 7901500Serics return (column); 7911500Serics } 7921500Serics else if (c >= ' ' && c != RUBOUT) 7931500Serics column++; 7941500Serics if (column >= Mcol && fold_opt) break; 7951500Serics c = Getc (f); 7961500Serics } 7971500Serics if (column >= Mcol && Mcol > 0) { 7981500Serics if (!Wrap) { 7991500Serics *p++ = '\n'; 8001500Serics } 8011500Serics } 8021500Serics colflg = column == Mcol && fold_opt; 80329907Smckusick if (colflg && eatnl && Wrap) { 80429907Smckusick *p++ = '\n'; /* simulate normal wrap */ 80529907Smckusick } 8061500Serics *length = p - Line; 8071500Serics *p = 0; 8081500Serics return (column); 8091500Serics } 8101500Serics 8111500Serics /* 8121500Serics ** Erase the rest of the prompt, assuming we are starting at column col. 8131500Serics */ 8141500Serics 8151500Serics erase (col) 8161500Serics register int col; 8171500Serics { 8181500Serics 8191500Serics if (promptlen == 0) 8201500Serics return; 8211500Serics if (hard) { 8221500Serics putchar ('\n'); 8231500Serics } 8241500Serics else { 8251500Serics if (col == 0) 8261500Serics putchar ('\r'); 8271500Serics if (!dumb && eraseln) 8281500Serics tputs (eraseln, 1, putch); 8291500Serics else 8301500Serics for (col = promptlen - col; col > 0; col--) 8311500Serics putchar (' '); 8321500Serics } 8331500Serics promptlen = 0; 8341500Serics } 8351500Serics 8361500Serics /* 8371500Serics ** Erase the current line entirely 8381500Serics */ 8391500Serics 8401500Serics kill_line () 8411500Serics { 8421500Serics erase (0); 8431500Serics if (!eraseln || dumb) putchar ('\r'); 8441500Serics } 8451500Serics 8461500Serics /* 8473455Sroot * force clear to end of line 8483455Sroot */ 8493455Sroot cleareol() 8503455Sroot { 8513594Sroot tputs(eraseln, 1, putch); 8523455Sroot } 8533455Sroot 8543594Sroot clreos() 8553455Sroot { 8563594Sroot tputs(EodClr, 1, putch); 8573455Sroot } 8583455Sroot 8593455Sroot /* 8601500Serics ** Print string and return number of characters 8611500Serics */ 8621500Serics 8631500Serics pr(s1) 8641500Serics char *s1; 8651500Serics { 8661500Serics register char *s; 8671500Serics register char c; 8681500Serics 8691500Serics for (s = s1; c = *s++; ) 8701500Serics putchar(c); 8711500Serics return (s - s1 - 1); 8721500Serics } 8731500Serics 8741500Serics 8751500Serics /* Print a buffer of n characters */ 8761500Serics 8771500Serics prbuf (s, n) 8781500Serics register char *s; 8791500Serics register int n; 8801500Serics { 88116710Sjak register char c; /* next output character */ 8823594Sroot register int state; /* next output char's UL state */ 88316710Sjak #define wouldul(s,n) ((n) >= 2 && (((s)[0] == '_' && (s)[1] == '\b') || ((s)[1] == '\b' && (s)[2] == '_'))) 8843594Sroot 8853594Sroot while (--n >= 0) 8863594Sroot if (!ul_opt) 8873594Sroot putchar (*s++); 8883594Sroot else { 88916710Sjak if (*s == ' ' && pstate == 0 && ulglitch && wouldul(s+1, n-1)) { 89016710Sjak s++; 89116710Sjak continue; 89216710Sjak } 89316710Sjak if (state = wouldul(s, n)) { 89416710Sjak c = (*s == '_')? s[2] : *s ; 8953594Sroot n -= 2; 89616710Sjak s += 3; 89716710Sjak } else 8983594Sroot c = *s++; 89916710Sjak if (state != pstate) { 90016710Sjak if (c == ' ' && state == 0 && ulglitch && wouldul(s, n-1)) 90116710Sjak state = 1; 90216710Sjak else 90316710Sjak tputs(state ? ULenter : ULexit, 1, putch); 9043594Sroot } 90516710Sjak if (c != ' ' || pstate == 0 || state != 0 || ulglitch == 0) 90616710Sjak putchar(c); 9073594Sroot if (state && *chUL) { 9083594Sroot pr(chBS); 9093594Sroot tputs(chUL, 1, putch); 9103594Sroot } 91116710Sjak pstate = state; 9123594Sroot } 9131500Serics } 9141500Serics 9151500Serics /* 9161500Serics ** Clear the screen 9171500Serics */ 9181500Serics 9191500Serics doclear() 9201500Serics { 9211500Serics if (Clear && !hard) { 9221500Serics tputs(Clear, 1, putch); 9231500Serics 9241500Serics /* Put out carriage return so that system doesn't 9251500Serics ** get confused by escape sequences when expanding tabs 9261500Serics */ 9271500Serics putchar ('\r'); 9281500Serics promptlen = 0; 9291500Serics } 9301500Serics } 9311500Serics 9323455Sroot /* 9333455Sroot * Go to home position 9343455Sroot */ 9353455Sroot home() 9363455Sroot { 9373455Sroot tputs(Home,1,putch); 9383455Sroot } 9393455Sroot 9401500Serics static int lastcmd, lastarg, lastp; 9411500Serics static int lastcolon; 9421500Serics char shell_line[132]; 9431500Serics 9441500Serics /* 9451500Serics ** Read a command and do it. A command consists of an optional integer 9461500Serics ** argument followed by the command character. Return the number of lines 9471500Serics ** to display in the next screenful. If there is nothing more to display 9481500Serics ** in the current file, zero is returned. 9491500Serics */ 9501500Serics 9511500Serics command (filename, f) 9521500Serics char *filename; 9531500Serics register FILE *f; 9541500Serics { 9551500Serics register int nlines; 9561500Serics register int retval; 9571500Serics register char c; 9581500Serics char colonch; 9591500Serics FILE *helpf; 9601500Serics int done; 9611500Serics char comchar, cmdbuf[80], *p; 9621500Serics 9631500Serics #define ret(val) retval=val;done++;break 9641500Serics 9651500Serics done = 0; 9661500Serics if (!errors) 9671500Serics prompt (filename); 9681500Serics else 9691500Serics errors = 0; 9701500Serics if (MBIT == RAW && slow_tty) { 9711500Serics otty.sg_flags |= MBIT; 97216582Sleres stty(fileno(stderr), &otty); 9731500Serics } 9741500Serics for (;;) { 9751500Serics nlines = number (&comchar); 9761500Serics lastp = colonch = 0; 9771500Serics if (comchar == '.') { /* Repeat last command */ 9781500Serics lastp++; 9791500Serics comchar = lastcmd; 9801500Serics nlines = lastarg; 9811500Serics if (lastcmd == ':') 9821500Serics colonch = lastcolon; 9831500Serics } 9841500Serics lastcmd = comchar; 9851500Serics lastarg = nlines; 9861500Serics if (comchar == otty.sg_erase) { 9871500Serics kill_line (); 9881500Serics prompt (filename); 9891500Serics continue; 9901500Serics } 9911500Serics switch (comchar) { 9921500Serics case ':': 9931500Serics retval = colon (filename, colonch, nlines); 9941500Serics if (retval >= 0) 9951500Serics done++; 9961500Serics break; 99724490Sbloom case 'b': 99833232Sbostic case ctrl('B'): 99924490Sbloom { 100024490Sbloom register int initline; 100124490Sbloom 100224490Sbloom if (no_intty) { 100324490Sbloom write(2, &bell, 1); 100424490Sbloom return (-1); 100524490Sbloom } 100624490Sbloom 100724490Sbloom if (nlines == 0) nlines++; 100824490Sbloom 100924490Sbloom putchar ('\r'); 101024490Sbloom erase (0); 101124490Sbloom printf ("\n"); 101224490Sbloom if (clreol) 101324490Sbloom cleareol (); 101424490Sbloom printf ("...back %d page", nlines); 101524490Sbloom if (nlines > 1) 101624490Sbloom pr ("s\n"); 101724490Sbloom else 101824490Sbloom pr ("\n"); 101924490Sbloom 102024490Sbloom if (clreol) 102124490Sbloom cleareol (); 102224490Sbloom pr ("\n"); 102324490Sbloom 102424490Sbloom initline = Currline - dlines * (nlines + 1); 102524490Sbloom if (! noscroll) 102624490Sbloom --initline; 102724490Sbloom if (initline < 0) initline = 0; 102824490Sbloom Fseek(f, 0L); 102924490Sbloom Currline = 0; /* skiplns() will make Currline correct */ 103024490Sbloom skiplns(initline, f); 103124490Sbloom if (! noscroll) { 103224490Sbloom ret(dlines + 1); 103324490Sbloom } 103424490Sbloom else { 103524490Sbloom ret(dlines); 103624490Sbloom } 103724490Sbloom } 10381500Serics case ' ': 10391500Serics case 'z': 10401500Serics if (nlines == 0) nlines = dlines; 10411500Serics else if (comchar == 'z') dlines = nlines; 10421500Serics ret (nlines); 10431500Serics case 'd': 104433232Sbostic case ctrl('D'): 10451500Serics if (nlines != 0) nscroll = nlines; 10461500Serics ret (nscroll); 10471500Serics case 'q': 10481500Serics case 'Q': 10491500Serics end_it (); 10501500Serics case 's': 10511500Serics case 'f': 10521500Serics if (nlines == 0) nlines++; 10531500Serics if (comchar == 'f') 10541500Serics nlines *= dlines; 10551500Serics putchar ('\r'); 10561500Serics erase (0); 10573594Sroot printf ("\n"); 10583594Sroot if (clreol) 10593594Sroot cleareol (); 10603594Sroot printf ("...skipping %d line", nlines); 10611500Serics if (nlines > 1) 10623594Sroot pr ("s\n"); 10631500Serics else 10643594Sroot pr ("\n"); 10653594Sroot 10663594Sroot if (clreol) 10673594Sroot cleareol (); 10683594Sroot pr ("\n"); 10693594Sroot 10701500Serics while (nlines > 0) { 10711500Serics while ((c = Getc (f)) != '\n') 10721500Serics if (c == EOF) { 10731500Serics retval = 0; 10741500Serics done++; 10751500Serics goto endsw; 10761500Serics } 10771500Serics Currline++; 10781500Serics nlines--; 10791500Serics } 10801500Serics ret (dlines); 10811500Serics case '\n': 10821500Serics if (nlines != 0) 10831500Serics dlines = nlines; 10841500Serics else 10851500Serics nlines = 1; 10861500Serics ret (nlines); 10871500Serics case '\f': 10881500Serics if (!no_intty) { 10891500Serics doclear (); 10901500Serics Fseek (f, screen_start.chrctr); 10911500Serics Currline = screen_start.line; 10921500Serics ret (dlines); 10931500Serics } 10941500Serics else { 10951500Serics write (2, &bell, 1); 10961500Serics break; 10971500Serics } 10981500Serics case '\'': 10991500Serics if (!no_intty) { 11001500Serics kill_line (); 11011500Serics pr ("\n***Back***\n\n"); 11021500Serics Fseek (f, context.chrctr); 11031500Serics Currline = context.line; 11041500Serics ret (dlines); 11051500Serics } 11061500Serics else { 11071500Serics write (2, &bell, 1); 11081500Serics break; 11091500Serics } 11101500Serics case '=': 11111500Serics kill_line (); 11121500Serics promptlen = printd (Currline); 11131500Serics fflush (stdout); 11141500Serics break; 11151500Serics case 'n': 11161500Serics lastp++; 11171500Serics case '/': 11181500Serics if (nlines == 0) nlines++; 11191500Serics kill_line (); 11201500Serics pr ("/"); 11211500Serics promptlen = 1; 11221500Serics fflush (stdout); 11231500Serics if (lastp) { 11241500Serics write (2,"\r", 1); 11251500Serics search (NULL, f, nlines); /* Use previous r.e. */ 11261500Serics } 11271500Serics else { 11281500Serics ttyin (cmdbuf, 78, '/'); 11291500Serics write (2, "\r", 1); 11301500Serics search (cmdbuf, f, nlines); 11311500Serics } 11323455Sroot ret (dlines-1); 11331500Serics case '!': 11341500Serics do_shell (filename); 11351500Serics break; 113624490Sbloom case '?': 11371500Serics case 'h': 11381500Serics if ((helpf = fopen (HELPFILE, "r")) == NULL) 11391500Serics error ("Can't open help file"); 11401500Serics if (noscroll) doclear (); 11411500Serics copy_file (helpf); 114227006Sdonn fclose (helpf); 11431500Serics prompt (filename); 11441500Serics break; 11451500Serics case 'v': /* This case should go right before default */ 11461500Serics if (!no_intty) { 11471500Serics kill_line (); 11481500Serics cmdbuf[0] = '+'; 114924490Sbloom scanstr (Currline - dlines < 0 ? 0 115024490Sbloom : Currline - (dlines + 1) / 2, &cmdbuf[1]); 11511500Serics pr ("vi "); pr (cmdbuf); putchar (' '); pr (fnames[fnum]); 11521500Serics execute (filename, VI, "vi", cmdbuf, fnames[fnum], 0); 11531500Serics break; 11541500Serics } 11551500Serics default: 115616710Sjak if (dum_opt) { 115716710Sjak kill_line (); 115816710Sjak if (Senter && Sexit) { 115916710Sjak tputs (Senter, 1, putch); 116016710Sjak promptlen = pr ("[Press 'h' for instructions.]") + (2 * soglitch); 116116710Sjak tputs (Sexit, 1, putch); 116216710Sjak } 116316710Sjak else 116416710Sjak promptlen = pr ("[Press 'h' for instructions.]"); 116516710Sjak fflush (stdout); 116616710Sjak } 116716710Sjak else 116816710Sjak write (2, &bell, 1); 11691500Serics break; 11701500Serics } 11711500Serics if (done) break; 11721500Serics } 11731500Serics putchar ('\r'); 11741500Serics endsw: 11751500Serics inwait = 0; 11761500Serics notell++; 11771500Serics if (MBIT == RAW && slow_tty) { 11781500Serics otty.sg_flags &= ~MBIT; 117916582Sleres stty(fileno(stderr), &otty); 11801500Serics } 11811500Serics return (retval); 11821500Serics } 11831500Serics 11841500Serics char ch; 11851500Serics 11861500Serics /* 11871500Serics * Execute a colon-prefixed command. 11881500Serics * Returns <0 if not a command that should cause 11891500Serics * more of the file to be printed. 11901500Serics */ 11911500Serics 11921500Serics colon (filename, cmd, nlines) 11931500Serics char *filename; 11941500Serics int cmd; 11951500Serics int nlines; 11961500Serics { 11971500Serics if (cmd == 0) 11981500Serics ch = readch (); 11991500Serics else 12001500Serics ch = cmd; 12011500Serics lastcolon = ch; 12021500Serics switch (ch) { 12031500Serics case 'f': 12041500Serics kill_line (); 12051500Serics if (!no_intty) 12061500Serics promptlen = printf ("\"%s\" line %d", fnames[fnum], Currline); 12071500Serics else 12081500Serics promptlen = printf ("[Not a file] line %d", Currline); 12091500Serics fflush (stdout); 12101500Serics return (-1); 12111500Serics case 'n': 12121500Serics if (nlines == 0) { 12131500Serics if (fnum >= nfiles - 1) 12141500Serics end_it (); 12151500Serics nlines++; 12161500Serics } 12171500Serics putchar ('\r'); 12181500Serics erase (0); 12191500Serics skipf (nlines); 12201500Serics return (0); 12211500Serics case 'p': 12221500Serics if (no_intty) { 12231500Serics write (2, &bell, 1); 12241500Serics return (-1); 12251500Serics } 12261500Serics putchar ('\r'); 12271500Serics erase (0); 12281500Serics if (nlines == 0) 12291500Serics nlines++; 12301500Serics skipf (-nlines); 12311500Serics return (0); 12321500Serics case '!': 12331500Serics do_shell (filename); 12341500Serics return (-1); 12351500Serics case 'q': 12361500Serics case 'Q': 12371500Serics end_it (); 12381500Serics default: 12391500Serics write (2, &bell, 1); 12401500Serics return (-1); 12411500Serics } 12421500Serics } 12431500Serics 12441500Serics /* 12451500Serics ** Read a decimal number from the terminal. Set cmd to the non-digit which 12461500Serics ** terminates the number. 12471500Serics */ 12481500Serics 12491500Serics number(cmd) 12501500Serics char *cmd; 12511500Serics { 12521500Serics register int i; 12531500Serics 12541500Serics i = 0; ch = otty.sg_kill; 12551500Serics for (;;) { 12561500Serics ch = readch (); 12571500Serics if (ch >= '0' && ch <= '9') 12581500Serics i = i*10 + ch - '0'; 12591500Serics else if (ch == otty.sg_kill) 12601500Serics i = 0; 12611500Serics else { 12621500Serics *cmd = ch; 12631500Serics break; 12641500Serics } 12651500Serics } 12661500Serics return (i); 12671500Serics } 12681500Serics 12691500Serics do_shell (filename) 12701500Serics char *filename; 12711500Serics { 12721500Serics char cmdbuf[80]; 12731500Serics 12741500Serics kill_line (); 12751500Serics pr ("!"); 12761500Serics fflush (stdout); 12771500Serics promptlen = 1; 12781500Serics if (lastp) 12791500Serics pr (shell_line); 12801500Serics else { 12811500Serics ttyin (cmdbuf, 78, '!'); 12821500Serics if (expand (shell_line, cmdbuf)) { 12831500Serics kill_line (); 12841500Serics promptlen = printf ("!%s", shell_line); 12851500Serics } 12861500Serics } 12871500Serics fflush (stdout); 12881500Serics write (2, "\n", 1); 12891500Serics promptlen = 0; 12901500Serics shellp = 1; 12911500Serics execute (filename, shell, shell, "-c", shell_line, 0); 12921500Serics } 12931500Serics 12941500Serics /* 12951500Serics ** Search for nth ocurrence of regular expression contained in buf in the file 12961500Serics */ 12971500Serics 12981500Serics search (buf, file, n) 12991500Serics char buf[]; 13001500Serics FILE *file; 13011500Serics register int n; 13021500Serics { 13031500Serics long startline = Ftell (file); 13041500Serics register long line1 = startline; 13051500Serics register long line2 = startline; 13061500Serics register long line3 = startline; 13071500Serics register int lncount; 13081500Serics int saveln, rv, re_exec(); 13091500Serics char *s, *re_comp(); 13101500Serics 13111500Serics context.line = saveln = Currline; 13121500Serics context.chrctr = startline; 13131500Serics lncount = 0; 13141500Serics if ((s = re_comp (buf)) != 0) 13151500Serics error (s); 13161500Serics while (!feof (file)) { 13171500Serics line3 = line2; 13181500Serics line2 = line1; 13191500Serics line1 = Ftell (file); 13201500Serics rdline (file); 13211500Serics lncount++; 13221500Serics if ((rv = re_exec (Line)) == 1) 13231500Serics if (--n == 0) { 13241500Serics if (lncount > 3 || (lncount > 1 && no_intty)) 13253455Sroot { 13263455Sroot pr ("\n"); 13273594Sroot if (clreol) 13283594Sroot cleareol (); 13293455Sroot pr("...skipping\n"); 13303455Sroot } 13311500Serics if (!no_intty) { 13321500Serics Currline -= (lncount >= 3 ? 3 : lncount); 13331500Serics Fseek (file, line3); 13343594Sroot if (noscroll) 13353594Sroot if (clreol) { 13363594Sroot home (); 13373594Sroot cleareol (); 133816582Sleres } 13393594Sroot else 13403594Sroot doclear (); 13411500Serics } 13421500Serics else { 13431500Serics kill_line (); 13443594Sroot if (noscroll) 13453594Sroot if (clreol) { 134616582Sleres home (); 13473594Sroot cleareol (); 134816582Sleres } 13493594Sroot else 13503594Sroot doclear (); 13511500Serics pr (Line); 13521500Serics putchar ('\n'); 13531500Serics } 13541500Serics break; 13551500Serics } 13561500Serics else if (rv == -1) 13571500Serics error ("Regular expression botch"); 13581500Serics } 13591500Serics if (feof (file)) { 13601500Serics if (!no_intty) { 13611500Serics file->_flag &= ~_IOEOF; /* why doesn't fseek do this ??!!??! */ 13621500Serics Currline = saveln; 13631500Serics Fseek (file, startline); 13641500Serics } 13651500Serics else { 13661500Serics pr ("\nPattern not found\n"); 13671500Serics end_it (); 13681500Serics } 13691500Serics error ("Pattern not found"); 13701500Serics } 13711500Serics } 13721500Serics 137332737Sbostic /*VARARGS2*/ 137432737Sbostic execute (filename, cmd, va_alist) 13751500Serics char *filename; 137632737Sbostic char *cmd; 137732737Sbostic va_dcl 13781500Serics { 13791500Serics int id; 138016710Sjak int n; 138132737Sbostic va_list argp; 13821500Serics 13831500Serics fflush (stdout); 13841500Serics reset_tty (); 138516710Sjak for (n = 10; (id = fork ()) < 0 && n > 0; n--) 13861500Serics sleep (5); 13871500Serics if (id == 0) { 138816710Sjak if (!isatty(0)) { 138916710Sjak close(0); 139016710Sjak open("/dev/tty", 0); 139116710Sjak } 139232737Sbostic va_start(argp); 139332737Sbostic execv (cmd, argp); 13941500Serics write (2, "exec failed\n", 12); 13951500Serics exit (1); 139633087Sbostic va_end(argp); /* balance {}'s for some UNIX's */ 13971500Serics } 139816710Sjak if (id > 0) { 139916710Sjak signal (SIGINT, SIG_IGN); 140016710Sjak signal (SIGQUIT, SIG_IGN); 140116710Sjak if (catch_susp) 140216710Sjak signal(SIGTSTP, SIG_DFL); 140316710Sjak while (wait(0) > 0); 140416710Sjak signal (SIGINT, end_it); 140516710Sjak signal (SIGQUIT, onquit); 140616710Sjak if (catch_susp) 140716710Sjak signal(SIGTSTP, onsusp); 140816710Sjak } else 140916710Sjak write(2, "can't fork\n", 11); 14101500Serics set_tty (); 14111500Serics pr ("------------------------\n"); 14121500Serics prompt (filename); 14131500Serics } 14141500Serics /* 14151500Serics ** Skip n lines in the file f 14161500Serics */ 14171500Serics 14181500Serics skiplns (n, f) 14191500Serics register int n; 14201500Serics register FILE *f; 14211500Serics { 14221500Serics register char c; 14231500Serics 14241500Serics while (n > 0) { 14251500Serics while ((c = Getc (f)) != '\n') 14261500Serics if (c == EOF) 14271500Serics return; 14281500Serics n--; 14291500Serics Currline++; 14301500Serics } 14311500Serics } 14321500Serics 14331500Serics /* 14341500Serics ** Skip nskip files in the file list (from the command line). Nskip may be 14351500Serics ** negative. 14361500Serics */ 14371500Serics 14381500Serics skipf (nskip) 14391500Serics register int nskip; 14401500Serics { 14411500Serics if (nskip == 0) return; 14421500Serics if (nskip > 0) { 14431500Serics if (fnum + nskip > nfiles - 1) 14441500Serics nskip = nfiles - fnum - 1; 14451500Serics } 14461500Serics else if (within) 14471500Serics ++fnum; 14481500Serics fnum += nskip; 14491500Serics if (fnum < 0) 14501500Serics fnum = 0; 14513594Sroot pr ("\n...Skipping "); 14523455Sroot pr ("\n"); 14533594Sroot if (clreol) 14543594Sroot cleareol (); 14553455Sroot pr ("...Skipping "); 14561500Serics pr (nskip > 0 ? "to file " : "back to file "); 14571500Serics pr (fnames[fnum]); 14583455Sroot pr ("\n"); 14593594Sroot if (clreol) 14603594Sroot cleareol (); 14613455Sroot pr ("\n"); 14621500Serics --fnum; 14631500Serics } 14641500Serics 14651500Serics /*----------------------------- Terminal I/O -------------------------------*/ 14661500Serics 14671500Serics initterm () 14681500Serics { 14691500Serics char buf[TBUFSIZ]; 147017195Sralph static char clearbuf[TBUFSIZ]; 14711500Serics char *clearptr, *padstr; 14721500Serics int ldisc; 147317592Sleres int lmode; 147410823Ssam char *term; 147516582Sleres int tgrp; 147618030Sbloom struct winsize win; 14771500Serics 147816582Sleres retry: 147916582Sleres if (!(no_tty = gtty(fileno(stdout), &otty))) { 148017592Sleres if (ioctl(fileno(stdout), TIOCLGET, &lmode) < 0) { 148117592Sleres perror("TIOCLGET"); 148217592Sleres exit(1); 148317592Sleres } 148417592Sleres docrterase = ((lmode & LCRTERA) != 0); 148517592Sleres docrtkill = ((lmode & LCRTKIL) != 0); 148616582Sleres /* 148717592Sleres * Wait until we're in the foreground before we save the 148817592Sleres * the terminal modes. 148916582Sleres */ 149016582Sleres if (ioctl(fileno(stdout), TIOCGPGRP, &tgrp) < 0) { 149117592Sleres perror("TIOCGPGRP"); 149216582Sleres exit(1); 149316582Sleres } 149416582Sleres if (tgrp != getpgrp(0)) { 149516582Sleres kill(0, SIGTTOU); 149616582Sleres goto retry; 149716582Sleres } 149813830Skre if ((term = getenv("TERM")) == 0 || tgetent(buf, term) <= 0) { 14993594Sroot dumb++; ul_opt = 0; 15001500Serics } 15011500Serics else { 150218030Sbloom if (ioctl(fileno(stdout), TIOCGWINSZ, &win) < 0) { 150318030Sbloom Lpp = tgetnum("li"); 150418030Sbloom Mcol = tgetnum("co"); 150518030Sbloom } else { 150618030Sbloom if ((Lpp = win.ws_row) == 0) 150718030Sbloom Lpp = tgetnum("li"); 150818030Sbloom if ((Mcol = win.ws_col) == 0) 150918030Sbloom Mcol = tgetnum("co"); 151018030Sbloom } 151118030Sbloom if ((Lpp <= 0) || tgetflag("hc")) { 15121500Serics hard++; /* Hard copy terminal */ 15131500Serics Lpp = 24; 15141500Serics } 151529907Smckusick if (tgetflag("xn")) 151629907Smckusick eatnl++; /* Eat newline at last column + 1; dec, concept */ 151718030Sbloom if (Mcol <= 0) 151818030Sbloom Mcol = 80; 151918030Sbloom 15201500Serics if (tailequ (fnames[0], "page") || !hard && tgetflag("ns")) 15211500Serics noscroll++; 15221500Serics Wrap = tgetflag("am"); 15231500Serics bad_so = tgetflag ("xs"); 15241500Serics clearptr = clearbuf; 15251500Serics eraseln = tgetstr("ce",&clearptr); 15261500Serics Clear = tgetstr("cl", &clearptr); 15271500Serics Senter = tgetstr("so", &clearptr); 15281500Serics Sexit = tgetstr("se", &clearptr); 152916710Sjak if ((soglitch = tgetnum("sg")) < 0) 153016710Sjak soglitch = 0; 15313594Sroot 15323594Sroot /* 15333594Sroot * Set up for underlining: some terminals don't need it; 15343594Sroot * others have start/stop sequences, still others have an 15353594Sroot * underline char sequence which is assumed to move the 15363594Sroot * cursor forward one character. If underline sequence 15373594Sroot * isn't available, settle for standout sequence. 15383594Sroot */ 15393594Sroot 15403594Sroot if (tgetflag("ul") || tgetflag("os")) 15413594Sroot ul_opt = 0; 15423594Sroot if ((chUL = tgetstr("uc", &clearptr)) == NULL ) 15433594Sroot chUL = ""; 154416710Sjak if (((ULenter = tgetstr("us", &clearptr)) == NULL || 154516710Sjak (ULexit = tgetstr("ue", &clearptr)) == NULL) && !*chUL) { 154616710Sjak if ((ULenter = Senter) == NULL || (ULexit = Sexit) == NULL) { 154716710Sjak ULenter = ""; 154816710Sjak ULexit = ""; 154916710Sjak } else 155016710Sjak ulglitch = soglitch; 155116710Sjak } else { 155216710Sjak if ((ulglitch = tgetnum("ug")) < 0) 155316710Sjak ulglitch = 0; 155416710Sjak } 155516582Sleres 15561500Serics if (padstr = tgetstr("pc", &clearptr)) 15571500Serics PC = *padstr; 15583455Sroot Home = tgetstr("ho",&clearptr); 155913536Ssam if (Home == 0 || *Home == '\0') 15603455Sroot { 15613594Sroot if ((cursorm = tgetstr("cm", &clearptr)) != NULL) { 15623594Sroot strcpy(cursorhome, tgoto(cursorm, 0, 0)); 15633455Sroot Home = cursorhome; 15643455Sroot } 15653455Sroot } 15663594Sroot EodClr = tgetstr("cd", &clearptr); 156725540Smckusick if ((chBS = tgetstr("bc", &clearptr)) == NULL) 156825540Smckusick chBS = "\b"; 156925540Smckusick 15701500Serics } 15711500Serics if ((shell = getenv("SHELL")) == NULL) 15721500Serics shell = "/bin/sh"; 15731500Serics } 157416582Sleres no_intty = gtty(fileno(stdin), &otty); 157516582Sleres gtty(fileno(stderr), &otty); 157613830Skre savetty = otty; 15771500Serics ospeed = otty.sg_ospeed; 15781500Serics slow_tty = ospeed < B1200; 157927006Sdonn hardtabs = (otty.sg_flags & TBDELAY) != XTABS; 15801500Serics if (!no_tty) { 15811500Serics otty.sg_flags &= ~ECHO; 15821500Serics if (MBIT == CBREAK || !slow_tty) 15831500Serics otty.sg_flags |= MBIT; 15841500Serics } 15851500Serics } 15861500Serics 15871500Serics readch () 15881500Serics { 15891500Serics char ch; 15901500Serics extern int errno; 15911500Serics 159231089Skarels errno = 0; 15931500Serics if (read (2, &ch, 1) <= 0) 15941500Serics if (errno != EINTR) 159531089Skarels end_it(); 15961500Serics else 15971500Serics ch = otty.sg_kill; 15981500Serics return (ch); 15991500Serics } 16001500Serics 16011500Serics static char BS = '\b'; 160217592Sleres static char *BSB = "\b \b"; 16031500Serics static char CARAT = '^'; 160417592Sleres #define ERASEONECHAR \ 160517592Sleres if (docrterase) \ 160617592Sleres write (2, BSB, sizeof(BSB)); \ 160717592Sleres else \ 160817592Sleres write (2, &BS, sizeof(BS)); 16091500Serics 16101500Serics ttyin (buf, nmax, pchar) 16111500Serics char buf[]; 16121500Serics register int nmax; 16131500Serics char pchar; 16141500Serics { 16151500Serics register char *sptr; 16161500Serics register char ch; 16171500Serics register int slash = 0; 16181500Serics int maxlen; 16191500Serics char cbuf; 16201500Serics 16211500Serics sptr = buf; 16221500Serics maxlen = 0; 16231500Serics while (sptr - buf < nmax) { 16241500Serics if (promptlen > maxlen) maxlen = promptlen; 16251500Serics ch = readch (); 16261500Serics if (ch == '\\') { 16271500Serics slash++; 16281500Serics } 16291500Serics else if ((ch == otty.sg_erase) && !slash) { 16301500Serics if (sptr > buf) { 16311500Serics --promptlen; 163217592Sleres ERASEONECHAR 16331500Serics --sptr; 16341500Serics if ((*sptr < ' ' && *sptr != '\n') || *sptr == RUBOUT) { 16351500Serics --promptlen; 163617592Sleres ERASEONECHAR 16371500Serics } 16381500Serics continue; 16391500Serics } 16401500Serics else { 16411500Serics if (!eraseln) promptlen = maxlen; 16421500Serics longjmp (restore, 1); 16431500Serics } 16441500Serics } 16451500Serics else if ((ch == otty.sg_kill) && !slash) { 16461500Serics if (hard) { 16471500Serics show (ch); 16481500Serics putchar ('\n'); 16491500Serics putchar (pchar); 16501500Serics } 16511500Serics else { 16521500Serics putchar ('\r'); 16531500Serics putchar (pchar); 16541500Serics if (eraseln) 16551500Serics erase (1); 165617592Sleres else if (docrtkill) 165717592Sleres while (promptlen-- > 1) 165817592Sleres write (2, BSB, sizeof(BSB)); 16591500Serics promptlen = 1; 16601500Serics } 16611500Serics sptr = buf; 16621500Serics fflush (stdout); 16631500Serics continue; 16641500Serics } 16651500Serics if (slash && (ch == otty.sg_kill || ch == otty.sg_erase)) { 166617592Sleres ERASEONECHAR 16671500Serics --sptr; 16681500Serics } 16691500Serics if (ch != '\\') 16701500Serics slash = 0; 16711500Serics *sptr++ = ch; 16721500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 16731500Serics ch += ch == RUBOUT ? -0100 : 0100; 16741500Serics write (2, &CARAT, 1); 16751500Serics promptlen++; 16761500Serics } 16771500Serics cbuf = ch; 16781500Serics if (ch != '\n' && ch != ESC) { 16791500Serics write (2, &cbuf, 1); 16801500Serics promptlen++; 16811500Serics } 16821500Serics else 16831500Serics break; 16841500Serics } 16851500Serics *--sptr = '\0'; 16861500Serics if (!eraseln) promptlen = maxlen; 16871500Serics if (sptr - buf >= nmax - 1) 16881500Serics error ("Line too long"); 16891500Serics } 16901500Serics 16911500Serics expand (outbuf, inbuf) 16921500Serics char *outbuf; 16931500Serics char *inbuf; 16941500Serics { 16951500Serics register char *instr; 16961500Serics register char *outstr; 16971500Serics register char ch; 16981500Serics char temp[200]; 16991500Serics int changed = 0; 17001500Serics 17011500Serics instr = inbuf; 17021500Serics outstr = temp; 17031500Serics while ((ch = *instr++) != '\0') 17041500Serics switch (ch) { 17051500Serics case '%': 17061500Serics if (!no_intty) { 17071500Serics strcpy (outstr, fnames[fnum]); 17081500Serics outstr += strlen (fnames[fnum]); 17091500Serics changed++; 17101500Serics } 17111500Serics else 17121500Serics *outstr++ = ch; 17131500Serics break; 17141500Serics case '!': 17151500Serics if (!shellp) 17161500Serics error ("No previous command to substitute for"); 17171500Serics strcpy (outstr, shell_line); 17181500Serics outstr += strlen (shell_line); 17191500Serics changed++; 17201500Serics break; 17211500Serics case '\\': 17221500Serics if (*instr == '%' || *instr == '!') { 17231500Serics *outstr++ = *instr++; 17241500Serics break; 17251500Serics } 17261500Serics default: 17271500Serics *outstr++ = ch; 17281500Serics } 17291500Serics *outstr++ = '\0'; 17301500Serics strcpy (outbuf, temp); 17311500Serics return (changed); 17321500Serics } 17331500Serics 17341500Serics show (ch) 17351500Serics register char ch; 17361500Serics { 17371500Serics char cbuf; 17381500Serics 17391500Serics if ((ch < ' ' && ch != '\n' && ch != ESC) || ch == RUBOUT) { 17401500Serics ch += ch == RUBOUT ? -0100 : 0100; 17411500Serics write (2, &CARAT, 1); 17421500Serics promptlen++; 17431500Serics } 17441500Serics cbuf = ch; 17451500Serics write (2, &cbuf, 1); 17461500Serics promptlen++; 17471500Serics } 17481500Serics 17491500Serics error (mess) 17501500Serics char *mess; 17511500Serics { 17523594Sroot if (clreol) 17533594Sroot cleareol (); 17543594Sroot else 17553594Sroot kill_line (); 17561500Serics promptlen += strlen (mess); 17571500Serics if (Senter && Sexit) { 17581500Serics tputs (Senter, 1, putch); 17591500Serics pr(mess); 17601500Serics tputs (Sexit, 1, putch); 17611500Serics } 17621500Serics else 17631500Serics pr (mess); 17641500Serics fflush(stdout); 17651500Serics errors++; 17661500Serics longjmp (restore, 1); 17671500Serics } 17681500Serics 17691500Serics 17701500Serics set_tty () 17711500Serics { 17721500Serics otty.sg_flags |= MBIT; 17731500Serics otty.sg_flags &= ~ECHO; 177416582Sleres stty(fileno(stderr), &otty); 17751500Serics } 17761500Serics 17771500Serics reset_tty () 17781500Serics { 177931033Sbostic if (no_tty) 178031033Sbostic return; 178116710Sjak if (pstate) { 178216710Sjak tputs(ULexit, 1, putch); 178316710Sjak fflush(stdout); 178416710Sjak pstate = 0; 178516710Sjak } 17861500Serics otty.sg_flags |= ECHO; 17871500Serics otty.sg_flags &= ~MBIT; 178816582Sleres stty(fileno(stderr), &savetty); 17891500Serics } 17901500Serics 17911500Serics rdline (f) 17921500Serics register FILE *f; 17931500Serics { 17941500Serics register char c; 17951500Serics register char *p; 17961500Serics 17971500Serics p = Line; 17981500Serics while ((c = Getc (f)) != '\n' && c != EOF && p - Line < LINSIZ - 1) 17991500Serics *p++ = c; 18001500Serics if (c == '\n') 18011500Serics Currline++; 18021500Serics *p = '\0'; 18031500Serics } 18041500Serics 18051500Serics /* Come here when we get a suspend signal from the terminal */ 18061500Serics 18071500Serics onsusp () 18081500Serics { 180914861Skarels /* ignore SIGTTOU so we don't get stopped if csh grabs the tty */ 181014861Skarels signal(SIGTTOU, SIG_IGN); 18111500Serics reset_tty (); 18121500Serics fflush (stdout); 181314861Skarels signal(SIGTTOU, SIG_DFL); 18141500Serics /* Send the TSTP signal to suspend our process group */ 181513289Ssam signal(SIGTSTP, SIG_DFL); 181613289Ssam sigsetmask(0); 18171500Serics kill (0, SIGTSTP); 18181500Serics /* Pause for station break */ 18191500Serics 18201500Serics /* We're back */ 18211500Serics signal (SIGTSTP, onsusp); 18221500Serics set_tty (); 18231500Serics if (inwait) 18241500Serics longjmp (restore); 18251500Serics } 1826