root/trunk/src/inifile.c

Revision 428, 9.0 kB (checked in by walter, 2 years ago)

remove tabs, any trailing spaces

  • Property svn:eol-style set to native
Line 
1 /*
2  * Some portions copyright (c) 1994-1995 by Symantec
3  * Copyright (c) 1999-2009 by Digital Mars
4  * All Rights Reserved
5  * http://www.digitalmars.com
6  * Written by Walter Bright
7  *
8  * This source file is made available for personal use
9  * only. The license is in /dmd/src/dmd/backendlicense.txt
10  * For any other uses, please contact Digital Mars.
11  */
12
13 #include        <stdio.h>
14 #include        <string.h>
15 #include        <stdlib.h>
16 #include        <ctype.h>
17
18 #if _WIN32
19 #include <windows.h>
20 #endif
21
22 #if __APPLE__
23 #include        <sys/syslimits.h>
24 #endif
25
26 #if __FreeBSD__ || __sun&&__SVR4
27 // for PATH_MAX
28 #include        <limits.h>
29 #endif
30
31 #if __sun&&__SVR4
32 #include        <alloca.h>
33 #endif
34
35 #include        "root.h"
36 #include        "rmem.h"
37
38 #define LOG     0
39
40 char *skipspace(const char *p);
41
42 #if __GNUC__
43 char *strupr(char *s)
44 {
45     char *t = s;
46
47     while (*s)
48     {
49         *s = toupper(*s);
50         s++;
51     }
52
53     return t;
54 }
55 #endif
56
57 /*****************************
58  * Read and analyze .ini file.
59  * Input:
60  *      argv0   program name (argv[0])
61  *      inifile .ini file name
62  * Returns:
63  *      file name of ini file
64  *      Note: this is a memory leak
65  */
66
67 const char *inifile(const char *argv0x, const char *inifilex)
68 {
69     char *argv0 = (char *)argv0x;
70     char *inifile = (char *)inifilex;   // do const-correct later
71     char *path;         // need path for @P macro
72     char *filename;
73     OutBuffer buf;
74     int i;
75     int k;
76     int envsection = 0;
77
78 #if LOG
79     printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile);
80 #endif
81     if (FileName::absolute(inifile))
82     {
83         filename = inifile;
84     }
85     else
86     {
87         /* Look for inifile in the following sequence of places:
88          *      o current directory
89          *      o home directory
90          *      o directory off of argv0
91          *      o /etc/
92          */
93         if (FileName::exists(inifile))
94         {
95             filename = inifile;
96         }
97         else
98         {
99             filename = FileName::combine(getenv("HOME"), inifile);
100             if (!FileName::exists(filename))
101             {
102 #if _WIN32 // This fix by Tim Matthews
103                 char resolved_name[MAX_PATH + 1];
104                 if(GetModuleFileName(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name))
105                 {
106                         filename = (char *)FileName::replaceName(resolved_name, inifile);
107                         if(FileName::exists(filename))
108                                 goto Ldone;
109                 }
110 #endif
111                 filename = (char *)FileName::replaceName(argv0, inifile);
112                 if (!FileName::exists(filename))
113                 {
114 #if linux || __APPLE__ || __FreeBSD__ || __sun&&__SVR4
115 #if __GLIBC__ || __APPLE__ || __FreeBSD__ || __sun&&__SVR4   // This fix by Thomas Kuehne
116                     /* argv0 might be a symbolic link,
117                      * so try again looking past it to the real path
118                      */
119 #if __APPLE__ || __FreeBSD__ || __sun&&__SVR4
120                     char resolved_name[PATH_MAX + 1];
121                     char* real_argv0 = realpath(argv0, resolved_name);
122 #else
123                     char* real_argv0 = realpath(argv0, NULL);
124 #endif
125                     //printf("argv0 = %s, real_argv0 = %p\n", argv0, real_argv0);
126                     if (real_argv0)
127                     {
128                         filename = (char *)FileName::replaceName(real_argv0, inifile);
129 #if linux
130                         free(real_argv0);
131 #endif
132                         if (FileName::exists(filename))
133                             goto Ldone;
134                     }
135 #else
136 #error use of glibc non-standard extension realpath(char*, NULL)
137 #endif
138                     if (1){
139                     // Search PATH for argv0
140                     const char *p = getenv("PATH");
141 #if LOG
142                     printf("\tPATH='%s'\n", p);
143 #endif
144                     Array *paths = FileName::splitPath(p);
145                     filename = FileName::searchPath(paths, argv0, 0);
146                     if (!filename)
147                         goto Letc;              // argv0 not found on path
148                     filename = (char *)FileName::replaceName(filename, inifile);
149                     if (FileName::exists(filename))
150                         goto Ldone;
151                     }
152 #endif
153
154                     // Search /etc/ for inifile
155                 Letc:
156                     filename = FileName::combine((char *)"/etc/", inifile);
157
158                 Ldone:
159                     ;
160                 }
161             }
162         }
163     }
164     path = FileName::path(filename);
165 #if LOG
166     printf("\tpath = '%s', filename = '%s'\n", path, filename);
167 #endif
168
169     File file(filename);
170
171     if (file.read())
172         return filename;                        // error reading file
173
174     // Parse into lines
175     int eof = 0;
176     for (i = 0; i < file.len && !eof; i++)
177     {
178         int linestart = i;
179
180         for (; i < file.len; i++)
181         {
182             switch (file.buffer[i])
183             {
184                 case '\r':
185                     break;
186
187                 case '\n':
188                     // Skip if it was preceded by '\r'
189                     if (i && file.buffer[i - 1] == '\r')
190                         goto Lskip;
191                     break;
192
193                 case 0:
194                 case 0x1A:
195                     eof = 1;
196                     break;
197
198                 default:
199                     continue;
200             }
201             break;
202         }
203
204         // The line is file.buffer[linestart..i]
205         char *line;
206         int len;
207         char *p;
208         char *pn;
209
210         line = (char *)&file.buffer[linestart];
211         len = i - linestart;
212
213         buf.reset();
214
215         // First, expand the macros.
216         // Macros are bracketed by % characters.
217
218         for (k = 0; k < len; k++)
219         {
220             if (line[k] == '%')
221             {
222                 int j;
223
224                 for (j = k + 1; j < len; j++)
225                 {
226                     if (line[j] == '%')
227                     {
228                         if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0)
229                         {
230                             // %@P% is special meaning the path to the .ini file
231                             p = path;
232                             if (!*p)
233                                 p = (char *)".";
234                         }
235                         else
236                         {   int len = j - k;
237                             char tmp[10];       // big enough most of the time
238
239                             if (len <= sizeof(tmp))
240                                 p = tmp;
241                             else
242                                 p = (char *)alloca(len);
243                             len--;
244                             memcpy(p, &line[k + 1], len);
245                             p[len] = 0;
246                             strupr(p);
247                             p = getenv(p);
248                             if (!p)
249                                 p = (char *)"";
250                         }
251                         buf.writestring(p);
252                         k = j;
253                         goto L1;
254                     }
255                 }
256             }
257             buf.writeByte(line[k]);
258          L1:
259             ;
260         }
261
262         // Remove trailing spaces
263         while (buf.offset && isspace(buf.data[buf.offset - 1]))
264             buf.offset--;
265
266         p = buf.toChars();
267
268         // The expanded line is in p.
269         // Now parse it for meaning.
270
271         p = skipspace(p);
272         switch (*p)
273         {
274             case ';':           // comment
275             case 0:             // blank
276                 break;
277
278             case '[':           // look for [Environment]
279                 p = skipspace(p + 1);
280                 for (pn = p; isalnum(*pn); pn++)
281                     ;
282                 if (pn - p == 11 &&
283                     memicmp(p, "Environment", 11) == 0 &&
284                     *skipspace(pn) == ']'
285                    )
286                     envsection = 1;
287                 else
288                     envsection = 0;
289                 break;
290
291             default:
292                 if (envsection)
293                 {
294                     pn = p;
295
296                     // Convert name to upper case;
297                     // remove spaces bracketing =
298                     for (p = pn; *p; p++)
299                     {   if (islower(*p))
300                             *p &= ~0x20;
301                         else if (isspace(*p))
302                             memmove(p, p + 1, strlen(p));
303                         else if (*p == '=')
304                         {
305                             p++;
306                             while (isspace(*p))
307                                 memmove(p, p + 1, strlen(p));
308                             break;
309                         }
310                     }
311
312                     putenv(strdup(pn));
313 #if LOG
314                     printf("\tputenv('%s')\n", pn);
315                     //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
316 #endif
317                 }
318                 break;
319         }
320
321      Lskip:
322         ;
323     }
324     return filename;
325 }
326
327 /********************
328  * Skip spaces.
329  */
330
331 char *skipspace(const char *p)
332 {
333     while (isspace(*p))
334         p++;
335     return (char *)p;
336 }
Note: See TracBrowser for help on using the browser.