source: git/resources/feResource.cc @ 35d0c19

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