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

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