source: git/findexec/feResource.cc @ 4d80e2b

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