source: git/libpolys/resources/feResource.cc @ 06df101

spielwiese
Last change on this file since 06df101 was c54848, checked in by Oleksandr Motsak <motsak@…>, 13 years ago
ADD: another path to gftables
  • Property mode set to 100644
File size: 19.4 KB
Line 
1/****************************************
2*  Computer Algebra System SINGULAR     *
3****************************************/
4/* $Id$ */
5/*
6* ABSTRACT: management of resources
7*/
8
9#include <stdlib.h>
10#include <unistd.h>
11#include <string.h>
12#include <unistd.h>
13#include <sys/param.h>
14
15#include "config.h"
16#include <misc/auxiliary.h>
17
18#include "feResource.h"
19
20#ifdef AIX_4
21#define HAVE_PUTENV 1
22#endif
23
24#if defined(HPUX_10) || defined(HPUX_9)
25extern "C" int setenv(const char *name, const char *value, int overwrite);
26#endif
27
28
29#include <reporter/reporter.h>
30#if !defined(ESINGULAR) && !defined(TSINGULAR)
31#include <omalloc/omalloc.h>
32#else
33char* feResource(const char id, int warn = -1);
34char* feResource(const char* key, int warn = -1);
35#endif
36
37// define RESOURCE_DEBUG for chattering about resource management
38// #define RESOURCE_DEBUG
39
40#if defined(MAKE_DISTRIBUTION)
41#if defined(ix86_Win) && ! defined(__CYGWIN__)
42#define SINGULAR_DEFAULT_DIR "/Singular/"S_VERSION1
43#else // unix
44#define SINGULAR_DEFAULT_DIR "/usr/local/Singular/"S_VERSION1
45#endif
46#else // ! defined(MAKE_DISTRIBUTION)
47#define SINGULAR_DEFAULT_DIR S_ROOT_DIR
48#endif // defined(MAKE_DISTRIBUTION)
49
50/*****************************************************************
51 *
52 * Declarations: Data  structures
53 *
54 *****************************************************************/
55typedef enum {feResUndef = 0, feResBinary, feResDir, feResFile, feResUrl, feResPath} feResourceType;
56
57typedef struct feResourceConfig_s
58{
59  const char*           key;   // key to identify resource
60  const char            id;    // char id to identify resource
61  feResourceType  type;  // type of Resource
62  const char*           env;   // env variable to look for
63  const char*           fmt;   // format string -- see below for epxlaination
64  char*                 value; // what it was set to: may be changed
65} feResourceConfig_s;
66typedef feResourceConfig_s * feResourceConfig;
67
68// feSprintf transforms format strings as follows:
69// 1.) substrings of the form %c (c being a letter) are replaced by respective resource value
70// 2.) substrings of the form $string are replaced by value of resp. env variable
71
72// feCleanResource makes furthermore  the following transformations (except for URL resources)
73// 1.) '/' characters are replaced by respective directory - separators
74// 2.) ';' characters are replaced by respective path separators
75static feResourceConfig_s feResourceConfigs[] =
76{
77  {"SearchPath",    's', feResPath,  NULL,
78   "$SINGULARPATH;"
79   "%b/LIB;"
80   "%b/MOD;"
81   "%b/../lib/libpolys/MOD;"
82   "%r/LIB;"
83   "%r/../LIB;"
84   "%d/LIB;"
85   "%d/../LIB;"
86   "%b/gftables;"
87   "%b/../share/gftables;"
88   "%b/../factory/gftables;"
89   "%b/../../../factory/gftables;"
90   "%b/../../factory/gftables",
91   ""},
92  {"Singular",  'S',    feResBinary,"SINGULAR_EXECUTABLE",  "%d/"S_UNAME"/Singular",(char *)""},
93  {"BinDir",    'b',    feResDir,   "SINGULAR_BIN_DIR",     "%d/"S_UNAME,           (char *)""},
94  {"RootDir",   'r',    feResDir,   "SINGULAR_ROOT_DIR",    "%b/..",                (char *)""},
95  {"DefaultDir",'d',    feResDir,   "SINGULAR_DEFAULT_DIR",  SINGULAR_DEFAULT_DIR,  (char *)""},
96  {"InfoFile",  'i',    feResFile,  "SINGULAR_INFO_FILE",   "%r/info/singular.hlp", (char *)""},
97  {"IdxFile",   'x',    feResFile,  "SINGULAR_IDX_FILE",    "%r/doc/singular.idx",  (char *)""},
98  {"HtmlDir",   'h',    feResDir,   "SINGULAR_HTML_DIR",    "%r/html",              (char *)""},
99#ifdef ix86_Win
100  {"HtmlHelpFile",'C',  feResFile,  "SINGULAR_CHM_FILE",    "%r/doc/Manual.chm",    (char *)""},
101#endif
102  {"ManualUrl", 'u',    feResUrl,   "SINGULAR_URL",         "http://www.singular.uni-kl.de/Manual/"S_VERSION1,    (char *)""},
103  {"ExDir",     'm',    feResDir,   "SINGULAR_EXAMPLES_DIR","%r/examples",          (char *)""},
104  {"Path",      'p',    feResPath,  NULL,                   "%b;$PATH",             (char *)""},
105
106#ifdef ESINGULAR
107  {"emacs",     'E',    feResBinary,"ESINGULAR_EMACS",      "%b/emacs",             (char *)""},
108  {"xemacs",    'A',    feResBinary,"ESINGULAR_EMACS",      "%b/xemacs",            (char *)""},
109  {"SingularEmacs",'M', feResBinary,"ESINGULAR_SINGULAR",   "%b/Singular",          (char *)""},
110  {"EmacsLoad", 'l',    feResFile,  "ESINGULAR_EMACS_LOAD", "%e/.emacs-singular",   (char *)""},
111  {"EmacsDir",  'e',    feResDir,   "ESINGULAR_EMACS_DIR",  "%r/emacs",             (char *)""},
112#elif defined(TSINGULAR)
113  {"SingularXterm",'M', feResBinary,"TSINGULAR_SINGULAR",   "%b/Singular",          (char *)""},
114#ifdef ix86_Win
115  {"rxvt",      'X',    feResBinary,"RXVT",                 "%b/rxvt",              (char *)""},
116#else
117  {"xterm",     'X',    feResBinary,"XTERM",                "%b/xterm",             (char *)""},
118#endif
119#else
120  {"EmacsDir",  'e',    feResDir,   "SINGULAR_EMACS_DIR",   "%r/emacs",             (char *)""},
121#endif
122  {NULL, 0, feResUndef, NULL, NULL, NULL}, // must be the last record
123};
124
125
126/*****************************************************************
127 *
128 * Declarations: Local variables / functions
129 *
130 *****************************************************************/
131char* feArgv0=NULL;
132#define MAXRESOURCELEN 5*MAXPATHLEN
133
134static feResourceConfig feGetResourceConfig(const char id);
135static feResourceConfig feGetResourceConfig(const char* key);
136static char* feResource(feResourceConfig config, int warn);
137static char* feResourceDefault(feResourceConfig config);
138static char* feInitResource(feResourceConfig config, int warn);
139static char* feGetExpandedExecutable();
140static BOOLEAN feVerifyResourceValue(feResourceType type, char* value);
141static char* feCleanResourceValue(feResourceType type, char* value);
142static char* feCleanUpFile(char* fname);
143static char* feCleanUpPath(char* path);
144static void mystrcpy(char* d, char* s);
145static char* feSprintf(char* s, const char* fmt, int warn = -1);
146#if defined(ix86_Win) && defined(__GNUC__)
147// utility function of Cygwin32:
148extern "C" int cygwin32_posix_path_list_p (const char *path);
149#endif
150
151/*****************************************************************
152 *
153 * Public functions
154 *
155 *****************************************************************/
156char* feResource(const char* key, int warn)
157{
158  return feResource(feGetResourceConfig(key), warn);
159}
160
161char* feResource(const char id, int warn)
162{
163  return feResource(feGetResourceConfig(id), warn);
164}
165
166char* feGetResource(const char id)
167{
168  return feResource(feGetResourceConfig(id), -1);
169}
170
171char* feResourceDefault(const char id)
172{
173  return feResourceDefault(feGetResourceConfig(id));
174}
175
176char* feResourceDefault(const char* key)
177{
178  return feResourceDefault(feGetResourceConfig(key));
179}
180
181void feInitResources(char* argv0)
182{
183#if defined(ix86_Win) && defined(__GNUC__)
184  if (cygwin32_posix_path_list_p (getenv("PATH")))
185    fePathSep = ':';
186#endif
187  if (argv0==NULL)
188  {
189    feArgv0 = (char*)omAlloc0(MAXPATHLEN+strlen("/Singular"));
190    getcwd(feArgv0,MAXPATHLEN);
191    strcpy(feArgv0+strlen(feArgv0),"/Singular");
192  }
193  else
194    feArgv0 = omStrDup(argv0);
195#ifdef RESOURCE_DEBUG
196  printf("feInitResources: entering with argv0=%s=\n", feArgv0);
197#endif
198  // init some Resources
199  feResource('b');
200  feResource('r');
201  // don't complain about stuff when initializing SingularPath
202  feResource('s',0);
203
204#if defined(HAVE_SETENV) || defined(HAVE_PUTENV)
205  char* path = feResource('p');
206#ifdef RESOURCE_DEBUG
207  printf("feInitResources: setting path with argv0=%s=\n", path);
208#endif
209#ifdef HAVE_PUTENV
210  if (path != NULL) { char *s=(char *)omAlloc0(strlen(path)+6);
211                      sprintf(s,"PATH=%s",path);
212                      putenv(s);
213                    }
214#else
215  if (path != NULL) setenv("PATH", path, 1);
216#endif
217#endif
218}
219
220void feReInitResources()
221{
222  int i = 0;
223  while (feResourceConfigs[i].key != NULL)
224  {
225    if (feResourceConfigs[i].value[0] != '\0')
226    {
227      if (feResourceConfigs[i].value != NULL)
228        omFree(feResourceConfigs[i].value);
229      feResourceConfigs[i].value = (char *)"";
230    }
231    i++;
232  }
233#ifdef RESOURCE_DEBUG
234  printf("feInitResources: entering with argv0=%s=\n", feArgv0);
235#endif
236  // init some Resources
237  feResource('b');
238  feResource('r');
239  // don't complain about stuff when initializing SingularPath
240  feResource('s',0);
241}
242
243/*****************************************************************
244 *
245 * Local functions
246 *
247 *****************************************************************/
248static feResourceConfig feGetResourceConfig(const char id)
249{
250  int i = 0;
251  while (feResourceConfigs[i].key != NULL)
252  {
253    if (feResourceConfigs[i].id == id) return &(feResourceConfigs[i]);
254    i++;
255  }
256  return NULL;
257}
258
259static feResourceConfig feGetResourceConfig(const char* key)
260{
261  int i = 0;
262  while (feResourceConfigs[i].key != NULL)
263  {
264    if (strcmp(feResourceConfigs[i].key, key) == 0)
265      return &(feResourceConfigs[i]);
266    i++;
267  }
268  return NULL;
269}
270
271static char* feResource(feResourceConfig config, int warn)
272{
273  if (config == NULL) return NULL;
274  if (config->value != NULL && *(config->value) != '\0') return config->value;
275  return feInitResource(config, warn);
276}
277
278static char* feResourceDefault(feResourceConfig config)
279{
280  if (config == NULL) return NULL;
281  char* value = (char*) omAlloc(MAXRESOURCELEN);
282  feSprintf(value, config->fmt, -1);
283  return value;
284}
285
286static char* feInitResource(feResourceConfig config, int warn)
287{
288  assume(config != NULL);
289#ifdef RESOURCE_DEBUG
290  printf("feInitResource: entering for %s\n", config->key);
291#endif
292
293  char value[MAXRESOURCELEN];
294  // now we have to work
295  // First, check Environment variable
296  if (config->env != NULL)
297  {
298    char* evalue = getenv(config->env);
299    if (evalue != NULL)
300    {
301#ifdef RESOURCE_DEBUG
302      printf("feInitResource: Found value from env:%s\n", evalue);
303#endif
304      strcpy(value, evalue);
305      if (config->type == feResBinary  // do not verify binaries
306          ||
307          feVerifyResourceValue(config->type,
308                                feCleanResourceValue(config->type, value)))
309      {
310#ifdef RESOURCE_DEBUG
311        printf("feInitResource: Set value of %s to =%s=\n", config->key, value);
312#endif
313        config->value = omStrDup(value);
314        return config->value;
315      }
316    }
317  }
318
319  *value = '\0';
320  // Special treatment of executable
321  if (config->id == 'S')
322  {
323    char* executable = feGetExpandedExecutable();
324    if (executable != NULL)
325    {
326#ifdef RESOURCE_DEBUG
327      printf("exec:%s\n", executable);
328#endif
329      strcpy(value, executable);
330#ifdef RESOURCE_DEBUG
331      printf("value:%s\n", value);
332#endif
333      omFree(executable);
334    }
335  }
336  // and bindir
337  else if (config->id == 'b')
338  {
339    char* executable = feResource('S');
340#ifdef RESOURCE_DEBUG
341      printf("feInitResource: Get %s from %s\n", config->key, executable);
342#endif
343    if (executable != NULL)
344    {
345      strcpy(value, executable);
346      executable = strrchr(value, DIR_SEP);
347      if (executable != NULL) *executable = '\0';
348    }
349  }
350
351#ifdef RESOURCE_DEBUG
352  printf("value:%s\n", value);
353#endif
354
355  if (*value == '\0' && config->fmt != NULL )
356  {
357    feSprintf(value, config->fmt, warn);
358  }
359  else if (config->fmt == NULL)
360  {
361    sprintf(value, "Wrong Resource Specification of %s", config->key);
362    dReportBug(value);
363    return NULL;
364  }
365
366  // Clean and verify
367  if (feVerifyResourceValue(config->type,
368                            feCleanResourceValue(config->type, value)))
369  {
370#ifdef RESOURCE_DEBUG
371    printf("feInitResource: Set value of %s to =%s=\n", config->key, value);
372#endif
373    config->value = omStrDup(value);
374    return config->value;
375  }
376  else if (config->type == feResBinary)
377  {
378    // for binaries, search through PATH once more
379    char* executable = omFindExec(config->key, value);
380    if (executable != NULL)
381    {
382      if (feVerifyResourceValue(config->type,
383                                feCleanResourceValue(config->type, value)))
384      {
385        config->value = omStrDup(value);
386#ifdef RESOURCE_DEBUG
387        printf("feInitResource: Set value of %s to =%s=\n", config->key, config->value);
388#endif
389        return config->value;
390      }
391    }
392  }
393
394  // issue warning if explicitely requested, or if
395  // this value is gotten for the first time
396  if (warn > 0 || (warn < 0 && config->value != NULL))
397  {
398    Warn("Could not get %s. ", config->key);
399    Warn("Either set environment variable %s to %s,",
400         config->env, config->key);
401    feSprintf(value, config->fmt, warn);
402    Warn("or make sure that %s is at %s", config->key, value);
403  }
404#ifdef RESOURCE_DEBUG
405      printf("feInitResource: Set value of %s to NULL", config->key);
406#endif
407  config->value = NULL;
408  return NULL;
409}
410
411static char* feGetExpandedExecutable()
412{
413  if (feArgv0 == NULL || *feArgv0 == '\0')
414  {
415    if (feArgv0 == NULL) dReportBug("feArgv0 == NULL");
416    else dReportBug("feArgv0 == ''");
417    return NULL;
418  }
419#ifdef ix86_Win // stupid WINNT sometimes gives you argv[0] within ""
420  if (*feArgv0 == '"')
421  {
422    int l = strlen(feArgv0);
423    if (feArgv0[l-1] == '"')
424    {
425      feArgv0[l-1] = '\0';
426      feArgv0++;
427    }
428  }
429#endif
430#ifdef RESOURCE_DEBUG
431  printf("feGetExpandedExecutable: calling find_exec with =%s=\n", feArgv0);
432#endif
433  char executable[MAXRESOURCELEN];
434  char* value = omFindExec(feArgv0, executable);
435#ifdef RESOURCE_DEBUG
436  printf("feGetExpandedExecutable: find_exec exited with =%s=%d\n", executable, access(executable, X_OK));
437#endif
438  if (value == NULL)
439  {
440    char message[MAXRESOURCELEN];
441    sprintf(message, "Could not get expanded executable from %s", feArgv0);
442    dReportBug(message);
443    return NULL;
444  }
445  return omStrDup(value);
446}
447
448
449static BOOLEAN feVerifyResourceValue(feResourceType type, char* value)
450{
451#ifdef RESOURCE_DEBUG
452  printf("feVerifyResourceValue: entering with =%s=\n", value);
453  printf("%d:%d\n", access(value, R_OK), access(value, X_OK));
454#endif
455  switch(type)
456  {
457      case feResUrl:
458      case feResPath:
459        return TRUE;
460
461      case feResFile:
462        return ! access(value, R_OK);
463
464      case feResBinary:
465      case feResDir:
466        return ! access(value, X_OK);
467
468      default:
469        return FALSE;
470  }
471}
472
473/*****************************************************************
474 *
475 * Cleaning/Transformations of resource values
476 *
477 *****************************************************************/
478
479static char* feCleanResourceValue(feResourceType type, char* value)
480{
481  if (value == NULL || *value == '\0') return value;
482#ifdef RESOURCE_DEBUG
483      printf("Clean value:%s\n", value);
484#endif
485#ifdef ix86_Win
486#ifdef RESOURCE_DEBUG
487      printf("Clean WINNT value:%s\n", value);
488#endif
489  if (type == feResBinary)
490  {
491    int l = strlen(value);
492    if (l < 4 || (strcmp(&value[l-4], ".exe") != 0 &&
493                  strcmp(&value[l-4], ".EXE") != 0))
494      strcat(value, ".exe");
495  }
496#endif
497  if (type == feResFile || type == feResBinary || type == feResDir)
498    return feCleanUpFile(value);
499  if (type == feResPath)
500    return feCleanUpPath(value);
501  return value;
502}
503
504static char* feCleanUpFile(char* fname)
505{
506  char* fn, *s;
507
508#ifdef RESOURCE_DEBUG
509  printf("feCleanUpFile: entering with =%s=\n", fname);
510#endif
511  // Remove unnecessary .. and //
512  for (fn = fname; *fn != '\0'; fn++)
513  {
514    if (*fn == '/')
515    {
516      if (*(fn+1) == '\0')
517      {
518        if (fname != fn) *fn = '\0';
519        break;
520      }
521      if (*(fn + 1) == '/' && (fname != fn))
522      {
523        mystrcpy(fn, fn+1);
524        fn--;
525      }
526      else if (*(fn+1) == '.')
527      {
528        if (*(fn+2) == '.' && (*(fn + 3) == '/' || *(fn + 3) == '\0'))
529        {
530        #if 0
531        // this does not work: ./../../mmm will be changed to ./../mmm
532        // but we only want to change ././mmm to ./mmm
533          *fn = '\0';
534          s = strrchr(fname, '/');
535          if (s != NULL)
536          {
537            mystrcpy(s+1, fn + (*(fn + 3) != '\0' ? 4 : 3));
538            fn = s-1;
539          }
540          else
541          {
542            *fn = '/';
543          }
544        #endif
545        }
546        else if (*(fn+2) == '/' || *(fn+2) == '\0')
547        {
548          mystrcpy(fn+1, fn+3);
549          fn--;
550        }
551      }
552    }
553  }
554
555#ifdef RESOURCE_DEBUG
556  printf("feCleanUpFile: leaving with =%s=\n", fname);
557#endif
558  return fname;
559}
560
561// remove duplicates dir resp. those which do not exist
562static char* feCleanUpPath(char* path)
563{
564#ifdef RESOURCE_DEBUG
565  printf("feCleanUpPath: entering with: =%s=\n", path);
566#endif
567  if (path == NULL) return path;
568
569  int n_comps = 1, i, j;
570  char* opath = path;
571  char** path_comps;
572
573  for (; *path != '\0'; path++)
574  {
575    if (*path == fePathSep) n_comps++;
576    else if (*path == ';')
577    {
578      *path = fePathSep;
579      n_comps++;
580    }
581  }
582
583  path_comps = (char**) omAlloc(n_comps*sizeof(char*));
584  path_comps[0]=opath;
585  path=opath;
586  i = 1;
587
588  if (i < n_comps)
589  {
590    while (1)
591    {
592      if (*path == fePathSep)
593      {
594        *path = '\0';
595        path_comps[i] = path+1;
596        i++;
597        if (i == n_comps) break;
598      }
599      path++;
600    }
601  }
602
603  for (i=0; i<n_comps; i++)
604    path_comps[i] = feCleanUpFile(path_comps[i]);
605#ifdef RESOURCE_DEBUG
606  PrintS("feCleanUpPath: after CleanUpName: ");
607  for (i=0; i<n_comps; i++)
608    Print("%s:", path_comps[i]);
609  Print("\n");
610#endif
611
612  for (i=0; i<n_comps;)
613  {
614#ifdef RESOURCE_DEBUG
615    if (access(path_comps[i], X_OK | R_OK))
616      Print("feCleanUpPath: remove %d:%s -- can not access\n", i, path_comps[i]);
617#endif
618    if ( ! access(path_comps[i], X_OK | R_OK))
619    {
620      // x- permission is granted -- we assume that it is a dir
621      for (j=0; j<i; j++)
622      {
623        if (strcmp(path_comps[j], path_comps[i]) == 0)
624        {
625          // found a duplicate
626#ifdef RESOURCE_DEBUG
627          Print("feCleanUpPath: remove %d:%s -- equal to %d:%s\n", j, path_comps[j], i, path_comps[i]);
628#endif
629          j = i+1;
630          break;
631        }
632      }
633      if (j == i)
634      {
635        i++;
636        continue;
637      }
638    }
639    // now we can either not access or found a duplicate
640    path_comps[i] = NULL;
641    for (j=i+1; j<n_comps; j++)
642        path_comps[j-1] = path_comps[j];
643    n_comps--;
644  }
645
646
647  // assemble everything again
648  for (path=opath, i=0;i<n_comps-1;i++)
649  {
650    mystrcpy(path, path_comps[i]);
651    path += strlen(path);
652    *path = fePathSep;
653    path++;
654  }
655  if (n_comps)
656  {
657    mystrcpy(path, path_comps[i]);
658  }
659  else
660  {
661    *opath = '\0';
662  }
663  omFree(path_comps);
664#ifdef RESOURCE_DEBUG
665  Print("feCleanUpPath: leaving with path=%s=\n", opath);
666#endif
667  return opath;
668}
669
670// strcpy where source and destination may overlap
671static void mystrcpy(char* d, char* s)
672{
673  assume(d != NULL && s != NULL);
674  while (*s != '\0')
675  {
676    *d = *s;
677    d++;
678    s++;
679  }
680  *d = '\0';
681}
682
683/*****************************************************************
684 *
685 * feSprintf
686 *
687 *****************************************************************/
688static char* feSprintf(char* s, const char* fmt, int warn)
689{
690  char* s_in = s;
691  if (fmt == NULL) return NULL;
692
693  while (*fmt != '\0')
694  {
695    *s = *fmt;
696
697    if (*fmt == '%' && *(fmt + 1) != '\0')
698    {
699      fmt++;
700      char* r = feResource(*fmt, warn);
701      if (r != NULL)
702      {
703        strcpy(s, r);
704        s += strlen(r) - 1;
705      }
706      else
707      {
708        s++;
709        *s = *fmt;
710      }
711    }
712    else if (*fmt == '$' && *(fmt + 1) != '\0')
713    {
714      fmt++;
715      char* v = s + 1;
716      while (*fmt == '_' ||
717             (*fmt >= 'A' && *fmt <= 'Z') ||
718             (*fmt >= 'a' && *fmt <= 'z'))
719      {
720        *v = *fmt;
721        v++;
722        fmt++;
723      }
724      fmt--;
725      *v = '\0';
726      v = getenv(s + 1);
727      if (v != NULL) strcpy(s, v);
728      s += strlen(s) - 1;
729    }
730    s++;
731    fmt++;
732  }
733  *s = '\0';
734  return s_in;
735}
736
737void feStringAppendResources(int warn)
738{
739  int i = 0;
740  char* r;
741  StringAppend("%-10s:\t%s\n", "argv[0]", feArgv0);
742  while (feResourceConfigs[i].key != NULL)
743  {
744    r = feResource(feResourceConfigs[i].key, warn);
745    StringAppend("%-10s:\t%s\n", feResourceConfigs[i].key,
746                 (r != NULL ? r : ""));
747    i++;
748  }
749}
Note: See TracBrowser for help on using the repository browser.