source: git/Singular/fehelp.cc @ 1a2a74

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