source: git/Singular/fehelp.cc @ 5476e83

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