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 <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