📄 pg.c
字号:
case 's': case '!': return STRING; case 'm': case 'b': case 't': return ADDON_FIN; default:#ifndef PGNOBELL if (bell) tputs(bell, 1, outcap);#endif /* PGNOBELL */ return INVALID; }}/* * Get the count and ignore last character of string. */static intgetcount(char *cmdstr){ char *buf; char *p; int i; if (*cmdstr == '\0') return 1; buf = (char *)smalloc(strlen(cmdstr) + 1); strcpy(buf, cmdstr); if (cmd.key != '\0') { if (cmd.key == '/' || cmd.key == '?' || cmd.key == '^') { if ((p = strchr(buf, cmd.key)) != NULL) *p = '\0'; } else *(buf + strlen(buf) - 1) = '\0'; } if (*buf == '\0') return 1; if (buf[0] == '-' && buf[1] == '\0') { i = -1; } else { if (*buf == '+') i = atoi(buf + 1); else i = atoi(buf); } free(buf); return i;}/* * Read what the user writes at the prompt. This is tricky because * we check for valid input. */static voidprompt(long long pageno){ struct termios tio; char key; int state = COUNT; int escape = 0; char b[LINE_MAX], *p; if (pageno != -1) { if ((p = strstr(pstring, "%d")) == NULL) { mesg(pstring); } else { strcpy(b, pstring); sprintf(b + (p - pstring), "%lld", pageno); strcat(b, p + 2); mesg(b); } } cmd.key = cmd.addon = cmd.cmdline[0] = '\0'; cmd.cmdlen = 0; tcgetattr(1, &tio); tio.c_lflag &= ~(ICANON | ECHO); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; tcsetattr(1, TCSADRAIN, &tio); tcflush(1, TCIFLUSH); for (;;) { switch (read(1, &key, 1)) { case 0: quit(0); /*NOTREACHED*/ case -1: quit(1); } if (key == tio.c_cc[VERASE]) { if (cmd.cmdlen) { write(1, "\b \b", 3); cmd.cmdline[--cmd.cmdlen] = '\0'; switch (state) { case ADDON_FIN: state = SEARCH_FIN; cmd.addon = '\0'; break; case CMD_FIN: cmd.key = '\0'; state = COUNT; break; case SEARCH_FIN: state = SEARCH; /*FALLTHRU*/ case SEARCH: if (cmd.cmdline[cmd.cmdlen - 1] == '\\') { escape = 1; while(cmd.cmdline[cmd.cmdlen - escape - 1] == '\\') escape++; escape %= 2; } else { escape = 0; if (strchr(cmd.cmdline, cmd.key) == NULL) { cmd.key = '\0'; state = COUNT; } } break; } } if (cmd.cmdlen == 0) { state = COUNT; cmd.key = '\0'; } continue; } if (key == tio.c_cc[VKILL]) { cline(); cmd.cmdlen = 0; cmd.cmdline[0] = '\0'; state = COUNT; cmd.key = '\0'; continue; } if (key == '\n' || (nflag && state == COUNT && key == ' ')) break; if (cmd.cmdlen >= CMDBUF - 1) continue; switch (state) { case STRING: break; case SEARCH: if (!escape) { if (key == cmd.key) state = SEARCH_FIN; if (key == '\\') escape = 1; } else escape = 0; break; case SEARCH_FIN: if (getstate(key) != ADDON_FIN) continue; state = ADDON_FIN; cmd.addon = key; switch (key) { case 't': searchdisplay = TOP; break; case 'm': searchdisplay = MIDDLE; break; case 'b': searchdisplay = BOTTOM; break; } break; case CMD_FIN: case ADDON_FIN: continue; default: state = getstate(key); switch (state) { case SIGN: if (cmd.cmdlen != 0) { state = INVALID; continue; } state = COUNT; /*FALLTHRU*/ case COUNT: break; case ADDON_FIN: case INVALID: continue; default: cmd.key = key; } } write(1, &key, 1); cmd.cmdline[cmd.cmdlen++] = key; cmd.cmdline[cmd.cmdlen] = '\0'; if (nflag && state == CMD_FIN) goto endprompt; }endprompt: tcsetattr(1, TCSADRAIN, &otio); cline(); cmd.count = getcount(cmd.cmdline);}#ifdef ENABLE_WIDECHAR/* * Remove backspace formatting, for searches * in case MB_CUR_MAX > 1. */static char *colb_for_mb(char *s){ char *p = s; wchar_t *wp, *wq; size_t l = strlen(s), wl; unsigned i; if ((wl = xmbstowcs(wbuf, p, sizeof wbuf)) == (size_t)-1) return s; for (wp = wbuf, wq = wbuf, i = 0; *wp != L'\0' && i < wl; wp++, wq++) { if (*wp == L'\b') { if (wq != wbuf) wq -= 2; else wq--; } else *wq = *wp; } *wq = L'\0'; wp = wbuf; wcstombs(s, wp, l + 1); return s;}#endif/* * Remove backspace formatting, for searches. */static char *colb(char *s){ char *p = s, *q;#ifdef ENABLE_WIDECHAR if (MB_CUR_MAX > 1) return colb_for_mb(s);#endif for (q = s; *p != '\0'; p++, q++) { if (*p == '\b') { if (q != s) q -= 2; else q--; } else *q = *p; } *q = '\0'; return s;}#ifdef ENABLE_WIDECHAR/* * Convert nonprintable characters to spaces * in case MB_CUR_MAX > 1. */static voidmakeprint_for_mb(char *s, size_t l){ char *t = s; wchar_t *wp = wbuf; size_t wl; if ((wl = xmbstowcs(wbuf, t, sizeof wbuf)) == (size_t)-1) return; while (wl--) { if (!iswprint(*wp) && *wp != L'\n' && *wp != L'\r' && *wp != L'\b' && *wp != L'\t') *wp = L'?'; wp++; } wp = wbuf; wcstombs(s, wp, l);}#endif/* * Convert nonprintable characters to spaces. */static voidmakeprint(char *s, size_t l){#ifdef ENABLE_WIDECHAR if (MB_CUR_MAX > 1) return makeprint_for_mb(s, l);#endif while (l--) { if (!isprint(cuc(*s)) && *s != '\n' && *s != '\r' && *s != '\b' && *s != '\t') *s = '?'; s++; }}/* * Strip backslash characters from the given string. */static voidstriprs(char *s){ char *p = s; do { if (*s == '\\') { s++; } *p++ = *s; } while (*s++ != '\0');}/* * Extract the search pattern off the command line. */static char *makepat(void){ char *p; if (cmd.addon == '\0') p = cmd.cmdline + strlen(cmd.cmdline) - 1; else p = cmd.cmdline + strlen(cmd.cmdline) - 2; if (*p == cmd.key) *p = '\0'; else *(p + 1) = '\0'; if ((p = strchr(cmd.cmdline, cmd.key)) != NULL) { p++; striprs(p); } return p;}/* * Process errors that occurred in temporary file operations. */static voidtmperr(FILE *f, char *ftype){ if (ferror(f)) fprintf(stderr, _("%s: Read error from %s file\n"), progname, ftype); else if (feof(f)) /* * Most likely '\0' in input. */ fprintf(stderr, _("%s: Unexpected EOF in %s file\n"), progname, ftype); else fprintf(stderr, _("%s: Unknown error in %s file\n"), progname, ftype); quit(++exitstatus);}/* * perror()-like, but showing the program's name. */static voidpgerror(int eno, char *string){ fprintf(stderr, "%s: %s: %s\n", progname, string, strerror(eno));}/* * Read the file and respond to user input. * Beware: long and ugly. */static voidpgfile(FILE *f, char *name){ off_t pos, oldpos, fpos; off_t line = 0, fline = 0, bline = 0, oldline = 0, eofline = 0; int dline = 0; /* * These are the line counters: * line the line desired to display * fline the current line of the input file * bline the current line of the file buffer * oldline the line before a search was started * eofline the last line of the file if it is already reached * dline the line on the display */ int search = 0; unsigned searchcount = 0; /* * Advance to EOF immediately. */ int seekeof = 0; /* * EOF has been reached by `line'. */ int eof = 0; /* * f and fbuf refer to the same file. */ int nobuf = 0; int sig; int rerror; size_t sz; char b[READBUF + 1]; char *p; /* * fbuf an exact copy of the input file as it gets read * find index table for input, one entry per line * save for the s command, to save to a file */ FILE *fbuf, *find, *save; /* silence compiler - it may warn about longjmp() */ CLOBBGRD(line); CLOBBGRD(fline); CLOBBGRD(bline); CLOBBGRD(oldline); CLOBBGRD(eofline); CLOBBGRD(dline); CLOBBGRD(ttycols); CLOBBGRD(search); CLOBBGRD(searchcount); CLOBBGRD(seekeof); CLOBBGRD(eof); CLOBBGRD(fpos); CLOBBGRD(nobuf); CLOBBGRD(fbuf); if (ontty == 0) { /* * Just copy stdin to stdout. */ while ((sz = fread(b, sizeof *b, READBUF, f)) != 0) write(1, b, sz); if (ferror(f)) { pgerror(errno, name); exitstatus++; } return; } if ((fpos = my_fseeko(f, (off_t)0, SEEK_SET)) == -1) fbuf = tmpfile(); else { fbuf = f; nobuf = 1; } find = tmpfile(); if (fbuf == NULL || find == NULL) { fprintf(stderr, _("%s: Cannot create tempfile\n"), progname); quit(++exitstatus); } if (searchfor) { search = FORWARD; oldline = 0; searchcount = 1; rerror = regcomp(&re, searchfor, REG_NOSUB | REG_NEWLINE); if (rerror != 0) { mesg(_("RE error: ")); regerror(rerror, &re, b, READBUF); mesg(b); goto newcmd; } remembered = 1; } for (line = startline; ; ) { /* * Get a line from input file or buffer. */ if (line < bline) { my_fseeko(find, line * sizeof pos, SEEK_SET); if (fread(&pos, sizeof pos, 1, find) == 0) tmperr(find, "index"); my_fseeko(find, (off_t)0, SEEK_END); my_fseeko(fbuf, pos, SEEK_SET); if (fgets(b, READBUF, fbuf) == NULL) tmperr(fbuf, "buffer"); } else if (eofline == 0) { my_fseeko(find, (off_t)0, SEEK_END); do { if (!nobuf) my_fseeko(fbuf, (off_t)0, SEEK_END); pos = my_ftello(fbuf); if ((sig = setjmp(jmpenv)) != 0) { /* * We got a signal. */ canjump = 0; my_sigrelse(sig); my_fseeko(fbuf, pos, SEEK_SET); *b = '\0'; dline = pagelen; break; } else { if (nobuf) my_fseeko(f, fpos, SEEK_SET); canjump = 1; p = fgets(b, READBUF, f); if (nobuf) if ((fpos = my_ftello(f)) == -1) pgerror(errno, name); canjump = 0; } if (p == NULL || *b == '\0') { if (ferror(f)) pgerror(errno, name); eofline = fline; eof = 1; break; } else { if (!nobuf) fputs(b, fbuf); fwrite(&pos, sizeof pos, 1, find); if (!fflag) { oldpos = pos; p = b; while (*(p = endline(ttycols, p)) != '\0') { pos = oldpos + (p - b); fwrite(&pos, sizeof pos, 1, find); fline++; bline++; } } fline++; } } while (line > bline++); } else { /* * eofline != 0 */ eof = 1; } if (search == FORWARD) { if (eof) { line = oldline; search = searchcount = 0; mesg(_("Pattern not found")); eof = 0; goto newcmd; } line++; colb(b); if (regexec(&re, b, 0, NULL, 0) == 0) { searchcount--; } if (searchcount == 0) { search = dline = 0; switch (searchdisplay) { case TOP: line -= 1; break; case MIDDLE: line -= pagelen / 2 + 1; break; case BOTTOM: line -= pagelen; break; } skip(1); } continue; } else if (eof) { /* * We are not searching. */ line = bline; } else if (*b != '\0') { if (cflag && clear_screen) { switch (dline) { case 0: tputs(clear_screen, 1, outcap); dline = 0; } } line++; if (eofline && line == eofline) eof = 1; dline++; if ((sig = setjmp(jmpenv)) != 0) { /* * We got a signal. */ canjump = 0; my_sigrelse(sig); dline = pagelen;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -