To: djgpp-workers AT delorie DOT com Subject: Support for program specific environment files From: Michael Bukin 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 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 #include -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 +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