Modular handling of externals
[delight/core.git] / dmd2 / inifile.c
blob529f8d07e489fb7cd8639efa8e87a1f2513ff32f
2 // Copyright (c) 1999-2006 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
8 #include <stdio.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <ctype.h>
13 #include "root.h"
14 #include "mem.h"
16 #define LOG 0
18 char *skipspace(const char *p);
20 #if __GNUC__
21 char *strupr(char *s)
23 char *t = s;
25 while (*s)
27 *s = toupper(*s);
28 s++;
31 return t;
33 #endif /* unix */
35 /*****************************
36 * Read and analyze .ini file.
37 * Input:
38 * argv0 program name (argv[0])
39 * inifile .ini file name
42 void inifile(char *argv0, char *inifile)
44 char *path; // need path for @P macro
45 char *filename;
46 OutBuffer buf;
47 int i;
48 int k;
49 int envsection = 0;
51 #if LOG
52 printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile);
53 #endif
54 if (FileName::absolute(inifile))
56 filename = inifile;
58 else
60 /* Look for inifile in the following sequence of places:
61 * o current directory
62 * o home directory
63 * o directory off of argv0
64 * o /etc/
66 if (FileName::exists(inifile))
68 filename = inifile;
70 else
72 filename = FileName::combine(getenv("HOME"), inifile);
73 if (!FileName::exists(filename))
75 filename = FileName::replaceName(argv0, inifile);
76 if (!FileName::exists(filename))
78 #if linux
79 #if __GLIBC__ // This fix by Thomas Kuehne
80 /* argv0 might be a symbolic link,
81 * so try again looking past it to the real path
83 char* real_argv0 = realpath(argv0, NULL);
84 //printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0);
85 if (real_argv0)
87 filename = FileName::replaceName(real_argv0, inifile);
88 free(real_argv0);
89 if (FileName::exists(filename))
90 goto Ldone;
92 #else
93 #error use of glibc non-standard extension realpath(char*, NULL)
94 #endif
95 if (1){
96 // Search PATH for argv0
97 const char *p = getenv("PATH");
98 Array *paths = FileName::splitPath(p);
99 filename = FileName::searchPath(paths, argv0, 0);
100 if (!filename)
101 goto Letc; // argv0 not found on path
102 filename = FileName::replaceName(filename, inifile);
103 if (FileName::exists(filename))
104 goto Ldone;
106 #endif
108 // Search /etc/ for inifile
109 Letc:
110 filename = FileName::combine("/etc/", inifile);
112 Ldone:
118 path = FileName::path(filename);
119 #if LOG
120 printf("\tpath = '%s', filename = '%s'\n", path, filename);
121 #endif
123 File file(filename);
125 if (file.read())
126 return; // error reading file
128 // Parse into lines
129 int eof = 0;
130 for (i = 0; i < file.len && !eof; i++)
132 int linestart = i;
134 for (; i < file.len; i++)
136 switch (file.buffer[i])
138 case '\r':
139 break;
141 case '\n':
142 // Skip if it was preceded by '\r'
143 if (i && file.buffer[i - 1] == '\r')
144 goto Lskip;
145 break;
147 case 0:
148 case 0x1A:
149 eof = 1;
150 break;
152 default:
153 continue;
155 break;
158 // The line is file.buffer[linestart..i]
159 char *line;
160 int len;
161 char *p;
162 char *pn;
164 line = (char *)&file.buffer[linestart];
165 len = i - linestart;
167 buf.reset();
169 // First, expand the macros.
170 // Macros are bracketed by % characters.
172 for (k = 0; k < len; k++)
174 if (line[k] == '%')
176 int j;
178 for (j = k + 1; j < len; j++)
180 if (line[j] == '%')
182 if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0)
184 // %@P% is special meaning the path to the .ini file
185 p = path;
186 if (!*p)
187 p = ".";
189 else
190 { int len = j - k;
191 char tmp[10]; // big enough most of the time
193 if (len <= sizeof(tmp))
194 p = tmp;
195 else
196 p = (char *)alloca(len);
197 len--;
198 memcpy(p, &line[k + 1], len);
199 p[len] = 0;
200 strupr(p);
201 p = getenv(p);
202 if (!p)
203 p = "";
205 buf.writestring(p);
206 k = j;
207 goto L1;
211 buf.writeByte(line[k]);
216 // Remove trailing spaces
217 while (buf.offset && isspace(buf.data[buf.offset - 1]))
218 buf.offset--;
220 p = buf.toChars();
222 // The expanded line is in p.
223 // Now parse it for meaning.
225 p = skipspace(p);
226 switch (*p)
228 case ';': // comment
229 case 0: // blank
230 break;
232 case '[': // look for [Environment]
233 p = skipspace(p + 1);
234 for (pn = p; isalnum(*pn); pn++)
236 if (pn - p == 11 &&
237 memicmp(p, "Environment", 11) == 0 &&
238 *skipspace(pn) == ']'
240 envsection = 1;
241 else
242 envsection = 0;
243 break;
245 default:
246 if (envsection)
248 pn = p;
250 // Convert name to upper case;
251 // remove spaces bracketing =
252 for (p = pn; *p; p++)
253 { if (islower(*p))
254 *p &= ~0x20;
255 else if (isspace(*p))
256 memmove(p, p + 1, strlen(p));
257 else if (*p == '=')
259 p++;
260 while (isspace(*p))
261 memmove(p, p + 1, strlen(p));
262 break;
266 putenv(strdup(pn));
267 #if LOG
268 printf("\tputenv('%s')\n", pn);
269 //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
270 #endif
272 break;
275 Lskip:
280 /********************
281 * Skip spaces.
284 char *skipspace(const char *p)
286 while (isspace(*p))
287 p++;
288 return (char *)p;