source: git/Singular/fehelp.cc @ fa167e

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