/* BMORE - binary more * * 1990-01-31 V 1.0.0 * 1990-09-04 V 1.1.0 * 2000-05-31 V 1.3.0 beta * 2000-10-18 V 1.3.0 final * 2002-01-16 V 1.3.1 * 2004-01-09 V 1.3.2 * * NOTE: Edit this file with tabstop=4 ! * * Copyright 1990-2004 by Gerhard Buergmann * gerhard@puon.at * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any * later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * See file COPYING for information on distribution conditions. */ #include #ifdef HAVE_LOCALE_H # include #endif #if defined(__MSDOS__) && !defined(DJGPP) # define PRINTF cprintf #else # define PRINTF printf #ifndef HELPFILE # ifdef DJGPP # define HELPFILE "/dev/env/DJDIR/lib/bmore.help" # else # define HELPFILE "/usr/local/lib/bmore.help" # endif #endif #endif #include "bmore.h" char *copyright = "Copyright (C) 1990-2004 by Gerhard Buergmann"; int maxx, maxy; int mymaxx = 0, mymaxy = 0; char *name = NULL; char sstring[MAXCMD] = ""; /* string for search */ char estring[MAXCMD] = ""; /* string for shell escape */ char string[MAXCMD]; FILE *curr_file = NULL, *help_file; int AnzAdd; long precount = -1; /* number preceding command */ char **files; /* list of input files */ int numfiles; /* number of input files */ int file_nr = 0; /* number of current input file */ int arrnum = 0; char numarr[64]; /* string for collecting number */ char addr_form[15]; int ascii_flag = 0; int c_flag = 0, d_flag = 0; int exval = 0; int init_search = 0; char buffer1[MAXCMD], buffer2[MAXCMD]; int out_len; int corr = 0, do_header = 0, to_print; off_t init_byte = 0; off_t last_search = 0; off_t screen_home, filesize; off_t bytepos, oldpos; int prompt = 1; char helppath[MAXCMD]; static char progname[10]; static char cmdbuf[MAXCMD]; static int cnt = 0; static int icnt = 0; static int smode; char search_pat[BUFFER]; /* / or ? command */ char *emptyclass = "Empty byte class '[]' or '[^]'"; /* -a ASCII mode * -d beginners mode * -c clear before displaying * -i ignore case * -n number of lines/screen * -w width of screen */ void usage() { fprintf(stderr, "Usage: %s [-acdi] [-lines] [+linenum | +/pattern] name1 name2 ...\n", progname); exit(1); } int main(argc, argv) int argc; char *argv[]; { int ch, ch1; int colon = 0, last_ch = 0; long last_pre = 0; int lflag, repeat; long count; int i, n = 1; int d_line, r_line, z_line; char *poi; #if defined(__MSDOS__) && !defined(DJGPP) strcpy(helppath, argv[0]); poi = strrchr(helppath, '\\'); *poi = '\0'; strcat(helppath, "\\BMORE.HLP"); #else strncpy(helppath, HELPFILE, MAXCMD - 1); #endif #ifdef HAVE_LOCALE_H setlocale(LC_ALL, ""); #endif poi = strrchr(argv[0], DELIM); if (poi) strncpy(progname, ++poi, 9); else strncpy(progname, argv[0], 9); strtok(progname, "."); while (n < argc) { switch (argv[n][0]) { case '-': if (argv[n][1] >= '0' && argv[n][1] <= '9') { sscanf(&argv[n][1], "%dx%d", &mymaxy, &mymaxx); } else if (argv[n][1] == 'n') { if (argv[n+1] == NULL || argv[n+1][0] == '-') { usage(); } else { sscanf(&argv[++n][0], "%d", &mymaxy); } } else if (argv[n][1] == 'w') { if (argv[n+1] == NULL || argv[n+1][0] == '-') { usage(); } else { sscanf(&argv[++n][0], "%d", &mymaxx); } } else { i = 1; while (argv[n][i] != '\0') { switch (argv[n][i]) { case 'a': ascii_flag++; break; case 'c': c_flag++; break; case 'd': d_flag++; break; case 'i': ignore_case++; break; default: usage(); } i++; } } n++; break; case '+': /* +cmd */ if (argv[n][1] == '/' || argv[n][1] == '\\') { init_search = argv[n][1]; strcpy(sstring, &argv[n][2]); } else { if (argv[n][1] == '0') { init_byte = (off_t)strtol(argv[n] + 1, NULL, 16); } else { init_byte = (off_t)strtol(argv[n] + 1, NULL, 10); } } n++; break; default: /* must be a file name */ name = strdup(argv[n]); files = &(argv[n]); numfiles = argc - n; n = argc; break; } } initterm(); set_tty(); maxy -= 2; if (mymaxy) { maxy = mymaxy; } z_line = maxy; d_line = maxy / 2; r_line = 1; if (numfiles == 0) { curr_file = stdin; if (isatty(fileno(stdin)) != 0) { reset_tty(); usage(); } } else { file_nr = 1; while (open_file(name)) { do_next(1); } if (exval) { } else { fseek(curr_file, init_byte, SEEK_SET); bytepos += init_byte; } } screen_home = bytepos; AnzAdd = 10; strcpy(addr_form, "%08lX "); if (ascii_flag) out_len = ((maxx - AnzAdd - 1) / 4) * 4; else out_len = ((maxx - AnzAdd - 1) / 16) * 4; if (mymaxx) { out_len = mymaxx; } if (init_search) bmsearch(init_search); if (no_tty) { int fileloop; for (fileloop = 0; fileloop < numfiles; fileloop++) { while(!printout(1)); do_next(1); open_file(name); } fclose(curr_file); reset_tty(); exit(exval); } if (!exval) { if (printout(maxy)) { do_next(1); } } signal(SIGINT, sig); signal(SIGQUIT, sig); /* main loop */ do { to_print = 0; if (prompt) { if (prompt == 2) { while (open_file(name)) { do_next(1); } } highlight(); PRINTF("--More--"); if (prompt == 2) { PRINTF("(Next file: %s)", name); } else if (!no_intty && filesize) { PRINTF("(%d%%)", (int)((bytepos * 100) / filesize)); } if (d_flag) PRINTF("[Press space to continue, 'q' to quit]"); normal(); fflush(stdout); } ch = vgetc(); /* if (prompt == 2) { open_file(name); } */ prompt = 1; PRINTF("\r"); while (ch >= '0' && ch <= '9') { numarr[arrnum++] = ch; ch = vgetc(); } numarr[arrnum] = '\0'; if (arrnum != 0) precount = strtol(numarr, (char **)NULL, 10); else precount = -1; lflag = arrnum = 0; if (ch == '.') { precount = last_pre; ch = last_ch; repeat = 1; } else { last_pre = precount; last_ch = ch; if (ch == ':') colon = vgetc(); repeat = 0; } switch (ch) { case ' ': /* Display next k lines of text [current screen size] */ if (precount > 0) to_print = precount; else to_print = maxy; break; case 'z': /* Display next k lines of bytes [current screen size]* */ if (precount > 0) z_line = precount; to_print = z_line; break; case '\r': case '\n': /* Display next k lines of text [current screen size]* */ if (precount > 0) r_line = precount; to_print = r_line; break; case 'q': case 'Q': cleartoeol(); fclose(curr_file); reset_tty(); exit(exval); case ':' : switch (colon) { case 'f': prompt = 0; if (!no_intty) PRINTF("\"%s\" line %lu", name, (unsigned long)(bytepos - out_len)); else PRINTF("[Not a file] line %lu", (unsigned long)(bytepos - out_len)); fflush(stdout); break; case 'n': if (precount < 1) precount = 1; do_next(precount); PRINTF("\r"); cleartoeol(); PRINTF("\n...Skipping to file %s\r\n\r\n", name); prompt = 2; break; case 'p': if (precount < 1) precount = 1; do_next(-precount); PRINTF("\r"); cleartoeol(); PRINTF("\n...Skipping back to file %s\r\n\r\n", name); prompt = 2; break; case 'q': cleartoeol(); fclose(curr_file); reset_tty(); exit(exval); break; case '!': if (!no_intty) { cleartoeol(); if (rdline(colon, estring)) break; doshell(estring); PRINTF("------------------------\r\n"); break; } default: bmbeep(); } break; case '!': if (!no_intty) { cleartoeol(); if (rdline(ch, estring)) break; doshell(estring); PRINTF("------------------------\r\n"); break; } case 'd': /* Scroll k lines [current scroll size, initially 11]* */ case BVICTRL('D'): if (precount > 0) d_line = precount; to_print = d_line; break; case BVICTRL('L'): /*** REDRAW SCREEN ***/ if (no_intty) { bmbeep(); } else { clearscreen(); to_print = maxy + 1; fseek(curr_file, screen_home, SEEK_SET); bytepos = screen_home; } break; case 'b': /* Skip backwards k screenfuls of text [1] */ case BVICTRL('B'): if (no_intty) { bmbeep(); } else { if (precount < 1) precount = 1; PRINTF("...back %ld page", precount); if (precount > 1) { PRINTF("s\r\n"); } else { PRINTF("\r\n"); } screen_home -= (maxy + 1) * out_len; if (screen_home < 0) screen_home = 0; fseek(curr_file, screen_home, SEEK_SET); bytepos = screen_home; to_print = maxy + 1; } break; case 'f': /* Skip forward k screenfuls of bytes [1] */ case 's': /* Skip forward k lines of bytes [1] */ if (precount < 1) precount = 1; if (ch == 'f') { count = maxy * precount; } else { count = precount; } putchar('\r'); cleartoeol(); PRINTF("\n...skipping %ld line", count); if (count > 1) { PRINTF("s\r\n\r\n"); } else { PRINTF("\r\n\r\n"); } screen_home += (count + maxy) * out_len; fseek(curr_file, screen_home, SEEK_SET); bytepos = screen_home; to_print = maxy; break; case '\\': if (ascii_flag) { bmbeep(); break; } case '/': /**** Search String ****/ if (!repeat) { cleartoeol(); if (rdline(ch, sstring)) break; } case 'n': /**** Search Next ****/ case 'N': bmsearch(ch); /* to_print--; */ break; case '\'': if (no_intty) { bmbeep(); } else { bytepos = last_search; fseek(curr_file, bytepos, SEEK_SET); screen_home = bytepos; to_print = maxy; PRINTF("\r"); cleartoeol(); PRINTF("\n\r\n***Back***\r\n\r\n"); } break; case '=': prompt = 0; cleartoeol(); PRINTF("%lX hex %lu dec", (unsigned long)bytepos, (unsigned long)bytepos); fflush(stdout); break; case '?': case 'h': if ((help_file = fopen(helppath, "r")) == NULL) { emsg("Can't open help file"); break; } while ((ch1 = getc(help_file)) != EOF) putchar(ch1); fclose(help_file); to_print = 0; break; case 'w': case 'v': if (!no_intty) { cleartoeol(); if (ch == 'v') { sprintf(string, "bvi +%lu %s", (unsigned long)(screen_home + (maxy + 1) / 2 * out_len), name); } else { if (precount < 1) precount = bytepos - screen_home; sprintf(string, "bvi -b %lu -s %lu %s", (unsigned long)screen_home, (unsigned long)precount, name); } doshell(string); to_print = maxy + 1; break; } default : if (d_flag) { emsg("[Press 'h' for instructions.]"); } else { bmbeep(); } break; } if (to_print) { if (printout(to_print)) { do_next(1); } } } while (1); } int rdline(ch, sstring) int ch; char *sstring; { int i = 0; int ch1 = 0; char bstring[MAXCMD]; if (ch == '!') { strcpy(bstring, sstring); sstring[0] = '\0'; } putchar(ch); fflush(stdout); while (i < MAXCMD) { ch1 = vgetc(); if (ch1 == '\n' || ch1 == '\r' || ch1 == ESC) { break; } else if (ch1 == 8) { if (i) { sstring[--i] = '\0'; PRINTF("\r%c%s", ch, sstring); cleartoeol(); } else { ch1 = ESC; break; } } else if (ch1 == '!' && i == 0) { if (bstring[0] == '\0') { emsg("No previous command"); return 1; } putchar(ch1); PRINTF("\r%c%s", ch, bstring); strcat(sstring, bstring); i = strlen(sstring); } else { putchar(ch1); sstring[i++] = ch1; } fflush(stdout); } if (ch1 == ESC) { putchar('\r'); cleartoeol(); return 1; } if (i) sstring[i] = '\0'; return 0; } void do_next(n) int n; { if (numfiles) { if (n == 1 && file_nr == numfiles) { fclose(curr_file); reset_tty(); exit(exval); } if ((file_nr + n) > numfiles) file_nr = numfiles; else if ((file_nr + n) < 1) file_nr = 1; else file_nr += n; prompt = 2; free(name); name = strdup(*(files + file_nr - 1)); } else { fclose(curr_file); reset_tty(); exit(exval); } } int open_file(name) char *name; { struct stat buf; if (stat(name, &buf) > -1) { filesize = buf.st_size; } if (curr_file != NULL) fclose(curr_file); if (numfiles > 1) do_header = 1; if ((curr_file = fopen(name, "rb")) == NULL) { perror(name); exval = 1; return 1; } bytepos = screen_home = 0; return 0; } void putline(buf, num) char *buf; int num; { int print_pos; unsigned char ch; PRINTF(addr_form, (unsigned long)bytepos); for (print_pos = 0; print_pos < num; print_pos++) { ch = buf[print_pos]; if (!ascii_flag) { PRINTF("%02X ", ch); } ++bytepos; if ((ch > 31) && (ch < 127)) *(string + print_pos) = ch; else *(string + print_pos) = '.'; } for (; print_pos < out_len; print_pos++) { if (!ascii_flag) { PRINTF(" "); } ++bytepos; *(string + print_pos) = ' '; } *(string + num) = '\0'; if (no_tty) PRINTF("%s\n", string); else PRINTF("%s\r\n", string); } int printout(lns) int lns; { int c, num; int doub = 0; static int flag; if (c_flag) { clearscreen(); } if (do_header) { if (no_tty) { PRINTF("::::::::::::::\n%s\n::::::::::::::\n", name); } else { PRINTF("\r"); cleartoeol(); PRINTF("::::::::::::::\r\n%s\r\n::::::::::::::\r\n", name); } do_header = 0; corr = 2; } if (corr && (lns > maxy - 2)) lns -= corr; corr = 0; do { for (num = 0; num < out_len; num++) { if ((c = nextchar()) == -1) break; buffer1[num] = c; } if (!num) return 1; if (memcmp(buffer1, buffer2, num) || !bytepos ) { memcpy(buffer2, buffer1, num); putline(buffer2, num); if (!no_tty) flag = TRUE; lns--; } else { if (flag) { cleartoeol(); PRINTF("*\r\n"); lns--; } else { doub++; } flag = FALSE; bytepos += num; } if (lns == 0) { screen_home = bytepos - ((maxy + 1 + doub) * out_len); if (screen_home < 0) screen_home = 0; return 0; } } while(num); return 1; } int nextchar() { if (cnt == 0) return fgetc(curr_file); cnt--; return cmdbuf[icnt++] & 0xff; } void pushback(n, where) int n; char *where; { if (cnt) memmove(cmdbuf + n, cmdbuf, n); memcpy(cmdbuf, where, n); icnt = 0; cnt += n; } /* Return: * -1 EOF * 0 not found at current position * 1 found */ int bmregexec(scan) char *scan; { char *act; int count, test; int l; char act_pat[MAXCMD]; /* found pattern */ act = act_pat; l = 0; while (*scan != 0) { if ((test = nextchar()) == -1) return -1; *act++ = test; if (++l == MAXCMD) { pushback(l, act_pat); return 0; } if (ignore_case && smode == ASCII) test = toupper(test); switch (*scan++) { case ONE: /* exactly one character */ count = *scan++; if (count == 1) { if (test != *scan) { bytepos++; if (l > 1) pushback(--l, act_pat + 1); return 0; } scan++; } else if (count > 1) { if (sbracket(test, scan, count)) { bytepos++; if (l > 1) pushback(--l, act_pat + 1); return 0; } scan += count; } break; case STAR: /* zero or more characters */ count = *scan++; if (count == 1) { /* only one character, 0 - n times */ while (test == *scan) { if ((test = nextchar()) == -1) return -2; *act++ = test; if (++l == MAXCMD) { pushback(l, act_pat); return 0; } if (ignore_case && smode == ASCII) test = toupper(test); } pushback(1, --act); l--; scan++; } else if (count > 1) { /* characters in bracket */ if (*scan == '^') { do { /* If we found something matching the next part of the expression, we * abandon the search for not-matching characters. */ if (bmregexec(scan + count)) { *act++ = test; /* May be wrong case !! */ l++; scan += count; bytepos--; break; } if (sbracket(test, scan, count)) { bytepos++; if (l > 1) pushback(--l, act_pat + 1); return 0; } else { if ((test = nextchar()) == -1) return -3; *act++ = test; if (++l == MAXCMD) { pushback(l, act_pat); return 0; } if (ignore_case && smode == ASCII) test = toupper(test); } } while(1); } else { while(!sbracket(test, scan, count)) { if ((test = nextchar()) == -1) return -4; *act++ = test; if (++l == MAXCMD) { pushback(l, act_pat); return 0; } if (ignore_case && smode == ASCII) test = toupper(test); } scan += count; pushback(1, --act); l--; } } else { /* ".*" */ do { if ((test = nextchar()) == -1) return -5; *act++ = test; if (++l == MAXCMD) { pushback(l, act_pat); return 0; } pushback(1, act - 1); bytepos--; } while (bmregexec(scan) == 0); bytepos++; act--; l--; } break; } } pushback(l, act_pat); return 1; /* found */ } int sbracket(start, scan, count) int start; char *scan; int count; { if (*scan++ == '^') { if (!memchr(scan, start, --count)) return 0; } else { if (memchr(scan, start, --count)) return 0; } return 1; } void bmsearch(ch) int ch; { int i; if (sstring[0] == '\0') { emsg("No previous regular expression"); return; } if (ch == '/') { if (ascii_comp(search_pat, sstring)) return; } if (ch == '\\') { if (hex_comp(search_pat, sstring)) return; } oldpos = bytepos; last_search = screen_home; if (precount < 1) precount = 1; while (precount--) { while ((i = bmregexec(search_pat)) == 0); if (i == 1) { screen_home = bytepos; to_print = maxy; } else { /* i == -1 -> EOF */ if (no_intty) { PRINTF("\r\nPattern not found\r\n"); do_next(1); } else { /* sprintf(string, "Pattern not found %d - %ul", i, (unsigned long)bytepos); emsg(string); */ emsg("Pattern not found"); bytepos = oldpos; fseek(curr_file, bytepos, SEEK_SET); break; } } if (precount) { nextchar(); bytepos++; } } if (prompt) { PRINTF("\r\n...skipping\r\n"); } } void emsg(s) char *s; { putchar('\r'); cleartoeol(); highlight(); PRINTF(s); normal(); fflush(stdout); prompt = 0; } void bmbeep() { putchar(7); }