summaryrefslogtreecommitdiff
path: root/search.c
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:49:23 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:49:23 +0000
commit36fca7804971e1b209138fcf82aee2d74cb2583e (patch)
tree5359a5d57d4193ee2954f56eb780f0f6da312344 /search.c
Initial revisionXORG-STABLE
Diffstat (limited to 'search.c')
-rw-r--r--search.c395
1 files changed, 395 insertions, 0 deletions
diff --git a/search.c b/search.c
new file mode 100644
index 0000000..052dae0
--- /dev/null
+++ b/search.c
@@ -0,0 +1,395 @@
+/* $XConsortium: search.c,v 1.21 94/04/17 20:43:58 rws Exp $ */
+/*
+
+Copyright (c) 1987, 1988 X Consortium
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of the X Consortium shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the X Consortium.
+
+*/
+/* $XFree86: xc/programs/xman/search.c,v 1.5 2001/01/27 17:24:27 herrb Exp $ */
+
+
+#include "globals.h"
+#include "vendor.h"
+
+/* Map <CR> and control-M to goto begining of file. */
+
+#define SEARCHARGS 10
+
+FILE * DoManualSearch(ManpageGlobals *man_globals, char * string);
+static int BEntrySearch(char * string, char ** first, int number);
+
+/* Function Name: MakeSearchWidget
+ * Description: This Function Creates the Search Widget.
+ * Arguments: man_globals - the pseudo globas for this manpage.
+ * w - the widgets parent
+ * Returns: the search widget.
+ */
+
+void
+MakeSearchWidget(ManpageGlobals * man_globals, Widget parent)
+{
+ Widget dialog, command, text, cancel;
+ Arg arglist[2];
+ Cardinal num_args = 0;
+
+ XtSetArg(arglist[0], XtNtransientFor, parent);
+ man_globals->search_widget = XtCreatePopupShell(SEARCHNAME,
+ transientShellWidgetClass,
+ parent,
+ arglist, 1);
+
+ if (resources.clear_search_string) {
+ XtSetArg(arglist[0], XtNvalue, ""); num_args++;
+ }
+
+ dialog = XtCreateManagedWidget(DIALOG, dialogWidgetClass,
+ man_globals->search_widget,
+ arglist, num_args);
+
+ if ( (text = XtNameToWidget(dialog, "value")) == (Widget) NULL)
+ PopupWarning(NULL, "Could not find text widget in MakeSearchWidget.");
+ else
+ XtSetKeyboardFocus(dialog, text);
+
+ XawDialogAddButton(dialog, MANUALSEARCH, NULL, NULL);
+ XawDialogAddButton(dialog, APROPOSSEARCH, NULL, NULL);
+ XawDialogAddButton(dialog, CANCEL, NULL, NULL);
+
+/*
+ * This is a bit gross, but it get the cancel button underneath the
+ * others, and forms them up to the right size..
+ */
+
+ if ( ((command = XtNameToWidget(dialog, MANUALSEARCH)) == (Widget) NULL) ||
+ ((cancel = XtNameToWidget(dialog, CANCEL)) == (Widget) NULL) )
+ PopupWarning(NULL,
+ "Could not find manual search widget in MakeSearchWidget.");
+ else {
+ static char * half_size[] = {
+ MANUALSEARCH, APROPOSSEARCH, NULL
+ };
+ static char * full_size[] = {
+ "label", "value", CANCEL, NULL
+ };
+
+ num_args = 0;
+ XtSetArg(arglist[num_args], XtNfromVert, command); num_args++;
+ XtSetArg(arglist[num_args], XtNfromHoriz, NULL); num_args++;
+ XtSetValues(cancel, arglist, num_args);
+ FormUpWidgets(dialog, full_size, half_size);
+ }
+
+}
+
+/* Function Name: SearchString
+ * Description: Returns the search string.
+ * Arguments: man_globals - the globals.
+ * Returns: the search string.
+ */
+
+static char *
+SearchString(
+ManpageGlobals * man_globals)
+{
+ Widget dialog;
+
+ dialog = XtNameToWidget(man_globals->search_widget, DIALOG);
+ if (dialog != NULL)
+ return(XawDialogGetValueString(dialog));
+
+ PopupWarning(man_globals,
+ "Could not get the search string, no search will be preformed.");
+ return(NULL);
+}
+
+
+/* Function Name: DoSearch
+ * Description: This function performs a search for a man page or apropos
+ * search upon search string.
+ * Arguments: man_globals - the pseudo globas for this manpage.
+ * type - the type of search.
+ * Returns: none.
+ */
+
+#define LOOKLINES 6
+
+/*
+ * Manual searches look through the list of manual pages for the right one
+ * with a binary search.
+ *
+ * Apropos searches still exec man -k.
+ *
+ * If nothing is found then I send a warning message to the user, and do
+ * nothing.
+ */
+
+FILE *
+DoSearch(ManpageGlobals * man_globals, int type)
+{
+ char cmdbuf[BUFSIZ],*mantmp, *manpath;
+ char tmp[BUFSIZ],path[BUFSIZ];
+ char string_buf[BUFSIZ], cmp_str[BUFSIZ], error_buf[BUFSIZ];
+ char * search_string = SearchString(man_globals);
+ FILE * file;
+#ifdef HAS_MKSTEMP
+ int fd;
+#endif
+ int count;
+ Boolean flag;
+
+ if (search_string == NULL) return(NULL);
+
+ /* If the string is empty or starts with a space then do not search */
+
+ if ( streq(search_string,"") ) {
+ PopupWarning(man_globals, "Search string is empty.");
+ return(NULL);
+ }
+
+ if (search_string[0] == ' ') {
+ PopupWarning(man_globals, "First character cannot be a space.");
+ return(NULL);
+ }
+
+ if (type == APROPOS) {
+ char label[BUFSIZ];
+
+ strcpy(tmp, MANTEMP); /* get a temp file. */
+#ifdef HAS_MKSTEMP
+ fd = mkstemp(tmp);
+ if (fd < 0) {
+ PopupWarning(man_globals, "Cant create temp file");
+ return NULL;
+ }
+#else
+ (void)mktemp(tmp);
+#endif
+ mantmp = tmp;
+
+ manpath=getenv("MANPATH");
+ if (manpath == NULL || streq(manpath,"") ) {
+#ifdef MANCONF
+ if (!ReadManConfig(path))
+#endif
+ {
+ strcpy(path,SYSMANPATH);
+#ifdef LOCALMANPATH
+ strcat(path,":");
+ strcat(path,LOCALMANPATH);
+#endif
+ }
+ } else {
+ strcpy(path,manpath);
+ }
+
+ sprintf(label,"Results of apropos search on: %s", search_string);
+
+#ifdef NO_MANPATH_SUPPORT /* not quite correct, but the best I can do. */
+ sprintf(cmdbuf, APROPOS_FORMAT, search_string, mantmp);
+#else
+ sprintf(cmdbuf, APROPOS_FORMAT, path, search_string, mantmp);
+#endif
+
+ if(system(cmdbuf) != 0) { /* execute search. */
+ sprintf(error_buf,"Something went wrong trying to run %s\n",cmdbuf);
+ PopupWarning(man_globals, error_buf);
+ }
+
+#ifdef HAS_MKSTEMP
+ if ((file = fdopen(fd, "r")) == NULL)
+#else
+ if((file = fopen(mantmp,"r")) == NULL)
+#endif
+ PrintError("lost temp file? out of temp space?");
+
+/*
+ * Since we keep the FD open we can unlink the file safely, this
+ * will keep extra files out of /tmp.
+ */
+
+ unlink(mantmp);
+
+ sprintf(string_buf,"%s: nothing appropriate", search_string);
+
+ /*
+ * Check first LOOKLINES lines for "nothing appropriate".
+ */
+
+ count = 0;
+ flag = FALSE;
+ while ( (fgets(cmp_str, BUFSIZ, file) != NULL) && (count < LOOKLINES) ) {
+ if ( cmp_str[strlen(cmp_str) - 1] == '\n') /* strip off the '\n' */
+ cmp_str[strlen(cmp_str) - 1] = '\0';
+
+ if (streq(cmp_str, string_buf)) {
+ flag = TRUE;
+ break;
+ }
+ count++;
+ }
+
+ /*
+ * If the file is less than this number of lines then assume that there is
+ * nothing apropriate found. This does not confuse the apropos filter.
+ */
+
+ if (flag) {
+ fclose(file);
+ file = NULL;
+ ChangeLabel(man_globals->label,string_buf);
+ return(NULL);
+ }
+
+ strcpy(man_globals->manpage_title,label);
+ ChangeLabel(man_globals->label,label);
+ fseek(file, 0L, 0); /* reset file to point at top. */
+ }
+ else { /* MANUAL SEACH */
+ file = DoManualSearch(man_globals, search_string);
+ if (file == NULL) {
+ sprintf(string_buf,"No manual entry for %s.", search_string);
+ ChangeLabel(man_globals->label, string_buf);
+ if (man_globals->label == NULL)
+ PopupWarning(man_globals, string_buf);
+ return(NULL);
+ }
+ }
+
+ if (resources.clear_search_string) {
+ Arg arglist[1];
+ Widget dialog;
+
+ dialog = XtNameToWidget(man_globals->search_widget, DIALOG);
+ if (dialog == NULL)
+ PopupWarning(man_globals, "Could not clear the search string.");
+
+ XtSetArg(arglist[0], XtNvalue, "");
+ XtSetValues(dialog, arglist, (Cardinal) 1);
+ }
+
+ return(file);
+}
+
+/* Function Name: DoManualSearch
+ * Description: performs a manual search.
+ * Arguments: man_globals - the manual page specific globals.
+ * Returns: the filename of the man page.
+ */
+
+#define NO_ENTRY -100
+
+FILE *
+DoManualSearch(ManpageGlobals *man_globals, char * string)
+{
+ int e_num = NO_ENTRY;
+ int i;
+
+/* search current section first. */
+
+ i = man_globals->current_directory;
+ e_num = BEntrySearch(string, manual[i].entries, manual[i].nentries);
+
+/* search other sections. */
+
+ if (e_num == NO_ENTRY) {
+ i = 0; /* At the exit of the loop i needs to
+ be the one we used. */
+ while ( TRUE ) {
+ if (i == man_globals->current_directory)
+ if (++i >= sections) return(NULL);
+ e_num = BEntrySearch(string, manual[i].entries, manual[i].nentries);
+ if (e_num != NO_ENTRY) break;
+ if (++i >= sections) return(NULL);
+ }
+
+/*
+ * Manual page found in some other section, unhighlight the current one.
+ */
+ if ( man_globals->manpagewidgets.box != NULL)
+ XawListUnhighlight(
+ man_globals->manpagewidgets.box[man_globals->current_directory]);
+ }
+ else {
+ /*
+ * Highlight the element we are searching for if it is in the directory
+ * listing currently being shown.
+ */
+ if ( man_globals->manpagewidgets.box != NULL)
+ XawListHighlight(man_globals->manpagewidgets.box[i], e_num);
+ }
+ return(FindManualFile(man_globals, i, e_num));
+}
+
+/* Function Name: BEntrySearch
+ * Description: binary search through entries.
+ * Arguments: string - the string to match.
+ * first - the first entry in the list.
+ * number - the number of entries.
+ * Returns: a pointer to the entry found.
+ */
+
+static int
+BEntrySearch(
+char * string,
+char ** first,
+int number)
+{
+ int check, cmp, len_cmp, global_number;
+ char *head, *tail;
+
+ global_number = 0;
+ while (TRUE) {
+
+ if (number == 0) {
+ return(NO_ENTRY); /* didn't find it. */
+ }
+
+ check = number/2;
+
+ head = rindex(first[ global_number + check ], '/');
+ if (head == NULL)
+ PrintError("index failure in BEntrySearch");
+ head++;
+
+ tail = rindex(head, '.');
+ if (tail == NULL)
+ /* not an error, some systems (e.g. sgi) have only a .z suffix */
+ tail = head + strlen(head);
+
+ cmp = strncmp(string, head, (tail - head));
+ len_cmp = strlen(string) - (int) (tail - head);
+
+ if ( cmp == 0 && len_cmp == 0) {
+ return(global_number + check);
+ }
+ else if ( cmp < 0 || ((cmp == 0) && (len_cmp < 0)) )
+ number = check;
+ else /* cmp > 0 || ((cmp == 0) && (len_cmp > 0)) */ {
+ global_number += (check + 1);
+ number -= ( check + 1 );
+ }
+ }
+}