source: git/Singular/fehelp.cc @ 6ce030f

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