source: git/Singular/fehelp.cc @ a3f0fea

spielwiese
Last change on this file since a3f0fea was a3f0fea, checked in by Reimer Behrends <behrends@…>, 5 years ago
Modify variable declarions for pSingular.
  • 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.hlp */
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.hlp */
961                 {
962                   char *i_res=feResource('i');
963                   if (i_res!=NULL) strcat(sys,i_res);
964                   else
965                   {
966                     WarnS("singular.hlp 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.