source: git/Singular/fehelp.cc @ aa37e4

spielwiese
Last change on this file since aa37e4 was 423f4e, checked in by Hans Schoenemann <hannes@…>, 22 months ago
allow (some)help in restricted mode
  • 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  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                       snprintf(temp,256,"%s/%d-%d-%d/index.htm", htmldir,
918                                  SINGULAR_VERSION/1000,
919                                 (SINGULAR_VERSION % 1000)/100,
920                                 (SINGULAR_VERSION % 100)/10
921                       );
922                     else
923                       snprintf(temp,256,"%s/index.htm", htmldir);
924                   }
925                   #else
926                   {
927                     if (*p=='H')
928                       sprintf(temp,"%s/%d-%d-%d/%s", htmldir,
929                                  SINGULAR_VERSION/1000,
930                                 (SINGULAR_VERSION % 1000)/100,
931                                 (SINGULAR_VERSION % 100)/10,
932                       hentry->url);
933                     else
934                       sprintf(temp,"%s/%d-%d-%d/%s", htmldir, hentry->url);
935                   }
936                   else
937                     if (*p=='H')
938                       sprintf(temp,"%s/%d-%d-%d/index.htm", htmldir,
939                                  SINGULAR_VERSION/1000,
940                                 (SINGULAR_VERSION % 1000)/100,
941                                 (SINGULAR_VERSION % 100)/10
942                       );
943                     else
944                       sprintf(temp,"%s/index.htm", htmldir);
945                   }
946                   #endif
947                   strcat(sys,temp);
948                   if ((*p)=='f')
949                   { // remove #SEC
950                     char *pp=(char *)strchr(sys,'#');
951                     if (pp!=NULL)
952                     {
953                       *pp='\0';
954                       i=strlen(sys);
955                       memset(pp,0,MAX_SYSCMD_LEN-i);
956                     }
957                   }
958                   i=strlen(sys);
959                   break;
960                 }
961        case 'i': /* singular.info */
962                 {
963                   char *i_res=feResource('i');
964                   if (i_res!=NULL) strcat(sys,i_res);
965                   else
966                   {
967                     WarnS("singular.info not found");
968                     return;
969                   }
970                   i=strlen(sys);
971                   break;
972                 }
973        case 'n': /* info node */
974                 {
975                   char temp[256];
976                   if ((hentry!=NULL) && (*(hentry->node) != '\0'))
977                     sprintf(temp,"%s",hentry->node);
978                   //else if ((hentry!=NULL) && (hentry->key!=NULL))
979                   //  sprintf(temp,"Index '%s'",hentry->key);
980                   else
981                     sprintf(temp,"Top");
982                   strcat(sys,temp);
983                   i=strlen(sys);
984                   break;
985                 }
986        case 'v': /* version number*/
987                 {
988                   char temp[256];
989                   sprintf(temp,"%d-%d-%d",SINGULAR_VERSION/1000,
990                                 (SINGULAR_VERSION % 1000)/100,
991                                 (SINGULAR_VERSION % 100)/10);
992                   strcat(sys,temp);
993                   i=strlen(sys);
994                   break;
995                 }
996        default: break;
997      }
998      p++;
999    }
1000    else
1001    {
1002      sys[i]=*p;
1003      p++;i++;
1004    }
1005  }
1006  Print("running `%s`\n",sys);
1007  if (!FE_OPT_NO_SHELL_FLAG) (void) system(sys);
1008}
1009
1010static BOOLEAN heDummyInit(int /*warn*/, int /*br*/)
1011{
1012  return TRUE;
1013}
1014static void heDummyHelp(heEntry /*hentry*/, int /*br*/)
1015{
1016  WerrorS("No functioning help browser available.");
1017}
1018
1019static BOOLEAN heEmacsInit(int /*warn*/, int /*br*/)
1020{
1021  return TRUE;
1022}
1023static void heEmacsHelp(heEntry hentry, int /*br*/)
1024{
1025  WarnS("Your help command could not be executed. Use");
1026  Warn("C-h C-s %s",
1027       (hentry != NULL && *(hentry->node) != '\0' ? hentry->node : "Top"));
1028  WarnS("to enter the Singular online help. For general");
1029  WarnS("information on Singular running under Emacs, type C-h m.");
1030}
1031static int singular_manual(char *str, BOOLEAN isIndexEntry);
1032static void heBuiltinHelp(heEntry hentry, int /*br*/)
1033{
1034  char* node = omStrDup(hentry != NULL && *(hentry->key) != '\0' ?
1035                       hentry->key : "Top");
1036  singular_manual(node,(hentry != NULL) && *(hentry->url)!='\0');
1037  omFree(node);
1038}
1039
1040
1041/* ========================================================================== */
1042// old, stupid builtin_help
1043// This could be implemented much more clever, but I'm too lazy to do this now
1044//
1045#define HELP_OK        0
1046#define FIN_INDEX    '\037'
1047#define HELP_NOT_OPEN  1
1048#define HELP_NOT_FOUND 2
1049#define BUF_LEN        256
1050#define IDX_LEN        256
1051
1052static inline char tolow(char p)
1053{
1054  if (('A'<=p)&&(p<='Z')) return p | 040;
1055  return p;
1056}
1057
1058/*************************************************/
1059static int show(unsigned long offset, char *close)
1060{ char buffer[BUF_LEN+1];
1061  int  lines = 0;
1062  FILE * help;
1063
1064  if( (help = fopen(feResource('i'), "rb")) == NULL)
1065    return HELP_NOT_OPEN;
1066
1067  fseek(help,  (long)(offset+1), (int)0);
1068  while( (!feof(help))
1069        && (*fgets(buffer, BUF_LEN, help) != EOF)
1070        && (buffer[0] != FIN_INDEX))
1071  {
1072    printf("%s", buffer);
1073    if(lines++==pagelength)
1074    {
1075      printf("\n Press <RETURN> to continue or x to exit help.\n");
1076      fflush(stdout);
1077      *close = (char)getchar();
1078      if(*close=='x')
1079      {
1080        getchar();
1081        break;
1082      }
1083      lines=0;
1084    }
1085  }
1086  if((*close!='x')&&(pagelength>0))
1087  {
1088    printf("\nEnd of part. Press <RETURN> to continue or x to exit help.\n");
1089    fflush(stdout);
1090    *close = (char)getchar();
1091    if(*close=='x')
1092      getchar();
1093  }
1094  fclose(help);
1095  return HELP_OK;
1096}
1097
1098/*************************************************/
1099static int singular_manual(char *str, BOOLEAN isIndexEntry)
1100{ FILE *index=NULL;
1101  unsigned long offset;
1102  char *p,close=' ';
1103  int done = 0;
1104  char buffer[BUF_LEN+1],
1105       Index[IDX_LEN+1],
1106       String[IDX_LEN+1];
1107  Print("HELP >>%s>>\n",str);
1108
1109  if( (index = fopen(feResource('i'), "rb")) == NULL)
1110  {
1111    return HELP_NOT_OPEN;
1112  }
1113
1114  if (!isIndexEntry)
1115  {
1116    for(p=str; *p; p++) *p = tolow(*p);/* */
1117    do
1118    {
1119      p--;
1120    }
1121    while ((p != str) && (*p<=' '));
1122    p++;
1123    *p='\0';
1124    (void)sprintf(String, " %s ", str);
1125  }
1126  else
1127  {
1128    (void)sprintf(String, " %s", str);
1129  }
1130
1131  while(!feof(index)
1132        && (fgets(buffer, BUF_LEN, index) != (char *)0)
1133        && (buffer[0] != FIN_INDEX));
1134
1135  while(!feof(index))
1136  {
1137    if (fgets(buffer, BUF_LEN, index)==NULL) break; /*fill buffer */
1138    if (si_sscanf(buffer, "Node:%[^\177]\177%ld\n", Index, &offset)!=2)
1139      continue;
1140    if (!isIndexEntry)
1141    {
1142      for(p=Index; *p; p++) *p = tolow(*p);/* */
1143      (void)strcat(Index, " ");
1144      if( strstr(Index, String)!=NULL)
1145      {
1146        done++; (void)show(offset, &close);
1147      }
1148    }
1149    else if( strcmp(Index, String)==0)
1150    {
1151      done++; (void)show(offset, &close);
1152      break;
1153    }
1154    Index[0]='\0';
1155    if(close=='x')
1156    break;
1157  }
1158  if (index != NULL) (void)fclose(index);
1159  if(done==0)
1160  {
1161    Warn("`%s` not found",String);
1162    return HELP_NOT_FOUND;
1163  }
1164  return HELP_OK;
1165}
1166/*************************************************/
Note: See TracBrowser for help on using the repository browser.