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