bvi/bvi.c

1057 lines
22 KiB
C

/* BVI - Binary Visual Editor
*
* 1996-02-28 V 1.0.0
* 1999-01-27 V 1.1.0
* 1999-04-22 V 1.1.1
* 1999-07-01 V 1.2.0 beta
* 1999-10-22 V 1.2.0 final
* 2000-05-10 V 1.3.0 alpha
* 2000-10-24 V 1.3.0 final
* 2002-01-03 V 1.3.1
* 2004-01-04 V 1.3.2
* 2006-04-04 V 1.3.3
* 2013-08-23 V 1.4.0alpha
* 2014-10-07 V 1.4.0
* 2019-10-12 V 1.4.1
*
* NOTE: Edit this file with tabstop=4 !
*
* Copyright 1996-2019 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 3, 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>
#include "bvi.h"
#include "set.h"
#ifdef HAVE_LOCALE_H
# include <locale.h>
#endif
char *copyright = "(C) GPL 1996-2019 by Gerhard Buergmann";
jmp_buf env; /* context for `longjmp' function */
int loc;
int maxx, maxy, x, xx, y;
int screen, status, statsize;
off_t size;
PTR mem = NULL;
PTR curpos;
PTR maxpos;
PTR pagepos;
PTR spos;
char *name = NULL;
char *shell;
char string[MAXCMD+1];
char cmdstr[MAXCMD+1] = "";
FILE *Ausgabe_Datei;
int edits = 0;
int AnzAdd, Anzahl, Anzahl3;
off_t filesize, memsize, undosize;
long precount = -1;
int block_flag = 0;
off_t block_begin, block_end, block_size;
char **files; /* list of input files */
int numfiles; /* number of input files */
int curfile; /* number of the current file */
int arrnum = 0;
char numarr[MAXCMD+1]; /* string for collecting number */
char rep_buf[BUFFER];
PTR current;
PTR last_motion;
PTR current_start;
PTR undo_start;
off_t undo_count;
off_t yanked = 0L;
char *yank_buf = NULL;
char *undo_buf = NULL;
char *fname_buf = NULL;
PTR markbuf[26];
char addr_form[15];
char *nobytes = "No bytes@in the buffer";
static char progname[8];
static char line[MAXCMD+1];
static int mark;
static int wrstat = 1;
void
usage()
{
fprintf(stderr, "Usage: %s [-R] [-c cmd | +cmd] [-f script]\n\
[-s skip] [-e end] [-n length] file ...\n\
file offset/size: 10k, 20m, 1g, 0x1000 hex, 0200 octal\n", progname);
exit(1);
}
int
main(argc, argv)
int argc;
char *argv[];
{
int ch;
int lflag;
long count;
int n = 1;
int script = -1;
off_t inaddr;
char *poi;
#ifdef HAVE_LOCALE_H
setlocale(LC_ALL, "");
#endif
poi = strrchr(argv[0], DELIM);
if (poi) strncpy(progname, ++poi, 7);
else strncpy(progname, argv[0], 7);
strtok(progname, ".");
if (!strcasecmp(progname, "bview")) {
params[P_RO].flags |= P_CHANGED;
P(P_RO) = TRUE;
} else if (!strcasecmp(progname, "bvedit")) {
/* This should be the beginners version */
}
while (n < argc) {
switch (argv[n][0]) {
case '-':
if (argv[n][1] == 'R') {
params[P_RO].flags |= P_CHANGED;
P(P_RO) = TRUE;
} else if (argv[n][1] == 'c') {
if (argv[n + 1] == NULL) {
usage();
} else {
strcpy(cmdstr, argv[++n]);
}
} else if (argv[n][1] == 'f') {
if (argv[n + 1] == NULL || argv[n + 1][0] == '-') {
usage();
} else {
script = ++n;
}
} else if (argv[n][1] == 's') {
if (argv[n + 1] == NULL || argv[n + 1][0] == '-') {
usage();
} else {
block_begin = calc_size(argv[++n]);
block_flag |= BLOCK_BEGIN;
}
} else if (argv[n][1] == 'e') {
if (argv[n + 1] == NULL || argv[n + 1][0] == '-') {
usage();
} else {
block_end = calc_size(argv[++n]);
block_flag |= BLOCK_END;
}
} else if (argv[n][1] == 'n') {
if (argv[n + 1] == NULL || argv[n + 1][0] == '-') {
usage();
} else {
block_size = calc_size(argv[++n]);
block_flag |= BLOCK_LEN;
}
} else if (argv[n][1] == 'w') {
if (argv[n][2] == '\0') {
usage();
} else {
params[P_LI].flags |= P_CHANGED;
P(P_LI) = atoi(argv[n] + 2);
}
} else usage();
n++;
break;
case '+': /* +cmd */
if (argv[n][1] == '\0') {
strcpy(cmdstr, "$");
} else {
strcpy(cmdstr, &argv[n][1]);
}
n++;
break;
default: /* must be a file name */
name = strdup(argv[n]);
files = &(argv[n]);
numfiles = argc - n;
n = argc;
break;
}
}
/* TODO default block_size - end of file up to max 64 KB with warning */
switch (block_flag) {
case BLOCK_BEGIN:
/* Acc. to SF-Error 3036881 we should use the whole rest of the file */
/*
block_size = 1024;
block_end = block_begin + block_size - 1;
*/
break;
case BLOCK_END:
block_begin = 0;
block_size = block_end - block_begin + 1;
break;
case BLOCK_BEGIN|BLOCK_END:
block_size = block_end - block_begin + 1;
break;
case BLOCK_LEN:
block_begin = 0;
block_end = block_begin + block_size - 1;
break;
case BLOCK_BEGIN|BLOCK_LEN:
block_end = block_begin + block_size - 1;
break;
case BLOCK_END|BLOCK_LEN:
block_begin = block_end + 1 - block_size;
break;
case BLOCK_BEGIN|BLOCK_END|BLOCK_LEN:
if (block_end - block_begin != block_size + 1) {
fprintf(stderr, "Ambigous block data\n");
exit(1);
}
break;
}
if (block_flag && !numfiles) {
fprintf(stderr, "Cannot read a range of a nonexisting file\n");
exit(1);
}
if (numfiles > 1) fprintf(stderr, "%d files to edit\n", numfiles);
curfile = 0;
/****** Initialisation of curses ******/
initscr();
attrset(A_NORMAL);
maxy = LINES;
if (params[P_LI].flags & P_CHANGED) maxy = P(P_LI);
P(P_SS) = maxy / 2;
P(P_LI) = maxy;
maxy--;
keypad(stdscr, TRUE);
scrollok(stdscr, TRUE);
nonl();
cbreak();
noecho();
/* address column width */
/* default is 8 + 2 blanks */
/* if block_begin has 8 hex digits or more */
/* reserve 1 hex digit more than required */
char tmp[sizeof(block_begin) * 2 + 3];
AnzAdd = sprintf(tmp, "%llX", (long long unsigned)block_begin) + 1;
if (AnzAdd < 8)
AnzAdd = 8;
if (AnzAdd > sizeof(block_begin) * 2)
AnzAdd = sizeof(block_begin) * 2;
sprintf(addr_form, "%%0%dllX ", AnzAdd);
AnzAdd = sprintf(tmp, addr_form, block_begin);
Anzahl = ((COLS - AnzAdd - 1) / 16) * 4;
P(P_CM) = Anzahl;
maxx = Anzahl * 4 + AnzAdd + 1;
Anzahl3 = Anzahl * 3;
statsize = 35;
status = Anzahl3 + Anzahl - statsize;
screen = Anzahl * (maxy - 1);
signal(SIGINT, SIG_IGN);
filesize = load(name);
bvi_init(argv[0]);
params[P_TT].svalue = terminal;
if (block_flag && (P(P_MM) == TRUE)) {
P(P_MM) = FALSE;
params[P_TT].flags |= P_CHANGED;
}
if (script > -1)
read_rc(argv[script]);
if (*cmdstr != '\0')
docmdline(cmdstr);
msg(fname_buf);
/* main loop */
do {
setjmp(env);
current = (PTR)(pagepos + y * Anzahl + xpos());
if (wrstat) statpos();
wrstat = 1;
setcur();
ch = vgetc();
while (ch >= '0' && ch <= '9') {
if (arrnum < MAXCMD) numarr[arrnum++] = ch;
ch = vgetc();
}
numarr[arrnum] = '\0';
if (arrnum != 0) precount = strtoll(numarr, (char **)NULL, 10);
else precount = -1;
lflag = arrnum = 0;
switch (ch) {
case '^': x = AnzAdd;
loc = HEX;
break;
/*
case '0': x = AnzAdd + Anzahl3;
loc = ASCII;
break;
*/
case '$': x = AnzAdd - 1 + Anzahl3 + Anzahl;
loc = ASCII;
break;
case '\t': toggle();
break;
case '~': if (precount < 1) precount = 1;
sprintf(rep_buf, "%ld~", precount);
do_tilde((off_t)precount);
lflag++;
break;
case KEY_HOME:
case 'H': if (precount > 0) {
y = --precount;
if (y > maxy - 1) {
scrolldown(y - maxy + 1);
y = maxy - 1; }
} else y = 0;
if (loc == HEX) x = AnzAdd;
else x = AnzAdd + Anzahl3;
break;
case 'M': y = maxy / 2;
if ((PTR)(pagepos + screen) > maxpos)
y = (int)(maxpos - pagepos) / Anzahl / 2;
if (loc == HEX) x = AnzAdd;
else x = AnzAdd + Anzahl3;
break;
case KEY_LL:
case 'L': if (precount < 1) precount = 1;
n = maxy - 1;
if ((PTR)((pagepos + screen)) > maxpos)
n = (int)(maxpos - pagepos) / Anzahl;
if (precount < n) y = n + 1 - precount;
if (loc == HEX) x = AnzAdd;
else x = AnzAdd + Anzahl3;
break;
case BVICTRL('H'):
case ASCII_DEL:
case KEY_BACKSPACE:
case KEY_LEFT:
case 'h': do {
if (x > (AnzAdd + 2) && x < (Anzahl3 + AnzAdd + 1))
x -= 3;
else
if (x > (Anzahl3 + AnzAdd - 2)) x--;
} while (--precount > 0);
if (x < AnzAdd + Anzahl3) loc = HEX;
else loc = ASCII;
break;
case ' ':
case KEY_RIGHT:
case 'l': do {
/*
if (x < (Anzahl3 + 6)) x += 3;
*/
if (x < (Anzahl3 + AnzAdd - 2)) x += 3;
else if (x > (Anzahl3 + 3)
&& x < (Anzahl3 + AnzAdd - 1 + Anzahl))
x++;
} while (--precount > 0);
if (x < AnzAdd + Anzahl3) loc = HEX;
else loc = ASCII;
break;
case '-':
case KEY_UP :
case 'k': do {
if (y > 0) y--;
else scrollup(1);
} while(--precount > 0);
break;
case '+':
case CR: if (loc == HEX) x = AnzAdd;
else x = AnzAdd + Anzahl3;
case 'j':
case BVICTRL('J'):
case BVICTRL('N'):
case KEY_DOWN:
do {
if ((PTR)((pagepos + (y + 1) * Anzahl)) > maxpos) break;
if (y < (maxy - 1)) y++;
else scrolldown(1);
} while(--precount > 0);
break;
case '|': if (precount < 1) break;
if (loc == ASCII) x = AnzAdd - 1 + Anzahl3 + precount;
else x = 5 + 3 * precount;
if (x > AnzAdd - 1 + Anzahl3 + Anzahl) {
x = AnzAdd - 1 + Anzahl3 + Anzahl;
loc = ASCII; }
break;
case ':' : clearstr();
addch(ch);
refresh();
getcmdstr(cmdstr, 1);
if (strlen(cmdstr))
docmdline(cmdstr);
break;
case BVICTRL('B'):
case KEY_PPAGE: /**** Previous Page ****/
if (mem <= (PTR)(pagepos - screen)) pagepos -= screen;
else pagepos = mem;
repaint();
break;
case BVICTRL('D'):
if (precount > 1) P(P_SS) = precount;
scrolldown(P(P_SS));
break;
case BVICTRL('U'):
if (precount > 1) P(P_SS) = precount;
scrollup(P(P_SS));
break;
case BVICTRL('E'):
if (y > 0) y--;
scrolldown(1);
break;
case BVICTRL('F'):
case KEY_NPAGE: /**** Next Page *****/
if (maxpos >= (PTR)(pagepos + screen)) {
pagepos += screen;
current += screen;
if (current - mem >= filesize) {
current = mem + filesize;
setpage((PTR)(mem + filesize - 1L));
}
repaint();
}
break;
case BVICTRL('G'):
fileinfo(name);
wrstat = 0;
break;
case BVICTRL('L'): /*** REDRAW SCREEN ***/
new_screen();
break;
case BVICTRL('Y'):
if (y < maxy - 1) y++;
scrollup(1);
break;
case 'A': smsg("APPEND MODE");
current = (PTR)(mem + filesize - 1L);
setpage(current++);
cur_forw(0);
setcur();
undosize = filesize;
undo_count = edit(ch);
break;
case 'B':
case 'b': setpage(backsearch(current, ch));
break;
case 'e': setpage(end_word(current));
break;
case ',': do_ft(-1, 0);
break;
case ';': do_ft(0, 0);
break;
case 'F':
case 'f':
case 't':
case 'T': do_ft(ch, 0);
break;
case 'G': last_motion = current;
if (precount > -1) {
if ((precount < P(P_OF)) ||
(precount - P(P_OF)) > (filesize - 1L)) {
beep();
} else {
setpage((PTR)(mem + precount - P(P_OF)));
}
} else {
setpage((PTR)(mem + filesize - 1L));
}
break;
case 'g': last_motion = current;
clearstr();
outmsg("Goto Hex Address:");
refresh();
getcmdstr(cmdstr, 18);
clearstr();
if (cmdstr[0] == '^') {
inaddr = P(P_OF);
} else if (cmdstr[0] == '$') {
inaddr = filesize + P(P_OF) - 1L;
} else {
off_t ltmp;
sscanf(cmdstr, "%llx", (long long unsigned *)&ltmp);
inaddr = ltmp;
}
if (inaddr < P(P_OF)) break;
inaddr -= P(P_OF);
if (inaddr < filesize) {
setpage(mem + inaddr);
} else {
if (filesize == 0L) break;
sprintf(string, "Max. address of current file : %06llX", (long long unsigned)(filesize - 1L + P(P_OF)));
emsg(string);
}
break;
case '?':
case '/': /**** Search String ****/
case '#':
case '\\': clearstr();
addch(ch);
refresh();
if (getcmdstr(line, 1)) break;
last_motion = current;
hl_spat = P(P_HL);
searching(ch, line, current, maxpos - 1, P(P_WS));
if (hl_spat) {
repaint();
}
break;
case ESC: /* un-highlight */
hl_spat = FALSE;
repaint();
break;
case 'n': /**** Search Next ****/
case 'N': last_motion = current;
hl_spat = P(P_HL);
searching(ch, "", current, maxpos - 1, P(P_WS));
if (hl_spat) {
repaint();
}
break;
case 'm': do_mark(vgetc(), current);
break;
case '\'':
case '`': if ((ch == '`' && loc == ASCII) ||
(ch == '\'' && loc == HEX))
toggle();
mark = vgetc();
if (mark == '`' || mark == '\'') {
setpage(last_motion);
last_motion = current;
} else {
if (mark < 'a' || mark > 'z') {
beep(); break;
} else if (markbuf[mark - 'a'] == NULL) {
beep(); break;
}
setpage(markbuf[mark - 'a']);
}
break;
case 'D': if (precount < 1) precount = 1;
sprintf(rep_buf, "%ldD", precount);
trunc_cur();
break;
case 'o': /* overwrite: this is an overwriting put */
if (precount < 1) precount = 1;
sprintf(rep_buf, "%ldo", precount);
do_over(current, yanked, yank_buf);
break;
case 'P':
if (precount < 1) precount = 1;
if ((undo_count = alloc_buf(yanked, &undo_buf)) == 0L)
break;
sprintf(rep_buf, "%ldP", precount);
if (do_append((off_t)yanked, yank_buf)) break;
/* we save it not for undo but for the dot command
memcpy(undo_buf, yank_buf, yanked);
*/
repaint();
break;
case 'r':
case 'R': if (filesize == 0L) break;
if (precount < 1) precount = 1;
sprintf(rep_buf, "%ld%c", precount, ch);
undo_count = edit(ch);
lflag++;
break;
case 'u': do_undo();
break;
case 'W':
case 'w': // loc = ASCII;
setpage(wordsearch(current, ch));
break;
case 'y': count = range(ch);
if (count > 0) {
/*
sprintf(string, "$%ld$", (long)yanked);
msg(string);
vgetc();
*/
if ((yanked = alloc_buf((off_t)count, &yank_buf)) == 0L) {
break;
}
memcpy(yank_buf, current, yanked);
} else if (count < 0) {
if ((yanked = alloc_buf(-(off_t)count, &yank_buf)) == 0L) {
break;
}
memcpy(yank_buf, current, yanked);
} else {
break;
}
/*
sprintf(string, "%ld bytes yanked", labs(count));
msg(string);
*/
break;
case 'z': do_z(vgetc());
break;
case 'Z': if (vgetc() == 'Z') do_exit();
else beep();
break;
case '.':
if (!strlen(rep_buf)) {
beep();
} else {
stuffin(rep_buf);
}
break;
default :
if P(P_MM) {
if (precount < 1) precount = 1;
switch (ch) {
case 'I':
sprintf(rep_buf, "%ldI", precount);
current = mem;
setpage(mem);
repaint();
undo_count = edit('i');
lflag++;
break;
/* undo does not work correctly !!! */
case 's':
sprintf(rep_buf, "%lds", precount);
if (do_delete((off_t)precount, current)) break;
precount = 1;
undo_count = edit('i');
lflag++;
break;
case 'a':
if (cur_forw(1)) break;
current++;
case 'i':
sprintf(rep_buf, "%ld%c", precount, ch);
undo_count = edit(ch);
lflag++;
break;
case 'p':
sprintf(rep_buf, "%ldp", precount);
do_put(current, yanked, yank_buf);
break;
case 'c':
case 'd':
count = range(ch);
if (count > 0)
do_delete((off_t)count, current);
else if (count < 0)
do_back(-(off_t)count, current);
if (ch == 'c') {
precount = 1;
undo_count = edit('i');
lflag++;
}
break;
case 'x':
sprintf(rep_buf, "%ldx", precount);
do_delete((off_t)precount, current);
break;
case 'X':
sprintf(rep_buf, "%ldX", precount);
do_back((off_t)precount, current);
break;
default:
flushinp();
beep();
}
} else {
switch (ch) {
case 'x':
if (precount < 1) precount = 1;
if ((off_t)precount + current == maxpos) {
sprintf(rep_buf, "%ldx", precount);
do_delete((off_t)precount, current);
} else {
movebyte();
flushinp();
beep();
}
break;
case 'd':
case 'i':
case 'I':
case 'p':
case 'X':
movebyte();
default:
flushinp();
beep();
}
}
}
if (lflag) lineout();
} while (1);
}
off_t
calc_size(arg)
char *arg;
{
off_t val;
extern int errno;
char *poi;
errno = 0;
val = strtoll(arg, &poi, 0);
if (val < 0) {
fprintf(stderr, "negative begin/size/end not allowed\n");
usage();
}
if (poi == arg || errno != 0) {
/* cygwin gdb displays errno incorrectly as 0 */
fprintf(stderr, "invalid begin/size/end (hex nr 0x#, octal 0#)\n");
usage();
}
switch (*poi) {
case 'k':
case 'K': val *= 1024;
break;
case 'm':
case 'M': val *= 1048576;
break;
case 'g':
case 'G': val *= 1024*1024*1024LL;
break;
case '\0': break;
default: usage();
}
return (off_t)val;
}
void
trunc_cur()
{
undosize = filesize;
undo_count = (off_t)(maxpos - current);
undo_start = current;
filesize = pagepos - mem + y * Anzahl + xpos();
maxpos = (PTR)(mem + filesize);
if (filesize == 0L) {
emsg(nobytes);
} else cur_back();
edits = U_TRUNC;
repaint();
}
int
do_append(count, buf)
off_t count;
char *buf;
{
if (filesize + count > memsize) {
if (enlarge(count + 100L)) return 1;
}
memcpy(mem + filesize, buf, count);
undo_start = mem + filesize - 1L;
setpage(undo_start + count);
edits = U_APPEND;
undosize = filesize;
filesize += count;
maxpos += count;
return 0;
}
void
do_tilde(count)
off_t count;
{
if (filesize == 0L) return;
undo_start = current;
if (current + count > maxpos) {
beep();
return;
}
if ((undo_count = alloc_buf(count, &undo_buf)) == 0L)
return;
memcpy(undo_buf, current, undo_count);
while (count--) {
if (isupper((int)(*current))) *current = tolower((int)(*current));
else if (islower((int)(*current)))
*current = toupper((int)(*current));
current++;
cur_forw(0);
}
edits = U_TILDE;
setcur();
}
void
do_undo()
{
off_t n, tempsize;
char temp;
PTR set_cursor;
PTR s;
PTR d;
if (undo_count == 0L) {
emsg("Nothing to undo");
return;
}
set_cursor = undo_start;
switch (edits) {
case U_EDIT:
case U_TILDE:
n = undo_count;
s = undo_buf;
d = undo_start;
while (n--) {
temp = *d;
*d = *s;
*s = temp;
s++; d++;
}
break;
case U_APPEND:
case U_TRUNC:
tempsize = filesize;
filesize = undosize;
undosize = tempsize;
maxpos = (PTR)(mem + filesize);
if (filesize)
set_cursor = maxpos - 1L;
else
set_cursor = maxpos;
break;
case U_INSERT:
filesize -= undo_count;
maxpos -= undo_count;
memcpy(undo_buf, undo_start, undo_count);
memmove(undo_start, undo_start + undo_count,
maxpos - undo_start);
edits = U_DELETE;
break;
case U_BACK:
case U_DELETE:
filesize += undo_count;
maxpos += undo_count;
memmove(undo_start + undo_count, undo_start,
maxpos - undo_start);
memcpy(undo_start, undo_buf, undo_count);
edits = U_INSERT;
break;
}
setpage(set_cursor);
if (edits == U_TRUNC && undosize > filesize) cur_back();
repaint();
}
void
do_over(loc, n, buf)
PTR loc;
off_t n;
PTR buf;
{
if (n < 1L) {
emsg(nobytes);
return;
}
if (loc + n > maxpos) {
beep();
return;
}
if ((undo_count = alloc_buf(n, &undo_buf)) == 0L)
return;
undo_start = loc;
memcpy(undo_buf, loc, n);
memcpy(loc, buf, n);
edits = U_EDIT;
setpage(loc + n - 1);
repaint();
}
void
do_put(loc, n, buf)
PTR loc;
off_t n;
PTR buf;
{
if (n < 1L) {
emsg(nobytes);
return;
}
if (loc > maxpos) {
beep();
return;
}
if (filesize + n > memsize) {
if (enlarge(n + 1024)) return;
}
if ((undo_count = alloc_buf(n, &undo_buf)) == 0L)
return;
undo_start = loc + 1;
edits = U_INSERT;
filesize += n;
maxpos += n;
memmove(undo_start + n, undo_start, maxpos - loc);
memcpy(undo_start, buf, n);
setpage(loc + n);
repaint();
}
/* argument sig not used, because only SIGINT will be catched */
void
jmpproc(sig)
int sig;
{
if (P(P_EB)) beep();
repaint();
clearstr();
signal(SIGINT, SIG_IGN);
longjmp(env, 0);
}
off_t
range(ch)
int ch;
{
int ch1;
long count;
ch1 = vgetc();
while (ch1 >= '0' && ch1 <= '9') {
numarr[arrnum++] = ch1;
ch1 = vgetc();
}
numarr[arrnum] = '\0';
if (arrnum != 0) count = strtol(numarr, (char **)NULL, 10);
else count = 1;
arrnum = 0;
sprintf(rep_buf, "%ld%c%s%c", precount, ch, numarr, ch1);
switch (ch1) {
case '/': /**** Search String ****/
case '\\':
strcat(rep_buf, "\n");
clearstr();
addch(ch1);
refresh();
if (getcmdstr(line, 1)) break;
end_addr = searching(ch1, line, current, maxpos - 1, FALSE);
if (!end_addr) {
beep();
return 0;
}
return(end_addr - current);
case '?':
case '#':
strcat(rep_buf, "\n");
clearstr();
addch(ch1);
refresh();
if (getcmdstr(line, 1)) break;
start_addr = searching(ch1, line, current, maxpos - 1, FALSE);
if (!start_addr) {
beep();
return 0;
}
return(start_addr - current);
case 'f':
case 't':
precount = count;
end_addr = do_ft(ch1, 1);
if (!end_addr) {
beep();
return 0;
}
return (end_addr + 1 - current);
case 'F':
case 'T':
precount = count;
start_addr = do_ft(ch1, 1);
if (!start_addr) {
beep();
return 0;
}
return (start_addr - current);
case '$':
trunc_cur();
return 0;
case 'G':
if (count == -1) {
trunc_cur();
return 0;
} else if ((count < P(P_OF)) || (count
- (off_t)P(P_OF)) > (filesize - 1L)) {
beep();
return 0;
} else {
if (mem + count < current) {
return(mem + count - current);
} else {
return(count - (current - mem));
}
}
case ' ':
return precount;
case '`':
case '\'':
mark = vgetc();
if (mark < 'a' || mark > 'z') {
beep();
return 0;
}
end_addr = markbuf[mark - 'a'];
if (end_addr == NULL) {
beep();
return 0;
}
if (end_addr < current) {
return(end_addr - current);
} else {
return(end_addr - current + 1);
}
}
beep();
return 0;
}