source: git/Singular/fehelp.cc @ 89a527

fieker-DuValspielwiese
Last change on this file since 89a527 was 89a527, checked in by Hans Schoenemann <hannes@…>, 2 years ago
fix: typo
  • Property mode set to 100644
File size: 30.3 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/*
5* ABSTRACT: help system
6*/
7
8#include "kernel/mod2.h"
9#include "omalloc/omalloc.h"
10#include "misc/mylimits.h"
11#include "resources/feResource.h"
12#include "reporter/reporter.h"
13#include "resources/omFindExec.h"
14#include "reporter/si_signals.h"
15
16#include "ipid.h"
17#include "ipshell.h"
18#include "libparse.h"
19#include "feOpt.h"
20
21#include "tok.h"
22#include "fehelp.h"
23
24/*****************************************************************
25 *
26 * Declarations: Data  structures
27 *
28 *****************************************************************/
29#define MAX_HE_ENTRY_LENGTH 160
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, int br);
40typedef BOOLEAN (*heBrowserInitProc)(int warn, int br);
41
42typedef struct
43{
44  const char* browser;
45  heBrowserInitProc init_proc;
46  heBrowserHelpProc help_proc;
47  const char* required;
48  const char* action;
49} heBrowser_s;
50typedef heBrowser_s * heBrowser;
51
52/*****************************************************************
53 *
54 * Declarations: Local functions
55 *
56 *****************************************************************/
57static char* strclean(char* str);
58static BOOLEAN heKey2Entry(char* filename, char* key, heEntry hentry);
59static int heReKey2Entry (char* filename, char* key, heEntry hentry);
60static BOOLEAN strmatch(char* s, char* re);
61static BOOLEAN heOnlineHelp(char* s);
62static void heBrowserHelp(heEntry hentry);
63static long heKeyChksum(char* key);
64
65// browser functions
66static BOOLEAN heGenInit(int,int);    static void heGenHelp(heEntry hentry,int);
67                                      static void heBuiltinHelp(heEntry hentry,int);
68static BOOLEAN heDummyInit(int,int);   static void heDummyHelp(heEntry hentry,int);
69static BOOLEAN heEmacsInit(int,int);   static void heEmacsHelp(heEntry hentry,int);
70
71STATIC_VAR heBrowser heCurrentHelpBrowser = NULL;
72STATIC_VAR int heCurrentHelpBrowserIndex= -1;
73
74
75/*****************************************************************
76 *
77 * Definition: available help browsers
78 *
79 *****************************************************************/
80// order is important -- first possible help is chosen
81// moved to LIB/help.cnf
82STATIC_VAR heBrowser_s *heHelpBrowsers=NULL;
83
84/*****************************************************************
85 *
86 * Implementation: public function
87 *
88 *****************************************************************/
89EXTERN_VAR BOOLEAN FE_OPT_NO_SHELL_FLAG;
90void feHelp(char *str)
91{
92  if (FE_OPT_NO_SHELL_FLAG) {WerrorS("no help available");return;}
93  str = strclean(str);
94  if (str == NULL) {heBrowserHelp(NULL); return;}
95
96  if (strlen(str) > MAX_HE_ENTRY_LENGTH - 2)  // need room for extra **
97    str[MAX_HE_ENTRY_LENGTH - 3] = '\0';
98
99  BOOLEAN key_is_regexp = (strchr(str, '*') != NULL);
100
101
102  heEntry_s hentry;
103  memset(&hentry,0,sizeof(hentry));
104  char* idxfile = feResource('x' /*"IdxFile"*/);
105
106  // Try exact match of help string with key in index
107  if (!key_is_regexp && (idxfile != NULL) && heKey2Entry(idxfile, str, &hentry))
108  {
109    heBrowserHelp(&hentry);
110    return;
111  }
112
113  // Try to match approximately with key in index file
114  if (idxfile != NULL)
115  {
116    if (heCurrentHelpBrowser == NULL) feHelpBrowser(NULL, 0);
117    assume(heCurrentHelpBrowser != NULL);
118
119    StringSetS("");
120    int found = heReKey2Entry(idxfile, str, &hentry);
121
122
123    if (found == 0)
124    {
125      // try proc help and library help
126      if (! key_is_regexp && heOnlineHelp(str)) return;
127
128      // Try to match with str*
129      char mkey[MAX_HE_ENTRY_LENGTH];
130      strcpy(mkey, str);
131      strcat(mkey, "*");
132      found = heReKey2Entry(idxfile, mkey, &hentry);
133      // Try to match with *str*
134      if (found == 0)
135      {
136        mkey[0] = '*';
137        strcpy(mkey + 1, str);
138        strcat(mkey, "*");
139        found = heReKey2Entry(idxfile, mkey, &hentry);
140      }
141
142      // Print warning and return if nothing found
143      if (found == 0)
144      {
145        Warn("No help for topic '%s' (not even for '*%s*')", str, str);
146        WarnS("Try '?;'       for general help");
147        WarnS("or  '?Index;'  for all available help topics.");
148        return;
149      }
150    }
151
152    // do help if unique match was found
153    if (found == 1)
154    {
155      heBrowserHelp(&hentry);
156      return;
157    }
158    // Print warning about multiple matches and return
159    if (key_is_regexp)
160      Warn("No unique help for '%s'", str);
161    else
162      Warn("No help for topic '%s'", str);
163    WarnS("Try one of");
164    char *matches=StringEndS();
165    PrintS(matches);
166    omFree(matches);
167    PrintLn();
168    return;
169  }
170
171  // no idx file, let Browsers deal with it, if they can
172  strcpy(hentry.key, str);
173  *hentry.node = '\0';
174  *hentry.url = '\0';
175  hentry.chksum = 0;
176  heBrowserHelp(&hentry);
177}
178static void feBrowserFile()
179{
180  FILE *f=feFopen("help.cnf","r",NULL,TRUE);
181  int br=0;
182  if (f!=NULL)
183  {
184    char buf[512];
185    while (fgets( buf, sizeof(buf), f))
186    {
187      if ((buf[0]!='#') && (buf[0]>' ')) br++;
188    }
189    fseek(f,0,SEEK_SET);
190    // for the 4(!) default browsers
191    heHelpBrowsers=(heBrowser_s*)omAlloc0((br+4)*sizeof(heBrowser_s));
192    br = 0;
193    while (fgets( buf, sizeof(buf), f))
194    {
195      if ((buf[0]!='#') && (buf[0]>' '))
196      {
197        char *name=strtok(buf,"!");
198        char *req=strtok(NULL,"!");
199        char *cmd=strtok(NULL,"!");
200        if ((name!=NULL) && (req!=NULL) && (cmd!=NULL))
201        {
202          while ((cmd[0]!='\0') && (cmd[strlen(cmd)-1]<=' '))
203            cmd[strlen(cmd)-1]='\0';
204          //Print("name %d >>%s<<\n\treq:>>%s<<\n\tcmd:>>%s<<\n",br,name,req,cmd);
205          heHelpBrowsers[br].browser=(char *)omStrDup(name);
206          heHelpBrowsers[br].init_proc=heGenInit;
207          heHelpBrowsers[br].help_proc=heGenHelp;
208          heHelpBrowsers[br].required=omStrDup(req);
209          heHelpBrowsers[br].action=omStrDup(cmd);
210          br++;
211        }
212        else
213        {
214          Print("syntax error in help.cnf, at line starting with %s\n",buf);
215        }
216      }
217    }
218    fclose(f);
219  }
220  else
221  {
222    // for the 4(!) default browsers
223    heHelpBrowsers=(heBrowser_s*)omAlloc0(4*sizeof(heBrowser_s));
224  }
225  heHelpBrowsers[br].browser="builtin";
226  heHelpBrowsers[br].init_proc=heGenInit;
227  heHelpBrowsers[br].help_proc=heBuiltinHelp;
228  heHelpBrowsers[br].required="i";
229  //heHelpBrowsers[br].action=NULL;
230  br++;
231  heHelpBrowsers[br].browser="dummy";
232  heHelpBrowsers[br].init_proc=heDummyInit;
233  heHelpBrowsers[br].help_proc=heDummyHelp;
234  //heHelpBrowsers[br].required=NULL;
235  //heHelpBrowsers[br].action=NULL;
236  br++;
237  heHelpBrowsers[br].browser="emacs";
238  heHelpBrowsers[br].init_proc=heEmacsInit;
239  heHelpBrowsers[br].help_proc=heEmacsHelp;
240  //heHelpBrowsers[br].required=NULL;
241  //heHelpBrowsers[br].action=NULL;
242  //br++;
243  //heHelpBrowsers[br].browser=NULL;
244  //heHelpBrowsers[br].init_proc=NULL;
245  //heHelpBrowsers[br].help_proc=NULL;
246  //heHelpBrowsers[br].required=NULL;
247  //heHelpBrowsers[br].action=NULL;
248}
249
250const char* feHelpBrowser(char* which, int warn)
251{
252  int i = 0;
253
254  // if no argument, choose first available help browser
255  if (heHelpBrowsers==NULL) feBrowserFile();
256  if (which == NULL || *which == '\0')
257  {
258    // return, if already set
259    if (heCurrentHelpBrowser != NULL)
260      return heCurrentHelpBrowser->browser;
261
262    // First, try emacs, if emacs-option is set
263    if (feOptValue(FE_OPT_EMACS) != NULL)
264    {
265      while (heHelpBrowsers[i].browser != NULL)
266      {
267        if (strcmp(heHelpBrowsers[i].browser, "emacs") == 0 &&
268            (heHelpBrowsers[i].init_proc(0,i)))
269        {
270          heCurrentHelpBrowser = &(heHelpBrowsers[i]);
271          heCurrentHelpBrowserIndex=i;
272          goto Finish;
273        }
274        i++;
275      }
276      i=0;
277    }
278    while (heHelpBrowsers[i].browser != NULL)
279    {
280      if (heHelpBrowsers[i].init_proc(0,i))
281      {
282        heCurrentHelpBrowser = &(heHelpBrowsers[i]);
283        heCurrentHelpBrowserIndex=i;
284        goto Finish;
285      }
286      i++;
287    }
288    // should never get here
289    dReportBug("should never get here");
290  }
291
292  // with argument, find matching help browser
293  while (heHelpBrowsers[i].browser != NULL &&
294         strcmp(heHelpBrowsers[i].browser, which) != 0)
295  {i++;}
296
297  if (heHelpBrowsers[i].browser == NULL)
298  {
299    if (warn) Warn("No help browser '%s' available.", which);
300  }
301  else
302  {
303    // see whether we can init it
304    if (heHelpBrowsers[i].init_proc(warn,i))
305    {
306      heCurrentHelpBrowser = &(heHelpBrowsers[i]);
307      heCurrentHelpBrowserIndex=i;
308      goto Finish;
309    }
310  }
311
312  // something went wrong
313  if (heCurrentHelpBrowser == NULL)
314  {
315    feHelpBrowser();
316    assume(heCurrentHelpBrowser != NULL);
317    if (warn)
318      Warn("Setting help browser to '%s'.", heCurrentHelpBrowser->browser);
319    return heCurrentHelpBrowser->browser;
320  }
321  else
322  {
323    // or, leave as is
324    if (warn)
325      Warn("Help browser stays at '%s'.",  heCurrentHelpBrowser->browser);
326    return heCurrentHelpBrowser->browser;
327  }
328
329  Finish:
330  // update value of Browser Option
331  if (feOptSpec[FE_OPT_BROWSER].value == NULL ||
332      strcmp((char*) feOptSpec[FE_OPT_BROWSER].value,
333             heCurrentHelpBrowser->browser) != 0)
334  {
335    omfree(feOptSpec[FE_OPT_BROWSER].value);
336    feOptSpec[FE_OPT_BROWSER].value
337     = (void*) omStrDup(heCurrentHelpBrowser->browser);
338  }
339  return heCurrentHelpBrowser->browser;
340}
341
342void  feStringAppendBrowsers(int warn)
343{
344  int i;
345  StringAppendS("Available HelpBrowsers: ");
346
347  i = 0;
348  if (heHelpBrowsers==NULL) feBrowserFile();
349  while (heHelpBrowsers[i].browser != NULL)
350  {
351    if (heHelpBrowsers[i].init_proc(warn,i))
352      StringAppend("%s, ", heHelpBrowsers[i].browser);
353    i++;
354  }
355  StringAppend("\nCurrent HelpBrowser: %s ", feHelpBrowser());
356}
357
358
359/*****************************************************************
360 *
361 * Implementation: local function
362 *
363 *****************************************************************/
364// Remove whitspaces from beginning and end, return NULL if only whitespaces
365static char* strclean(char* str)
366{
367  if (str == NULL) return NULL;
368  char *s=str;
369  while ((*s <= ' ') && (*s != '\0')) s++;
370  if (*s == '\0') return NULL;
371  char *ss=s;
372  while (*ss!='\0') ss++;
373  ss--;
374  while ((*ss <= ' ') && (*ss != '\0'))
375  {
376    *ss='\0';
377    ss--;
378  }
379  if (*ss == '\0') return NULL;
380  return s;
381}
382
383// Finds help entry for key:
384// returns filled-in hentry and TRUE, on success
385// FALSE, on failure
386// Assumes that lines of idx file have the following form
387// key\tnode\turl\tchksum\n (chksum ma be empty, then it is set to -1)
388// and that lines are sorted alpahbetically w.r.t. index entries
389static BOOLEAN heKey2Entry(char* filename, char* key, heEntry hentry)
390{
391  FILE* fd;
392  int c, k;
393  int kl, i;
394  *(hentry->key) = '\0';
395  *(hentry->url) = '\0';
396  *(hentry->node) = '\0';
397  hentry->chksum = 0;
398  if (filename == NULL || key == NULL)  return FALSE;
399  fd = fopen(filename, "r");
400  if (fd == NULL) return FALSE;
401  kl = strlen(key);
402
403  k = key[0];
404  i = 0;
405  while ((c = getc(fd)) != EOF)
406  {
407    if (c < k)
408    {
409      /* Skip line */
410      while (getc(fd) != '\n') {};
411      if (i)
412      {
413        i=0;
414        k=key[0];
415      }
416    }
417    else if (c == k)
418    {
419      i++;
420      if (i == kl)
421      {
422        // \t must follow, otherwise only substring match
423        if (getc(fd) != '\t') goto Failure;
424
425        // Now we found an exact match
426        if (hentry->key != key) strcpy(hentry->key, key);
427        // get node
428        i = 0;
429        while ((c = getc(fd)) != '\t' && c != EOF)
430        {
431          hentry->node[i] = c;
432          i++;
433        }
434        if (c == EOF) goto Failure;
435        if (hentry->node[0]=='\0')
436          strcpy(hentry->node,hentry->key);
437
438        // get url
439        //hentry->node[i] = '\0';
440        i = 0;
441        while ((c = getc(fd)) != '\t' && c != EOF)
442        {
443          hentry->url[i] = c;
444          i++;
445        }
446        if (c == EOF) goto Failure;
447
448        // get chksum
449        hentry->url[i] = '\0';
450
451        if (si_fscanf(fd, "%ld\n", &(hentry->chksum)) != 1)
452        {
453          hentry->chksum = -1;
454        }
455        fclose(fd);
456        return TRUE;
457      }
458      else if (i > kl)
459      {
460        goto Failure;
461      }
462      else
463      {
464        k = key[i];
465      }
466    }
467    else
468    {
469      goto Failure;
470    }
471  }
472  Failure:
473  fclose(fd);
474  return FALSE;
475}
476
477// return TRUE if s matches re
478// FALSE, otherwise
479// does not distinguish lower and upper cases
480// inteprets * as wildcard
481static BOOLEAN strmatch(char* s, char* re)
482{
483  if (s == NULL || *s == '\0')
484    return (re == NULL || *re == '\0' || strcmp(re, "*") == 0);
485  if (re == NULL || *re == '\0') return FALSE;
486
487  int i;
488  char ls[MAX_HE_ENTRY_LENGTH + 1];
489  char rs[MAX_HE_ENTRY_LENGTH + 1];
490  char *l, *r, *ll, *rr;
491
492  // make everything to lower case
493  i=1;
494  ls[0] = '\0';
495  do
496  {
497    if (*s >= 'A' && *s <= 'Z') ls[i] = *s + ('a' - 'A');
498    else ls[i] = *s;
499    i++;
500    s++;
501  } while (*s != '\0');
502  ls[i] = '\0';
503  l = &(ls[1]);
504
505  i=1;
506  rs[0] = '\0';
507  do
508  {
509    if (*re >= 'A' && *re <= 'Z') rs[i]= *re + ('a' - 'A');
510    else rs[i] = *re;
511    i++;
512    re++;
513  } while (*re != '\0');
514  rs[i] = '\0';
515  r = &(rs[1]);
516
517  // chopp of exact matches from beginning and end
518  while (*r != '*' && *r != '\0' && *l != '\0')
519  {
520    if (*r != *l) return FALSE;
521    *r = '\0';
522    *s = '\0';
523    r++;
524    l++;
525  }
526  if (*r == '\0') return (*l == '\0');
527  if (*r == '*' && r[1] == '\0') return TRUE;
528  if (*l == '\0') return FALSE;
529
530  rr = &r[strlen(r) - 1];
531  ll = &l[strlen(l) - 1];
532  while (*rr != '*' && *rr != '\0' && *ll != '\0')
533  {
534    if (*rr != *ll) return FALSE;
535    *rr = '\0';
536    *ll = '\0';
537    rr--;
538    ll--;
539  }
540  if (*rr == '\0') return (*ll == '\0');
541  if (*rr == '*' && rr[-1] == '\0') return TRUE;
542  if (*ll == '\0') return FALSE;
543
544  // now *r starts with a * and ends with a *
545  r++;
546  *rr = '\0'; rr--;
547  while (*r != '\0')
548  {
549    rr = r + 1;
550    while (*rr != '*' && *rr != '\0') rr++;
551    if (*rr == '*')
552    {
553      *rr = '\0';
554      rr++;
555    }
556    l = strstr(l, r);
557    if (l == NULL) return FALSE;
558    r = rr;
559  }
560  return TRUE;
561}
562
563// similar to heKey2Entry, except that
564// key is taken as regexp (see above)
565// and number of matches is returned
566// if number of matches > 0, then hentry contains entry for first match
567// if number of matches > 1, matches are printed as komma-separated
568// into global string
569static int heReKey2Entry (char* filename, char* key, heEntry hentry)
570{
571  int i = 0;
572  FILE* fd;
573  char index_key[MAX_HE_ENTRY_LENGTH];
574
575  if (filename == NULL || key == NULL)  return 0;
576  fd = fopen(filename, "r");
577  if (fd == NULL) return 0;
578  memset(index_key,0,MAX_HE_ENTRY_LENGTH);
579  while (si_fscanf(fd, "%[^\t]\t%*[^\n]\n", index_key) == 1)
580  {
581    if ((index_key[MAX_HE_ENTRY_LENGTH-1]!='\0'))
582    {
583      index_key[MAX_HE_ENTRY_LENGTH-1]='\0';
584      Werror("index file corrupt at line >>%s<<",index_key);
585      break;
586    }
587    else if (strmatch(index_key, key))
588    {
589      i++;
590      if (i == 1)
591      {
592        heKey2Entry(filename, index_key, hentry);
593      }
594      else if (i == 2)
595      {
596        StringAppend("?%s; ?%s;", hentry->key, index_key);
597      }
598      else
599      {
600        StringAppend(" ?%s;", index_key);
601      }
602    }
603  }
604  fclose(fd);
605  return i;
606}
607
608// test for h being a string and print it
609static void hePrintHelpStr(const idhdl hh,const char *id,const char *pa)
610{
611  if ((hh!=NULL) && (IDTYP(hh)==STRING_CMD))
612  {
613    PrintS(IDSTRING(hh));
614    PrintLn();
615  }
616  else
617    Print("`%s` not found in package %s\n",id,pa);
618}
619// try to find the help string as a loaded procedure or library
620// if found, display the help and return TRUE
621// otherwise, return FALSE
622static BOOLEAN heOnlineHelp(char* s)
623{
624  char *ss;
625  idhdl h;
626
627  if ((ss=strstr(s,"::"))!=NULL)
628  {
629    *ss='\0';
630    ss+=2;
631    h=ggetid(s);
632    if (h!=NULL)
633    {
634      Print("help for %s from package %s\n",ss,s);
635      char s_help[200];
636      strcpy(s_help,ss);
637      strcat(s_help,"_help");
638      idhdl hh=IDPACKAGE(h)->idroot->get(s_help,0);
639      hePrintHelpStr(hh,s_help,s);
640      return TRUE;
641    }
642    else Print("package %s not found\n",s);
643    return TRUE; /* do not search the manual */
644  }
645  h=IDROOT->get(s,myynest);
646  // try help for a procedure
647  if (h!=NULL)
648  {
649    if  (IDTYP(h)==PROC_CMD)
650    {
651      char *lib=iiGetLibName(IDPROC(h));
652      if((lib!=NULL)&&(*lib!='\0'))
653      {
654        Print("// proc %s from lib %s\n",s,lib);
655        procinfov pi=IDPROC(h);
656        if (pi->language==LANG_SINGULAR)
657        {
658          s=iiGetLibProcBuffer(pi, 0);
659          if (s!=NULL)
660          {
661            PrintS(s);
662            omFree((ADDRESS)s);
663          }
664          return TRUE;
665        }
666      }
667    }
668    else if (IDTYP(h)==PACKAGE_CMD)
669    {
670      idhdl hh=IDPACKAGE(h)->idroot->get("info",0);
671      hePrintHelpStr(hh,"info",s);
672      return TRUE;
673    }
674    return FALSE;
675  }
676
677  // try help for a library
678  int ls = strlen(s);
679  char* str = NULL;
680  // check that it ends with "[.,_]lib"
681  if (strlen(s) >=4 &&  strcmp(&s[ls-3], "lib") == 0)
682  {
683    if (s[ls - 4] == '.') str = s;
684    else
685    {
686      str = omStrDup(s);
687      str[ls - 4] = '.';
688    }
689  }
690  else
691  {
692    return FALSE;
693  }
694
695  char libnamebuf[1024];
696  FILE *fp=NULL;
697  // first, search for library of that name
698  if ((str[1]!='\0') &&
699      ((iiLocateLib(str, libnamebuf) && (fp=feFopen(libnamebuf, "rb")) !=NULL)
700       ||
701       ((fp=feFopen(str,"rb", libnamebuf))!=NULL)))
702  {
703    EXTERN_VAR FILE *yylpin;
704    lib_style_types lib_style; // = OLD_LIBSTYLE;
705
706    yylpin = fp;
707    yylplex(str, libnamebuf, &lib_style, IDROOT, FALSE, GET_INFO);
708    reinit_yylp();
709    if(lib_style == OLD_LIBSTYLE)
710    {
711      char buf[256];
712      fseek(fp, 0, SEEK_SET);
713      Warn( "library %s has an old format. Please fix it for the next time",
714            str);
715      if (str != s) omFree(str);
716      BOOLEAN found=FALSE;
717      while (fgets( buf, sizeof(buf), fp))
718      {
719        if (strncmp(buf,"//",2)==0)
720        {
721          if (found) return TRUE;
722        }
723        else if ((strncmp(buf,"proc ",5)==0)||(strncmp(buf,"LIB ",4)==0))
724        {
725          if (!found) WarnS("no help part in library found");
726          return TRUE;
727        }
728        else
729        {
730          found=TRUE;
731          PrintS(buf);
732        }
733      }
734    }
735    else
736    {
737      if (str != s) omFree(str);
738      fclose( yylpin );
739      PrintS(text_buffer);
740      omFree(text_buffer);
741      text_buffer=NULL;
742    }
743    return TRUE;
744  }
745
746  if (str != s) omFree(str);
747  return FALSE;
748}
749
750static long heKeyChksum(char* key)
751{
752  if (key == NULL || *key == '\0') return 0;
753  idhdl h=IDROOT->get(key,myynest);
754  if ((h!=NULL) && (IDTYP(h)==PROC_CMD))
755  {
756    procinfo *pi = IDPROC(h);
757    if (pi != NULL) return pi->data.s.help_chksum;
758  }
759  return 0;
760}
761
762/*****************************************************************
763 *
764 * Implementation : Help Browsers
765 *
766 *****************************************************************/
767
768STATIC_VAR BOOLEAN feHelpCalled = FALSE;
769
770static void heBrowserHelp(heEntry hentry)
771{
772  // check checksums of procs
773  int kchksum = (hentry != NULL && hentry->chksum > 0 ?
774                 heKeyChksum(hentry->key) : 0);
775  if (kchksum  && kchksum != hentry->chksum && heOnlineHelp(hentry->key))
776    return;
777
778  if (heCurrentHelpBrowser == NULL) feHelpBrowser(NULL, 0);
779  assume(heCurrentHelpBrowser != NULL);
780  if (! feHelpCalled)
781  {
782    Warn("Displaying help in browser '%s'.", heCurrentHelpBrowser->browser);
783    //if (strcmp(heCurrentHelpBrowser->browser, "netscape") == 0 &&
784    //    feResource('h', 0) == NULL)
785    //{
786    //  Warn("Using URL '%s'.", feResource('u', 0));
787    //}
788    WarnS("Use 'system(\"--browser\", <browser>);' to change browser,");
789    StringSetS("where <browser> can be: ");
790    int i = 0;
791    i = 0;
792    while (heHelpBrowsers[i].browser != NULL)
793    {
794      if (heHelpBrowsers[i].init_proc(0,i))
795        StringAppend("\"%s\", ", heHelpBrowsers[i].browser);
796      i++;
797    }
798    char *browsers=StringEndS();
799    if (browsers[strlen(browsers)-2] == ',')
800    {
801      browsers[strlen(browsers)-2] = '.';
802      browsers[strlen(browsers)-1] = '\0';
803    }
804    WarnS(browsers);
805    omFree(browsers);
806  }
807
808  heCurrentHelpBrowser->help_proc(hentry, heCurrentHelpBrowserIndex);
809  feHelpCalled = TRUE;
810}
811
812#define MAX_SYSCMD_LEN MAXPATHLEN*2
813static BOOLEAN heGenInit(int warn, int br)
814{
815  if (heHelpBrowsers[br].required==NULL) return TRUE;
816  const char *p=heHelpBrowsers[br].required;
817  while (*p>'\0')
818  {
819    switch (*p)
820    {
821      case '#': break;
822      case ' ': break;
823      case 'i': /* singular.info */
824      case 'x': /* singular.idx */
825      case 'h': /* html dir */
826               if (feResource(*p, warn) == NULL)
827               {
828                 if (warn) Warn("resource `%c` not found",*p);
829                 return FALSE;
830               }
831               break;
832      case 'D': /* DISPLAY */
833               if (getenv("DISPLAY") == NULL)
834               {
835                 if (warn) WarnS("resource `D` not found");
836                 return FALSE;
837               }
838               break;
839      case 'E': /* executable: E:xterm: */
840      case 'O': /* OS: O:ix86Mac-darwin/ppcMac-darwin: */
841               {
842                 char name[128];
843                 char exec[128];
844                 char op=*p;
845                 memset(name,0,128);
846                 int i=0;
847                 p++;
848                 while (((*p==':')||(*p<=' ')) && (*p!='\0')) p++;
849                 while((i<127) && (*p>' ') && (*p!=':'))
850                 {
851                   name[i]=*p; p++; i++;
852                 }
853                 if (i==0) return FALSE;
854
855                 if ((op=='O') && (strcmp(name,S_UNAME)!=0))
856                   return FALSE;
857                 if ((op=='E') && (omFindExec(name,exec)==NULL))
858                 {
859                   if (warn) Warn("executable `%s` not found",name);
860                   return FALSE;
861                 }
862               }
863               break;
864      default: Warn("unknown char %c",*p);
865               break;
866    }
867    p++;
868  }
869  return TRUE;
870}
871
872static void heGenHelp(heEntry hentry, int br)
873{
874  char sys[MAX_SYSCMD_LEN];
875  const char *p=heHelpBrowsers[br].action;
876  if (p==NULL) {PrintS("no action ?\n"); return;}
877  memset(sys,0,MAX_SYSCMD_LEN);
878  int i=0;
879  while ((*p>'\0')&& (i<MAX_SYSCMD_LEN))
880  {
881    if ((*p)=='%')
882    {
883      p++;
884      switch (*p)
885      {
886        case 'f': /* local html:file */
887        case 'h': /* local html:URL */
888        case 'H': /* www html */
889                 {
890                   char temp[256];
891                   char *htmldir = feResource('h' /*"HtmlDir"*/);
892                   if ((*p=='h')&&(htmldir!=NULL))
893                     strcat(sys,"file://localhost");
894                   else if ((*p=='H')||(htmldir==NULL))
895                     htmldir = feResource('u' /* %H -> "ManualUrl"*/);
896                     /* always defined */
897                   if (hentry != NULL && *(hentry->url) != '\0')
898                   #ifdef HAVE_VSNPRINTF
899                   {
900                     if (*p=='H')
901                     #ifdef SINGULAR_4_2
902                       snprintf(temp,256,"%s/%d-%d/%s", htmldir,
903                                  SINGULAR_VERSION/1000,
904                                 (SINGULAR_VERSION % 1000)/100,
905                     #else
906                       snprintf(temp,256,"%s/%d-%d-%d/%s", htmldir,
907                                  SINGULAR_VERSION/1000,
908                                 (SINGULAR_VERSION % 1000)/100,
909                                 (SINGULAR_VERSION % 100)/10,
910                     #endif
911                       hentry->url);
912                     else
913                       snprintf(temp,256,"%s/%s", htmldir, hentry->url);
914                   }
915                   else
916                   {
917                     if (*p=='H')
918                       snprintf(temp,256,"%s/%d-%d-%d/index.htm", htmldir,
919                                  SINGULAR_VERSION/1000,
920                                 (SINGULAR_VERSION % 1000)/100,
921                                 (SINGULAR_VERSION % 100)/10
922                       );
923                     else
924                       snprintf(temp,256,"%s/index.htm", htmldir);
925                   }
926                   #else
927                   {
928                     if (*p=='H')
929                       sprintf(temp,"%s/%d-%d-%d/%s", htmldir,
930                                  SINGULAR_VERSION/1000,
931                                 (SINGULAR_VERSION % 1000)/100,
932                                 (SINGULAR_VERSION % 100)/10,
933                       hentry->url);
934                     else
935                       sprintf(temp,"%s/%d-%d-%d/%s", htmldir, hentry->url);
936                   }
937                   else
938                     if (*p=='H')
939                       sprintf(temp,"%s/%d-%d-%d/index.htm", htmldir,
940                                  SINGULAR_VERSION/1000,
941                                 (SINGULAR_VERSION % 1000)/100,
942                                 (SINGULAR_VERSION % 100)/10
943                       );
944                     else
945                       sprintf(temp,"%s/index.htm", htmldir);
946                   }
947                   #endif
948                   strcat(sys,temp);
949                   if ((*p)=='f')
950                   { // remove #SEC
951                     char *pp=(char *)strchr(sys,'#');
952                     if (pp!=NULL)
953                     {
954                       *pp='\0';
955                       i=strlen(sys);
956                       memset(pp,0,MAX_SYSCMD_LEN-i);
957                     }
958                   }
959                   i=strlen(sys);
960                   break;
961                 }
962        case 'i': /* singular.info */
963                 {
964                   char *i_res=feResource('i');
965                   if (i_res!=NULL) strcat(sys,i_res);
966                   else
967                   {
968                     WarnS("singular.info not found");
969                     return;
970                   }
971                   i=strlen(sys);
972                   break;
973                 }
974        case 'n': /* info node */
975                 {
976                   char temp[256];
977                   if ((hentry!=NULL) && (*(hentry->node) != '\0'))
978                     sprintf(temp,"%s",hentry->node);
979                   //else if ((hentry!=NULL) && (hentry->key!=NULL))
980                   //  sprintf(temp,"Index '%s'",hentry->key);
981                   else
982                     sprintf(temp,"Top");
983                   strcat(sys,temp);
984                   i=strlen(sys);
985                   break;
986                 }
987        case 'v': /* version number*/
988                 {
989                   char temp[256];
990                   sprintf(temp,"%d-%d-%d",SINGULAR_VERSION/1000,
991                                 (SINGULAR_VERSION % 1000)/100,
992                                 (SINGULAR_VERSION % 100)/10);
993                   strcat(sys,temp);
994                   i=strlen(sys);
995                   break;
996                 }
997        default: break;
998      }
999      p++;
1000    }
1001    else
1002    {
1003      sys[i]=*p;
1004      p++;i++;
1005    }
1006  }
1007  Print("running `%s`\n",sys);
1008  (void) system(sys);
1009}
1010
1011static BOOLEAN heDummyInit(int /*warn*/, int /*br*/)
1012{
1013  return TRUE;
1014}
1015static void heDummyHelp(heEntry /*hentry*/, int /*br*/)
1016{
1017  WerrorS("No functioning help browser available.");
1018}
1019
1020static BOOLEAN heEmacsInit(int /*warn*/, int /*br*/)
1021{
1022  return TRUE;
1023}
1024static void heEmacsHelp(heEntry hentry, int /*br*/)
1025{
1026  WarnS("Your help command could not be executed. Use");
1027  Warn("C-h C-s %s",
1028       (hentry != NULL && *(hentry->node) != '\0' ? hentry->node : "Top"));
1029  WarnS("to enter the Singular online help. For general");
1030  WarnS("information on Singular running under Emacs, type C-h m.");
1031}
1032static int singular_manual(char *str, BOOLEAN isIndexEntry);
1033static void heBuiltinHelp(heEntry hentry, int /*br*/)
1034{
1035  char* node = omStrDup(hentry != NULL && *(hentry->key) != '\0' ?
1036                       hentry->key : "Top");
1037  singular_manual(node,(hentry != NULL) && *(hentry->url)!='\0');
1038  omFree(node);
1039}
1040
1041
1042/* ========================================================================== */
1043// old, stupid builtin_help
1044// This could be implemented much more clever, but I'm too lazy to do this now
1045//
1046#define HELP_OK        0
1047#define FIN_INDEX    '\037'
1048#define HELP_NOT_OPEN  1
1049#define HELP_NOT_FOUND 2
1050#define BUF_LEN        256
1051#define IDX_LEN        256
1052
1053static inline char tolow(char p)
1054{
1055  if (('A'<=p)&&(p<='Z')) return p | 040;
1056  return p;
1057}
1058
1059/*************************************************/
1060static int show(unsigned long offset, char *close)
1061{ char buffer[BUF_LEN+1];
1062  int  lines = 0;
1063  FILE * help;
1064
1065  if( (help = fopen(feResource('i'), "rb")) == NULL)
1066    return HELP_NOT_OPEN;
1067
1068  fseek(help,  (long)(offset+1), (int)0);
1069  while( (!feof(help))
1070        && (*fgets(buffer, BUF_LEN, help) != EOF)
1071        && (buffer[0] != FIN_INDEX))
1072  {
1073    printf("%s", buffer);
1074    if(lines++==pagelength)
1075    {
1076      printf("\n Press <RETURN> to continue or x to exit help.\n");
1077      fflush(stdout);
1078      *close = (char)getchar();
1079      if(*close=='x')
1080      {
1081        getchar();
1082        break;
1083      }
1084      lines=0;
1085    }
1086  }
1087  if((*close!='x')&&(pagelength>0))
1088  {
1089    printf("\nEnd of part. Press <RETURN> to continue or x to exit help.\n");
1090    fflush(stdout);
1091    *close = (char)getchar();
1092    if(*close=='x')
1093      getchar();
1094  }
1095  fclose(help);
1096  return HELP_OK;
1097}
1098
1099/*************************************************/
1100static int singular_manual(char *str, BOOLEAN isIndexEntry)
1101{ FILE *index=NULL;
1102  unsigned long offset;
1103  char *p,close=' ';
1104  int done = 0;
1105  char buffer[BUF_LEN+1],
1106       Index[IDX_LEN+1],
1107       String[IDX_LEN+1];
1108  Print("HELP >>%s>>\n",str);
1109
1110  if( (index = fopen(feResource('i'), "rb")) == NULL)
1111  {
1112    return HELP_NOT_OPEN;
1113  }
1114
1115  if (!isIndexEntry)
1116  {
1117    for(p=str; *p; p++) *p = tolow(*p);/* */
1118    do
1119    {
1120      p--;
1121    }
1122    while ((p != str) && (*p<=' '));
1123    p++;
1124    *p='\0';
1125    (void)sprintf(String, " %s ", str);
1126  }
1127  else
1128  {
1129    (void)sprintf(String, " %s", str);
1130  }
1131
1132  while(!feof(index)
1133        && (fgets(buffer, BUF_LEN, index) != (char *)0)
1134        && (buffer[0] != FIN_INDEX));
1135
1136  while(!feof(index))
1137  {
1138    if (fgets(buffer, BUF_LEN, index)==NULL) break; /*fill buffer */
1139    if (si_sscanf(buffer, "Node:%[^\177]\177%ld\n", Index, &offset)!=2)
1140      continue;
1141    if (!isIndexEntry)
1142    {
1143      for(p=Index; *p; p++) *p = tolow(*p);/* */
1144      (void)strcat(Index, " ");
1145      if( strstr(Index, String)!=NULL)
1146      {
1147        done++; (void)show(offset, &close);
1148      }
1149    }
1150    else if( strcmp(Index, String)==0)
1151    {
1152      done++; (void)show(offset, &close);
1153      break;
1154    }
1155    Index[0]='\0';
1156    if(close=='x')
1157    break;
1158  }
1159  if (index != NULL) (void)fclose(index);
1160  if(done==0)
1161  {
1162    Warn("`%s` not found",String);
1163    return HELP_NOT_FOUND;
1164  }
1165  return HELP_OK;
1166}
1167/*************************************************/
Note: See TracBrowser for help on using the repository browser.