home *** CD-ROM | disk | FTP | other *** search
- #ifndef lint
- static char *rcsid = "$Header: /usr1/ben/jkh/src/xinfo/RCS/Info.c,v 1.2 90/01/29 11:29:19 jkh Exp $";
- #endif
-
- #include <X11/IntrinsicP.h>
- #include <X11/Shell.h>
- #include <X11/StringDefs.h>
- #include <X11/Xaw/AsciiText.h>
- #include <X11/Xaw/Box.h>
- #include <X11/Xaw/Command.h>
- #include <X11/Xaw/Label.h>
- #include <X11/Xaw/List.h>
- #include <X11/Xaw/Viewport.h>
-
- #include <sys/stat.h>
- #include <stdio.h>
- #include <ctype.h>
- #include <pwd.h>
-
- /* #include <X11/Xaw/InfoP.h> */
- #include "InfoP.h"
-
- /*
- *
- * Copyright 1989, 1990
- * Jordan K. Hubbard
- *
- * PCS Computer Systeme, GmbH.
- * Munich, West Germany
- *
- *
- * This file is part of GNU Info widget.
- *
- * The GNU Info widget is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as published
- * by the Free Software Foundation; either version 1, or (at your option)
- * any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- */
-
- /*
- *
- * $Log: Info.c,v $
- * Revision 1.2 90/01/29 11:29:19 jkh
- * *** empty log message ***
- *
- * Revision 1.1 90/01/27 22:43:22 jkh
- * Initial revision
- *
- *
- */
-
- #define offset(name) XtOffset(InfoWidget, info.name)
-
- Local XtResource resources[] = {
- { XtNinfoHelp, XtCInfoHelp, XtRString, sizeof(String), offset(helpFile),
- XtRString, HELPFILE },
- { XtNinfoPath, XtCInfoPath, XtRString, sizeof(String), offset(path),
- XtRString, XtDefaultInfoPath },
- { XtNinfoFile, XtCInfoFile, XtRString, sizeof(String), offset(file),
- XtRString, XtDefaultInfoFile },
- { XtNinfoNode, XtCInfoNode, XtRString, sizeof(String), offset(node),
- XtRString, XtDefaultInfoNode },
- { XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t),
- offset(callback), XtRCallback, NULL},
- { XtNprintCommand, XtCPrintCommand, XtRString, sizeof(String),
- offset(printCmd), XtRString, XtDefaultPrintCommand },
- };
-
- #undef offset
-
- Local void Initialize(), Destroy();
- Local Boolean SetValues();
-
- Local void NodeDir(), NodeNext(), NodePrev(), NodeUp(), NodeTop(),
- NodeLast(), NodeXRef(), NodeGoto(), NodeSearch(), NodeQuit(),
- NodeMenuSelectByNumber(), NodePrint(), NodeHelp(), NodeTutorial();
-
- Local XtActionsRec actions[] =
- {
- { "dir", NodeDir },
- { "next", NodeNext },
- { "prev", NodePrev },
- { "up", NodeUp },
- { "top", NodeTop },
- { "last", NodeLast },
- { "xref", NodeXRef },
- { "goto", NodeGoto },
- { "search", NodeSearch },
- { "menusel", NodeMenuSelectByNumber },
- { "print", NodePrint },
- { "quit", NodeQuit },
- { "tutorial", NodeTutorial },
- { "popupHelp", NodeHelp },
- { NULL, NULL }
- };
-
- Local char deflTrans[] = "\
- <Key>1: menusel(1)\n\
- <Key>2: menusel(2)\n\
- <Key>3: menusel(3)\n\
- <Key>4: menusel(4)\n\
- <Key>5: menusel(5)\n\
- <Key>6: menusel(6)\n\
- <Key>7: menusel(7)\n\
- <Key>8: menusel(8)\n\
- <Key>9: menusel(9)\n\
- <Key>Help: popupHelp()\n\
- <Key>question: popupHelp()\n\
- Meta<Key>P: print()\n\
- None<Key>d: dir()\n\
- None<Key>f: xref()\n\
- None<Key>g: goto()\n\
- None<Key>h: tutorial()\n\
- None<Key>l: last()\n\
- None<Key>m: menusel(0)\n\
- None<Key>n: next()\n\
- None<Key>p: prev()\n\
- None<Key>q: quit()\n\
- None<Key>s: search()\n\
- None<Key>t: top()\n\
- None<Key>u: up()\n\
- ";
-
- /* page movement translations for text areas */
- Local char textTrans[] = "\
- None<Key>b: beginning-of-file()\n\
- <Key>Home: beginning-of-file()\n\
- <Key>Delete: previous-page()\n\
- <Key>Prior: previous-page()\n\
- <Key>Next: next-page()\n\
- <Key>space: next-page()\n\
- ";
-
- Export InfoClassRec infoClassRec = {
- { /* core fields */
- /* superclass */ (WidgetClass) &panedClassRec,
- /* class_name */ "Info",
- /* widget_size */ sizeof(InfoRec),
- /* class_initialize */ NULL,
- /* class_part_initialize */ NULL,
- /* class_inited */ FALSE,
- /* initialize */ Initialize,
- /* initialize_hook */ NULL,
- /* realize */ XtInheritRealize,
- /* actions */ actions,
- /* num_actions */ XtNumber(actions),
- /* resources */ resources,
- /* num_resources */ XtNumber(resources),
- /* xrm_class */ NULLQUARK,
- /* compress_motion */ TRUE,
- /* compress_exposure */ TRUE,
- /* compress_enterleave */ TRUE,
- /* visible_interest */ FALSE,
- /* destroy */ Destroy,
- /* resize */ XtInheritResize,
- /* expose */ XtInheritExpose,
- /* set_values */ SetValues,
- /* set_values_hook */ NULL,
- /* set_values_almost */ XtInheritSetValuesAlmost,
- /* get_values_hook */ NULL,
- /* accept_focus */ XtInheritAcceptFocus,
- /* version */ XtVersion,
- /* callback_private */ NULL,
- /* tm_table */ deflTrans,
- /* query_geometry */ XtInheritQueryGeometry,
- /* display_accelerator */ XtInheritDisplayAccelerator,
- /* extension */ NULL
- },
- { /* composite_class fields */
- /* geometry_manager */ XtInheritGeometryManager,
- /* change_managed */ XtInheritChangeManaged,
- /* insert_child */ XtInheritInsertChild,
- /* delete_child */ XtInheritDeleteChild,
- /* extension */ NULL
- },
- { /* constraint_class fields */
- /* subresourses */ NULL,
- /* subresource_count */ 0,
- /* constraint_size */ sizeof(InfoConstraintsRec),
- /* initialize */ NULL,
- /* destroy */ NULL,
- /* set_values */ NULL,
- /* extension */ NULL
- },
- { /* paned_class fields */
- /* empty */ 0
- },
- { /* info fields */
- /* empty */ 0
- }
- };
-
- Export WidgetClass infoWidgetClass = (WidgetClass)&infoClassRec;
-
- Local int findNode();
- Local int iindex();
- Local int strcomp();
- Local int strncomp();
- Local void parseIndirect();
- Local void message();
- Local void strccpy();
- Local void parseNode();
- Local void parseHeader();
- Local void parseMenu();
- Local void parseXRefs();
- Local void displayNode();
- Local void displayHeader();
- Local void showStatus();
- Local String getFile();
- Local String find_file();
- Local String offsetToString();
- Local String file_name();
- Local String eat_whitespace();
- Local String search();
- Local String search_back();
- Local String strconcat();
- Local String substr();
- Local String reverse();
- Local String get_arg();
- Local String trueName();
- Local String downcase();
- Local String strip_evil();
- Local Boolean getNode();
- Local Boolean parseTags();
- Local NodeInfo *pushNode();
- Local NodeInfo *popNode();
-
- Local void do_prev(), do_up(), do_next(), do_menu(),
- do_xref(), do_menu_sel(), do_xref_sel(), do_goto(), do_search();
-
- Import char tolower();
-
- Local XtCallbackRec cb[2];
- #define XtSetCbk(argarray, rtn, arg) \
- cb[0].callback = rtn; \
- cb[0].closure = (caddr_t)arg; \
- XtSetArg(argarray, XtNcallback, cb)
-
- Local void Initialize(request, new)
- Widget request;
- Widget new;
- {
- Arg args[10];
- Cardinal i;
- InfoWidget iw = (InfoWidget)new;
- Widget box1, box2, vport, vport2;
- char blanks[MAXSTR];
- XtTranslations defltrans, texttrans;
- Import char *bzero();
-
- /* parse the transation tables */
- defltrans = XtParseTranslationTable(deflTrans);
- texttrans = XtParseTranslationTable(textTrans);
-
- /* create a blank filled string as a placeholder for certain labels */
- for (i = 0; i < MAXSTR - 1; i++)
- blanks[i] = ' ';
- blanks[i] = '\0';
-
- /*
- * Create top row of "main control" buttons and labels.
- */
- i = 0;
- box1 = XtCreateManagedWidget("box1", boxWidgetClass, new, args, i);
-
- i = 0;
- XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
- XtSetArg(args[i], XtNlabel, "File: "); i++;
- iw->info.fileLabel = XtCreateManagedWidget("file", labelWidgetClass,
- box1, args, i);
- i = 0;
- XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
- XtSetArg(args[i], XtNlabel, "Node: "); i++;
- iw->info.nodeLabel = XtCreateManagedWidget("node", labelWidgetClass,
- box1, args, i);
- i = 0;
- XtSetArg(args[i], XtNborderWidth, 2); i++;
- XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
- XtSetArg(args[i], XtNlabel, "Prev: "); i++;
- XtSetCbk(args[i], do_prev, iw); i++;
- iw->info.prevCmd = XtCreateManagedWidget("prev", commandWidgetClass,
- box1, args, i);
- i = 0;
- XtSetArg(args[i], XtNborderWidth, 2); i++;
- XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
- XtSetArg(args[i], XtNlabel, "Up: "); i++;
- XtSetCbk(args[i], do_up, iw); i++;
- iw->info.upCmd = XtCreateManagedWidget("up", commandWidgetClass,
- box1, args, i);
- i = 0;
- XtSetArg(args[i], XtNborderWidth, 2); i++;
- XtSetArg(args[i], XtNjustify, XtJustifyLeft); i++;
- XtSetArg(args[i], XtNlabel, "Next: "); i++;
- XtSetCbk(args[i], do_next, iw); i++;
- iw->info.nextCmd = XtCreateManagedWidget("next", commandWidgetClass,
- box1, args, i);
-
- /* Create the menu pane */
- i = 0;
- XtSetArg(args[i], XtNallowVert, TRUE); i++;
- XtSetArg(args[i], XtNallowResize, TRUE); i++;
- vport = XtCreateManagedWidget("vport1", viewportWidgetClass,
- new, args, i);
- i = 0;
- XtSetArg(args[i], XtNheight, 150); i++;
- XtSetArg(args[i], XtNpasteBuffer, TRUE); i++;
- XtSetArg(args[i], XtNcolumnSpacing, 8); i++;
- XtSetCbk(args[i], do_menu_sel, iw); i++;
- iw->info.menuList = XtCreateManagedWidget("menu", listWidgetClass,
- vport, args, i);
-
- /*
- * Create the text area for displaying node contents.
- */
- i = 0;
- XtSetArg(args[i], XtNheight, 500); i++;
- XtSetArg(args[i], XtNstring, "/dev/null"); i++;
- XtSetArg(args[i], XtNeditType, XawtextEdit); i++;
- XtSetArg(args[i], XtNtype, XawAsciiFile); i++;
- iw->info.nodeText = XtCreateManagedWidget("nodeText",
- asciiTextWidgetClass,
- new, args, i);
- XtOverrideTranslations(iw->info.nodeText, defltrans);
- XtOverrideTranslations(iw->info.nodeText, texttrans);
-
-
- i = 0;
- XtSetArg(args[i], XtNheight, 20); i++;
- XtSetArg(args[i], XtNmin, 20); i++;
- XtSetArg(args[i], XtNallowVert, TRUE); i++;
- XtSetArg(args[i], XtNallowResize, TRUE); i++;
- vport2 = XtCreateManagedWidget("vport2", viewportWidgetClass,
- new, args, i);
- /* Create the xref pane */
- i = 0;
- XtSetArg(args[i], XtNpasteBuffer, TRUE); i++;
- XtSetArg(args[i], XtNdefaultColumns, 6); i++;
- XtSetArg(args[i], XtNcolumnSpacing, 8); i++;
- XtSetCbk(args[i], do_xref_sel, iw); i++;
- iw->info.xrefList = XtCreateManagedWidget("xref", listWidgetClass,
- vport2, args, i);
-
- /*
- * Create the bottom "auxilliary" command button group.
- */
- i = 0;
- XtSetArg(args[i], XtNheight, 30); i++;
- XtSetArg(args[i], XtNmin, 30); i++;
- box2 = XtCreateManagedWidget("box2", boxWidgetClass,
- new, args, i);
- i = 0;
- XtSetArg(args[i], XtNborderWidth, 2); i++;
- XtSetCbk(args[i], do_menu, iw); i++;
- iw->info.xrefCmd = XtCreateManagedWidget("menu", commandWidgetClass,
- box2, args, i);
- i = 0;
- XtSetArg(args[i], XtNborderWidth, 2); i++;
- XtSetCbk(args[i], do_xref, iw); i++;
- iw->info.xrefCmd = XtCreateManagedWidget("xref", commandWidgetClass,
- box2, args, i);
- i = 0;
- XtSetArg(args[i], XtNborderWidth, 2); i++;
- XtSetCbk(args[i], do_goto, iw); i++;
- iw->info.gotoCmd = XtCreateManagedWidget("goto", commandWidgetClass,
- box2, args, i);
- i = 0;
- XtSetArg(args[i], XtNborderWidth, 2); i++;
- XtSetCbk(args[i], do_search, iw); i++;
- iw->info.searchCmd = XtCreateManagedWidget("search", commandWidgetClass,
- box2, args, i);
- i = 0;
- bzero(iw->info.arg, ARGLEN);
- XtSetArg(args[i], XtNstring, iw->info.arg); i++;
- XtSetArg(args[i], XtNlength, ARGLEN); i++;
- XtSetArg(args[i], XtNwidth, 200); i++;
- XtSetArg(args[i], XtNallowResize, TRUE); i++;
- XtSetArg(args[i], XtNresize, TRUE); i++;
- XtSetArg(args[i], XtNborderWidth, 2); i++;
- XtSetArg(args[i], XtNeditType, XawtextEdit); i++;
- iw->info.argText = XtCreateManagedWidget("arg", asciiTextWidgetClass,
- box2, args, i);
-
- /*
- * Create the status and message area labels.
- */
-
- i = 0;
- XtSetArg(args[i], XtNheight, 20); i++;
- XtSetArg(args[i], XtNmin, 20); i++;
- XtSetArg(args[i], XtNmax, 20); i++;
- XtSetArg(args[i], XtNresize, FALSE); i++;
- XtSetArg(args[i], XtNlabel, blanks); i++;
- XtSetArg(args[i], XtNborderWidth, 0); i++;
- iw->info.statusLabel = XtCreateManagedWidget("status", labelWidgetClass,
- new, args, i);
- i = 0;
- XtSetArg(args[i], XtNheight, 20); i++;
- XtSetArg(args[i], XtNmin, 20); i++;
- XtSetArg(args[i], XtNmax, 20); i++;
- XtSetArg(args[i], XtNresize, FALSE); i++;
- XtSetArg(args[i], XtNlabel, blanks); i++;
- XtSetArg(args[i], XtNborderWidth, 0); i++;
- iw->info.messageLabel = XtCreateManagedWidget("message", labelWidgetClass,
- new, args, i);
-
- /* set the initial node information */
- ZERO_TABLE(INDIRECT(iw));
- ZERO_TABLE(TAGTABLE(iw));
- DATA(iw) = NULL;
- CURNODE(iw) = NULL;
-
- /* decide who can get bigger */
- XawPanedAllowResize(vport, TRUE);
- XawPanedAllowResize(vport2, TRUE);
- XawPanedAllowResize(iw->info.xrefList, TRUE);
-
- iw->info.file = XtNewString(iw->info.file);
- iw->info.node = XtNewString(iw->info.node);
- iw->info.tempfile = NULL;
-
- if (getNode(iw, iw->info.file, iw->info.node, NULL) == FALSE)
- message(iw, "?Can't find initial file/node.");
- }
-
- Local void Destroy(w)
- Widget w;
- {
- InfoWidget iw = (InfoWidget)w;
-
- if (INDIRECT(iw).table)
- FREE_TAG_TABLE(INDIRECT(iw));
- if (TAGTABLE(iw).table)
- FREE_TAG_TABLE(TAGTABLE(iw));
- while (popNode(iw)); /* popNode will free contents */
- /* free the last one */
- if (CURNODE(iw)) {
- XtFree(CURNODE(iw)->file);
- XtFree(CURNODE(iw)->node);
- XtFree(CURNODE(iw));
- }
- if (iw->info.file)
- XtFree(iw->info.file);
- if (iw->info.node)
- XtFree(iw->info.node);
- }
-
- Local Boolean SetValues(current, request, new)
- Widget current, request, new;
- {
- InfoWidget cw = (InfoWidget)current;
- InfoWidget nw = (InfoWidget)new;
-
- if (cw->info.file != nw->info.file
- || strcomp(cw->info.file, nw->info.file)
- || cw->info.node != nw->info.node
- || strcomp(cw->info.node, nw->info.node)) {
- XtFree(cw->info.file);
- XtFree(cw->info.node);
- getNode(nw, nw->info.file, nw->info.node, NULL);
- }
- /* getNode() does the redisplay implicitly */
- return(FALSE);
- }
-
- /*****************************************************************************
- * Info file manipulation routines. *
- *****************************************************************************/
-
- /* Here is the main guy. Handles all navigation within the info tree. */
- Local Boolean getNode(iw, file, node, pushTo)
- InfoWidget iw;
- String file, node;
- NodeInfo *pushTo;
- {
- NodeInfo *cur;
- int offset;
- Boolean status = FALSE;
-
- if (node && index(node, '(') && index(node, ')')) {
- file = substr(node, iindex(node, '(') + 1,
- iindex(node, ')') - 1);
- node = index(node, ')') + 1;
- }
- if (!node || !*node)
- node = "Top";
-
- if (!file)
- file = iw->info.file;
-
- if (!DATA(iw) || strcomp(file_name(file), file_name(iw->info.file))) {
- /* get a new file */
- if ((file = getFile(iw, file, FALSE)) != NULL) {
- if (file && iw->info.file != file) {
- XtFree(iw->info.file);
- iw->info.file = XtNewString(file);
- }
- iw->info.subFile = NULL;
- }
- }
- else if (!strcomp(node, iw->info.node))
- return(TRUE); /* we're already there */
- else {
- XtFree(iw->info.node);
- iw->info.node = XtNewString(node);
- }
- if (file && (offset = findNode(iw, node)) >= 0) {
- if (!pushTo) {
- cur = pushNode(iw, iw->info.file, iw->info.node, offset);
- parseNode(iw, cur, offset);
- }
- else
- cur = pushTo;
- displayNode(iw, cur);
- message(iw, NULL);
- showStatus(iw, cur);
- status = TRUE;
- }
- else {
- /* Failed to get the new node, go back (but only once) */
- if (!pushTo && CURNODE(iw))
- getNode(iw, CURNODE(iw)->file, CURNODE(iw)->node, CURNODE(iw));
- }
- return(status);
- }
-
- /* Loads in file "name" and tag/indirect info, if any. */
- Local String getFile(iw, name, subfilep)
- InfoWidget iw;
- String name;
- Boolean subfilep;
- {
- String ret;
-
- FILE *fp;
-
- ret = find_file(iw->info.path, name);
- if (ret) {
- Import int stat();
- struct stat sb;
-
- if (!stat(ret, &sb) && (fp = fopen(ret, "r"))) {
- if (DATA(iw))
- XtFree(DATA(iw));
- DATA(iw) = XtMalloc(sb.st_size);
- if (fread(DATA(iw), 1, sb.st_size, fp) == sb.st_size) {
- fclose(fp);
- DATASIZE(iw) = sb.st_size;
- if (!subfilep) {
- Boolean needIndirect;
-
- needIndirect = parseTags(iw);
- parseIndirect(iw, needIndirect);
- }
- }
- else {
- message(iw, "?Read error on %s.", name);
- XtFree(DATA(iw));
- ret = NULL;
- }
- }
- else
- ret = NULL;
- }
- return(ret);
- }
-
- /* Look through tag table (and/or current buffer) for a node */
- Local int findNode(iw, name)
- InfoWidget iw;
- String name;
- {
- ID_P i;
- int offset = -1;
- String s, srch;
-
- /* A node name of "*" means the whole file */
- if (!strcomp(name, "*"))
- return(0);
-
- if (TAGTABLE(iw).table) {
- for (i = TAGTABLE(iw).table; I_NAME(*i); i++) {
- if (!strcomp(I_NAME(*i), name)) {
- offset = I_OFFSET(*i);
- break;
- }
- }
- /* if we found the tag and there's an indirect table, adjust */
- if (offset > 0 && INDIRECT(iw).table) {
- String sub;
-
- for (i = INDIRECT(iw).table; I_NAME(*i); i++) {
- if (I_OFFSET(*i) > offset) /* got it */
- break;
- }
- sub = I_NAME(*(--i));
- if (strcomp(sub, iw->info.subFile)) {
- if (!getFile(iw, sub, TRUE))
- return(0);
- else
- iw->info.subFile = sub;
- }
- offset -= I_OFFSET(*i);
- /* compensate for header */
- offset += HDRSIZE(iw);
- }
- }
- /*
- * Now search forward for the node name. Note that this will
- * work whether or not we found the tag in the tag table. Having
- * found the tag only insures that we search a little less (personally,
- * I think that this whole indirect/tag nonsense is a bad idea. If
- * one could count on tags always being accurate, I wouldn't mind so
- * much, but one can't. As it is, it's just a pain in the ass on fast VM
- * systems where file size and search time aren't such significant issues
- * for files <~600K. Think how much simpler this code would be if
- * we didn't have to deal with all the indirect/tag crap).
- */
-
- s = START(iw);
- if (offset > 0)
- s += offset;
-
- /*
- * since bogus tags can leave us *after* the node start as well as
- * before it, we risk a little extra searching and back up to the
- * closest node marker above. Es tut mir leid, but this is what you
- * get with out-of-date tags!
- */
- while (s > START(iw) && *s != INFO_CHAR)
- --s;
- srch = strconcat(NODE_TOKEN, name);
- while (s) {
- if ((s = search(iw, s, END(iw), srch, TRUE)) != NULL) {
- /* If not an exact match, keep looking */
- if (!index(NAME, *s))
- continue;
- offset = INTOFF(START(iw), s);
- /* found it, move to the beginning */
- while(START(iw)[offset - 1] != INFO_CHAR)
- offset--;
- s = NULL;
- }
- else
- offset = -1;
- }
- return(offset);
- }
-
- /* Push a node onto the history list */
- Local NodeInfo *pushNode(iw, file, node, offset)
- InfoWidget iw;
- String file, node;
- int offset;
- {
- NodeInfo *tmp;
-
- tmp = (NodeInfo *)XtMalloc(sizeof(NodeInfo));
- tmp->file = XtNewString(file);
- tmp->node = XtNewString(node);
- tmp->start = offset;
- tmp->nextNode = CURNODE(iw);
- CURNODE(iw) = tmp;
- return(tmp);
- }
-
- /* Pop a node off the history list */
- Local NodeInfo *popNode(iw)
- InfoWidget iw;
- {
- NodeInfo *tmp = NULL;
-
- if (CURNODE(iw) && CURNODE(iw)->nextNode) {
- tmp = CURNODE(iw)->nextNode;
- XtFree(CURNODE(iw)->file);
- XtFree(CURNODE(iw)->node);
- XtFree(CURNODE(iw));
- CURNODE(iw) = tmp;
- }
- return(tmp);
- }
-
- /* Parse out all the header/menu/xref information for a node. */
- Local void parseNode(iw, n, offset)
- InfoWidget iw;
- NodeInfo *n;
- int offset;
- {
- register String start = START(iw) + offset;
-
- /* was the whole file ("*") selected? */
- if (offset == 0) {
- n->length = DATASIZE(iw);
- I_START(n->name) = I_LEN(n->name) = 0;
- I_START(n->prev) = I_LEN(n->prev) = 0;
- I_START(n->up) = I_LEN(n->up) = 0;
- I_START(n->next) = I_LEN(n->next) = 0;
- I_START(n->text) = 0;
- I_LEN(n->text) = n->length;
- }
- else {
- /* find the end of the node */
- n->length = 0;
- start = START(iw) + offset;
- while (start < END(iw) && *start != INFO_CHAR) {
- n->length++;
- start++;
- }
- }
- /* get the header */
- parseHeader(iw, n);
- /* get the menu items */
- parseMenu(iw, n);
- /* get the cross reference entries */
- parseXRefs(iw, n);
- }
-
- Local void parseHeader(iw, n)
- InfoWidget iw;
- NodeInfo *n;
- {
- String strpbrk(), tmp;
-
- /* first, get the node name offset */
- I_START(n->name) = INTOFF(START(iw), NSEARCH(iw, n, NODE_TOKEN));
- I_LEN(n->name) = INTOFF(START(iw), strpbrk(START(iw) + I_START(n->name),
- NAME_END_TOKEN)) -
- I_START(n->name);
-
- /* now the prev, if any */
- if ((I_START(n->prev) = INTOFF(START(iw),
- NSEARCH(iw, n, PREV_TOKEN))) > 0)
- I_LEN(n->prev) = INTOFF(START(iw),
- strpbrk(START(iw) + I_START(n->prev),
- NAME_END_TOKEN)) -
- I_START(n->prev);
- else
- I_LEN(n->prev) = I_START(n->prev) = 0;
-
- /* and the up, if any */
- if ((I_START(n->up) = INTOFF(START(iw),
- NSEARCH(iw, n, UP_TOKEN))) > 0)
- I_LEN(n->up) = INTOFF(START(iw), strpbrk(START(iw) + I_START(n->up),
- NAME_END_TOKEN)) -
- I_START(n->up);
- else
- I_LEN(n->up) = I_START(n->up) = 0;
-
- /* the next, if any */
- if ((I_START(n->next) = INTOFF(START(iw),
- NSEARCH(iw, n, NEXT_TOKEN))) > 0)
- I_LEN(n->next) = INTOFF(START(iw),
- strpbrk(START(iw) + I_START(n->next),
- NAME_END_TOKEN)) -
- I_START(n->next);
- else
- I_LEN(n->next) = I_START(n->next) = 0;
-
- /* And finally skip over the header and set the text offset there */
- tmp = START(iw) + I_START(n->name);
- while (*tmp != '\n')
- tmp++;
- I_START(n->text) = INTOFF(START(iw), tmp + 1);
- I_LEN(n->text) = n->length - (I_START(n->text) - n->start);
- }
-
- Local void parseMenu(iw, n)
- InfoWidget iw;
- NodeInfo *n;
- {
- register String mstart;
-
- /* start clean */
- ZERO_LIST(n->menu);
-
- /* Does node have a menu? */
- if ((mstart = NSEARCH(iw, n, MENU_TOKEN)) != NULL) {
- /* Initialize table and string list */
- ALLOC_LIST(n->menu);
-
- /* go looking for menu items */
- while (mstart = search(iw, mstart, NEND(iw, n), MENU_SEP_TOKEN,
- FALSE)) {
- MAYBE_BUMP_LIST(n->menu);
- I_LEN(TPOS(n->menu.t)) = 0;
- I_START(TPOS(n->menu.t)) = INTOFF(START(iw), mstart);
- while (*(mstart++) != ':')
- I_LEN(TPOS(n->menu.t))++;
- /* save the menu name as a string */
- LPOS(n->menu) = XtMalloc(I_LEN(TPOS(n->menu.t)) + 1);
- strncpy(LPOS(n->menu), START(iw) + I_START(TPOS(n->menu.t)),
- I_LEN(TPOS(n->menu.t)));
- LPOS(n->menu)[I_LEN(TPOS(n->menu.t))] = '\0';
- strip_evil(LPOS(n->menu));
- /* Is the menu name not the node name? */
- if (*mstart != ':') {
- mstart = eat_whitespace(mstart);
- I_START(TPOS(n->menu.t)) = INTOFF(START(iw), mstart);
- I_LEN(TPOS(n->menu.t)) =
- INTOFF(START(iw), strpbrk(mstart, NAME_END_TOKEN)) -
- I_START(TPOS(n->menu.t));
- }
- INCP(n->menu.t);
- }
- ROUND_LIST(n->menu);
- }
- }
-
- Local void parseXRefs(iw, n)
- InfoWidget iw;
- NodeInfo *n;
- {
- register String nstart;
-
- /* start clean */
- ZERO_LIST(n->xref);
-
- /* Do we have any cross-reference entries? */
- if ((nstart = search(iw, NSTART(iw, n), NEND(iw, n), NOTE_TOKEN, TRUE))
- != NULL) {
- ALLOC_LIST(n->xref);
- nstart = NSTART(iw, n);
-
- /*
- * Go looking for cross-references (including the one we just
- * found; wasteful, but avoiding it would make for grotty code).
- */
- while (nstart = search(iw, nstart, NEND(iw, n), NOTE_TOKEN, TRUE)) {
- /* skip over whitespace */
- nstart = eat_whitespace(nstart);
- MAYBE_BUMP_LIST(n->xref);
- I_LEN(TPOS(n->xref.t)) = 0;
- I_START(TPOS(n->xref.t)) = INTOFF(START(iw), nstart);
- while (*(nstart++) != ':')
- I_LEN(TPOS(n->xref.t))++;
- /* save the note name as a string */
- LPOS(n->xref) = XtMalloc(I_LEN(TPOS(n->xref.t)) + 1);
- strncpy(LPOS(n->xref), START(iw) + I_START(TPOS(n->xref.t)),
- I_LEN(TPOS(n->xref.t)));
- LPOS(n->xref)[I_LEN(TPOS(n->xref.t))] = '\0';
- strip_evil(LPOS(n->xref));
- /* Is the note name not the first part? */
- if (*nstart != ':') {
- nstart = eat_whitespace(nstart + 1);
- I_START(TPOS(n->xref.t)) = INTOFF(START(iw), nstart);
- I_LEN(TPOS(n->xref.t)) =
- INTOFF(START(iw), strpbrk(nstart, NAME_END_TOKEN)) -
- I_START(TPOS(n->xref.t));
- }
- INCP(n->xref.t);
- }
- ROUND_LIST(n->xref);
- }
- }
-
- /* Put the node information on the screen */
- Local void displayNode(iw, n)
- InfoWidget iw;
- NodeInfo *n;
- {
- Arg args[5];
- Cardinal i, lst_size;
- String *lst;
- Local char *nolist[] = { "", NULL }; /* make the list widget happy */
- Local char tmpfile[256];
-
- /* show the header */
- displayHeader(iw, n);
-
- /* show the menu */
- if (!n->menu.l) {
- lst = nolist;
- lst_size = 1;
- }
- else {
- lst = n->menu.l;
- lst_size = IDX(n->menu.t);
- }
- XawPanedAllowResize(iw->info.menuList, TRUE);
- XawListChange(iw->info.menuList, lst, lst_size, 0, TRUE);
-
- /* change the xref list */
- if (!n->xref.l) {
- lst = nolist;
- lst_size = 1;
- }
- else {
- lst = n->xref.l;
- lst_size = IDX(n->xref.t);
- }
- XawPanedAllowResize(iw->info.xrefList, TRUE);
- XawListChange(iw->info.xrefList, lst, lst_size, 0, TRUE);
-
- /* Show the new text */
- i = 0;
- if (iw->info.tempfile) {
- extern int unlink();
-
- unlink(iw->info.tempfile);
- iw->info.tempfile = NULL;
- }
- if (I_START(n->text)) {
- FILE *fp;
-
- iw->info.tempfile = tmpnam(tmpfile);
- if ((fp = fopen(iw->info.tempfile, "w")) == NULL) {
- XtError("info: Can't open temporary file");
- return;
- }
- else {
- fwrite(START(iw) + I_START(n->text), 1, I_LEN(n->text), fp);
- fclose(fp);
- }
- XtSetArg(args[i], XtNstring, iw->info.tempfile); i++;
- }
- else {
- iw->info.tempfile = NULL;
- XtSetArg(args[i], XtNstring, iw->info.file); i++;
- }
- XtSetValues(iw->info.nodeText, args, i);
- }
-
- /* display the header information */
- Local void displayHeader(iw, n)
- InfoWidget iw;
- NodeInfo *n;
- {
- Arg args[5];
- Cardinal i;
- String tmp;
- int sensitive;
-
- /* set the file name */
- tmp = strconcat("File: ", file_name(iw->info.file));
- i = 0;
- XtSetArg(args[i], XtNlabel, tmp); i++;
- XtSetValues(iw->info.fileLabel, args, i);
-
- /* set the node name */
- i = 0;
- if ((tmp = offsetToString(iw, n->name)) != NULL)
- sensitive = TRUE;
- else
- sensitive = FALSE;
- XtSetArg(args[i], XtNlabel, strconcat("Node: ", tmp)); i++;
- XtSetArg(args[i], XtNsensitive, sensitive); i++;
- XtSetValues(iw->info.nodeLabel, args, i);
-
- /* set the prev */
- i = 0;
- if ((tmp = offsetToString(iw, n->prev)) != NULL)
- sensitive = TRUE;
- else
- sensitive = FALSE;
- XtSetArg(args[i], XtNlabel, strconcat("Prev: ", tmp)); i++;
- XtSetArg(args[i], XtNsensitive, sensitive); i++;
- XtSetValues(iw->info.prevCmd, args, i);
-
- /* set the up */
- i = 0;
- if ((tmp = offsetToString(iw, n->up)) != NULL)
- sensitive = TRUE;
- else
- sensitive = FALSE;
- XtSetArg(args[i], XtNlabel, strconcat("Up: ", tmp)); i++;
- XtSetArg(args[i], XtNsensitive, sensitive); i++;
- XtSetValues(iw->info.upCmd, args, i);
-
- /* set the next */
- i = 0;
- if ((tmp = offsetToString(iw, n->next)) != NULL)
- sensitive = TRUE;
- else
- sensitive = FALSE;
- XtSetArg(args[i], XtNlabel, strconcat("Next: ", tmp)); i++;
- XtSetArg(args[i], XtNsensitive, sensitive); i++;
- XtSetValues(iw->info.nextCmd, args, i);
- }
-
- /*
- * Look for tag table information in the current buffer. If tag table
- * is indirect, return TRUE, else return false.
- */
- Local Boolean parseTags(iw)
- InfoWidget iw;
- {
- String start, s1;
- char tmp[MAXSTR];
- Boolean indirect = FALSE;
- int i;
-
- /*
- * go back about 8 lines. I don't know if this will always back up
- * past the end marker, but Emacs info seems to think so.
- */
- start = END(iw);
- i = 0;
- while (i < 8)
- if (*(--start) == '\n')
- i++;
-
- start = search(iw, start, END(iw), TAGEND_TOKEN, TRUE);
- if (start && (start = search_back(iw, start, START(iw),
- TAGTABLE_TOKEN, TRUE))) {
- ALLOC_TABLE(TAGTABLE(iw));
- /* we were searching backward so move over the token */
- start += strlen(TAGTABLE_TOKEN);
- if ((s1 = search(iw, start, start + strlen(ITAGTABLE_TOKEN) + 10,
- ITAGTABLE_TOKEN, TRUE)) != NULL) {
- indirect = TRUE;
- start = s1;
- }
- while ((start = search(iw, start, END(iw), NODE_TOKEN, FALSE))
- != NULL) {
- MAYBE_BUMP_TABLE(TAGTABLE(iw));
- strccpy(tmp, start, DEL_CHAR);
- I_NAME(TPOS(TAGTABLE(iw))) = XtNewString(tmp);
- start += strlen(tmp) + 1;
- sscanf(start, "%d", &I_OFFSET(TPOS(TAGTABLE(iw))));
- INCP(TAGTABLE(iw));
- }
- ROUND_TABLE(TAGTABLE(iw));
- }
- else if (TAGTABLE(iw).table)
- FREE_TAG_TABLE(TAGTABLE(iw));
- return(indirect);
- }
-
- /* Look for indirect file information in the current buffer */
- Local void parseIndirect(iw, needIndirect)
- InfoWidget iw;
- Boolean needIndirect;
- {
- String start;
- char tmp[MAXSTR], *s1;
-
- if (start = search(iw, START(iw), END(iw), INDIRECT_TOKEN, TRUE)) {
- /* move backwards looking for the INFO_CHAR */
- for (s1 = start; s1 >= START(iw) && *s1 != INFO_CHAR; s1--);
- if (s1 < START(iw)) {
- message(iw, "?Invalid indirect table for %s!", iw->info.file);
- return;
- }
- else
- HDRSIZE(iw) = INTOFF(START(iw), s1);
- ALLOC_TABLE(INDIRECT(iw));
- for (IDX(INDIRECT(iw)) = 0; *start != INFO_CHAR; INCP(INDIRECT(iw))){
- MAYBE_BUMP_TABLE(INDIRECT(iw));
- strccpy(tmp, start, ':');
- I_NAME(TPOS(INDIRECT(iw))) = XtNewString(tmp);
- start += strlen(tmp) + 1;
- sscanf(start, "%d", &I_OFFSET(TPOS(INDIRECT(iw))));
- start = index(start, '\n') + 1;
- }
- ROUND_TABLE(INDIRECT(iw));
- }
- else if (needIndirect)
- message(iw, "?Indirect table not found for %s! Hilfe!",
- iw->info.file);
- else if (INDIRECT(iw).table)
- FREE_TAG_TABLE(INDIRECT(iw));
- }
-
- /*****************************************************************************
- * Text display functions. *
- *****************************************************************************/
-
- /* display a message in the message area */
- Local void message(iw, s, p1, p2, p3)
- InfoWidget iw;
- String s;
- caddr_t p1, p2, p3;
- {
- char msgbuf[MAXSTR];
- Arg args[5];
- Cardinal i;
-
- i = 0;
- if (s) {
- sprintf(msgbuf, s, p1, p2, p3);
- XtSetArg(args[i], XtNlabel, msgbuf); i++;
- XtSetValues(iw->info.messageLabel, args, i);
- XBell(XtDisplay(iw), 50);
- if (*s == '?') /* a dire warning */
- XtWarning(msgbuf);
- }
- else { /* clear the message area */
- XtSetArg(args[i], XtNlabel, " "); i++;
- XtSetValues(iw->info.messageLabel, args, i);
- }
- }
-
- /* display the current node/file */
- Local void showStatus(iw, n)
- InfoWidget iw;
- NodeInfo *n;
- {
- char statbuf[MAXSTR];
- Arg args[5];
- Cardinal i;
- String sub = iw->info.subFile;
-
- sprintf(statbuf, "(%s)%s, %d characters%s", file_name(iw->info.file),
- iw->info.node, n->length,
- sub ? strconcat(", subfile: ", sub) : ".");
- i = 0;
- XtSetArg(args[i], XtNlabel, statbuf); i++;
- XtSetValues(iw->info.statusLabel, args, i);
- }
-
- /*****************************************************************************
- * Various callback/action routines *
- *****************************************************************************/
-
- Local void NodeDir(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- if (getNode(iw, "dir", "Top", NULL) == FALSE)
- message(iw, "?Yow! The directory seems to have disappeared!\n");
- }
-
- Local void NodeNext(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- do_next(NULL, iw, NULL);
- }
-
- Local void NodePrev(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- do_prev(NULL, iw, NULL);
- }
-
-
- Local void NodeUp(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- do_up(NULL, iw, NULL);
- }
-
- Local void NodeTop(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- if (getNode(iw, NULL, "Top", NULL) == FALSE)
- message(iw, "?This node has no top! Bad joss!");
- }
-
- Local void NodeLast(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- NodeInfo *tmp;
- InfoWidget iw = TOP_WIDGET(w);
-
- if ((tmp = popNode(iw)) != NULL) {
- if (getNode(iw, tmp->file, tmp->node, tmp) == FALSE)
- message(iw, "?Can't pop back to last node! We're hosed!");
- }
- else
- message(iw, "No further history.");
- }
-
- Local void NodeXRef(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- do_xref(NULL, iw, NULL);
- }
-
- Local void NodeGoto(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- do_goto(NULL, iw, NULL);
- }
-
- Local void NodeSearch(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- do_search(NULL, iw, NULL);
- }
-
- Local void NodeQuit(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- if (XtHasCallbacks(iw, XtNcallback) != XtCallbackHasSome)
- message(iw, "Sorry, I just don't know how to quit.");
- else
- XtCallCallbacks(iw, XtNcallback, NULL);
- }
-
- Local void NodeTutorial(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- InfoWidget iw = TOP_WIDGET(w);
-
- if (getNode(iw, "info", "Help", NULL) == FALSE)
- message(iw, "?Hmmm. I can't seem to find the info tutorial!");
- }
-
- /*
- * Seems there should be a better way of doing this. Methinks the
- * XtCallbackPopdown() stuff isn't general enough. Should be a way of
- * doing this (and only this).
- */
- Local void popdown(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- XtPopdown((Widget)client_data);
- }
-
- Local void NodeHelp(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- Cardinal i;
- Arg args[5];
- InfoWidget iw = TOP_WIDGET(w);
-
- if (!iw->info.helpPopup) {
- Widget hpane, htext;
- Local XtCallbackRec cb[2];
- Local char pophelp[] = "None<Key>q: MenuPopdown(help)\n";
-
- /* create the help popup */
- i = 0;
- XtSetArg(args[i], XtNheight, 300); i++;
- XtSetArg(args[i], XtNwidth, 400); i++;
- iw->info.helpPopup = XtCreatePopupShell("help",
- topLevelShellWidgetClass,
- iw, args, i);
- i = 0;
- hpane = XtCreateManagedWidget("pane", panedWidgetClass,
- iw->info.helpPopup, args, i);
- i = 0;
- cb[0].callback = popdown;
- cb[0].closure = (caddr_t)iw->info.helpPopup;
- XtSetArg(args[i], XtNcallback, cb); i++;
- XtCreateManagedWidget("Close", commandWidgetClass,
- hpane, args, i);
- i = 0;
- XtSetArg(args[i], XtNtype, XawAsciiFile); i++;
- XtSetArg(args[i], XtNstring, iw->info.helpFile); i++;
- XtSetArg(args[i], XtNeditType, XawtextRead); i++;
- XtSetArg(args[i], XtNscrollVertical, XawtextScrollWhenNeeded); i++;
- XtSetArg(args[i], XtNwrap, XawtextWrapWord); i++;
- htext = XtCreateManagedWidget("text", asciiTextWidgetClass,
- hpane, args, i);
- XtOverrideTranslations(htext, XtParseTranslationTable(textTrans));
- XtOverrideTranslations(htext, XtParseTranslationTable(pophelp));
- }
- XtPopup(iw->info.helpPopup, XtGrabNonexclusive);
- }
-
- Local void NodeMenuSelectByNumber(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- Import int atoi();
- int menunum;
- int nitems;
- InfoWidget iw = TOP_WIDGET(w);
-
- nitems = IDX(CURNODE(iw)->menu.t);
- menunum = atoi(*params);
- /* menu number of zero means get menu from arg area */
- if (!menunum)
- do_menu(NULL, iw, NULL);
- else if (!nitems)
- message(iw, "No menu for this node.");
- else if (menunum > nitems)
- message(iw, "There are only %d menu items.", nitems);
- else {
- XawListHighlight(iw->info.menuList, menunum - 1);
- if (getNode(iw, NULL,
- offsetToString(iw,CURNODE(iw)->menu.t.table[menunum-1]),
- NULL) == FALSE)
- message(iw, "?Can't find node for menu item #%s", *params);
- }
- }
-
- Local void NodePrint(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- Import int unlink();
- String tmp;
- FILE *out;
- InfoWidget iw = TOP_WIDGET(w);
-
- /* if you don't have this routine in your stdlib, make one up */
- tmp = tmpnam(NULL);
-
- if (!CURNODE(iw))
- message(iw, "?No current node?");
- else if ((out = fopen(tmp, "w")) == NULL)
- message(iw, "?Can't open temporary file '%s'.", tmp);
- else {
- String s1 = NSTART(iw, CURNODE(iw));
- String s2 = NEND(iw, CURNODE(iw));
- char syscmd[MAXSTR];
- int stat;
-
- message(iw, "Sending '%s' to the printer, please wait..",
- iw->info.node);
-
- while (s1 < s2) {
- fputc(*s1, out);
- s1++;
- }
- fclose(out);
- sprintf(syscmd, "%s %s", iw->info.printCmd, tmp);
- if ((stat = system(syscmd)) != 0)
- message(iw, "?'%s' failed with exit status %d. Help!",
- syscmd, stat);
- else
- message(iw, "Finished printing.");
- unlink(tmp);
- }
-
-
- }
-
- Local void do_prev(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- String tmp;
-
- if ((tmp = offsetToString(iw, CURNODE(iw)->prev))) {
- if (getNode(iw, NULL, tmp, NULL) == FALSE)
- message(iw, "?Can't find the previous (%s) for this node.",
- tmp);
- }
- else
- message(iw, "Node has no previous");
- }
-
- Local void do_up(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- String tmp;
-
- if ((tmp = offsetToString(iw, CURNODE(iw)->up))) {
- if (getNode(iw, NULL, tmp, NULL) == FALSE)
- message(iw, "?Can't find the up (%s) for this node.", tmp);
- }
- else
- message(iw, "Node has no up");
- }
-
- Local void do_next(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- String tmp;
-
- if ((tmp = offsetToString(iw, CURNODE(iw)->next))) {
- if (getNode(iw, NULL, tmp, NULL) == FALSE)
- message(iw, "?Can't find the next (%s) for this node.", tmp);
- }
- else
- message(iw, "Node has no next");
- }
-
- Local void do_xref(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- String tmp;
-
- if ((tmp = get_arg(iw)) != NULL) {
- if ((tmp = trueName(iw, CURNODE(iw)->xref, tmp)) == NULL)
- message(iw, "No cross reference entry named '%s' in this node.",
- get_arg(iw));
- else if (getNode(iw, NULL, tmp, NULL) == FALSE)
- message(iw, "?Can't find node for xref item '%s'!",
- get_arg(iw));
- }
- else
- message(iw, "You must supply the name of a cross-reference.");
- }
-
- Local void do_menu(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- String tmp;
-
- if ((tmp = get_arg(iw)) != NULL) {
- if ((tmp = trueName(iw, CURNODE(iw)->menu, tmp)) == NULL)
- message(iw, "No menu entry named '%s' in this node.",
- get_arg(iw));
- else if (getNode(iw, NULL, tmp, NULL) == FALSE)
- message(iw, "?Can't find node for menu item '%s'",
- get_arg(iw));
- }
- else
- message(iw, "You must supply a menu entry name.");
- }
-
- Local void do_goto(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- String tmp;
-
- if ((tmp = get_arg(iw)) != NULL) {
- if (getNode(iw, NULL, tmp, NULL) == FALSE)
- message(iw, "Can't find a node named %s", tmp);
- }
- else
- message(iw, "You must supply the name of a node to go to.");
- }
-
- /*
- * Implement a somewhat simplistic search strategy. If file has an indirect
- * list, look for a match in the tag table (since just looking in the current
- * file probably wouldn't be very useful). If not, then search the current
- * file. If we're successful in either case, record the position (in the
- * tags table or the file) so that we don't hit it again right away.
- */
- Local void do_search(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- String tmp, s;
- char name[MAXSTR];
- Local struct {
- String file;
- caddr_t pos;
- } oldPos;
-
- if ((tmp = get_arg(iw)) != NULL) {
- /* if remembered position is invalid, reset it */
- if (strcomp(oldPos.file, iw->info.file)) {
- oldPos.file = iw->info.file;
- oldPos.pos = NULL;
- }
- if (INDIRECT(iw).table) {
- ID_P i;
- int len = strlen(tmp);
-
- if (oldPos.pos)
- i = (ID_P)oldPos.pos;
- else
- i = TAGTABLE(iw).table;
- /* do a tags search */
- while (I_NAME(*i)) {
- if (!strncomp(I_NAME(*i), tmp, len))
- break;
- i++;
- }
- /* success? */
- if (I_NAME(*i)) {
- oldPos.pos = (caddr_t)(i + 1);
- if (getNode(iw, iw->info.file, I_NAME(*i), NULL) == FALSE)
- message(iw, "?Can't find node for tag %s!",
- I_NAME(*i));
- }
- else {
- message(iw, "Tag search for '%s' failed.", tmp);
- oldPos.pos = NULL;
- }
- }
- else {
- if (oldPos.pos)
- s = (String)oldPos.pos;
- else
- s = START(iw);
- if ((s = search(iw, s, END(iw),
- strconcat(NODE_TOKEN, tmp),
- TRUE)) != NULL) {
- int i;
-
- oldPos.pos = (caddr_t)s;
- strcpy(name, tmp);
- i = strlen(name);
- while (!index(NAME, *s))
- name[i++] = *s++;
- name[i] = '\0';
- if (getNode(iw, iw->info.file, name, NULL) == FALSE)
- message(iw, "?Can't find node name in search!");
- }
- else {
- message(iw, "Search for '%s' failed.", tmp);
- oldPos.pos = NULL;
- }
- }
- }
- else
- message(iw, "You must supply a search string.");
- }
-
- /* These two handle selections from the menu and xref lists */
-
- Local void do_menu_sel(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- XawListReturnStruct *rs = (XawListReturnStruct *)call_data;
-
- if (getNode(iw, NULL, trueName(iw, CURNODE(iw)->menu, rs->string),
- NULL) == FALSE)
- message(iw, "?Can't find node for menu item '%s'", rs->string);
- }
-
- Local void do_xref_sel(w, client_data, call_data)
- Widget w;
- caddr_t client_data;
- caddr_t call_data;
- {
- InfoWidget iw = (InfoWidget)client_data;
- XawListReturnStruct *rs = (XawListReturnStruct *)call_data;
-
- if (getNode(iw, NULL, trueName(iw, CURNODE(iw)->xref, rs->string),
- NULL) == FALSE)
- message(iw, "?Can't find node for cross reference '%s'", rs->string);
- }
-
- /*****************************************************************************
- * Utility functions. *
- *****************************************************************************/
-
- /*
- * Search for a file along a path, returning the complete path name if found.
- * This routine uses fopen() rather than access() to determine whether a file
- * exists (and is readable) because access()'s argument macros [X_OK, R_OK, ..]
- * tend to be in different places on different unix's and it's a pain to find
- * them reliably.
- */
- Local String find_file(path, name)
- String path, name;
- {
- FILE *tmp = NULL;
- String cp = path;
- Boolean more_path = TRUE;
- Local char dir[MAXPATHLEN];
-
- dir[0] = '\0';
-
- /* absolute path name? */
- if (name[0] == '/') {
- if ((tmp = fopen(name, "r")) != NULL) {
- fclose(tmp);
- return(name);
- }
- else
- name = file_name(name);
- }
- while (!tmp && more_path) {
- if ((cp = index(path, ':')) != NULL) {
- strncpy(dir, path, cp - path);
- dir[cp - path] = '\0';
- strcat(dir, "/");
- path = cp + 1;
- }
- else {
- strcpy(dir, path);
- strcat(dir, "/");
- more_path = FALSE;
- }
- strcat(dir, name);
- tmp = fopen(dir, "r");
- if (!tmp) /* if we failed, try again in lower case */
- tmp = fopen(downcase(dir), "r");
- }
- if (tmp)
- fclose(tmp);
- if (dir[0])
- return(dir);
- else
- return(NULL);
- }
-
- /* return the file part of a path name */
- Local Inline String file_name(s)
- register String s;
- {
- register int i = strlen(s);
-
- while (i) {
- if (s[i - 1] == '/')
- return(s + i);
- i--;
- }
- return(s);
- }
-
- /* strip evil tab/formfeed/newline chars from a string (replacing w/blanks) */
- Local Inline String strip_evil(s)
- register String s;
- {
- if (s) {
- while (*s) {
- if (isspace(*s))
- *s = ' ';
- s++;
- }
- }
- return(s);
- }
-
- /* Convert from an offset ID to a string. */
- Local Inline String offsetToString(iw, blk)
- InfoWidget iw;
- ID blk;
- {
- Local char ret[MAXSTR];
-
- if (I_LEN(blk) != 0) {
- strncpy(ret, START(iw) + I_START(blk), I_LEN(blk));
- ret[I_LEN(blk)] = '\0';
- return(ret);
- }
- else
- return(NULL);
- }
-
- /* chew through white space */
- Local Inline String eat_whitespace(s)
- register String s;
- {
- while (*s && isspace(*s))
- s++;
- return(s);
- }
-
- /* Get the argument area as a string */
- Local String get_arg(iw)
- InfoWidget iw;
- {
- String str;
- Arg args[1];
-
- XtSetArg(args[0], XtNstring, &str);
- XtGetValues(iw->info.argText, args, 1);
- if (*str)
- return(str);
- else
- return(NULL);
- }
-
- /* look up the actual name of a list item */
- Local String trueName(iw, lst, name)
- InfoWidget iw;
- IDList lst;
- String name;
- {
- register int i;
-
- for (i = 0; i < lst.t.idx; i++)
- if (!strcomp(lst.l[i], name))
- return(offsetToString(iw, lst.t.table[i]));
- return(NULL);
- }
-
- /* Search for a string. */
- Local String search(iw, start, end, str, igncase)
- InfoWidget iw;
- register String start, end, str;
- Boolean igncase;
- {
- register String ind = str;
- register String stop = str + strlen(str);
- register int comp;
-
- while (start < end) {
- if (!igncase)
- comp = (*start == *ind);
- else
- comp = (tolower(*start) == tolower(*ind));
- if (!comp) {
- if (ind != str)
- ind = str;
- else
- start++;
- }
- else {
- if (++start <= end && ++ind == stop)
- return(start);
- }
- }
- return(NULL);
- }
-
- /*
- * Like search(), but in the reverse direction.
- */
- Local String search_back(iw, start, end, str, igncase)
- InfoWidget iw;
- register String start, end, str;
- Boolean igncase;
- {
- register String ind;
- register String stop;
- register int comp;
-
- ind = str = reverse(str);
- stop = ind + strlen(ind);
-
- while (start > end) {
- if (!igncase)
- comp = (*start == *ind);
- else
- comp = (tolower(*start) == tolower(*ind));
- if (!comp) {
- if (ind != str)
- ind = str;
- else
- start--;
- }
- else {
- start--;
- if (++ind == stop)
- return(start);
- }
- }
- return(NULL);
- }
-
- /*
- * Safe and sane strcmp. Deals with null pointer for either arg and ignores
- * case.
- */
- Local Inline int strcomp(s1, s2)
- register String s1, s2;
- {
- if (s1 && s2) {
- if (strlen(s1) != strlen(s2))
- return(-1);
-
- while (*s1 && *s2 && (tolower(*s1) == tolower(*s2)))
- s1++, s2++;
- if (!*s1 && !*s2)
- return(0);
- else if (*s1 < *s2)
- return (-1);
- else
- return(1);
- }
- else if (!s1 && !s2)
- return(0);
- else if (!s1 && s2)
- return(-1);
- else
- return(1);
- }
-
- /* like above, but stops after n characters */
- Local Inline int strncomp(s1, s2, n)
- register String s1, s2;
- int n;
- {
- register String s3 = s2 + n;
-
- if (s1 && s2) {
- while (*s1 && *s2 && (tolower(*s1) == tolower(*s2)) && (s2 < s3))
- s1++, s2++;
- if (!*s1 && !*s2 || s2 == s3)
- return(0);
- else if (*s1 < *s2)
- return (-1);
- else
- return(1);
- }
- else if (!s1 && !s2)
- return(0);
- else if (!s1 && s2)
- return(-1);
- else
- return(1);
- }
-
- /* Copy s2 to s1 up to (but not including) character c */
- Local Inline void strccpy(s1, s2, c)
- register String s1, s2;
- register char c;
- {
- while (*s2 && *s2 != c)
- *(s1++) = *(s2++);
- *s1 = '\0';
- }
-
- /*
- * Return integer subscript of character 'c' in string 's'.
- * (why doesn't this already exist in a library somewhere?).
- */
- Local Inline int iindex(s, c)
- register char *s, c;
- {
- register char *cp;
-
- if (!s)
- return(-1);
- cp = index(s, c);
- if (cp)
- return(cp - s);
- else
- return(-1);
- }
-
- Local String substr(s, p1, p2)
- register String s;
- register int p1, p2;
- {
- Local char ret[MAXSTR];
- register int i = 0;
-
- if (p1 > p2) {
- sprintf(ret, "substr: start %d, end %d. start must be <= end",
- p1, p2);
- XtWarning(ret);
- return(NULL);
- }
- if (p2 - p1 > MAXSTR) {
- sprintf(ret, "substr: end - start is > max len of %d", MAXSTR);
- XtWarning(ret);
- return(NULL);
- }
- while (p1 <= p2)
- ret[i++] = s[p1++];
- ret[i] = '\0';
- return(ret);
- }
-
- /*
- * Safely concatenate two strings into static area, returning pointer to
- * result.
- */
- Local String strconcat(s1, s2)
- register String s1, s2;
- {
- Local char ret[MAXSTR];
- int len1;
-
- if (s1) {
- if ((len1 = strlen(s1)) >= MAXSTR) {
- sprintf(ret, "strconcat: length of s1 > MAX (%d)", MAXSTR);
- XtWarning(ret);
- return(NULL);
- }
- else
- strcpy(ret, s1);
- if (s2) {
- if (len1 + strlen(s2) > MAXSTR) {
- sprintf(ret, "strconcat: length of s1 + s2 is > MAX (%d)",
- MAXSTR);
- XtWarning(ret);
- }
- else
- strcat(ret, s2);
- }
- return(ret);
- }
- else
- return(NULL);
- }
-
- /* reverse a string so that a simple reverse search may be done on it */
- Local String reverse(s)
- register String s;
- {
- Local char ret[MAXSTR];
- register int i, len;
-
- if ((len = strlen(s)) > MAXSTR) {
- sprintf(ret, "reverse: string too long to reverse. MAX is %d",
- MAXSTR);
- XtWarning(ret);
- return(NULL);
- }
- else {
- i = 0;
- while (len)
- ret[i++] = s[--len];
- ret[i] = '\0';
- return(ret);
- }
- }
-
- /* convert a string to lower case */
- Local Inline String downcase(s)
- register String s;
- {
- String orig = s;
-
- if (s)
- while (*s) {
- *s = tolower(*s);
- s++;
- }
- return(orig);
- }
-