source: git/libpolys/resources/feResource.cc @ 76388e

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