1: /*
2: * Some portions copyright (c) 1994-1995 by Symantec
3: * Copyright (c) 1999-2011 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__ || __OpenBSD__ || __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);
warning C4996: 'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h(433) : see declaration of 'getenv'
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__ || __OpenBSD__ || __sun&&__SVR4
115: #if __GLIBC__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __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__ || __OpenBSD__ || __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: Strings *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:
warning C4102: 'Letc' : unreferenced label
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++)
warning C4018: '<' : signed/unsigned mismatch
177: {
178: int linestart = i;
179:
180: for (; i < file.len; i++)
warning C4018: '<' : signed/unsigned mismatch
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)
warning C4996: 'memicmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _memicmp. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(93) : see declaration of 'memicmp'
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;
warning C6246: Local declaration of 'len' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '206' of 'c:\projects\extern\d\dmd\src\inifile.c': Lines: 206
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);
warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead
warning C6263: Using _alloca in a loop: this can quickly overflow stack: Lines: 224
243: len--;
244: memcpy(p, &line[k + 1], len);
245: p[len] = 0;
246: strupr(p);
warning C4996: 'strupr': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _strupr. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(252) : see declaration of 'strupr'
247: p = getenv(p);
warning C4996: 'getenv': This function or variable may be unsafe. Consider using _dupenv_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h(433) : see declaration of 'getenv'
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++)
warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'isalnum'
281: ;
282: if (pn - p == 11 &&
283: memicmp(p, "Environment", 11) == 0 &&
284: *skipspace(pn) == ']'
285: )
warning C4996: 'memicmp': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _memicmp. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h(93) : see declaration of 'memicmp'
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))
warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'islower'
300: *p &= ~0x20;
301: else if (isspace(*p))
warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'isspace'
302: memmove(p, p + 1, strlen(p));
303: else if (*p == '=')
304: {
305: p++;
306: while (isspace(*p))
warning C6328: 'char' passed as parameter '1' when 'unsigned char' is required in call to 'isspace'
307: memmove(p, p + 1, strlen(p));
308: break;
309: }
310: }
311:
312: putenv(strdup(pn));
warning C4996: 'putenv': The POSIX name for this item is deprecated. Instead, use the ISO C++ conformant name: _putenv. See online help for details.
c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h(869) : see declaration of 'putenv'
warning C6031: Return value ignored: 'putenv'
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))
warning C6328: 'const char' passed as parameter '1' when 'unsigned char' is required in call to 'isspace'
334: p++;
335: return (char *)p;
336: }
337:
338: