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