-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
+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>
-#******************************************************************************\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
+#******************************************************************************
+# @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.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
+#******************************************************************************
+# @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.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
+#******************************************************************************
+# @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 )
-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
+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.
-/******************************************************************************\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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @file command.h
+ *****************************************************************************/
+#ifndef _COMMAND_H
+#define _COMMAND_H
+
+struct commands {
+
+ char *text;
+ unsigned long len;
+
+};
+
+#endif /* _COMMAND_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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @file dep.h
+ *****************************************************************************/
+#ifndef _DEP_H
+#define _DEP_H
+
+struct dep {
+
+ char *name;
+ struct dep *next;
+
+};
+
+#endif /* _DEP_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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @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 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
+/******************************************************************************
+ * @file variable.c
+ *****************************************************************************/
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined (_WIN32) && !defined (__WIN32__) && !defined (__MSDOS__)
+# define __USE_POSIX
+#endif
+
+#include <stdio.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 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);
+
+}
+
+#if defined (_WIN32) || defined (__WIN32__)
+# include <windows.h>
+static char *func_shell (const char *filename, unsigned long line_no, char *input) {
+
+ DWORD dwExitCode;
+
+ PROCESS_INFORMATION pi;
+ SECURITY_ATTRIBUTES sa;
+ STARTUPINFO si;
+
+ HANDLE hStdInPipeRead, hStdInPipeWrite;
+ HANDLE hStdOutPipeRead, hStdOutPipeWrite;
+
+ struct linebuf lbuf;
+ char *p, ch;
+
+ char *cmd = xmalloc (strlen (getenv ("COMSPEC") + 4 + strlen (input) + 1);
+ sprintf (cmd, "%s /c %s", getenv ("COMSPEC"), input);
+
+ memset (&sa, 0, sizeof (sa));
+ memset (&si, 0, sizeof (si));
+ memset (&pi, 0, sizeof (pi));
+
+ sa.nLength = sizeof (sa);
+ sa.bInheritHandle = 1;
+
+ if (!CreatePipe (&hStdInPipeRead, &hStdInPipeWrite, &sa, 0)) {
+
+ fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);
+ fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);
+
+ exit (EXIT_FAILURE);
+
+ }
+
+ /*if (!SetHandleInformation (g_stdout_read, HANDLE_FLAG_INHERIT, 0)) {
+
+ fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);
+ fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);
+
+ exit (EXIT_FAILURE);
+
+ }*/
+
+ if (!CreatePipe (&hStdOutPipeRead, &hStdOutPipeWrite, &sa, 0)) {
+
+ fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);
+ fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);
+
+ exit (EXIT_FAILURE);
+
+ }
+
+ /*if (!SetHandleInformation (g_stdin_read, HANDLE_FLAG_INHERIT, 0)) {
+
+ fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);
+ fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);
+
+ exit (EXIT_FAILURE);
+
+ }*/
+
+ si.cb = sizeof (si);
+
+ si.hStdError = hStdOutPipeWrite;
+ si.hStdOutput = hStdOutPipeWrite;
+ si.hStdInput = hStdInPipeRead;
+
+ si.dwFlags |= STARTF_USESTDHANDLES;
+
+ if (!CreateProcess (getenv ("COMSPEC"), cmd, 0, 0, 1, CREATE_NO_WINDOW, 0, 0, &si, &pi)) {
+
+ fprintf (stderr, "process_begin: CreateProcess(NULL, %s, ...) failed.\n", input);
+ fprintf (stderr, "%s: %s:%lu: pipe: No error\n", program_name, filename, line_no);
+
+ exit (EXIT_FAILURE);
+
+ }
+
+ CloseHandle (hStdOutPipeWrite);
+ CloseHandle (hStdInPipeRead);
+
+ /*WaitForSingleObject (pi.hProcess, INFINITE);*/
+ lbuf.start = xmalloc (lbuf.size = 256);
+
+ {
+
+ char *end = lbuf.start + lbuf.size;
+ char *p = lbuf.start;
+
+ DWORD dwRead;
+
+ while (ReadFile (hStdOutPipeRead, p, end - p, &dwRead, 0)) {
+
+ size_t offset;
+ p += strlen (p);
+
+ offset = p - lbuf.start;
+
+ if (end - p >= 80) {
+ continue;
+ }
+
+ lbuf.size *= 2;
+ lbuf.start = xrealloc (lbuf.start, lbuf.size);
+
+ p = lbuf.start + offset;
+ end = lbuf.start + lbuf.size;
+
+ }
+
+ }
+
+ CloseHandle (hStdOutPipeRead);
+ CloseHandle (hStdInPipeWrite);
+
+ GetExitCodeProcess (pi.hProcess, &dwExitCode);
+
+ CloseHandle (pi.hProcess);
+ CloseHandle (pi.hThread);
+
+ if (dwExitCode) {
+
+ fprintf (stderr, "%s\n", lbuf.start);
+ exit (EXIT_FAILURE);
+
+ }
+
+ p = lbuf.start;
+
+ while ((ch = *p++)) {
+
+ if (ch == '\n' || ch == '\r') {
+ p[-1] = ' ';
+ }
+
+ }
+
+ return lbuf.start;
+
+}
+#else
+# include <sys/wait.h>
+# include <unistd.h>
+static char *func_shell (const char *filename, unsigned long line_no, char *input) {
+
+ FILE *cmd_output;
+
+ struct linebuf lbuf;
+ char *p, ch;
+
+ int pipefd[2], pid, status;
+
+ if (pipe (pipefd) < 0) {
+
+ perror ("pipe");
+ exit (EXIT_FAILURE);
+
+ }
+
+ if ((pid = fork ()) < 0) {
+
+ perror ("fork");
+ exit (EXIT_FAILURE);
+
+ }
+
+ if (pid == 0) {
+
+ dup2 (pipefd[1], STDOUT_FILENO);
+
+ close (pipefd[0]);
+ close (pipefd[1]);
+
+ execl ("/bin/sh", program_name, "-c", input, NULL);
+
+ (void) filename; (void) line_no;
+ exit (EXIT_FAILURE);
+
+ }
+
+ close (pipefd[1]);
+
+ if (!(cmd_output = fdopen (pipefd[0], "r"))) {
+
+ perror ("fdopen");
+ exit (EXIT_FAILURE);
+
+ }
+
+ lbuf.start = xmalloc (lbuf.size = 256);
+
+ {
+
+ char *end = lbuf.start + lbuf.size;
+ char *p = lbuf.start;
+
+ while (fgets (p, end - p, cmd_output)) {
+
+ size_t offset;
+ p += strlen (p);
+
+ offset = p - lbuf.start;
+
+ if (end - p >= 80) {
+ continue;
+ }
+
+ lbuf.size *= 2;
+ lbuf.start = xrealloc (lbuf.start, lbuf.size);
+
+ p = lbuf.start + offset;
+ end = lbuf.start + lbuf.size;
+
+ }
+
+ }
+
+ wait (&status);
+
+ if (status) {
+
+ fprintf (stderr, "%s\n", lbuf.start);
+ exit (EXIT_FAILURE);
+
+ }
+
+ p = lbuf.start;
+
+ while ((ch = *p++)) {
+
+ if (ch == '\n' || ch == '\r') {
+ p[-1] = ' ';
+ }
+
+ }
+
+ return lbuf.start;
+
+}
+#endif
+
+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 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
+/******************************************************************************
+ * @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 ("sh.exe"), VAR_ORIGIN_FILE);
+#else
+ variable_add (xstrdup ("SHELL"), xstrdup ("/bin/sh"), 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;
+
+}