www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1999/03/22/12:00:09

To: djgpp-workers AT delorie DOT com
Subject: Support for program specific environment files
From: Michael Bukin <M DOT A DOT Bukin AT inp DOT nsk DOT su>
Date: 22 Mar 1999 22:00:48 +0600
In-Reply-To: DJ Delorie's message of "Sun, 21 Mar 1999 10:41:48 -0500"
Message-ID: <20emmho6of.fsf_-_@Sky.inp.nsk.su>
Lines: 314
X-Mailer: Gnus v5.5/Emacs 19.34
Reply-To: djgpp-workers AT delorie DOT com

DJ Delorie <dj AT delorie DOT com> writes:

> > 3.  This is not a problem, but just an idea.  How feasible is it to
> > add support for per program env file.  Then each package can be
> 
> Pretty easy, I think.  After parsing djgpp.env, use some variable
> (DJENV?) to load a second file.  You know the name of the program, as
> djgpp.env uses it already.
> 
> Go ahead and try it.

I reworked src/libc/crt0/c1loadef.c and added support for program
specific environment files.  Startup code will try to load $DJGPP
first, then $DJDIR/env/program.env, then $DJENV/program.env and
then ./program.env.  IMHO, all of these files are pretty useful, the
first one is useful for standard DJGPP installation, second one is for
flexibility (to be able to place env. files in arbitrary directory),
and last one for playing with package when it is not installed yet.

For large packages with a lot of programs that need similar
env. vars. it can be useful to have env. files which are loaded for
a class of programs, not just based on program's name.  But after
thinking about it, I have a feeling that problems with proper
implementation will outweight its usefulness (i.e. it would be simpler
just to copy one file for all programs in the package or just suggest
to add necessary variables in environment).

Below are two diffs and one new file.  And I have not updated libc
reference for __crt0_load_env_file yet.


--- old/src/libc/crt0/c1loadef.c	Fri Jul 26 00:50:56 1996
+++ new/src/libc/crt0/c1loadef.c	Mon Mar 22 20:56:48 1999
@@ -10,28 +10,35 @@
 #include <ctype.h>
 #include <unistd.h>
 
-void
-__crt0_load_environment_file(char *app_name)
+#define ENV_DIRECTORY "env"
+#define ENV_EXTENSION ".env"
+
+static void
+__load_environment_file(char *file_env, char *app_name)
 {
-  int djgpp_env;
-  char *djgpp_var = getenv("DJGPP");
+  int fd = _open(file_env, O_RDONLY);
+  char *file = 0;
 
-  if (djgpp_var)
+  if (fd >= 0)
   {
-    djgpp_env = _open(djgpp_var, O_RDONLY);
-    if (djgpp_env >= 0)
+    do
     {
-      char *file;
       char base[PATH_MAX], *bp, *a0p, *tb;
       int this_prog = 1;
-      int fsize = lseek(djgpp_env, 0L, SEEK_END);
+      int fsize = lseek(fd, 0L, SEEK_END);
+
+      if (fsize < 0)
+	break;
 
       file = (char *)malloc(fsize+2);
       if (file == 0)
-	return;
-      lseek(djgpp_env, 0L, 0);
-      _read(djgpp_env, file, fsize);
-      _close(djgpp_env);
+	break;
+
+      lseek(fd, 0L, 0);
+      fsize = _read(fd, file, fsize);
+      if (fsize <= 0)
+	break;
+
       if (file[fsize-1] == '\n')
       {
 	file[fsize] = 0;
@@ -45,9 +52,6 @@
 
       base[0] = '[';
       bp = app_name;
-      for (a0p = bp; *a0p; a0p++)
-	if (strchr("\\/:", *a0p))
-	  bp = a0p+1;
       for (a0p=base+1; *bp && *bp != '.';)
 	*a0p++ = tolower(*bp++);
       *a0p++ = ']';
@@ -160,7 +164,156 @@
 	  }
 	}
       }
-      free(file);
     }
+    while (0);
+  }
+
+  if (file)
+    free(file);
+  if (fd >= 0)
+    _close(fd);
+}
+
+static char*
+safe_string_append (char *to, const char *from, int size)
+{
+  char *d;
+  const char *dend = to + size - 1;
+
+  for (d = to; *d; d++)
+    ;
+  if (d < dend)
+  {
+    const char *s;
+    for (s = from; (d < dend) && *s;)
+      *d++ = *s++;
+    *d = 0;
   }
+
+  return to;
+}
+
+static char*
+__find_basename (char *path)
+{
+  char *p;
+  char *base = path;
+
+  for (p = base; *p; p++)
+    if (strchr ("\\/:", *p))
+      base = p + 1;
+
+  return base;
+}
+
+static char*
+__find_extension (char *path)
+{
+  char *p;
+  char *ext = path + strlen (path);
+
+  for (p = ext - 1; p > path; p--)
+  {
+    if (*p == '.')
+    {
+      ext = p;
+      break;
+    }
+    else if (strchr ("\\/:", *p))
+      break;
+  }
+
+  return ext;
+}
+
+static void
+__append_filename (char *path, char *name, int size)
+{
+  int len = strlen (path);
+
+  if ((len > 0) && (path[len - 1] != '\\') && (path[len - 1] != '/'))
+    safe_string_append (path, "/", size);
+  safe_string_append (path, name, size);
+}
+
+#if 0
+static void
+__replace_filename (char *path, char *name, int size)
+{
+  *(__find_basename (path)) = 0;
+  safe_string_append (path, name, size);
+}
+#endif
+
+static void
+__replace_extension (char *path, char *ext, int size)
+{
+  *(__find_extension (path)) = 0;
+  safe_string_append (path, ext, size);
+}
+
+void
+__crt0_load_environment_file(char *app_name)
+{
+  char *env_var = getenv ("DJGPP");
+  char *app_basename = __find_basename (app_name);
+
+  if (env_var)
+  {
+    /* Load primary env. file (DJGPP.ENV).  */
+    __load_environment_file (env_var, app_basename);
+  }
+
+  if (*app_basename)
+  {
+    /* Load program specific env. files.  */
+    char sec_env[PATH_MAX];
+
+    env_var = getenv ("DJDIR");
+    if (env_var)
+    {
+      /* Try $DJDIR/env/app_basename.env  */
+      sec_env[0] = 0;
+      safe_string_append (sec_env, env_var, sizeof (sec_env));
+      __append_filename (sec_env, ENV_DIRECTORY, sizeof (sec_env));
+      __append_filename (sec_env, app_basename, sizeof (sec_env));
+      __replace_extension (sec_env, ENV_EXTENSION, sizeof (sec_env));
+      __load_environment_file (sec_env, app_basename);
+    }
+
+    env_var = getenv ("DJENV");
+    if (env_var)
+    {
+      /* Try $DJENV/app_basename.env  */
+      sec_env[0] = 0;
+      safe_string_append (sec_env, env_var, sizeof (sec_env));
+      __append_filename (sec_env, app_basename, sizeof (sec_env));
+      __replace_extension (sec_env, ENV_EXTENSION, sizeof (sec_env));
+      __load_environment_file (sec_env, app_basename);
+    }
+
+    /* Try app_name.env  */
+    sec_env[0] = 0;
+    safe_string_append (sec_env, app_name, sizeof (sec_env));
+    __replace_extension (sec_env, ENV_EXTENSION, sizeof (sec_env));
+    __load_environment_file (sec_env, app_basename);
+  }
+}
+
+#ifdef TEST
+#include <stdio.h>
+int
+main (void)
+{
+  char *p;
+
+  p = getenv ("T1");
+  printf ("env. var. T1 %s%s\n", (p ? "contains " : "undefined"), (p ? p : ""));
+  p = getenv ("T2");
+  printf ("env. var. T2 %s%s\n", (p ? "contains " : "undefined"), (p ? p : ""));
+  p = getenv ("T3");
+  printf ("env. var. T3 %s%s\n", (p ? "contains " : "undefined"), (p ? p : ""));
+
+  return 0;
 }
+#endif


--- old/src/docs/kb/hidden.txi	Sat Apr 27 21:39:08 1996
+++ new/src/docs/kb/hidden.txi	Mon Mar 22 20:19:14 1999
@@ -3,6 +3,8 @@
 
 @menu
 * DJGPP.ENV::	All about the format of the DJGPP.ENV file
+* otherenv::	Program specific environment files
 @end menu
 
 @include djgppenv.txi
+@include otherenv.txi


*** beginning of src/docs/kb/otherenv.txi ***
@node otherenv, , , Hidden Features
@section Program specific environment files

@cindex Program Specific Environment Files
@cindex More Environment Variables

Environment variables are loaded from several environment files.
Program tries to load environment variables from file pointed to by
DJGPP environment variable (@pxref{DJGPP.ENV}) and then from environment
files named after program name.  Name of these program specific
environment files is made by getting basename of the program and
replacing extension with `.env', in short

@example
env_file_name=`basename "$0" | sed 's,^\([^.]*\).*,\1.env,'`
@end example

If program basename is not empty, then startup code will try to load
program specific environment files from all of the following directories

@enumerate
@item
If DJDIR environment variable points to a directory, then startup code
will try to load program specific environment file from `env'
subdirectory in that directory.

Note that DJDIR environment variable is automatically set by djgpp.env
file distributed with DJGPP, so programs can just place their specific
environment files in the `env' subdirectory of main djgpp directory.

@item
If you set DJENV environment variable to point to a directory, startup
code will try to load program specific environment file from that
directory.

@item
At last, startup will try to load program specific environment file from
the same directory where program is located.
@end enumerate

All program specific files are parsed in the same way as DJGPP.ENV
file, i.e. first section (before any [program] lines) apply to that
program and variables in program specific sections are loaded only when
section name matches lowercased program's basename without extension.
*** end of src/docs/kb/otherenv.txi ***

-- 
Michael Bukin

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019