source: git/Singular/fehelp.cc @ 9db0567

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