diff dmd/inifile.c @ 1:c53b6e3fe49a trunk

[svn r5] Initial commit. Most things are very rough.
author lindquist
date Sat, 01 Sep 2007 21:43:27 +0200
parents
children 3cfcb944304e
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/inifile.c	Sat Sep 01 21:43:27 2007 +0200
@@ -0,0 +1,272 @@
+
+// Copyright (c) 1999-2006 by Digital Mars
+// All Rights Reserved
+// written by Walter Bright
+// http://www.digitalmars.com
+
+
+#include	<stdio.h>
+#include	<string.h>
+#include	<stdlib.h>
+#include	<ctype.h>
+
+#include	"root.h"
+#include	"mem.h"
+
+#define LOG	0
+
+char *skipspace(const char *p);
+
+#if __GNUC__
+char *strupr(char *s)
+{
+    char *t = s;
+    
+    while (*s)
+    {
+	*s = toupper(*s);
+	s++;
+    }
+
+    return t;
+}
+#endif /* unix */
+
+/*****************************
+ * Read and analyze .ini file.
+ * Input:
+ *	argv0	program name (argv[0])
+ *	inifile	.ini file name
+ */
+
+void inifile(char *argv0, char *inifile)
+{
+    char *path;		// need path for @P macro
+    char *filename;
+    OutBuffer buf;
+    int i;
+    int k;
+    int envsection = 0;
+
+#if LOG
+    printf("inifile(argv0 = '%s', inifile = '%s')\n", argv0, inifile);
+#endif
+    if (FileName::absolute(inifile))
+    {
+	filename = inifile;
+    }
+    else
+    {
+	/* Look for inifile in the following sequence of places:
+	 *	o current directory
+	 *	o home directory
+	 *	o directory off of argv0
+	 *	o /etc/
+	 */
+	if (FileName::exists(inifile))
+	{
+	    filename = inifile;
+	}
+	else
+	{
+	    filename = FileName::combine(getenv("HOME"), inifile);
+	    if (!FileName::exists(filename))
+	    {
+		filename = FileName::replaceName(argv0, inifile);
+		if (!FileName::exists(filename))
+		{
+#if linux
+		    // Search PATH for argv0
+		    const char *p = getenv("PATH");
+		    Array *paths = FileName::splitPath(p);
+		    filename = FileName::searchPath(paths, argv0, 0);
+		    if (!filename)
+			goto Letc;		// argv0 not found on path
+		    filename = FileName::replaceName(filename, inifile);
+		    if (FileName::exists(filename))
+			goto Ldone;
+#endif
+
+		    // Search /etc/ for inifile
+		Letc:
+		    filename = FileName::combine("/etc/", inifile);
+
+		Ldone:
+		    ;
+		}
+	    }
+	}
+    }
+    path = FileName::path(filename);
+#if LOG
+    printf("\tpath = '%s', filename = '%s'\n", path, filename);
+#endif
+
+    File file(filename);
+
+    if (file.read())
+	return;			// error reading file
+
+    // Parse into lines
+    int eof = 0;
+    for (i = 0; i < file.len && !eof; i++)
+    {
+	int linestart = i;
+
+	for (; i < file.len; i++)
+	{
+	    switch (file.buffer[i])
+	    {
+		case '\r':
+		    break;
+
+		case '\n':
+		    // Skip if it was preceded by '\r'
+		    if (i && file.buffer[i - 1] == '\r')
+			goto Lskip;
+		    break;
+
+		case 0:
+		case 0x1A:
+		    eof = 1;
+		    break;
+
+		default:
+		    continue;
+	    }
+	    break;
+	}
+
+	// The line is file.buffer[linestart..i]
+	char *line;
+	int len;
+	char *p;
+	char *pn;
+
+	line = (char *)&file.buffer[linestart];
+	len = i - linestart;
+
+	buf.reset();
+
+	// First, expand the macros.
+	// Macros are bracketed by % characters.
+
+	for (k = 0; k < len; k++)
+	{
+	    if (line[k] == '%')
+	    {
+		int j;
+
+		for (j = k + 1; j < len; j++)
+		{
+		    if (line[j] == '%')
+		    {
+			if (j - k == 3 && memicmp(&line[k + 1], "@P", 2) == 0)
+			{
+			    // %@P% is special meaning the path to the .ini file
+			    p = path;
+			    if (!*p)
+				p = ".";
+			}
+			else
+			{   int len = j - k;
+			    char tmp[10];	// big enough most of the time
+
+			    if (len <= sizeof(tmp))
+				p = tmp;
+			    else
+				p = (char *)alloca(len);
+			    len--;
+			    memcpy(p, &line[k + 1], len);
+			    p[len] = 0;
+			    strupr(p);
+			    p = getenv(p);
+			    if (!p)
+				p = "";
+			}
+			buf.writestring(p);
+			k = j;
+			goto L1;
+		    }
+		}
+	    }
+	    buf.writeByte(line[k]);
+	 L1:
+	    ;
+	}
+
+	// Remove trailing spaces
+	while (buf.offset && isspace(buf.data[buf.offset - 1]))
+	    buf.offset--;
+
+	p = buf.toChars();
+
+	// The expanded line is in p.
+	// Now parse it for meaning.
+
+	p = skipspace(p);
+	switch (*p)
+	{
+	    case ';':		// comment
+	    case 0:		// blank
+		break;
+
+	    case '[':		// look for [Environment]
+		p = skipspace(p + 1);
+		for (pn = p; isalnum(*pn); pn++)
+		    ;
+		if (pn - p == 11 &&
+		    memicmp(p, "Environment", 11) == 0 &&
+		    *skipspace(pn) == ']'
+		   )
+		    envsection = 1;
+		else
+		    envsection = 0;
+		break;
+
+	    default:
+		if (envsection)
+		{
+		    pn = p;
+
+		    // Convert name to upper case;
+		    // remove spaces bracketing =
+		    for (p = pn; *p; p++)
+		    {   if (islower(*p))
+			    *p &= ~0x20;
+			else if (isspace(*p))
+			    memmove(p, p + 1, strlen(p));
+			else if (*p == '=')
+			{
+			    p++;
+			    while (isspace(*p))
+				memmove(p, p + 1, strlen(p));
+			    break;
+			}
+		    }
+
+		    putenv(strdup(pn));
+#if LOG
+		    printf("\tputenv('%s')\n", pn);
+		    //printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
+#endif
+		}
+		break;
+	}
+
+     Lskip:
+	;
+    }
+}
+
+/********************
+ * Skip spaces.
+ */
+
+char *skipspace(const char *p)
+{
+    while (isspace(*p))
+	p++;
+    return (char *)p;
+}
+