dwbinit.c - 9base - revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log
Files
Refs
README
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 
    77 #include 
    78 #include 
    79 #include 
    80 #include 
    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