[alt.sources] lq-text Full Text Retrieval Database Part 10/13

lee@sq.sq.com (Liam R. E. Quin) (03/04/91)

: cut here --- cut here --
: To unbundle, sh this file
#! /bin/sh
: part 10
echo x - lq-text/src/menu/text.c 1>&2
sed 's/^X//' >lq-text/src/menu/text.c <<'@@@End of lq-text/src/menu/text.c'
X/* Use menu interface as a simple front end to a prototype
X * text retrieval program...
X *
X * Liam R. Quin, September 11th 1989
X * 
X * $Id: text.c,v 1.7 90/10/13 03:07:14 lee Rel1-10 $
X *
X * $Log:	text.c,v $
X * Revision 1.7  90/10/13  03:07:14  lee
X * After Sabre-C.
X * 
X * Revision 1.6  90/10/04  16:28:25  lee
X * SysV compat improved.
X * 
X * Revision 1.5  90/10/03  21:33:24  lee
X * Some work to make it OK on BSD;
X * Changed BSD to CURSESX for curses diffs.
X * 
X * Revision 1.4  90/08/29  21:51:16  lee
X * lq-text browser
X * 
X * Revision 1.3  90/03/09  23:24:39  lee
X * Added first hooks for pattern menu...
X * 
X * Revision 1.1  89/10/12  04:04:50  lee
X * Initial revision
X * 
X *
X */
X
X#ifndef BSD
X#include <malloc.h>
X#endif
X#ifdef ultrix
X# include <cursesX.h>
X#else
X# include <curses.h>
X#endif
X
X#ifndef A_STANDOUT
X# include "oldcurses.h"
X#endif
X
X#include <ctype.h>
X
X#include "globals.h"
X
X#include "menu.h"
X#include "error.h"
X
X#include <sys/types.h>
X#include "fileinfo.h"
X#include "wordinfo.h"
X#include "wordrules.h"
X#include "pblock.h"
X#include "phrase.h"
X#include "emalloc.h"
X
X#ifndef KEY_LEFT
X# define KEY_LEFT '\b'
X#endif
X
Xint MenuUsed = 0; /* (sigh) */
X/* The above is needed because of a bug in "m". */
X
X/* Some handy macros */
X#ifndef new
X# define new(type) (type *) emalloc(sizeof(type))
X#endif
X
X#ifndef STREQ /* STREQ is an optimisation due to Henry Spencer, utzoo!henry */
X# define STREQ(henry,utzoo) ((*(henry)==(*(utzoo)))&&!strcmp((henry),(utzoo)))
X#endif
X
Xchar *cmdname = (char *) 0;
Xchar *progname = "[menu]";
X
X/** Unix system calls that need to be declared **/
Xextern void exit();
Xextern int unlink();
X
X/** Unix/C library functions that need to be declared **/
Xextern int strcmp();
Xextern char *getenv();
Xextern char *strrchr();
Xextern int getopt();
X
X/** Curses functions that need to be declared: **/
X#ifndef beep
X extern int beep();
X#endif
X#ifndef endwin
X extern int endwin();
X#endif
X#ifdef A_STANDOUT
X# ifndef isendwin
X  extern int isendwin(); /* only needed on V.3.2 I think */
X# endif
X#endif
X#ifndef keypad
X extern int keypad();
X#endif
X#ifndef mvwaddstr
X extern int mvwaddstr();
X#endif
X#ifndef mvwprintw
X extern int mvwprintw();
X#endif
Xextern int waddstr(), wclear(), wclrtoeol();
X#ifndef wmove
X extern int wmove();
X#endif
X#ifndef wrefresh
X extern int wrefresh();
X#endif
X#ifndef noecho
X extern int noecho();
X#endif
X#ifndef nonl
X extern int nonl();
X#endif
X#ifdef CURSESX
X extern int w32addch();
X#endif
X
X/** lqtext functions that need to be declared: **/
Xextern void SetDefaults();
X#ifndef efree
Xextern void efree();
X#endif
X
X/** libmenu functions that need to be declared **/
Xextern int UseMenuBar();
Xint AddPhrase();
Xextern t_Menu *NewMenu();
X
X/** Functions within this file that must be declared: **/
Xvoid ClearMessage(), SetMessage();
Xvoid StartCurses(), EndCurses();
Xextern int MySystem();
Xvoid ShowInstructions(), ClearInstructions();
Xvoid Usage();
Xt_MenuBar *SetUpMenus();
X
X/** **/
X
Xstatic int PhraseCount = 0;
X
Xint
Xmain(argc, argv)
X    int argc; char *argv[];
X{
X    /* (unused) extern char *optarg; */
X    /* (unused) extern int optind; */
X    /** end getopts stuff **/
X    t_MenuBar *MenuBar;
X    void SetUpScreen();
X
X    int optchar; /** start getopts stuff **/
X    int errflag = 0;
X
X    /* Make progname point to the last component of argv[0] */
X    progname = strrchr(argv[0], '/');
X    if (progname) {
X	if (*++progname == '\0') {
X	    --progname; /* No Unix filename can do this! */
X	}
X    } else {
X	progname = argv[0];
X    }
X    /* cmdname lets you say CMDNAME=`basename $0` in a shell script
X     * for better error reporting
X     */
X    cmdname = getenv("CMDNAME");
X
X    SetDefaults(argc, argv);
X
X    while ((optchar = getopt(argc, argv, "z:ZvXV")) != EOF) {
X	switch (optchar) {
X	case 'z':
X	case 'Z': /* already dealt with by Defaults */
X	    break;
X	case 'X':
X	    Usage(0);
X	    /*NOTREACHED*/
X	    break;
X	case 'V':
X	    error(ERR_FATAL, "Version: $Id: text.c,v 1.7 90/10/13 03:07:14 lee Rel1-10 $");
X	    /*NOTREACHED*/
X	    exit(1);
X	case '?':
X	    errflag++;
X	}
X    }
X    if (errflag) {
X	Usage(1);
X    }
X
X    StartCurses();
X
X    MenuBar = SetUpMenus();
X
X    SetUpScreen();
X
X    while (UseMenuBar(MenuBar) != -2) {
X	if (PhraseCount == 0) {
X	    ShowInstructions();
X	}
X    }
X
X    EndCurses();
X
X    exit(0);
X    /*NOTREACHED*/
X    return 1; /* this is for lint and gcc -Wall... */
X}
X
Xvoid
XUsage(exitstatus)
X    int exitstatus;
X{
X    if (cmdname) fprintf(stderr, "%s: ", cmdname);
X    fprintf(stderr, "%s: usage: %s [-XV]\n", progname, progname);
X    fprintf(stderr, "\t-X\t-- print this eXplanation\n");
X    fprintf(stderr, "\t-V\t-- print %s version info\n", progname);
X    exit(exitstatus);
X}
X
Xstatic int ThisCol = 0;
Xstatic int ThisRow = 5;
X
X/* A list of phrases: */
Xstatic t_Phrase *PhraseList = (t_Phrase *) 0;
X
Xint
XGetWords()
X{
X    int i;
X    char Buffer[1024];
X    char *q;
X    t_Phrase *PP;
X
X    ThisRow = 5;
X
X    if (PhraseCount && PhraseList) {
X	t_Phrase *p;
X
X	PP = PhraseList;
X
X	while (PP) {
X	    p = PP->Next;
X	    (void) efree((char *) PP);
X				/* BUG: does not free everything: NOTDONE */
X	    			/* (I need a destructor function here!!!!!) */
X	    PP = p;
X	}
X	PhraseList = (t_Phrase *) 0;
X    }
X
X    PhraseCount = 0;
X
X    for (i = 2; i < LINES; i++) {
X	move(i ,0);
X	clrtoeol();
X    }
X    SetMessage(
X	"Type the words or phrases to look for, one per line, then press F1");
X    move(ThisRow, ThisCol);
X    refresh();
X
X    q = (char *) 0;
X
X    PhraseCount = 0;
X
X    while ((i = getch()) != KEY_F(1)) {
Xdecode:
X	if (i == KEY_F(1) || (ThisCol <= 1 && i == '\004')) {
X	    break;
X	} else if (isprint(i)) {
X	    mvwaddch(stdscr, ThisRow, ThisCol, i);
X	    if (q == (char *) 0) q = Buffer;
X	    if (q - Buffer >= sizeof(Buffer)) {
X		beep();
X	    } else {
X		*q++ = i;
X		*q = '\0';
X	    }
X	    ++ThisCol;
X	} else switch (i) {
X	case 'X' ^ 64: /* contol X */
X	case 'U' ^ 64: /* ^U */
X	    /* delete to start of line */
X	    ThisCol = 0;
X	    move(ThisRow, ThisCol);
X	    clrtoeol();
X	    if (q != (char *) 0) q = Buffer;
X	    break;
X	case 'W' ^ 64: /* control-W */
X	    if (ThisCol && q && q > Buffer) {
X		*q = ' ';
X		while (ThisCol > 0 && q > Buffer && isspace(*q)) {
X		    q--;
X		    --ThisCol;
X		}
X		while (ThisCol > 0 && q > Buffer && !isspace(*q)) {
X		    q--;
X		    --ThisCol;
X		}
X		*q = '\0';
X		move(ThisRow, ThisCol);
X		clrtoeol();
X	    } else if (!ThisCol) {
X		beep();
X	    }
X	    break;
X	case '\010': /* control-h */
X	case '\177': /* DEL */
X	case 255: /* DEL */
X	    mvwaddch(stdscr, ThisRow, ThisCol, ' ');
X	    if (ThisCol > 0) {
X		--ThisCol;
X		if (q != (char *) 0 && q > Buffer) --q;
X	    }
X	    break;
X	case ' ':
X	case '\t':
X	    ++ThisCol;
X	    if (q != (char *) 0) {
X		if (q - Buffer >= sizeof(Buffer)) {
X		    beep();
X		} else {
X		    *q++ = ' ';
X		    *q = '\0';
X		}
X	    }
X	    break;
X	case '\n':
X	case '\r':
X	    /* Add word to list */
X	    if (q) {
X		int ok;
X		*q = '\0';
X		if (*Buffer) {
X		    ok = AddPhrase(Buffer);
X		    PhraseCount += ok;
X		    if (ok) ++ThisRow;
X		}
X	    }
X	    ThisCol = 0;
X	    q = (char *) 0;
X	    break;
X	case '\033': /* ESC */
X	    switch (i = getch()) {
X	    case '0':
X	    case '1': case '2': case '3':
X	    case '4': case '5': case '6':
X	    case '7': case '8': case '9':
X		i = KEY_F(i - '0');
X		goto decode;
X	    default:
X		beep();
X	    }
X	default:
X	    beep();
X	}
X	if (ThisCol >= COLS - 1) {
X	    ThisCol = 0;
X	    ThisRow++;
X	}
X	if (ThisRow >= LINES) break;
X	mvwaddch(stdscr, ThisRow, ThisCol, ' ');
X	move(ThisRow, ThisCol);
X	refresh();
X    }
X    if (q) {
X	*q = '\0';
X	if (*Buffer) PhraseCount += AddPhrase(Buffer);
X    }
X    SetMessage("Select MATCH ALL from the ALL WORDS menu to find files...");
X    refresh();
X    return 0;
X}
X
Xint
XAddPhrase(String)
X    char *String;
X{
X    extern t_Phrase *String2Phrase();
X    t_Phrase **PP;
X
X    if (!String || !*String) return 0;
X
X    /* Add it to the list */
X    for (PP = &PhraseList; *PP; PP = &(*PP)->Next) {
X	/* void */ ;
X    }
X
X    (void) move(ThisRow, 0);
X    clrtoeol();
X
X    if ((*PP = String2Phrase(String)) == (t_Phrase *) 0) {
X	int spacecount = 0;
X	char *p;
X
X	for (p = String; *p; p++) {
X	    if (*p == ' ') spacecount++;
X	}
X	switch (spacecount) {
X	    case 0: p = "This word does not"; break;
X	    case 1: p = "These words don't"; break; 
X	    case 2: p = "These words do not"; break;
X	    default: p = "None of these words"; break;
X	}
X	error(0,  "\
X%s appear\n\
Xin the database dictionary", p);
X	return 0;
X    }
X    /* The user sees the phrases numbered from 1, not from zero */
X    mvwprintw(stdscr, ThisRow, 0, "%-2d. %-7.7d %s", PhraseCount + 1,
X				/* No matches yet */ 0, (*PP)->ModifiedString);
X    return 1;
X}
X
Xextern t_PhraseCaseMatch PhraseMatchLevel; /* Phrase.c */
X
Xint
XMF_MatchAll()
X{
X    t_Phrase *PP;
X    extern long MakeMatches();
X    int Row = 5; /* as per ThisRow */
X    long Total = 0;
X
X    if (PhraseList == (t_Phrase *) 0) {
X	SetMessage(
X	"Select NEW WORDS from the FILE menu and type words to match");
X	return KEY_LEFT;
X    }
X
X    mvwprintw(stdscr, LINES - 1, 0, "Searching...");
X    refresh();
X
X    for (PP = PhraseList; PP != (t_Phrase *) 0; PP = PP->Next) {
X	move(Row, 4);
X	wclrtoeol(stdscr);
X	PP->NumberOfMatches = MakeMatches(PP);
X	Total += PP->NumberOfMatches;
X	mvwprintw(stdscr, Row, 4, "%-7.7ld %s", PP->NumberOfMatches,
X							PP->ModifiedString);
X	++Row;
X    }
X    mvwprintw(stdscr, LINES - 1, 0, "Finished... ");
X    if (Total) {
X	SetMessage("Select BROWSE ALL from the ALL WORDS menu to see the files");
X    } else {
X	char *m;
X
X	switch (PhraseMatchLevel) {
X	case PCM_HalfCase: /* this is the normal case */
X	default:
X	    m = "(select ROUGH from the MATCHING menu, or choose new words)";
X	    break;
X	case PCM_SameCase:
X	    m = "(select USER MATCHING from the MATCHING menu, or choose new words)";
X	    break;
X	case PCM_AnyCase:
X	    m = "(not found --- choose new words or phrases)";
X	    break;
X	}
X	SetMessage(m);
X    }
X    refresh();
X    return 0;
X}
X
Xint
XMF_SetAnyMatch()
X{
X    PhraseMatchLevel = PCM_AnyCase;
X    return 0;
X}
X
Xint
XMF_SetRoughMatch()
X{
X    PhraseMatchLevel = PCM_AnyCase;
X    return 0;
X}
X
Xint
XMF_SetUserMatch()
X{
X    PhraseMatchLevel = PCM_HalfCase;
X    return 0;
X}
X
Xint
XMF_SetExactMatch()
X{
X    PhraseMatchLevel = PCM_SameCase;
X    return 0;
X}
X
Xlong
XWriteFileList(Name, fp)
X    char *Name;
X    FILE *fp;
X{
X    extern t_FileInfo *GetFileInfo();
X    extern long MakeMatches();
X
X    t_Phrase *PP;
X    t_MatchList *Matches = (t_MatchList *) 0;
X    t_FID FID = (t_FID) 0;
X    t_FileInfo *FileInfo = (t_FileInfo *) 0;
X    long Total = 0L;
X
X    /* For each phrase... */
X    for (PP = PhraseList; PP != (t_Phrase *) 0; PP = PP->Next) {
X
X	if (!PP || !PP->Matches) continue;
X
X	/* For each match */
X	for (Matches = PP->Matches; Matches != (t_MatchList *) 0;
X						Matches = Matches->Next) {
X	    if (Matches->Match != (t_Match *) 0) {
X		if (Matches->Match->Where->FID != FID || !FileInfo) {
X		    if (FileInfo) (void) efree((char *) FileInfo);
X		    FileInfo = GetFileInfo(FID = Matches->Match->Where->FID);
X		}
X
X		fprintf(fp, "%s%ul %u %s",
X			     FileInfo ? "" : "# ",
X			     Matches->Match->Where->BlockInFile,
X			     Matches->Match->Where->WordInBlock,
X			     FileInfo ? FileInfo->Name : " unknown_"
X		);
X		if (FileInfo) {
X		    fputc('\n', fp);
X		    ++Total;
X		} else {
X		    fprintf(fp, "%ld\n", (long) FID);
X		}
X	    }
X	}
X    }
X    return Total;
X}
X
X/* TODO
X * -- use signal handling to ensure that the tmp file gets removed
X * even if there is an interrupt....
X * NOTDONE FIXME
X */
Xint
XMF_BrowseAll()
X{
X    extern char *mktemp();
X
X    char *t;
X    FILE *fp = (FILE *) 0;
X    char TmpBuf[30]; /* enough for /tmp/text=a124356\0 */
X#ifndef LQSHOW
X# define LQSHOW "lqshow"
X#endif
X    char SystemBuffer[sizeof(LQSHOW) + sizeof(" -f  ") + sizeof TmpBuf + 3];
X		    /* the +3 above is for spaces and a trailing \0 */
X    long Total;
X
X    if (PhraseCount == 0) {
X	SetMessage("select NEW WORDS from the FILE menu first.");
X	return 0;
X    }
X
X    ClearMessage();
X
X    (void) sprintf(TmpBuf, "/tmp/text=XXXXXX");
X    t = mktemp(TmpBuf);
X
X    if (t == (char *) 0 || (fp = fopen(t, "w")) == (FILE *) 0) {
X	error(0, "\
XCan't create tempory file\n\
X(\"%s\")\n\
Xto hold the list of matches,\n\
Xsorry.\n\
X", t ? t : "[internal_error]");
X	return -1;
X    }
X
X    Total = WriteFileList(t, fp);
X    (void) fclose(fp);
X
X    if (Total) { 
X#ifdef CURSESX
X	/* lqshow works in raw mode, so no need to fiddle tty settings */
X#else
X	/* We need to set the tty modes for lqshow: */
X	(void) nocbreak();
X	(void) echo();
X	(void) nl();
X	(void) keypad(stdscr, FALSE);
X#endif
X	clearok(stdscr, TRUE);
X	(void) sprintf(SystemBuffer, "%s -f %s", LQSHOW, t);
X	(void) system(SystemBuffer);
X#ifndef CURSESX
X	(void) cbreak();
X	(void) noecho();
X	(void) nonl();
X	(void) keypad(stdscr, TRUE);
X#endif
X	SetMessage("(save the matches using SAVE LIST from the FILE menu)");
X    } else {
X	SetMessage("(no matches; select MATCH ALL before BROWSE ALL)");
X    }
X
X    if (t) (void) unlink(t);
X
X    return 0;
X}
X
Xint
XMF_EndProg()
X{
X    endwin();
X    exit();
X    /*NOTREACHED*/
X    return (-1);
X}
X
Xint
XMF_OpenList()
X{
X    beep(); /* NOTDONE */
X    SetMessage("Function OPEN LIST unimplemented -- sorry");
X    return 0;
X}
X
Xint
XMF_SaveList()
X{
X    extern char *AskForString();
X
X    char *FileName;
X    FILE *fp;
X    t_Phrase *PP;
X
X    if (PhraseCount == 0) {
X	SetMessage("No matches... nothing to save");
X	return 0;
X    }
X
X    FileName = AskForString(
X	"Enter the name of a file in which to save the list:",
X					2048, (WINDOW *) 0, 7, 5);
X    if (FileName == (char *) 0) {
X	beep();
X	return 0;
X    }
X
X    if ((fp = fopen(FileName, "r")) != (FILE *) 0) {
X	char *yorn;
X	char *Result = (char *) 0;
X
X	(void) fclose(fp);
X
X	yorn = "\
XThe file already exists.  Type  replace  to replace it, \n\
Xor type  keep  to keep it as it is, and then press Enter: ";
X	
X	while (!Result || !STREQ(Result, "replace")) {
X	    /* the 7 is max(strlen("replace"), strlen("keep")), the
X	     * longest allowed input string
X	     */
X	    Result = AskForString(yorn, 7, (WINDOW *) 0, 7, 5);
X	    if (STREQ(Result, "keep")) {
X		SetMessage("(the list of matches was not saved)");
X		(void) efree((char *) Result);
X		(void) efree(FileName);
X		return 0;
X	    }
X	}
X	if (Result) (void) efree(Result);
X    }
X
X    if ((fp = fopen(FileName, "w")) == (FILE *) 0) {
X	SetMessage("Couldn't creat the file to save the list of matches");
X	beep();
X	refresh();
X	(void) efree(FileName);
X	return 0;
X    }
X
X    /* get rid of any lingering dialogue boxes... */
X    SetMessage("Saving list...");
X    (void) refresh();
X
X    fprintf(fp, "## file created automatically by lqtext -- do not edit!\n");
X
X    /* Write out the list of phrases */
X    for (PP = PhraseList; PP != (t_Phrase *) 0; PP = PP->Next) {
X	(void) fprintf(fp, "## %s\n", PP->OriginalString);
X    }
X
X    (void) WriteFileList(FileName, fp);
X
X    (void) fclose(fp);
X    SetMessage("List saved.  Type   q   if you want to quit now.");
X    return 0;
X}
X
Xint
XMF_ViewFile()
X{
X    extern char *AskForString();
X    char *p;
X
X    p = AskForString(
X	    "Enter a filename:                  ", 2048, (WINDOW *) 0, 5, 5);
X
X    if (p && *p) {
X	int Retval;
X	char *sysbuf = emalloc(strlen(p) + sizeof(PAGER) + 3);
X
X	(void) sprintf(sysbuf, "%s %s", PAGER, p);
X	Retval = MySystem(sysbuf);
X	(void) efree(sysbuf);
X	return Retval;
X    } else {
X	beep();
X    }
X    return 0;
X}
X
Xint
XMF_ListFiles()
X{
X#ifndef LQFILE
X# define LQFILE "lqfile"
X#endif
X#ifndef PAGER
X# define PAGER "more"
X#endif
X    char *buf = emalloc(sizeof(LQFILE) + sizeof(PAGER) + 6);
X    int Retval = 0;
X
X	/* +4 is for "-a | " and \0 */
X    if (!buf) {
X	beep();
X	return -1;
X    }
X
X    (void) sprintf(buf, "%s -a | %s", LQFILE, PAGER);
X    Retval = MySystem(buf);
X    (void) efree(buf);
X    return Retval;
X}
X
Xint
XMF_AddNewFile()
X{
X    extern char *AskForString();
X    char *p;
X
X    p = AskForString(
X	    "Enter a file to add:                  ", 2048, (WINDOW *) 0, 5, 5);
X
X    if (p && *p) {
X	char sysbuf[2048 + 50];
X
X	(void) sprintf(sysbuf, "lqaddfile -v \"%s\"", p);
X	(void) MySystem(sysbuf);
X    } else {
X	beep();
X    }
X    return 0;
X}
X
X
Xint
XMF_NotDone()
X{
X    mvwaddstr(stdscr, LINES - 1, 1, "NOTDONE");
X    return 0;
X}
X
Xstatic t_MenuBar *MainMenuBar;
X
Xt_MenuBar *
XSetUpMenus()
X{
X    t_Menu *Menu;
X
X    MainMenuBar = new(t_MenuBar);
X
X    if (MainMenuBar == (t_MenuBar *) 0) {
X	error(ERR_FATAL|ERR_MEMORY, "Not enough memory for main menu bar");
X    }
X    MainMenuBar->MenuBarId = 0; /* Private (oh for c++) */
X    MainMenuBar->HowManyMenus = 0;
X    MainMenuBar->SelectedMenu = 0;
X    MainMenuBar->ScrollOffset = 0;
X
X    /* Now some menus: */
X
X    Menu = NewMenu("File");
X
X    Menu->Description = "\
X File Operations -- \n\
X  New Words -- selecting files based on keywords; \n\
X  Save/Open List -- remembering a list of files for later use \n\
X  Finish -- leave the program (you can also type \"q\") \n\
X\n\
X You probably want to use \"New Words\" to start with, \n\
X and then use the \"All Words\" menu to see the result.";
X
X    Menu->Items = (t_MenuItem *) emalloc(sizeof(t_MenuItem) * 4);
X
X    Menu->Items[0].Name = "New Words";
X    Menu->Items[0].NameLength = 0;
X    Menu->Items[0].Function = GetWords;
X    Menu->Items[0].Description =
X"Type in a new list of words\n\
Xfor which to search";
X
X    Menu->Items[1].Name = "Save List";
X    Menu->Items[1].NameLength = 0;
X    Menu->Items[1].Function = MF_SaveList;
X    Menu->Items[1].Description =
X"Save List -- Save the list of files that\n\
Xyou have found in a file";
X
X    Menu->Items[2].Name = "Open List";
X    Menu->Items[2].NameLength = 0;
X    Menu->Items[2].Function = MF_OpenList;
X    Menu->Items[2].Description =
X"Open List -- Open a list of filenames\n\
Xthat you previously saved";
X
X    Menu->Items[3].Name = "Finish";
X    Menu->Items[3].NameLength = 0;
X    Menu->Items[3].Function = MF_EndProg;
X    Menu->Items[3].Description = "Finish -- leave the program";
X
X    Menu->HowManyItems = 4;
X
X    MainMenuBar->Menus[MainMenuBar->HowManyMenus++] = Menu;
X
X    /* Now choosing words */
X    Menu = NewMenu("All Words");
X
X    Menu->Description = "\
X Main Word Menu\n\
X  Once you have typed one or more phrases using \n\
X  \"New Words\" from the \"File\" menu, you can \n\
X  use this menu to find the list of files which \n\
X  contain the phrases, and then you can look at \n\
X  the files with \"Browse All\".\
X ";
X    Menu->Items = (t_MenuItem *) emalloc(sizeof(t_MenuItem) * 3);
X    Menu->Items[0].Name = "Match All";
X    Menu->Items[0].NameLength = 0;
X    Menu->Items[0].Function = MF_MatchAll;
X    Menu->Items[0].Description =
X"Look for files containing\n\
Xthe phrases you have entered.";
X    Menu->Items[1].Name = "Browse All";
X    Menu->Items[1].NameLength = 0;
X    Menu->Items[1].Function = MF_BrowseAll;
X    Menu->Items[1].Description =
X"Browse through the matches (if any)\n";
X    Menu->HowManyItems = 2;
X
X    MainMenuBar->Menus[MainMenuBar->HowManyMenus++] = Menu;
X
X    /* Setting match level */
X    Menu = NewMenu("Matching");
X
X    Menu->Description = "\
XMatching Menu\n\
X Use this menu if you want finer control over \n\
X the way phrases are matched.\n\
X\n\
X The \"Rough Matching\" option will generally \n\
X produce the most matches.\n\
X After you have changed the match level, \n\
X you have to use \"Match All\" from the \n\
X \"All Words\" menu.\
X";
X    Menu->Items = (t_MenuItem *) emalloc(sizeof(t_MenuItem) * 3);
X
X    Menu->Items[0].Name = "Exact Matching";
X    Menu->Items[0].NameLength = 0;
X    Menu->Items[0].Function = MF_SetExactMatch;
X    Menu->Items[0].Description =
X"Match phrases as exactly as possible,\n\
Xincluding Case, pluralS and Possessive's";
X
X    Menu->SelectedLine = 1; /* the default */
X    Menu->Items[1].Name = "User Matching";
X    Menu->Items[1].NameLength = 0;
X    Menu->Items[1].Function = MF_SetUserMatch;
X    Menu->Items[1].Description =
X"Match phrases roughly, but match Case,\n\
XpluralS and so on exactly when given";
X
X    Menu->Items[2].Name = "Rough Matching";
X    Menu->Items[2].NameLength = 0;
X    Menu->Items[2].Function = MF_SetRoughMatch;
X    Menu->Items[2].Description =
X"Ensure that words in phrases are in\n\
Xthe same order as you type, but don't\n\
Xbother about cAsE, plurals, etc.";
X
X    Menu->HowManyItems = 3;
X
X    MainMenuBar->Menus[MainMenuBar->HowManyMenus++] = Menu;
X
X    /* Indexing files... */
X    Menu = NewMenu("Indexing");
X
X    Menu->Description = "\
XIndexing Menu\n\
X Use this menu to add new files to the index, \n\
X to examine the list of indexed files, or\n\
X to examine the files themselves.\
X";
X    Menu->Items = (t_MenuItem *) emalloc(sizeof(t_MenuItem) * 3);
X    Menu->Items[0].Name = "Add New file";
X    Menu->Items[0].NameLength = 0;
X    Menu->Items[0].Function = MF_AddNewFile;
X    Menu->Items[0].Description = "\
XAdd a new file to the index, \n\
Xso that it can be found later. ";
X
X    Menu->Items[1].Name = "List Index";
X    Menu->Items[1].NameLength = 0;
X    Menu->Items[1].Function = MF_ListFiles;
X    Menu->Items[1].Description = "\
XSee the list of files that are \n\
Xalready in the index.";
X
X    Menu->Items[2].Name = "View File";
X    Menu->Items[2].NameLength = 0;
X    Menu->Items[2].Function = MF_ViewFile;
X    Menu->Items[2].Description = "Look at a file (using pg) ";
X
X    Menu->HowManyItems = 3;
X
X    MainMenuBar->Menus[MainMenuBar->HowManyMenus++] = Menu;
X
X    /* Patterns... */
X    Menu = NewMenu("Patterns");
X
X    Menu->Description = "\
XPatterns Menu\n\
X This menu lets you specify the order in which files \n\
X are presented, and also how inexact words --- like \n\
X \"someth*\"  or  \"Is[ia][ia]*h\" --- are matched. \n\
X See the explanations of the individual menu items \n\
X for more details of what they do.\
X";
X    Menu->Items = (t_MenuItem *) emalloc(sizeof(t_MenuItem) * 9);
X    Menu->Items[0].Name = "Prefer All";
X    Menu->Items[0].NameLength = 0;
X    Menu->Items[0].Function = MF_NotDone;
X    Menu->Items[0].Description = "\
XPut files containing all of the phrases \n\
Xfirst in the list when browsing. ";
X
X    Menu->Items[1].Name = "Prefer Most";
X    Menu->Items[1].NameLength = 0;
X    Menu->Items[1].Function = MF_NotDone;
X    Menu->Items[1].Description = "\
XPut the files containing the most matches\n\
Xfirst in the list when browsing.";
X
X    Menu->Items[2].Name = "Prefer Oldest";
X    Menu->Items[2].NameLength = 0;
X    Menu->Items[2].Function = MF_NotDone;
X    Menu->Items[2].Description = "\
XPut the oldest files entered into the database \n\
Xfirst in the list when browsing. ";
X
X    Menu->Items[3].Name = "Unsorted";
X    Menu->Items[3].NameLength = 0;
X    Menu->Items[3].Function = MF_NotDone;
X    Menu->Items[3].Description = "\
XDon't bother sorting the list of files before browsing; \n\
Xthis is usually the fastest option.";
X
X    Menu->Items[4].Name = "Reverse";
X    Menu->Items[4].NameLength = 0;
X    Menu->Items[4].Function = MF_NotDone;
X    Menu->Items[4].Description = "\
XReverse the order in which files are presented \n\
X(so, for example, if they are to be sorted on \n\
Xthe number of matches, you will get the files \n\
Xwith only one match before those containing several \n\
Xmatches, and so on) ";
X
X    Menu->Items[5].Name = "No Patterns";
X    Menu->Items[5].NameLength = 0;
X    Menu->Items[5].Function = MF_NotDone;
X    Menu->Items[5].Description = "Don't allow patterns in words or phrases. ";
X
X    Menu->Items[6].Name = "Simple Patterns";
X    Menu->Items[6].NameLength = 0;
X    Menu->Items[6].Function = MF_NotDone;
X    Menu->Items[6].Description = "\
XWhen you type words to be matched, a * will \n\
Xmean any sequence of characters, and a ? a single character, \n\
Xso that  *day  would find all occurrences of Monday, Tuesday, \n\
XHoliday, and so on, whilst   bo?  would look for all \n\
Xthree-letter words beginning in \"bo\", such as box and boy. ";
X
X    Menu->Items[7].Name = "Complex patterns";
X    Menu->Items[7].NameLength = 0;
X    Menu->Items[7].Function = MF_NotDone;
X    Menu->Items[7].Description = "\
XAllow full (\"egrep\"-style) regular expressions when looking for \n\
Xwords.  This means that when you are entering NEW WORDS to search \n\
Xfor, certain characters have special meaning: \n\
X x*    matches any number of \"x\", where \"x\" can be anything;\n\
X .     matches a single character (letter or digit);\n\
X a|b   means either \"a\" or \"b\" (within a single word); \n\
X [xyz] matches a single character that's an x, y or z; you\n\
X       can use a - to represent a range, as in [a-zA-Z0-9],\n\
X       and of course [aeiou]* would mean 0 or more vowels.\n\
XSee the User Reference Book for more detail on this.\n\
X";
X
X    Menu->HowManyItems = 8;
X
X    MainMenuBar->Menus[MainMenuBar->HowManyMenus++] = Menu;
X
X    return MainMenuBar;
X}
X
XWINDOW *WordInfoBox = 0;
X
Xvoid
XSetUpScreen()
X{
X    /* Put some important info on the screen itself...
X     * One could use menus to change the screen display, perhaps.
X     * A more general program would use a screen form to do this.
X     */
X
X    /* First, version information */
X    mvwprintw(stdscr, 10, 0, "%s revision %s", progname, "$Revision: 1.7 $");
X    mvwaddstr(stdscr, 11, 0, "[press return to continue]");
X    refresh();
X    (void) getch();
X    clear();
X    refresh();
X
X    /* Now, we want to tell the user what to do... */
X    ShowInstructions();
X}
X
Xvoid
XSetMessage(s)
X    char *s;
X{
X    move(3, 1);
X    clrtoeol();
X    mvwaddstr(stdscr, 3, 1, s);
X}
X
Xvoid
XClearMessage()
X{
X    move(3, 1);
X    clrtoeol();
X}
X
Xvoid
XShowInstructions()
X{
X    char *s;
X
X    s =  "\
XUse the arrow keys to choose a menu at the top of the screen, \n\
Xand then use the space bar to select it. \n\
XUse the up and down arrow keys to choose a command, \n\
Xand then press space. \n\
XYou can press  x  for an eXplanation of any menu or menu item. \n\
X\n\
XYou probably want to start by selecting the FILE menu,\n\
Xand choosing NEW WORDS from it. \n\
X";
X    
X    ClearInstructions();
X    mvwaddstr(stdscr, LINES - 12, 3, s);
X    refresh();
X}
X
Xvoid
XClearInstructions()
X{
X    int i;
X
X    /* get rid of "Type the list... and press F1" */
X    /* ClearMessage(); */
X    /* get rid of the instructions */
X    for (i = LINES - 12; i < LINES; i++) {
X	if (PhraseCount - 5 < i) { /* don't overwrite phrases */
X	    move(i, 0);
X	    clrtoeol();
X	}
X    }
X}
X
Xvoid
XStartCurses()
X{
X    if (InCurses) {
X	error(ERR_FATAL|ERR_INTERNAL, "StartCurses() called in curses mode");
X    }
X    (void) initscr();
X    InCurses = 1;
X    (void) cbreak();
X    (void) noecho();
X    (void) nonl();
X    (void) keypad(stdscr, TRUE);
X}
X
Xvoid
XEndCurses()
X{
X    clear();
X    (void) refresh();
X
X    InCurses = 0;
X    (void) endwin();
X}
@@@End of lq-text/src/menu/text.c
echo x - lq-text/src/menu/ultrixhack.h 1>&2
sed 's/^X//' >lq-text/src/menu/ultrixhack.h <<'@@@End of lq-text/src/menu/ultrixhack.h'
X#define ACS_BSSS '+'
X#define ACS_SBSS '+'
X#define ACS_SSBS '+'
X#define ACS_SSSB '+'
X#define ACS_HLINE '='
X#define ACS_LARROW '>'
X#define ACS_LLCORNER '+'
X#define ACS_LRCORNER '+'
X#define ACS_RARROW '<'
X#define ACS_VLINE '|'
X#define KEY_HELP 999 /* an unlikely key to be pressed */
@@@End of lq-text/src/menu/ultrixhack.h
echo x - lq-text/src/saber.project 1>&2
sed 's/^X//' >lq-text/src/saber.project <<'@@@End of lq-text/src/saber.project'
X/* Saber-C Project File */
X/* Set current directory */
Xcd /home/lee/lq-text/src
X/* Options for project */
Xunsetopt ansi
Xunsetopt auto_compile
Xsetopt auto_reload
Xsetopt auto_replace
Xunsetopt batch_load
Xunsetopt batch_run
Xunsetopt cc_prog
Xsetopt ccargs               -g
Xunsetopt create_file
Xunsetopt debug_child
Xunsetopt echo
Xsetopt edit_jobs            5
Xunsetopt eight_bit
Xsetopt line_edit
Xunsetopt line_meta
Xsetopt lint_load            2
Xsetopt lint_run             2
Xsetopt list_action
Xunsetopt load_flags
Xunsetopt long_not_int
Xunsetopt make_args
Xsetopt make_hfiles
Xunsetopt make_offset
Xunsetopt make_prog
Xsetopt make_symbol          #
Xsetopt mem_config           16384
Xunsetopt mem_trace
Xsetopt num_proc             1
Xsetopt page_cmds            22
Xsetopt page_list            10
Xsetopt page_load            22
Xunsetopt path
Xsetopt proto_path           . /stage/saber_dir30/sun4-40/proto /stage/saber_dir30/sun4-40/../common/proto
Xunsetopt preprocessor
Xsetopt program_name         a.out
Xunsetopt print_custom
Xsetopt print_pointer
Xsetopt print_string         20
Xunsetopt save_memory
Xsetopt sbrk_size            1048576
Xsetopt src_err              3
Xsetopt src_step             1
Xsetopt src_stop             3
Xsetopt sys_load_flags       -L/lib -L/usr/lib -L/usr/local/lib -I/usr/include -Dunix -Dsun -Dsparc -I. -I./h -I../h
Xunsetopt tab_stop
Xunsetopt terse_suppress
Xunsetopt terse_where
Xsetopt unset_value          191
Xunsetopt win_fork_nodup
Xunsetopt win_no_raise
Xunsetopt win_message_list
Xunsetopt win_project_list
X/* Suppressions for project */
X
X/* Contents of project */
Xload  /lib/libc.a
Xload -g\ -DASCIITRACE\ -DBSD\ -USYSV\ -Dsdbm\ -DSDBM\ -DDUFF\ -DDUPERROR\ -DSPLITERROR\ -ULiamSysV sdbm/sdbm.c sdbm/pair.c sdbm/hash.c
X/* load -I./h\ -DBSD\ -Dsdbm\ -DASCIITRACE lqtext/lqaddfile.c */
Xload -g\ -DASCIITRACE\ -DBSD\ -USYSV\ -Dsdbm\ -I../h liblqtext/DocPath.c liblqtext/Defaults.c liblqtext/FileList.c liblqtext/Phrase.c liblqtext/Root.c liblqtext/WordInfo.c liblqtext/malloc.c liblqtext/numbers.c liblqtext/pblock.c liblqtext/smalldb.c
Xload -I./h\ -DBSD\ -Dsdbm\ -DASCIITRACE\ -USYSV liblqtext/FilterType.c
Xload -g\ -DASCIITRACE\ -DBSD\ -USYSV\ -Dsdbm\ -I../h liblqtext/asciitrace.c liblqtext/cmdname.c
Xload  lib/liblqtext.a
Xload -I./h\ -DBSD\ -Dsdbm\ -DASCIITRACE lqtext/wordtable.c
Xlink
X
X/* Signals caught and ignored */
Xcatch HUP
Xcatch INT
Xcatch QUIT
Xcatch ILL
Xcatch TRAP
Xcatch IOT
Xcatch EMT
Xcatch FPE
Xcatch KILL
Xcatch BUS
Xcatch SEGV
Xcatch SYS
Xcatch PIPE
Xcatch TERM
Xcatch URG
Xcatch STOP
Xcatch TSTP
Xcatch TTIN
Xcatch TTOU
Xcatch IO
Xcatch XCPU
Xcatch XFSZ
Xcatch VTALRM
Xcatch PROF
Xcatch LOST
Xcatch USR1
Xcatch USR2
Xignore ALRM
Xignore CONT
Xignore CHLD
Xignore WINCH
X
X/* Status of project */
@@@End of lq-text/src/saber.project
echo x - lq-text/src/test/Makefile 1>&2
sed 's/^X//' >lq-text/src/test/Makefile <<'@@@End of lq-text/src/test/Makefile'
X# Makefile for LQ-Text, a full text retrieval package by Liam R. Quin
X# This Makefile belongs in the "src/test" directory.
X#
X# Note that most of the actual configuration is done in ../Makefile and
X# in ../h/global.h, and not here.
X#
X# $Id: Makefile,v 1.3 90/10/08 21:15:10 lee Exp $
X
X#
X# $Log:	Makefile,v $
X# Revision 1.3  90/10/08  21:15:10  lee
X# Cope with non-writeable numbers.c and SixBit.c
X# 
X# Revision 1.2  90/10/06  01:27:05  lee
X# Prepared for first Beta release.
X# 
X# Revision 1.1  90/08/09  19:17:53  lee
X# Initial revision
X# 
X# 
X#
X
XPWD=test
X
X# no rules for the first 4 yet, sorry
XTARGETS = MaxWid TryHash put trywid dbmtry TryRoot TryNum NumberTest
XTESTPROGS = MaxWid TryHash put trywid dbmtry TryRoot TryNum NumberTest 
X
XTESTBIN=../testbin
XMODE=755
XOWNER=lee
X
XEXTRA=-I../h
X
Xall: $(TARGETS)
X
Xsaber_src:
X
Xsaber_obj:
X
X# for ndbm (simplest), leave empty or use -lndbm if you need it
X# for sdbm (best so far), use ../lib/libsdbm.a
X# for gdbm... well, I dunno.
XDBMLIBS=../lib/libsdbm.a
X# DBMLIBS=-lndbm
X# DBMLIBS=ndbm.o bcopy.o
X
XLIAMLIB=../lib/liblq.a
XTEXTLIB=../lib/liblqtext.a
X
Xinstall: all
X	@test -d $(TESTBIN) || mkdir $(TESTBIN)
X	for i in $(TESTPROGS); do cp "$$i" $(TESTBIN); \
X	strip "$(TESTBIN)/$$i" ; \
X	chmod $(MODE) "$(TESTBIN)/$$i" ; \
X	chown $(OWNER) "$(TESTBIN)/$$i" ; \
X	done
X
Xtidy:
X	/bin/rm -f *.o core
X
Xclean: tidy
X	/bin/rm -f $(TARGETS) $(TEST) numbers.c
X
Xdepend:
X	mkdep $(CFLAGS) *.c
X
XMaxWid: MaxWid.o $(TEXTLIB) $(LIAMLIB) $(DBMLIBS)
X	$(CC) $(CFLAGS) -o MaxWid MaxWid.o $(TEXTLIB) $(LIAMLIB) $(DBMLIBS)
X
XTryHash: TryHash.o $(TEXTLIB) $(LIAMLIB)
X	$(CC) $(CFLAGS) -o TryHash TryHash.o $(TEXTLIB)
X
XTryNum: TryNum.o $(TEXTLIB) $(LIAMLIB)
X	$(CC) $(CFLAGS) -o TryNum TryNum.o $(TEXTLIB) $(LIAMLIB)
X
XTryRoot: TryRoot.o $(TEXTLIB) $(LIAMLIB) $(DBMLIBS)
X	$(CC) $(CFLAGS) -o TryRoot TryRoot.o $(TEXTLIB) $(LIAMLIB) $(DBMLIBS)
X
Xdbmtry: dbmtry.o $(TEXTLIB) $(LIAMLIB) $(DBMLIBS)
X	$(CC) $(CFLAGS) -o dbmtry dbmtry.o $(TEXTLIB) $(LIAMLIB) $(DBMLIBS)
X
Xput: put.o
X	$(CC) $(CFLAGS) -o put put.o
X
Xtrywid: trywid.o $(TEXTLIB) $(LIAMLIB) $(DBMLIBS)
X	$(CC) $(CFLAGS) -o trywid trywid.o $(TEXTLIB) $(LIAMLIB) $(DBMLIBS)
X
Xnumbers.c: ../liblqtext/numbers.c
X	/bin/rm -f numbers.c
X	cp ../liblqtext/numbers.c .
X
XNumberTest: numbers.o
X	$(CC) $(CFLAGS) -DTESTNUMBERS -o NumberTest numbers.c
X
X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
X# DO NOT DELETE THIS LINE -- mkdep uses it.
X# DO NOT PUT ANYTHING AFTER THIS LINE, IT WILL GO AWAY.
X
XMaxWid.o: MaxWid.c ../h/globals.h 
XTryHash.o: TryHash.c ../h/globals.h
XTryNum.o: TryNum.c ../h/globals.h ../h/numbers.h
XTryNum.o: ../h/emalloc.h
XTryRoot.o: TryRoot.c 
XTryRoot.o: ../h/fileinfo.h ../h/wordinfo.h ../h/pblock.h ../h/wordrules.h
Xdbmtry.o: dbmtry.c ../h/globals.h 
Xdbmtry.o: ../h/smalldb.h ../h/ozmadbm.h ../h/db.h
Xlqmalloc.o: lqmalloc.c 
Xput.o: put.c 
Xtrywid.o: trywid.c ../h/globals.h
Xtrywid.o: ../h/fileinfo.h
Xtrywid.o: ../h/wordinfo.h ../h/pblock.h
X
X# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
@@@End of lq-text/src/test/Makefile
echo x - lq-text/src/test/MaxWid.c 1>&2
sed 's/^X//' >lq-text/src/test/MaxWid.c <<'@@@End of lq-text/src/test/MaxWid.c'
X/* MaxWid.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
X * This code is NOT in the public domain.
X * See the file COPYRIGHT for full details.
X */
X
X#include "globals.h" /* defines and declarations for database filenames */
X
X#include <stdio.h>
Xextern void SetDefaults();
Xextern void exit();
X
Xint
Xmain(argc, argv)
X    int argc;
X    char *argv[];
X{
X    extern unsigned long GetMaxWID();
X
X    SetDefaults(argc, argv);
X
X    printf("Max Word Identifier (MaxWID) is %lu\n", GetMaxWID());
X    return 0;
X}
@@@End of lq-text/src/test/MaxWid.c
echo x - lq-text/src/test/TryHash.c 1>&2
sed 's/^X//' >lq-text/src/test/TryHash.c <<'@@@End of lq-text/src/test/TryHash.c'
X/* $Header: /usr/src/cmd/lq-text/src/test/RCS/TryHash.c,v 1.1 90/08/09 19:17:43 lee Rel1-10 $
X *
X * $Log:	TryHash.c,v $
X * Revision 1.1  90/08/09  19:17:43  lee
X * Initial revision
X * 
X *
X */
X
X
X#ifdef SYSV
X extern int _flsbuf();
X#endif
X#include <stdio.h>
X
X#include "globals.h" /* defines and declarations for database filenames */
X
X#define HASHSIZ 4096
X
Xint AsciiTrace = 1;
Xchar *progname = "TryHash";
X
X/** Unix library functions: **/
Xextern int strlen();
X
Xint
XHash0(String)
X    char *String;
X{
X    register int Result = strlen(String);
X    register char *q;
X
X    for (q = String; *q; q++) {
X	Result = ((Result * 211) | *q) & (HASHSIZ - 1);
X    }
X    return Result;
X}
X
Xint
XHash1(str) /* Ozan's ... */
X    register char *str;
X{
X    register unsigned long n = 0;
X    register int len = strlen(str);
X
X#ifdef DUFF
X
X#define HASHC	n = *str++ + 65599 * n
X
X    if (len > 0) {
X	register int loop = (len + 8 - 1) >> 3;
X
X	switch(len & (8 - 1)) {
X	case 0:	do {
X		HASHC;	case 7:	HASHC;
X	case 6:	HASHC;	case 5:	HASHC;
X	case 4:	HASHC;	case 3:	HASHC;
X	case 2:	HASHC;	case 1:	HASHC;
X		} while (--loop);
X	}
X
X    }
X#else
X    while (len--)
X	n = *str++ + 65599 * n;
X#endif
X    return n & (HASHSIZ - 1);
X}
X
Xtypedef int (* t_ifp)();
Xt_ifp HashTab[] = {
X    Hash0,
X    Hash1
X#define MAXHASHF 2 /* CHANGE ME: number of hash functions */
X};
X
Xint
Xmain()
X{
X    char Buffer[1000];
X    int i;
X    t_ifp f;
X
X    while (gets(Buffer) != (char *) 0) {
X	printf("%s:", Buffer);
X	for (i = 0; i < MAXHASHF; i++) {
X	    f = HashTab[i];
X	    printf("\t%d", (* f)(Buffer));
X	}
X	putchar('\n');
X    }
X    return 0;
X}
@@@End of lq-text/src/test/TryHash.c
echo x - lq-text/src/test/TryNum.c 1>&2
sed 's/^X//' >lq-text/src/test/TryNum.c <<'@@@End of lq-text/src/test/TryNum.c'
X/* TryNum.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
X * This code is NOT in the public domain.
X * See the file COPYRIGHT for full details.
X */
X
X/* For testing number routines from numbers.c */
X
X/* $Header: /usr/src/cmd/lq-text/src/test/RCS/TryNum.c,v 1.2 90/08/29 21:53:25 lee Rel1-10 $
X *
X * $Log:	TryNum.c,v $
X * Revision 1.2  90/08/29  21:53:25  lee
X * Test for variable-sozed numbers
X * 
X * Revision 1.1  90/08/09  19:17:44  lee
X * Initial revision
X * 
X * Revision 1.2  89/09/16  21:16:04  lee
X * First demonstratable version.
X * 
X * Revision 1.1  89/09/07  21:05:50  lee
X * Initial revision
X * 
X */
X
X#include <stdio.h>
X#include "globals.h"
X#include "numbers.h"
X
X#include "emalloc.h"
X
X/** Unix system calls that need to be declared **/
Xextern void exit();
X
X/** Unix Library Functions that need to be declared **/
Xextern int strcmp();
Xextern void perror();
Xextern int strlen();
Xextern char *strcpy();
X
X/** Functions from this file that need to be declared: **/
Xvoid dostrings();
X
X/** **/
X
Xchar *progname = "@(#) $Header: /usr/src/cmd/lq-text/src/test/RCS/TryNum.c,v 1.2 90/08/29 21:53:25 lee Rel1-10 $";
Xint AsciiTrace = 0;
X
Xint
Xmain(ac, av)
X    int ac;
X    char *av[];
X{
X    FILE *f;
X    unsigned long L;
X
X    progname = av[0]; /* leave the full path */
X
X    if (ac == 3 && !strcmp(av[1], "-s")) {
X	dostrings(av[2]);
X	exit(0);
X    }
X
X    if (ac != 2) {
X	fprintf(stderr, "Usage: %s file, or %s -s string\n", av[0], av[0]);
X	exit(1);
X    }
X
X    if ((f = fopen(av[1], "r")) == (FILE *) 0) {
X	extern int errno;
X	int e = errno;
X	fprintf(stderr, "%s: can't open file ", av[0]);
X	errno = e;
X	perror(av[1]);
X	exit(1);
X    }
X
X    for (;;) {
X	L = fReadNumber(f);
X	printf("%ld\n", L);
X	fflush(stdout);
X	if (feof(f)) break;
X    }
X
X    (void) fclose(f);
X
X    exit(0);
X    /*NOTREACHED*/
X    return 1; /* for lint */
X}
X
Xvoid
Xdostrings(string)
X    char *string;
X{
X    int len;
X    char *Buf;
X    char *End;
X
X    len = strlen(string);
X
X    /* the extra bytes allow sReadNumber to over-run */
X    if ((Buf = emalloc(len + sizeof(unsigned long) + 1)) == (char *) 0) {
X	fprintf(stderr, "%s: Not enough memory\n", progname);
X	exit(1);
X    }
X
X    (void) strcpy(Buf, string);
X
X    End = &Buf[len];
X    string = Buf;
X
X    while (string < End) {
X	printf("%lu\n", sReadNumber(&string));
X    }
X}
@@@End of lq-text/src/test/TryNum.c
echo x - lq-text/src/test/TryRoot.c 1>&2
sed 's/^X//' >lq-text/src/test/TryRoot.c <<'@@@End of lq-text/src/test/TryRoot.c'
X/* TryRoot.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
X * This code is NOT in the public domain.
X * See the file COPYRIGHT for full details.
X *
X * $Header: /usr/src/cmd/lq-text/src/test/RCS/TryRoot.c,v 1.1 90/08/09 19:17:45 lee Rel1-10 $
X *
X * $Log:	TryRoot.c,v $
X * Revision 1.1  90/08/09  19:17:45  lee
X * Initial revision
X * 
X *
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <sys/types.h>
X#include "fileinfo.h" /* this is needed by wordinfo.h */
X#include "wordinfo.h"
X#include "wordrules.h" /* for the flags, etc */
X
Xchar *progname = "TryRoot";
X
X/** Unix/C Library Functions: **/
Xextern int strlen();
X#ifndef tolower
Xextern int tolower();
X#endif
X
X/** lqtext library functions: **/
Xextern char *WordRoot();
Xextern void SetDefaults();
X
X/** **/
X
Xint
Xmain(argc, argv)
X    int argc;
X    char *argv[];
X{
X    t_WordInfo W;
X
X    SetDefaults(argc, argv);
X
X    while (--argc) {
X	extern char *UnFlag();
X	extern char *TryRoot();
X
X	char *s;
X	W.Word = *++argv;
X	W.Length = strlen(*argv);
X	W.WordPlace.Flags = 0;
X
X	printf("%s --> ", *argv);
X	if (isupper(W.Word[0])) {
X	    W.WordPlace.Flags |= WPF_UPPERCASE;
X	}
X	for (s = W.Word; *s; s++) {
X	    *s = tolower(*s);
X	}
X	s = WordRoot(&W);
X	printf("%s [%d] -->", s, W.WordPlace.Flags);
X	printf("%s", UnFlag(&W, W.WordPlace.Flags));
X	printf(" [%d]\n", W.WordPlace.Flags);
X    }
X    return 0;
X}
@@@End of lq-text/src/test/TryRoot.c
echo x - lq-text/src/test/dbmtry.c 1>&2
sed 's/^X//' >lq-text/src/test/dbmtry.c <<'@@@End of lq-text/src/test/dbmtry.c'
X/* dbmtry.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
X * This code is NOT in the public domain.
X * See the file COPYRIGHT for full details.
X */
X
X/* If you have problems with the dbm interface, try this program.
X * If it fails with ALERT messages when given an argument of 300 or so,
X * you almost certainly have a faulty dbm.
X *
X * On SysV, by the way, check for delitem() calling bcopy() with
X * overlapping arguments...
X *
X * $Header: /usr/src/cmd/lq-text/src/test/RCS/dbmtry.c,v 1.5 91/03/03 00:47:56 lee Exp $
X *
X * $Log:	dbmtry.c,v $
X * Revision 1.5  91/03/03  00:47:56  lee
X * added sys/types.h for ozmahash
X * 
X * Revision 1.4  90/08/09  19:17:47  lee
X * *** empty log message ***
X * 
X * Revision 1.3  90/07/27  17:41:54  lee
X * *** empty log message ***
X * 
X * Revision 1.2  89/09/16  21:16:15  lee
X * First demonstratable version.
X * 
X * Revision 1.1  89/09/07  21:05:54  lee
X * Initial revision
X * 
X */
X
X#include "globals.h" /* defines and declarations for database filenames */
X
X#include <stdio.h>
X#include <fcntl.h>
X#ifdef ozmahash
X# include <sys/types.h>
X#endif
X#include "smalldb.h"
X
Xchar *progname = "dbmtry";
X
X/** Unix system calls: **/
Xextern void exit();
X
X/** Unix Library Functions: **/
Xextern int atoi();
Xextern int strlen();
Xextern void perror();
X
X/** Routines in this file which need declaring: **/
Xvoid printvalues();
X
X/** **/
X
X
Xint
Xmain(ac, av)
X    int ac;
X    char *av[];
X{
X    DBM *db;
X    int max = atoi(av[1]);
X    int i;
X    datum key, data;
X    char dbuf[30];
X
X
X    if (ac <= 1) {
X	fprintf(stderr, "Usage: %s maxkey\n", av[0]);
X	exit(1);
X    }
X
X    if ((db = startdb("/tmp/trydbm")) == (DBM *) 0) {
X	fprintf(stderr, "dbmopen 1 failed\n");
X	exit(1);
X    }
X
X    for (i = 1; i <= max; i++) {
X	char buf[20];
X	register int s_val;
X
X	if ((i % 500) == 0) {
X	    (void) fprintf(stderr, "\r%d ", i);
X	    (void) fflush(stderr);
X	}
X	sprintf(buf, "%d", i);
X	sprintf(dbuf, "%d data item here", i);
X	    /* Note: the number is at the start to help speed the
X	     * strcmp, as it is most likely to differ
X	     */
X	key.dsize = strlen(buf) + 1; /* include th nul so we can strcmp() */
X	key.dptr = buf;
X	data.dptr = dbuf;
X	data.dsize = strlen(dbuf) + 1;
X	s_val = dbm_store(db, key, data, DBM_INSERT);
X	if (s_val != 0) {
X	    printf("store %d returned %d\n", i, s_val);
X	}
X    }
X
X    enddb(db);
X
X    printvalues(max);
X    return 0;
X}
X
Xvoid
Xprintvalues(max)
X    int max;
X{
X    DBM *db;
X    int i;
X    datum key, data;
X
X    db = startdb("/tmp/trydbm");
X
X    if (!db) {
X	fprintf(stderr, "Unable to open database ");
X	perror("/tmp/trydbm");
X	exit(1);
X    }
X
X    for (i = 1; i <= max; i++) {
X	char buf[20];
X
X	sprintf(buf, "%d", i);
X	key.dsize = strlen(buf) + 1;
X	key.dptr = buf;
X	data = dbm_fetch(db, key);
X
X	if (data.dsize == 0) {
X	    printf("ALERT! Item %d has been lost! ALERT!\n", i);
X	} else {
X	    char *Buf[100];
X	    (void) sprintf(Buf, "%d data item here", i);
X	    if (strcmp(Buf, data.dptr) != 0) {
X		printf("%d: Corrupt: \"%s\" != \"%s\"\n",
X				i, data.dptr, Buf);
X		/* NOTE: no use using STREQ, as the strings are usually
X		 * the same.
X		 */
X	    }
X	}
X    }
X
X    enddb(db);
X}
@@@End of lq-text/src/test/dbmtry.c
echo x - lq-text/src/test/numbers.c 1>&2
sed 's/^X//' >lq-text/src/test/numbers.c <<'@@@End of lq-text/src/test/numbers.c'
X/* numbers.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
X * This code is NOT in the public domain.
X * See the file COPYRIGHT for full details.
X */
X
X/* Routines to read and write numbers in a compressed format, preserving
X * block boundaries.
X * The actual compression seems to be about 50%, as most numbers turn
X * out to fit in 16 bits.  Interestingly, there is room for another one
X * or two bits, I think, that could be used for something else, in the
X * main pblock index.  For example, it could mark whether words were
X * plural/-"ing"/"un"-/ with 2 bits.
X *
X * $Header: /usr/src/cmd/lq-text/src/test/RCS/numbers.c,v 1.2 90/10/03 21:13:21 lee Rel1-10 $
X *
X * $Log:	numbers.c,v $
X * Revision 1.2  90/10/03  21:13:21  lee
X * Added a cast.
X * 
X * Revision 1.3  90/08/09  19:16:49  lee
X * BSD lint and fixes...
X * 
X * Revision 1.2  90/04/18  19:47:13  lee
X * More flexible (and slightly more compact) number format.
X * 
X * Revision 2.2  89/10/08  20:46:36  lee
X * Working version of nx-text engine.  Addfile and wordinfo work OK.
X * 
X * Revision 2.1  89/10/02  01:15:15  lee
X * New index format, with Block/WordInBlock/Flags/BytesSkipped info.
X * 
X * Revision 1.2  89/09/16  21:16:26  lee
X * First demonstratable version.
X * 
X * Revision 1.1  89/09/07  21:06:01  lee
X * Initial revision
X * 
X *
X */
X
X#include "globals.h"
X
X#ifdef SYSV
X	extern int _filbuf(), _flsbuf();
X#endif
X#include <stdio.h>
X#include "numbers.h"
X
X/* ReadNumber and WriteNumber take/return a long, using a compression
X * algorithm to reduce the amount of data taken.
X * The current algorithm is simply like internet addresses:
X * a 0 in the top bit followed by a 0 means it's one byte
X * a 0 followed by a 1 means it's 2 bytes
X * a 1 followed by a 0 means it's 3 bytes, and
X * a 1 followed by a 1 means it's 4 bytes.
X * A better alternative might simply use a 1 in the top bit, hence fitting
X * 7 bits into each bytes.  The advantages of considering more than
X * one number at a time and using compress-style LS packing are not clear.
X * In particular, speed of recovery is an issue too.
X *
X * The routines use (char *) pointers instead of files prefixes with an s.
X * see numbers.h for some related macros.
X *
X */
X
X
X#ifdef TESTNUMBERS
Xchar *progname;
X
Xint
Xmain(ac, av)
X    int ac;
X    char *av[];
X{
X    extern long atol();
X    FILE *f;
X    extern FILE *fopen();
X
X    progname = av[0];
X
X    while (--ac) {
X	unsigned long L = atol(*++av);
X	unsigned long L2;
X
X	f = fopen("/tmp/boy", "w");
X	printf("Write %u\n", L);
X	fWriteNumber(f, L);
X	fclose(f);
X	f = fopen("/tmp/boy", "r");
X	L2 = fReadNumber(f);
X	printf("Read %u\n", L2);
X	if (L != L2) {
X	    printf("**** ERROR **** %ld != %ld\n", L, L2);
X	}
X	fclose(f);
X    }
X    return 0;
X}
X#endif /*TESTNUMBERS*/
X
XINLINE void
XfWriteNumber(f, Number)
X    FILE *f;
X    unsigned long Number;
X{
X    /* Compressed numbers:
X     * 7 bit numbers --> single byte;
X     * 8...14 bits --> 2 bytes
X     * 15...21 bits --> 3 bytes
X     * 22..28 bits --> 4 bytes
X     * 29..32 bits --> 5 bytes
X     */
X    while (Number > 0177) {
X	putc((Number & 0177) | 0200, f);
X	Number >>= 7;
X    }
X    putc(Number & 0177, f);
X}
X
X#define PutC(ch, S)  (*((*S)++) = (char) (ch))
X
XINLINE void
XsWriteNumber(s, Number)
X    char **s;
X    unsigned long Number;
X{
X    /* Compressed numbers:
X     * 7 bit numbers --> single byte;
X     * 8...14 bits --> 2 bytes
X     * 15...21 bits --> 3 bytes
X     * 22..28 bits --> 4 bytes
X     * 29..32 bits --> 5 bytes
X     */
X    while (Number > 0177) {
X	PutC((Number & 0177) | 0200, s);
X	Number >>= 7;
X    }
X    PutC(Number & 0177, s);
X}
X
XINLINE unsigned long
XfReadNumber(f)
X    FILE *f;
X{
X    unsigned long Result = 0L;
X    int ThereIsMore;
X    int Shift = 0;
X
X    /* Read a number, 7 bits at a time, lsb first, until there is
X     * a byte without the top bit set -- that's the most significant
X     * byte, and there is no more of this number.
X     */
X    do {
X	Result |= ((ThereIsMore = getc(f)) & 0177) << Shift;
X	ThereIsMore &= 0200;
X	Shift += 7;
X    } while (ThereIsMore);
X    return Result;
X}
X
X#define GetC(S) \
X    ( (unsigned int) * (unsigned char *) ((* (unsigned char **)S)++) )
X
XINLINE unsigned long
XsReadNumber(s)
X    char **s;
X{
X    unsigned long Result = 0L;
X    int ThereIsMore;
X    int Shift = 0;
X
X    /* Read a number, 7 bits at a time, lsb first, until there is
X     * a byte without the top bit set -- that's the most significant
X     * byte, and there is no more of this number.
X     */
X    do {
X	Result |= ((ThereIsMore = GetC(s)) & 0177) << Shift;
X	ThereIsMore &= 0200;
X	Shift += 7;
X    } while (ThereIsMore);
X    return Result;
X}
@@@End of lq-text/src/test/numbers.c
echo x - lq-text/src/test/put.c 1>&2
sed 's/^X//' >lq-text/src/test/put.c <<'@@@End of lq-text/src/test/put.c'
X/* put.c -- Copyright 1989 Liam R. Quin.  All Rights Reserved.
X * This code is NOT in the public domain.
X * See the file COPYRIGHT for full details.
X */
X
X/* This is useful if your echo doesn't grok \ddd.
X * Use put [string|number]*, numbers wih a leading 0 are octal.
X * Use -s to mean that the next argument is a string.  Use -s -s to print
X * the string "-s".
X *
X * $Header: /usr/src/cmd/lq-text/src/test/RCS/put.c,v 1.1 90/08/09 19:17:50 lee Rel1-10 $
X *
X * $Log:	put.c,v $
X * Revision 1.1  90/08/09  19:17:50  lee
X * Initial revision
X * 
X * Revision 1.2  89/09/16  21:18:32  lee
X * First demonstratable version.
X * 
X * Revision 1.1  89/09/07  21:06:10  lee
X * Initial revision
X * 
X *
X */
X
X#ifdef SYSV
X    extern int _flsbuf(); /* keep lint ang gcc -Wall happy */
X#endif
X#include <stdio.h>
X#include <ctype.h>
X
X/** Unix/C Library Functions: **/
Xextern int atoi(), strcmp();
X/** **/
X
Xint
Xmain(ac, av)
X    int ac;
X    char *av[];
X{
X    while (--ac) {
X	++av;
X	if (isdigit(**av)) {
X	    if (**av == '0') {
X		int o;
X
X		sscanf(*av, "%o", &o);
X		putchar(o);
X	    } else {
X		putchar(atoi(*av));
X	    }
X	} else {
X	    if (ac > 1 && !strcmp(*av, "-s")) {
X		--ac;
X		++av;
X	    }
X	    printf("%s", *av);
X	}
X    }
X}
@@@End of lq-text/src/test/put.c
echo end of part 10
-- 
Liam R. E. Quin,  lee@sq.com, SoftQuad Inc., Toronto, +1 (416) 963-8337