source: git/resources/feResource.cc @ da7eaf

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