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