source: git/libpolys/resources/feResource.cc @ 4f07ef

fieker-DuValspielwiese
Last change on this file since 4f07ef was 59a62bd, checked in by Oleksandr Motsak <motsak@…>, 13 years ago
ADD: feInitResources can use 'program_invocation_name' instead of argv[0] ADD: executables should run feInitResources at the start
  • 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
13#include "config.h"
14#include <misc/auxiliary.h>
15
16#include "feResource.h"
17
18
19// the following is needed due to 'program_invocation_name'
20#define _GNU_SOURCE
21#include <errno.h>
22
23
24#ifdef AIX_4
25#define HAVE_PUTENV 1
26#endif
27
28#if defined(HPUX_10) || defined(HPUX_9)
29extern "C" int setenv(const char *name, const char *value, int overwrite);
30#endif
31
32
33#include <reporter/reporter.h>
34#if !defined(ESINGULAR) && !defined(TSINGULAR)
35#include <omalloc/omalloc.h>
36#else
37char* feResource(const char id, int warn = -1);
38char* feResource(const char* key, int warn = -1);
39#endif
40
41// define RESOURCE_DEBUG for chattering about resource management
42// #define RESOURCE_DEBUG
43
44#if defined(MAKE_DISTRIBUTION)
45#if defined(ix86_Win) && ! defined(__CYGWIN__)
46#define SINGULAR_DEFAULT_DIR "/Singular/"S_VERSION1
47#else // unix
48#define SINGULAR_DEFAULT_DIR "/usr/local/Singular/"S_VERSION1
49#endif
50#else // ! defined(MAKE_DISTRIBUTION)
51#define SINGULAR_DEFAULT_DIR S_ROOT_DIR
52#endif // defined(MAKE_DISTRIBUTION)
53
54/*****************************************************************
55 *
56 * Declarations: Data  structures
57 *
58 *****************************************************************/
59typedef enum {feResUndef = 0, feResBinary, feResDir, feResFile, feResUrl, feResPath} feResourceType;
60
61typedef struct feResourceConfig_s
62{
63  const char*           key;   // key to identify resource
64  const char            id;    // char id to identify resource
65  feResourceType  type;  // type of Resource
66  const char*           env;   // env variable to look for
67  const char*           fmt;   // format string -- see below for epxlaination
68  char*                 value; // what it was set to: may be changed
69} feResourceConfig_s;
70typedef feResourceConfig_s * feResourceConfig;
71
72// feSprintf transforms format strings as follows:
73// 1.) substrings of the form %c (c being a letter) are replaced by respective resource value
74// 2.) substrings of the form $string are replaced by value of resp. env variable
75
76// feCleanResource makes furthermore  the following transformations (except for URL resources)
77// 1.) '/' characters are replaced by respective directory - separators
78// 2.) ';' characters are replaced by respective path separators
79static feResourceConfig_s feResourceConfigs[] =
80{
81  {"SearchPath",    's', feResPath,  NULL,
82   "$SINGULARPATH;"
83   "%b/LIB;"
84   "%b/MOD;"
85   "%r/LIB;"
86   "%r/../LIB;"
87   "%d/LIB;"
88   "%d/../LIB"
89   ""},
90  {"Singular",  'S',    feResBinary,"SINGULAR_EXECUTABLE",  "%d/"S_UNAME"/Singular",(char *)""},
91  {"BinDir",    'b',    feResDir,   "SINGULAR_BIN_DIR",     "%d/"S_UNAME,           (char *)""},
92  {"RootDir",   'r',    feResDir,   "SINGULAR_ROOT_DIR",    "%b/..",                (char *)""},
93  {"DefaultDir",'d',    feResDir,   "SINGULAR_DEFAULT_DIR",  SINGULAR_DEFAULT_DIR,  (char *)""},
94  {"InfoFile",  'i',    feResFile,  "SINGULAR_INFO_FILE",   "%r/info/singular.hlp", (char *)""},
95  {"IdxFile",   'x',    feResFile,  "SINGULAR_IDX_FILE",    "%r/doc/singular.idx",  (char *)""},
96  {"HtmlDir",   'h',    feResDir,   "SINGULAR_HTML_DIR",    "%r/html",              (char *)""},
97#ifdef ix86_Win
98  {"HtmlHelpFile",'C',  feResFile,  "SINGULAR_CHM_FILE",    "%r/doc/Manual.chm",    (char *)""},
99#endif
100  {"ManualUrl", 'u',    feResUrl,   "SINGULAR_URL",         "http://www.singular.uni-kl.de/Manual/"S_VERSION1,    (char *)""},
101  {"ExDir",     'm',    feResDir,   "SINGULAR_EXAMPLES_DIR","%r/examples",          (char *)""},
102  {"Path",      'p',    feResPath,  NULL,                   "%b;$PATH",             (char *)""},
103
104#ifdef ESINGULAR
105  {"emacs",     'E',    feResBinary,"ESINGULAR_EMACS",      "%b/emacs",             (char *)""},
106  {"xemacs",    'A',    feResBinary,"ESINGULAR_EMACS",      "%b/xemacs",            (char *)""},
107  {"SingularEmacs",'M', feResBinary,"ESINGULAR_SINGULAR",   "%b/Singular",          (char *)""},
108  {"EmacsLoad", 'l',    feResFile,  "ESINGULAR_EMACS_LOAD", "%e/.emacs-singular",   (char *)""},
109  {"EmacsDir",  'e',    feResDir,   "ESINGULAR_EMACS_DIR",  "%r/emacs",             (char *)""},
110#elif defined(TSINGULAR)
111  {"SingularXterm",'M', feResBinary,"TSINGULAR_SINGULAR",   "%b/Singular",          (char *)""},
112#ifdef ix86_Win
113  {"rxvt",      'X',    feResBinary,"RXVT",                 "%b/rxvt",              (char *)""},
114#else
115  {"xterm",     'X',    feResBinary,"XTERM",                "%b/xterm",             (char *)""},
116#endif
117#else
118  {"EmacsDir",  'e',    feResDir,   "SINGULAR_EMACS_DIR",   "%r/emacs",             (char *)""},
119#endif
120  {NULL, 0, feResUndef, NULL, NULL, NULL}, // must be the last record
121};
122
123
124/*****************************************************************
125 *
126 * Declarations: Local variables / functions
127 *
128 *****************************************************************/
129char* feArgv0=NULL;
130#define MAXRESOURCELEN 5*MAXPATHLEN
131
132static feResourceConfig feGetResourceConfig(const char id);
133static feResourceConfig feGetResourceConfig(const char* key);
134static char* feResource(feResourceConfig config, int warn);
135static char* feResourceDefault(feResourceConfig config);
136static char* feInitResource(feResourceConfig config, int warn);
137static char* feGetExpandedExecutable();
138static BOOLEAN feVerifyResourceValue(feResourceType type, char* value);
139static char* feCleanResourceValue(feResourceType type, char* value);
140static char* feCleanUpFile(char* fname);
141static char* feCleanUpPath(char* path);
142static void mystrcpy(char* d, char* s);
143static char* feSprintf(char* s, const char* fmt, int warn = -1);
144#if defined(ix86_Win) && defined(__GNUC__)
145// utility function of Cygwin32:
146extern "C" int cygwin32_posix_path_list_p (const char *path);
147#endif
148
149/*****************************************************************
150 *
151 * Public functions
152 *
153 *****************************************************************/
154char* feResource(const char* key, int warn)
155{
156  return feResource(feGetResourceConfig(key), warn);
157}
158
159char* feResource(const char id, int warn)
160{
161  return feResource(feGetResourceConfig(id), warn);
162}
163
164char* feGetResource(const char id)
165{
166  return feResource(feGetResourceConfig(id), -1);
167}
168
169char* feResourceDefault(const char id)
170{
171  return feResourceDefault(feGetResourceConfig(id));
172}
173
174char* feResourceDefault(const char* key)
175{
176  return feResourceDefault(feGetResourceConfig(key));
177}
178
179void feInitResources(char* argv0)
180{
181  if (argv0==NULL)
182  {
183    argv0 = program_invocation_name;
184  }
185 
186#if defined(ix86_Win) && defined(__GNUC__)
187  if (cygwin32_posix_path_list_p (getenv("PATH")))
188    fePathSep = ':';
189#endif
190  feArgv0 = omStrDup(argv0);
191#ifdef RESOURCE_DEBUG
192  printf("feInitResources: entering with argv0=%s=\n", argv0);
193#endif
194  // init some Resources
195  feResource('b');
196  feResource('r');
197  // don't complain about stuff when initializing SingularPath
198  feResource('s',0);
199
200#if defined(HAVE_SETENV) || defined(HAVE_PUTENV)
201  char* path = feResource('p');
202#ifdef RESOURCE_DEBUG
203  printf("feInitResources: setting path with argv0=%s=\n", path);
204#endif
205#ifdef HAVE_PUTENV
206  if (path != NULL) { char *s=(char *)omAlloc0(strlen(path)+6);
207                      sprintf(s,"PATH=%s",path);
208                      putenv(s);
209                    }
210#else
211  if (path != NULL) setenv("PATH", path, 1);
212#endif
213#endif
214}
215
216void feReInitResources()
217{
218  int i = 0;
219  while (feResourceConfigs[i].key != NULL)
220  {
221    if (feResourceConfigs[i].value[0] != '\0')
222    {
223      if (feResourceConfigs[i].value != NULL)
224        omFree(feResourceConfigs[i].value);
225      feResourceConfigs[i].value = (char *)"";
226    }
227    i++;
228  }
229#ifdef RESOURCE_DEBUG
230  printf("feInitResources: entering with argv0=%s=\n", feArgv0);
231#endif
232  // init some Resources
233  feResource('b');
234  feResource('r');
235  // don't complain about stuff when initializing SingularPath
236  feResource('s',0);
237}
238
239/*****************************************************************
240 *
241 * Local functions
242 *
243 *****************************************************************/
244static feResourceConfig feGetResourceConfig(const char id)
245{
246  int i = 0;
247  while (feResourceConfigs[i].key != NULL)
248  {
249    if (feResourceConfigs[i].id == id) return &(feResourceConfigs[i]);
250    i++;
251  }
252  return NULL;
253}
254
255static feResourceConfig feGetResourceConfig(const char* key)
256{
257  int i = 0;
258  while (feResourceConfigs[i].key != NULL)
259  {
260    if (strcmp(feResourceConfigs[i].key, key) == 0)
261      return &(feResourceConfigs[i]);
262    i++;
263  }
264  return NULL;
265}
266
267static char* feResource(feResourceConfig config, int warn)
268{
269  if (config == NULL) return NULL;
270  if (config->value != NULL && *(config->value) != '\0') return config->value;
271  return feInitResource(config, warn);
272}
273
274static char* feResourceDefault(feResourceConfig config)
275{
276  if (config == NULL) return NULL;
277  char* value = (char*) omAlloc(MAXRESOURCELEN);
278  feSprintf(value, config->fmt, -1);
279  return value;
280}
281
282static char* feInitResource(feResourceConfig config, int warn)
283{
284  assume(config != NULL);
285#ifdef RESOURCE_DEBUG
286  printf("feInitResource: entering for %s\n", config->key);
287#endif
288
289  char value[MAXRESOURCELEN];
290  // now we have to work
291  // First, check Environment variable
292  if (config->env != NULL)
293  {
294    char* evalue = getenv(config->env);
295    if (evalue != NULL)
296    {
297#ifdef RESOURCE_DEBUG
298      printf("feInitResource: Found value from env:%s\n", evalue);
299#endif
300      strcpy(value, evalue);
301      if (config->type == feResBinary  // do not verify binaries
302          ||
303          feVerifyResourceValue(config->type,
304                                feCleanResourceValue(config->type, value)))
305      {
306#ifdef RESOURCE_DEBUG
307        printf("feInitResource: Set value of %s to =%s=\n", config->key, value);
308#endif
309        config->value = omStrDup(value);
310        return config->value;
311      }
312    }
313  }
314
315  *value = '\0';
316  // Special treatment of executable
317  if (config->id == 'S')
318  {
319    char* executable = feGetExpandedExecutable();
320    if (executable != NULL)
321    {
322#ifdef RESOURCE_DEBUG
323      printf("exec:%s\n", executable);
324#endif
325      strcpy(value, executable);
326#ifdef RESOURCE_DEBUG
327      printf("value:%s\n", value);
328#endif
329      omFree(executable);
330    }
331  }
332  // and bindir
333  else if (config->id == 'b')
334  {
335    char* executable = feResource('S');
336#ifdef RESOURCE_DEBUG
337      printf("feInitResource: Get %s from %s\n", config->key, executable);
338#endif
339    if (executable != NULL)
340    {
341      strcpy(value, executable);
342      executable = strrchr(value, DIR_SEP);
343      if (executable != NULL) *executable = '\0';
344    }
345  }
346
347#ifdef RESOURCE_DEBUG
348  printf("value:%s\n", value);
349#endif
350
351  if (*value == '\0' && config->fmt != NULL )
352  {
353    feSprintf(value, config->fmt, warn);
354  }
355  else if (config->fmt == NULL)
356  {
357    sprintf(value, "Wrong Resource Specification of %s", config->key);
358    dReportBug(value);
359    return NULL;
360  }
361
362  // Clean and verify
363  if (feVerifyResourceValue(config->type,
364                            feCleanResourceValue(config->type, value)))
365  {
366#ifdef RESOURCE_DEBUG
367    printf("feInitResource: Set value of %s to =%s=\n", config->key, value);
368#endif
369    config->value = omStrDup(value);
370    return config->value;
371  }
372  else if (config->type == feResBinary)
373  {
374    // for binaries, search through PATH once more
375    char* executable = omFindExec(config->key, value);
376    if (executable != NULL)
377    {
378      if (feVerifyResourceValue(config->type,
379                                feCleanResourceValue(config->type, value)))
380      {
381        config->value = omStrDup(value);
382#ifdef RESOURCE_DEBUG
383        printf("feInitResource: Set value of %s to =%s=\n", config->key, config->value);
384#endif
385        return config->value;
386      }
387    }
388  }
389
390  // issue warning if explicitely requested, or if
391  // this value is gotten for the first time
392  if (warn > 0 || (warn < 0 && config->value != NULL))
393  {
394    Warn("Could not get %s. ", config->key);
395    Warn("Either set environment variable %s to %s,",
396         config->env, config->key);
397    feSprintf(value, config->fmt, warn);
398    Warn("or make sure that %s is at %s", config->key, value);
399  }
400#ifdef RESOURCE_DEBUG
401      printf("feInitResource: Set value of %s to NULL", config->key);
402#endif
403  config->value = NULL;
404  return NULL;
405}
406
407static char* feGetExpandedExecutable()
408{
409  if (feArgv0 == NULL || *feArgv0 == '\0')
410  {
411    if (feArgv0 == NULL) dReportBug("feArgv0 == NULL");
412    else dReportBug("feArgv0 == ''");
413    return NULL;
414  }
415#ifdef ix86_Win // stupid WINNT sometimes gives you argv[0] within ""
416  if (*feArgv0 == '"')
417  {
418    int l = strlen(feArgv0);
419    if (feArgv0[l-1] == '"')
420    {
421      feArgv0[l-1] = '\0';
422      feArgv0++;
423    }
424  }
425#endif
426#ifdef RESOURCE_DEBUG
427  printf("feGetExpandedExecutable: calling find_exec with =%s=\n", feArgv0);
428#endif
429  char executable[MAXRESOURCELEN];
430  char* value = omFindExec(feArgv0, executable);
431#ifdef RESOURCE_DEBUG
432  printf("feGetExpandedExecutable: find_exec exited with =%s=%d\n", executable, access(executable, X_OK));
433#endif
434  if (value == NULL)
435  {
436    char message[MAXRESOURCELEN];
437    sprintf(message, "Could not get expanded executable from %s", feArgv0);
438    dReportBug(message);
439    return NULL;
440  }
441  return omStrDup(value);
442}
443
444
445static BOOLEAN feVerifyResourceValue(feResourceType type, char* value)
446{
447#ifdef RESOURCE_DEBUG
448  printf("feVerifyResourceValue: entering with =%s=\n", value);
449  printf("%d:%d\n", access(value, R_OK), access(value, X_OK));
450#endif
451  switch(type)
452  {
453      case feResUrl:
454      case feResPath:
455        return TRUE;
456
457      case feResFile:
458        return ! access(value, R_OK);
459
460      case feResBinary:
461      case feResDir:
462        return ! access(value, X_OK);
463
464      default:
465        return FALSE;
466  }
467}
468
469/*****************************************************************
470 *
471 * Cleaning/Transformations of resource values
472 *
473 *****************************************************************/
474
475static char* feCleanResourceValue(feResourceType type, char* value)
476{
477  if (value == NULL || *value == '\0') return value;
478#ifdef RESOURCE_DEBUG
479      printf("Clean value:%s\n", value);
480#endif
481#ifdef ix86_Win
482#ifdef RESOURCE_DEBUG
483      printf("Clean WINNT value:%s\n", value);
484#endif
485  if (type == feResBinary)
486  {
487    int l = strlen(value);
488    if (l < 4 || (strcmp(&value[l-4], ".exe") != 0 &&
489                  strcmp(&value[l-4], ".EXE") != 0))
490      strcat(value, ".exe");
491  }
492#endif
493  if (type == feResFile || type == feResBinary || type == feResDir)
494    return feCleanUpFile(value);
495  if (type == feResPath)
496    return feCleanUpPath(value);
497  return value;
498}
499
500static char* feCleanUpFile(char* fname)
501{
502  char* fn, *s;
503
504#ifdef RESOURCE_DEBUG
505  printf("feCleanUpFile: entering with =%s=\n", fname);
506#endif
507  // Remove unnecessary .. and //
508  for (fn = fname; *fn != '\0'; fn++)
509  {
510    if (*fn == '/')
511    {
512      if (*(fn+1) == '\0')
513      {
514        if (fname != fn) *fn = '\0';
515        break;
516      }
517      if (*(fn + 1) == '/' && (fname != fn))
518      {
519        mystrcpy(fn, fn+1);
520        fn--;
521      }
522      else if (*(fn+1) == '.')
523      {
524        if (*(fn+2) == '.' && (*(fn + 3) == '/' || *(fn + 3) == '\0'))
525        {
526          *fn = '\0';
527          s = strrchr(fname, '/');
528          if (s != NULL)
529          {
530            mystrcpy(s+1, fn + (*(fn + 3) != '\0' ? 4 : 3));
531            fn = s-1;
532          }
533          else
534          {
535            *fn = '/';
536          }
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**) omAlloc(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  omFree(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.