📄 more.c
字号:
/* * Copyright (C) 1980 The Regents of the University of California. * All rights reserved. * * Redistribution and use in source and binary forms are permitted * provided that the above copyright notice and this paragraph are * duplicated in all such forms and that any documentation, * advertising materials, and other materials related to such * distribution and use acknowledge that the software was developed * by the University of California, Berkeley. The name of the * University may not be used to endorse or promote products derived * from this software without specific prior written permission. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. *//*** more.c - General purpose tty output filter and file perusal program**** by Eric Shienbrood, UC Berkeley**** modified by Geoff Peck, UCB to add underlining, single spacing** modified by John Foderaro, UCB to add -c and MORE environment variable** modified by Erik Troan <ewt@redhat.com> to be more posix and so compile** on linux/axp.** modified by Kars de Jong <jongk@cs.utwente.nl> to use terminfo instead** of termcap. 1999-02-22 Arkadiusz Mi秌iewicz <misiek@pld.ORG.PL> - added Native Language Support 1999-03-19 Arnaldo Carvalho de Melo <acme@conectiva.com.br> - more nls translatable strings 1999-05-09 aeb - applied a RedHat patch (setjmp->sigsetjmp); without it a second ^Z would fail. 1999-05-09 aeb - undone Kars' work, so that more works without libcurses (and hence can be in /bin with libcurses being in /usr/lib which may not be mounted). However, when termcap is not present curses can still be used.*/#include <stdio.h>#include <string.h>#include <unistd.h>#include <stdlib.h> /* for alloca() */#include <stdarg.h> /* for va_start() etc */#include <sys/param.h>#include <ctype.h>#include <signal.h>#include <errno.h>#include <termios.h>#include <setjmp.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/file.h>#include <sys/wait.h>#include <a.out.h>#include <locale.h>#include "xstrncpy.h"#include "nls.h"#include "widechar.h"#define _REGEX_RE_COMP#include <regex.h>#undef _REGEX_RE_COMP#define VI "vi" /* found on the user's path */#define Fopen(s,m) (Currline = 0,file_pos=0,fopen(s,m))#define Ftell(f) file_pos#define Fseek(f,off) (file_pos=off,fseek(f,off,0))#define Getc(f) (++file_pos, getc(f))#define Ungetc(c,f) (--file_pos, ungetc(c,f))#define putcerr(c) fputc(c, stderr)#define putserr(s) fputs(s, stderr)#define putsout(s) fputs(s, stdout)#define stty(fd,argp) tcsetattr(fd,TCSANOW,argp)/* some function declarations */void initterm(void);void kill_line(void);void doclear(void);void cleareol(void);void clreos(void);void home(void);void error (char *mess);void do_shell (char *filename);int colon (char *filename, int cmd, int nlines);int expand (char **outbuf, char *inbuf);void argscan(char *s,char *argv0);void rdline (register FILE *f);void copy_file(register FILE *f);void search(char buf[], FILE *file, register int n);void skipf (register int nskip);void skiplns(register int n, register FILE *f);void screen (register FILE *f, register int num_lines);int command (char *filename, register FILE *f);void erasep (register int col);void show (register char ch);void set_tty(void);void reset_tty(void);void ttyin (unsigned char buf[], register int nmax, char pchar);int number(char *cmd);int readch (void);int get_line(register FILE *f, int *length);void prbuf (register char *s, register int n);void execute (char *filename, char *cmd, ...);FILE *checkf (char *, int *);#define TBUFSIZ 1024#define LINSIZ 256#define ctrl(letter) (letter & 077)#define RUBOUT '\177'#define ESC '\033'#define QUIT '\034'struct termios otty, savetty0;long file_pos, file_size;int fnum, no_intty, no_tty, slow_tty;int dum_opt, dlines;void onquit(int), onsusp(int), chgwinsz(int), end_it(int);int nscroll = 11; /* Number of lines scrolled by 'd' */int fold_opt = 1; /* Fold long lines */int stop_opt = 1; /* Stop after form feeds */int ssp_opt = 0; /* Suppress white space */int ul_opt = 1; /* Underline as best we can */int promptlen;int Currline; /* Line we are currently at */int startup = 1;int firstf = 1;int notell = 1;int docrterase = 0;int docrtkill = 0;int bad_so; /* True if overwriting does not turn off standout */int inwait, Pause, errors;int within; /* true if we are within a file, false if we are between files */int hard, dumb, noscroll, hardtabs, clreol, eatnl;int catch_susp; /* We should catch the SIGTSTP signal */char **fnames; /* The list of file names */int nfiles; /* Number of files left to process */char *shell; /* The name of the shell to use */int shellp; /* A previous shell command exists */sigjmp_buf restore;char Line[LINSIZ+2]; /* Line buffer */int Lpp = 24; /* lines per page */char *Clear; /* clear screen */char *eraseln; /* erase line */char *Senter, *Sexit;/* enter and exit standout mode */char *ULenter, *ULexit; /* enter and exit underline mode */char *chUL; /* underline character */char *chBS; /* backspace character */char *Home; /* go to home */char *cursorm; /* cursor movement */char cursorhome[40]; /* contains cursor movement to home */char *EodClr; /* clear rest of screen */int Mcol = 80; /* number of columns */int Wrap = 1; /* set if automargins */int soglitch; /* terminal has standout mode glitch */int ulglitch; /* terminal has underline mode glitch */int pstate = 0; /* current UL state */static int magic(FILE *, char *);struct { long chrctr, line;} context, screen_start;extern char PC; /* pad character */#ifndef HAVE_termcap#define USE_CURSES#endif#ifdef USE_CURSES#if NCH#include <ncurses.h>#else#include <curses.h>#endif#include <term.h> /* include after <curses.h> */static voidmy_putstring(char *s) { tputs (s, 1, putchar); /* putp(s); */}static voidmy_setupterm(const char *term, int fildes, int *errret) { setupterm(term, fildes, errret);}static intmy_tgetnum(char *s, char *ss) { return tigetnum(ss);}static intmy_tgetflag(char *s, char *ss) { return tigetflag(ss);}static char *my_tgetstr(char *s, char *ss) { return tigetstr(ss);}static char *my_tgoto(const char *cap, int col, int row) { return tparm(cap, col, row);}#else /* no CURSES */#include <termcap.h>char termbuffer[4096];char tcbuffer[4096];char *strbuf = termbuffer;static voidmy_putstring(char *s) { tputs (s, 1, putchar);}static voidmy_setupterm(const char *term, int fildes, int *errret) { *errret = tgetent(tcbuffer, term);}static intmy_tgetnum(char *s, char *ss) { return tgetnum(s);}static intmy_tgetflag(char *s, char *ss) { return tgetflag(s);}static char *my_tgetstr(char *s, char *ss) { return tgetstr(s, &strbuf);}static char *my_tgoto(const char *cap, int col, int row) { return tgoto(cap, col, row);}#endif /* USE_CURSES */static voididummy(int *kk) {}static voidFdummy(FILE **ff) {}static voidusage(char *s) { char *p = strrchr(s, '/'); fprintf(stderr, _("usage: %s [-dflpcsu] [+linenum | +/pattern] name1 name2 ...\n"), p ? p + 1 : s);}int main(int argc, char **argv) { FILE *f; char *s; char *p; int ch; int left; int prnames = 0; int initopt = 0; int srchopt = 0; int clearit = 0; int initline = 0; char initbuf[80]; setlocale(LC_ALL, ""); bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); /* avoid gcc complaints about register variables that may be clobbered by a longjmp, by forcing our variables here to be non-register */ Fdummy(&f); idummy(&left); idummy(&prnames); idummy(&initopt); idummy(&srchopt); idummy(&initline); nfiles = argc; fnames = argv; setlocale(LC_ALL, ""); initterm (); nscroll = Lpp/2 - 1; if (nscroll <= 0) nscroll = 1; if((s = getenv("MORE")) != NULL) argscan(s,argv[0]); while (--nfiles > 0) { if ((ch = (*++fnames)[0]) == '-') { argscan(*fnames+1,argv[0]); } else if (ch == '+') { s = *fnames; if (*++s == '/') { srchopt++; for (++s, p = initbuf; p < initbuf + 79 && *s != '\0';) *p++ = *s++; *p = '\0'; } else { initopt++; for (initline = 0; *s != '\0'; s++) if (isdigit (*s)) initline = initline*10 + *s -'0'; --initline; } } else break; } /* allow clreol only if Home and eraseln and EodClr strings are * defined, and in that case, make sure we are in noscroll mode */ if(clreol) { if((Home == NULL) || (*Home == '\0') || (eraseln == NULL) || (*eraseln == '\0') || (EodClr == NULL) || (*EodClr == '\0') ) clreol = 0; else noscroll = 1; } if (dlines == 0) dlines = Lpp - (noscroll ? 1 : 2); left = dlines; if (nfiles > 1) prnames++; if (!no_intty && nfiles == 0) { usage(argv[0]); exit(1); } else f = stdin; if (!no_tty) { signal(SIGQUIT, onquit); signal(SIGINT, end_it);#ifdef SIGWINCH signal(SIGWINCH, chgwinsz);#endif if (signal (SIGTSTP, SIG_IGN) == SIG_DFL) { signal(SIGTSTP, onsusp); catch_susp++; } stty (fileno(stderr), &otty); } if (no_intty) { if (no_tty) copy_file (stdin); else { if ((ch = Getc (f)) == '\f') doclear(); else { Ungetc (ch, f); if (noscroll && (ch != EOF)) { if (clreol) home (); else doclear (); } } if (srchopt) { search (initbuf, stdin, 1); if (noscroll) left--; } else if (initopt) skiplns (initline, stdin); screen (stdin, left); } no_intty = 0; prnames++; firstf = 0; } while (fnum < nfiles) { if ((f = checkf (fnames[fnum], &clearit)) != NULL) { context.line = context.chrctr = 0; Currline = 0; if (firstf) sigsetjmp (restore, 1); if (firstf) { firstf = 0; if (srchopt) { search (initbuf, f, 1); if (noscroll) left--; } else if (initopt) skiplns (initline, f); } else if (fnum < nfiles && !no_tty) { sigsetjmp (restore, 1); left = command (fnames[fnum], f); } if (left != 0) { if ((noscroll || clearit) && (file_size != LONG_MAX)) { if (clreol) home (); else doclear (); } if (prnames) { if (bad_so) erasep (0); if (clreol) cleareol (); putsout("::::::::::::::"); if (promptlen > 14) erasep (14); putchar('\n'); if(clreol) cleareol(); puts(fnames[fnum]); if(clreol) cleareol(); puts("::::::::::::::"); if (left > Lpp - 4) left = Lpp - 4; } if (no_tty) copy_file (f); else { within++; screen(f, left); within = 0; } } sigsetjmp (restore, 1); fflush(stdout); fclose(f); screen_start.line = screen_start.chrctr = 0L; context.line = context.chrctr = 0L; } fnum++; firstf = 0; } reset_tty (); exit(0);}void argscan(char *s, char *argv0) { int seen_num = 0; while (*s != '\0') { switch (*s) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (!seen_num) { dlines = 0; seen_num = 1; } dlines = dlines*10 + *s - '0'; break; case 'd': dum_opt = 1; break; case 'l': stop_opt = 0; break; case 'f': fold_opt = 0; break; case 'p': noscroll++; break; case 'c': clreol++; break; case 's': ssp_opt = 1; break; case 'u': ul_opt = 0; break; case '-': case ' ': case '\t': break; default: fprintf(stderr, _("%s: unknown option \"-%c\"\n"), argv0, *s); usage(argv0); exit(1); break; } s++; }}/*** Check whether the file named by fs is an ASCII file which the user may** access. If it is, return the opened file. Otherwise return NULL.*/FILE *checkf (fs, clearfirst) register char *fs; int *clearfirst;{ struct stat stbuf; register FILE *f; int c; if (stat (fs, &stbuf) == -1) { (void)fflush(stdout); if (clreol) cleareol (); perror(fs); return((FILE *)NULL); } if ((stbuf.st_mode & S_IFMT) == S_IFDIR) { printf(_("\n*** %s: directory ***\n\n"), fs); return((FILE *)NULL); } if ((f = Fopen(fs, "r")) == NULL) { (void)fflush(stdout); perror(fs); return((FILE *)NULL); } if (magic(f, fs)) return((FILE *)NULL); c = Getc(f); *clearfirst = (c == '\f'); Ungetc (c, f); if ((file_size = stbuf.st_size) == 0) file_size = LONG_MAX; return(f);}/* * magic -- * check for file magic numbers. This code would best be shared with * the file(1) program or, perhaps, more should not try and be so smart? */static intmagic(f, fs) FILE *f; char *fs;{ char twobytes[2]; /* don't try to look ahead if the input is unseekable */ if (fseek(f, 0L, SEEK_SET)) return(0); if (fread(twobytes, 2, 1, f) == 1) { switch(twobytes[0] + (twobytes[1]<<8)) { case OMAGIC: /* 0407 */ case NMAGIC: /* 0410 */ case ZMAGIC: /* 0413 */ case 0405: case 0411: case 0177545: case 0x457f: /* simple ELF detection */ printf(_("\n******** %s: Not a text file ********\n\n"), fs); (void)fclose(f); return(1); } } (void)fseek(f, 0L, SEEK_SET); /* rewind() not necessary */ return(0);}/*** Print out the contents of the file f, one screenful at a time.*/#define STOP -10void screen (register FILE *f, register int num_lines){ register int c; register int nchars; int length; /* length of current line */ static int prev_len = 1; /* length of previous line */ for (;;) { while (num_lines > 0 && !Pause) { if ((nchars = get_line (f, &length)) == EOF) { if (clreol) clreos(); return; } if (ssp_opt && length == 0 && prev_len == 0) continue; prev_len = length; if (bad_so || ((Senter && *Senter == ' ') && (promptlen > 0))) erasep (0); /* must clear before drawing line since tabs on some terminals * do not erase what they tab over. */ if (clreol) cleareol (); prbuf (Line, length); if (nchars < promptlen) erasep (nchars); /* erasep () sets promptlen to 0 */ else promptlen = 0; /* is this needed? * if (clreol) * cleareol(); * must clear again in case we wrapped * */ if (nchars < Mcol || !fold_opt) prbuf("\n", 1); /* will turn off UL if necessary */ if (nchars == STOP) break; num_lines--; } if (pstate) { my_putstring (ULexit); pstate = 0; } fflush(stdout); if ((c = Getc(f)) == EOF) { if (clreol) clreos (); return; } if (Pause && clreol) clreos (); Ungetc (c, f); sigsetjmp (restore, 1); Pause = 0; startup = 0; if ((num_lines = command (NULL, f)) == 0) return; if (hard && promptlen > 0) erasep (0); if (noscroll && num_lines >= dlines) { if (clreol) home(); else doclear (); } screen_start.line = Currline; screen_start.chrctr = Ftell (f); }}/*** Come here if a quit signal is received*/void onquit(int dummy) { signal(SIGQUIT, SIG_IGN); if (!inwait) { putchar ('\n'); if (!startup) { signal(SIGQUIT, onquit); siglongjmp (restore, 1); } else Pause++; } else if (!dum_opt && notell) { promptlen += fprintf(stderr, _("[Use q or Q to quit]")); notell = 0; } signal(SIGQUIT, onquit);}/*** Come here if a signal for a window size change is received*/#ifdef SIGWINCHvoid chgwinsz(int dummy) { struct winsize win; (void) signal(SIGWINCH, SIG_IGN); if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1) { if (win.ws_row != 0) { Lpp = win.ws_row; nscroll = Lpp/2 - 1; if (nscroll <= 0) nscroll = 1; dlines = Lpp - (noscroll ? 1 : 2); } if (win.ws_col != 0) Mcol = win.ws_col; } (void) signal(SIGWINCH, chgwinsz);}#endif/*** Clean up terminal state and exit. Also come here if interrupt signal received*/void end_it (int dummy) { reset_tty (); if (clreol) { putchar ('\r'); clreos (); fflush (stdout); } else if (!clreol && (promptlen > 0)) { kill_line (); fflush (stdout); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -