source: git/libpolys/resources/feResource.cc @ 2c52441

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