Changed func_shell to use PLATFORM specific calls for more flexability
authorRobert Pengelly <robertapengelly@hotmail.com>
Mon, 24 Mar 2025 23:10:59 +0000 (23:10 +0000)
committerRobert Pengelly <robertapengelly@hotmail.com>
Mon, 24 Mar 2025 23:10:59 +0000 (23:10 +0000)
23 files changed:
LICENSE
Makefile.pdw
Makefile.unix
Makefile.w32
README.md
cstr.c
hashtab.c
include/xmake/command.h
include/xmake/cstr.h
include/xmake/dep.h
include/xmake/hashtab.h
include/xmake/lib.h
include/xmake/read.h
include/xmake/report.h
include/xmake/rule.h
include/xmake/variable.h
include/xmake/xmake.h
lib.c
read.c
report.c
rule.c
variable.c
xmake.c

diff --git a/LICENSE b/LICENSE
index fdddb29aa445bf3d6a5d843d6dd77e10a9f99657..f50ef622698e47501d1bb3292f4f775a0fb54429 100644 (file)
--- a/LICENSE
+++ b/LICENSE
@@ -1,24 +1,24 @@
-This is free and unencumbered software released into the public domain.
-
-Anyone is free to copy, modify, publish, use, compile, sell, or
-distribute this software, either in source code form or as a compiled
-binary, for any purpose, commercial or non-commercial, and by any
-means.
-
-In jurisdictions that recognize copyright laws, the author or authors
-of this software dedicate any and all copyright interest in the
-software to the public domain. We make this dedication for the benefit
-of the public at large and to the detriment of our heirs and
-successors. We intend this dedication to be an overt act of
-relinquishment in perpetuity of all present and future rights to this
-software under copyright law.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-For more information, please refer to <https://unlicense.org>
+This is free and unencumbered software released into the public domain.\r
+\r
+Anyone is free to copy, modify, publish, use, compile, sell, or\r
+distribute this software, either in source code form or as a compiled\r
+binary, for any purpose, commercial or non-commercial, and by any\r
+means.\r
+\r
+In jurisdictions that recognize copyright laws, the author or authors\r
+of this software dedicate any and all copyright interest in the\r
+software to the public domain. We make this dedication for the benefit\r
+of the public at large and to the detriment of our heirs and\r
+successors. We intend this dedication to be an overt act of\r
+relinquishment in perpetuity of all present and future rights to this\r
+software under copyright law.\r
+\r
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,\r
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\r
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\r
+IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR\r
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,\r
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\r
+OTHER DEALINGS IN THE SOFTWARE.\r
+\r
+For more information, please refer to <https://unlicense.org>\r
index a6256dfcb56aaaa5d62ef56f4b360fb0ef2bdbb7..f6618cb3216a7c292db0fd848112de34b1108b88 100644 (file)
@@ -1,22 +1,22 @@
-#******************************************************************************
-# @file             Makefile.pdw
-#******************************************************************************
-AS=aswin
-CC=gccwin
-LD=ldwin
-
-COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__WIN32__ -D__NOBIVA__ -D__PDOS__
-COBJ=cstr.o hashtab.o lib.o report.o read.o rule.o variable.o xmake.o
-
-all: clean xmake.exe
-
-xmake.exe: $(COBJ)
-  $(LD) -s -o xmake.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a ../pdos/src/kernel32.a
-
-.c.o:
-  $(CC) $(COPTS) $<
-  $(AS) -o $@ $*.s
-  rm -f $*.s
-
-clean:
-  rm -f *.o xmake.exe
+#******************************************************************************\r
+# @file             Makefile.pdw\r
+#******************************************************************************\r
+AS=aswin\r
+CC=gccwin\r
+LD=ldwin\r
+\r
+COPTS=-S -O2 -fno-common -ansi -I. -I./include -I../pdos/pdpclib -I../pdos/src -D__WIN32__ -D__NOBIVA__ -D__PDOS__\r
+COBJ=cstr.o hashtab.o lib.o report.o read.o rule.o variable.o xmake.o\r
+\r
+all: clean xmake.exe\r
+\r
+xmake.exe: $(COBJ)\r
+  $(LD) -s -o xmake.exe ../pdos/pdpclib/w32start.o $(COBJ) ../pdos/pdpclib/msvcrt.a ../pdos/src/kernel32.a\r
+\r
+.c.o:\r
+  $(CC) $(COPTS) $<\r
+  $(AS) -o $@ $*.s\r
+  rm -f $*.s\r
+\r
+clean:\r
+  rm -f *.o xmake.exe\r
index 9c4310bb50ad1b9c4cab2010da9dee770c3e4f27..d3c8f3ed191517b5b9c5f6ff98f89f979df48b3c 100644 (file)
@@ -1,27 +1,27 @@
-#******************************************************************************
-# @file             Makefile.unix
-#******************************************************************************
-SRCDIR              ?=  $(CURDIR)
-VPATH               :=  $(SRCDIR)
-
-CC                  :=  gcc
-CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -I$(SRCDIR)/include -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90
-
-CSRC                :=  cstr.c hashtab.c lib.c read.c report.c rule.c variable.c xmake.c
-
-ifeq ($(OS), Windows_NT)
-all: xmake.exe
-
-xmake.exe: $(CSRC)
-       $(CC) $(CFLAGS) -o $@ $^
-else
-all: xmake
-
-xmake: $(CSRC)
-       $(CC) $(CFLAGS) -o $@ $^
-endif
-
-clean:
-
-       if [ -f xmake ]; then rm -rf xmake; fi
-       if [ -f xmake.exe ]; then rm -rf xmake.exe; fi
+#******************************************************************************\r
+# @file             Makefile.unix\r
+#******************************************************************************\r
+SRCDIR              ?=  $(CURDIR)\r
+VPATH               :=  $(SRCDIR)\r
+\r
+CC                  :=  gcc\r
+CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -I$(SRCDIR)/include -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90\r
+\r
+CSRC                :=  cstr.c hashtab.c lib.c read.c report.c rule.c variable.c xmake.c\r
+\r
+ifeq ($(OS), Windows_NT)\r
+all: xmake.exe\r
+\r
+xmake.exe: $(CSRC)\r
+       $(CC) $(CFLAGS) -o $@ $^\r
+else\r
+all: xmake\r
+\r
+xmake: $(CSRC)\r
+       $(CC) $(CFLAGS) -o $@ $^\r
+endif\r
+\r
+clean:\r
+\r
+       if [ -f xmake ]; then rm -rf xmake; fi\r
+       if [ -f xmake.exe ]; then rm -rf xmake.exe; fi\r
index 7d64d9ec93a7b50358b5fe4e21dd153720789177..605dd56a7ce12203eebeb9919106f436b02916ef 100644 (file)
@@ -1,21 +1,21 @@
-#******************************************************************************
-# @file             Makefile.w32
-#******************************************************************************
-SRCDIR              ?=  $(CURDIR)
-VPATH               :=  $(SRCDIR)
-
-CC                  :=  gcc
-CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -I$(SRCDIR)/include -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90
-
-CSRC                :=  cstr.c hashtab.c lib.c read.c report.c rule.c variable.c xmake.c
-
-all: xmake.exe
-
-xmake.exe: $(CSRC)
-
-       $(CC) $(CFLAGS) -o $@ $^
-
-clean:
-
-       if exist xmake ( del /q xmake )
-       if exist xmake.exe ( del /q xmake.exe )
+#******************************************************************************\r
+# @file             Makefile.w32\r
+#******************************************************************************\r
+SRCDIR              ?=  $(CURDIR)\r
+VPATH               :=  $(SRCDIR)\r
+\r
+CC                  :=  gcc\r
+CFLAGS              :=  -D_FILE_OFFSET_BITS=64 -I$(SRCDIR)/include -O2 -Wall -Werror -Wextra -ansi -pedantic -std=c90\r
+\r
+CSRC                :=  cstr.c hashtab.c lib.c read.c report.c rule.c variable.c xmake.c\r
+\r
+all: xmake.exe\r
+\r
+xmake.exe: $(CSRC)\r
+\r
+       $(CC) $(CFLAGS) -o $@ $^\r
+\r
+clean:\r
+\r
+       if exist xmake ( del /q xmake )\r
+       if exist xmake.exe ( del /q xmake.exe )\r
index 334430ac45d844f0d7d93bf1bc9f3e944fbfcccb..aa9269b98b7f7e2e6df291d721cea8dc6e3a4e20 100644 (file)
--- a/README.md
+++ b/README.md
@@ -1,23 +1,23 @@
-All source code is Public Domain.
-
-## Obtain the source code
-
-    git clone https://git.candlhat.org/xmake.git
-
-## Building
-
-    BSD:
-    
-        Make sure you have gcc and gmake installed then run gmake -f Makefile.unix.
-    
-    Linux:
-    
-        Make sure you have gcc and make installed then run make -f Makefile.unix.
-    
-    macOS:
-    
-        Make sure you have xcode command line tools installed then run make -f Makefile.unix.
-    
-    Windows:
-    
-        Make sure you have mingw installed and the location within your PATH variable then run mingw32-make.exe -f Makefile.w32.
+All source code is Public Domain.\r
+\r
+## Obtain the source code\r
+\r
+    git clone https://git.candlhat.org/xmake.git\r
+\r
+## Building\r
+\r
+    BSD:\r
+    \r
+        Make sure you have gcc and gmake installed then run gmake -f Makefile.unix.\r
+    \r
+    Linux:\r
+    \r
+        Make sure you have gcc and make installed then run make -f Makefile.unix.\r
+    \r
+    macOS:\r
+    \r
+        Make sure you have xcode command line tools installed then run make -f Makefile.unix.\r
+    \r
+    Windows:\r
+    \r
+        Make sure you have mingw installed and the location within your PATH variable then run mingw32-make.exe -f Makefile.w32.\r
diff --git a/cstr.c b/cstr.c
index 803ee72960f336b34baf320c3dae1c5735ddd14b..e676d7019020565843302e46047a1728f0deba09 100644 (file)
--- a/cstr.c
+++ b/cstr.c
@@ -1,69 +1,69 @@
-/******************************************************************************
- * @file            cstr.c
- *****************************************************************************/
-#include    <stdlib.h>
-#include    <string.h>
-
-#include    <xmake/cstr.h>
-
-extern void *xrealloc (void *__ptr, unsigned long __size);
-
-static void cstr_realloc (CString *cstr, long new_size) {
-
-    long size = cstr->size_allocated;
-    
-    if (size < 8) {
-        size = 8;
-    }
-    
-    while (size < new_size) {
-        size *= 2;
-    }
-    
-    cstr->data = xrealloc (cstr->data, size);
-    cstr->size_allocated = size;
-
-}
-
-void cstr_ccat (CString *cstr, int ch) {
-
-    long size = cstr->size + 1;
-    
-    if (size > cstr->size_allocated) {
-        cstr_realloc (cstr, size);
-    }
-    
-    ((unsigned char *) cstr->data)[size - 1] = ch;
-    cstr->size = size;
-
-}
-
-void cstr_cat (CString *cstr, const char *str, long len) {
-
-    long size;
-    
-    if (len <= 0) {
-        len = strlen (str) + 1 + len;
-    }
-    
-    size = cstr->size + len;
-    
-    if (size > cstr->size_allocated) {
-        cstr_realloc (cstr, size);
-    }
-    
-    memmove (((unsigned char *) cstr->data) + cstr->size, str, len);
-    cstr->size = size;
-
-}
-
-void cstr_new (CString *cstr) {
-    memset (cstr, 0, sizeof (CString));
-}
-
-void cstr_free (CString *cstr) {
-
-    free (cstr->data);
-    cstr_new (cstr);
-
-}
+/******************************************************************************\r
+ * @file            cstr.c\r
+ *****************************************************************************/\r
+#include    <stdlib.h>\r
+#include    <string.h>\r
+\r
+#include    <xmake/cstr.h>\r
+\r
+extern void *xrealloc (void *__ptr, unsigned long __size);\r
+\r
+static void cstr_realloc (CString *cstr, long new_size) {\r
+\r
+    long size = cstr->size_allocated;\r
+    \r
+    if (size < 8) {\r
+        size = 8;\r
+    }\r
+    \r
+    while (size < new_size) {\r
+        size *= 2;\r
+    }\r
+    \r
+    cstr->data = xrealloc (cstr->data, size);\r
+    cstr->size_allocated = size;\r
+\r
+}\r
+\r
+void cstr_ccat (CString *cstr, int ch) {\r
+\r
+    long size = cstr->size + 1;\r
+    \r
+    if (size > cstr->size_allocated) {\r
+        cstr_realloc (cstr, size);\r
+    }\r
+    \r
+    ((unsigned char *) cstr->data)[size - 1] = ch;\r
+    cstr->size = size;\r
+\r
+}\r
+\r
+void cstr_cat (CString *cstr, const char *str, long len) {\r
+\r
+    long size;\r
+    \r
+    if (len <= 0) {\r
+        len = strlen (str) + 1 + len;\r
+    }\r
+    \r
+    size = cstr->size + len;\r
+    \r
+    if (size > cstr->size_allocated) {\r
+        cstr_realloc (cstr, size);\r
+    }\r
+    \r
+    memmove (((unsigned char *) cstr->data) + cstr->size, str, len);\r
+    cstr->size = size;\r
+\r
+}\r
+\r
+void cstr_new (CString *cstr) {\r
+    memset (cstr, 0, sizeof (CString));\r
+}\r
+\r
+void cstr_free (CString *cstr) {\r
+\r
+    free (cstr->data);\r
+    cstr_new (cstr);\r
+\r
+}\r
index c25447dad08d44ee06128556d8b76680fc845571..1787d5675491249463c57f9face23ca1565c508d 100644 (file)
--- a/hashtab.c
+++ b/hashtab.c
-/******************************************************************************
- * @file            hashtab.c
- *****************************************************************************/
-#include    <stddef.h>
-#include    <stdlib.h>
-#include    <string.h>
-
-#include    <xmake/hashtab.h>
-
-static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned long capacity, struct hashtab_name *key);
-
-static int adjust_capacity (struct hashtab *table, unsigned long new_capacity) {
-
-    struct hashtab_entry *new_entries, *old_entries;
-    unsigned long i, new_count, old_capacity;
-    
-    if ((new_entries = malloc (sizeof (*new_entries) * new_capacity)) == NULL) {
-        return -2;
-    }
-    
-    for (i = 0; i < new_capacity; i++) {
-    
-        struct hashtab_entry *entry = &new_entries[i];
-        
-        entry->key = NULL;
-        entry->value = NULL;
-    
-    }
-    
-    old_entries = table->entries;
-    old_capacity = table->capacity;
-    
-    new_count = 0;
-    
-    for (i = 0; i < old_capacity; i++) {
-    
-        struct hashtab_entry *entry = &old_entries[i], *dest;
-        
-        if (entry->key == NULL) {
-            continue;
-        }
-        
-        dest = find_entry (new_entries, new_capacity, entry->key);
-        
-        dest->key = entry->key;
-        dest->value = entry->value;
-        
-        new_count++;
-    
-    }
-    
-    free (old_entries);
-    
-    table->capacity = new_capacity;
-    table->count = new_count;
-    table->entries = new_entries;
-    table->used = new_count;
-    
-    return 0;
-
-}
-
-static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned long capacity, struct hashtab_name *key) {
-
-    struct hashtab_entry *tombstone = NULL;
-    unsigned long index;
-    
-    for (index = key->hash % capacity; ; index = (index + 1) % capacity) {
-    
-        struct hashtab_entry *entry = &entries[index];
-        
-        if (entry->key == NULL) {
-        
-            if (entry->value == NULL) {
-            
-                if (tombstone == NULL) {
-                    return entry;
-                }
-                
-                return tombstone;
-            
-            } else if (tombstone == NULL) {
-                tombstone = entry;
-            }
-        
-        } else if (entry->key->bytes == key->bytes) {
-        
-            if (memcmp (entry->key->chars, key->chars, key->bytes) == 0 && entry->key->hash == key->hash) {
-                return entry;
-            }
-        
-        }
-    
-    }
-
-}
-
-static unsigned long hash_string (const void *p, unsigned long length) {
-
-    const unsigned char *str = (const unsigned char *) p;
-    unsigned long i, result = 0;
-    
-    for (i = 0; i < length; i++) {
-        result = (str[i] << 24) + (result >> 19) + (result << 16) + (result >> 13) + (str[i] << 8) - result;
-    }
-    
-    return result;
-
-}
-
-struct hashtab_name *hashtab_alloc_name (const char *str) {
-
-    struct hashtab_name *name;
-    unsigned long bytes = strlen (str), hash = hash_string (str, bytes);
-    
-    if ((name = malloc (sizeof (*name))) == NULL) {
-        return NULL;
-    }
-    
-    name->bytes = bytes;
-    name->chars = str;
-    name->hash = hash;
-    
-    return name;
-
-}
-
-struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name) {
-
-    struct hashtab_name *key;
-    struct hashtab_entry *entry;
-    
-    if (table == NULL || table->count == 0 || !(key = hashtab_alloc_name (name))) {
-        return 0;
-    }
-    
-    entry = find_entry (table->entries, table->capacity, key);
-    free (key);
-    
-    return entry->key;
-
-}
-
-void *hashtab_get (struct hashtab *table, struct hashtab_name *key) {
-
-    struct hashtab_entry *entry;
-    
-    if (table == NULL || table->count == 0) {
-        return NULL;
-    }
-    
-    entry = find_entry (table->entries, table->capacity, key);
-    
-    if (entry->key == NULL) {
-        return NULL;
-    }
-    
-    return entry->value;
-
-}
-
-int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value) {
-
-    const long MIN_CAPACITY = 15;
-    
-    struct hashtab_entry *entry;
-    int ret = 0;
-    
-    if (table->used >= table->capacity / 2) {
-    
-        long capacity = table->capacity * 2 - 1;
-        
-        if (capacity < MIN_CAPACITY) {
-            capacity = MIN_CAPACITY;
-        }
-        
-        if ((ret = adjust_capacity (table, capacity))) {
-            return ret;
-        }
-    
-    }
-    
-    entry = find_entry (table->entries, table->capacity, key);
-    
-    if (entry->key == NULL) {
-    
-        table->count++;
-        
-        if (entry->value == NULL) {
-            table->used++;
-        }
-    
-    }
-    
-    entry->key = key;
-    entry->value = value;
-    
-    return 0;
-
-}
-
-void hashtab_remove (struct hashtab *table, struct hashtab_name *key) {
-
-    struct hashtab_entry *entry;
-    
-    if ((entry = find_entry (table->entries, table->capacity, key)) != NULL) {
-    
-        entry->key = NULL;
-        entry->value = NULL;
-        
-        --table->count;
-    
-    }
-
-}
+/******************************************************************************\r
+ * @file            hashtab.c\r
+ *****************************************************************************/\r
+#include    <stddef.h>\r
+#include    <stdlib.h>\r
+#include    <string.h>\r
+\r
+#include    <xmake/hashtab.h>\r
+\r
+static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned long capacity, struct hashtab_name *key);\r
+\r
+static int adjust_capacity (struct hashtab *table, unsigned long new_capacity) {\r
+\r
+    struct hashtab_entry *new_entries, *old_entries;\r
+    unsigned long i, new_count, old_capacity;\r
+    \r
+    if ((new_entries = malloc (sizeof (*new_entries) * new_capacity)) == NULL) {\r
+        return -2;\r
+    }\r
+    \r
+    for (i = 0; i < new_capacity; i++) {\r
+    \r
+        struct hashtab_entry *entry = &new_entries[i];\r
+        \r
+        entry->key = NULL;\r
+        entry->value = NULL;\r
+    \r
+    }\r
+    \r
+    old_entries = table->entries;\r
+    old_capacity = table->capacity;\r
+    \r
+    new_count = 0;\r
+    \r
+    for (i = 0; i < old_capacity; i++) {\r
+    \r
+        struct hashtab_entry *entry = &old_entries[i], *dest;\r
+        \r
+        if (entry->key == NULL) {\r
+            continue;\r
+        }\r
+        \r
+        dest = find_entry (new_entries, new_capacity, entry->key);\r
+        \r
+        dest->key = entry->key;\r
+        dest->value = entry->value;\r
+        \r
+        new_count++;\r
+    \r
+    }\r
+    \r
+    free (old_entries);\r
+    \r
+    table->capacity = new_capacity;\r
+    table->count = new_count;\r
+    table->entries = new_entries;\r
+    table->used = new_count;\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+static struct hashtab_entry *find_entry (struct hashtab_entry *entries, unsigned long capacity, struct hashtab_name *key) {\r
+\r
+    struct hashtab_entry *tombstone = NULL;\r
+    unsigned long index;\r
+    \r
+    for (index = key->hash % capacity; ; index = (index + 1) % capacity) {\r
+    \r
+        struct hashtab_entry *entry = &entries[index];\r
+        \r
+        if (entry->key == NULL) {\r
+        \r
+            if (entry->value == NULL) {\r
+            \r
+                if (tombstone == NULL) {\r
+                    return entry;\r
+                }\r
+                \r
+                return tombstone;\r
+            \r
+            } else if (tombstone == NULL) {\r
+                tombstone = entry;\r
+            }\r
+        \r
+        } else if (entry->key->bytes == key->bytes) {\r
+        \r
+            if (memcmp (entry->key->chars, key->chars, key->bytes) == 0 && entry->key->hash == key->hash) {\r
+                return entry;\r
+            }\r
+        \r
+        }\r
+    \r
+    }\r
+\r
+}\r
+\r
+static unsigned long hash_string (const void *p, unsigned long length) {\r
+\r
+    const unsigned char *str = (const unsigned char *) p;\r
+    unsigned long i, result = 0;\r
+    \r
+    for (i = 0; i < length; i++) {\r
+        result = (str[i] << 24) + (result >> 19) + (result << 16) + (result >> 13) + (str[i] << 8) - result;\r
+    }\r
+    \r
+    return result;\r
+\r
+}\r
+\r
+struct hashtab_name *hashtab_alloc_name (const char *str) {\r
+\r
+    struct hashtab_name *name;\r
+    unsigned long bytes = strlen (str), hash = hash_string (str, bytes);\r
+    \r
+    if ((name = malloc (sizeof (*name))) == NULL) {\r
+        return NULL;\r
+    }\r
+    \r
+    name->bytes = bytes;\r
+    name->chars = str;\r
+    name->hash = hash;\r
+    \r
+    return name;\r
+\r
+}\r
+\r
+struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name) {\r
+\r
+    struct hashtab_name *key;\r
+    struct hashtab_entry *entry;\r
+    \r
+    if (table == NULL || table->count == 0 || !(key = hashtab_alloc_name (name))) {\r
+        return 0;\r
+    }\r
+    \r
+    entry = find_entry (table->entries, table->capacity, key);\r
+    free (key);\r
+    \r
+    return entry->key;\r
+\r
+}\r
+\r
+void *hashtab_get (struct hashtab *table, struct hashtab_name *key) {\r
+\r
+    struct hashtab_entry *entry;\r
+    \r
+    if (table == NULL || table->count == 0) {\r
+        return NULL;\r
+    }\r
+    \r
+    entry = find_entry (table->entries, table->capacity, key);\r
+    \r
+    if (entry->key == NULL) {\r
+        return NULL;\r
+    }\r
+    \r
+    return entry->value;\r
+\r
+}\r
+\r
+int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value) {\r
+\r
+    const long MIN_CAPACITY = 15;\r
+    \r
+    struct hashtab_entry *entry;\r
+    int ret = 0;\r
+    \r
+    if (table->used >= table->capacity / 2) {\r
+    \r
+        long capacity = table->capacity * 2 - 1;\r
+        \r
+        if (capacity < MIN_CAPACITY) {\r
+            capacity = MIN_CAPACITY;\r
+        }\r
+        \r
+        if ((ret = adjust_capacity (table, capacity))) {\r
+            return ret;\r
+        }\r
+    \r
+    }\r
+    \r
+    entry = find_entry (table->entries, table->capacity, key);\r
+    \r
+    if (entry->key == NULL) {\r
+    \r
+        table->count++;\r
+        \r
+        if (entry->value == NULL) {\r
+            table->used++;\r
+        }\r
+    \r
+    }\r
+    \r
+    entry->key = key;\r
+    entry->value = value;\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+void hashtab_remove (struct hashtab *table, struct hashtab_name *key) {\r
+\r
+    struct hashtab_entry *entry;\r
+    \r
+    if ((entry = find_entry (table->entries, table->capacity, key)) != NULL) {\r
+    \r
+        entry->key = NULL;\r
+        entry->value = NULL;\r
+        \r
+        --table->count;\r
+    \r
+    }\r
+\r
+}\r
index c3ce4e1dc89132e20b5e811a4190164688604251..52c2cd7c2c46cc22af7e25601b075fc71495b0fe 100644 (file)
@@ -1,14 +1,14 @@
-/******************************************************************************
- * @file            command.h
- *****************************************************************************/
-#ifndef     _COMMAND_H
-#define     _COMMAND_H
-
-struct commands {
-
-    char *text;
-    unsigned long len;
-
-};
-
-#endif      /* _COMMAND_H */
+/******************************************************************************\r
+ * @file            command.h\r
+ *****************************************************************************/\r
+#ifndef     _COMMAND_H\r
+#define     _COMMAND_H\r
+\r
+struct commands {\r
+\r
+    char *text;\r
+    unsigned long len;\r
+\r
+};\r
+\r
+#endif      /* _COMMAND_H */\r
index 62022707c0d7a80ecaa40ed910911e0ef180a163..1d9abf4730292c130a20e93e6f7526779698bd20 100644 (file)
@@ -1,22 +1,22 @@
-/******************************************************************************
- * @file            cstr.h
- *****************************************************************************/
-#ifndef     _CSTR_H
-#define     _CSTR_H
-
-typedef struct CString {
-
-    long size;
-    void *data;
-    
-    long size_allocated;
-
-} CString;
-
-void cstr_ccat (CString *cstr, int ch);
-void cstr_cat (CString *cstr, const char *str, long len);
-
-void cstr_new (CString *cstr);
-void cstr_free (CString *cstr);
-
-#endif      /* _CSTR_H */
+/******************************************************************************\r
+ * @file            cstr.h\r
+ *****************************************************************************/\r
+#ifndef     _CSTR_H\r
+#define     _CSTR_H\r
+\r
+typedef struct CString {\r
+\r
+    long size;\r
+    void *data;\r
+    \r
+    long size_allocated;\r
+\r
+} CString;\r
+\r
+void cstr_ccat (CString *cstr, int ch);\r
+void cstr_cat (CString *cstr, const char *str, long len);\r
+\r
+void cstr_new (CString *cstr);\r
+void cstr_free (CString *cstr);\r
+\r
+#endif      /* _CSTR_H */\r
index b683f814257d306f4af115d8e40679ae538bad13..89725c4c2b687180d84568cd7f7c23b3f5ae5d7f 100644 (file)
@@ -1,14 +1,14 @@
-/******************************************************************************
- * @file            dep.h
- *****************************************************************************/
-#ifndef     _DEP_H
-#define     _DEP_H
-
-struct dep {
-
-    char *name;
-    struct dep *next;
-
-};
-
-#endif      /* _DEP_H */
+/******************************************************************************\r
+ * @file            dep.h\r
+ *****************************************************************************/\r
+#ifndef     _DEP_H\r
+#define     _DEP_H\r
+\r
+struct dep {\r
+\r
+    char *name;\r
+    struct dep *next;\r
+\r
+};\r
+\r
+#endif      /* _DEP_H */\r
index 0c40a69431207c6091e3cf356f5c5017aba38d2f..684e4d37cb2f0735328b8a6db57ef038cbe69b72 100644 (file)
@@ -1,36 +1,36 @@
-/******************************************************************************
- * @file            hashtab.h
- *****************************************************************************/
-#ifndef     _HASHTAB_H
-#define     _HASHTAB_H
-
-struct hashtab_name {
-
-    const char *chars;
-    unsigned long bytes, hash;
-
-};
-
-struct hashtab_entry {
-
-    struct hashtab_name *key;
-    void *value;
-
-};
-
-struct hashtab {
-
-    struct hashtab_entry *entries;
-    unsigned long capacity, count, used;
-
-};
-
-struct hashtab_name *hashtab_alloc_name (const char *str);
-struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name);
-
-int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value);
-
-void *hashtab_get (struct hashtab *table, struct hashtab_name *key);
-void hashtab_remove (struct hashtab *table, struct hashtab_name *key);
-
-#endif      /* _HASHTAB_H */
+/******************************************************************************\r
+ * @file            hashtab.h\r
+ *****************************************************************************/\r
+#ifndef     _HASHTAB_H\r
+#define     _HASHTAB_H\r
+\r
+struct hashtab_name {\r
+\r
+    const char *chars;\r
+    unsigned long bytes, hash;\r
+\r
+};\r
+\r
+struct hashtab_entry {\r
+\r
+    struct hashtab_name *key;\r
+    void *value;\r
+\r
+};\r
+\r
+struct hashtab {\r
+\r
+    struct hashtab_entry *entries;\r
+    unsigned long capacity, count, used;\r
+\r
+};\r
+\r
+struct hashtab_name *hashtab_alloc_name (const char *str);\r
+struct hashtab_name *hashtab_get_key (struct hashtab *table, const char *name);\r
+\r
+int hashtab_put (struct hashtab *table, struct hashtab_name *key, void *value);\r
+\r
+void *hashtab_get (struct hashtab *table, struct hashtab_name *key);\r
+void hashtab_remove (struct hashtab *table, struct hashtab_name *key);\r
+\r
+#endif      /* _HASHTAB_H */\r
index d3eaf801bdf38615097b789cc3408274b6dbfa5c..04d9abb94360e98a3419182225faf5b383b611ae 100644 (file)
@@ -1,35 +1,35 @@
-/******************************************************************************
- * @file            lib.h
- *****************************************************************************/
-#ifndef     _LIB_H
-#define     _LIB_H
-
-#if     defined (_WIN32)
-# define    PATHSEP                     ";"
-#else
-# define    PATHSEP                     ":"
-#endif
-
-struct option {
-
-    const char *rule;
-    int (*callback) (const char *);
-
-};
-
-char *xstrdup (const char *__s);
-char *xstrndup (const char *__s, unsigned long __len);
-
-int parse_args (char **__args, int __cnt);
-void dynarray_add (void *__ptab, unsigned long *__nb_ptr, void *__data);
-
-void *xmalloc (unsigned long __sz);
-void *xrealloc (void *__ptr, unsigned long __sz);
-
-
-char *get_current_directory (void);
-
-int change_directory (const char *__path);
-int directory_exists (const char *__path);
-
-#endif      /* _LIB_H */
+/******************************************************************************\r
+ * @file            lib.h\r
+ *****************************************************************************/\r
+#ifndef     _LIB_H\r
+#define     _LIB_H\r
+\r
+#if     defined (_WIN32)\r
+# define    PATHSEP                     ";"\r
+#else\r
+# define    PATHSEP                     ":"\r
+#endif\r
+\r
+struct option {\r
+\r
+    const char *rule;\r
+    int (*callback) (const char *);\r
+\r
+};\r
+\r
+char *xstrdup (const char *__s);\r
+char *xstrndup (const char *__s, unsigned long __len);\r
+\r
+int parse_args (char **__args, int __cnt);\r
+void dynarray_add (void *__ptab, unsigned long *__nb_ptr, void *__data);\r
+\r
+void *xmalloc (unsigned long __sz);\r
+void *xrealloc (void *__ptr, unsigned long __sz);\r
+\r
+\r
+char *get_current_directory (void);\r
+\r
+int change_directory (const char *__path);\r
+int directory_exists (const char *__path);\r
+\r
+#endif      /* _LIB_H */\r
index a880c0e4fd5627b50c44caae8d609ff9d6d90073..00450770ba8b324e27ab9a0b00f2755af3618107 100644 (file)
@@ -1,20 +1,20 @@
-/******************************************************************************
- * @file            read.h
- *****************************************************************************/
-#ifndef     _READ_H
-#define     _READ_H
-
-void read_memory_makefile (const char *filename, unsigned long line_no, char *memory);
-int read_makefile (const char *filename);
-
-struct nameseq {
-
-    char *name;
-    struct nameseq *next;
-
-};
-
-void record_files (const char *filename, unsigned long line_no, struct nameseq *filenames, char *cmds, size_t cmds_idx, char *depstr);
-void *parse_nameseq (char *line, size_t size);
-
-#endif      /* _READ_H */
+/******************************************************************************\r
+ * @file            read.h\r
+ *****************************************************************************/\r
+#ifndef     _READ_H\r
+#define     _READ_H\r
+\r
+void read_memory_makefile (const char *filename, unsigned long line_no, char *memory);\r
+int read_makefile (const char *filename);\r
+\r
+struct nameseq {\r
+\r
+    char *name;\r
+    struct nameseq *next;\r
+\r
+};\r
+\r
+void record_files (const char *filename, unsigned long line_no, struct nameseq *filenames, char *cmds, size_t cmds_idx, char *depstr);\r
+void *parse_nameseq (char *line, size_t size);\r
+\r
+#endif      /* _READ_H */\r
index 4e507f489e4f2c54f8e9376f6e7a2a3466f7924d..907cad1c41e37a5be1046c4b3d5fcb5c686dae8f 100644 (file)
@@ -1,29 +1,29 @@
-/******************************************************************************
- * @file            report.h
- *****************************************************************************/
-#ifndef     _REPORT_H
-#define     _REPORT_H
-
-enum report_type {
-
-    REPORT_WARNING,
-    REPORT_ERROR,
-    REPORT_FATAL_ERROR,
-    REPORT_INTERNAL_ERROR
-
-};
-
-#if     defined (_WIN32)
-# define    COLOR_ERROR                 12
-# define    COLOR_WARNING               13
-# define    COLOR_INTERNAL_ERROR        19
-#else
-# define    COLOR_ERROR                 91
-# define    COLOR_INTERNAL_ERROR        94
-# define    COLOR_WARNING               95
-#endif
-
-unsigned long get_error_count (void);
-void report_at (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, ...);
-
-#endif      /* _REPORT_H */
+/******************************************************************************\r
+ * @file            report.h\r
+ *****************************************************************************/\r
+#ifndef     _REPORT_H\r
+#define     _REPORT_H\r
+\r
+enum report_type {\r
+\r
+    REPORT_WARNING,\r
+    REPORT_ERROR,\r
+    REPORT_FATAL_ERROR,\r
+    REPORT_INTERNAL_ERROR\r
+\r
+};\r
+\r
+#if     defined (_WIN32)\r
+# define    COLOR_ERROR                 12\r
+# define    COLOR_WARNING               13\r
+# define    COLOR_INTERNAL_ERROR        19\r
+#else\r
+# define    COLOR_ERROR                 91\r
+# define    COLOR_INTERNAL_ERROR        94\r
+# define    COLOR_WARNING               95\r
+#endif\r
+\r
+unsigned long get_error_count (void);\r
+void report_at (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, ...);\r
+\r
+#endif      /* _REPORT_H */\r
index 9e01c7b1c0af4c076fe86f66389cdb9749aed77a..25a2cda4b50824fa2ea5e1c0040b086f7e6499f4 100644 (file)
@@ -1,41 +1,41 @@
-/******************************************************************************
- * @file            rule.h
- *****************************************************************************/
-#ifndef     _RULE_H
-#define     _RULE_H
-
-#include    <xmake/command.h>
-#include    <xmake/dep.h>
-
-struct rule {
-
-    char *name;
-    
-    struct dep *deps;
-    struct commands *cmds;
-    
-    const char *filename;
-    unsigned long line_no;
-
-};
-
-struct suffix_rule {
-
-    char *first, *second;
-    struct commands *cmds;
-    
-    const char *filename;
-    unsigned long line_no;
-    
-    struct suffix_rule *next;
-
-};
-
-extern struct suffix_rule *suffix_rules;
-struct rule *rule_find (const char *name);
-
-void rule_add (const char *filename, unsigned long line_no, char *name, struct dep *deps, struct commands *cmds);
-void rule_add_suffix (const char *filename, unsigned long line_no, char *name, struct commands *cmds);
-void rules_init (void);
-
-#endif      /* _RULE_H */
+/******************************************************************************\r
+ * @file            rule.h\r
+ *****************************************************************************/\r
+#ifndef     _RULE_H\r
+#define     _RULE_H\r
+\r
+#include    <xmake/command.h>\r
+#include    <xmake/dep.h>\r
+\r
+struct rule {\r
+\r
+    char *name;\r
+    \r
+    struct dep *deps;\r
+    struct commands *cmds;\r
+    \r
+    const char *filename;\r
+    unsigned long line_no;\r
+\r
+};\r
+\r
+struct suffix_rule {\r
+\r
+    char *first, *second;\r
+    struct commands *cmds;\r
+    \r
+    const char *filename;\r
+    unsigned long line_no;\r
+    \r
+    struct suffix_rule *next;\r
+\r
+};\r
+\r
+extern struct suffix_rule *suffix_rules;\r
+struct rule *rule_find (const char *name);\r
+\r
+void rule_add (const char *filename, unsigned long line_no, char *name, struct dep *deps, struct commands *cmds);\r
+void rule_add_suffix (const char *filename, unsigned long line_no, char *name, struct commands *cmds);\r
+void rules_init (void);\r
+\r
+#endif      /* _RULE_H */\r
index 95573cb56a3673a49facf44fcffc02652f13ef5b..7527684410a5dfb2c10d4c3748b1513ec81b7300 100644 (file)
@@ -1,41 +1,41 @@
-/******************************************************************************
- * @file            variable.h
- *****************************************************************************/
-#ifndef     _VARIABLE_H
-#define     _VARIABLE_H
-
-enum variable_flavor {
-
-    VAR_FLAVOR_RECURSIVELY_EXPANDED,
-    VAR_FLAVOR_SIMPLY_EXPANDED,
-    VAR_FLAVOR_IMMEDIATELY_EXPANDED
-
-};
-
-enum variable_origin {
-
-    VAR_ORIGIN_AUTOMATIC,
-    VAR_ORIGIN_COMMAND_LINE,
-    VAR_ORIGIN_FILE
-
-};
-
-struct variable {
-
-    char *name, *value;
-    
-    enum variable_flavor flavor;
-    enum variable_origin origin;
-
-};
-
-struct variable *variable_add (char *name, char *value, enum variable_origin origin);
-struct variable *variable_change (char *name, char *value, enum variable_origin origin);
-struct variable *variable_find (char *name);
-
-void parse_var_line (const char *filename, unsigned long line_no, char *line, enum variable_origin origin);
-char *variable_expand_line (const char *filename, unsigned long line_no, char *line);
-
-void variables_init (void);
-
-#endif      /* _VARIABLE_H */
+/******************************************************************************\r
+ * @file            variable.h\r
+ *****************************************************************************/\r
+#ifndef     _VARIABLE_H\r
+#define     _VARIABLE_H\r
+\r
+enum variable_flavor {\r
+\r
+    VAR_FLAVOR_RECURSIVELY_EXPANDED,\r
+    VAR_FLAVOR_SIMPLY_EXPANDED,\r
+    VAR_FLAVOR_IMMEDIATELY_EXPANDED\r
+\r
+};\r
+\r
+enum variable_origin {\r
+\r
+    VAR_ORIGIN_AUTOMATIC,\r
+    VAR_ORIGIN_COMMAND_LINE,\r
+    VAR_ORIGIN_FILE\r
+\r
+};\r
+\r
+struct variable {\r
+\r
+    char *name, *value;\r
+    \r
+    enum variable_flavor flavor;\r
+    enum variable_origin origin;\r
+\r
+};\r
+\r
+struct variable *variable_add (char *name, char *value, enum variable_origin origin);\r
+struct variable *variable_change (char *name, char *value, enum variable_origin origin);\r
+struct variable *variable_find (char *name);\r
+\r
+void parse_var_line (const char *filename, unsigned long line_no, char *line, enum variable_origin origin);\r
+char *variable_expand_line (const char *filename, unsigned long line_no, char *line);\r
+\r
+void variables_init (void);\r
+\r
+#endif      /* _VARIABLE_H */\r
index 1c3db3faef60c5c01f544fe9722078b25c8773d2..233d826ec7ce5b5970bfef52aa7e35cfa55a56ae 100644 (file)
@@ -1,34 +1,34 @@
-/******************************************************************************
- * @file            xmake.h
- *****************************************************************************/
-#ifndef     _XMAKE_H
-#define     _XMAKE_H
-
-struct xmake_state {
-
-    char **makefiles;
-    unsigned long nb_makefiles;
-    
-    char **goals;
-    unsigned long nb_goals;
-    
-    char **include_paths;
-    unsigned long nb_include_paths;
-    
-    char **directories;
-    unsigned long nb_directories;
-    
-    char *path;
-    int quiet, no_print;
-    
-    int dry_run;
-    int ignore_errors;
-
-};
-
-extern struct xmake_state *state;
-extern const char *program_name;
-
-int rule_search_and_build (char *name);
-
-#endif      /* _XMAKE_H */
+/******************************************************************************\r
+ * @file            xmake.h\r
+ *****************************************************************************/\r
+#ifndef     _XMAKE_H\r
+#define     _XMAKE_H\r
+\r
+struct xmake_state {\r
+\r
+    char **makefiles;\r
+    unsigned long nb_makefiles;\r
+    \r
+    char **goals;\r
+    unsigned long nb_goals;\r
+    \r
+    char **include_paths;\r
+    unsigned long nb_include_paths;\r
+    \r
+    char **directories;\r
+    unsigned long nb_directories;\r
+    \r
+    char *path;\r
+    int quiet, no_print;\r
+    \r
+    int dry_run;\r
+    int ignore_errors;\r
+\r
+};\r
+\r
+extern struct xmake_state *state;\r
+extern const char *program_name;\r
+\r
+int rule_search_and_build (char *name);\r
+\r
+#endif      /* _XMAKE_H */\r
diff --git a/lib.c b/lib.c
index c6d1bde45dadc45aaeeba3d69cad42e0e60d77fb..9d70a7e776c66a089a7dddfafb6ad296aa7edecc 100644 (file)
--- a/lib.c
+++ b/lib.c
-/******************************************************************************
- * @file            lib.c
- *****************************************************************************/
-#include    <assert.h>
-#include    <stdio.h>
-#include    <stdlib.h>
-#include    <string.h>
-
-#include    <xmake/cstr.h>
-#include    <xmake/lib.h>
-#include    <xmake/report.h>
-#include    <xmake/variable.h>
-#include    <xmake/xmake.h>
-
-size_t len = 0;
-
-static int print_help (const char *arg) {
-
-    (void) arg;
-    
-    fprintf (stderr, "Usage: %s [options] [target] ...\n\n", program_name);
-    fprintf (stderr, "Options:\n\n");
-    
-    fprintf (stderr, "    -B                    Ignored.\n");
-    fprintf (stderr, "\n");
-    
-    fprintf (stderr, "    -C DIRECTORY          Change to DIRECTORY before doing anything.\n");
-    fprintf (stderr, "    -I DIRECTORY          Search DIRECTORY for included makefiles.\n");
-    fprintf (stderr, "\n");
-    
-    fprintf (stderr, "    -f FILE               Read FILE as a makefile.\n");
-    fprintf (stderr, "    -s                    Don't echo recipes.\n");
-    fprintf (stderr, "\n");
-    
-    fprintf (stderr, "    --no-print-directory  Don't print the current directory.\n");
-    fprintf (stderr, "    --help                Print this help information.\n");
-    
-    fprintf (stderr, "\n");
-    exit (EXIT_SUCCESS);
-
-}
-
-static int print_version (const char *arg) {
-
-    (void) arg;
-    
-    fprintf (stderr, "%s: version 0.0.1\n", program_name);
-    return 1;
-
-}
-
-static int set_quiet (const char *arg) {
-
-    (void) arg;
-    
-    state->quiet = 1;
-    return 0;
-
-}
-
-static int set_ignore_errors (const char *arg) {
-
-    (void) arg;
-    
-    state->ignore_errors = 1;
-    return 0;
-
-}
-
-static int set_dry_run (const char *arg) {
-
-    (void) arg;
-    
-    state->dry_run = 1;
-    return 0;
-
-}
-
-static int set_no_print (const char *arg) {
-
-    (void) arg;
-    
-    state->no_print = 1;
-    return 0;
-
-}
-
-static int add_include_path (const char *path) {
-
-    const char *in = path;
-    const char *p;
-    
-    do {
-    
-        int c;
-        
-        CString str;
-        cstr_new (&str);
-        
-        for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; p++) {
-        
-            if (c == '\\') { c = '/'; }
-            cstr_ccat (&str, c);
-        
-        }
-        
-        if (str.size) {
-        
-            if (((char *) str.data)[str.size - 1] != '/') {
-                cstr_ccat (&str, '/');
-            }
-            
-            cstr_ccat (&str, '\0');
-            dynarray_add (&state->include_paths, &state->nb_include_paths, xstrdup (str.data));
-        
-        }
-        
-        cstr_free (&str);
-        in = (p + 1);
-    
-    } while (*p != '\0');
-    
-    return 0;
-
-}
-
-static int ignored (const char *arg) {
-
-    (void) arg;
-    return 0;
-
-}
-
-static int add_directory (const char *path) {
-
-    char *arg = xstrdup (path);
-    
-    while (arg[strlen (arg) - 1] == '/' || arg[strlen (arg) - 1] == '\\') {
-        arg[strlen (arg) - 1] = '\0';
-    }
-    
-    dynarray_add (&state->directories, &state->nb_directories, arg);
-    return 0;
-
-}
-
-static int add_makefile (const char *name) {
-
-    dynarray_add (&state->makefiles, &state->nb_makefiles, xstrdup (name));
-    return 0;
-
-}
-
-static int non_option (const char *arg) {
-
-    if (strchr (arg, '=')) {
-    
-        char *temp = xstrdup (arg);
-        
-        parse_var_line ("<command-line>", 1, temp, VAR_ORIGIN_COMMAND_LINE);
-        free (temp);
-    
-    } else {
-        dynarray_add (&state->goals, &state->nb_goals, xstrdup (arg));
-    }
-    
-    return 0;
-
-}
-
-static struct option opts[] = {
-
-    {   "--help",                   &print_help             },
-    {   "-h",                       &print_help             },
-    
-    {   "--version",                &print_version          },
-    
-    {   "--silent",                 &set_quiet              },
-    {   "--quiet",                  &set_quiet              },
-    {   "-s",                       &set_quiet              },
-    
-    {   "--no-print-directory",     &set_no_print           },
-    
-    {   "--no-builtin-rules",       &ignored                },
-    {   "-r",                       &ignored                },
-    
-    {   "--include_dir=",           &add_include_path       },
-    {   "-I:",                      &add_include_path       },
-    
-    {   "--always-make",            &ignored                },
-    {   "-B",                       &ignored                },
-    
-    {   "--directory=",             &add_directory          },
-    {   "-C:",                      &add_directory          },
-    
-    {   "--makefile=",              &add_makefile           },
-    {   "--file=",                  &add_makefile           },
-    {   "-f:",                      &add_makefile           },
-    
-    {   "--ignore-errors",          &set_ignore_errors      },
-    {   "-i",                       &set_ignore_errors      },
-    
-    {   "--dry_run",                &set_dry_run            },
-    {   "-n",                       &set_dry_run            },
-    
-    
-    
-    {   0,                          &non_option             }
-
-};
-
-static int match_rule (const char *rule, const char *arg) {
-
-    const char *ptr;
-    
-    assert (rule);
-    assert (arg);
-    
-    while (*rule == *arg && *rule && *arg) {
-    
-        rule++;
-        arg++;
-    
-    }
-    
-    switch (*rule) {
-    
-        case '\0':
-            return *arg == '\0';
-        
-        case '[':
-        
-            ptr = ++rule;
-            
-            while (*ptr != ']') {
-                ptr++;
-            }
-            
-            return !strncmp (rule, arg, ptr - rule) ? match_rule (ptr + 1, arg + (ptr - rule)) : match_rule (ptr + 1, arg);
-        
-        case '{':
-        
-            do {
-            
-                ptr = ++rule;
-                
-                while (*ptr != '}' && *ptr != '|') {
-                    ptr++;
-                }
-                
-                if (strncmp (rule, arg, ptr - rule) == 0) {
-                
-                    arg = arg + (ptr - rule);
-                    
-                    do {
-                    
-                        rule = ptr;
-                        ptr++;
-                    
-                    } while (*rule != '}');
-                    
-                    return match_rule (ptr, arg);
-                
-                }
-                
-                rule = ptr;
-            
-            } while (*rule == '|');
-            
-            break;
-    
-    }
-    
-    return 0;
-
-}
-
-static int match_arg (struct option opt, int argc, char **argv, int *ret) {
-
-    size_t rule_len, arg_len;
-    assert (opt.callback);
-    
-    *ret = 0;
-    
-    rule_len = strlen (opt.rule);
-    arg_len = strlen (argv[0]);
-    
-    switch (opt.rule[rule_len - 1]) {
-    
-        case ':':
-        
-            rule_len--;
-            
-            if (strncmp (opt.rule, argv[0], rule_len) == 0) {
-            
-                if (arg_len == rule_len) {
-                
-                    if (argc < 2) {
-                    
-                        report_at (program_name, 0, REPORT_ERROR, "missing argument to '%s'", opt.rule);
-                        
-                        *ret = 1;
-                        return 0;
-                    
-                    }
-                    
-                    *ret = opt.callback (argv[1]);
-                    return 2;
-                
-                } else {
-                
-                    assert (arg_len > rule_len);
-                    
-                    *ret = opt.callback (argv[0] + rule_len);
-                    return 1;
-                
-                }
-            
-            }
-            
-            break;
-        
-        case '<':
-        
-            rule_len--;
-            /* fall through */
-        
-        case '=':
-        
-            if (strncmp (opt.rule, argv[0], rule_len) == 0) {
-            
-                if (arg_len == rule_len) {
-                
-                    report_at (program_name, 0, REPORT_ERROR, "missing argument to '%s'", argv[0]);
-                    
-                    *ret = 1;
-                    return 0;
-                
-                }
-                
-                *ret = opt.callback (argv[0] + rule_len);
-                return 1;
-            
-            }
-            
-            break;
-        
-        default:
-        
-            if (match_rule (opt.rule, argv[0])) {
-            
-                *ret = opt.callback (argv[0]);
-                return 1;
-            
-            }
-    
-    }
-    
-    return 0;
-
-}
-
-
-char *xstrdup (const char *__s) {
-
-    char *p = xmalloc (strlen (__s) + 1);
-    
-    strcpy (p, __s);
-    return p;
-
-}
-
-char *xstrndup (const char *__s, unsigned long __len) {
-
-    char *p = xmalloc (__len + 1);
-    
-    memcpy (p, __s, __len);
-    return p;
-
-}
-
-int parse_args (char **__args, int __cnt) {
-
-    struct option *opt, *last;
-    int i, c, ret;
-    
-    for (last = opts; last->rule; last++) {
-        ;
-    }
-    
-    for (i = 1; i < __cnt; ) {
-    
-        if (*(__args[i]) == '-') {
-        
-            for (opt = opts, c = 0; opt->rule && !c; opt++) {
-            
-                c = match_arg (*opt, __cnt - i, __args + i, &ret);
-                
-                if (ret != 0) {
-                    return ret;
-                }
-            
-            }
-            
-            if (c) {
-                i += c;
-            } else {
-            
-                report_at (program_name, 0, REPORT_ERROR, "unrecognized option '%s'", __args[i]);
-                return 1;
-            
-            }
-        
-        } else {
-        
-            if ((ret = last->callback (__args[i])) != 0) {
-                return ret;
-            }
-            
-            i++;
-        
-        }
-    
-    }
-    
-    if (!state->nb_makefiles) {
-        dynarray_add (&state->makefiles, &state->nb_makefiles, xstrdup ("Makefile"));
-    }
-    
-    return 0;
-
-}
-
-void dynarray_add (void *__ptab, unsigned long *__nb_ptr, void *__data) {
-
-    long nb, nb_alloc;
-    void **pp;
-    
-    nb = *__nb_ptr;
-    pp = *(void ***) __ptab;
-    
-    if ((nb & (nb - 1)) == 0) {
-    
-        if (!nb) {
-            nb_alloc = 1;
-        } else {
-            nb_alloc = nb * 2;
-        }
-        
-        pp = xrealloc (pp, nb_alloc * sizeof (void *));
-        *(void ***) __ptab = pp;
-    
-    }
-    
-    pp[nb++] = __data;
-    *__nb_ptr = nb;
-
-}
-
-void *xmalloc (unsigned long __sz) {
-
-    void *ptr = malloc (__sz);
-    
-    if (!ptr && __sz) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)");
-        exit (EXIT_FAILURE);
-    
-    }
-    
-    memset (ptr, 0, __sz);
-    return ptr;
-
-}
-
-void *xrealloc (void *__ptr, unsigned long __sz) {
-
-    void *ptr = realloc (__ptr, __sz);
-    
-    if (!ptr && __sz) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)");
-        exit (EXIT_FAILURE);
-    
-    }
-    
-    return ptr;
-
-}
-
-
-#if     defined(_WIN32)
-# include   <windows.h>
-
-char *get_current_directory (void) {
-
-    static TCHAR tszBuffer[4096];
-    size_t i;
-    
-    DWORD dwRet;
-    
-    if ((dwRet = GetCurrentDirectory (sizeof (tszBuffer), tszBuffer)) == 0) {
-    
-        report_at (program_name, 0, REPORT_FATAL_ERROR, "failed to get current directory");
-        exit (EXIT_FAILURE);
-    
-    }
-    
-    for (i = 0; i < strlen (tszBuffer); i++) {
-    
-        if (tszBuffer[i] == '\\') {
-            tszBuffer[i] = '/';
-        }
-    
-    }
-    
-    return tszBuffer;
-
-}
-
-int change_directory (const char *__path) {
-    return (SetCurrentDirectory (__path) != 0);
-}
-
-int directory_exists (const char *__path) {
-
-    DWORD dwAttrib = GetFileAttributes (__path);
-    return ((dwAttrib != -1LU) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
-
-}
-#else
-# include   <dirent.h>
-# include   <unistd.h>
-
-char *get_current_directory (void) {
-
-    static char cwd[4096] = { 0 };
-    memset (cwd, 0, sizeof (cwd));
-    
-    if (getcwd (cwd, sizeof (cwd))) {
-        return cwd;
-    }
-    
-    report_at (program_name, 0, REPORT_FATAL_ERROR, "failed to get current directory");
-    exit (EXIT_FAILURE);
-
-}
-
-int change_directory (const char *__path) {
-    return (chdir (__path) == 0);
-}
-
-int directory_exists (const char *__path) {
-
-    DIR *dir;
-    
-    if ((dir = opendir (__path))) {
-    
-        closedir (dir);
-        return 1;
-    
-    }
-    
-    return 0;
-
-}
-#endif
+/******************************************************************************\r
+ * @file            lib.c\r
+ *****************************************************************************/\r
+#include    <assert.h>\r
+#include    <stdio.h>\r
+#include    <stdlib.h>\r
+#include    <string.h>\r
+\r
+#include    <xmake/cstr.h>\r
+#include    <xmake/lib.h>\r
+#include    <xmake/report.h>\r
+#include    <xmake/variable.h>\r
+#include    <xmake/xmake.h>\r
+\r
+size_t len = 0;\r
+\r
+static int print_help (const char *arg) {\r
+\r
+    (void) arg;\r
+    \r
+    fprintf (stderr, "Usage: %s [options] [target] ...\n\n", program_name);\r
+    fprintf (stderr, "Options:\n\n");\r
+    \r
+    fprintf (stderr, "    -B                    Ignored.\n");\r
+    fprintf (stderr, "\n");\r
+    \r
+    fprintf (stderr, "    -C DIRECTORY          Change to DIRECTORY before doing anything.\n");\r
+    fprintf (stderr, "    -I DIRECTORY          Search DIRECTORY for included makefiles.\n");\r
+    fprintf (stderr, "\n");\r
+    \r
+    fprintf (stderr, "    -f FILE               Read FILE as a makefile.\n");\r
+    fprintf (stderr, "    -s                    Don't echo recipes.\n");\r
+    fprintf (stderr, "\n");\r
+    \r
+    fprintf (stderr, "    --no-print-directory  Don't print the current directory.\n");\r
+    fprintf (stderr, "    --help                Print this help information.\n");\r
+    \r
+    fprintf (stderr, "\n");\r
+    exit (EXIT_SUCCESS);\r
+\r
+}\r
+\r
+static int print_version (const char *arg) {\r
+\r
+    (void) arg;\r
+    \r
+    fprintf (stderr, "%s: version 0.0.1\n", program_name);\r
+    return 1;\r
+\r
+}\r
+\r
+static int set_quiet (const char *arg) {\r
+\r
+    (void) arg;\r
+    \r
+    state->quiet = 1;\r
+    return 0;\r
+\r
+}\r
+\r
+static int set_ignore_errors (const char *arg) {\r
+\r
+    (void) arg;\r
+    \r
+    state->ignore_errors = 1;\r
+    return 0;\r
+\r
+}\r
+\r
+static int set_dry_run (const char *arg) {\r
+\r
+    (void) arg;\r
+    \r
+    state->dry_run = 1;\r
+    return 0;\r
+\r
+}\r
+\r
+static int set_no_print (const char *arg) {\r
+\r
+    (void) arg;\r
+    \r
+    state->no_print = 1;\r
+    return 0;\r
+\r
+}\r
+\r
+static int add_include_path (const char *path) {\r
+\r
+    const char *in = path;\r
+    const char *p;\r
+    \r
+    do {\r
+    \r
+        int c;\r
+        \r
+        CString str;\r
+        cstr_new (&str);\r
+        \r
+        for (p = in; c = *p, c != '\0' && c != PATHSEP[0]; p++) {\r
+        \r
+            if (c == '\\') { c = '/'; }\r
+            cstr_ccat (&str, c);\r
+        \r
+        }\r
+        \r
+        if (str.size) {\r
+        \r
+            if (((char *) str.data)[str.size - 1] != '/') {\r
+                cstr_ccat (&str, '/');\r
+            }\r
+            \r
+            cstr_ccat (&str, '\0');\r
+            dynarray_add (&state->include_paths, &state->nb_include_paths, xstrdup (str.data));\r
+        \r
+        }\r
+        \r
+        cstr_free (&str);\r
+        in = (p + 1);\r
+    \r
+    } while (*p != '\0');\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+static int ignored (const char *arg) {\r
+\r
+    (void) arg;\r
+    return 0;\r
+\r
+}\r
+\r
+static int add_directory (const char *path) {\r
+\r
+    char *arg = xstrdup (path);\r
+    \r
+    while (arg[strlen (arg) - 1] == '/' || arg[strlen (arg) - 1] == '\\') {\r
+        arg[strlen (arg) - 1] = '\0';\r
+    }\r
+    \r
+    dynarray_add (&state->directories, &state->nb_directories, arg);\r
+    return 0;\r
+\r
+}\r
+\r
+static int add_makefile (const char *name) {\r
+\r
+    dynarray_add (&state->makefiles, &state->nb_makefiles, xstrdup (name));\r
+    return 0;\r
+\r
+}\r
+\r
+static int non_option (const char *arg) {\r
+\r
+    if (strchr (arg, '=')) {\r
+    \r
+        char *temp = xstrdup (arg);\r
+        \r
+        parse_var_line ("<command-line>", 1, temp, VAR_ORIGIN_COMMAND_LINE);\r
+        free (temp);\r
+    \r
+    } else {\r
+        dynarray_add (&state->goals, &state->nb_goals, xstrdup (arg));\r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+static struct option opts[] = {\r
+\r
+    {   "--help",                   &print_help             },\r
+    {   "-h",                       &print_help             },\r
+    \r
+    {   "--version",                &print_version          },\r
+    \r
+    {   "--silent",                 &set_quiet              },\r
+    {   "--quiet",                  &set_quiet              },\r
+    {   "-s",                       &set_quiet              },\r
+    \r
+    {   "--no-print-directory",     &set_no_print           },\r
+    \r
+    {   "--no-builtin-rules",       &ignored                },\r
+    {   "-r",                       &ignored                },\r
+    \r
+    {   "--include_dir=",           &add_include_path       },\r
+    {   "-I:",                      &add_include_path       },\r
+    \r
+    {   "--always-make",            &ignored                },\r
+    {   "-B",                       &ignored                },\r
+    \r
+    {   "--directory=",             &add_directory          },\r
+    {   "-C:",                      &add_directory          },\r
+    \r
+    {   "--makefile=",              &add_makefile           },\r
+    {   "--file=",                  &add_makefile           },\r
+    {   "-f:",                      &add_makefile           },\r
+    \r
+    {   "--ignore-errors",          &set_ignore_errors      },\r
+    {   "-i",                       &set_ignore_errors      },\r
+    \r
+    {   "--dry_run",                &set_dry_run            },\r
+    {   "-n",                       &set_dry_run            },\r
+    \r
+    \r
+    \r
+    {   0,                          &non_option             }\r
+\r
+};\r
+\r
+static int match_rule (const char *rule, const char *arg) {\r
+\r
+    const char *ptr;\r
+    \r
+    assert (rule);\r
+    assert (arg);\r
+    \r
+    while (*rule == *arg && *rule && *arg) {\r
+    \r
+        rule++;\r
+        arg++;\r
+    \r
+    }\r
+    \r
+    switch (*rule) {\r
+    \r
+        case '\0':\r
+            return *arg == '\0';\r
+        \r
+        case '[':\r
+        \r
+            ptr = ++rule;\r
+            \r
+            while (*ptr != ']') {\r
+                ptr++;\r
+            }\r
+            \r
+            return !strncmp (rule, arg, ptr - rule) ? match_rule (ptr + 1, arg + (ptr - rule)) : match_rule (ptr + 1, arg);\r
+        \r
+        case '{':\r
+        \r
+            do {\r
+            \r
+                ptr = ++rule;\r
+                \r
+                while (*ptr != '}' && *ptr != '|') {\r
+                    ptr++;\r
+                }\r
+                \r
+                if (strncmp (rule, arg, ptr - rule) == 0) {\r
+                \r
+                    arg = arg + (ptr - rule);\r
+                    \r
+                    do {\r
+                    \r
+                        rule = ptr;\r
+                        ptr++;\r
+                    \r
+                    } while (*rule != '}');\r
+                    \r
+                    return match_rule (ptr, arg);\r
+                \r
+                }\r
+                \r
+                rule = ptr;\r
+            \r
+            } while (*rule == '|');\r
+            \r
+            break;\r
+    \r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+static int match_arg (struct option opt, int argc, char **argv, int *ret) {\r
+\r
+    size_t rule_len, arg_len;\r
+    assert (opt.callback);\r
+    \r
+    *ret = 0;\r
+    \r
+    rule_len = strlen (opt.rule);\r
+    arg_len = strlen (argv[0]);\r
+    \r
+    switch (opt.rule[rule_len - 1]) {\r
+    \r
+        case ':':\r
+        \r
+            rule_len--;\r
+            \r
+            if (strncmp (opt.rule, argv[0], rule_len) == 0) {\r
+            \r
+                if (arg_len == rule_len) {\r
+                \r
+                    if (argc < 2) {\r
+                    \r
+                        report_at (program_name, 0, REPORT_ERROR, "missing argument to '%s'", opt.rule);\r
+                        \r
+                        *ret = 1;\r
+                        return 0;\r
+                    \r
+                    }\r
+                    \r
+                    *ret = opt.callback (argv[1]);\r
+                    return 2;\r
+                \r
+                } else {\r
+                \r
+                    assert (arg_len > rule_len);\r
+                    \r
+                    *ret = opt.callback (argv[0] + rule_len);\r
+                    return 1;\r
+                \r
+                }\r
+            \r
+            }\r
+            \r
+            break;\r
+        \r
+        case '<':\r
+        \r
+            rule_len--;\r
+            /* fall through */\r
+        \r
+        case '=':\r
+        \r
+            if (strncmp (opt.rule, argv[0], rule_len) == 0) {\r
+            \r
+                if (arg_len == rule_len) {\r
+                \r
+                    report_at (program_name, 0, REPORT_ERROR, "missing argument to '%s'", argv[0]);\r
+                    \r
+                    *ret = 1;\r
+                    return 0;\r
+                \r
+                }\r
+                \r
+                *ret = opt.callback (argv[0] + rule_len);\r
+                return 1;\r
+            \r
+            }\r
+            \r
+            break;\r
+        \r
+        default:\r
+        \r
+            if (match_rule (opt.rule, argv[0])) {\r
+            \r
+                *ret = opt.callback (argv[0]);\r
+                return 1;\r
+            \r
+            }\r
+    \r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+\r
+char *xstrdup (const char *__s) {\r
+\r
+    char *p = xmalloc (strlen (__s) + 1);\r
+    \r
+    strcpy (p, __s);\r
+    return p;\r
+\r
+}\r
+\r
+char *xstrndup (const char *__s, unsigned long __len) {\r
+\r
+    char *p = xmalloc (__len + 1);\r
+    \r
+    memcpy (p, __s, __len);\r
+    return p;\r
+\r
+}\r
+\r
+int parse_args (char **__args, int __cnt) {\r
+\r
+    struct option *opt, *last;\r
+    int i, c, ret;\r
+    \r
+    for (last = opts; last->rule; last++) {\r
+        ;\r
+    }\r
+    \r
+    for (i = 1; i < __cnt; ) {\r
+    \r
+        if (*(__args[i]) == '-') {\r
+        \r
+            for (opt = opts, c = 0; opt->rule && !c; opt++) {\r
+            \r
+                c = match_arg (*opt, __cnt - i, __args + i, &ret);\r
+                \r
+                if (ret != 0) {\r
+                    return ret;\r
+                }\r
+            \r
+            }\r
+            \r
+            if (c) {\r
+                i += c;\r
+            } else {\r
+            \r
+                report_at (program_name, 0, REPORT_ERROR, "unrecognized option '%s'", __args[i]);\r
+                return 1;\r
+            \r
+            }\r
+        \r
+        } else {\r
+        \r
+            if ((ret = last->callback (__args[i])) != 0) {\r
+                return ret;\r
+            }\r
+            \r
+            i++;\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    if (!state->nb_makefiles) {\r
+        dynarray_add (&state->makefiles, &state->nb_makefiles, xstrdup ("Makefile"));\r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+void dynarray_add (void *__ptab, unsigned long *__nb_ptr, void *__data) {\r
+\r
+    long nb, nb_alloc;\r
+    void **pp;\r
+    \r
+    nb = *__nb_ptr;\r
+    pp = *(void ***) __ptab;\r
+    \r
+    if ((nb & (nb - 1)) == 0) {\r
+    \r
+        if (!nb) {\r
+            nb_alloc = 1;\r
+        } else {\r
+            nb_alloc = nb * 2;\r
+        }\r
+        \r
+        pp = xrealloc (pp, nb_alloc * sizeof (void *));\r
+        *(void ***) __ptab = pp;\r
+    \r
+    }\r
+    \r
+    pp[nb++] = __data;\r
+    *__nb_ptr = nb;\r
+\r
+}\r
+\r
+void *xmalloc (unsigned long __sz) {\r
+\r
+    void *ptr = malloc (__sz);\r
+    \r
+    if (!ptr && __sz) {\r
+    \r
+        report_at (program_name, 0, REPORT_ERROR, "memory full (malloc)");\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    memset (ptr, 0, __sz);\r
+    return ptr;\r
+\r
+}\r
+\r
+void *xrealloc (void *__ptr, unsigned long __sz) {\r
+\r
+    void *ptr = realloc (__ptr, __sz);\r
+    \r
+    if (!ptr && __sz) {\r
+    \r
+        report_at (program_name, 0, REPORT_ERROR, "memory full (realloc)");\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    return ptr;\r
+\r
+}\r
+\r
+\r
+#if     defined(_WIN32)\r
+# include   <windows.h>\r
+\r
+char *get_current_directory (void) {\r
+\r
+    static TCHAR tszBuffer[4096];\r
+    size_t i;\r
+    \r
+    DWORD dwRet;\r
+    \r
+    if ((dwRet = GetCurrentDirectory (sizeof (tszBuffer), tszBuffer)) == 0) {\r
+    \r
+        report_at (program_name, 0, REPORT_FATAL_ERROR, "failed to get current directory");\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    for (i = 0; i < strlen (tszBuffer); i++) {\r
+    \r
+        if (tszBuffer[i] == '\\') {\r
+            tszBuffer[i] = '/';\r
+        }\r
+    \r
+    }\r
+    \r
+    return tszBuffer;\r
+\r
+}\r
+\r
+int change_directory (const char *__path) {\r
+    return (SetCurrentDirectory (__path) != 0);\r
+}\r
+\r
+int directory_exists (const char *__path) {\r
+\r
+    DWORD dwAttrib = GetFileAttributes (__path);\r
+    return ((dwAttrib != -1LU) && (dwAttrib & FILE_ATTRIBUTE_DIRECTORY));\r
+\r
+}\r
+#else\r
+# include   <dirent.h>\r
+# include   <unistd.h>\r
+\r
+char *get_current_directory (void) {\r
+\r
+    static char cwd[4096] = { 0 };\r
+    memset (cwd, 0, sizeof (cwd));\r
+    \r
+    if (getcwd (cwd, sizeof (cwd))) {\r
+        return cwd;\r
+    }\r
+    \r
+    report_at (program_name, 0, REPORT_FATAL_ERROR, "failed to get current directory");\r
+    exit (EXIT_FAILURE);\r
+\r
+}\r
+\r
+int change_directory (const char *__path) {\r
+    return (chdir (__path) == 0);\r
+}\r
+\r
+int directory_exists (const char *__path) {\r
+\r
+    DIR *dir;\r
+    \r
+    if ((dir = opendir (__path))) {\r
+    \r
+        closedir (dir);\r
+        return 1;\r
+    \r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+#endif\r
diff --git a/read.c b/read.c
index 0656805f25a6a34a046b0ecde5ba552b7ff4a020..0e28226071de74510fe7bd78e133f0957454ab9d 100644 (file)
--- a/read.c
+++ b/read.c
-/******************************************************************************
- * @file            read.c
- *****************************************************************************/
-#include    <ctype.h>
-#include    <stdio.h>
-#include    <stdlib.h>
-#include    <string.h>
-
-#include    <xmake/command.h>
-#include    <xmake/dep.h>
-#include    <xmake/lib.h>
-#include    <xmake/read.h>
-#include    <xmake/rule.h>
-#include    <xmake/variable.h>
-#include    <xmake/xmake.h>
-
-extern struct variable *default_goal_var;
-
-struct linebuf {
-
-    char *start, *memory;
-    unsigned long size;
-    
-    const char *filename;
-    unsigned long line_no;
-    
-    FILE *f;
-
-};
-
-static char *memory_fgets (char *str, int num, char **source_p) {
-
-    char *source = *source_p;
-    char *p = strchr (source, '\n');
-    
-    if (source[0] == '\0') {
-        return 0;
-    }
-    
-    if (p && p - source < num - 1) {
-    
-        memcpy (str, source, p - source + 1);
-        str[p - source + 1] = '\0';
-        
-        *source_p += p - source + 1;
-        return str;
-    
-    }
-    
-    if ((int) strlen (source) > num - 1) {
-    
-        memcpy (str, source, num - 1);
-        str[num - 1] = '\0';
-        
-        *source_p += num - 1;;
-        return str;
-    
-    }
-    
-    strcpy (str, source);
-    
-    *source_p += strlen (source);
-    return str;
-
-}
-
-static long read_line (struct linebuf *lbuf) {
-
-    long lines_read = 0;
-    
-    char *end = lbuf->start + lbuf->size;
-    char *p = lbuf->start;
-    
-    while (lbuf->f ? fgets (p, end - p, lbuf->f) : memory_fgets (p, end - p, &(lbuf->memory))) {
-    
-        size_t offset;
-        
-        p += strlen (p);
-        offset = p - lbuf->start;
-        
-        lines_read++;
-        
-        if (offset >= 2) {
-        
-            if (p[-1] == '\n' && p[-2] != '\\') {
-            
-                p[-1] = '\0';
-                break;
-            
-            }
-        
-        } else if (offset >= 1) {
-        
-            if (p[-1] == '\n') {
-            
-                p[-1] = '\0';
-                break;
-            
-            }
-        
-        }
-        
-        if (end - p >= 80) {
-            continue;
-        }
-        
-        lbuf->size *= 2;
-        lbuf->start = xrealloc (lbuf->start, lbuf->size);
-        
-        p = lbuf->start + offset;
-        end = lbuf->start + lbuf->size;
-    
-    }
-    
-    return lines_read;
-
-}
-
-static void remove_backslash_newlines (char *line) {
-
-    char *in = line, *out = line;
-    char *p;
-    
-    if (!(p = strchr (in, '\n'))) {
-        return;
-    }
-    
-    do {
-    
-        size_t out_line_len = p - in - 1;
-        
-        if (out != in) {
-            memmove (out, in, out_line_len);
-        }
-        
-        out += out_line_len;
-        in = p + 1;
-        
-        while (isspace ((int) *in)) {
-            in++;
-        }
-        
-        *(out++) = ' ';
-    
-    } while ((p = strchr (in, '\n')));
-    
-    memmove (out, in, strlen (in) + 1);
-
-}
-
-static void remove_comment (char *line) {
-
-    char *p;
-    
-    if ((p = strchr (line, '#'))) {
-        *p = '\0';
-    }
-
-}
-
-struct if_stack {
-
-    struct if_stack *prev;
-    
-    int ignoring;
-    int prev_ignoring;
-    int has_else;
-
-};
-
-static struct if_stack *cur_if_stack = 0;
-
-static void add_if_stack (void) {
-
-    struct if_stack *if_stack = xmalloc (sizeof *if_stack);
-    
-    if (cur_if_stack) {
-        if_stack->prev_ignoring = cur_if_stack->ignoring;
-    }
-    
-    if_stack->prev = cur_if_stack;
-    cur_if_stack = if_stack;
-
-}
-
-static int include_makefile (const char *src_filename, unsigned long line_no, const char *filename, int bsd) {
-
-    struct if_stack *saved_if_stack = cur_if_stack;
-    char *path, *new_name;
-    
-    unsigned long i;
-    cur_if_stack = 0;
-    
-    if (bsd) {
-    
-        char ch = *filename++, *end;
-        
-        if (ch != '<' && ch != '"') {
-        
-            fprintf (stderr, "%s: %s: %lu: *** .include filename must be delimited by '\"' or '<'. Stop.\n", program_name, src_filename, line_no);
-            exit (EXIT_FAILURE);
-        
-        }
-        
-        if (ch == '<') {
-        
-            if (!(end = strrchr (filename, '>'))) {
-            
-                fprintf (stderr, "%s: %s: %lu: *** unclosed .include filename. '>' expected. Stop.\n", program_name, src_filename, line_no);
-                exit (EXIT_FAILURE);
-            
-            }
-        
-        } else if (ch == '"') {
-        
-            if (!(end = strrchr (filename, '"'))) {
-            
-                fprintf (stderr, "%s: %s: %lu: *** unclosed .include filename. '\"' expected. Stop.\n", program_name, src_filename, line_no);
-                exit (EXIT_FAILURE);
-            
-            }
-        
-        }
-        
-        *end = '\0';
-    
-    }
-    
-    if (!read_makefile (filename)) {
-    
-        cur_if_stack = saved_if_stack;
-        return 0;
-    
-    }
-    
-    for (i = 0; i < state->nb_include_paths; i++) {
-    
-        path = state->include_paths[i];
-        
-        new_name = xmalloc (strlen (path) + strlen (filename) + 1);
-        sprintf (new_name, "%s%s", path, filename);
-        
-        if (!read_makefile (new_name)) {
-        
-            cur_if_stack = saved_if_stack;
-            
-            free (new_name);
-            return 0;
-        
-        }
-        
-        free (new_name);
-    
-    }
-    
-    fprintf (stderr, "%s: %s: %lu: *** failed to include '%s'. Stop.\n", program_name, src_filename, line_no, filename);
-    exit (EXIT_FAILURE);
-
-}
-
-static char *skip_whitespace (char *p) {
-
-    while (isspace ((int) *p)) {
-        p++;
-    }
-    
-    return p;
-
-}
-
-static int read_lbuf (struct linebuf *lbuf, int set_default) {
-
-    struct nameseq* filenames = 0;
-    int ret;
-    
-    char *cmds, *clean = 0, *depstr = 0, *q;
-    size_t clean_size = 0, cmds_idx = 0, cmds_sz = 256;
-    
-    char *colon, *semicolonp, *commentp;
-    long lines_read;
-    
-    unsigned long line_no = 1;
-    cmds = xmalloc (cmds_sz);
-    
-#define     record_waiting_files()                                              \
-    do {                                                                        \
-        if (filenames) {                                                        \
-            record_files (lbuf->filename, line_no, filenames, cmds, cmds_idx, depstr);                   \
-            filenames = 0;                                                      \
-        }                                                                       \
-        cmds_idx = 0;                                                           \
-    } while (0)
-    
-    while ((lines_read = read_line (lbuf))) {
-    
-        char *line = lbuf->start;
-        int after_else = 0;
-        
-        char *p, *src, *dst, *comma, *arg1 = 0, *arg2 = 0;
-        char ch;
-        
-        line_no = lbuf->line_no;
-        lbuf->line_no += lines_read;
-        
-        if (*line == '\0') {
-            continue;
-        }
-        
-        if (strlen (line) + 1 > clean_size) {
-        
-            clean_size = strlen (line) + 1;
-            
-            free (clean);
-            clean = xmalloc (clean_size);
-        
-        }
-        
-        strcpy (clean, line);
-        
-        remove_backslash_newlines (clean);
-        remove_comment (clean);
-        
-        p = skip_whitespace (clean);
-        
-        if (*p == '\0') {
-            continue;
-        }
-        
-        /**
-         * In command lines ifeq, etc. with space/tab before them
-         * should be treated as real commands, not directives.
-         */
-        if (filenames && p != clean) {
-            goto is_command;
-        }
-        
-        if (strncmp (p, ".else", 5) == 0 || strncmp (p, "else", 4) == 0) {
-        
-            if (*p == '.') {
-                p = skip_whitespace (p + 5);
-            } else {
-                p = skip_whitespace (p + 4);
-            }
-            
-            if (!cur_if_stack) {
-                fprintf (stderr, "%s: %s: %lu: extraneous 'else'\n", program_name, lbuf->filename, line_no);
-            }
-            
-            if (strncmp (p, "ifeq", 4) == 0 || strncmp (p, "ifneq", 5) == 0 || strncmp (p, "ifdef", 5) == 0 || strncmp (p, "ifndef", 6) == 0) {
-                after_else = 1;
-            } else {
-            
-                if (*p) {
-                    fprintf (stderr, "%s: %s: %lu: extraneous text after 'else' directive\n", program_name, lbuf->filename, line_no);
-                }
-                
-                if (cur_if_stack->has_else) {
-                
-                    fprintf (stderr, "%s: %s: %lu: *** only one 'else' per conditional. Stop.\n", program_name, lbuf->filename, line_no);
-                    exit (EXIT_FAILURE);
-                
-                }
-                
-                cur_if_stack->ignoring = (cur_if_stack->prev_ignoring || !cur_if_stack->ignoring);
-                cur_if_stack->has_else = 1;
-                
-                continue;
-            
-            }
-        
-        }
-        
-        if (strncmp (p, "ifeq", 4) == 0 || strncmp (p, "ifneq", 5) == 0) {
-        
-            int ifneq;
-            
-            if (strncmp (p, "ifeq", 4) == 0) {
-            
-                ifneq = 0;
-                p += 4;
-            
-            } else {
-            
-                ifneq = 1;
-                p += 5;
-            
-            }
-            
-            if (*p == '(' || *skip_whitespace (p) == '(') {
-            
-                q = skip_whitespace (skip_whitespace (p) + 1);
-                
-                if ((comma = strrchr (p, ','))) {
-                
-                    if (!isspace ((int) *p)) {
-                    
-                        fprintf (stderr, "%s: %s: %lu: *** missing separator (%s must be followed by whitespace). Stop.\n", program_name, lbuf->filename, line_no, ifneq ? "ifneq" : "ifeq");
-                        exit (EXIT_FAILURE);
-                    
-                    }
-                    
-                    arg1 = p = q;
-                    
-                    if (!(q = strrchr (p, ')')) || q < comma) {
-                        goto ifeq_invalid_syntax;
-                    }
-                    
-                    *comma = '\0';
-                    *q = '\0';
-                    
-                    for (q = comma; q > p && isspace ((int) *(q - 1));) {
-                        *--q = '\0';
-                    }
-                    
-                    for (p = comma + 1; isspace ((int) *p);) {
-                        p++;
-                    }
-                    
-                    arg2 = p;
-                    
-                    while (*p != '\0') {
-                        p++;
-                    }
-                
-                } else {
-                
-                    fprintf (stderr, "%s: %s: %lu: currently only ifeq (arg,arg) is supported\n", program_name, lbuf->filename, line_no);
-                    exit (EXIT_FAILURE);
-                
-                }
-            
-            } else {
-            
-                if (!*skip_whitespace (p)) {
-                    goto ifeq_invalid_syntax;
-                }
-                
-                if (!isspace ((int) *p)) {
-                
-                    fprintf (stderr, "%s: %s: %lu: *** missing separator (%s must be followed by whitespace). Stop.\n", program_name, lbuf->filename, line_no, ifneq ? "ifneq" : "ifeq");
-                    exit (EXIT_FAILURE);
-                
-                }
-                
-                p = skip_whitespace (p);
-                
-                if (*p == '"' || *p == '\'') {
-                
-                    ch = *p++;
-                    arg1 = p;
-                    
-                    while (*p != ch) {
-                    
-                        if (*p == '\0') {
-                            goto ifeq_invalid_syntax;
-                        }
-                        
-                        p++;
-                    
-                    }
-                    
-                    *p = '\0';
-                    p = skip_whitespace (p + 1);
-                    
-                    if (*p != '"' && *p != '\'') {
-                        goto ifeq_invalid_syntax;
-                    }
-                    
-                    ch = *p++;
-                    arg2 = p;
-                    
-                    while (*p != ch) {
-                    
-                        if (*p == '\0') {
-                            goto ifeq_invalid_syntax;
-                        }
-                        
-                        p++;
-                    
-                    }
-                    
-                    *p++ = '\0';
-                
-                }
-            
-            }
-            
-            p = skip_whitespace (p);
-            
-            if (*p || !arg1 || !arg2) {
-                fprintf (stderr, "%s: %s: %lu: extraneous text after '%s' directive\n", program_name, lbuf->filename, line_no, ifneq ? "ifneq" : "ifeq");
-            }
-            
-            p = variable_expand_line (lbuf->filename, line_no, xstrdup (arg1));
-            q = variable_expand_line (lbuf->filename, line_no, xstrdup (arg2));
-            
-            if (after_else) {
-                cur_if_stack->prev_ignoring |= !cur_if_stack->ignoring;
-            } else {
-                add_if_stack ();
-            }
-            
-            if (cur_if_stack->prev_ignoring) {
-                cur_if_stack->ignoring = 1;
-            } else {
-            
-                int is_equal = (strcmp (p, q) == 0);
-                cur_if_stack ->ignoring = is_equal ^ (!ifneq);
-            
-            }
-            
-            free (p);
-            free (q);
-            
-            continue;
-            
-        ifeq_invalid_syntax:
-            
-            fprintf (stderr, "%s: %s: %lu: *** invalid syntax in conditional. Stop.", program_name, lbuf->filename, line_no);
-            exit (EXIT_FAILURE);
-        
-        }
-        
-        if (strncmp (p, ".ifdef", 6) == 0 || strncmp (p, "ifdef", 5) == 0 || strncmp (p, ".ifndef", 7) == 0 || strncmp (p, "ifndef", 6) == 0) {
-        
-            struct variable *var;
-            int ifndef;
-            
-            if (*p == '.') {
-                p++;
-            }
-            
-            if (strncmp (p, "ifdef", 5) == 0) {
-            
-                ifndef = 0;
-                p += 5;
-            
-            } else {
-            
-                ifndef = 1;
-                p += 6;
-            
-            }
-            
-            if (!isspace ((int) *p)) {
-            
-                fprintf (stderr, "%s: %s: %lu: %s must be followed by whitespace. Stop.", program_name, lbuf->filename, line_no, ifndef ? "ifndef" : "ifdef");
-                exit (EXIT_FAILURE);
-            
-            }
-            
-            p = line = variable_expand_line (lbuf->filename, line_no, xstrdup (skip_whitespace (p)));
-            
-            for (; isspace ((int) *p);) {
-                p++;
-            }
-            
-            for (q = p + strlen (p); q > p && isspace ((int) *(q - 1));) {
-                *--q = '\0';
-            }
-            
-            var = variable_find (p);
-            
-            if (after_else) {
-                cur_if_stack->prev_ignoring |= !cur_if_stack->ignoring;
-            } else {
-                add_if_stack ();
-            }
-            
-            if (cur_if_stack->prev_ignoring) {
-                cur_if_stack->ignoring = 1;
-            } else {
-            
-                int is_defined = 0;
-                
-                if (var) {
-                    is_defined = 1;
-                }
-                
-                cur_if_stack->ignoring = is_defined ^ (!ifndef);
-            
-            }
-            
-            continue;
-        
-        }
-        
-        if (strncmp (p, ".endif", 6) == 0 || strncmp (p, "endif", 5) == 0) {
-        
-            if (*p == '.') {
-                p = skip_whitespace (p + 6);
-            } else {
-                p = skip_whitespace (p + 5);
-            }
-            
-            if (!cur_if_stack) {
-                fprintf (stderr, "%s: %s: %lu: extraneous 'endif'\n", program_name, lbuf->filename, line_no);
-            } else {
-            
-                struct if_stack *prev = cur_if_stack->prev;
-                
-                free (cur_if_stack);
-                cur_if_stack = prev;
-            
-            }
-            
-            if (*p) {
-                fprintf (stderr, "%s: %s: %lu: extraneous text after 'endif' directive\n", program_name, lbuf->filename, line_no);
-            }
-            
-            continue;
-        
-        }
-        
-    is_command:
-        
-        if (cur_if_stack && cur_if_stack->ignoring) {
-            continue;
-        }
-        
-        if (line[0] == ' ' || line[0] == '\t') {
-        
-            if (filenames) {
-            
-                while (line[0] == ' ' || line[0] == '\t') {
-                    line++;
-                }
-                
-                if (cmds_idx + strlen (line) + 1 > cmds_sz) {
-                
-                    cmds_sz = (cmds_idx + strlen (line) + 1) * 2;
-                    cmds = xrealloc (cmds, cmds_sz);
-                
-                }
-                
-                src = line;
-                dst = &cmds[cmds_idx];
-                
-                for (; *src; src++, dst++) {
-                
-                    if (src[0] == '\n' && src[-1] == '\\' && src[1] == '\t') {
-                    
-                        *dst = *src;
-                        
-                        src++;
-                        continue;
-                    
-                    }
-                    
-                    *dst = *src;
-                
-                }
-                
-                *dst = '\0';
-                
-                cmds_idx += dst - &cmds[cmds_idx] + 1;
-                cmds[cmds_idx - 1] = '\n';
-                
-                continue;
-            
-            }
-        
-        }
-        
-        if (strncmp (p, ".include", 8) == 0 || (strncmp (p, "include", 7) == 0 && (isspace ((int) p[7]) || p[7] == '\0'))) {
-        
-            int bsd = 0;
-            
-            if (*p == '.') {
-            
-                bsd = 1;
-                p++;
-            
-            }
-            
-            p = skip_whitespace (p + 7);
-            
-            for (q = p + strlen (p); q > p && isspace ((int) q[-1]); q--) {
-                ;
-            }
-            
-            *q = '\0';
-            p = line = variable_expand_line (lbuf->filename, line_no, xstrdup (p));
-            
-            while (1) {
-            
-                char saved_ch;
-                
-                for (; isspace ((int) *p); p++) {
-                    ;
-                }
-                
-                for (q = p; *q && !isspace ((int) *q); q++) {
-                    ;
-                }
-                
-                if (q == p) {
-                    break;
-                }
-                
-                saved_ch = *q;
-                *q = '\0';
-                
-                if ((ret = include_makefile (lbuf->filename, line_no, p, bsd))) {
-                    return ret;
-                }
-                
-                *q = saved_ch;
-                
-                p = q;
-            
-            }
-            
-            free (line);
-            continue;
-        
-        }
-        
-        if (*p == '$') {
-        
-            variable_expand_line (lbuf->filename, line_no, p);
-            continue;
-        
-        } else if (strchr (p, '=')) {
-        
-            record_waiting_files ();
-            
-            parse_var_line (lbuf->filename, line_no, p, VAR_ORIGIN_FILE);
-            continue;
-        
-        }
-        
-        record_waiting_files ();
-        
-        semicolonp = strchr (line, ';');
-        commentp = strchr (line, '#');
-        
-        if (commentp && semicolonp && (commentp < semicolonp)) {
-        
-            *commentp = '\0';
-            semicolonp = 0;
-        
-        } else if (semicolonp) {
-            *(semicolonp++) = '\0';
-        }
-        
-        remove_backslash_newlines (line);
-        line = variable_expand_line (lbuf->filename, line_no, xstrdup (line));
-        
-        if (!(colon = strchr (line, ':'))) {
-        
-            if (*(p = skip_whitespace (line))) {
-                fprintf (stderr, "%s: %s: %lu: missing ':' in rule line!\n", program_name, lbuf->filename, line_no);
-            }
-            
-            free (line);
-            continue;
-        
-        }
-        
-        *colon = '\0';
-        
-        filenames = parse_nameseq (line, sizeof (*filenames));
-        depstr = xstrdup (colon + 1);
-        
-        free (line);
-        
-        if (semicolonp) {
-        
-            if (cmds_idx + strlen (semicolonp) + 1 > cmds_sz) {
-            
-                cmds_sz = (cmds_idx + strlen (semicolonp) + 1) * 2;
-                cmds = xrealloc (cmds, cmds_sz);
-            
-            }
-            
-            memcpy (&(cmds[cmds_idx]), semicolonp, strlen (semicolonp) + 1);
-            cmds_idx += strlen (semicolonp) + 1;
-        
-        }
-        
-        if (set_default && default_goal_var->value[0] == '\0') {
-        
-            struct nameseq *ns;
-            
-            for (ns = filenames; ns; ns = ns->next) {
-            
-                if ((ns->name[0] == '.') && strchr (ns->name, '\\') == 0 && strchr (ns->name, '/') == 0) {
-                    continue;
-                }
-                
-                free (default_goal_var->value);
-                
-                default_goal_var->value = xstrdup (ns->name);
-                break;
-            
-            }
-        
-        }
-    
-    }
-    
-    record_waiting_files ();
-    
-    if (*(skip_whitespace (lbuf->start))) {
-        line_no++;
-    }
-    
-    free (clean);
-    free (cmds);
-    
-    if (cur_if_stack) {
-    
-        struct if_stack *prev;
-        
-        for (; cur_if_stack; cur_if_stack = prev) {
-        
-            prev = cur_if_stack->prev;
-            free (cur_if_stack);
-        
-        }
-        
-        fprintf (stderr, "%s: %s: %lu: *** missing 'endif'. Stop.\n", program_name, lbuf->filename, line_no);
-        exit (EXIT_FAILURE);
-    
-    }
-    
-    return 0;
-
-}
-
-int read_makefile (const char *filename) {
-
-    struct linebuf lbuf;
-    struct variable *makefile_list;
-    
-    char *new_value;
-    int ret;
-    
-    if (strcmp (filename, "-") == 0) {
-    
-        filename = "<stdin>";
-        lbuf.f = stdin;
-    
-    } else if (!(lbuf.f = fopen (filename, "r"))) {
-        return 1;
-    }
-    
-    lbuf.size = 256;
-    
-    lbuf.filename = filename;
-    lbuf.line_no = 1;
-    
-    lbuf.start = xmalloc (lbuf.size);
-    
-    if ((makefile_list = variable_find ("MAKEFILE_LIST"))) {
-    
-        unsigned long old_len = strlen (makefile_list->value);
-        
-        new_value = xmalloc (old_len + 1 + strlen (filename) + 1);
-        sprintf (new_value, "%s %s", makefile_list->value, filename);
-        
-        variable_change ("MAKEFILE_LIST", new_value, VAR_ORIGIN_FILE);
-    
-    } else {
-    
-        new_value = xmalloc (strlen (filename) + 1);
-        sprintf (new_value, "%s", filename);
-        
-        variable_change ("MAKEFILE_LIST", new_value, VAR_ORIGIN_FILE);
-    
-    }
-    
-    ret = read_lbuf (&lbuf, 1);
-    free (lbuf.start);
-    
-    if (lbuf.f != stdin) {
-        fclose (lbuf.f);
-    }
-    
-    return ret;
-
-}
-
-void read_memory_makefile (const char *filename, unsigned long line_no, char *memory) {
-
-    struct if_stack *saved_if_stack;
-    struct linebuf lbuf;
-    
-    lbuf.size = 256;
-    lbuf.f = 0;
-    
-    lbuf.start = xmalloc (lbuf.size);
-    lbuf.memory = memory;
-    
-    lbuf.filename = filename;
-    lbuf.line_no = line_no;
-    
-    saved_if_stack = cur_if_stack;
-    cur_if_stack = 0;
-    
-    read_lbuf (&lbuf, 1);
-    free (lbuf.start);
-    
-    cur_if_stack = saved_if_stack;
-
-}
-
-void *parse_nameseq (char *line, size_t size) {
-
-    struct nameseq *start = 0;
-    struct nameseq **pp = &start;
-    
-    char *p, *temp;
-    temp = xmalloc (strlen (line) + 1);
-    
-#define     add_nameseq(_name)                              \
-    do {                                                    \
-        *pp = xmalloc (size);                               \
-        (*pp)->name = xstrdup (_name);                      \
-        pp = &((*pp)->next);                                \
-    } while (0)
-    
-    p = line;
-    
-    while (1) {
-    
-        char *p2;
-        
-        while (isspace ((int) *p)) {
-            p++;
-        }
-        
-        if (*p == '\0') {
-            break;
-        }
-        
-        p2 = p;
-        
-        while (*p2 && !isspace ((int) *p2)) {
-            p2++;
-        }
-        
-        memcpy (temp, p, p2 - p);
-        temp[p2 - p] = '\0';
-        
-        add_nameseq (temp);
-        p = p2;
-    
-    }
-    
-#undef      add_nameseq
-    
-    free (temp);
-    return start;
-
-}
-
-void record_files (const char *filename, unsigned long line_no, struct nameseq *filenames, char *cmds, size_t cmds_idx, char *depstr) {
-
-    struct commands *cmds_p;
-    
-    struct dep *deps;
-    struct nameseq *ns, *old_ns;
-    
-    if (cmds_idx > 0) {
-    
-        cmds_p = xmalloc (sizeof (*cmds_p));
-        
-        cmds_p->text = xstrndup (cmds, cmds_idx);
-        cmds_p->len = cmds_idx;
-    
-    } else {
-        cmds_p = 0;
-    }
-    
-    if (depstr) {
-        deps = parse_nameseq (depstr, sizeof (*deps));
-    } else {
-        deps = 0;
-    }
-    
-    for (ns = filenames, old_ns = 0; ns; old_ns = ns, ns = ns->next, free (old_ns->name), free (old_ns)) {
-    
-        if (ns->name[0] == '.' && !strchr (ns->name, '\\') && !strchr (ns->name, '/')) {
-            rule_add_suffix (filename, line_no - 1, ns->name, cmds_p);
-        } else {
-            rule_add (filename, line_no - 1, ns->name, deps, cmds_p);
-        }
-    
-    }
-    
-    free (depstr);
-
-}
+/******************************************************************************\r
+ * @file            read.c\r
+ *****************************************************************************/\r
+#include    <ctype.h>\r
+#include    <stdio.h>\r
+#include    <stdlib.h>\r
+#include    <string.h>\r
+\r
+#include    <xmake/command.h>\r
+#include    <xmake/dep.h>\r
+#include    <xmake/lib.h>\r
+#include    <xmake/read.h>\r
+#include    <xmake/rule.h>\r
+#include    <xmake/variable.h>\r
+#include    <xmake/xmake.h>\r
+\r
+extern struct variable *default_goal_var;\r
+\r
+struct linebuf {\r
+\r
+    char *start, *memory;\r
+    unsigned long size;\r
+    \r
+    const char *filename;\r
+    unsigned long line_no;\r
+    \r
+    FILE *f;\r
+\r
+};\r
+\r
+static char *memory_fgets (char *str, int num, char **source_p) {\r
+\r
+    char *source = *source_p;\r
+    char *p = strchr (source, '\n');\r
+    \r
+    if (source[0] == '\0') {\r
+        return 0;\r
+    }\r
+    \r
+    if (p && p - source < num - 1) {\r
+    \r
+        memcpy (str, source, p - source + 1);\r
+        str[p - source + 1] = '\0';\r
+        \r
+        *source_p += p - source + 1;\r
+        return str;\r
+    \r
+    }\r
+    \r
+    if ((int) strlen (source) > num - 1) {\r
+    \r
+        memcpy (str, source, num - 1);\r
+        str[num - 1] = '\0';\r
+        \r
+        *source_p += num - 1;;\r
+        return str;\r
+    \r
+    }\r
+    \r
+    strcpy (str, source);\r
+    \r
+    *source_p += strlen (source);\r
+    return str;\r
+\r
+}\r
+\r
+static long read_line (struct linebuf *lbuf) {\r
+\r
+    long lines_read = 0;\r
+    \r
+    char *end = lbuf->start + lbuf->size;\r
+    char *p = lbuf->start;\r
+    \r
+    while (lbuf->f ? fgets (p, end - p, lbuf->f) : memory_fgets (p, end - p, &(lbuf->memory))) {\r
+    \r
+        size_t offset;\r
+        \r
+        p += strlen (p);\r
+        offset = p - lbuf->start;\r
+        \r
+        lines_read++;\r
+        \r
+        if (offset >= 2) {\r
+        \r
+            if (p[-1] == '\n' && p[-2] != '\\') {\r
+            \r
+                p[-1] = '\0';\r
+                break;\r
+            \r
+            }\r
+        \r
+        } else if (offset >= 1) {\r
+        \r
+            if (p[-1] == '\n') {\r
+            \r
+                p[-1] = '\0';\r
+                break;\r
+            \r
+            }\r
+        \r
+        }\r
+        \r
+        if (end - p >= 80) {\r
+            continue;\r
+        }\r
+        \r
+        lbuf->size *= 2;\r
+        lbuf->start = xrealloc (lbuf->start, lbuf->size);\r
+        \r
+        p = lbuf->start + offset;\r
+        end = lbuf->start + lbuf->size;\r
+    \r
+    }\r
+    \r
+    return lines_read;\r
+\r
+}\r
+\r
+static void remove_backslash_newlines (char *line) {\r
+\r
+    char *in = line, *out = line;\r
+    char *p;\r
+    \r
+    if (!(p = strchr (in, '\n'))) {\r
+        return;\r
+    }\r
+    \r
+    do {\r
+    \r
+        size_t out_line_len = p - in - 1;\r
+        \r
+        if (out != in) {\r
+            memmove (out, in, out_line_len);\r
+        }\r
+        \r
+        out += out_line_len;\r
+        in = p + 1;\r
+        \r
+        while (isspace ((int) *in)) {\r
+            in++;\r
+        }\r
+        \r
+        *(out++) = ' ';\r
+    \r
+    } while ((p = strchr (in, '\n')));\r
+    \r
+    memmove (out, in, strlen (in) + 1);\r
+\r
+}\r
+\r
+static void remove_comment (char *line) {\r
+\r
+    char *p;\r
+    \r
+    if ((p = strchr (line, '#'))) {\r
+        *p = '\0';\r
+    }\r
+\r
+}\r
+\r
+struct if_stack {\r
+\r
+    struct if_stack *prev;\r
+    \r
+    int ignoring;\r
+    int prev_ignoring;\r
+    int has_else;\r
+\r
+};\r
+\r
+static struct if_stack *cur_if_stack = 0;\r
+\r
+static void add_if_stack (void) {\r
+\r
+    struct if_stack *if_stack = xmalloc (sizeof *if_stack);\r
+    \r
+    if (cur_if_stack) {\r
+        if_stack->prev_ignoring = cur_if_stack->ignoring;\r
+    }\r
+    \r
+    if_stack->prev = cur_if_stack;\r
+    cur_if_stack = if_stack;\r
+\r
+}\r
+\r
+static int include_makefile (const char *src_filename, unsigned long line_no, const char *filename, int bsd) {\r
+\r
+    struct if_stack *saved_if_stack = cur_if_stack;\r
+    char *path, *new_name;\r
+    \r
+    unsigned long i;\r
+    cur_if_stack = 0;\r
+    \r
+    if (bsd) {\r
+    \r
+        char ch = *filename++, *end;\r
+        \r
+        if (ch != '<' && ch != '"') {\r
+        \r
+            fprintf (stderr, "%s: %s:%lu: *** .include filename must be delimited by '\"' or '<'. Stop.\n", program_name, src_filename, line_no);\r
+            exit (EXIT_FAILURE);\r
+        \r
+        }\r
+        \r
+        if (ch == '<') {\r
+        \r
+            if (!(end = strrchr (filename, '>'))) {\r
+            \r
+                fprintf (stderr, "%s: %s:%lu: *** unclosed .include filename. '>' expected. Stop.\n", program_name, src_filename, line_no);\r
+                exit (EXIT_FAILURE);\r
+            \r
+            }\r
+        \r
+        } else if (ch == '"') {\r
+        \r
+            if (!(end = strrchr (filename, '"'))) {\r
+            \r
+                fprintf (stderr, "%s: %s:%lu: *** unclosed .include filename. '\"' expected. Stop.\n", program_name, src_filename, line_no);\r
+                exit (EXIT_FAILURE);\r
+            \r
+            }\r
+        \r
+        }\r
+        \r
+        *end = '\0';\r
+    \r
+    }\r
+    \r
+    if (!read_makefile (filename)) {\r
+    \r
+        cur_if_stack = saved_if_stack;\r
+        return 0;\r
+    \r
+    }\r
+    \r
+    for (i = 0; i < state->nb_include_paths; i++) {\r
+    \r
+        path = state->include_paths[i];\r
+        \r
+        new_name = xmalloc (strlen (path) + strlen (filename) + 1);\r
+        sprintf (new_name, "%s%s", path, filename);\r
+        \r
+        if (!read_makefile (new_name)) {\r
+        \r
+            cur_if_stack = saved_if_stack;\r
+            \r
+            free (new_name);\r
+            return 0;\r
+        \r
+        }\r
+        \r
+        free (new_name);\r
+    \r
+    }\r
+    \r
+    fprintf (stderr, "%s: %s:%lu: *** failed to include '%s'. Stop.\n", program_name, src_filename, line_no, filename);\r
+    exit (EXIT_FAILURE);\r
+\r
+}\r
+\r
+static char *skip_whitespace (char *p) {\r
+\r
+    while (isspace ((int) *p)) {\r
+        p++;\r
+    }\r
+    \r
+    return p;\r
+\r
+}\r
+\r
+static int read_lbuf (struct linebuf *lbuf, int set_default) {\r
+\r
+    struct nameseq* filenames = 0;\r
+    int ret;\r
+    \r
+    char *cmds, *clean = 0, *depstr = 0, *q;\r
+    size_t clean_size = 0, cmds_idx = 0, cmds_sz = 256;\r
+    \r
+    char *colon, *semicolonp, *commentp;\r
+    long lines_read;\r
+    \r
+    unsigned long line_no = 1;\r
+    cmds = xmalloc (cmds_sz);\r
+    \r
+#define     record_waiting_files()                                              \\r
+    do {                                                                        \\r
+        if (filenames) {                                                        \\r
+            record_files (lbuf->filename, line_no, filenames, cmds, cmds_idx, depstr);                   \\r
+            filenames = 0;                                                      \\r
+        }                                                                       \\r
+        cmds_idx = 0;                                                           \\r
+    } while (0)\r
+    \r
+    while ((lines_read = read_line (lbuf))) {\r
+    \r
+        char *line = lbuf->start;\r
+        int after_else = 0;\r
+        \r
+        char *p, *src, *dst, *comma, *arg1 = 0, *arg2 = 0;\r
+        char ch;\r
+        \r
+        line_no = lbuf->line_no;\r
+        lbuf->line_no += lines_read;\r
+        \r
+        if (*line == '\0') {\r
+            continue;\r
+        }\r
+        \r
+        if (strlen (line) + 1 > clean_size) {\r
+        \r
+            clean_size = strlen (line) + 1;\r
+            \r
+            free (clean);\r
+            clean = xmalloc (clean_size);\r
+        \r
+        }\r
+        \r
+        strcpy (clean, line);\r
+        \r
+        remove_backslash_newlines (clean);\r
+        remove_comment (clean);\r
+        \r
+        p = skip_whitespace (clean);\r
+        \r
+        if (*p == '\0') {\r
+            continue;\r
+        }\r
+        \r
+        /**\r
+         * In command lines ifeq, etc. with space/tab before them\r
+         * should be treated as real commands, not directives.\r
+         */\r
+        if (filenames && p != clean) {\r
+            goto is_command;\r
+        }\r
+        \r
+        if (strncmp (p, ".else", 5) == 0 || strncmp (p, "else", 4) == 0) {\r
+        \r
+            if (*p == '.') {\r
+                p = skip_whitespace (p + 5);\r
+            } else {\r
+                p = skip_whitespace (p + 4);\r
+            }\r
+            \r
+            if (!cur_if_stack) {\r
+                fprintf (stderr, "%s: %s:%lu: extraneous 'else'\n", program_name, lbuf->filename, line_no);\r
+            }\r
+            \r
+            if (strncmp (p, "ifeq", 4) == 0 || strncmp (p, "ifneq", 5) == 0 || strncmp (p, "ifdef", 5) == 0 || strncmp (p, "ifndef", 6) == 0) {\r
+                after_else = 1;\r
+            } else {\r
+            \r
+                if (*p) {\r
+                    fprintf (stderr, "%s: %s:%lu: extraneous text after 'else' directive\n", program_name, lbuf->filename, line_no);\r
+                }\r
+                \r
+                if (cur_if_stack->has_else) {\r
+                \r
+                    fprintf (stderr, "%s: %s:%lu: *** only one 'else' per conditional. Stop.\n", program_name, lbuf->filename, line_no);\r
+                    exit (EXIT_FAILURE);\r
+                \r
+                }\r
+                \r
+                cur_if_stack->ignoring = (cur_if_stack->prev_ignoring || !cur_if_stack->ignoring);\r
+                cur_if_stack->has_else = 1;\r
+                \r
+                continue;\r
+            \r
+            }\r
+        \r
+        }\r
+        \r
+        if (strncmp (p, "ifeq", 4) == 0 || strncmp (p, "ifneq", 5) == 0) {\r
+        \r
+            int ifneq;\r
+            \r
+            if (strncmp (p, "ifeq", 4) == 0) {\r
+            \r
+                ifneq = 0;\r
+                p += 4;\r
+            \r
+            } else {\r
+            \r
+                ifneq = 1;\r
+                p += 5;\r
+            \r
+            }\r
+            \r
+            if (*p == '(' || *skip_whitespace (p) == '(') {\r
+            \r
+                q = skip_whitespace (skip_whitespace (p) + 1);\r
+                \r
+                if ((comma = strrchr (p, ','))) {\r
+                \r
+                    if (!isspace ((int) *p)) {\r
+                    \r
+                        fprintf (stderr, "%s: %s:%lu: *** missing separator (%s must be followed by whitespace). Stop.\n", program_name, lbuf->filename, line_no, ifneq ? "ifneq" : "ifeq");\r
+                        exit (EXIT_FAILURE);\r
+                    \r
+                    }\r
+                    \r
+                    arg1 = p = q;\r
+                    \r
+                    if (!(q = strrchr (p, ')')) || q < comma) {\r
+                        goto ifeq_invalid_syntax;\r
+                    }\r
+                    \r
+                    *comma = '\0';\r
+                    *q = '\0';\r
+                    \r
+                    for (q = comma; q > p && isspace ((int) *(q - 1));) {\r
+                        *--q = '\0';\r
+                    }\r
+                    \r
+                    for (p = comma + 1; isspace ((int) *p);) {\r
+                        p++;\r
+                    }\r
+                    \r
+                    arg2 = p;\r
+                    \r
+                    while (*p != '\0') {\r
+                        p++;\r
+                    }\r
+                \r
+                } else {\r
+                \r
+                    fprintf (stderr, "%s: %s:%lu: currently only ifeq (arg,arg) is supported\n", program_name, lbuf->filename, line_no);\r
+                    exit (EXIT_FAILURE);\r
+                \r
+                }\r
+            \r
+            } else {\r
+            \r
+                if (!*skip_whitespace (p)) {\r
+                    goto ifeq_invalid_syntax;\r
+                }\r
+                \r
+                if (!isspace ((int) *p)) {\r
+                \r
+                    fprintf (stderr, "%s: %s:%lu: *** missing separator (%s must be followed by whitespace). Stop.\n", program_name, lbuf->filename, line_no, ifneq ? "ifneq" : "ifeq");\r
+                    exit (EXIT_FAILURE);\r
+                \r
+                }\r
+                \r
+                p = skip_whitespace (p);\r
+                \r
+                if (*p == '"' || *p == '\'') {\r
+                \r
+                    ch = *p++;\r
+                    arg1 = p;\r
+                    \r
+                    while (*p != ch) {\r
+                    \r
+                        if (*p == '\0') {\r
+                            goto ifeq_invalid_syntax;\r
+                        }\r
+                        \r
+                        p++;\r
+                    \r
+                    }\r
+                    \r
+                    *p = '\0';\r
+                    p = skip_whitespace (p + 1);\r
+                    \r
+                    if (*p != '"' && *p != '\'') {\r
+                        goto ifeq_invalid_syntax;\r
+                    }\r
+                    \r
+                    ch = *p++;\r
+                    arg2 = p;\r
+                    \r
+                    while (*p != ch) {\r
+                    \r
+                        if (*p == '\0') {\r
+                            goto ifeq_invalid_syntax;\r
+                        }\r
+                        \r
+                        p++;\r
+                    \r
+                    }\r
+                    \r
+                    *p++ = '\0';\r
+                \r
+                }\r
+            \r
+            }\r
+            \r
+            p = skip_whitespace (p);\r
+            \r
+            if (*p || !arg1 || !arg2) {\r
+                fprintf (stderr, "%s: %s:%lu: extraneous text after '%s' directive\n", program_name, lbuf->filename, line_no, ifneq ? "ifneq" : "ifeq");\r
+            }\r
+            \r
+            p = variable_expand_line (lbuf->filename, line_no, xstrdup (arg1));\r
+            q = variable_expand_line (lbuf->filename, line_no, xstrdup (arg2));\r
+            \r
+            if (after_else) {\r
+                cur_if_stack->prev_ignoring |= !cur_if_stack->ignoring;\r
+            } else {\r
+                add_if_stack ();\r
+            }\r
+            \r
+            if (cur_if_stack->prev_ignoring) {\r
+                cur_if_stack->ignoring = 1;\r
+            } else {\r
+            \r
+                int is_equal = (strcmp (p, q) == 0);\r
+                cur_if_stack ->ignoring = is_equal ^ (!ifneq);\r
+            \r
+            }\r
+            \r
+            free (p);\r
+            free (q);\r
+            \r
+            continue;\r
+            \r
+        ifeq_invalid_syntax:\r
+            \r
+            fprintf (stderr, "%s: %s:%lu: *** invalid syntax in conditional. Stop.", program_name, lbuf->filename, line_no);\r
+            exit (EXIT_FAILURE);\r
+        \r
+        }\r
+        \r
+        if (strncmp (p, ".ifdef", 6) == 0 || strncmp (p, "ifdef", 5) == 0 || strncmp (p, ".ifndef", 7) == 0 || strncmp (p, "ifndef", 6) == 0) {\r
+        \r
+            struct variable *var;\r
+            int ifndef;\r
+            \r
+            if (*p == '.') {\r
+                p++;\r
+            }\r
+            \r
+            if (strncmp (p, "ifdef", 5) == 0) {\r
+            \r
+                ifndef = 0;\r
+                p += 5;\r
+            \r
+            } else {\r
+            \r
+                ifndef = 1;\r
+                p += 6;\r
+            \r
+            }\r
+            \r
+            if (!isspace ((int) *p)) {\r
+            \r
+                fprintf (stderr, "%s: %s:%lu: %s must be followed by whitespace. Stop.", program_name, lbuf->filename, line_no, ifndef ? "ifndef" : "ifdef");\r
+                exit (EXIT_FAILURE);\r
+            \r
+            }\r
+            \r
+            p = line = variable_expand_line (lbuf->filename, line_no, xstrdup (skip_whitespace (p)));\r
+            \r
+            for (; isspace ((int) *p);) {\r
+                p++;\r
+            }\r
+            \r
+            for (q = p + strlen (p); q > p && isspace ((int) *(q - 1));) {\r
+                *--q = '\0';\r
+            }\r
+            \r
+            var = variable_find (p);\r
+            \r
+            if (after_else) {\r
+                cur_if_stack->prev_ignoring |= !cur_if_stack->ignoring;\r
+            } else {\r
+                add_if_stack ();\r
+            }\r
+            \r
+            if (cur_if_stack->prev_ignoring) {\r
+                cur_if_stack->ignoring = 1;\r
+            } else {\r
+            \r
+                int is_defined = 0;\r
+                \r
+                if (var) {\r
+                    is_defined = 1;\r
+                }\r
+                \r
+                cur_if_stack->ignoring = is_defined ^ (!ifndef);\r
+            \r
+            }\r
+            \r
+            continue;\r
+        \r
+        }\r
+        \r
+        if (strncmp (p, ".endif", 6) == 0 || strncmp (p, "endif", 5) == 0) {\r
+        \r
+            if (*p == '.') {\r
+                p = skip_whitespace (p + 6);\r
+            } else {\r
+                p = skip_whitespace (p + 5);\r
+            }\r
+            \r
+            if (!cur_if_stack) {\r
+                fprintf (stderr, "%s: %s:%lu: extraneous 'endif'\n", program_name, lbuf->filename, line_no);\r
+            } else {\r
+            \r
+                struct if_stack *prev = cur_if_stack->prev;\r
+                \r
+                free (cur_if_stack);\r
+                cur_if_stack = prev;\r
+            \r
+            }\r
+            \r
+            if (*p) {\r
+                fprintf (stderr, "%s: %s:%lu: extraneous text after 'endif' directive\n", program_name, lbuf->filename, line_no);\r
+            }\r
+            \r
+            continue;\r
+        \r
+        }\r
+        \r
+    is_command:\r
+        \r
+        if (cur_if_stack && cur_if_stack->ignoring) {\r
+            continue;\r
+        }\r
+        \r
+        if (line[0] == ' ' || line[0] == '\t') {\r
+        \r
+            if (filenames) {\r
+            \r
+                while (line[0] == ' ' || line[0] == '\t') {\r
+                    line++;\r
+                }\r
+                \r
+                if (cmds_idx + strlen (line) + 1 > cmds_sz) {\r
+                \r
+                    cmds_sz = (cmds_idx + strlen (line) + 1) * 2;\r
+                    cmds = xrealloc (cmds, cmds_sz);\r
+                \r
+                }\r
+                \r
+                src = line;\r
+                dst = &cmds[cmds_idx];\r
+                \r
+                for (; *src; src++, dst++) {\r
+                \r
+                    if (src[0] == '\n' && src[-1] == '\\' && src[1] == '\t') {\r
+                    \r
+                        *dst = *src;\r
+                        \r
+                        src++;\r
+                        continue;\r
+                    \r
+                    }\r
+                    \r
+                    *dst = *src;\r
+                \r
+                }\r
+                \r
+                *dst = '\0';\r
+                \r
+                cmds_idx += dst - &cmds[cmds_idx] + 1;\r
+                cmds[cmds_idx - 1] = '\n';\r
+                \r
+                continue;\r
+            \r
+            }\r
+        \r
+        }\r
+        \r
+        if (strncmp (p, ".include", 8) == 0 || (strncmp (p, "include", 7) == 0 && (isspace ((int) p[7]) || p[7] == '\0'))) {\r
+        \r
+            int bsd = 0;\r
+            \r
+            if (*p == '.') {\r
+            \r
+                bsd = 1;\r
+                p++;\r
+            \r
+            }\r
+            \r
+            p = skip_whitespace (p + 7);\r
+            \r
+            for (q = p + strlen (p); q > p && isspace ((int) q[-1]); q--) {\r
+                ;\r
+            }\r
+            \r
+            *q = '\0';\r
+            p = line = variable_expand_line (lbuf->filename, line_no, xstrdup (p));\r
+            \r
+            while (1) {\r
+            \r
+                char saved_ch;\r
+                \r
+                for (; isspace ((int) *p); p++) {\r
+                    ;\r
+                }\r
+                \r
+                for (q = p; *q && !isspace ((int) *q); q++) {\r
+                    ;\r
+                }\r
+                \r
+                if (q == p) {\r
+                    break;\r
+                }\r
+                \r
+                saved_ch = *q;\r
+                *q = '\0';\r
+                \r
+                if ((ret = include_makefile (lbuf->filename, line_no, p, bsd))) {\r
+                    return ret;\r
+                }\r
+                \r
+                *q = saved_ch;\r
+                \r
+                p = q;\r
+            \r
+            }\r
+            \r
+            free (line);\r
+            continue;\r
+        \r
+        }\r
+        \r
+        if (*p == '$') {\r
+        \r
+            variable_expand_line (lbuf->filename, line_no, p);\r
+            continue;\r
+        \r
+        } else if (strchr (p, '=')) {\r
+        \r
+            record_waiting_files ();\r
+            \r
+            parse_var_line (lbuf->filename, line_no, p, VAR_ORIGIN_FILE);\r
+            continue;\r
+        \r
+        }\r
+        \r
+        record_waiting_files ();\r
+        \r
+        semicolonp = strchr (line, ';');\r
+        commentp = strchr (line, '#');\r
+        \r
+        if (commentp && semicolonp && (commentp < semicolonp)) {\r
+        \r
+            *commentp = '\0';\r
+            semicolonp = 0;\r
+        \r
+        } else if (semicolonp) {\r
+            *(semicolonp++) = '\0';\r
+        }\r
+        \r
+        remove_backslash_newlines (line);\r
+        line = variable_expand_line (lbuf->filename, line_no, xstrdup (line));\r
+        \r
+        if (!(colon = strchr (line, ':'))) {\r
+        \r
+            if (*(p = skip_whitespace (line))) {\r
+                fprintf (stderr, "%s: %s:%lu: missing ':' in rule line!\n", program_name, lbuf->filename, line_no);\r
+            }\r
+            \r
+            free (line);\r
+            continue;\r
+        \r
+        }\r
+        \r
+        *colon = '\0';\r
+        \r
+        filenames = parse_nameseq (line, sizeof (*filenames));\r
+        depstr = xstrdup (colon + 1);\r
+        \r
+        free (line);\r
+        \r
+        if (semicolonp) {\r
+        \r
+            if (cmds_idx + strlen (semicolonp) + 1 > cmds_sz) {\r
+            \r
+                cmds_sz = (cmds_idx + strlen (semicolonp) + 1) * 2;\r
+                cmds = xrealloc (cmds, cmds_sz);\r
+            \r
+            }\r
+            \r
+            memcpy (&(cmds[cmds_idx]), semicolonp, strlen (semicolonp) + 1);\r
+            cmds_idx += strlen (semicolonp) + 1;\r
+        \r
+        }\r
+        \r
+        if (set_default && default_goal_var->value[0] == '\0') {\r
+        \r
+            struct nameseq *ns;\r
+            \r
+            for (ns = filenames; ns; ns = ns->next) {\r
+            \r
+                if ((ns->name[0] == '.') && strchr (ns->name, '\\') == 0 && strchr (ns->name, '/') == 0) {\r
+                    continue;\r
+                }\r
+                \r
+                free (default_goal_var->value);\r
+                \r
+                default_goal_var->value = xstrdup (ns->name);\r
+                break;\r
+            \r
+            }\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    record_waiting_files ();\r
+    \r
+    if (*(skip_whitespace (lbuf->start))) {\r
+        line_no++;\r
+    }\r
+    \r
+    free (clean);\r
+    free (cmds);\r
+    \r
+    if (cur_if_stack) {\r
+    \r
+        struct if_stack *prev;\r
+        \r
+        for (; cur_if_stack; cur_if_stack = prev) {\r
+        \r
+            prev = cur_if_stack->prev;\r
+            free (cur_if_stack);\r
+        \r
+        }\r
+        \r
+        fprintf (stderr, "%s: %s:%lu: *** missing 'endif'. Stop.\n", program_name, lbuf->filename, line_no);\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+int read_makefile (const char *filename) {\r
+\r
+    struct linebuf lbuf;\r
+    struct variable *makefile_list;\r
+    \r
+    char *new_value;\r
+    int ret;\r
+    \r
+    if (strcmp (filename, "-") == 0) {\r
+    \r
+        filename = "<stdin>";\r
+        lbuf.f = stdin;\r
+    \r
+    } else if (!(lbuf.f = fopen (filename, "r"))) {\r
+        return 1;\r
+    }\r
+    \r
+    lbuf.size = 256;\r
+    \r
+    lbuf.filename = filename;\r
+    lbuf.line_no = 1;\r
+    \r
+    lbuf.start = xmalloc (lbuf.size);\r
+    \r
+    if ((makefile_list = variable_find ("MAKEFILE_LIST"))) {\r
+    \r
+        unsigned long old_len = strlen (makefile_list->value);\r
+        \r
+        new_value = xmalloc (old_len + 1 + strlen (filename) + 1);\r
+        sprintf (new_value, "%s %s", makefile_list->value, filename);\r
+        \r
+        variable_change ("MAKEFILE_LIST", new_value, VAR_ORIGIN_FILE);\r
+    \r
+    } else {\r
+    \r
+        new_value = xmalloc (strlen (filename) + 1);\r
+        sprintf (new_value, "%s", filename);\r
+        \r
+        variable_change ("MAKEFILE_LIST", new_value, VAR_ORIGIN_FILE);\r
+    \r
+    }\r
+    \r
+    ret = read_lbuf (&lbuf, 1);\r
+    free (lbuf.start);\r
+    \r
+    if (lbuf.f != stdin) {\r
+        fclose (lbuf.f);\r
+    }\r
+    \r
+    return ret;\r
+\r
+}\r
+\r
+void read_memory_makefile (const char *filename, unsigned long line_no, char *memory) {\r
+\r
+    struct if_stack *saved_if_stack;\r
+    struct linebuf lbuf;\r
+    \r
+    lbuf.size = 256;\r
+    lbuf.f = 0;\r
+    \r
+    lbuf.start = xmalloc (lbuf.size);\r
+    lbuf.memory = memory;\r
+    \r
+    lbuf.filename = filename;\r
+    lbuf.line_no = line_no;\r
+    \r
+    saved_if_stack = cur_if_stack;\r
+    cur_if_stack = 0;\r
+    \r
+    read_lbuf (&lbuf, 1);\r
+    free (lbuf.start);\r
+    \r
+    cur_if_stack = saved_if_stack;\r
+\r
+}\r
+\r
+void *parse_nameseq (char *line, size_t size) {\r
+\r
+    struct nameseq *start = 0;\r
+    struct nameseq **pp = &start;\r
+    \r
+    char *p, *temp;\r
+    temp = xmalloc (strlen (line) + 1);\r
+    \r
+#define     add_nameseq(_name)                              \\r
+    do {                                                    \\r
+        *pp = xmalloc (size);                               \\r
+        (*pp)->name = xstrdup (_name);                      \\r
+        pp = &((*pp)->next);                                \\r
+    } while (0)\r
+    \r
+    p = line;\r
+    \r
+    while (1) {\r
+    \r
+        char *p2;\r
+        \r
+        while (isspace ((int) *p)) {\r
+            p++;\r
+        }\r
+        \r
+        if (*p == '\0') {\r
+            break;\r
+        }\r
+        \r
+        p2 = p;\r
+        \r
+        while (*p2 && !isspace ((int) *p2)) {\r
+            p2++;\r
+        }\r
+        \r
+        memcpy (temp, p, p2 - p);\r
+        temp[p2 - p] = '\0';\r
+        \r
+        add_nameseq (temp);\r
+        p = p2;\r
+    \r
+    }\r
+    \r
+#undef      add_nameseq\r
+    \r
+    free (temp);\r
+    return start;\r
+\r
+}\r
+\r
+void record_files (const char *filename, unsigned long line_no, struct nameseq *filenames, char *cmds, size_t cmds_idx, char *depstr) {\r
+\r
+    struct commands *cmds_p;\r
+    \r
+    struct dep *deps;\r
+    struct nameseq *ns, *old_ns;\r
+    \r
+    if (cmds_idx > 0) {\r
+    \r
+        cmds_p = xmalloc (sizeof (*cmds_p));\r
+        \r
+        cmds_p->text = xstrndup (cmds, cmds_idx);\r
+        cmds_p->len = cmds_idx;\r
+    \r
+    } else {\r
+        cmds_p = 0;\r
+    }\r
+    \r
+    if (depstr) {\r
+        deps = parse_nameseq (depstr, sizeof (*deps));\r
+    } else {\r
+        deps = 0;\r
+    }\r
+    \r
+    for (ns = filenames, old_ns = 0; ns; old_ns = ns, ns = ns->next, free (old_ns->name), free (old_ns)) {\r
+    \r
+        if (ns->name[0] == '.' && !strchr (ns->name, '\\') && !strchr (ns->name, '/')) {\r
+            rule_add_suffix (filename, line_no - 1, ns->name, cmds_p);\r
+        } else {\r
+            rule_add (filename, line_no - 1, ns->name, deps, cmds_p);\r
+        }\r
+    \r
+    }\r
+    \r
+    free (depstr);\r
+\r
+}\r
index d36483b6d449496e9dc812cb6b5388fd61351a73..6d4bb89c304d9eb899ae58d3c6fb417af260d196 100644 (file)
--- a/report.c
+++ b/report.c
-/******************************************************************************
- * @file            report.c
- *****************************************************************************/
-#include    <stdarg.h>
-#include    <stdio.h>
-#include    <string.h>
-
-#include    <xmake/report.h>
-
-unsigned long errors = 0;
-
-#ifndef     __PDOS__
-#if     defined (_WIN32)
-# include   <windows.h>
-static int OriginalConsoleColor = -1;
-#endif
-
-static void reset_console_color (void) {
-
-#if     defined (_WIN32)
-
-    HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE);
-    
-    if (OriginalConsoleColor == -1) { return; }
-    
-    SetConsoleTextAttribute (hStdError, OriginalConsoleColor);
-    OriginalConsoleColor = -1;
-
-#else
-
-    fprintf (stderr, "\033[0m");
-
-#endif
-
-}
-
-static void set_console_color (int color) {
-
-#if     defined (_WIN32)
-
-    HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE);
-    WORD wColor;
-    
-    if (OriginalConsoleColor == -1) {
-    
-        CONSOLE_SCREEN_BUFFER_INFO csbi;
-        
-        if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) {
-            return;
-        }
-        
-        OriginalConsoleColor = csbi.wAttributes;
-    
-    }
-    
-    wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF);
-    SetConsoleTextAttribute (hStdError, wColor);
-
-#else
-
-    fprintf (stderr, "\033[%dm", color);
-
-#endif
-
-}
-#endif
-
-static void output_message (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, va_list ap) {
-
-    if (filename) {
-    
-        if (lineno == 0) {
-            fprintf (stderr, "%s: ", filename);
-        } else {
-            fprintf (stderr, "%s:", filename);
-        }
-    
-    }
-    
-    if (lineno > 0) {
-        fprintf (stderr, "%lu: ", lineno);
-    }
-    
-    if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) {
-    
-#ifndef     __PDOS__
-        set_console_color (COLOR_ERROR);
-#endif
-        
-        if (type == REPORT_ERROR) {
-            fprintf (stderr, "error:");
-        } else {
-            fprintf (stderr, "fatal error:");
-        }
-    
-    } else if (type == REPORT_INTERNAL_ERROR) {
-    
-#ifndef     __PDOS__
-        set_console_color (COLOR_INTERNAL_ERROR);
-#endif
-        
-        fprintf (stderr, "internal error:");
-    
-    } else if (type == REPORT_WARNING) {
-    
-#ifndef     __PDOS__
-        set_console_color (COLOR_WARNING);
-#endif
-        
-        fprintf (stderr, "warning:");
-    
-    }
-    
-#ifndef     __PDOS__
-    reset_console_color ();
-#endif
-    
-    fprintf (stderr, " ");
-    vfprintf (stderr, fmt, ap);
-    fprintf (stderr, "\n");
-    
-    if (type != REPORT_WARNING) {
-        ++errors;
-    }
-
-}
-
-unsigned long get_error_count (void) {
-    return errors;
-}
-
-void report_at (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, ...) {
-
-    va_list ap;
-    
-    va_start (ap, fmt);
-    output_message (filename, lineno, type, fmt, ap);
-    va_end (ap);
-
-}
+/******************************************************************************\r
+ * @file            report.c\r
+ *****************************************************************************/\r
+#include    <stdarg.h>\r
+#include    <stdio.h>\r
+#include    <string.h>\r
+\r
+#include    <xmake/report.h>\r
+\r
+unsigned long errors = 0;\r
+\r
+#ifndef     __PDOS__\r
+#if     defined (_WIN32)\r
+# include   <windows.h>\r
+static int OriginalConsoleColor = -1;\r
+#endif\r
+\r
+static void reset_console_color (void) {\r
+\r
+#if     defined (_WIN32)\r
+\r
+    HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE);\r
+    \r
+    if (OriginalConsoleColor == -1) { return; }\r
+    \r
+    SetConsoleTextAttribute (hStdError, OriginalConsoleColor);\r
+    OriginalConsoleColor = -1;\r
+\r
+#else\r
+\r
+    fprintf (stderr, "\033[0m");\r
+\r
+#endif\r
+\r
+}\r
+\r
+static void set_console_color (int color) {\r
+\r
+#if     defined (_WIN32)\r
+\r
+    HANDLE hStdError = GetStdHandle (STD_ERROR_HANDLE);\r
+    WORD wColor;\r
+    \r
+    if (OriginalConsoleColor == -1) {\r
+    \r
+        CONSOLE_SCREEN_BUFFER_INFO csbi;\r
+        \r
+        if (!GetConsoleScreenBufferInfo (hStdError, &csbi)) {\r
+            return;\r
+        }\r
+        \r
+        OriginalConsoleColor = csbi.wAttributes;\r
+    \r
+    }\r
+    \r
+    wColor = (OriginalConsoleColor & 0xF0) + (color & 0xF);\r
+    SetConsoleTextAttribute (hStdError, wColor);\r
+\r
+#else\r
+\r
+    fprintf (stderr, "\033[%dm", color);\r
+\r
+#endif\r
+\r
+}\r
+#endif\r
+\r
+static void output_message (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, va_list ap) {\r
+\r
+    if (filename) {\r
+    \r
+        if (lineno == 0) {\r
+            fprintf (stderr, "%s: ", filename);\r
+        } else {\r
+            fprintf (stderr, "%s:", filename);\r
+        }\r
+    \r
+    }\r
+    \r
+    if (lineno > 0) {\r
+        fprintf (stderr, "%lu: ", lineno);\r
+    }\r
+    \r
+    if (type == REPORT_ERROR || type == REPORT_FATAL_ERROR) {\r
+    \r
+#ifndef     __PDOS__\r
+        set_console_color (COLOR_ERROR);\r
+#endif\r
+        \r
+        if (type == REPORT_ERROR) {\r
+            fprintf (stderr, "error:");\r
+        } else {\r
+            fprintf (stderr, "fatal error:");\r
+        }\r
+    \r
+    } else if (type == REPORT_INTERNAL_ERROR) {\r
+    \r
+#ifndef     __PDOS__\r
+        set_console_color (COLOR_INTERNAL_ERROR);\r
+#endif\r
+        \r
+        fprintf (stderr, "internal error:");\r
+    \r
+    } else if (type == REPORT_WARNING) {\r
+    \r
+#ifndef     __PDOS__\r
+        set_console_color (COLOR_WARNING);\r
+#endif\r
+        \r
+        fprintf (stderr, "warning:");\r
+    \r
+    }\r
+    \r
+#ifndef     __PDOS__\r
+    reset_console_color ();\r
+#endif\r
+    \r
+    fprintf (stderr, " ");\r
+    vfprintf (stderr, fmt, ap);\r
+    fprintf (stderr, "\n");\r
+    \r
+    if (type != REPORT_WARNING) {\r
+        ++errors;\r
+    }\r
+\r
+}\r
+\r
+unsigned long get_error_count (void) {\r
+    return errors;\r
+}\r
+\r
+void report_at (const char *filename, unsigned long lineno, enum report_type type, const char *fmt, ...) {\r
+\r
+    va_list ap;\r
+    \r
+    va_start (ap, fmt);\r
+    output_message (filename, lineno, type, fmt, ap);\r
+    va_end (ap);\r
+\r
+}\r
diff --git a/rule.c b/rule.c
index 19c7484f26c6ed5cc568533f4614a2c8957ba126..7338d7ccb3e6158acd99c5811eccd98b4892c710 100644 (file)
--- a/rule.c
+++ b/rule.c
@@ -1,73 +1,73 @@
-/******************************************************************************
- * @file            rule.c
- *****************************************************************************/
-#include    <string.h>
-
-#include    <xmake/command.h>
-#include    <xmake/dep.h>
-#include    <xmake/hashtab.h>
-#include    <xmake/lib.h>
-#include    <xmake/rule.h>
-
-static struct hashtab hashtab_rules = { 0 };
-struct suffix_rule *suffix_rules = 0;
-
-struct rule *rule_find (const char *name) {
-
-    struct hashtab_name *key;
-    
-    if (!(key = hashtab_get_key (&hashtab_rules, name))) {
-        return 0;
-    }
-    
-    return hashtab_get (&hashtab_rules, key);
-
-}
-
-void rule_add (const char *filename, unsigned long line_no, char *name, struct dep *deps, struct commands *cmds) {
-
-    struct hashtab_name *key;
-    struct rule *r;
-    
-    if (!(key = hashtab_alloc_name (xstrdup (name)))) {
-        return;
-    }
-    
-    r = xmalloc (sizeof (*r));
-    
-    r->name = xstrdup (name);
-    r->deps = deps;
-    r->cmds = cmds;
-    
-    r->filename = xstrdup (filename);
-    r->line_no = line_no;
-    
-    hashtab_put (&hashtab_rules, key, r);
-
-}
-
-void rule_add_suffix (const char *filename, unsigned long line_no, char *name, struct commands *cmds) {
-
-    struct suffix_rule *s = xmalloc (sizeof (*s));
-    char *p;
-    
-    if ((p = strchr (name + 1, '.'))) {
-    
-        s->second = xstrdup (p);
-        *p = '\0';
-    
-    }
-    
-    s->first = xstrdup (name);
-    
-    s->cmds = cmds;
-    s->next = suffix_rules;
-    
-    s->filename = xstrdup (filename);
-    s->line_no = line_no;
-    
-    suffix_rules = s;
-
-}
-
-void rules_init (void) {}
+/******************************************************************************\r
+ * @file            rule.c\r
+ *****************************************************************************/\r
+#include    <string.h>\r
+\r
+#include    <xmake/command.h>\r
+#include    <xmake/dep.h>\r
+#include    <xmake/hashtab.h>\r
+#include    <xmake/lib.h>\r
+#include    <xmake/rule.h>\r
+\r
+static struct hashtab hashtab_rules = { 0 };\r
+struct suffix_rule *suffix_rules = 0;\r
+\r
+struct rule *rule_find (const char *name) {\r
+\r
+    struct hashtab_name *key;\r
+    \r
+    if (!(key = hashtab_get_key (&hashtab_rules, name))) {\r
+        return 0;\r
+    }\r
+    \r
+    return hashtab_get (&hashtab_rules, key);\r
+\r
+}\r
+\r
+void rule_add (const char *filename, unsigned long line_no, char *name, struct dep *deps, struct commands *cmds) {\r
+\r
+    struct hashtab_name *key;\r
+    struct rule *r;\r
+    \r
+    if (!(key = hashtab_alloc_name (xstrdup (name)))) {\r
+        return;\r
+    }\r
+    \r
+    r = xmalloc (sizeof (*r));\r
+    \r
+    r->name = xstrdup (name);\r
+    r->deps = deps;\r
+    r->cmds = cmds;\r
+    \r
+    r->filename = xstrdup (filename);\r
+    r->line_no = line_no;\r
+    \r
+    hashtab_put (&hashtab_rules, key, r);\r
+\r
+}\r
+\r
+void rule_add_suffix (const char *filename, unsigned long line_no, char *name, struct commands *cmds) {\r
+\r
+    struct suffix_rule *s = xmalloc (sizeof (*s));\r
+    char *p;\r
+    \r
+    if ((p = strchr (name + 1, '.'))) {\r
+    \r
+        s->second = xstrdup (p);\r
+        *p = '\0';\r
+    \r
+    }\r
+    \r
+    s->first = xstrdup (name);\r
+    \r
+    s->cmds = cmds;\r
+    s->next = suffix_rules;\r
+    \r
+    s->filename = xstrdup (filename);\r
+    s->line_no = line_no;\r
+    \r
+    suffix_rules = s;\r
+\r
+}\r
+\r
+void rules_init (void) {}\r
index b3912391bac13bef74f97aa21452ea801ca67563..4b32952b4c4e53e4105ce65626e65e6cf14fb4f0 100644 (file)
-/******************************************************************************
- * @file            variable.c
- *****************************************************************************/
-#include    <ctype.h>
-#include    <stdio.h>
-#include    <stdlib.h>
-#include    <string.h>
-
-#include    <xmake/hashtab.h>
-#include    <xmake/lib.h>
-#include    <xmake/read.h>
-#include    <xmake/report.h>
-#include    <xmake/variable.h>
-#include    <xmake/xmake.h>
-
-struct linebuf {
-
-    char *start;
-    unsigned long size;
-    
-    FILE *f;
-
-};
-
-struct builtin_function {
-
-    const char *name;
-    char *(*func) (const char *filename, unsigned long line_no, char *input);
-
-};
-
-static char *func_eval (const char *filename, unsigned long line_no, char *input) {
-
-    read_memory_makefile (filename, line_no, input);
-    return 0;
-
-}
-
-static void read_line (struct linebuf *lbuf) {
-
-    char *end = lbuf->start + lbuf->size;
-    char *p = lbuf->start;
-    
-    while (fgets (p, end - p, lbuf->f)) {
-    
-        size_t offset;
-        
-        p += strlen (p);
-        offset = p - lbuf->start;
-        
-        if (p[-1] == '\n') {
-        
-            p--;
-            
-            if (p[-1] == '\r') {
-                p[-1] = ' ';
-            }
-        
-        }
-        
-        if (end - p >= 80) {
-            continue;
-        }
-        
-        lbuf->size *= 2;
-        lbuf->start = xrealloc (lbuf->start, lbuf->size);
-        
-        p = lbuf->start + offset;
-        end = lbuf->start + lbuf->size;
-    
-    }
-
-}
-
-static char *func_error (const char *filename, unsigned long line_no, char *input) {
-
-    fprintf (stderr, "%s: %s: %lu: *** %s. Stop.\n", program_name, filename, line_no, input);
-    exit (EXIT_FAILURE);
-
-}
-
-static char *func_shell (const char *filename, unsigned long line_no, char *input) {
-
-    struct linebuf lbuf;
-    FILE *fp;
-    
-    (void) filename;
-    (void) line_no;
-    
-    if (!(fp = popen (input, "rb"))) {
-        return 0;
-    }
-    
-    lbuf.size = 256;
-    
-    lbuf.start = xmalloc (lbuf.size);
-    lbuf.f = fp;
-    
-    read_line (&lbuf);
-    pclose(fp);
-    
-    return lbuf.start;
-
-}
-
-static struct builtin_function builtin_functions[] ={
-
-    {   "error",    &func_error     },
-    {   "shell",    &func_shell     },
-    
-    {   "eval",     &func_eval      },
-    {   0,          0               }
-
-};
-
-static struct hashtab hashtab_builtin = { 0 };
-static struct hashtab hashtab_vars = { 0 };
-
-static struct builtin_function *find_builtin_function (const char *name) {
-
-    struct hashtab_name *key;
-    
-    if ((key = hashtab_get_key (&hashtab_builtin, name))) {
-        return hashtab_get (&hashtab_builtin, key);
-    }
-    
-    return 0;
-
-}
-
-static char *variable_suffix_replace (char *body, const char *from_s, const char *to_s) {
-
-    char *new_body = xstrdup (body);
-    char *p;
-    
-    while ((p = strstr (new_body, from_s))) {
-    
-        if (strlen (from_s) == strlen (to_s)) {
-            memcpy (p, to_s, strlen (to_s));
-        } else if (strlen (from_s) > strlen (to_s)) {
-        
-            size_t rem = strlen (from_s) - strlen (to_s);
-            memcpy (p, to_s, strlen (to_s));
-            
-            while (rem--) {
-                p[strlen (to_s) + rem] = ' ';
-            }
-        
-        } else {
-        
-            size_t rem = strlen (to_s) - strlen (from_s);
-            
-            new_body = xrealloc (new_body, strlen (new_body) + rem);
-            memmove (p + rem, p, strlen (p) + 1);
-            memcpy (p, to_s, strlen (to_s));
-        
-        }
-    
-    }
-    
-    return new_body;
-
-}
-
-struct variable *variable_add (char *name, char *value, enum variable_origin origin) {
-
-    struct hashtab_name *key;
-    struct variable *var;
-    
-    if (!(key = hashtab_alloc_name (name))) {
-    
-        report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for name '%s'", name);
-        exit (EXIT_FAILURE);
-    
-    }
-    
-    var = xmalloc (sizeof (*var));
-    var->flavor = VAR_FLAVOR_RECURSIVELY_EXPANDED;
-    var->name = name;
-    var->origin = origin;
-    var->value = value;
-    
-    if (hashtab_put (&hashtab_vars, key, var)) {
-    
-        report_at (program_name, 0, REPORT_FATAL_ERROR, "failed to insert variable '%s' into hashtab", var->name);
-        exit (EXIT_FAILURE);
-    
-    }
-    
-    return var;
-
-}
-
-struct variable *variable_change (char *name, char *value, enum variable_origin origin) {
-
-    struct variable *var;
-    
-    if (!(var = variable_find (name))) {
-        return variable_add (xstrdup (name), value, origin);
-    }
-    
-    switch (origin) {
-    
-        case VAR_ORIGIN_AUTOMATIC:
-        case VAR_ORIGIN_COMMAND_LINE:
-        
-            break;
-        
-        case VAR_ORIGIN_FILE:
-        
-            if (var->origin == VAR_ORIGIN_FILE) {
-                break;
-            }
-            
-            free (value);
-            return 0;
-    
-    }
-    
-    free (var->value);
-    
-    var->value = value;
-    var->origin = origin;
-    
-    return var;
-
-}
-
-struct variable *variable_find (char *name) {
-
-    struct hashtab_name *key;
-    
-    if (!(key = hashtab_get_key (&hashtab_vars, name))) {
-        return 0;
-    }
-    
-    return hashtab_get (&hashtab_vars, key);
-
-}
-
-char *variable_expand_line (const char *filename, unsigned long line_no, char *line) {
-
-    size_t pos = 0;
-    
-    while (line[pos]) {
-    
-        if (line[pos] == '$') {
-        
-            char *new, *replacement = "";
-            char *p_after_variable;
-            
-            struct variable *var = 0;
-            char *alloc_replacement = 0;
-            
-            struct builtin_function *func;
-            char saved_ch;
-            
-            if (line[pos + 1] == '$') {
-            
-                p_after_variable = line + pos + 2;
-                pos += 1;
-            
-            } else if (line[pos + 1] == '(' || line[pos + 1] == '{') {
-            
-                char *body = line + pos + 2;
-                char *q = body, *content;
-                
-                int paren_inbalance = 1;
-                char opening_paren = line[pos + 1];
-                
-                while (paren_inbalance) {
-                
-                    if (*q == opening_paren) {
-                        paren_inbalance++;
-                    } else if (*q == ')' && opening_paren == '(') {
-                        paren_inbalance--;
-                    } else if (*q == '}' && opening_paren == '{') {
-                        paren_inbalance--;
-                    } else if (*q == '\0') {
-                    
-                        fprintf (stderr, "%s: *** unterminated variable reference. Stop.\n", program_name);
-                        exit (EXIT_FAILURE);
-                    
-                    }
-                    
-                    q++;
-                
-                }
-                
-                q--;
-                
-                p_after_variable = q + 1;
-                content = variable_expand_line (filename, line_no, xstrndup (body, q - body));
-                
-                for (q = content; *q && !isspace ((int) *q);) {
-                    q++;
-                }
-                
-                saved_ch = *q;
-                *q = '\0';
-                
-                func = find_builtin_function (content);
-                *q = saved_ch;
-                
-                if (func) {
-                
-                    for (; isspace ((int) *q);) {
-                        q++;
-                    }
-                    
-                    if ((alloc_replacement = func->func (filename, line_no, q))) {
-                    
-                        new = xmalloc (pos + strlen (alloc_replacement) + 1);
-                        
-                        memcpy (new, line, pos);
-                        memcpy (new + pos, alloc_replacement, strlen (alloc_replacement));
-                        
-                        free (alloc_replacement);
-                        return new;
-                    
-                    }
-                
-                } else if ((q = strchr (content, '='))) {
-                
-                    char *colon = strchr (content, ':');
-                    
-                    if (colon && colon != content && colon < q) {
-                    
-                        char *from, *to, *p;
-                        *colon = '\0';
-                        
-                        var = variable_find (content);
-                        
-                        for (from = colon + 1; isspace ((int) *from); from++) {
-                            ;
-                        }
-                        
-                        for (p = q; p != from && isspace ((int) p[-1]); p--) {
-                            ;
-                        }
-                        
-                        *p = '\0';
-                        
-                        for (to = q + 1; isspace ((int) *to); to++) {
-                            ;
-                        }
-                        
-                        for (p = to + strlen (to); p != to && isspace ((int) p[-1]); p--) {
-                            ;
-                        }
-                        
-                        *p = '\0';
-                        
-                        if (*from && var) {
-                            alloc_replacement = variable_suffix_replace (var->value, from, to);
-                        }
-                    
-                    }
-                
-                } else {
-                    var = variable_find (content);
-                }
-                
-                free (content);
-            
-            } else if (line[pos + 1]) {
-            
-                char name[2] = { 0, 0 };
-                
-                p_after_variable = line + pos + 2;
-                name[0] = line[pos + 1];
-                
-                var = variable_find (name);
-            
-            } else {
-                p_after_variable = line + pos + 1;
-            }
-            
-            if (var) {
-                replacement = var->value;
-            }
-            
-            if (alloc_replacement) {
-                replacement = alloc_replacement;
-            }
-            
-            new = xmalloc (pos + strlen (replacement) + strlen (p_after_variable) + 1);
-            
-            memcpy (new, line, pos);
-            memcpy (new + pos, replacement, strlen (replacement));
-            memcpy (new + pos + strlen (replacement), p_after_variable, strlen (p_after_variable) + 1);
-            
-            free (line);
-            line = new;
-            
-            if (!alloc_replacement && var && var->flavor == VAR_FLAVOR_SIMPLY_EXPANDED) {
-                pos += strlen (replacement);
-            }
-            
-            free (alloc_replacement);
-            continue;
-            
-        
-        }
-        
-        pos++;
-    
-    }
-    
-    return line;
-
-}
-
-void parse_var_line (const char *filename, unsigned long line_no, char *line, enum variable_origin origin) {
-
-    enum {
-        VAR_ASSIGN,
-        VAR_CONDITIONAL_ASSIGN,
-        VAR_APPEND,
-        VAR_SHELL
-    } opt = VAR_ASSIGN;
-    
-    enum variable_flavor flavor = VAR_FLAVOR_RECURSIVELY_EXPANDED;
-    struct variable *var;
-    
-    char *var_name, *new_value;
-    char *equals_sign, *p;
-    
-    if (!(equals_sign = strchr (line, '='))) {
-    
-        fprintf (stderr, "+++ invalid variable definition!\n");
-        return;
-    
-    }
-    
-    p = equals_sign;
-    
-    switch (p - line) {
-    
-        default:
-        
-            if (p[-1] == ':' && p[-2] == ':' && p[-3] == ':') {
-            
-                flavor = VAR_FLAVOR_IMMEDIATELY_EXPANDED;
-                
-                p -= 3;
-                break;
-            
-            }
-            
-            /* fall through */
-        
-        case 2:
-        
-            if (p[-1] == ':' && p[-2] == ':') {
-            
-                flavor = VAR_FLAVOR_SIMPLY_EXPANDED;
-                
-                p -= 2;
-                break;
-            
-            }
-            
-            /* fall through */
-        
-        case 1:
-        
-            if (p[-1] == ':') {
-            
-                flavor = VAR_FLAVOR_SIMPLY_EXPANDED;
-                
-                p--;
-                break;
-            
-            }
-            
-            if (p[-1] == '?') {
-            
-                opt = VAR_CONDITIONAL_ASSIGN;
-                
-                p--;
-                break;
-            
-            }
-            
-            if (p[-1] == '+') {
-            
-                opt = VAR_APPEND;
-                
-                p--;
-                break;
-            
-            }
-            
-            if (p[-1] == '!') {
-            
-                opt = VAR_SHELL;
-                
-                p--;
-                break;
-            
-            }
-            
-            break;
-        
-        case 0:
-        
-            break;
-    
-    }
-    
-    for (; p > line && isspace ((int) p[-1]); p--) {
-        ;
-    }
-    
-    var_name = variable_expand_line (filename, line_no, xstrndup (line, p - line));
-    
-    if (*var_name == '\0') {
-    
-        fprintf (stderr, "%s: *** empty variable name. Stop.\n", program_name);
-        exit (EXIT_FAILURE);
-    
-    }
-    
-    var = variable_find (var_name);
-    
-    if (opt == VAR_CONDITIONAL_ASSIGN && var) {
-    
-        free (var_name);
-        return;
-    
-    }
-    
-    for (p = equals_sign; isspace ((int) p[1]); p++) {
-        ;
-    }
-    
-    new_value = xstrdup (p + 1);
-    
-    if (opt == VAR_ASSIGN || opt == VAR_CONDITIONAL_ASSIGN) {
-    
-        switch (flavor) {
-        
-            case VAR_FLAVOR_RECURSIVELY_EXPANDED:
-            
-                break;
-            
-            case VAR_FLAVOR_SIMPLY_EXPANDED:
-            
-                new_value = variable_expand_line (filename, line_no, new_value);
-                break;
-            
-            case VAR_FLAVOR_IMMEDIATELY_EXPANDED: {
-            
-                size_t dollar_count;
-                char *temp, *p2;
-                
-                new_value = variable_expand_line (filename, line_no, new_value);
-                
-                for (dollar_count = 0, p = new_value; *p; p++) {
-                
-                    if (*p == '$') {
-                        dollar_count++;
-                    }
-                
-                }
-                
-                temp = xmalloc (strlen (new_value) + 1 + dollar_count);
-                
-                for (p = new_value, p2 = temp; *p; p++, p2++) {
-                
-                    *p2 = *p;
-                    
-                    if (*p == '$') {
-                    
-                        p2[1] = '$';
-                        p2++;
-                    
-                    }
-                    
-                    *p2 = '\0';
-                    
-                    free (new_value);
-                    new_value = temp;
-                
-                }
-                
-                break;
-            
-            }
-        
-        }
-    
-    } else if (opt == VAR_APPEND) {
-    
-        struct variable *var;
-        
-        if ((var = variable_find (var_name))) {
-        
-            char *temp = xstrdup (new_value);
-            free (new_value);
-            
-            new_value = xmalloc (strlen (var->value) + 1 + strlen (temp) + 1);
-            sprintf (new_value, "%s %s", var->value, temp);
-            
-            free (temp);
-        
-        }
-    
-    } else if (opt == VAR_SHELL) {
-    
-        char *temp = xstrdup (new_value);
-        free (new_value);
-        
-        new_value = variable_expand_line (filename, line_no, func_shell (filename, line_no, temp));
-        free (temp);
-    
-    }
-    
-    if ((var = variable_change (var_name, new_value, origin))) {
-        var->flavor = flavor;
-    }
-    
-    free (var_name);
-
-}
-
-void variables_init (void) {
-
-    struct builtin_function *builtin;
-    struct hashtab_name *key;
-    
-    for (builtin = builtin_functions; builtin->name; builtin++) {
-    
-        if (!(key = hashtab_alloc_name (builtin->name))) {
-            continue;
-        }
-        
-        hashtab_put (&hashtab_builtin, key, builtin);
-    
-    }
-
-}
+/******************************************************************************\r
+ * @file            variable.c\r
+ *****************************************************************************/\r
+#include    <ctype.h>\r
+#include    <stdlib.h>\r
+#include    <string.h>\r
+\r
+#if     !defined (_WIN32) && !defined (__WIN32__) && !defined (__MSDOS__)\r
+# define        __USE_POSIX\r
+#endif\r
+\r
+#include    <stdio.h>\r
+\r
+#include    <xmake/hashtab.h>\r
+#include    <xmake/lib.h>\r
+#include    <xmake/read.h>\r
+#include    <xmake/report.h>\r
+#include    <xmake/variable.h>\r
+#include    <xmake/xmake.h>\r
+\r
+struct linebuf {\r
+\r
+    char *start;\r
+    unsigned long size;\r
+    \r
+    FILE *f;\r
+\r
+};\r
+\r
+struct builtin_function {\r
+\r
+    const char *name;\r
+    char *(*func) (const char *filename, unsigned long line_no, char *input);\r
+\r
+};\r
+\r
+static char *func_eval (const char *filename, unsigned long line_no, char *input) {\r
+\r
+    read_memory_makefile (filename, line_no, input);\r
+    return 0;\r
+\r
+}\r
+\r
+static char *func_error (const char *filename, unsigned long line_no, char *input) {\r
+\r
+    fprintf (stderr, "%s: %s:%lu: *** %s. Stop.\n", program_name, filename, line_no, input);\r
+    exit (EXIT_FAILURE);\r
+\r
+}\r
+\r
+#if     defined (_WIN32) || defined (__WIN32__)\r
+# include       <windows.h>\r
+static char *func_shell (const char *filename, unsigned long line_no, char *input) {\r
+\r
+    DWORD dwExitCode;\r
+    \r
+    PROCESS_INFORMATION pi;\r
+    SECURITY_ATTRIBUTES sa;\r
+    STARTUPINFO si;\r
+    \r
+    HANDLE hStdInPipeRead, hStdInPipeWrite;\r
+    HANDLE hStdOutPipeRead, hStdOutPipeWrite;\r
+    \r
+    struct linebuf lbuf;\r
+    char *p, ch;\r
+    \r
+    char *cmd = xmalloc (strlen (getenv ("COMSPEC") + 4 + strlen (input) + 1);\r
+    sprintf (cmd, "%s /c %s", getenv ("COMSPEC"), input);\r
+    \r
+    memset (&sa, 0, sizeof (sa));\r
+    memset (&si, 0, sizeof (si));\r
+    memset (&pi, 0, sizeof (pi));\r
+    \r
+    sa.nLength = sizeof (sa);\r
+    sa.bInheritHandle = 1;\r
+    \r
+    if (!CreatePipe (&hStdInPipeRead, &hStdInPipeWrite, &sa, 0)) {\r
+    \r
+        fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);\r
+        fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);\r
+        \r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    /*if (!SetHandleInformation (g_stdout_read, HANDLE_FLAG_INHERIT, 0)) {\r
+    \r
+        fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);\r
+        fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);\r
+        \r
+        exit (EXIT_FAILURE);\r
+    \r
+    }*/\r
+    \r
+    if (!CreatePipe (&hStdOutPipeRead, &hStdOutPipeWrite, &sa, 0)) {\r
+    \r
+        fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);\r
+        fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);\r
+        \r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    /*if (!SetHandleInformation (g_stdin_read, HANDLE_FLAG_INHERIT, 0)) {\r
+    \r
+        fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);\r
+        fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);\r
+        \r
+        exit (EXIT_FAILURE);\r
+    \r
+    }*/\r
+    \r
+    si.cb = sizeof (si);\r
+    \r
+    si.hStdError = hStdOutPipeWrite;\r
+    si.hStdOutput = hStdOutPipeWrite;\r
+    si.hStdInput = hStdInPipeRead;\r
+    \r
+    si.dwFlags |= STARTF_USESTDHANDLES;\r
+    \r
+    if (!CreateProcess (getenv ("COMSPEC"), cmd, 0, 0, 1, CREATE_NO_WINDOW, 0, 0, &si, &pi)) {\r
+    \r
+        fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);\r
+        fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);\r
+        \r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    CloseHandle (hStdOutPipeWrite);\r
+    CloseHandle (hStdInPipeRead);\r
+    \r
+    /*WaitForSingleObject (pi.hProcess, INFINITE);*/\r
+    lbuf.start = xmalloc (lbuf.size = 256);\r
+    \r
+    {\r
+    \r
+        char *end = lbuf.start + lbuf.size;\r
+        char *p = lbuf.start;\r
+        \r
+        DWORD dwRead;\r
+        \r
+        while (ReadFile (hStdOutPipeRead, p, end - p, &dwRead, 0)) {\r
+        \r
+            size_t offset;\r
+            p += strlen (p);\r
+            \r
+            offset = p - lbuf.start;\r
+            \r
+            if (end - p >= 80) {\r
+                continue;\r
+            }\r
+            \r
+            lbuf.size *= 2;\r
+            lbuf.start = xrealloc (lbuf.start, lbuf.size);\r
+            \r
+            p = lbuf.start + offset;\r
+            end = lbuf.start + lbuf.size;\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    CloseHandle (hStdOutPipeRead);\r
+    CloseHandle (hStdInPipeWrite);\r
+    \r
+    GetExitCodeProcess (pi.hProcess, &dwExitCode);\r
+    \r
+    CloseHandle (pi.hProcess);\r
+    CloseHandle (pi.hThread);\r
+    \r
+    if (dwExitCode) {\r
+    \r
+        fprintf (stderr, "%s\n", lbuf.start);\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    p = lbuf.start;\r
+    \r
+    while ((ch = *p++)) {\r
+    \r
+        if (ch == '\n' || ch == '\r') {\r
+            p[-1] = ' ';\r
+        }\r
+    \r
+    }\r
+    \r
+    return lbuf.start;\r
+\r
+}\r
+#else\r
+# include       <sys/wait.h>\r
+# include       <unistd.h>\r
+static char *func_shell (const char *filename, unsigned long line_no, char *input) {\r
+\r
+    FILE *cmd_output;\r
+    \r
+    struct linebuf lbuf;\r
+    char *p, ch;\r
+    \r
+    int pipefd[2], pid, status;\r
+    \r
+    if (pipe (pipefd) < 0) {\r
+    \r
+        perror ("pipe");\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    if ((pid = fork ()) < 0) {\r
+    \r
+        perror ("fork");\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    if (pid == 0) {\r
+    \r
+        dup2 (pipefd[1], STDOUT_FILENO);\r
+        \r
+        close (pipefd[0]);\r
+        close (pipefd[1]);\r
+        \r
+        execl ("/bin/sh", program_name, "-c", input, NULL);\r
+        \r
+        (void) filename; (void) line_no;\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    close (pipefd[1]);\r
+    \r
+    if (!(cmd_output = fdopen (pipefd[0], "r"))) {\r
+    \r
+        perror ("fdopen");\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    lbuf.start = xmalloc (lbuf.size = 256);\r
+    \r
+    {\r
+    \r
+        char *end = lbuf.start + lbuf.size;\r
+        char *p = lbuf.start;\r
+        \r
+        while (fgets (p, end - p, cmd_output)) {\r
+        \r
+            size_t offset;\r
+            p += strlen (p);\r
+            \r
+            offset = p - lbuf.start;\r
+            \r
+            if (end - p >= 80) {\r
+                continue;\r
+            }\r
+            \r
+            lbuf.size *= 2;\r
+            lbuf.start = xrealloc (lbuf.start, lbuf.size);\r
+            \r
+            p = lbuf.start + offset;\r
+            end = lbuf.start + lbuf.size;\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    wait (&status);\r
+    \r
+    if (status) {\r
+    \r
+        fprintf (stderr, "%s\n", lbuf.start);\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    p = lbuf.start;\r
+    \r
+    while ((ch = *p++)) {\r
+    \r
+        if (ch == '\n' || ch == '\r') {\r
+            p[-1] = ' ';\r
+        }\r
+    \r
+    }\r
+    \r
+    return lbuf.start;\r
+\r
+}\r
+#endif\r
+\r
+static struct builtin_function builtin_functions[] ={\r
+\r
+    {   "error",    &func_error     },\r
+    {   "shell",    &func_shell     },\r
+    \r
+    {   "eval",     &func_eval      },\r
+    {   0,          0               }\r
+\r
+};\r
+\r
+static struct hashtab hashtab_builtin = { 0 };\r
+static struct hashtab hashtab_vars = { 0 };\r
+\r
+static struct builtin_function *find_builtin_function (const char *name) {\r
+\r
+    struct hashtab_name *key;\r
+    \r
+    if ((key = hashtab_get_key (&hashtab_builtin, name))) {\r
+        return hashtab_get (&hashtab_builtin, key);\r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+static char *variable_suffix_replace (char *body, const char *from_s, const char *to_s) {\r
+\r
+    char *new_body = xstrdup (body);\r
+    char *p;\r
+    \r
+    while ((p = strstr (new_body, from_s))) {\r
+    \r
+        if (strlen (from_s) == strlen (to_s)) {\r
+            memcpy (p, to_s, strlen (to_s));\r
+        } else if (strlen (from_s) > strlen (to_s)) {\r
+        \r
+            size_t rem = strlen (from_s) - strlen (to_s);\r
+            memcpy (p, to_s, strlen (to_s));\r
+            \r
+            while (rem--) {\r
+                p[strlen (to_s) + rem] = ' ';\r
+            }\r
+        \r
+        } else {\r
+        \r
+            size_t rem = strlen (to_s) - strlen (from_s);\r
+            \r
+            new_body = xrealloc (new_body, strlen (new_body) + rem);\r
+            memmove (p + rem, p, strlen (p) + 1);\r
+            memcpy (p, to_s, strlen (to_s));\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    return new_body;\r
+\r
+}\r
+\r
+struct variable *variable_add (char *name, char *value, enum variable_origin origin) {\r
+\r
+    struct hashtab_name *key;\r
+    struct variable *var;\r
+    \r
+    if (!(key = hashtab_alloc_name (name))) {\r
+    \r
+        report_at (program_name, 0, REPORT_ERROR, "failed to allocate memory for name '%s'", name);\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    var = xmalloc (sizeof (*var));\r
+    var->flavor = VAR_FLAVOR_RECURSIVELY_EXPANDED;\r
+    var->name = name;\r
+    var->origin = origin;\r
+    var->value = value;\r
+    \r
+    if (hashtab_put (&hashtab_vars, key, var)) {\r
+    \r
+        report_at (program_name, 0, REPORT_FATAL_ERROR, "failed to insert variable '%s' into hashtab", var->name);\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    return var;\r
+\r
+}\r
+\r
+struct variable *variable_change (char *name, char *value, enum variable_origin origin) {\r
+\r
+    struct variable *var;\r
+    \r
+    if (!(var = variable_find (name))) {\r
+        return variable_add (xstrdup (name), value, origin);\r
+    }\r
+    \r
+    switch (origin) {\r
+    \r
+        case VAR_ORIGIN_AUTOMATIC:\r
+        case VAR_ORIGIN_COMMAND_LINE:\r
+        \r
+            break;\r
+        \r
+        case VAR_ORIGIN_FILE:\r
+        \r
+            if (var->origin == VAR_ORIGIN_FILE) {\r
+                break;\r
+            }\r
+            \r
+            free (value);\r
+            return 0;\r
+    \r
+    }\r
+    \r
+    free (var->value);\r
+    \r
+    var->value = value;\r
+    var->origin = origin;\r
+    \r
+    return var;\r
+\r
+}\r
+\r
+struct variable *variable_find (char *name) {\r
+\r
+    struct hashtab_name *key;\r
+    \r
+    if (!(key = hashtab_get_key (&hashtab_vars, name))) {\r
+        return 0;\r
+    }\r
+    \r
+    return hashtab_get (&hashtab_vars, key);\r
+\r
+}\r
+\r
+char *variable_expand_line (const char *filename, unsigned long line_no, char *line) {\r
+\r
+    size_t pos = 0;\r
+    \r
+    while (line[pos]) {\r
+    \r
+        if (line[pos] == '$') {\r
+        \r
+            char *new, *replacement = "";\r
+            char *p_after_variable;\r
+            \r
+            struct variable *var = 0;\r
+            char *alloc_replacement = 0;\r
+            \r
+            struct builtin_function *func;\r
+            char saved_ch;\r
+            \r
+            if (line[pos + 1] == '$') {\r
+            \r
+                p_after_variable = line + pos + 2;\r
+                pos += 1;\r
+            \r
+            } else if (line[pos + 1] == '(' || line[pos + 1] == '{') {\r
+            \r
+                char *body = line + pos + 2;\r
+                char *q = body, *content;\r
+                \r
+                int paren_inbalance = 1;\r
+                char opening_paren = line[pos + 1];\r
+                \r
+                while (paren_inbalance) {\r
+                \r
+                    if (*q == opening_paren) {\r
+                        paren_inbalance++;\r
+                    } else if (*q == ')' && opening_paren == '(') {\r
+                        paren_inbalance--;\r
+                    } else if (*q == '}' && opening_paren == '{') {\r
+                        paren_inbalance--;\r
+                    } else if (*q == '\0') {\r
+                    \r
+                        fprintf (stderr, "%s: *** unterminated variable reference. Stop.\n", program_name);\r
+                        exit (EXIT_FAILURE);\r
+                    \r
+                    }\r
+                    \r
+                    q++;\r
+                \r
+                }\r
+                \r
+                q--;\r
+                \r
+                p_after_variable = q + 1;\r
+                content = variable_expand_line (filename, line_no, xstrndup (body, q - body));\r
+                \r
+                for (q = content; *q && !isspace ((int) *q);) {\r
+                    q++;\r
+                }\r
+                \r
+                saved_ch = *q;\r
+                *q = '\0';\r
+                \r
+                func = find_builtin_function (content);\r
+                *q = saved_ch;\r
+                \r
+                if (func) {\r
+                \r
+                    for (; isspace ((int) *q);) {\r
+                        q++;\r
+                    }\r
+                    \r
+                    if ((alloc_replacement = func->func (filename, line_no, q))) {\r
+                    \r
+                        new = xmalloc (pos + strlen (alloc_replacement) + 1);\r
+                        \r
+                        memcpy (new, line, pos);\r
+                        memcpy (new + pos, alloc_replacement, strlen (alloc_replacement));\r
+                        \r
+                        free (alloc_replacement);\r
+                        return new;\r
+                    \r
+                    }\r
+                \r
+                } else if ((q = strchr (content, '='))) {\r
+                \r
+                    char *colon = strchr (content, ':');\r
+                    \r
+                    if (colon && colon != content && colon < q) {\r
+                    \r
+                        char *from, *to, *p;\r
+                        *colon = '\0';\r
+                        \r
+                        var = variable_find (content);\r
+                        \r
+                        for (from = colon + 1; isspace ((int) *from); from++) {\r
+                            ;\r
+                        }\r
+                        \r
+                        for (p = q; p != from && isspace ((int) p[-1]); p--) {\r
+                            ;\r
+                        }\r
+                        \r
+                        *p = '\0';\r
+                        \r
+                        for (to = q + 1; isspace ((int) *to); to++) {\r
+                            ;\r
+                        }\r
+                        \r
+                        for (p = to + strlen (to); p != to && isspace ((int) p[-1]); p--) {\r
+                            ;\r
+                        }\r
+                        \r
+                        *p = '\0';\r
+                        \r
+                        if (*from && var) {\r
+                            alloc_replacement = variable_suffix_replace (var->value, from, to);\r
+                        }\r
+                    \r
+                    }\r
+                \r
+                } else {\r
+                    var = variable_find (content);\r
+                }\r
+                \r
+                free (content);\r
+            \r
+            } else if (line[pos + 1]) {\r
+            \r
+                char name[2] = { 0, 0 };\r
+                \r
+                p_after_variable = line + pos + 2;\r
+                name[0] = line[pos + 1];\r
+                \r
+                var = variable_find (name);\r
+            \r
+            } else {\r
+                p_after_variable = line + pos + 1;\r
+            }\r
+            \r
+            if (var) {\r
+                replacement = var->value;\r
+            }\r
+            \r
+            if (alloc_replacement) {\r
+                replacement = alloc_replacement;\r
+            }\r
+            \r
+            new = xmalloc (pos + strlen (replacement) + strlen (p_after_variable) + 1);\r
+            \r
+            memcpy (new, line, pos);\r
+            memcpy (new + pos, replacement, strlen (replacement));\r
+            memcpy (new + pos + strlen (replacement), p_after_variable, strlen (p_after_variable) + 1);\r
+            \r
+            free (line);\r
+            line = new;\r
+            \r
+            if (!alloc_replacement && var && var->flavor == VAR_FLAVOR_SIMPLY_EXPANDED) {\r
+                pos += strlen (replacement);\r
+            }\r
+            \r
+            free (alloc_replacement);\r
+            continue;\r
+            \r
+        \r
+        }\r
+        \r
+        pos++;\r
+    \r
+    }\r
+    \r
+    return line;\r
+\r
+}\r
+\r
+void parse_var_line (const char *filename, unsigned long line_no, char *line, enum variable_origin origin) {\r
+\r
+    enum {\r
+        VAR_ASSIGN,\r
+        VAR_CONDITIONAL_ASSIGN,\r
+        VAR_APPEND,\r
+        VAR_SHELL\r
+    } opt = VAR_ASSIGN;\r
+    \r
+    enum variable_flavor flavor = VAR_FLAVOR_RECURSIVELY_EXPANDED;\r
+    struct variable *var;\r
+    \r
+    char *var_name, *new_value;\r
+    char *equals_sign, *p;\r
+    \r
+    if (!(equals_sign = strchr (line, '='))) {\r
+    \r
+        fprintf (stderr, "+++ invalid variable definition!\n");\r
+        return;\r
+    \r
+    }\r
+    \r
+    p = equals_sign;\r
+    \r
+    switch (p - line) {\r
+    \r
+        default:\r
+        \r
+            if (p[-1] == ':' && p[-2] == ':' && p[-3] == ':') {\r
+            \r
+                flavor = VAR_FLAVOR_IMMEDIATELY_EXPANDED;\r
+                \r
+                p -= 3;\r
+                break;\r
+            \r
+            }\r
+            \r
+            /* fall through */\r
+        \r
+        case 2:\r
+        \r
+            if (p[-1] == ':' && p[-2] == ':') {\r
+            \r
+                flavor = VAR_FLAVOR_SIMPLY_EXPANDED;\r
+                \r
+                p -= 2;\r
+                break;\r
+            \r
+            }\r
+            \r
+            /* fall through */\r
+        \r
+        case 1:\r
+        \r
+            if (p[-1] == ':') {\r
+            \r
+                flavor = VAR_FLAVOR_SIMPLY_EXPANDED;\r
+                \r
+                p--;\r
+                break;\r
+            \r
+            }\r
+            \r
+            if (p[-1] == '?') {\r
+            \r
+                opt = VAR_CONDITIONAL_ASSIGN;\r
+                \r
+                p--;\r
+                break;\r
+            \r
+            }\r
+            \r
+            if (p[-1] == '+') {\r
+            \r
+                opt = VAR_APPEND;\r
+                \r
+                p--;\r
+                break;\r
+            \r
+            }\r
+            \r
+            if (p[-1] == '!') {\r
+            \r
+                opt = VAR_SHELL;\r
+                \r
+                p--;\r
+                break;\r
+            \r
+            }\r
+            \r
+            break;\r
+        \r
+        case 0:\r
+        \r
+            break;\r
+    \r
+    }\r
+    \r
+    for (; p > line && isspace ((int) p[-1]); p--) {\r
+        ;\r
+    }\r
+    \r
+    var_name = variable_expand_line (filename, line_no, xstrndup (line, p - line));\r
+    \r
+    if (*var_name == '\0') {\r
+    \r
+        fprintf (stderr, "%s: *** empty variable name. Stop.\n", program_name);\r
+        exit (EXIT_FAILURE);\r
+    \r
+    }\r
+    \r
+    var = variable_find (var_name);\r
+    \r
+    if (opt == VAR_CONDITIONAL_ASSIGN && var) {\r
+    \r
+        free (var_name);\r
+        return;\r
+    \r
+    }\r
+    \r
+    for (p = equals_sign; isspace ((int) p[1]); p++) {\r
+        ;\r
+    }\r
+    \r
+    new_value = xstrdup (p + 1);\r
+    \r
+    if (opt == VAR_ASSIGN || opt == VAR_CONDITIONAL_ASSIGN) {\r
+    \r
+        switch (flavor) {\r
+        \r
+            case VAR_FLAVOR_RECURSIVELY_EXPANDED:\r
+            \r
+                break;\r
+            \r
+            case VAR_FLAVOR_SIMPLY_EXPANDED:\r
+            \r
+                new_value = variable_expand_line (filename, line_no, new_value);\r
+                break;\r
+            \r
+            case VAR_FLAVOR_IMMEDIATELY_EXPANDED: {\r
+            \r
+                size_t dollar_count;\r
+                char *temp, *p2;\r
+                \r
+                new_value = variable_expand_line (filename, line_no, new_value);\r
+                \r
+                for (dollar_count = 0, p = new_value; *p; p++) {\r
+                \r
+                    if (*p == '$') {\r
+                        dollar_count++;\r
+                    }\r
+                \r
+                }\r
+                \r
+                temp = xmalloc (strlen (new_value) + 1 + dollar_count);\r
+                \r
+                for (p = new_value, p2 = temp; *p; p++, p2++) {\r
+                \r
+                    *p2 = *p;\r
+                    \r
+                    if (*p == '$') {\r
+                    \r
+                        p2[1] = '$';\r
+                        p2++;\r
+                    \r
+                    }\r
+                    \r
+                    *p2 = '\0';\r
+                    \r
+                    free (new_value);\r
+                    new_value = temp;\r
+                \r
+                }\r
+                \r
+                break;\r
+            \r
+            }\r
+        \r
+        }\r
+    \r
+    } else if (opt == VAR_APPEND) {\r
+    \r
+        struct variable *var;\r
+        \r
+        if ((var = variable_find (var_name))) {\r
+        \r
+            char *temp = xstrdup (new_value);\r
+            free (new_value);\r
+            \r
+            new_value = xmalloc (strlen (var->value) + 1 + strlen (temp) + 1);\r
+            sprintf (new_value, "%s %s", var->value, temp);\r
+            \r
+            free (temp);\r
+        \r
+        }\r
+    \r
+    } else if (opt == VAR_SHELL) {\r
+    \r
+        char *temp = xstrdup (new_value);\r
+        free (new_value);\r
+        \r
+        new_value = variable_expand_line (filename, line_no, func_shell (filename, line_no, temp));\r
+        free (temp);\r
+    \r
+    }\r
+    \r
+    if ((var = variable_change (var_name, new_value, origin))) {\r
+        var->flavor = flavor;\r
+    }\r
+    \r
+    free (var_name);\r
+\r
+}\r
+\r
+void variables_init (void) {\r
+\r
+    struct builtin_function *builtin;\r
+    struct hashtab_name *key;\r
+    \r
+    for (builtin = builtin_functions; builtin->name; builtin++) {\r
+    \r
+        if (!(key = hashtab_alloc_name (builtin->name))) {\r
+            continue;\r
+        }\r
+        \r
+        hashtab_put (&hashtab_builtin, key, builtin);\r
+    \r
+    }\r
+\r
+}\r
diff --git a/xmake.c b/xmake.c
index 8b41c0c1157c089a080d9d37cd0c6e3ce0966a83..614a46c4c1ef37ef87f8ee14a02d294a3ba525ca 100644 (file)
--- a/xmake.c
+++ b/xmake.c
-/******************************************************************************
- * @file            xmake.c
- *****************************************************************************/
-#include    <ctype.h>
-#include    <stdio.h>
-#include    <stdlib.h>
-#include    <string.h>
-
-#include    <xmake/cstr.h>
-#include    <xmake/lib.h>
-#include    <xmake/read.h>
-#include    <xmake/rule.h>
-#include    <xmake/variable.h>
-#include    <xmake/xmake.h>
-
-struct variable *default_goal_var = 0;
-
-struct xmake_state *state = 0;
-const char *program_name = 0;
-
-#if     defined (_WIN32) || defined (__WIN32__)
-const char *os_name = "Windows_NT";
-#elif   defined (__PDOS386__)
-const char *os_name = "PDOS";
-#elif   defined (__MSDOS__)
-const char *os_name = "MSDOS";
-#elif   defined (__APPLE__)
-const char *os_name = "Apple";
-#elif   defined (__linux__)
-const char *os_name = "Linux";
-#else
-const char *os_name = "Unix";
-#endif
-
-static int doing_inference_rule_commands = 0;
-
-static int rule_run_command (const char *filename, unsigned long line_no, const char *name, char *p, char *q) {
-
-    char *new_cmds, *s;
-    
-    int is_ignoring_errors = state->ignore_errors;
-    int is_quiet = state->quiet;
-    int should_execute = !state->dry_run;
-    
-    *q = '\0';
-    
-    new_cmds = xstrdup (p);
-    *q = '\n';
-    
-    new_cmds = variable_expand_line ("<command-line>", 1, new_cmds);
-    s = new_cmds;
-    
-    while (isspace ((int) *s) || *s == '-' || *s == '@' || *s == '+') {
-    
-        if (*s == '@') {
-            is_quiet = 1;
-        }
-        
-        if (*s == '-') {
-            is_ignoring_errors = 1;
-        }
-        
-        if (*s == '+') {
-            should_execute = 1;
-        }
-        
-        s++;
-    
-    }
-    
-    if (!is_quiet) {
-        printf ("%s\n", new_cmds);
-    }
-    
-    if (should_execute) {
-    
-        int error = system (s);
-        
-        if (!is_ignoring_errors && error) {
-        
-            fprintf (stderr, "%s: *** [%s:%lu: %s] Error %d\n", program_name, filename, line_no, name, error);
-            return 1;
-        
-        }
-    
-    }
-    
-    free (new_cmds);
-    return 0;
-
-}
-
-static char *parse_command (char *text) {
-
-    char *cwd = get_current_directory ();
-    char *ret, *p;
-    
-    if (strncmp (text, "./", 2) && strncmp (text, "../", 3)) {
-        return text;
-    }
-    
-    while (1) {
-    
-        if (strncmp (text, "./", 2) && strncmp (text, "../", 3)) {
-            break;
-        }
-        
-        if (strncmp (text, "./", 2) == 0) {
-            text += 2;
-        } else if (strncmp (text, "../", 3) == 0) {
-        
-            text += 3;
-            
-            if ((p = strrchr (cwd, '/'))) {
-                *p = '\0';
-            }
-        
-        }
-    
-    }
-    
-    ret = xmalloc (strlen (cwd) + 1 + strlen (text));
-    sprintf (ret, "%s/%s", cwd, text);
-    
-    return ret;
-
-}
-
-static int run_commands (const char *filename, unsigned long line_no, struct commands *cmds, char *name) {
-
-    char *p = parse_command (cmds->text), *q;
-    int error;
-    
-    while (1) {
-    
-        q = strchr (p, '\n');
-        
-        if (q != cmds->text) {
-        
-            while (q && q[-1] == '\\') {
-                q = strchr (q + 1, '\n');
-            }
-        
-        }
-        
-        if (!q) { break; };
-        
-        if ((error = rule_run_command (filename, line_no, name, p, q)) < 0) {
-            return error;
-        }
-        
-        p = q + 1;
-    
-    }
-    
-    return 0;
-
-}
-
-static int rule_use (struct rule *r, char *name) {
-
-    struct dep *dep;
-    
-    char *p, *star_name, *lesser_name;
-    int ret;
-    
-    CString str;
-    cstr_new (&str);
-    
-    for (dep = r->deps; dep; dep = dep->next) {
-    
-        cstr_cat (&str, dep->name, strlen (dep->name));
-        
-        if ((ret = rule_search_and_build (dep->name))) {
-            return ret;
-        }
-        
-        if (dep->next) {
-            cstr_ccat (&str, ' ');
-        }
-    
-    }
-    
-    cstr_ccat (&str, '\0');
-    
-    if (!r->cmds) {
-    
-        cstr_free (&str);
-        return 0;
-    
-    }
-    
-    doing_inference_rule_commands = 0;
-    
-    if (r->deps) {
-        lesser_name = xstrdup (r->deps->name);
-    } else {
-        lesser_name = xstrdup ("");
-    }
-    
-    star_name = xstrdup (name);
-    
-    if ((p = strrchr (star_name, '.'))) {
-        *p = '\0';
-    }
-    
-    variable_change ("@", xstrdup (name), VAR_ORIGIN_AUTOMATIC);
-    variable_change ("<", lesser_name, VAR_ORIGIN_AUTOMATIC);
-    variable_change ("*", star_name, VAR_ORIGIN_AUTOMATIC);
-    variable_change ("^", xstrdup (str.data), VAR_ORIGIN_AUTOMATIC);
-    
-    return run_commands (r->filename, r->line_no, r->cmds, name);
-
-}
-
-static int suffix_rule_use (struct suffix_rule *s, char *name) {
-
-    char *lesser_name, *star_name;
-    char *p;
-    
-    if (!s->cmds) { return 0; }
-    doing_inference_rule_commands = 1;
-    
-    lesser_name = xmalloc (strlen (name) + strlen (s->first) + 1);
-    memcpy (lesser_name, name, strlen (name) + 1);
-    
-    if ((p = strrchr (lesser_name, '.'))) {
-        *p = '\0';
-    }
-    
-    strcat (lesser_name, s->first);
-    star_name = xstrdup (name);
-    
-    if ((p = strrchr (star_name, '.'))) {
-        *p = '\0';
-    }
-    
-    variable_change ("<", lesser_name, VAR_ORIGIN_AUTOMATIC);
-    variable_change ("*", star_name, VAR_ORIGIN_AUTOMATIC);
-    
-    return run_commands (s->filename, s->line_no, s->cmds, name);
-
-}
-
-static int single_suffix_rule_use (struct suffix_rule *s, char *name) {
-
-    char *lesser_name, *star_name;
-    
-    if (!s->cmds) { return 0; }
-    doing_inference_rule_commands = 1;
-    
-    lesser_name = xmalloc (strlen (name) + strlen (s->first) + 1);
-    strcpy (lesser_name, name);
-    strcat (lesser_name, s->first);
-    
-    star_name = xstrdup (name);
-    
-    variable_change ("<", lesser_name, VAR_ORIGIN_AUTOMATIC);
-    variable_change ("*", star_name, VAR_ORIGIN_AUTOMATIC);
-    
-    return run_commands (s->filename, s->line_no, s->cmds, name);
-
-}
-
-static int file_exists (char *name) {
-
-    FILE *f;
-    
-    if (!(f = fopen (name, "r"))) {
-        return 0;
-    }
-    
-    fclose (f);
-    return 1;
-
-}
-
-static char *find_target (char *target) {
-
-    struct variable *vpath_var;
-    char *vpath;
-    
-    if (file_exists (target)) {
-        return target;
-    }
-    
-    if (!(vpath_var = variable_find ("VPATH"))) {
-        return 0;
-    }
-    
-    vpath = variable_expand_line ("<command-line>", 1, xstrdup (vpath_var->value));
-    
-    while (vpath && *vpath) {
-    
-        char *vpath_part, *new_target;
-        char saved_ch;
-        
-        while (*vpath && (isspace ((int) *vpath) || (*vpath == ';'))) {
-            vpath++;
-        }
-        
-        vpath_part = vpath;
-        
-        while (*vpath && !isspace ((int) *vpath) && *vpath != ';') {
-            vpath++;
-        }
-        
-        saved_ch = *vpath;
-        *vpath = '\0';
-        
-        new_target = xmalloc (strlen (vpath_part) + 1 + strlen (target) + 1);
-        strcpy (new_target, vpath_part);
-        
-        if (strchr (vpath_part, '\\')) {
-            strcat (new_target, "\\");
-        } else {
-            strcat (new_target, "/");
-        }
-        
-        strcat (new_target, target);
-        *vpath = saved_ch;
-        
-        if (file_exists (new_target)) {
-            return new_target;
-        }
-        
-        free (new_target);
-        
-        if (!(vpath = strchr (vpath, ';'))) {
-            break;
-        }
-        
-        vpath++;
-    
-    }
-    
-    return 0;
-
-}
-
-int rule_search_and_build (char *name) {
-
-    struct rule *r;
-    struct suffix_rule *s;
-    
-    char *suffix;
-    char *new_name;
-    
-    if ((r = rule_find (name))) {
-        return rule_use (r, name);
-    }
-    
-    if ((suffix = strrchr (name, '.'))) {
-    
-        char *duplicate_name = xstrdup (name);
-        variable_change ("@", xstrdup (duplicate_name), VAR_ORIGIN_AUTOMATIC);
-        
-        for (s = suffix_rules; s; s = s->next) {
-        
-            if (s->second && strcmp (suffix, s->second) == 0) {
-            
-                char *prereq_name, *p;
-                char *new_name;
-                
-                prereq_name = xmalloc (strlen (duplicate_name) + strlen (s->first) + 1);
-                sprintf (prereq_name, "%s", duplicate_name);
-                
-                if ((p = strrchr (prereq_name, '.'))) {
-                    *p = '\0';
-                }
-                
-                strcat (prereq_name, s->first);
-                
-                if (!(new_name = find_target (prereq_name))) {
-                
-                    free (prereq_name);
-                    continue;
-                
-                }
-                
-                if (prereq_name == new_name) {
-                
-                    free (prereq_name);
-                    break;
-                
-                }
-                
-                free (prereq_name);
-                
-                if (strlen (s->first) < strlen (s->second)) {
-                    new_name = xrealloc (new_name, strlen (new_name) + strlen (s->second) - strlen (s->first) + 1);
-                }
-                
-                if ((p = strrchr (new_name, '.'))) {
-                    *p = '\0';
-                }
-                
-                strcat (new_name, s->second);
-                
-                free (duplicate_name);
-                duplicate_name = new_name;
-                
-                break;
-            
-            }
-        
-        }
-        
-        if (s) {
-        
-            int ret = suffix_rule_use (s, duplicate_name);
-            
-            free (duplicate_name);
-            return ret;
-        
-        }
-        
-        free (duplicate_name);
-    
-    } else {
-    
-        variable_change ("@", xstrdup (name), VAR_ORIGIN_AUTOMATIC);
-        
-        for (s = suffix_rules; s; s = s->next) {
-        
-            if (!s->second) {
-            
-                char *prereq_name, *p;
-                char *new_name;
-                
-                prereq_name = xmalloc (strlen (name) + strlen (s->first) + 1);
-                strcpy (prereq_name, name);
-                strcat (prereq_name, s->first);
-                
-                if (!(new_name = find_target (prereq_name))) {
-                
-                    free (prereq_name);
-                    continue;
-                
-                }
-                
-                if (prereq_name != new_name) {
-                    free (prereq_name);
-                }
-                
-                p = new_name + strlen (new_name) - strlen (s->first);
-                *p = '\0';
-                
-                single_suffix_rule_use (s, new_name);
-                free (new_name);
-                
-                return 0;
-            
-            }
-        
-        }
-    
-    }
-    
-    new_name = find_target (name);
-    
-    if (new_name != name) {
-        free (new_name);
-    }
-    
-    if (!new_name) {
-    
-        fprintf (stderr, "%s: *** No rule to make target '%s'. Stop.\n", program_name, name);
-        return 1;
-    
-    }
-    
-    return 0;
-
-}
-
-int main (int argc, char **argv) {
-
-    int ret;
-    unsigned long i;
-    
-    if (argc && *argv) {
-    
-        char *p;
-        program_name = *argv;
-        
-        if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {
-            program_name = (p + 1);
-        }
-    
-    }
-    
-    variables_init ();
-    rules_init ();
-    
-    default_goal_var = variable_add (xstrdup (".DEFAULT_GOAL"), xstrdup (""), VAR_ORIGIN_FILE);
-    
-    variable_add (xstrdup ("OS"), xstrdup (os_name), VAR_ORIGIN_FILE);
-    variable_add (xstrdup ("MAKE"), xstrdup (argv[0]), VAR_ORIGIN_FILE);
-    
-#if     defined (_WIN32) || defined (__WIN32__)
-    variable_add (xstrdup ("SHELL"), xstrdup ("cmd.exe"), VAR_ORIGIN_FILE);
-#else
-    variable_add (xstrdup ("SHELL"), xstrdup ("sh.exe"), VAR_ORIGIN_FILE);
-#endif
-    
-    state = xmalloc (sizeof (*state));
-    parse_args (argv, argc);
-    
-    if (state->nb_directories > 0) {
-    
-        char *arg;
-        size_t len = 0;
-        
-        char *cwd = get_current_directory ();
-        unsigned long i;
-        
-        state->path = xmalloc (strlen (cwd) + 2);
-        len = sprintf (state->path, "%s/", cwd);
-        
-        for (i = 0; i < state->nb_directories; i++) {
-        
-            arg = state->directories[i];
-            
-#if     defined (_WIN32)
-            if (strlen (arg) < 3 || !(isalpha ((int) arg[0]) && arg[1] == ':' && (arg[2] == '/' || arg[2] == '\\'))) {
-#else
-            if (arg[0] != '/') {
-#endif
-            
-                state->path = xrealloc (state->path, len + strlen (arg) + 2);
-                
-                len += sprintf (state->path + len, "%s/", arg);
-                state->path[len] = '\0';
-            
-            } else {
-            
-                free (state->path);
-                
-                state->path = xmalloc (strlen (arg) + 1);
-                len = sprintf (state->path, "%s/", arg);
-            
-            }
-        
-        }
-        
-        if (!directory_exists (state->path)) {
-        
-            fprintf (stderr, "%s: *** '%s': No such directory. Stop.\n", program_name, state->path);
-            return EXIT_FAILURE;
-        
-        }
-        
-        if (!state->no_print) {
-            fprintf (stderr, "%s: Entering directory '%s'\n", program_name, state->path);
-        }
-        
-        if (!change_directory (state->path)) {
-        
-            fprintf (stderr, "%s: *** Failed to enter '%s'. Stop.\n", program_name, state->path);
-            return EXIT_FAILURE;
-        
-        }
-    
-    }
-    
-    {
-    
-        char *path, *cwd = get_current_directory ();
-        
-        path = xmalloc (strlen ("CURDIR") + 4 + strlen (cwd) + 1);
-        sprintf (path, "CURDIR ?= %s", cwd);
-        
-        parse_var_line ("<command-line>", 1, path, VAR_ORIGIN_FILE);
-        free (path);
-        
-        path = xmalloc (strlen (".CURDIR") + 4 + strlen (cwd) + 1);
-        sprintf (path, ".CURDIR ?= %s", cwd);
-        
-        parse_var_line ("<command-line>", 1, path, VAR_ORIGIN_FILE);
-        free (path);
-        
-        /*variable_add (xstrdup ("CURDIR"), xstrdup (get_current_directory ()), VAR_ORIGIN_FILE);*/
-    
-    }
-    
-    if (state->nb_makefiles > 0) {
-    
-        char *path;
-        unsigned long i;
-        
-        for (i = 0; i < state->nb_makefiles; i++) {
-        
-            path = state->makefiles[i];
-            
-            if ((ret = read_makefile (path))) {
-            
-                fprintf (stderr, "%s: *** Failed to read '%s'. Stop.\n", program_name, path);
-                goto out;
-            
-            }
-        
-        }
-    
-    }
-    
-    if (state->nb_goals == 0) {
-    
-        if (default_goal_var->value[0] == '\0') {
-        
-            fprintf (stderr, "%s: *** No targets. Stop.\n", program_name);
-            
-            ret = EXIT_FAILURE;
-            goto out;
-        
-        }
-        
-        dynarray_add (&state->goals, &state->nb_goals, xstrdup (default_goal_var->value));
-    
-    }
-    
-    for (i = 0; i < state->nb_goals; i++) {
-    
-        if ((ret = rule_search_and_build (state->goals[i]))) {
-            goto out;
-        }
-    
-    }
-    
-    ret = EXIT_SUCCESS;
-    
-out:
-    
-    if (state->nb_directories > 0 && !state->no_print) {
-        fprintf (stderr, "%s: Leaving directory '%s'\n", program_name, state->path);
-    }
-    
-    return ret;
-
-}
+/******************************************************************************\r
+ * @file            xmake.c\r
+ *****************************************************************************/\r
+#include    <ctype.h>\r
+#include    <stdio.h>\r
+#include    <stdlib.h>\r
+#include    <string.h>\r
+\r
+#include    <xmake/cstr.h>\r
+#include    <xmake/lib.h>\r
+#include    <xmake/read.h>\r
+#include    <xmake/rule.h>\r
+#include    <xmake/variable.h>\r
+#include    <xmake/xmake.h>\r
+\r
+struct variable *default_goal_var = 0;\r
+\r
+struct xmake_state *state = 0;\r
+const char *program_name = 0;\r
+\r
+#if     defined (_WIN32) || defined (__WIN32__)\r
+const char *os_name = "Windows_NT";\r
+#elif   defined (__PDOS386__)\r
+const char *os_name = "PDOS";\r
+#elif   defined (__MSDOS__)\r
+const char *os_name = "MSDOS";\r
+#elif   defined (__APPLE__)\r
+const char *os_name = "Apple";\r
+#elif   defined (__linux__)\r
+const char *os_name = "Linux";\r
+#else\r
+const char *os_name = "Unix";\r
+#endif\r
+\r
+static int doing_inference_rule_commands = 0;\r
+\r
+static int rule_run_command (const char *filename, unsigned long line_no, const char *name, char *p, char *q) {\r
+\r
+    char *new_cmds, *s;\r
+    \r
+    int is_ignoring_errors = state->ignore_errors;\r
+    int is_quiet = state->quiet;\r
+    int should_execute = !state->dry_run;\r
+    \r
+    *q = '\0';\r
+    \r
+    new_cmds = xstrdup (p);\r
+    *q = '\n';\r
+    \r
+    new_cmds = variable_expand_line ("<command-line>", 1, new_cmds);\r
+    s = new_cmds;\r
+    \r
+    while (isspace ((int) *s) || *s == '-' || *s == '@' || *s == '+') {\r
+    \r
+        if (*s == '@') {\r
+            is_quiet = 1;\r
+        }\r
+        \r
+        if (*s == '-') {\r
+            is_ignoring_errors = 1;\r
+        }\r
+        \r
+        if (*s == '+') {\r
+            should_execute = 1;\r
+        }\r
+        \r
+        s++;\r
+    \r
+    }\r
+    \r
+    if (!is_quiet) {\r
+        printf ("%s\n", new_cmds);\r
+    }\r
+    \r
+    if (should_execute) {\r
+    \r
+        int error = system (s);\r
+        \r
+        if (!is_ignoring_errors && error) {\r
+        \r
+            fprintf (stderr, "%s: *** [%s:%lu: %s] Error %d\n", program_name, filename, line_no, name, error);\r
+            return 1;\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    free (new_cmds);\r
+    return 0;\r
+\r
+}\r
+\r
+static char *parse_command (char *text) {\r
+\r
+    char *cwd = get_current_directory ();\r
+    char *ret, *p;\r
+    \r
+    if (strncmp (text, "./", 2) && strncmp (text, "../", 3)) {\r
+        return text;\r
+    }\r
+    \r
+    while (1) {\r
+    \r
+        if (strncmp (text, "./", 2) && strncmp (text, "../", 3)) {\r
+            break;\r
+        }\r
+        \r
+        if (strncmp (text, "./", 2) == 0) {\r
+            text += 2;\r
+        } else if (strncmp (text, "../", 3) == 0) {\r
+        \r
+            text += 3;\r
+            \r
+            if ((p = strrchr (cwd, '/'))) {\r
+                *p = '\0';\r
+            }\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    ret = xmalloc (strlen (cwd) + 1 + strlen (text));\r
+    sprintf (ret, "%s/%s", cwd, text);\r
+    \r
+    return ret;\r
+\r
+}\r
+\r
+static int run_commands (const char *filename, unsigned long line_no, struct commands *cmds, char *name) {\r
+\r
+    char *p = parse_command (cmds->text), *q;\r
+    int error;\r
+    \r
+    while (1) {\r
+    \r
+        q = strchr (p, '\n');\r
+        \r
+        if (q != cmds->text) {\r
+        \r
+            while (q && q[-1] == '\\') {\r
+                q = strchr (q + 1, '\n');\r
+            }\r
+        \r
+        }\r
+        \r
+        if (!q) { break; };\r
+        \r
+        if ((error = rule_run_command (filename, line_no, name, p, q)) < 0) {\r
+            return error;\r
+        }\r
+        \r
+        p = q + 1;\r
+    \r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+static int rule_use (struct rule *r, char *name) {\r
+\r
+    struct dep *dep;\r
+    \r
+    char *p, *star_name, *lesser_name;\r
+    int ret;\r
+    \r
+    CString str;\r
+    cstr_new (&str);\r
+    \r
+    for (dep = r->deps; dep; dep = dep->next) {\r
+    \r
+        cstr_cat (&str, dep->name, strlen (dep->name));\r
+        \r
+        if ((ret = rule_search_and_build (dep->name))) {\r
+            return ret;\r
+        }\r
+        \r
+        if (dep->next) {\r
+            cstr_ccat (&str, ' ');\r
+        }\r
+    \r
+    }\r
+    \r
+    cstr_ccat (&str, '\0');\r
+    \r
+    if (!r->cmds) {\r
+    \r
+        cstr_free (&str);\r
+        return 0;\r
+    \r
+    }\r
+    \r
+    doing_inference_rule_commands = 0;\r
+    \r
+    if (r->deps) {\r
+        lesser_name = xstrdup (r->deps->name);\r
+    } else {\r
+        lesser_name = xstrdup ("");\r
+    }\r
+    \r
+    star_name = xstrdup (name);\r
+    \r
+    if ((p = strrchr (star_name, '.'))) {\r
+        *p = '\0';\r
+    }\r
+    \r
+    variable_change ("@", xstrdup (name), VAR_ORIGIN_AUTOMATIC);\r
+    variable_change ("<", lesser_name, VAR_ORIGIN_AUTOMATIC);\r
+    variable_change ("*", star_name, VAR_ORIGIN_AUTOMATIC);\r
+    variable_change ("^", xstrdup (str.data), VAR_ORIGIN_AUTOMATIC);\r
+    \r
+    return run_commands (r->filename, r->line_no, r->cmds, name);\r
+\r
+}\r
+\r
+static int suffix_rule_use (struct suffix_rule *s, char *name) {\r
+\r
+    char *lesser_name, *star_name;\r
+    char *p;\r
+    \r
+    if (!s->cmds) { return 0; }\r
+    doing_inference_rule_commands = 1;\r
+    \r
+    lesser_name = xmalloc (strlen (name) + strlen (s->first) + 1);\r
+    memcpy (lesser_name, name, strlen (name) + 1);\r
+    \r
+    if ((p = strrchr (lesser_name, '.'))) {\r
+        *p = '\0';\r
+    }\r
+    \r
+    strcat (lesser_name, s->first);\r
+    star_name = xstrdup (name);\r
+    \r
+    if ((p = strrchr (star_name, '.'))) {\r
+        *p = '\0';\r
+    }\r
+    \r
+    variable_change ("<", lesser_name, VAR_ORIGIN_AUTOMATIC);\r
+    variable_change ("*", star_name, VAR_ORIGIN_AUTOMATIC);\r
+    \r
+    return run_commands (s->filename, s->line_no, s->cmds, name);\r
+\r
+}\r
+\r
+static int single_suffix_rule_use (struct suffix_rule *s, char *name) {\r
+\r
+    char *lesser_name, *star_name;\r
+    \r
+    if (!s->cmds) { return 0; }\r
+    doing_inference_rule_commands = 1;\r
+    \r
+    lesser_name = xmalloc (strlen (name) + strlen (s->first) + 1);\r
+    strcpy (lesser_name, name);\r
+    strcat (lesser_name, s->first);\r
+    \r
+    star_name = xstrdup (name);\r
+    \r
+    variable_change ("<", lesser_name, VAR_ORIGIN_AUTOMATIC);\r
+    variable_change ("*", star_name, VAR_ORIGIN_AUTOMATIC);\r
+    \r
+    return run_commands (s->filename, s->line_no, s->cmds, name);\r
+\r
+}\r
+\r
+static int file_exists (char *name) {\r
+\r
+    FILE *f;\r
+    \r
+    if (!(f = fopen (name, "r"))) {\r
+        return 0;\r
+    }\r
+    \r
+    fclose (f);\r
+    return 1;\r
+\r
+}\r
+\r
+static char *find_target (char *target) {\r
+\r
+    struct variable *vpath_var;\r
+    char *vpath;\r
+    \r
+    if (file_exists (target)) {\r
+        return target;\r
+    }\r
+    \r
+    if (!(vpath_var = variable_find ("VPATH"))) {\r
+        return 0;\r
+    }\r
+    \r
+    vpath = variable_expand_line ("<command-line>", 1, xstrdup (vpath_var->value));\r
+    \r
+    while (vpath && *vpath) {\r
+    \r
+        char *vpath_part, *new_target;\r
+        char saved_ch;\r
+        \r
+        while (*vpath && (isspace ((int) *vpath) || (*vpath == ';'))) {\r
+            vpath++;\r
+        }\r
+        \r
+        vpath_part = vpath;\r
+        \r
+        while (*vpath && !isspace ((int) *vpath) && *vpath != ';') {\r
+            vpath++;\r
+        }\r
+        \r
+        saved_ch = *vpath;\r
+        *vpath = '\0';\r
+        \r
+        new_target = xmalloc (strlen (vpath_part) + 1 + strlen (target) + 1);\r
+        strcpy (new_target, vpath_part);\r
+        \r
+        if (strchr (vpath_part, '\\')) {\r
+            strcat (new_target, "\\");\r
+        } else {\r
+            strcat (new_target, "/");\r
+        }\r
+        \r
+        strcat (new_target, target);\r
+        *vpath = saved_ch;\r
+        \r
+        if (file_exists (new_target)) {\r
+            return new_target;\r
+        }\r
+        \r
+        free (new_target);\r
+        \r
+        if (!(vpath = strchr (vpath, ';'))) {\r
+            break;\r
+        }\r
+        \r
+        vpath++;\r
+    \r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+int rule_search_and_build (char *name) {\r
+\r
+    struct rule *r;\r
+    struct suffix_rule *s;\r
+    \r
+    char *suffix;\r
+    char *new_name;\r
+    \r
+    if ((r = rule_find (name))) {\r
+        return rule_use (r, name);\r
+    }\r
+    \r
+    if ((suffix = strrchr (name, '.'))) {\r
+    \r
+        char *duplicate_name = xstrdup (name);\r
+        variable_change ("@", xstrdup (duplicate_name), VAR_ORIGIN_AUTOMATIC);\r
+        \r
+        for (s = suffix_rules; s; s = s->next) {\r
+        \r
+            if (s->second && strcmp (suffix, s->second) == 0) {\r
+            \r
+                char *prereq_name, *p;\r
+                char *new_name;\r
+                \r
+                prereq_name = xmalloc (strlen (duplicate_name) + strlen (s->first) + 1);\r
+                sprintf (prereq_name, "%s", duplicate_name);\r
+                \r
+                if ((p = strrchr (prereq_name, '.'))) {\r
+                    *p = '\0';\r
+                }\r
+                \r
+                strcat (prereq_name, s->first);\r
+                \r
+                if (!(new_name = find_target (prereq_name))) {\r
+                \r
+                    free (prereq_name);\r
+                    continue;\r
+                \r
+                }\r
+                \r
+                if (prereq_name == new_name) {\r
+                \r
+                    free (prereq_name);\r
+                    break;\r
+                \r
+                }\r
+                \r
+                free (prereq_name);\r
+                \r
+                if (strlen (s->first) < strlen (s->second)) {\r
+                    new_name = xrealloc (new_name, strlen (new_name) + strlen (s->second) - strlen (s->first) + 1);\r
+                }\r
+                \r
+                if ((p = strrchr (new_name, '.'))) {\r
+                    *p = '\0';\r
+                }\r
+                \r
+                strcat (new_name, s->second);\r
+                \r
+                free (duplicate_name);\r
+                duplicate_name = new_name;\r
+                \r
+                break;\r
+            \r
+            }\r
+        \r
+        }\r
+        \r
+        if (s) {\r
+        \r
+            int ret = suffix_rule_use (s, duplicate_name);\r
+            \r
+            free (duplicate_name);\r
+            return ret;\r
+        \r
+        }\r
+        \r
+        free (duplicate_name);\r
+    \r
+    } else {\r
+    \r
+        variable_change ("@", xstrdup (name), VAR_ORIGIN_AUTOMATIC);\r
+        \r
+        for (s = suffix_rules; s; s = s->next) {\r
+        \r
+            if (!s->second) {\r
+            \r
+                char *prereq_name, *p;\r
+                char *new_name;\r
+                \r
+                prereq_name = xmalloc (strlen (name) + strlen (s->first) + 1);\r
+                strcpy (prereq_name, name);\r
+                strcat (prereq_name, s->first);\r
+                \r
+                if (!(new_name = find_target (prereq_name))) {\r
+                \r
+                    free (prereq_name);\r
+                    continue;\r
+                \r
+                }\r
+                \r
+                if (prereq_name != new_name) {\r
+                    free (prereq_name);\r
+                }\r
+                \r
+                p = new_name + strlen (new_name) - strlen (s->first);\r
+                *p = '\0';\r
+                \r
+                single_suffix_rule_use (s, new_name);\r
+                free (new_name);\r
+                \r
+                return 0;\r
+            \r
+            }\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    new_name = find_target (name);\r
+    \r
+    if (new_name != name) {\r
+        free (new_name);\r
+    }\r
+    \r
+    if (!new_name) {\r
+    \r
+        fprintf (stderr, "%s: *** No rule to make target '%s'. Stop.\n", program_name, name);\r
+        return 1;\r
+    \r
+    }\r
+    \r
+    return 0;\r
+\r
+}\r
+\r
+int main (int argc, char **argv) {\r
+\r
+    int ret;\r
+    unsigned long i;\r
+    \r
+    if (argc && *argv) {\r
+    \r
+        char *p;\r
+        program_name = *argv;\r
+        \r
+        if ((p = strrchr (program_name, '/')) || (p = strrchr (program_name, '\\'))) {\r
+            program_name = (p + 1);\r
+        }\r
+    \r
+    }\r
+    \r
+    variables_init ();\r
+    rules_init ();\r
+    \r
+    default_goal_var = variable_add (xstrdup (".DEFAULT_GOAL"), xstrdup (""), VAR_ORIGIN_FILE);\r
+    \r
+    variable_add (xstrdup ("OS"), xstrdup (os_name), VAR_ORIGIN_FILE);\r
+    variable_add (xstrdup ("MAKE"), xstrdup (argv[0]), VAR_ORIGIN_FILE);\r
+    \r
+#if     defined (_WIN32) || defined (__WIN32__)\r
+    variable_add (xstrdup ("SHELL"), xstrdup ("sh.exe"), VAR_ORIGIN_FILE);\r
+#else\r
+    variable_add (xstrdup ("SHELL"), xstrdup ("/bin/sh"), VAR_ORIGIN_FILE);\r
+#endif\r
+    \r
+    state = xmalloc (sizeof (*state));\r
+    parse_args (argv, argc);\r
+    \r
+    if (state->nb_directories > 0) {\r
+    \r
+        char *arg;\r
+        size_t len = 0;\r
+        \r
+        char *cwd = get_current_directory ();\r
+        unsigned long i;\r
+        \r
+        state->path = xmalloc (strlen (cwd) + 2);\r
+        len = sprintf (state->path, "%s/", cwd);\r
+        \r
+        for (i = 0; i < state->nb_directories; i++) {\r
+        \r
+            arg = state->directories[i];\r
+            \r
+#if     defined (_WIN32)\r
+            if (strlen (arg) < 3 || !(isalpha ((int) arg[0]) && arg[1] == ':' && (arg[2] == '/' || arg[2] == '\\'))) {\r
+#else\r
+            if (arg[0] != '/') {\r
+#endif\r
+            \r
+                state->path = xrealloc (state->path, len + strlen (arg) + 2);\r
+                \r
+                len += sprintf (state->path + len, "%s/", arg);\r
+                state->path[len] = '\0';\r
+            \r
+            } else {\r
+            \r
+                free (state->path);\r
+                \r
+                state->path = xmalloc (strlen (arg) + 1);\r
+                len = sprintf (state->path, "%s/", arg);\r
+            \r
+            }\r
+        \r
+        }\r
+        \r
+        if (!directory_exists (state->path)) {\r
+        \r
+            fprintf (stderr, "%s: *** '%s': No such directory. Stop.\n", program_name, state->path);\r
+            return EXIT_FAILURE;\r
+        \r
+        }\r
+        \r
+        if (!state->no_print) {\r
+            fprintf (stderr, "%s: Entering directory '%s'\n", program_name, state->path);\r
+        }\r
+        \r
+        if (!change_directory (state->path)) {\r
+        \r
+            fprintf (stderr, "%s: *** Failed to enter '%s'. Stop.\n", program_name, state->path);\r
+            return EXIT_FAILURE;\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    {\r
+    \r
+        char *path, *cwd = get_current_directory ();\r
+        \r
+        path = xmalloc (strlen ("CURDIR") + 4 + strlen (cwd) + 1);\r
+        sprintf (path, "CURDIR ?= %s", cwd);\r
+        \r
+        parse_var_line ("<command-line>", 1, path, VAR_ORIGIN_FILE);\r
+        free (path);\r
+        \r
+        path = xmalloc (strlen (".CURDIR") + 4 + strlen (cwd) + 1);\r
+        sprintf (path, ".CURDIR ?= %s", cwd);\r
+        \r
+        parse_var_line ("<command-line>", 1, path, VAR_ORIGIN_FILE);\r
+        free (path);\r
+        \r
+        /*variable_add (xstrdup ("CURDIR"), xstrdup (get_current_directory ()), VAR_ORIGIN_FILE);*/\r
+    \r
+    }\r
+    \r
+    if (state->nb_makefiles > 0) {\r
+    \r
+        char *path;\r
+        unsigned long i;\r
+        \r
+        for (i = 0; i < state->nb_makefiles; i++) {\r
+        \r
+            path = state->makefiles[i];\r
+            \r
+            if ((ret = read_makefile (path))) {\r
+            \r
+                fprintf (stderr, "%s: *** Failed to read '%s'. Stop.\n", program_name, path);\r
+                goto out;\r
+            \r
+            }\r
+        \r
+        }\r
+    \r
+    }\r
+    \r
+    if (state->nb_goals == 0) {\r
+    \r
+        if (default_goal_var->value[0] == '\0') {\r
+        \r
+            fprintf (stderr, "%s: *** No targets. Stop.\n", program_name);\r
+            \r
+            ret = EXIT_FAILURE;\r
+            goto out;\r
+        \r
+        }\r
+        \r
+        dynarray_add (&state->goals, &state->nb_goals, xstrdup (default_goal_var->value));\r
+    \r
+    }\r
+    \r
+    for (i = 0; i < state->nb_goals; i++) {\r
+    \r
+        if ((ret = rule_search_and_build (state->goals[i]))) {\r
+            goto out;\r
+        }\r
+    \r
+    }\r
+    \r
+    ret = EXIT_SUCCESS;\r
+    \r
+out:\r
+    \r
+    if (state->nb_directories > 0 && !state->no_print) {\r
+        fprintf (stderr, "%s: Leaving directory '%s'\n", program_name, state->path);\r
+    }\r
+    \r
+    return ret;\r
+\r
+}\r