1
|
1
|
|
2 // Copyright (c) 1999-2006 by Digital Mars
|
|
3 // All Rights Reserved
|
|
4 // written by Walter Bright
|
|
5 // http://www.digitalmars.com
|
|
6
|
|
7
|
|
8 #include <stdio.h>
|
|
9 #include <string.h>
|
|
10 #include <stdlib.h>
|
|
11 #include <ctype.h>
|
|
12
|
|
13 #include "root.h"
|
|
14 #include "mem.h"
|
|
15
|
|
16 #define LOG 0
|
|
17
|
|
18 char *skipspace(const char *p);
|
|
19
|
|
20 #if __GNUC__
|
|
21 char *strupr(char *s)
|
|
22 {
|
|
23 char *t = s;
|
|
24
|
|
25 while (*s)
|
|
26 {
|
|
27 *s = toupper(*s);
|
|
28 s++;
|
|
29 }
|
|
30
|
|
31 return t;
|
|
32 }
|
|
33 #endif /* unix */
|
|
34
|
|
35 /*****************************
|
|
36 * Read and analyze .ini file.
|
|
37 * Input:
|
|
38 * argv0 program name (argv[0])
|
|
39 * inifile .ini file name
|
|
40 */
|
|
41
|
|
42 void inifile(char *argv0, char *inifile)
|
|
43 {
|
|
44 char *path; // need path for @P macro
|
|
45 char *filename;
|
|
46 OutBuffer buf;
|
|
47 int i;
|
|
48 int k;
|
|
49 int envsection = 0;
|
|
50
|
|
51 #if LOG
|
|
52 printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile);
|
|
53 #endif
|
|
54 if (FileName::absolute(inifile))
|
|
55 {
|
|
56 filename = inifile;
|
|
57 }
|
|
58 else
|
|
59 {
|
|
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/
|
|
65 */
|
|
66 if (FileName::exists(inifile))
|
|
67 {
|
|
68 filename = inifile;
|
|
69 }
|
|
70 else
|
|
71 {
|
|
72 filename = FileName::combine(getenv("HOME"), inifile);
|
|
73 if (!FileName::exists(filename))
|
|
74 {
|
|
75 filename = FileName::replaceName(argv0, inifile);
|
|
76 if (!FileName::exists(filename))
|
|
77 {
|
|
78 #if linux
|
|
79 // Search PATH for argv0
|
|
80 const char *p = getenv("PATH");
|
|
81 Array *paths = FileName::splitPath(p);
|
|
82 filename = FileName::searchPath(paths, argv0, 0);
|
|
83 if (!filename)
|
|
84 goto Letc; // argv0 not found on path
|
|
85 filename = FileName::replaceName(filename, inifile);
|
|
86 if (FileName::exists(filename))
|
|
87 goto Ldone;
|
|
88 #endif
|
|
89
|
|
90 // Search /etc/ for inifile
|
|
91 Letc:
|
|
92 filename = FileName::combine("/etc/", inifile);
|
|
93
|
|
94 Ldone:
|
|
95 ;
|
|
96 }
|
|
97 }
|
|
98 }
|
|
99 }
|
|
100 path = FileName::path(filename);
|
|
101 #if LOG
|
|
102 printf("\tpath = '%s', filename = '%s'\n", path, filename);
|
|
103 #endif
|
|
104
|
|
105 File file(filename);
|
|
106
|
|
107 if (file.read())
|
|
108 return; // error reading file
|
|
109
|
|
110 // Parse into lines
|
|
111 int eof = 0;
|
|
112 for (i = 0; i < file.len && !eof; i++)
|
|
113 {
|
|
114 int linestart = i;
|
|
115
|
|
116 for (; i < file.len; i++)
|
|
117 {
|
|
118 switch (file.buffer[i])
|
|
119 {
|
|
120 case '\r':
|
|
121 break;
|
|
122
|
|
123 case '\n':
|
|
124 // Skip if it was preceded by '\r'
|
|
125 if (i && file.buffer[i - 1] == '\r')
|
|
126 goto Lskip;
|
|
127 break;
|
|
128
|
|
129 case 0:
|
|
130 case 0x1A:
|
|
131 eof = 1;
|
|
132 break;
|
|
133
|
|
134 default:
|
|
135 continue;
|
|
136 }
|
|
137 break;
|
|
138 }
|
|
139
|
|
140 // The line is file.buffer[linestart..i]
|
|
141 char *line;
|
|
142 int len;
|
|
143 char *p;
|
|
144 char *pn;
|
|
145
|
|
146 line = (char *)&file.buffer[linestart];
|
|
147 len = i - linestart;
|
|
148
|
|
149 buf.reset();
|
|
150
|
|
151 // First, expand the macros.
|
|
152 // Macros are bracketed by % characters.
|
|
153
|
|
154 for (k = 0; k < len; k++)
|
|
155 {
|
|
156 if (line[k] == '%')
|
|
157 {
|
|
158 int j;
|
|
159
|
|
160 for (j = k + 1; j < len; j++)
|
|
161 {
|
|
162 if (line[j] == '%')
|
|
163 {
|
|
164 if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0)
|
|
165 {
|
|
166 // %@P% is special meaning the path to the .ini file
|
|
167 p = path;
|
|
168 if (!*p)
|
|
169 p = ".";
|
|
170 }
|
|
171 else
|
|
172 { int len = j - k;
|
|
173 char tmp[10]; // big enough most of the time
|
|
174
|
|
175 if (len <= sizeof(tmp))
|
|
176 p = tmp;
|
|
177 else
|
|
178 p = (char *)alloca(len);
|
|
179 len--;
|
|
180 memcpy(p, &line[k + 1], len);
|
|
181 p[len] = 0;
|
|
182 strupr(p);
|
|
183 p = getenv(p);
|
|
184 if (!p)
|
|
185 p = "";
|
|
186 }
|
|
187 buf.writestring(p);
|
|
188 k = j;
|
|
189 goto L1;
|
|
190 }
|
|
191 }
|
|
192 }
|
|
193 buf.writeByte(line[k]);
|
|
194 L1:
|
|
195 ;
|
|
196 }
|
|
197
|
|
198 // Remove trailing spaces
|
|
199 while (buf.offset && isspace(buf.data[buf.offset - 1]))
|
|
200 buf.offset--;
|
|
201
|
|
202 p = buf.toChars();
|
|
203
|
|
204 // The expanded line is in p.
|
|
205 // Now parse it for meaning.
|
|
206
|
|
207 p = skipspace(p);
|
|
208 switch (*p)
|
|
209 {
|
|
210 case ';': // comment
|
|
211 case 0: // blank
|
|
212 break;
|
|
213
|
|
214 case '[': // look for [Environment]
|
|
215 p = skipspace(p + 1);
|
|
216 for (pn = p; isalnum(*pn); pn++)
|
|
217 ;
|
|
218 if (pn - p == 11 &&
|
|
219 memicmp(p, "Environment", 11) == 0 &&
|
|
220 *skipspace(pn) == ']'
|
|
221 )
|
|
222 envsection = 1;
|
|
223 else
|
|
224 envsection = 0;
|
|
225 break;
|
|
226
|
|
227 default:
|
|
228 if (envsection)
|
|
229 {
|
|
230 pn = p;
|
|
231
|
|
232 // Convert name to upper case;
|
|
233 // remove spaces bracketing =
|
|
234 for (p = pn; *p; p++)
|
|
235 { if (islower(*p))
|
|
236 *p &= ~0x20;
|
|
237 else if (isspace(*p))
|
|
238 memmove(p, p + 1, strlen(p));
|
|
239 else if (*p == '=')
|
|
240 {
|
|
241 p++;
|
|
242 while (isspace(*p))
|
|
243 memmove(p, p + 1, strlen(p));
|
|
244 break;
|
|
245 }
|
|
246 }
|
|
247
|
|
248 putenv(strdup(pn));
|
|
249 #if LOG
|
|
250 printf("\tputenv('%s')\n", pn);
|
|
251 //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
|
|
252 #endif
|
|
253 }
|
|
254 break;
|
|
255 }
|
|
256
|
|
257 Lskip:
|
|
258 ;
|
|
259 }
|
|
260 }
|
|
261
|
|
262 /********************
|
|
263 * Skip spaces.
|
|
264 */
|
|
265
|
|
266 char *skipspace(const char *p)
|
|
267 {
|
|
268 while (isspace(*p))
|
|
269 p++;
|
|
270 return (char *)p;
|
|
271 }
|
|
272
|