1
0
Fork 0
mirror of https://github.com/vbatts/bvi.git synced 2024-11-22 08:35:42 +00:00
bvi/bmore.c

871 lines
17 KiB
C
Raw Normal View History

2001-01-15 00:00:00 +00:00
/* 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-02-18 00:00:00 +00:00
* 2002-01-16 V 1.3.1
2001-01-15 00:00:00 +00:00
*
* NOTE: Edit this file with tabstop=4 !
*
2002-02-18 00:00:00 +00:00
* Copyright 1990-2002 by Gerhard Buergmann
2001-01-15 00:00:00 +00:00
* Gerhard.Buergmann@altavista.net
*
* 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 <sys/types.h>
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
#ifdef __MSDOS__
# define PRINTF cprintf
#else
# define PRINTF printf
#ifndef HELPFILE
2002-02-18 00:00:00 +00:00
# define HELPFILE "/usr/local/share/bmore.help"
2001-01-15 00:00:00 +00:00
#endif
#endif
#include "bmore.h"
2002-02-18 00:00:00 +00:00
char *copyright = "Copyright (C) 1990-2002 by Gerhard Buergmann";
2001-01-15 00:00:00 +00:00
int maxx, maxy;
char *name = NULL;
2002-02-18 00:00:00 +00:00
char sstring[MAXCMD] = ""; /* string for search */
char estring[MAXCMD] = ""; /* string for shell escape */
2001-01-15 00:00:00 +00:00
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 d_flag = 0;
int init_search = 0;
char buffer1[MAXCMD], buffer2[MAXCMD];
int out_len;
int corr = 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;
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
* -i ignore case
*/
void
usage()
{
fprintf(stderr, "Usage: %s [-adi] [+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;
#ifdef __MSDOS__
char *poi;
strcpy(helppath, argv[0]);
poi = strrchr(helppath, '\\');
*poi = '\0';
strcat(helppath, "\\MORE.HLP");
#else
strncpy(helppath, HELPFILE, MAXCMD - 1);
#endif
#ifdef HAVE_LOCALE_H
setlocale(LC_ALL, "");
#endif
progname = argv[0];
while (n < argc) {
switch (argv[n][0]) {
case '-':
i = 1;
while (argv[n][i] != '\0') {
switch (argv[n][i]) {
case 'a': ascii_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;
}
}
if (numfiles == 0) {
curr_file = stdin;
if (isatty(fileno(stdin)) != 0) usage();
} else {
open_file(name);
file_nr = 1;
fseek(curr_file, init_byte, SEEK_SET);
bytepos += init_byte;
}
screen_home = bytepos;
initterm();
set_tty();
maxy -= 2;
z_line = maxy;
d_line = maxy / 2;
r_line = 1;
AnzAdd = 10;
strcpy(addr_form, "%08lX ");
if (ascii_flag)
2002-02-18 00:00:00 +00:00
out_len = ((maxx - AnzAdd - 1) / 4) * 4;
2001-01-15 00:00:00 +00:00
else
out_len = ((maxx - AnzAdd - 1) / 16) * 4;
if (init_search)
bmsearch(init_search);
if (no_tty) {
while(!printout(1));
2002-02-18 00:00:00 +00:00
fclose(curr_file);
2001-01-15 00:00:00 +00:00
reset_tty();
exit(0);
}
if (printout(maxy)) {
do_next(1);
}
/* main loop */
do {
to_print = 0;
if (prompt) {
highvideo();
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]");
normvideo();
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':
clreol();
2002-02-18 00:00:00 +00:00
fclose(curr_file);
2001-01-15 00:00:00 +00:00
reset_tty();
exit(0);
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");
clreol();
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");
clreol();
PRINTF("\n...Skipping back to file %s\r\n\r\n", name);
prompt = 2;
break;
case 'q':
clreol();
2002-02-18 00:00:00 +00:00
fclose(curr_file);
2001-01-15 00:00:00 +00:00
reset_tty();
exit(0);
break;
case '!':
if (!no_intty) {
clreol();
2002-02-18 00:00:00 +00:00
if (rdline(colon, estring)) break;
doshell(estring);
2001-01-15 00:00:00 +00:00
PRINTF("------------------------\r\n");
break;
}
default:
2002-02-18 00:00:00 +00:00
bmbeep();
2001-01-15 00:00:00 +00:00
}
break;
2002-02-18 00:00:00 +00:00
case '!':
if (!no_intty) {
clreol();
if (rdline(ch, estring)) break;
doshell(estring);
PRINTF("------------------------\r\n");
break;
}
2001-01-15 00:00:00 +00:00
case 'd': /* Scroll k lines [current scroll size, initially 11]* */
2002-02-18 00:00:00 +00:00
case BVICTRL('D'):
2001-01-15 00:00:00 +00:00
if (precount > 0) d_line = precount;
to_print = d_line;
break;
2002-02-18 00:00:00 +00:00
case BVICTRL('L'): /*** REDRAW SCREEN ***/
2001-01-15 00:00:00 +00:00
if (no_intty) {
2002-02-18 00:00:00 +00:00
bmbeep();
2001-01-15 00:00:00 +00:00
} else {
clrscr();
to_print = maxy + 1;
fseek(curr_file, screen_home, SEEK_SET);
bytepos = screen_home;
}
break;
case 'b': /* Skip backwards k screenfuls of text [1] */
2002-02-18 00:00:00 +00:00
case BVICTRL('B'):
2001-01-15 00:00:00 +00:00
if (no_intty) {
2002-02-18 00:00:00 +00:00
bmbeep();
2001-01-15 00:00:00 +00:00
} 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');
clreol();
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) {
2002-02-18 00:00:00 +00:00
bmbeep();
2001-01-15 00:00:00 +00:00
break;
}
case '/': /**** Search String ****/
if (!repeat) {
2002-02-18 00:00:00 +00:00
clreol();
if (rdline(ch, sstring)) break;
2001-01-15 00:00:00 +00:00
}
case 'n': /**** Search Next ****/
case 'N':
bmsearch(ch);
/*
to_print--;
*/
break;
case '\'':
if (no_intty) {
2002-02-18 00:00:00 +00:00
bmbeep();
2001-01-15 00:00:00 +00:00
} else {
bytepos = last_search;
fseek(curr_file, bytepos, SEEK_SET);
screen_home = bytepos;
to_print = maxy;
PRINTF("\r");
clreol();
PRINTF("\n\r\n***Back***\r\n\r\n");
}
break;
case '=':
prompt = 0;
clreol();
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) {
clreol();
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 {
2002-02-18 00:00:00 +00:00
bmbeep();
2001-01-15 00:00:00 +00:00
}
break;
}
if (to_print) {
if (printout(to_print)) {
do_next(1);
}
}
} while (1);
}
int
2002-02-18 00:00:00 +00:00
rdline(ch, sstring)
int ch;
char *sstring;
2001-01-15 00:00:00 +00:00
{
2002-02-18 00:00:00 +00:00
int i = 0;
int ch1 = 0;
char bstring[MAXCMD];
if (ch == '!') {
strcpy(bstring, sstring);
sstring[0] = '\0';
}
2001-01-15 00:00:00 +00:00
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);
clreol();
} else {
ch1 = ESC;
break;
}
2002-02-18 00:00:00 +00:00
} 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);
2001-01-15 00:00:00 +00:00
} else {
putchar(ch1);
sstring[i++] = ch1;
}
fflush(stdout);
}
if (ch1 == ESC) {
putchar('\r');
clreol();
return 1;
}
if (i) sstring[i] = '\0';
return 0;
}
void
do_next(n)
int n;
{
if (numfiles) {
if (n == 1 && file_nr == numfiles) {
2002-02-18 00:00:00 +00:00
fclose(curr_file);
2001-01-15 00:00:00 +00:00
reset_tty();
exit(0);
}
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 {
2002-02-18 00:00:00 +00:00
fclose(curr_file);
2001-01-15 00:00:00 +00:00
reset_tty();
exit(0);
}
}
void
open_file(name)
char *name;
{
struct stat buf;
if (stat(name, &buf) > -1) {
filesize = buf.st_size;
}
if (numfiles > 1) {
PRINTF("\r");
clreol();
PRINTF("\n::::::::::::::\r\n%s\r\n::::::::::::::\r\n", name);
corr = 2;
}
if (curr_file != NULL) fclose(curr_file);
if ((curr_file = fopen(name, "rb")) == NULL) {
2002-02-18 00:00:00 +00:00
/* reset_tty(); */
2001-01-15 00:00:00 +00:00
perror(name);
exit(1);
}
bytepos = screen_home = 0;
}
void
putline(buf, num)
char *buf;
int num;
{
int print_pos;
unsigned char ch;
PRINTF(addr_form, 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) = '.';
}
2002-02-18 00:00:00 +00:00
for (; print_pos < out_len; print_pos++) {
if (!ascii_flag) {
PRINTF(" ");
}
++bytepos;
*(string + print_pos) = ' ';
}
2001-01-15 00:00:00 +00:00
*(string + num) = '\0';
PRINTF("%s\r\n", string);
}
int
printout(lns)
int lns;
{
int c, num;
int doub = 0;
static int flag;
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) {
clreol();
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 {
2002-02-18 00:00:00 +00:00
/*
2001-01-15 00:00:00 +00:00
sprintf(string, "Pattern not found %d - %ul", i, (unsigned long)bytepos);
emsg(string);
*/
2002-02-18 00:00:00 +00:00
emsg("Pattern not found");
2001-01-15 00:00:00 +00:00
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');
clreol();
highvideo();
PRINTF(s);
normvideo();
fflush(stdout);
prompt = 0;
}
2002-02-18 00:00:00 +00:00
void
bmbeep() {
putchar(7);
}