source: git/Singular/fehelp.cc @ 3647c85

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