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