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