source: git/Singular/fehelp.cc @ 69331f

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