source: git/findexec/feResource.cc @ f0b795

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