source: git/Singular/fehelp.cc @ e62a1d

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