source: git/Singular/fehelp.cc @ cf2307d

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