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

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