source: git/kernel/feResource.cc @ 8e0511

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