home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
-
- 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 <eric@snark.thyrsus.com> 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 <stdio.h>
- #include <string.h>
- #include <signal.h>
- #include <ctype.h>
- #include <assert.h>
- #ifdef ATT
- #include <termio.h>
- #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, CTL('Q')}, {21, 27, CTL('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 (A_BUTTON_CHANGED & 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();
- #ifndef OLDCURSES
- (void)flushinp();
- #endif /* OLDCURSES */
- #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 (linbuf[0] == '=' || 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();
- #ifndef OLDCURSES
- (void)keypad(stdscr, TRUE);
- #endif /* BSD */
- #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 != CTL('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 OLDCURSES
- case KEY_HELP: /* go to help screen */
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_REFRESH: /* redraw screen */
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_NPAGE: /* page forward */
- #endif /* OLDCURSES */
- 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 OLDCURSES
- case KEY_PPAGE: /* page back */
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_UP:
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_DOWN:
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_ENTER: /* accept keyboard input */
- #endif /* OLDCURSES */
- case CTL('J'):
- case CTL('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 OLDCURSES
- case KEY_REFERENCE: /* chase reference */
- #endif /* OLDCURSES */
- 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 OLDCURSES
- case KEY_RIGHT: /* next reference */
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_LEFT: /* previous reference */
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_FIND: /* search for string */
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_SFIND: /* search for last string again */
- #endif /* OLDCURSES */
- case CTL('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(CTL('J'));
- }
- #endif /* POPUP */
- break;
-
- #ifndef OLDCURSES
- case KEY_SELECT: /* search for entry */
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_HOME: /* go to beginning of file */
- case KEY_BEG:
- #endif /* OLDCURSES */
- case CTL('A'):
- enqueue(cf);
- restore_select = FALSE;
- cf->toppos = 0;
- break;
-
- #ifndef OLDCURSES
- case KEY_END: /* go to end of file */
- #endif /* OLDCURSES */
- case CTL('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 OLDCURSES
- case KEY_UNDO: /* backtrack into the location stack */
- #endif /* OLDCURSES */
- 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 OLDCURSES
- case KEY_PRINT: /* append selected entry to file */
- #endif /* OLDCURSES */
- case CTL('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 BUTTON1_PRESSED: /* 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 BUTTON1_RELEASED: /* 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 BUTTON3_PRESSED: /* right button down; backtrack */
- restore_select = TRUE;
- dequeue(cf);
- break;
-
- case BUTTON3_RELEASED: /* 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, dofilter = FALSE;
- bool 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 'f':
- dofilter = 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 && !dofilter
- && 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 (dofilter)
- {
- daddr_t pos;
- char batchkey[81];
-
- if (!initbrowse(dbname))
- exit(1);
-
- while (fgets(batchkey, sizeof(batchkey) - 1, stdin) != (char *)NULL)
- {
- char *ep = &batchkey[strlen(batchkey) - 1];
-
- if (*ep == '\n')
- {
- *ep = '\0';
- if (*--ep == '\r')
- *ep = '\0';
- }
- 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 */
-