source: git/Singular/fehelp.cc @ 9f1850

spielwiese
Last change on this file since 9f1850 was 9f1850, checked in by Olaf Bachmann <obachman@…>, 25 years ago
* cosmetics git-svn-id: file:///usr/local/Singular/svn/trunk@3449 2c84dea3-7e68-4137-9b89-c4e89433aadc
  • Property mode set to 100644
File size: 23.7 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: help system
6*/
7
8#include <string.h>
9#include <unistd.h>
10#include <stdio.h>
11#include <stddef.h>
12#include <stdlib.h>
13#include <time.h>
14#include <limits.h>
15
16#include "mod2.h"
17#include "tok.h"
18#include "mmemory.h"
19#include "febase.h"
20#include "ipid.h"
21#include "ipshell.h"
22#include "libparse.h"
23
24/*****************************************************************
25 *
26 * Declarations: Data  structures
27 *
28 *****************************************************************/
29#define MAX_HE_ENTRY_LENGTH 60
30typedef struct
31{
32  char key[MAX_HE_ENTRY_LENGTH];
33  char node[MAX_HE_ENTRY_LENGTH];
34  char url[MAX_HE_ENTRY_LENGTH];
35  long  chksum;
36} heEntry_s;
37typedef  heEntry_s * heEntry;
38
39typedef void (*heBrowserHelpProc)(heEntry hentry);
40typedef BOOLEAN (*heBrowserInitProc)(int warn);
41
42typedef struct
43{
44  char* browser;
45  heBrowserInitProc init_proc;
46  heBrowserHelpProc help_proc;
47} heBrowser_s;
48typedef heBrowser_s * heBrowser;
49
50/*****************************************************************
51 *
52 * Declarations: Local functions
53 *
54 *****************************************************************/
55static char* strclean(char* str);
56static BOOLEAN heKey2Entry(char* filename, char* key, heEntry hentry);
57static int heReKey2Entry (char* filename, char* key, heEntry hentry);
58static BOOLEAN strmatch(char* s, char* re);
59static BOOLEAN heOnlineHelp(char* s);
60static void heBrowserHelp(heEntry hentry);
61static long heKeyChksum(char* key);
62
63// browser functions
64static BOOLEAN heInfoInit(int);    static void heInfoHelp(heEntry hentry);
65#if ! defined(WINNT) && ! defined(macintosh)
66static BOOLEAN heNetscapeInit(int);static void heNetscapeHelp(heEntry hentry);
67static BOOLEAN heXinfoInit(int);   static void heXinfoHelp(heEntry hentry);
68static BOOLEAN heTkinfoInit(int);  static void heTkinfoHelp(heEntry hentry);
69#endif
70static BOOLEAN heBuiltinInit(int); static void heBuiltinHelp(heEntry hentry);
71static BOOLEAN heDummyInit(int);   static void heDummyHelp(heEntry hentry);
72static BOOLEAN heEmacsInit(int);   static void heEmacsHelp(heEntry hentry);
73
74static heBrowser heCurrentHelpBrowser = NULL;
75
76
77/*****************************************************************
78 *
79 * Definition: available help browsers
80 *
81 *****************************************************************/
82// order is improtant -- first possible help is choosen
83static heBrowser_s heHelpBrowsers[] =
84{
85#if ! defined(WINNT) && ! defined(macintosh)
86  { "netscape", heNetscapeInit, heNetscapeHelp},
87  { "tkinfo",   heTkinfoInit,   heTkinfoHelp},
88  { "xinfo",    heXinfoInit,    heXinfoHelp},
89#endif
90  { "info",     heInfoInit,     heInfoHelp},
91  { "builtin",  heBuiltinInit,  heBuiltinHelp},
92  { "dummy",    heDummyInit,    heDummyHelp},
93  { "emacs",    heEmacsInit,    heEmacsHelp},
94  { NULL, NULL, NULL} // must be the last record
95};
96
97/*****************************************************************
98 *
99 * Implementation: public function
100 *
101 *****************************************************************/
102void feHelp(char *str)
103{
104  str = strclean(str);
105  if (str == NULL) {heBrowserHelp(NULL); return;}
106
107  if (strlen(str) > MAX_HE_ENTRY_LENGTH - 2)  // need room for extra **
108    str[MAX_HE_ENTRY_LENGTH - 3] = '\0';
109
110  BOOLEAN key_is_regexp = (strchr(str, '*') != NULL);
111  heEntry_s hentry;
112  char* idxfile = feResource('x' /*"IdxFile"*/);
113
114  // Try exact match of help string with key in index
115  if (!key_is_regexp && idxfile != NULL && heKey2Entry(idxfile, str, &hentry))
116  {
117    heBrowserHelp(&hentry);
118    return;
119  }
120
121  // try proc help and library help
122  if (! key_is_regexp && heOnlineHelp(str)) return;
123
124  // Try to match approximately with key in index file
125  if (idxfile != NULL)
126  {
127    char* matches = StringSetS("");
128    int found = heReKey2Entry(idxfile, str, &hentry);
129
130    // Try to match with str*
131    if (found == 0)
132    {
133      char mkey[MAX_HE_ENTRY_LENGTH];
134      strcpy(mkey, str);
135      strcat(mkey, "*");
136      found = heReKey2Entry(idxfile, mkey, &hentry);
137      // Try to match with *str*
138      if (found == 0)
139      {
140        mkey[0] = '*';
141        strcpy(mkey + 1, str);
142        strcat(mkey, "*");
143        found = heReKey2Entry(idxfile, mkey, &hentry);
144      }
145
146      // Print warning and return if nothing found
147      if (found == 0)
148      {
149        Warn("No help for topic '%s' (not even for '*%s*')", str, str);
150        WarnS("Try '?;'       for general help");
151        WarnS("or  '?Index;'  for all available help topics");
152        return;
153      }
154    }
155
156    // do help if unique match was found
157    if (found == 1)
158    {
159      heBrowserHelp(&hentry);
160      return;
161    }
162    // Print warning about multiple matches and return
163    if (key_is_regexp)
164      Warn("No unique help for '%s'", str);
165    else
166      Warn("No help for topic '%s'", str);
167    Warn("Try one of");
168    PrintS(matches);
169    PrintS("\n");
170    return;
171  }
172
173  // no idx file, let Browsers deal with it, if they can
174  strcpy(hentry.key, str);
175  *hentry.node = '\0';
176  *hentry.url = '\0';
177  hentry.chksum = 0;
178  heBrowserHelp(&hentry);
179}
180
181char* feHelpBrowser(char* which, int warn)
182{
183  int i = 0;
184  extern void mainSetSingOptionValue(const char* name, char* value);
185  char* mainGetSingOptionValue(const char* name);
186
187  // if no argument, see what we have as value to the option
188  if (which == NULL || *which == '\0')
189    which = mainGetSingOptionValue("browser");
190
191  // if no argument, choose first available help browser
192  if (which == NULL || *which == '\0')
193  {
194    // unles one is already set
195    if (heCurrentHelpBrowser != NULL) goto Finish;
196
197    while (heHelpBrowsers[i].browser != NULL)
198    {
199      if (heHelpBrowsers[i].init_proc(0))
200      {
201        heCurrentHelpBrowser = &(heHelpBrowsers[i]);
202        return heCurrentHelpBrowser->browser;
203      }
204      i++;
205    }
206    // should never get here
207    feReportBug("");
208  }
209
210  // with argument, find matching help browser
211  while (heHelpBrowsers[i].browser != NULL &&
212         strcmp(heHelpBrowsers[i].browser, which) != 0)
213  {i++;}
214
215  if (heHelpBrowsers[i].browser == NULL)
216  {
217    if (warn) Warn("No help browser '%s' available", which);
218  }
219  else
220  {
221    // see whether we can init it
222    if (heHelpBrowsers[i].init_proc(warn))
223    {
224      heCurrentHelpBrowser = &(heHelpBrowsers[i]);
225      goto Finish;
226    }
227  }
228
229  // something went wrong
230  if (heCurrentHelpBrowser == NULL)
231  {
232    // choose first available help browser
233    mainSetSingOptionValue("browser", "");
234    feHelpBrowser();
235    assume(heCurrentHelpBrowser != NULL);
236    if (warn)
237      Warn("Setting help browser to '%s'", heCurrentHelpBrowser->browser);
238    return heCurrentHelpBrowser->browser;
239  }
240  else
241  {
242    // or, leave as is
243    if (warn)
244      Warn("Help browser stays at '%s'",  heCurrentHelpBrowser->browser);
245  }
246
247  Finish:
248  mainSetSingOptionValue("browser", heCurrentHelpBrowser->browser);
249  return heCurrentHelpBrowser->browser;
250}
251
252void  feStringAppendBrowsers(int warn)
253{
254  int i;
255  StringAppendS("Available HelpBrowsers: ");
256
257  i = 0;
258  while (heHelpBrowsers[i].browser != NULL)
259  {
260    if (heHelpBrowsers[i].init_proc(warn))
261      StringAppend("%s, ", heHelpBrowsers[i].browser);
262    i++;
263  }
264  StringAppend("\nCurrent HelpBrowser: %s ", feHelpBrowser());
265}
266
267
268/*****************************************************************
269 *
270 * Implementation: local function
271 *
272 *****************************************************************/
273// Remove whitspaces from beginning and end, return NULL if only whitespaces
274static char* strclean(char* str)
275{
276  if (str == NULL) return NULL;
277  char *s=str;
278  while (*s <= ' ' && *s != '\0') s++;
279  if (*s == '\0') return NULL;
280  char *ss=s;
281  while (*ss!='\0') ss++;
282  ss--;
283  while (*ss <= ' ' && *ss != '\0')
284  {
285    *ss='\0';
286    ss--;
287  }
288  if (*ss == '\0') return NULL;
289  return s;
290}
291
292// Finds help entry for key:
293// returns filled-in hentry and TRUE, on success
294// FALSE, on failure
295// Assumes that lines of idx file have the following form
296// key\tnode\turl\tchksum\n (chksum ma be empty, then it is set to -1)
297// and that lines are sorted alpahbetically w.r.t. index entries
298static BOOLEAN heKey2Entry(char* filename, char* key, heEntry hentry)
299{
300  FILE* fd;
301  char c, k;
302  int kl, i;
303  *(hentry->key) = '\0';
304  *(hentry->url) = '\0';
305  *(hentry->node) = '\0';
306  hentry->chksum = 0;
307  if (filename == NULL || key == NULL)  return FALSE;
308  fd = fopen(filename, "r");
309  if (fd == NULL) return FALSE;
310  kl = strlen(key);
311
312  k = key[0];
313  i = 0;
314  while ((c = getc(fd)) != EOF)
315  {
316    if (c < k)
317    {
318      /* Skip line */
319      while (getc(fd) != '\n') {};
320      if (i)
321      {
322        i=0;
323        k=key[0];
324      }
325    }
326    else if (c == k)
327    {
328      i++;
329      if (i == kl)
330      {
331        // \t must follow, otherwise only substring match
332        if (getc(fd) != '\t') goto Failure;
333
334        // Now we found an exact match
335        if (hentry->key != key) strcpy(hentry->key, key);
336        // get node
337        i = 0;
338        while ((c = getc(fd)) != '\t' && c != EOF)
339        {
340          hentry->node[i] = c;
341          i++;
342        }
343        if (c == EOF) goto Failure;
344
345        // get url
346        hentry->node[i] = '\0';
347        i = 0;
348        while ((c = getc(fd)) != '\t' && c != EOF)
349        {
350          hentry->url[i] = c;
351          i++;
352        }
353        if (c == EOF) goto Failure;
354
355        // get chksum
356        hentry->url[i] = '\0';
357
358        if (fscanf(fd, "%ld\n", &(hentry->chksum)) != 1)
359        {
360          hentry->chksum = -1;
361        }
362        fclose(fd);
363        return TRUE;
364      }
365      else if (i > kl)
366      {
367        goto Failure;
368      }
369      else
370      {
371        k = key[i];
372      }
373    }
374    else
375    {
376      goto Failure;
377    }
378  }
379  Failure:
380  fclose(fd);
381  return FALSE;
382}
383
384// return TRUE if s matches re
385// FALSE, otherwise
386// does not distinguish lower and upper cases
387// inteprets * as wildcard
388static BOOLEAN strmatch(char* s, char* re)
389{
390  if (s == NULL || *s == '\0')
391    return (re == NULL || *re == '\0' || strcmp(re, "*") == 0);
392  if (re == NULL || *re == '\0') return FALSE;
393
394  int i;
395  char ls[MAX_HE_ENTRY_LENGTH + 1];
396  char rs[MAX_HE_ENTRY_LENGTH + 1];
397  char *l, *r, *ll, *rr;
398
399  // make everything to lower case
400  i=1;
401  ls[0] = '\0';
402  do
403  {
404    if (*s >= 'A' && *s <= 'Z') ls[i] = *s + ('a' - 'A');
405    else ls[i] = *s;
406    i++;
407    s++;
408  } while (*s != '\0');
409  ls[i] = '\0';
410  l = &(ls[1]);
411
412  i=1;
413  rs[0] = '\0';
414  do
415  {
416    if (*re >= 'A' && *re <= 'Z') rs[i]= *re + ('a' - 'A');
417    else rs[i] = *re;
418    i++;
419    re++;
420  } while (*re != '\0');
421  rs[i] = '\0';
422  r = &(rs[1]);
423
424  // chopp of exact matches from beginning and end
425  while (*r != '*' && *r != '\0' && *l != '\0')
426  {
427    if (*r != *l) return FALSE;
428    *r = '\0';
429    *s = '\0';
430    r++;
431    l++;
432  }
433  if (*r == '\0') return (*l == '\0');
434  if (*r == '*' && r[1] == '\0') return TRUE;
435  if (*l == '\0') return FALSE;
436
437  rr = &r[strlen(r) - 1];
438  ll = &l[strlen(l) - 1];
439  while (*rr != '*' && *rr != '\0' && *ll != '\0')
440  {
441    if (*rr != *ll) return FALSE;
442    *rr = '\0';
443    *ll = '\0';
444    rr--;
445    ll--;
446  }
447  if (*rr == '\0') return (*ll == '\0');
448  if (*rr == '*' && rr[-1] == '\0') return TRUE;
449  if (*ll == '\0') return FALSE;
450
451  // now *r starts with a * and ends with a *
452  r++;
453  *rr = '\0'; rr--;
454  while (*r != '\0')
455  {
456    rr = r + 1;
457    while (*rr != '*' && *rr != '\0') rr++;
458    if (*rr == '*')
459    {
460      *rr = '\0';
461      rr++;
462    }
463    l = strstr(l, r);
464    if (l == NULL) return FALSE;
465    r = rr;
466  }
467  return TRUE;
468}
469
470// similar to heKey2Entry, except that
471// key is taken as regexp (see above)
472// and number of matches is returned
473// if number of matches > 0, then hentry contains entry for first match
474// if number of matches > 1, matches are printed as komma-separated
475// into global string
476static int heReKey2Entry (char* filename, char* key, heEntry hentry)
477{
478  int i = 0;
479  FILE* fd;
480  char index_key[MAX_HE_ENTRY_LENGTH];
481
482  if (filename == NULL || key == NULL)  return 0;
483  fd = fopen(filename, "r");
484  if (fd == NULL) return 0;
485  while (fscanf(fd, "%[^\t]\t%*[^\n]\n", index_key) == 1)
486  {
487    if (strmatch(index_key, key))
488    {
489      i++;
490      if (i == 1)
491      {
492        heKey2Entry(filename, index_key, hentry);
493      }
494      else if (i == 2)
495      {
496        StringAppend("?%s; ?%s;", hentry->key, index_key);
497      }
498      else
499      {
500        StringAppend(" ?%s;", index_key);
501      }
502    }
503  }
504  fclose(fd);
505  return i;
506}
507
508// try to find the help string as a loaded procedure or library
509// if found, display the help and return TRUE
510// otherwise, return FALSE
511static BOOLEAN heOnlineHelp(char* s)
512{
513#ifdef HAVE_NAMESPACES
514  idhdl h, ns;
515  iiname2hdl(s, &ns, &h);
516#else /* HAVE_NAMESPACES */
517  idhdl h=idroot->get(s,myynest);
518#endif /* HAVE_NAMESPACES */
519
520  // try help for a procedure
521  if ((h!=NULL) && (IDTYP(h)==PROC_CMD))
522  {
523    char *lib=iiGetLibName(IDPROC(h));
524    if((lib!=NULL)&&(*lib!='\0'))
525    {
526      Print("// proc %s from lib %s\n",s,lib);
527      s=iiGetLibProcBuffer(IDPROC(h), 0);
528      PrintS(s);
529      FreeL((ADDRESS)s);
530      return TRUE;
531    }
532    return FALSE;
533  }
534
535  // try help for a library
536  int ls = strlen(s);
537  char* str = NULL;
538  // check that it ends with "[.,_]lib"
539  if (strlen(s) >=4 &&  strcmp(&s[ls-3], "lib") == 0)
540  {
541    if (s[ls - 4] == '.') str = s;
542    else
543    {
544      str = mstrdup(s);
545      str[ls - 4] = '.';
546    }
547  }
548  else
549  {
550    return FALSE;
551  }
552
553  char libnamebuf[128];
554  FILE *fp=NULL;
555  if ((str[1]!='\0') && ((fp=feFopen(str,"rb", libnamebuf))!=NULL))
556  {
557    extern FILE *yylpin;
558    lib_style_types lib_style; // = OLD_LIBSTYLE;
559
560    yylpin = fp;
561#ifdef HAVE_NAMESPACES
562    yylplex(str, libnamebuf, &lib_style, IDROOT, FALSE, GET_INFO);
563#else /* HAVE_NAMESPACES */
564    yylplex(str, libnamebuf, &lib_style, GET_INFO);
565#endif /* HAVE_NAMESPACES */
566    reinit_yylp();
567    if(lib_style == OLD_LIBSTYLE)
568    {
569      char buf[256];
570      fseek(fp, 0, SEEK_SET);
571      Warn( "library %s has an old format. Please fix it for the next time",
572            str);
573      if (str != s) FreeL(str);
574      BOOLEAN found=FALSE;
575      while (fgets( buf, sizeof(buf), fp))
576      {
577        if (strncmp(buf,"//",2)==0)
578        {
579          if (found) return TRUE;
580        }
581        else if ((strncmp(buf,"proc ",5)==0)||(strncmp(buf,"LIB ",4)==0))
582        {
583          if (!found) WarnS("no help part in library found");
584          return TRUE;
585        }
586        else
587        {
588          found=TRUE;
589          PrintS(buf);
590        }
591      }
592    }
593    else
594    {
595      if (str != s) FreeL(str);
596      fclose( yylpin );
597      PrintS(text_buffer);
598      FreeL(text_buffer);
599      text_buffer=NULL;
600    }
601    return TRUE;
602  }
603
604  if (str != s) FreeL(str);
605  return FALSE;
606}
607
608static long heKeyChksum(char* key)
609{
610  if (key == NULL || *key == '\0') return 0;
611#ifdef HAVE_NAMESPACES
612  idhdl h, ns;
613  iiname2hdl(key, &ns, &h);
614#else /* HAVE_NAMESPACES */
615  idhdl h=idroot->get(key,myynest);
616#endif /* HAVE_NAMESPACES */
617  if ((h!=NULL) && (IDTYP(h)==PROC_CMD))
618  {
619    procinfo *pi = IDPROC(h);
620    if (pi != NULL) return pi->data.s.help_chksum;
621  }
622  return 0;
623}
624
625/*****************************************************************
626 *
627 * Implementation : Help Browsers
628 *
629 *****************************************************************/
630
631static void heBrowserHelp(heEntry hentry)
632{
633  // check checksums of procs
634  int kchksum = (hentry != NULL && hentry->chksum > 0 ?
635                 heKeyChksum(hentry->key) : 0);
636  if (kchksum  && kchksum != hentry->chksum && heOnlineHelp(hentry->key))
637    return;
638
639  if (heCurrentHelpBrowser == NULL) feHelpBrowser();
640  assume(heCurrentHelpBrowser != NULL);
641  Warn("Displaying help in browser '%s'.", heCurrentHelpBrowser->browser);
642  Warn("Use 'system(\"--browser\", \"<browser>\");' to change browser");
643  Warn("Use 'system(\"browsers\");'               for available browsers");
644  heCurrentHelpBrowser->help_proc(hentry);
645}
646
647#define MAX_SYSCMD_LEN MAXPATHLEN*2
648// browser functions
649static BOOLEAN heInfoInit(int warn)
650{
651  if (feResource('i', warn) == NULL)
652  {
653    if (warn) WarnS("'info' help browser not available: no InfoFile");
654    return FALSE;
655  }
656  if (feResource('I') == NULL)
657  {
658    if (warn)
659      WarnS("'info' help browser not available: no 'info' program found");
660    return FALSE;
661  }
662  return TRUE;
663}
664static void heInfoHelp(heEntry hentry)
665{
666  char sys[MAX_SYSCMD_LEN];
667
668  if (hentry != NULL && *(hentry->key) != '\0')
669  {
670    if (*(hentry->node) != '\0')
671      sprintf(sys, "%s -f %s --node='%s'",
672              feResource('I'), feResource('i'), hentry->node);
673    else
674      sprintf(sys, "%s -f %s Index '%s'",
675              feResource('I'), feResource('i'), hentry->key);
676  }
677  else
678    sprintf(sys, "%s -f %s --node=Top", feResource('I'), feResource('i'));
679  system(sys);
680}
681
682#if ! defined(WINNT) && ! defined(macintosh)
683static BOOLEAN heNetscapeInit(int warn)
684{
685  if (feResource('N' /*"netscape"*/, warn) == NULL)
686  {
687    if (warn) WarnS("'netscape' help browser not available: no 'netscape' program found");
688    return FALSE;
689  }
690  if (getenv("DISPLAY") == NULL)
691  {
692    if (warn) WarnS("'netscape' help browser not available:");
693    if (warn) WarnS("Environment variable DISPLAY not set");
694    return FALSE;
695  }
696
697  if (feResource('h' /*"HtmlDir"*/, warn) == NULL)
698  {
699    if (warn) WarnS("no local HtmlDir found");
700    if (warn) Warn("using %s instead", feResource('u' /*"ManualUrl"*/, warn));
701  }
702  return TRUE;
703}
704static void heNetscapeHelp(heEntry hentry)
705{
706  char sys[MAX_SYSCMD_LEN];
707  char url[MAXPATHLEN];
708  char* htmldir = feResource('h' /*"HtmlDir"*/);
709  char* urltype;
710
711  if (htmldir == NULL)
712  {
713    urltype = "";
714    htmldir = feResource('u' /*"ManualUrl"*/);
715  }
716  else
717  {
718    urltype = "file:";
719  }
720
721  if (hentry != NULL && *(hentry->url) != '\0')
722  {
723    sprintf(url, "%s%s/%s", urltype, htmldir, hentry->url);
724  }
725  else
726  {
727    sprintf(url, "%s%s/index.htm", urltype, htmldir);
728  }
729  sprintf(sys, "%s --remote 'OpenUrl(%s)' > /dev/null 2>&1",
730          feResource('N' /*"netscape"*/), url);
731
732  // --remote exits with status != 0 if netscaep isn't already running
733  if (system(sys) != 0)
734  {
735    sprintf(sys, "%s %s &", feResource('N' /*"netscape"*/), url);
736    system(sys);
737  }
738}
739
740static BOOLEAN heXinfoInit(int warn)
741{
742  if (getenv("DISPLAY") == NULL)
743  {
744    if (warn) WarnS("'xinfo' help browser not available:");
745    if (warn) WarnS("Environment variable DISPLAY not set");
746    return FALSE;
747  }
748  if (feResource('i', warn) == NULL)
749  {
750    if (warn) WarnS("'xinfo' help browser not available: no InfoFile");
751    return FALSE;
752  }
753  if (feResource('I', warn) == NULL)
754  {
755    if (warn) WarnS("'xinfo' help browser not available: no 'info' program found");
756    return FALSE;
757  }
758  if (feResource('X', warn) == NULL)
759  {
760    if (warn) WarnS("'xinfo' help browser not available: no 'xterm' program found");
761    return FALSE;
762  }
763  return TRUE;
764}
765static void heXinfoHelp(heEntry hentry)
766{
767  char sys[MAX_SYSCMD_LEN];
768
769  if (hentry != NULL && *(hentry->key) != '\0')
770  {
771    if (*(hentry->node) != '\0')
772      sprintf(sys, "%s -e %s -f %s --node='%s' &",
773              feResource('X'), feResource('I'), feResource('i'), hentry->node);
774    else
775      sprintf(sys, "%s -e %s -f %s Index '%s' &",
776              feResource('X'), feResource('I'), feResource('i'), hentry->key);
777  }
778  else
779    sprintf(sys, "%s -e %s -f %s --node=Top &",
780            feResource('X'), feResource('I'), feResource('i'));
781  system(sys);
782}
783
784static BOOLEAN heTkinfoInit(int warn)
785{
786  if (getenv("DISPLAY") == NULL)
787  {
788    if (warn) WarnS("'tkinfo' help browser not available:");
789    if (warn) WarnS("Environment variable DISPLAY not set");
790    return FALSE;
791  }
792  if (feResource('i', warn) == NULL)
793  {
794    if (warn) WarnS("'tkinfo' help browser not available: no InfoFile");
795    return FALSE;
796  }
797  if (feResource('T', warn) == NULL)
798  {
799    if (warn) WarnS("'tkinfo' help browser not available: no 'tkinfo' program found");
800    return FALSE;
801  }
802  return TRUE;
803}
804static void heTkinfoHelp(heEntry hentry)
805{
806  char sys[MAX_SYSCMD_LEN];
807  if (hentry != NULL && *(hentry->node) != '\0')
808  {
809    sprintf(sys, "%s '(%s)%s' &",
810            feResource('T'), feResource('i'), hentry->node);
811  }
812  else
813  {
814    sprintf(sys, "%s %s &",
815            feResource('T'), feResource('i'));
816  }
817  system(sys);
818}
819#endif // ! defined(WINNT) && ! defined(macintosh)
820
821static BOOLEAN heDummyInit(int warn)
822{
823  return TRUE;
824}
825static void heDummyHelp(heEntry hentry)
826{
827  Werror("No functioning help browser available.");
828}
829
830static BOOLEAN heEmacsInit(int warn)
831{
832  return TRUE;
833}
834static void heEmacsHelp(heEntry hentry)
835{
836  WarnS("Your help command could not be executed. Use");
837  Warn("C-h C-s %s",
838       (hentry != NULL && *(hentry->node) != '\0' ? hentry->node : "Top"));
839  Warn("to enter the Singular online help. For general");
840  Warn("information on Singular running under Emacs, type C-h m");
841}
842static BOOLEAN heBuiltinInit(int warn)
843{
844  if (feResource('i', warn) == NULL)
845  {
846    if (warn) WarnS("'builtin' help browser not available: no InfoFile");
847    return FALSE;
848  }
849  return TRUE;
850}
851static int singular_manual(char *str);
852static void heBuiltinHelp(heEntry hentry)
853{
854  char* node = mstrdup(hentry != NULL && *(hentry->node) != '\0' ?
855                       hentry->node : "Top");
856  singular_manual(node);
857  FreeL(node);
858}
859
860
861/* ========================================================================== */
862// old, stupid builtin_help
863// This could be implemented much more clever, but I'm too lazy to do this now
864//
865#define HELP_OK        0
866#define FIN_INDEX    '\037'
867#define not  !
868#define HELP_NOT_OPEN  1
869#define HELP_NOT_FOUND 2
870#define BUF_LEN        256
871#define IDX_LEN        64
872#define MAX_LINES      21
873
874#ifdef macintosh
875static char tolow(char p)
876#else
877static inline char tolow(char p)
878#endif
879{
880  if (('A'<=p)&&(p<='Z')) return p | 040;
881  return p;
882}
883
884/*************************************************/
885static int show(unsigned long offset,FILE *help, char *close)
886{ char buffer[BUF_LEN+1];
887  int  lines = 0;
888
889  if( help== NULL)
890    if( (help = fopen(feResource('i'), "rb")) == NULL)
891      return HELP_NOT_OPEN;
892
893  fseek(help,  (long)(offset+1), (int)0);
894  while( !feof(help)
895        && *fgets(buffer, BUF_LEN, help) != EOF
896        && buffer[0] != FIN_INDEX)
897  {
898    printf("%s", buffer);
899    if(lines++> MAX_LINES)
900    {
901#ifdef macintosh
902      printf("\n Press <RETURN> to continue or x and <RETURN> to exit help.\n");
903#else
904      printf("\n Press <RETURN> to continue or x to exit help.\n");
905#endif
906      fflush(stdout);
907      *close = (char)getchar();
908      if(*close=='x')
909      {
910        getchar();
911        break;
912      }
913      lines=0;
914    }
915  }
916  if(*close!='x')
917  {
918#ifdef macintosh
919    printf("\nEnd of part. Press <RETURN> to continue or x and <RETURN> to exit help.\n");
920#else
921    printf("\nEnd of part. Press <RETURN> to continue or x to exit help.\n");
922#endif
923    fflush(stdout);
924    *close = (char)getchar();
925    if(*close=='x')
926      getchar();
927  }
928  return HELP_OK;
929}
930
931/*************************************************/
932static int singular_manual(char *str)
933{ FILE *index=NULL,*help=NULL;
934  unsigned long offset;
935  char *p,close;
936  int done = 0;
937  char buffer[BUF_LEN+1],
938       Index[IDX_LEN+1],
939       String[IDX_LEN+1];
940
941  if( (index = fopen(feResource('i'), "rb")) == NULL)
942  {
943    return HELP_NOT_OPEN;
944  }
945
946  for(p=str; *p; p++) *p = tolow(*p);/* */
947  do
948  {
949    p--;
950  }
951  while ((p != str) && (*p<=' '));
952  p++;
953  *p='\0';
954  (void)sprintf(String, " %s ", str);
955
956  while(!feof(index)
957        && fgets(buffer, BUF_LEN, index) != (char *)0
958        && buffer[0] != FIN_INDEX);
959
960  while(!feof(index))
961  {
962    (void)fgets(buffer, BUF_LEN, index); /* */
963    (void)sscanf(buffer, "Node:%[^\177]\177%ld\n", Index, &offset);
964    for(p=Index; *p; p++) *p = tolow(*p);/* */
965    (void)strcat(Index, " ");
966    if( strstr(Index, String)!=NULL)
967    {
968      done++; (void)show(offset, help, &close);
969    }
970    Index[0]='\0';
971    if(close=='x')
972    break;
973  }
974  if (index != NULL) (void)fclose(index);
975  if (help != NULL) (void)fclose(help);
976  if(not done)
977  {
978    Warn("`%s` not found",String);
979    return HELP_NOT_FOUND;
980  }
981  return HELP_OK;
982}
983/*************************************************/
Note: See TracBrowser for help on using the repository browser.