URI: 
       dwbinit.c - 9base - revived minimalist port of Plan 9 userland to Unix
  HTML git clone git://git.suckless.org/9base
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       dwbinit.c (9219B)
       ---
            1 /*
            2  *
            3  * Pathname management routines for DWB C programs.
            4  *
            5  * Applications should initialize a dwbinit array with the string
            6  * pointers and arrays that need to be updated, and then hand that
            7  * array to DWBinit before much else happens in their main program.
            8  * DWBinit calls DWBhome to get the current home directory. DWBhome
            9  * uses the last definition of DWBENV (usually "DWBHOME") in file
           10  * DWBCONFIG (e.g., /usr/lib/dwb3.4) or the value assigned to that
           11  * variable in the environment if the DWBCONFIG file doesn't exist,
           12  * can't be read, or doesn't define DWBENV.
           13  *
           14  * DWBCONFIG must be a simple shell script - comments, a definition
           15  * of DWBHOME, and perhaps an export or echo is about all that's
           16  * allowed. The parsing in DWBhome is simple and makes no attempt
           17  * to duplicate the shell. It only looks for DWBHOME= as the first
           18  * non-white space string on a line, so
           19  *
           20  *        #
           21  *        # A sample DWBCONFIG shell script
           22  *        #
           23  *
           24  *        DWBHOME=/usr/add-on/dwb3.4
           25  *        export DWBHOME
           26  *
           27  * means DWBhome would return "/usr/add-on/dwb3.4" for the DWB home
           28  * directory. A DWBCONFIG file means there can only be one working
           29  * copy of a DWB release on a system, which seems like a good idea.
           30  * Using DWBCONFIG also means programs will always include correct
           31  * versions of files (e.g., prologues or macro packages).
           32  *
           33  * Relying on an environment variable guarantees nothing. You could
           34  * execute a version of dpost, but your environment might point at
           35  * incorrect font tables or prologues. Despite the obvious problems
           36  * we've also implemented an environment variable approach, but it's
           37  * only used if there's no DWBCONFIG file.
           38  *
           39  * DWBinit calls DWBhome to get the DWB home directory prefix and
           40  * then marches through its dwbinit argument, removing the default
           41  * home directory and prepending the new home. DWBinit stops when
           42  * it reaches an element that has NULL for its address and value
           43  * fields. Pointers in a dwbinit array are reallocated and properly
           44  * initialized; arrays are simply reinitialized if there's room.
           45  * All pathnames that are to be adjusted should be relative. For
           46  * example,
           47  *
           48  *        char        *fontdir = "lib/font";
           49  *        char        xyzzy[25] = "etc/xyzzy";
           50  *
           51  * would be represented in a dwbinit array as,
           52  *
           53  *        dwbinit allpaths[] = {
           54  *                &fontdir, NULL, 0,
           55  *                NULL, xyzzy, sizeof(xyzzy),
           56  *                NULL, NULL, 0
           57  *        };
           58  *                
           59  * The last element must have NULL entries for the address and
           60  * value fields. The main() routine would then do,
           61  *
           62  *        #include "dwbinit.h"
           63  *
           64  *        main() {
           65  *
           66  *                DWBinit("program name", allpaths);
           67  *                ...
           68  *        }
           69  *
           70  * Debugging is enabled if DWBDEBUG is in the environment and has
           71  * the value ON. Output is occasionally useful and probably should
           72  * be documented.
           73  *
           74  */
           75 
           76 #include <u.h>
           77 #include <stdio.h>
           78 #include <ctype.h>
           79 #include <string.h>
           80 #include <stdlib.h>
           81 
           82 #include "dwbinit.h"
           83 
           84 #ifndef DWBCONFIG
           85 #define DWBCONFIG        "/dev/null"
           86 #endif
           87 
           88 #ifndef DWBENV
           89 #define DWBENV                "DWBHOME"
           90 #endif
           91 
           92 #ifndef DWBHOME
           93 #define DWBHOME                ""
           94 #endif
           95 
           96 #ifndef DWBDEBUG
           97 #define DWBDEBUG        "DWBDEBUG"
           98 #endif
           99 
          100 #ifndef DWBPREFIX
          101 #define DWBPREFIX        "\\*(.P"
          102 #endif
          103 
          104 /*****************************************************************************/
          105 
          106 void DWBdebug(dwbinit *ptr, int level)
          107 {
          108 
          109     char        *path;
          110     char        *home;
          111     static char        *debug = NULL;
          112 
          113 /*
          114  *
          115  * Debugging output, but only if DWBDEBUG is defined to be ON in the
          116  * environment. Dumps general info the first time through.
          117  *
          118  */
          119 
          120     if ( debug == NULL && (debug = getenv(DWBDEBUG)) == NULL )
          121         debug = "OFF";
          122 
          123     if ( strcmp(debug, "ON") == 0 ) {
          124         if ( level == 0 ) {
          125             fprintf(stderr, "Environment variable: %s\n", DWBENV);
          126             fprintf(stderr, "Configuration file: %s\n", DWBCONFIG);
          127             fprintf(stderr, "Default home: %s\n", DWBHOME);
          128             if ( (home = DWBhome()) != NULL )
          129                 fprintf(stderr, "Current home: %s\n", home);
          130         }   /* End if */
          131 
          132         fprintf(stderr, "\n%s pathnames:\n", level == 0 ? "Original" : "Final");
          133         for ( ; ptr->value != NULL || ptr->address != NULL; ptr++ ) {
          134             if ( (path = ptr->value) == NULL ) {
          135                 path = *ptr->address;
          136                 fprintf(stderr, " pointer: %s\n", path);
          137             } else fprintf(stderr, " array[%d]: %s\n", ptr->length, path);
          138             if ( level == 0 && *path == '/' )
          139                 fprintf(stderr, "  WARNING - absolute path\n");
          140         }   /* End for */
          141     }        /* End if */
          142 
          143 }   /* End of DWBdebug */
          144 
          145 /*****************************************************************************/
          146 
          147 extern        char        *unsharp(char*);
          148 
          149 char *DWBhome(void)
          150 {
          151 
          152     FILE        *fp;
          153     char        *ptr;
          154     char        *path;
          155     int                len;
          156     char        buf[200];
          157     char        *home = NULL;
          158 
          159 /*
          160  *
          161  * Return the DWB home directory. Uses the last definition of DWBENV
          162  * (usually "DWBHOME") in file DWBCONFIG (perhaps /usr/lib/dwb3.4) or
          163  * the value assigned to the variable named by the DWBENV string in
          164  * the environment if DWBCONFIG doesn't exist or doesn't define DWBENV.
          165  * Skips the file lookup if DWBCONFIG can't be read. Returns NULL if
          166  * there's no home directory.
          167  *
          168  */
          169 
          170     if ( (fp = fopen(DWBCONFIG, "r")) != NULL ) {
          171         len = strlen(DWBENV);
          172         while ( fgets(buf, sizeof(buf), fp) != NULL ) {
          173             for ( ptr = buf; isspace((uchar)*ptr); ptr++ ) ;
          174             if ( strncmp(ptr, DWBENV, len) == 0 && *(ptr+len) == '=' ) {
          175                 path = ptr + len + 1;
          176                 for ( ptr = path; !isspace((uchar)*ptr) && *ptr != ';'; ptr++ ) ;
          177                 *ptr = '\0';
          178                 if ( home != NULL )
          179                     free(home);
          180                 if ( (home = malloc(strlen(path)+1)) != NULL )
          181                     strcpy(home, path);
          182             }        /* End if */
          183         }   /* End while */
          184         fclose(fp);
          185     }   /* End if */
          186 
          187     if ( home == NULL ) {
          188         if ( (home = getenv(DWBENV)) == NULL ) {
          189             if ( (home = DWBHOME) == NULL || *home == '\0' || *home == ' ' )
          190                 home = NULL;
          191         }   /* End if */
          192         if ( home != NULL )
          193                 home = unsharp(home);
          194     }        /* End if */
          195 
          196     while (home && *home == '/' && *(home +1) == '/')        /* remove extra slashes */
          197         home++;
          198     return(home);
          199 
          200 }   /* End of DWBhome */
          201 
          202 /*****************************************************************************/
          203 
          204 void DWBinit(char *prog, dwbinit *paths)
          205 {
          206 
          207     char        *prefix;
          208     char        *value;
          209     char        *path;
          210     int                plen;
          211     int                length;
          212     dwbinit        *opaths = paths;
          213 
          214 /*
          215  *
          216  * Adjust the pathnames listed in paths, using the home directory
          217  * returned by DWBhome(). Stops when it reaches an element that has
          218  * NULL address and value fields. Assumes pathnames are relative,
          219  * but changes everything. DWBdebug issues a warning if an original
          220  * path begins with a /.
          221  *
          222  * A non-NULL address refers to a pointer, which is reallocated and
          223  * then reinitialized. A NULL address implies a non-NULL value field
          224  * and describes a character array that we only reinitialize. The
          225  * length field for an array is the size of that array. The length
          226  * field of a pointer is an increment that's added to the length
          227  * required to store the new pathname string - should help when we
          228  * want to change character arrays to pointers in applications like
          229  * troff.
          230  *
          231  */
          232 
          233     if ( (prefix = DWBhome()) == NULL ) {
          234         fprintf(stderr, "%s: no DWB home directory\n", prog);
          235         exit(1);
          236     }        /* End if */
          237 
          238     DWBdebug(opaths, 0);
          239     plen = strlen(prefix);
          240 
          241     for ( ; paths->value != NULL || paths->address != NULL; paths++ ) {
          242         if ( paths->address == NULL ) {
          243             length = 0;
          244             value = paths->value;
          245         } else {
          246             length = paths->length;
          247             value = *paths->address;
          248         }   /* End else */
          249 
          250         length += plen + 1 + strlen(value);        /* +1 is for the '/' */
          251 
          252         if ( (path = malloc(length+1)) == NULL ) {
          253             fprintf(stderr, "%s: can't allocate pathname memory\n", prog);
          254             exit(1);
          255         }   /* End if */
          256 
          257         if ( *value != '\0' ) {
          258             char *eop = prefix;
          259             while(*eop++)
          260                 ;
          261             eop -= 2;
          262             if (*value != '/' && *eop != '/') {
          263                 sprintf(path, "%s/%s", prefix, value);
          264             } else if (*value == '/' && *eop == '/') {
          265                 value++;
          266                 sprintf(path, "%s%s", prefix, value);
          267             } else
          268                 sprintf(path, "%s%s", prefix, value);
          269         } else
          270                 sprintf(path, "%s", prefix);
          271 
          272         if ( paths->address == NULL ) {
          273             if ( strlen(path) >= paths->length ) {
          274                 fprintf(stderr, "%s: no room for %s\n", prog, path);
          275                 exit(1);
          276             }        /* End if */
          277             strcpy(paths->value, path);
          278             free(path);
          279         } else *paths->address = path;
          280     }        /* End for */
          281 
          282     DWBdebug(opaths, 1);
          283 
          284 }   /* End of DWBinit */
          285 
          286 /*****************************************************************************/
          287 
          288 void DWBprefix( char *prog, char *path, int length)
          289 {
          290 
          291     char        *home;
          292     char        buf[512];
          293     int                len = strlen(DWBPREFIX);
          294 
          295 /*
          296  *
          297  * Replace a leading DWBPREFIX string in path by the current DWBhome().
          298  * Used by programs that pretend to handle .so requests. Assumes path
          299  * is an array with room for length characters. The implementation is
          300  * not great, but should be good enough for now. Also probably should
          301  * have DWBhome() only do the lookup once, and remember the value if
          302  * called again.
          303  * 
          304  */
          305 
          306     if ( strncmp(path, DWBPREFIX, len) == 0 ) {
          307         if ( (home = DWBhome()) != NULL ) {
          308             if ( strlen(home) + strlen(path+len) < length ) {
          309                 sprintf(buf, "%s%s", home, path+len);
          310                 strcpy(path, buf);                /* assuming there's room in path */
          311             } else fprintf(stderr, "%s: no room to grow path %s", prog, path);
          312         }   /* End if */
          313     }        /* End if */
          314 
          315 }   /* End of DWBprefix */
          316 
          317 /*****************************************************************************/
          318