source: git/Singular/fehelp.cc @ a9f049

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