Category : C Source Code
Archive   : VH_JARGO.ZIP
Filename : BROWSE.C

 
Output of file : BROWSE.C contained in archive : VH_JARGO.ZIP
/*****************************************************************************

NAME
browse.c -- curses(3)-using display front end for vh database browser

SYNOPSIS
main(argc, argv) --- browser main sequence
int argc; char *argv[][];

DESCRIPTION
This module defines the main and browse loop for the vh browser;
all user-interface decisions are made here. Screen, keyboard and
mouse handling support may be found in screen.c.

AUTHORS
Written by Eric S. Raymond for a UNIX
port of the 1.1 version of Raymond Gardner's MS-DOS browser, October
1991. Please see the source distribution's READ.ME for license
terms.

*****************************************************************************/
/*LINTLIBRARY*/
#include
#include
#include
#include
#include
#ifdef ATT
#include
#endif /* ATT */

#include "screen.h"
#include "vh.h"

#ifndef CONST
#define const
#endif /* CONST */

#ifdef MSDOS
/* emulate Borland-style scrollbar */
#define SBARCH ACS_CKBOARD /* scrollbar character */
#define SBARTOPCH 30 /* scrollbar up arrow */
#define SBARBOTCH 31 /* scrollbar down arrow */
#else
/* approximate X-style scrollbar */
#define SBARCH ACS_VLINE /* scrollbar character */
#define SBARTOPCH ACS_TTEE /* scrollbar up arrow */
#define SBARBOTCH ACS_BTEE /* scrollbar down arrow */
#endif
#define SBARTHUMBCH ACS_BULLET /* scrollbar thumb character */

#ifdef A_COLOR
#define NORMPAIR 1
#define HILITEPAIR 2
#define SELPAIR 3
#define PROMPTPAIR 4
#define FKEYPAIR 5
#define SBARPAIR 6
#define SBARENDPAIR 7
#define SBTHUMBPAIR 8
#endif /* A_COLOR */

#define SUPPRESS 0
#define OPTIONAL 1
#define FORCED 2

#ifndef UNIX
#define erasechar() BS
#endif /* UNIX */

#define CUTFILE "%s.cut"

/*
* When paging forward or back, it helps the reader to page by a few less
* lines than the page depth, so a few of the old ones show to give context.
* This controls how many old lines will show.
*/
#define OVERLAP 4

/* dialogue/message window parameters */
#define DTOP 10
#define DLEFT 10
#define DHEIGHT 7
#define DWIDTH 42

/*******************************************************************
*
* All message texts declared here for internationalization purposes
*
******************************************************************/

#ifdef MSDOS
#define USAGE "usage: jargon [-cigms] [-b key] [srcname] [indexname]\n\
-c --- check textfile/index pair for consistency\n\
-i --- enable incremental-lookup and search\n\
-g --- generate new index from textfile\n\
-m --- force monochrome operation\n\
-s --- compensate for snowy EGA monitor\n\
-b --- write single entry specified by following key to stdout\n\
-r --- display random entry\n"
#define TBANNER "TAB-Index F1-help F10-exit"
#define IBANNER "TAB-Text F1-help F10-exit"
#else
#define USAGE "usage: jargon [-cigmr] [-b key] [srcname] [indexname]\n"
#define TBANNER "TAB-Index ^Q-help ^C-exit"
#define IBANNER "TAB-Text ^Q-help ^C-exit"
#endif
typedef struct
{
int left; /* left boundary of pushbutton */
int right; /* right boundary of pushbutton */
char cmd; /* command character associated with pushbutton */
}
strip;
static strip panel[] = {{0, 8, TAB}, {11, 17, CTRL('Q')}, {21, 27, CTRL('C')}};
#define PANELSTART (COLS - 1 - strlen((cf==&vhi) ? IBANNER : TBANNER) + 1)

#define NOREFS "No references on this page"
#define NOSRCH "No previous search"
#define CUTNOP "Can't open cut file"
#define CUTNOW "Cutting to jargon.cut..."
#define CUTDNE "Cutting to jargon.cut...Done"

#define BRSMES "Browsing %s...\n"
#define IDXMES "Generating index for %s...\n"
#define CHKMES "Performing consistency check for %s...\n"

/*
* These have to be declared static, not macros; we use the address of the
* current prompt as a mode indicator.
*/
const static char NOMESG[] = " ";
#ifndef POPUP
/* we want these fixed-length so the entry line looks good */
const static char SEARCH[] = "String search for: ";
const static char INSRCH[] = "Search proceeding: ";
const static char NOTFND[] = "Search failed: ";
const static char LOOKUP[] = "Looking up entry: ";
const static char LOOKING[] = "Lookup in progress:";
#else
/* the popup windows will get sized to these */
const static char SEARCH[] = "String search for";
const static char INSRCH[] = "Search proceeding";
const static char NOTFND[] = "Search failed";
const static char LOOKUP[] = "Looking up entry";
const static char LOOKING[] = "Lookup in progress";
const static char BDLOOK[] = "Lookup failed";
#endif /* POPUP */

const static char *help_screen[] =
{
" Jargon File Browser v. 1.5",
" Copyright 1991 by Raymond D. Gardner & Eric S. Raymond",
" All Rights Reserved; Free Redistribution Encouraged",
"",
" ^L redraw screen (Refresh)",
"",
" space page forward (PgDn)",
" ^U page back (PgUp)",
" ^N / ^P scroll forward / back (Down/Up Arrow)",
" ^A / ^O go to top / end of file (Home/End)",
"",
" ^J or ^M chase highlighted reference (Reference)",
" ^F / ^B next/previous reference (Right / Left Arrow)",
"",
" ^E lookup entry by name (Select)",
" ^S search for string (Find)",
" ^R repeat previous search (Shift-Find)",
#ifdef UNIX /* keypad() seems to disable recognition of ESC */
" ^H undo last search or lookup (Undo)",
#else
" ^H or ESC undo last search or lookup (Undo)",
#endif
"",
" ^I toggle between word list and text (Tab)",
" ^Y append selected entry to cut file (Print)",
"",
" Typing an entry name followed by Enter works like an ^E command.",
" Press any key to return to the browser.",
NULL,
};

/*******************************************************************
*
* Shared global data
*
******************************************************************/

static char *execname; /* name under which program was invoked */
static FILEINFO *cf; /* pointer to current fileinfo block */

/* highlights */
static chtype normattr, hiliteattr, selattr, promptattr, fkeyattr, sbarattr;
static chtype sbarendattr, sbthumbattr;

static char lasthit[LNSZ + 1]; /* last key searched for */
static char linbuf[LNSZ + 1]; /* line input scratch buffer */
#ifdef POPUP
static WINDOW *dwin; /* dialogue & message window */
#endif /* POPUP */
static bool incrsearch; /* do incremental search? */

/*******************************************************************
*
* Message and dialogue code
*
******************************************************************/

static void waitforit(requeue)
/* wait for keystroke or mouse click */
bool requeue;
{
int c;
#ifdef MOUSE
int hsy, hsx;

/* wait for keypress or button click */
while ((c = egetch()) == KEY_MOUSE)
if (BUT_CHANGE & mouse_status(&hsy, &hsx))
break;
#else
c = egetch();
#endif /* MOUSE */
if (requeue)
ungetch(c);
}

#if defined(POPUP) && defined(CURSES)
static void draw_box(win, ty,tx, by,bx)
/* draw a box on the screen using best possible forms chars */
WINDOW *win;
int ty, tx, by, bx;
{
int j;

mvwaddch(win, ty, tx, ACS_ULCORNER);
mvwaddch(win, by, bx, ACS_LRCORNER);
mvwaddch(win, by, tx, ACS_LLCORNER);
mvwaddch(win, ty, bx, ACS_URCORNER);
wmove(win, ty, tx+1);
for (j = tx + 1; j <= bx - 1; j++)
waddch(win, ACS_HLINE);
wmove(win, by, tx+1);
for (j = tx + 1; j <= bx - 1; j++)
waddch(win, ACS_HLINE);
for (j = ty + 1; j <= by - 1; j++)
{
wmove(win, j, tx);
waddch(win, ACS_VLINE);
}
for (j = ty + 1; j <= by - 1; j++)
{
wmove(win, j, bx);
waddch(win, ACS_VLINE);
}
wrefresh(win);
}

static char *get_dialogue(prompt)
/* get string from user, with prompts */
char *prompt;
{
static char buf[MAXCOLS + 1];

if (prompt == (char *)NULL)
{
delwin(dwin);
dwin = (WINDOW *)NULL;
}
else
{
/* create a dialogue window */
if (dwin == (WINDOW *)NULL)
dwin = newwin(DHEIGHT, DWIDTH, DTOP, DLEFT);

wclear(dwin);

draw_box(dwin, 0, 0, DHEIGHT-1, DWIDTH-1);
draw_box(dwin, 2, 1, DHEIGHT-3, DWIDTH-2);

wattron(dwin, A_BOLD);
mvwaddstr(dwin, 1, 10, prompt);
wattroff(dwin, A_BOLD);

echo();
mvwgetstr(dwin, 3, 3, buf);
noecho();

return(buf);
}
}
#endif /* defined(POPUP) && defined(CURSES) */

static void message(s)
/* write message to prompt line */
char *s;
{
#ifndef POPUP
attrset(promptattr);
mvaddstr(LINES-1, 0, s);
attrset(normattr);
refresh();
#else
WINDOW *mwin;

if (dwin)
{
mvwaddstr(dwin, 5, 10, NOMESG);
wattron(dwin, A_BOLD);
mvwaddstr(dwin, 5, 10, s);
wattroff(dwin, A_BOLD);
wrefresh(dwin);
}
else
{
mwin = newwin(3, strlen(s) + 2, DTOP, DLEFT);
wclear(mwin);
draw_box(mwin, 0, 0, 2, strlen(s) + 1);

wattron(mwin, A_BOLD);
mvwaddstr(mwin, 1, 1, s);
wattroff(mwin, A_BOLD);
wrefresh(mwin);

waitforit(TRUE);

overwrite(stdscr, mwin);
delwin(mwin);
touchline(DTOP, stdscr);
wrefresh(stdscr);
}
#endif /* POPUP */
}

/*******************************************************************
*
* The browser itself
*
******************************************************************/

static void uninitbrowse(doclear)
/* end the browse, either normally or due to signal */
bool doclear;
{
mouse_hide();
if (doclear)
{
clear();
refresh();
}
#ifdef CURSES
/* weird sex with the tty driver */
(void)resetterm();
(void)echo();
(void)flushinp();
#endif /* CURSES */
(void)endwin();
exit(0);
}

static void paintselect(rp, attr)
/* turn highlight on a selection on or off */
region *rp; /* which to highlight */
chtype attr; /* attribute to use */
{
int x, y;

attrset(attr);
if (rp->yl == rp->yr)
{
move(rp->yl, rp->xl);
for (x = rp->xl; x <= rp->xr; x++)
addch(inch() & A_CHARTEXT);
}
else
{
int c, lastnsp;

/* don't highlight trailing spaces on line-wrapped references */
for (lastnsp = COLS - 1; lastnsp > 0; lastnsp--)
{
move(rp->yl, lastnsp);
if ((inch() & A_CHARTEXT) != ' ')
break;
}

/* write trailing-line part of highlight */
move(rp->yl, rp->xl);
for (x = rp->xl; x <= lastnsp; x++)
addch(inch() & A_CHARTEXT);

/* highlight everything *between* 1st and last lines in region */
for (y = rp->yl + 1; y < rp->yr; y++)
{
move(y, x);
for (x = 0; x < COLS - 1; x++)
addch(inch() & A_CHARTEXT);
}

/* don't highlight leading spaces on line-wrapped references */
for (x = 0; x <= COLS - 1; x++)
{
move(rp->yr, x);
if ((inch() & A_CHARTEXT) != ' ')
break;
}

/* write leading-line part of highlight */
move(rp->yr, x);
for (; x <= rp->xr; x++)
addch(inch() & A_CHARTEXT);
}
attrset(normattr);
}

static bool chase(x, y, isindex)
/* try to chase a link at this location */
int x, y;
bool isindex;
{
long pos; /* find target */
int dummy;

enqueue(cf); /* make sure we can un-chase it */

pos = iflink(x, y, &dummy, &dummy, isindex);
if (pos <= 0)
{
dequeue(cf);
return(FALSE);
}
else
{
if (isindex) /* if index, switch to text */
{
cf = vht;
cf->dsptoppos = cf->dspnextpos = NOWHERE;
}

cf->toppos = pos; /* set for new display */
return(TRUE);
}
}


static bool search(str, c)
/* search for given string in file */
char *str;
{
int i;

message(INSRCH);
enqueue(cf);
if (c)
cf->hitpos = ifind(cf->fp, cf->dspnextpos, c);
else
cf->hitpos = ffind(cf->fp, cf->dspnextpos, str);
if (cf->hitpos == NOWHERE)
{
message(NOTFND);
dequeue(cf);
return(FALSE);
}
else
{
/* else display hit on fourth line */
cf->toppos = cf->hitpos;
for (i = 0; i < OVERLAP; i++)
cf->toppos = getprevln(cf->fp, cf->toppos, linbuf);
if (str != lasthit)
(void) strcpy(lasthit, str);
return(TRUE);
}
}

static bool lookup(str, c)
/* search for given entry in file */
char *str, c;
{
long pos; /* find target */

enqueue(cf);

if (c)
pos = ilocate(c);
else
{
message(LOOKING);
pos = xlocate(str);
}

if (cf == &vhi) /* if index, switch to text */
{
cf = vht;
cf->dsptoppos = cf->dspnextpos = cf->endpos;
}

if (pos < 0)
{
cf->toppos = -pos; /* set for new display */
return(FALSE);
}
else
{
cf->toppos = pos; /* set for new display */
return(TRUE);
}
}

static daddr_t byname(prompt, str, c)
/* search or lookup given entry in file, depending on prompt value */
char *prompt, *str, c;
{
if (prompt == SEARCH)
return(search(str, c));
else
return(lookup(str, c));
}

/* entry buffer for lookup and search commands */
static char entrybuf[LNSZ + 1];
static int entrycnt = 0;

static void enterchar(c, prompt, row, col, maxcol)
/* accept a character into the entry buffer */
char c;
char *prompt;
int row, col;
int maxcol;
{
int es;

if (c == '\0')
{
entrybuf[entrycnt = 0] = '\0';
return;
}

es = col + strlen(prompt);
attrset(promptattr);
if (c == erasechar())
{
if (entrycnt > 0)
{
mvaddch(row, es + --entrycnt, ' ');
entrybuf[entrycnt] = '\0';
move(row, es + entrycnt);
ilocate(BS);
if (incrsearch)
dequeue(cf);
}
}
#ifdef CURSES
else if (c == killchar())
{
/* delete everything back to the end of the prompt */
while (entrycnt > 0)
{
mvaddch(row, es + --entrycnt, ' ');
entrybuf[entrycnt] = '\0';
move(row, es + entrycnt);
if (incrsearch)
dequeue(cf);
}
ilocate(DEL);
}
#endif /* CURSES */
else if (isprint(c))
{
mvaddstr(row, col, prompt);
if (es + entrycnt < maxcol
&& (!incrsearch || byname(prompt, (char *)NULL, c) != NOWHERE))
{
mvaddch(row, es + entrycnt, c);
entrybuf[entrycnt++] = c;
entrybuf[entrycnt] = '\0';
}
else if (c == '\0')
entrybuf[entrycnt = 0] = '\0';
else
beep();
}
attrset(normattr);

refresh();
}

static void cutentry(pos, fp)
/* send the text of the entry starting at pos to the gin file pointer */
daddr_t pos;
FILE *fp;
{
(void) fseek(vht->fp, pos, SEEK_SET);

/* always want first line */
(void) fgets(linbuf, LNSZ, vht->fp);
(void) fputs(linbuf, fp);

/* copy succeeding lines till we get to next entry */
while (fgets(linbuf, LNSZ, vht->fp) != (char *)NULL)
if (headword(linbuf))
break;
else
(void) fputs(linbuf, fp);
}

static char *nblanks(n)
/* blank-string return for fast fills; return up to 132 = MAXCOLS */
int n;
{
/* MAXCOLS+1 blanks */
const static char blanks[] = " ";
return(&blanks[sizeof(blanks) - 1 - n]);
}

static void browse(name, cok)
/* interactive browser loop */
char *name;
bool cok;
{
int i, c;
char **hp;
bool restore_select = FALSE;
FILE *cutfp;
int lightup = FORCED;
#ifdef MOUSE
int hsy, hsx, mstat; /* mouse hot spot coordinates */
bool thumbdrag = FALSE; /* are we in a thumbdrag? */
#endif /* MOUSE */
#ifndef POPUP
char *prompt = NOMESG;
#else
char *cp;
#endif /* POPUP */
#ifdef ATT
struct termio tty;
int saveintr;
#endif /* ATT */

if (!initbrowse(name))
exit(1);
cf = vht;

#ifdef UNIX
(void) signal(SIGINT,uninitbrowse);
(void) signal(SIGQUIT,uninitbrowse);
(void) signal(SIGTERM,uninitbrowse);
(void) signal(SIGIOT,uninitbrowse); /* for assert(3) */
#ifdef ATT
(void) ioctl(0, TCGETA, &tty);
saveintr = tty.c_cc[VINTR];
#endif /* ATT */
#endif /* UNIX */

(void) initscr();
setlastpage();

#ifdef A_COLOR
if (cok = (cok && has_colors()))
{
start_color();

init_pair(NORMPAIR, COLOR_WHITE, COLOR_BLUE);
init_pair(HILITEPAIR, COLOR_RED, COLOR_WHITE);
init_pair(SELPAIR, COLOR_YELLOW, COLOR_BLUE);
init_pair(PROMPTPAIR, COLOR_BLACK, COLOR_CYAN);
init_pair(FKEYPAIR, COLOR_RED, COLOR_CYAN);
init_pair(SBARPAIR, COLOR_WHITE, COLOR_BLACK);
init_pair(SBARENDPAIR, COLOR_BLUE, COLOR_WHITE);
init_pair(SBTHUMBPAIR, COLOR_BLUE, COLOR_BLACK);
}
mouse_color(cok);

normattr = cok ? (COLOR_PAIR(NORMPAIR) | A_BOLD) : A_NORMAL;
hiliteattr = cok ? COLOR_PAIR(HILITEPAIR) : A_REVERSE;
selattr = cok ? (COLOR_PAIR(SELPAIR) | A_BOLD) : A_BOLD;
promptattr = cok ? COLOR_PAIR(PROMPTPAIR) : A_REVERSE;
fkeyattr = cok ? COLOR_PAIR(FKEYPAIR) : A_BOLD;
#ifndef MSDOS
sbarendattr = sbthumbattr =
sbarattr = cok ? COLOR_PAIR(SBARPAIR) : A_NORMAL;
#else
sbarattr = cok ? COLOR_PAIR(SBARPAIR) : A_REVERSE;
sbarendattr = cok ? (COLOR_PAIR(SBARENDPAIR) | A_BOLD) : A_REVERSE;
sbthumbattr = cok ? (COLOR_PAIR(SBTHUMBPAIR) | A_BOLD) : A_NORMAL;
#endif
#else
normattr = A_NORMAL;
hiliteattr = A_REVERSE;
selattr = A_BOLD;
promptattr = A_REVERSE;
fkeyattr = A_BOLD;
sbarendattr = sbthumbattr =
sbarattr = A_NORMAL;
#ifdef MSDOS
sbarattr = A_REVERSE;
sbarendattr = A_REVERSE;
sbthumbattr = A_NORMAL;
#endif /* MSDOS */
#endif /* A_COLOR */

mouse_init();
#ifdef MOUSE
mouse_move(LINES - 1, COLS - 1);
#endif /* MOUSE */

#ifdef CURSES
(void)saveterm();
(void)nonl();
(void)raw();
(void)noecho();
(void)keypad(stdscr, TRUE);
#endif /* CURSES */

#ifdef ATT
(void) ioctl(0, TCGETA, &tty);
tty.c_cc[VINTR] = saveintr;
tty.c_iflag |= BRKINT;
tty.c_iflag &=~ IGNBRK;
tty.c_lflag |= ISIG;
(void) ioctl(0, TCSETA, &tty);
#endif /* ATT */

lasthit[0] = '\0';

for (c = KEY_REFRESH; c != CTRL('C') && c != KEY_EXIT; c = egetch())
{
#ifdef DEBUG
if (isprint(c))
(void) fprintf(stderr, "command: %c\n", c);
else if (iscntrl(c))
(void) fprintf(stderr, "command: ^%c\n", c + '@');
else if (c >= 0x80 & c <= 0x9f)
(void) fprintf(stderr, "command: M-^%c\n", (c &~ 0x80) + '@');
else if (c >= 0x80)
(void) fprintf(stderr, "command: M-%c\n", c &~ 0x80);
else
(void) fprintf(stderr, "command: 0x%02x\n", c);
#endif /* DEBUG */

switch(c)
{
#ifdef MSDOS
case KEY_F(10):
(void) ungetch(KEY_EXIT);
break;
#endif /* MSDOS */

#ifndef BSD
case KEY_HELP: /* go to help screen */
#endif /* BSD */
case CTRL('Q'):
#ifdef MSDOS
case KEY_F(1):
#endif /* MSDOS */
restore_select = TRUE;
i = 0;
for (hp = help_screen; *hp; hp++)
{
mvaddstr(i++, 0, *hp);
addstr(nblanks(COLS - strlen(*hp)));
}
refresh();
cf->dsptoppos = NOWHERE;
waitforit(FALSE);
/* FALL THROUGH */

#ifndef BSD
case KEY_REFRESH: /* redraw screen */
#endif /* BSD */
case CTRL('L'):
restore_select = TRUE;
#ifdef CURSES
clearok(stdscr, TRUE);
#endif /* CURSES */
break;

case SP:
restore_select = FALSE;
#ifndef POPUP
if (prompt != NOMESG)
goto medialspace;
/* FALL THROUGH */
#endif /* POPUP */

#ifndef BSD
case KEY_NPAGE: /* page forward */
#endif /* BSD */
pagefwd:
enqueue(cf);
restore_select = FALSE;
for (i = 0; i < LINES - OVERLAP; i++)
{
if (cf->toppos == cf->lastpagetoppos)
break;
cf->toppos = getnextln(cf->fp, cf->toppos, linbuf);
}
if (cf->sel.xl != NOPLACE)
{
cf->sel.yl -= i; cf->sel.yr -= i;
if (!(restore_select = (cf->sel.yl >= 0)))
cf->sel.xl = NOPLACE;
}
break;

#ifndef BSD
case KEY_PPAGE: /* page back */
#endif /* BSD */
case CTRL('U'):
pagebak:
enqueue(cf);
restore_select = FALSE;
for (i = 0; i < LINES - OVERLAP; i++)
{
if (cf->toppos == 0)
break;
cf->toppos = getprevln(cf->fp, cf->toppos, linbuf);
}
if (cf->sel.xl != NOPLACE)
{
cf->sel.yl += i; cf->sel.yr += i;
if (!(restore_select = (cf->sel.yr < LINES - 1)))
cf->sel.xl = NOPLACE;
}
break;

#ifndef BSD
case KEY_UP:
#endif /* BSD */
case CTRL('N'):
linebak:
restore_select = FALSE;
if (cf->toppos)
{
cf->toppos = getprevln(cf->fp, cf->toppos, linbuf);
if (cf->sel.xl != NOPLACE)
{
cf->sel.yl++; cf->sel.yr++;
if (!(restore_select = (cf->sel.yr < LINES - 1)))
cf->sel.xl = NOPLACE;
}
}
break;

#ifndef BSD
case KEY_DOWN:
#endif /* BSD */
case CTRL('P'):
linefwd:
restore_select = FALSE;
if (cf->toppos < cf->lastpagetoppos)
{
cf->toppos = getnextln(cf->fp, cf->toppos, linbuf);
if (cf->sel.xl != NOPLACE)
{
cf->sel.yl--; cf->sel.yr--;
if (!(restore_select = (cf->sel.yl >= 0)))
cf->sel.xl = NOPLACE;
}
}
break;

#ifndef BSD
case KEY_ENTER: /* accept keyboard input */
#endif /* BSD */
case CTRL('J'):
case CTRL('M'):
lightup = FORCED;
#ifndef POPUP
restore_select = FALSE;
if (prompt == SEARCH || prompt == LOOKUP)
{
if (!incrsearch && byname(prompt, entrybuf, '\0') == NOWHERE)
beep();
enterchar('\0', LOOKUP, LINES - 1, 0, PANELSTART);
prompt = NOMESG;
break;
}
/* nothing in prompt buffer, no search active: FALL THROUGH */
#endif /* POPUP */

#ifndef BSD
case KEY_REFERENCE: /* chase reference */
#endif /* BSD */
restore_select = FALSE;
if (cf->sel.xl == NOPLACE) /* any link? */
{
message(NOREFS);
continue;
}
else
(void) chase(cf->sel.xl, cf->sel.yl, cf == &vhi);
break;

#ifndef BSD
case KEY_RIGHT: /* next reference */
#endif /* BSD */
case CTRL('F'):
restore_select = FALSE;
if (cf->sel.xl == NOPLACE)
message(NOREFS);
else
{
paintselect(&cf->sel, (cf == &vhi) ? normattr : selattr);
cf->sel = findnextsel(cf->sel.xl, cf->sel.yl, cf == &vhi);
paintselect(&cf->sel, hiliteattr);
}
refresh();
continue;

#ifndef BSD
case KEY_LEFT: /* previous reference */
#endif /* BSD */
case CTRL('B'):
restore_select = FALSE;
if (cf->sel.xl == NOPLACE)
message(NOREFS);
else
{
paintselect(&cf->sel, (cf == &vhi) ? normattr : selattr);
/*
* The -1 offset on xsel is important. It insures that
* when findprevsel() starts looking for a previous
* tag, it doesn't find the current one again.
*/
cf->sel = findprevsel(cf->sel.xl-1, cf->sel.yl, cf == &vhi);
paintselect(&cf->sel, hiliteattr);
}
refresh();
continue;

#ifndef BSD
case KEY_FIND: /* search for string */
#endif /* BSD */
case CTRL('S'):
restore_select = FALSE;
#ifndef POPUP
prompt = SEARCH;
#else
if (cp = get_dialogue(SEARCH))
if (search(cp, '\0') != NOWHERE)
{
get_dialogue((char *)NULL);
break;
}
else
continue;
#endif /* POPUP */
break;

#ifndef BSD
case KEY_SFIND: /* search for last string again */
#endif /* BSD */
case CTRL('R'):
restore_select = FALSE;
if (lasthit[0] == '\0')
{
message(NOSRCH);
continue;
}
else
#ifdef POPUP
(void) search(lasthit, '\0');
#else
{
prompt = SEARCH;
(void) strcpy(entrybuf, lasthit);
entrycnt = strlen(lasthit);
(void) ungetch(CTRL('J'));
}
#endif /* POPUP */
break;

#ifndef BSD
case KEY_SELECT: /* search for entry */
#endif /* BSD */
case CTRL('E'):
lookfor:
restore_select = FALSE;
#ifndef POPUP
prompt = LOOKUP;
#else
if (cp = get_dialogue(LOOKUP))
{
if (lookup(cp, '\0') == NOWHERE)
beep();
get_dialogue((char *)NULL);
break;
}
#endif /* POPUP */
break;

#ifndef BSD
case KEY_HOME: /* go to beginning of file */
case KEY_BEG:
#endif /* BSD */
case CTRL('A'):
enqueue(cf);
restore_select = FALSE;
cf->toppos = 0;
break;

#ifndef BSD
case KEY_END: /* go to end of file */
#endif /* BSD */
case CTRL('O'):
enqueue(cf);
restore_select = FALSE;
cf->toppos = cf->lastpagetoppos;
break;

case BS: /* this is context-sensitive */
#ifndef POPUP
if (prompt != NOMESG)
goto medialspace;
/* FALL THROUGH */
#endif /* POPUP */

#ifndef BSD
case KEY_UNDO: /* backtrack into the location stack */
#endif /* BSD */
case ESC:
restore_select = TRUE;
dequeue(cf);
break;

case TAB: /* toggle between text and index */
restore_select = TRUE;
vhi.dsptoppos = vht->dsptoppos = NOWHERE;
if (cf == vht)
cf = &vhi;
else
cf = vht;
break;

#ifndef BSD
case KEY_PRINT: /* append selected entry to file */
#endif /* BSD */
case CTRL('Y'):
restore_select = FALSE;
(void) sprintf(linbuf, CUTFILE, execname);
if (cf->sel.xl == NOPLACE)
{
message(NOREFS);
continue;
}
else if ((cutfp = fopen(linbuf, "a")) == (FILE *)NULL)
{
message(CUTNOP);
continue;
}
else
{
long pos; /* find target */
int dummy;

message(CUTNOW);

pos = iflink(cf->sel.xl, cf->sel.yl, &dummy,&dummy, cf == &vhi);
if (pos >= 0) /* how can this fail? */
cutentry(pos, cutfp);
(void) fclose(cutfp);

message(CUTDNE);
continue;
}
break;

#ifdef MOUSE
/*
* Note: we treat a single-button mouse as having the left
* button only.
*
* The mouse_status() function should return the key-status defines
* implied below when appropriate. It should return the zero-origin
* mouse hotspot coordinates at character-cell resolution, with
* CMDLINE and THUMBCOL as special values designating the command
* line and thumb column respectively (on character displays these
* would be LINES - 1 and COLS - 1 respectively).
*/
case KEY_MOUSE: /* mouse gesture has occurred */
mstat = mouse_status(&hsy, &hsx);
#ifndef POPUP
hsy = (hsy == LINES - 1) ? CMDLINE : hsy;
#endif /* POPUP */
switch(mstat)
{
case BUT_LEFT_DOWN: /* left button down; chase link, else page */
restore_select = FALSE;
if (hsy == CMDLINE) /* clicked on entry line */
{
hsx -= PANELSTART;
for (i = 0; i < sizeof(panel) / sizeof(strip); i++)
if (hsx >= panel[i].left && hsx <= panel[i].right)
(void) ungetch(panel[i].cmd);
continue;
}
else if (hsx == THUMBCOL) /* click in thumb column */
{
if (hsy == 0) /* clicked top of bar */
goto linebak;
else if (hsy == LASTLINE) /* clicked bottom of bar */
goto linefwd;
else if (hsy < cf->ythumb) /* clicked above thumb */
goto pagebak;
else if (hsy > cf->ythumb) /* clicked below thumb */
goto pagefwd;
else /* clicked on the thumb */
thumbdrag = TRUE;
}
else if (!chase(hsx, hsy, cf == &vhi))
goto pagefwd; /* click in text somewhere */
break;

case BUT_LEFT_UP: /* left button up */
restore_select = FALSE;
if (thumbdrag && 0 < hsy && hsy < LASTLINE)
{
cf->toppos = /* compute new position */
cf->lastpagetoppos *
(hsy - 1) / (LASTLINE - 2);

assert(0 <= cf->toppos &&
cf->toppos <= cf->lastpagetoppos);

/* ensure on line boundary */
if (0 < cf->toppos && cf->toppos < cf->lastpagetoppos)
cf->toppos = getnextln(cf->fp, cf->toppos, linbuf);
}
thumbdrag = FALSE;
break;

case BUT_RIGHT_DOWN: /* right button down; backtrack */
restore_select = TRUE;
dequeue(cf);
break;

case BUT_RIGHT_UP: /* right button up */
/* reserved for future expansion */
break;
}
break;
#endif /* MOUSE */

default:
#ifdef POPUP
if (isprint(c))
{
(void) ungetch(c);
goto lookfor;
}
#else
medialspace:
restore_select = FALSE;
if (prompt == NOMESG)
{
ungetch(c);
goto lookfor;
}
enterchar(c, prompt, LINES - 1, 0, PANELSTART);
#endif /* POPUP */
lightup = SUPPRESS;
}

#ifndef POPUP
/* regenerate prompt */
attrset(promptattr);
move(LINES - 1, 0);
addstr(prompt);
addstr(entrybuf);
addstr(nblanks(PANELSTART - strlen(prompt) - strlen(entrybuf)));
mvaddstr(LINES - 1, PANELSTART, (cf == &vhi) ? IBANNER : TBANNER);
attrset(normattr);
#endif /* POPUP */

if (cf->toppos != cf->dsptoppos)
{
int i;
long newpos = cf->toppos;

#ifdef DEBUG
(void) fprintf(stderr,
"screen update triggered, toppos = %ld\n",
cf->toppos);
#endif /* DEBUG */

attrset(normattr);
for (i = 0; i <= LASTLINE; i++)
if ((newpos = getnextln(cf->fp, newpos, linbuf)) != NOWHERE)
{
mvaddstr(i, 0, linbuf);
/*
* This is actually faster, and creates less
* flicker, than clearing the screen.
*/
addstr(nblanks(COLS - strlen(linbuf)));
}
cf->dspnextpos = ftell(cf->fp);

#ifdef SCROLLBAR
/*
* Generate the scroll bar. Yes, we really do want the denominator
* to be lastpagetoppos and not endpos. This means the thumb only
* bottoms out if we're really at the end.
*/
cf->ythumb = 1 + cf->toppos * (LASTLINE - 2) / cf->lastpagetoppos;
assert(0 < cf->ythumb && cf->ythumb < LASTLINE);
mvaddch(0, COLS, SBARTOPCH | sbarendattr);
for (i = 1; i < LASTLINE; i++) /* set up scrollbar */
mvaddch(i, COLS, SBARCH | sbarattr);
mvaddch(LASTLINE, COLS, SBARBOTCH | sbarendattr);
mvaddch(cf->ythumb, COLS, SBARTHUMBCH | sbthumbattr);
#endif /* SCROLLBAR */
}

/*
* This has to be done whether or not lightup is going to happen.
* Otherwise, a following command may enqueue a bogus selection
* box as part of state.
*/
cf->sel = findnextsel(0, -1, cf == &vhi);

if (lightup == SUPPRESS)
lightup = OPTIONAL;
else
{
if (incrsearch)
(void) byname(prompt, (char *)NULL, DEL);

if (lightup == FORCED || cf->toppos != cf->dsptoppos)
{
lightup = OPTIONAL;

/* highlight the current select, if any */
if (restore_select && cf->sel.xl != NOPLACE)
paintselect(&cf->sel, hiliteattr); /* restore existing select */
else
{
/* highlight the first selection, if there is one */
if (cf->sel.xl != NOPLACE)
paintselect(&cf->sel, hiliteattr);
}

/* if in text, boldface all potential selects */
if (!(cf == &vhi) && cf->sel.xl != NOPLACE)
{
region hibox;

#ifdef DEBUG
(void) fprintf(stderr,
"current: x = %2d, y = %2d, pos = %ld.\n",
cf->sel.xl, cf->sel.yl, cf->toppos);
#endif /* DEBUG */
hibox.xl = cf->sel.xl;
hibox.yl = cf->sel.yl;
for (;;)
{
hibox = findnextsel(hibox.xl, hibox.yl, cf == &vhi);
#ifdef DEBUG
(void) fprintf(stderr,
"hibox: x = %2d, y = %2d.\n",
hibox.xl, hibox.yl);
#endif /* DEBUG */
if (hibox.xl == cf->sel.xl && hibox.yl == cf->sel.yl)
break;
paintselect(&hibox, selattr);
}
}
}
}

move(LINES - 1, 0);

cf->dsptoppos = cf->toppos;

refresh();
}

uninitbrowse(TRUE);
}

#ifdef MSDOS
static char *basename(s)
/* isolate base name of fully qualified filename (modifies the name passed!) */
char *s;
{
char *p;
p = strrchr(s, '.'); /* find rightmost dot */
if ( strchr(p, '\\') ) /* if a \ comes after it, find string end */
p = strchr(p, 0);
*p = 0; /* terminate at last dot after a \ (if any)*/
if ( (p = strrchr(s, '\\')) == NULL ) /* find last \ (if any) */
p = s; /* take whole string if no \ */
else
++p; /* else take string after \ */
strlwr(p);
return p;
}
#else
#define basename(x) x /* don't need to strip argv[0] under UNIX */
#endif /* MSDOS */

/*******************************************************************
*
* Main sequence
*
******************************************************************/

main(argc, argv)
int argc;
char **argv;
{
char *dbname, *batchkey = NULL;
int i;
bool doindex = FALSE, docheck = FALSE, forcemono = FALSE, atrandom = FALSE;

execname = argv[0];
while ((++argv, --argc) && *argv[0] == '-')
for (i = 1; argv[0][i]; i++)
switch(argv[0][i])
{
case 'b':
batchkey = argv[1];
break;

case 'c':
docheck = TRUE;
break;

case 'g':
doindex = TRUE;
break;

case 'i':
incrsearch = TRUE;
break;

case 'm':
forcemono = TRUE;
break;

case 'r':
atrandom = TRUE;
break;

#ifdef __TURBOC__
case 's':
{ /* if CGA that snows: */
extern bool has_snowy_CGA;
has_snowy_CGA = TRUE;
}
break;
#endif /* __TURBOC__ */

default:
(void) fprintf(stderr, USAGE);
exit(1);
}

#ifdef DEBUG
(void) freopen("ERRLOG", "w", stderr);
#endif /* DEBUG */

/*
* User specified a batch-retrieval option.
* OK, snarf the keyword from the next argument.
*/
if (batchkey)
++argv, --argc;

dbname = argc ? argv[0] : basename(execname);

if (!doindex && !docheck && !atrandom && batchkey == (char *)NULL)
{
(void) printf(BRSMES, dbname);
browse(dbname, !forcemono);
}

if (doindex)
{
(void) printf(IDXMES, dbname);
if (argc)
mkindex(argc, argv);
else
mkindex(1, &dbname);
}

if (docheck)
{
(void) printf(CHKMES, dbname);
chkindex(dbname);
}

if (batchkey)
{
daddr_t pos;

if (!initbrowse(dbname))
exit(1);

if ((pos = xlocate(batchkey)) >= 0)
cutentry(pos, stdout);
}

if (atrandom)
{
daddr_t pos;

if (!initbrowse(dbname))
exit(1);

if ((pos = jrandom()) >= 0)
cutentry(pos, stdout);
}

exit(0);
}

/* browse.c ends here */


  3 Responses to “Category : C Source Code
Archive   : VH_JARGO.ZIP
Filename : BROWSE.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/