source: git/Singular/fehelp.cc @ f22f22a

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