source: git/libpolys/resources/feResource.cc @ eb2d25

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