source: git/libpolys/resources/feResource.cc @ 3b2b4c7

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