diff --git a/cc_core.c b/cc_core.c
index 78abacd..214919f 100644
--- a/cc_core.c
+++ b/cc_core.c
@@ -37,6 +37,7 @@ char* break_target_num;
struct token_list* break_frame;
int current_count;
struct type* last_type;
+int Address_of;
/* Imported functions */
char* parse_string(char* string);
@@ -44,8 +45,6 @@ int escape_lookup(char* c);
char* numerate_number(int a);
-
-
struct token_list* emit(char *s, struct token_list* head)
{
struct token_list* t = calloc(1, sizeof(struct token_list));
@@ -179,8 +178,8 @@ void variable_load(struct token_list* a)
emit_out("LOAD_BASE_ADDRESS_eax %");
emit_out(numerate_number(a->depth));
emit_out("\n");
+ if(TRUE == Address_of) return;
if(match("=", global_token->s)) return;
- if(match("char**", a->type->name)) return;
emit_out("LOAD_INTEGER\n");
}
@@ -388,7 +387,7 @@ void postfix_expr_arrow()
emit_out("\nADD_ebx_to_eax\n");
}
- if(!match("=", global_token->s) && !match("char**", current_target->name))
+ if((!match("=", global_token->s) && (4 >= i->size)))
{
emit_out("LOAD_INTEGER\n");
}
@@ -553,6 +552,16 @@ void bitwise_expr()
void primary_expr()
{
+ if(match("&", global_token->s))
+ {
+ Address_of = TRUE;
+ global_token = global_token->next;
+ }
+ else
+ {
+ Address_of = FALSE;
+ }
+
if(match("sizeof", global_token->s)) unary_expr_sizeof();
else if('-' == global_token->s[0])
{
@@ -608,7 +617,7 @@ void collect_local()
struct token_list* a = sym_declare(global_token->s, type_size, function->locals);
if(match("main", function->s) && (NULL == function->locals))
{
- a->depth = -4;
+ a->depth = -20;
}
else if((NULL == function->arguments) && (NULL == function->locals))
{
@@ -1004,12 +1013,7 @@ void collect_arguments()
{
/* deal with foo(int a, char b) */
struct token_list* a = sym_declare(global_token->s, type_size, function->arguments);
- if(match("main", function->s))
- {
- if(match("argc", a->s)) a->depth = 4;
- if(match("argv", a->s)) a->depth = 8;
- }
- else if(NULL == function->arguments)
+ if(NULL == function->arguments)
{
a->depth = -4;
}
@@ -1047,10 +1051,6 @@ void declare_function()
emit_out(":FUNCTION_");
emit_out(function->s);
emit_out("\n");
- if(match("main", function->s))
- {
- emit_out("COPY_esp_to_ebp\t# Deal with special case\n");
- }
statement();
/* Prevent duplicate RETURNS */
@@ -1083,6 +1083,7 @@ struct token_list* program()
{
out = NULL;
function = NULL;
+ Address_of = FALSE;
struct type* type_size;
new_type:
diff --git a/cc_types.c b/cc_types.c
index 981cbf1..eacd3de 100644
--- a/cc_types.c
+++ b/cc_types.c
@@ -55,7 +55,7 @@ void initialize_types()
struct type* d = calloc(1, sizeof(struct type));
d->name = "char**";
d->size = 4;
- d->type = c;
+ d->type = b;
d->indirect = d;
/*fix up indrects for chars */
diff --git a/functions/execve.c b/functions/execve.c
new file mode 100644
index 0000000..a8914f1
--- /dev/null
+++ b/functions/execve.c
@@ -0,0 +1,47 @@
+## Copyright (C) 2016 Jeremiah Orians
+## This file is part of stage0.
+##
+## stage0 is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## stage0 is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with stage0. If not, see .
+
+void exit(int value);
+
+void _exit(int value)
+{
+ exit(value);
+}
+
+int waitpid (int pid, int* status_ptr, int options)
+{
+ asm("LOAD_EFFECTIVE_ADDRESS_ebx %12"
+ "LOAD_INTEGER_ebx"
+ "LOAD_EFFECTIVE_ADDRESS_ecx %8"
+ "LOAD_INTEGER_ecx"
+ "LOAD_EFFECTIVE_ADDRESS_edx %4"
+ "LOAD_INTEGER_edx"
+ "LOAD_IMMEDIATE_eax %7"
+ "INT_80");
+}
+
+
+int execve(char* file_name, char** argv, char** envp)
+{
+ asm("LOAD_EFFECTIVE_ADDRESS_ebx %12"
+ "LOAD_INTEGER_ebx"
+ "LOAD_EFFECTIVE_ADDRESS_ecx %8"
+ "LOAD_INTEGER_ecx"
+ "LOAD_EFFECTIVE_ADDRESS_edx %4"
+ "LOAD_INTEGER_edx"
+ "LOAD_IMMEDIATE_eax %11"
+ "INT_80");
+}
diff --git a/functions/fork.c b/functions/fork.c
new file mode 100644
index 0000000..610aa57
--- /dev/null
+++ b/functions/fork.c
@@ -0,0 +1,22 @@
+## Copyright (C) 2016 Jeremiah Orians
+## This file is part of stage0.
+##
+## stage0 is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## stage0 is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with stage0. If not, see .
+
+int fork()
+{
+ asm("LOAD_IMMEDIATE_eax %2"
+ "LOAD_IMMEDIATE_ebx %0"
+ "INT_80");
+}
diff --git a/functions/libc-core.M1 b/functions/libc-core.M1
index fd1da63..b6465e8 100644
--- a/functions/libc-core.M1
+++ b/functions/libc-core.M1
@@ -15,7 +15,28 @@
## along with stage0. If not, see .
:_start
+
+ COPY_esp_to_ebp ; Protect esp
+
+ ;; Prepare argv
+ LOAD_BASE_ADDRESS_eax %4 ; ARGV_address = EBP + 4
+ PUSH_eax ; Put argv on the stack
+
+ ;; Prepare envp
+ COPY_ebp_to_eax ; Address we need to load from
+ LOAD_INTEGER ; Get ARGC
+ ADD_IMMEDIATE_to_eax %2 ; OFFSET = ARGC + 2
+ SAL_eax_Immediate8 !2 ; OFFSET = OFFSET * WORDSIZE
+ ADD_ebp_to_eax ; ENVP_address = ESP + OFFSET
+ PUSH_eax ; Put envp on the stack
+
+ ;; Stack offset
+ ADD_IMMEDIATE_to_ebp %4 ; Fix ebp
+
+ ;; Perform the main loop
CALL_IMMEDIATE %FUNCTION_main
- COPY_eax_to_ebx
- LOAD_IMMEDIATE_eax %1
- INT_80
+
+ ;; Exit to kernel
+ COPY_eax_to_ebx ; Using the return code given by main
+ LOAD_IMMEDIATE_eax %1 ; Syscall exit
+ INT_80 ; Exit with that code
diff --git a/functions/uname.c b/functions/uname.c
index 1a052b0..55e43a3 100644
--- a/functions/uname.c
+++ b/functions/uname.c
@@ -17,11 +17,11 @@
struct utsname
{
- char** sysname[65]; /* Operating system name (e.g., "Linux") */
- char** nodename[65]; /* Name within "some implementation-defined network" */
- char** release[65]; /* Operating system release (e.g., "2.6.28") */
- char** version[65]; /* Operating system version */
- char** machine[65]; /* Hardware identifier */
+ char sysname[65]; /* Operating system name (e.g., "Linux") */
+ char nodename[65]; /* Name within "some implementation-defined network" */
+ char release[65]; /* Operating system release (e.g., "2.6.28") */
+ char version[65]; /* Operating system version */
+ char machine[65]; /* Hardware identifier */
};
int uname(struct utsname* unameData)
diff --git a/test/common_x86/x86_defs.M1 b/test/common_x86/x86_defs.M1
index e2d8d62..43af209 100644
--- a/test/common_x86/x86_defs.M1
+++ b/test/common_x86/x86_defs.M1
@@ -14,15 +14,19 @@
## You should have received a copy of the GNU General Public License
## along with stage0. If not, see .
-DEFINE ADD_ebx_to_eax 01D8
+DEFINE ADD_IMMEDIATE_to_eax 81C0
+DEFINE ADD_IMMEDIATE_to_ebp 81C5
DEFINE ADD_eax_to_ebx 01C3
+DEFINE ADD_ebp_to_eax 01E8
+DEFINE ADD_ebx_to_eax 01D8
DEFINE AND_eax_ebx 21D8
DEFINE CALL_IMMEDIATE E8
-DEFINE CALL_eax FFD0
DEFINE CALL_IMMEDIATE E8
+DEFINE CALL_eax FFD0
DEFINE CMP 39C3
DEFINE COPY_eax_to_ebx 89C3
DEFINE COPY_eax_to_ecx 89C1
+DEFINE COPY_ebp_to_eax 89E8
DEFINE COPY_ebx_to_eax 89D8
DEFINE COPY_ebx_to_edx 89DA
DEFINE COPY_ecx_to_ebp 89CD
diff --git a/test/test.answers b/test/test.answers
index e18baa9..6bb78f3 100644
--- a/test/test.answers
+++ b/test/test.answers
@@ -1,27 +1,27 @@
-12977ab3adfa80dd4e98068e3cf30a660bfbd5fc1c2e5ad4b33fb72ef8cb11a4 test/results/test00-binary
-76b75af92dbaba02222ca1a2ae1ec28d8ea075828039821b445c2368ee31d46d test/results/test01-binary
-02c8454596a4fddc5d659a547a12386bdde54f1d3e05df2558b0e89d676f2142 test/results/test02-binary
-735ce831b4c0f9909977d659fe2b5f83920cfd38606a1d833cab4d89f9619398 test/results/test03-binary
-62cafe3e96763862e802b83666b457ceaf4b3e4032b530349253b95c5c1e7bb3 test/results/test04-binary
-2cbd9acf2e8069f5d93764e1fe235f0e1606a36e058bad8a976a6d4e97b4b8fe test/results/test05-binary
-c921f545c7baebe05e1ce60c777d6d7782ba626fdf7520f576d3ee1b849a8bbf test/results/test06-binary
-b45fae655b7f848b28ebdb8eb2e30ae789fbcf7920bc315395d53986bb1adae4 test/results/test07-binary
-d511db73158a9544a5b5f828a79751e3de8a04b81c143fd0c146fc22c938aa9f test/results/test08-binary
-907e1808f2e2b15ac72ebf13898b15c678e68ebd43d673dcd0f408d907e7962f test/results/test09-binary
-ef179cd359ba1d61d45089e314cd4ac2069c8dc4dd7494d7c766344ea3c8cf88 test/results/test10-binary
-a6ba14a8d8fe29dccfacdf1723a241ede000d7cee50d82a443f60e73d97e384e test/results/test100-binary
-5aaf399fe706d4a8c85c121c75ada29a65c293b57c98e8999961a2ef0bab0d62 test/results/test11-binary
-4f8111e73e07255ae203963438c82ea8bcff7474e1594b52b426c58a03cb30eb test/results/test12-binary
-dd74dabfdce8657ff440c1eef531cbf67a64854f2020d4d6bcb65c9cc2d199cb test/results/test13-binary
-ed0960dc5809d8cda84e7df8bf02bd0cd2aeeba4df8c752d68af434408555f8c test/results/test14-binary
-e216869c3fb06de7a41578517c797169e219b20a5697a822ba11eeef0d04f181 test/results/test15-binary
-315ae5cc5c9d5bdcae0eddd55371128e53e3e9267a2a7c53832ed0af51693bea test/results/test16-binary
-fdce9856f885418a7b2f69fc24a6cc0c85922313b49694d8030c544e4b2ad16f test/results/test17-binary
-9a426972b6df90a158aebe3b8f3eb9ef8a63ce317d764afb92be4fce16542743 test/results/test18-binary
-91b761d241dd9969230b235c6cb3bc86cc6b0076d9d1a04c4950de32228149f5 test/results/test19-binary
-48d845d20fff86183047342641cc8a6174e71c0ca004be882f0195a141bd64ea test/results/test20-binary
-65354ea5f760e42ea054785033a6519e0eee30d21b1b69ac7715ef958c5e0e2f test/results/test21-binary
-9a79bdfb35c1c17bb0c66357836382bb08d3876ae8c0c77356776d16aa7faa7f test/results/test22-binary
-96e1789254675815a3ec5ad93c1cc32c4805d1ad7f029721cef102c4501df8e2 test/results/test23-binary
-50215e4b4e2ce22a959ea7bcfc77c4d6ac45464455f5103afcaea0e84f9bf1d1 test/results/test24-binary
-0013b8786068520e386a0cf2ce39c5145462439f17c264e62a9eddb1eed0433b test/results/test99-binary
+c52562bd0aabb86ce8ca177f22f8d0455769b444df2d4d62894faab63b7151d8 test/results/test00-binary
+eae96857f2b6d8e8ba86ac06e72345ea572622b358b23978bb5f2db1baadf41c test/results/test01-binary
+8ead336d2f3f72d5874230492e0472edec61d355905e8636e3dfb2731695037c test/results/test02-binary
+2313cb3f1a2b9eb6bf15f8d43418e15d6c16f7f1b5c22700fdfc2b38beb59192 test/results/test03-binary
+b7ddb37063c541c6a315809c4438aa235d6702f54bb64f4ffc88dbe78617de81 test/results/test04-binary
+4d4ec6247a7cc9062a5b3d8adfec7199476715446723a0b882268afe6daad1f3 test/results/test05-binary
+663fc6eefe965f237b6bf5a211398c8ae1210f97ff39b59603677e92462c68c7 test/results/test06-binary
+a9a3e332d13ded5f80d7431f8717f26527b3722b33ea57760a9a5723dffc099c test/results/test07-binary
+f1c01feb865c4d552033186d9ce50dd39468a7e8aebf762886c13ad3e03b5011 test/results/test08-binary
+3b39e72f3de90ed690adfaf6145af46157cef2ec5e72867ac577fa27a0229894 test/results/test09-binary
+020e86020819cc4963e6185b22e534fcf8306b6cb116f12643f254a24688ff0a test/results/test10-binary
+db41db8bc1dc2f94367c41c33d9438634d75994f79a46296bb8907905a64c013 test/results/test100-binary
+3fd11bad4a426ce1ff8fd9c6d7d2b943effae9f3f5740b7376e426e9b0555851 test/results/test11-binary
+f98ab8e4bb35580e0dde96126d7a56aff66bda208d02c8d89390b40d6cff591c test/results/test12-binary
+5051ffca2615144419f8ec1a5d4999486ae81e7781428f59e47e866af97cef92 test/results/test13-binary
+a8218958b628066e2fda63d3933f1bf607c358d7bdfe84fc02596393698ea5f6 test/results/test14-binary
+3adb4a5f3995583ba711151361728a26c3fbf0140864d13b4b042978ca45d683 test/results/test15-binary
+d70e072f4f1f077d10ff65e9216ca8b423b996e35d68d208025db7a78b062f50 test/results/test16-binary
+9b4ba350b07cc1cf4e12dc77d0d960ded1511f13b887363b0eb33421e2f626de test/results/test17-binary
+8de7384c4633b1d5c60bbbb298d7f4b738e52fbc266ef4ef9a48b3cb995e3176 test/results/test18-binary
+b0d7982de3f257d6a5b51ad356c1aa09f24b8a69d862a90f41aef7dc83ec3b2f test/results/test19-binary
+365c96fb8368710d620a76facd6bebcdeeb6f6d30ceaf0a6f1567fc3fcbe9b54 test/results/test20-binary
+abb4d9272a262c4bf77d9cbb714cbb8ce16841a128c670394f60cb817ebe7727 test/results/test21-binary
+24a14bd0641cdbcf49b69a71c80c00fb4f0c42c5ed72f7b44e5119ad1f22d533 test/results/test22-binary
+dd9081cb6eb908e8a727b05e2fc65efe01e5c33221eee9a70565808a97c7b294 test/results/test23-binary
+6fb0c0db1732038f945172ef05c33c976396baf86571b1169a3af02e850be0d5 test/results/test24-binary
+140af7fb3ef89d84b21bd3fe69f0d3260650ec0467c0ffadf9268fad573a397f test/results/test99-binary
diff --git a/test/test100/proof.answer b/test/test100/proof.answer
index 245687a..3046896 100644
--- a/test/test100/proof.answer
+++ b/test/test100/proof.answer
@@ -1 +1 @@
-d27357f9db85e403cc09ca59123009dd4193db287b91a3414c09eafb7e28d22e test/test100/proof
+b882976ea4fb2ede866851a57fd3be0653ac1918b87e183e4c1cd6cb5c60d2b4 test/test100/proof
diff --git a/test/test23/proof.answer b/test/test23/proof.answer
index 7ae9651..132300e 100644
--- a/test/test23/proof.answer
+++ b/test/test23/proof.answer
@@ -1 +1 @@
-736df1e1db39ffd6738be5efa064e14b26cc88fd7530efb6cf663df03c0db721 test/test23/proof
+16039cd07d755cff62d61efd6945f214a79cbfa07c32386beea9b9f5b771a976 test/test23/proof
diff --git a/test/test25/.gitignore b/test/test25/.gitignore
new file mode 100644
index 0000000..0ce0949
--- /dev/null
+++ b/test/test25/.gitignore
@@ -0,0 +1,7 @@
+# Ignore the files created by script
+*.M1
+*.hex2
+proof
+
+# A place to put a good run for comparison
+actual.M1
diff --git a/test/test25/cleanup.sh b/test/test25/cleanup.sh
new file mode 100755
index 0000000..b7fe1fe
--- /dev/null
+++ b/test/test25/cleanup.sh
@@ -0,0 +1,6 @@
+#! /bin/sh
+rm -f test/test25/kaem.M1
+rm -f test/test25/kaem-footer.M1
+rm -f test/test25/kaem.hex2
+rm -f test/test25/proof
+exit 0
diff --git a/test/test25/hello.sh b/test/test25/hello.sh
new file mode 100755
index 0000000..5274989
--- /dev/null
+++ b/test/test25/hello.sh
@@ -0,0 +1,39 @@
+#! /bin/sh
+set -x
+# Build the test
+./bin/M2-Planet -f functions/exit.c \
+ -f functions/file.c \
+ -f functions/file_print.c \
+ -f functions/malloc.c \
+ -f functions/calloc.c \
+ -f functions/match.c \
+ -f functions/numerate_number.c \
+ -f functions/fork.c \
+ -f functions/execve.c \
+ -f test/test25/kaem.c \
+ --debug \
+ -o test/test25/kaem.M1 || exit 1
+
+# Build debug footer
+blood-elf -f test/test25/kaem.M1 \
+ -o test/test25/kaem-footer.M1 || exit 2
+
+# Macro assemble with libc written in M1-Macro
+M1 -f test/common_x86/x86_defs.M1 \
+ -f functions/libc-core.M1 \
+ -f test/test25/kaem.M1 \
+ -f test/test25/kaem-footer.M1 \
+ --LittleEndian \
+ --Architecture 1 \
+ -o test/test25/kaem.hex2 || exit 3
+
+# Resolve all linkages
+hex2 -f test/common_x86/ELF-i386-debug.hex2 \
+ -f test/test25/kaem.hex2 \
+ --LittleEndian \
+ --Architecture 1 \
+ --BaseAddress 0x8048000 \
+ -o test/results/test25-binary \
+ --exec_enable || exit 4
+
+exit 0
diff --git a/test/test25/kaem.c b/test/test25/kaem.c
new file mode 100644
index 0000000..f2ed363
--- /dev/null
+++ b/test/test25/kaem.c
@@ -0,0 +1,369 @@
+/* Copyright (C) 2016 Jeremiah Orians
+ * This file is part of mescc-tools.
+ *
+ * mescc-tools is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * mescc-tools is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with mescc-tools. If not, see .
+ */
+
+#include
+#include
+#include
+#include
+
+#define FALSE 0
+//CONSTANT FALSE 0
+#define TRUE 1
+//CONSTANT TRUE 1
+#define max_string 4096
+//CONSTANT max_string 4096
+#define max_args 256
+//CONSTANT max_args 256
+
+void file_print(char* s, FILE* f);
+char* numerate_number(int a);
+int match(char* a, char* b);
+
+char** tokens;
+int command_done;
+int VERBOSE;
+int STRICT;
+
+/* Function for purging line comments */
+void collect_comment(FILE* input)
+{
+ int c;
+ do
+ {
+ c = fgetc(input);
+ if(-1 == c)
+ {
+ file_print("IMPROPERLY TERMINATED LINE COMMENT!\nABORTING HARD\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+ } while('\n' != c);
+}
+
+/* Function for collecting RAW strings and removing the " that goes with them */
+int collect_string(FILE* input, int index, char* target)
+{
+ int c;
+ do
+ {
+ c = fgetc(input);
+ if(-1 == c)
+ { /* We never should hit EOF while collecting a RAW string */
+ file_print("IMPROPERLY TERMINATED RAW string!\nABORTING HARD\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+ else if('"' == c)
+ { /* Made it to the end */
+ c = 0;
+ }
+ target[index] = c;
+ index = index + 1;
+ } while(0 != c);
+ return index;
+}
+
+/* Function to collect an individual argument or purge a comment */
+char* collect_token(FILE* input)
+{
+ char* token = calloc(max_string, sizeof(char));
+ char c;
+ int i = 0;
+ do
+ {
+ c = fgetc(input);
+ if(-1 == c)
+ { /* Deal with end of file */
+ file_print("execution complete\n", stderr);
+ exit(EXIT_SUCCESS);
+ }
+ else if((' ' == c) || ('\t' == c))
+ { /* space and tab are token seperators */
+ c = 0;
+ }
+ else if('\n' == c)
+ { /* Command terminates at end of line */
+ c = 0;
+ command_done = 1;
+ }
+ else if('"' == c)
+ { /* RAW strings are everything between a pair of "" */
+ i = collect_string(input, i, token);
+ c = 0;
+ }
+ else if('#' == c)
+ { /* Line comments to aid the humans */
+ collect_comment(input);
+ c = 0;
+ command_done = 1;
+ }
+ else if('\\' == c)
+ { /* Support for end of line escapes, drops the char after */
+ fgetc(input);
+ c = 0;
+ }
+ token[i] = c;
+ i = i + 1;
+ } while (0 != c);
+
+ if(1 == i)
+ { /* Nothing worth returning */
+ free(token);
+ return NULL;
+ }
+ return token;
+}
+
+char* copy_string(char* target, char* source)
+{
+ while(0 != source[0])
+ {
+ target[0] = source[0];
+ target = target + 1;
+ source = source + 1;
+ }
+ return target;
+}
+
+char* prepend_string(char* add, char* base)
+{
+ char* ret = calloc(max_string, sizeof(char));
+ copy_string(copy_string(ret, add), base);
+ return ret;
+}
+
+char* find_char(char* string, char a)
+{
+ if(0 == string[0]) return NULL;
+ while(a != string[0])
+ {
+ string = string + 1;
+ if(0 == string[0]) return string;
+ }
+ return string;
+}
+
+char* prematch(char* search, char* field)
+{
+ do
+ {
+ if(search[0] != field[0]) return NULL;
+ search = search + 1;
+ field = field + 1;
+ } while(0 != search[0]);
+ return field;
+}
+
+char* env_lookup(char* token, char** envp)
+{
+ if(NULL == envp) return NULL;
+ int i = 0;
+ char* ret = NULL;
+ do
+ {
+ ret = prematch(token, envp[i]);
+ if(NULL != ret) return ret;
+ i = i + 1;
+ } while(NULL != envp[i]);
+ return NULL;
+}
+
+char* find_executable(char* name, char* PATH)
+{
+ if(('.' == name[0]) || ('/' == name[0]))
+ { /* assume names that start with . or / are relative or absolute */
+ return name;
+ }
+
+ char* next = find_char(PATH, ':');
+ char* trial;
+ FILE* try;
+ while(NULL != next)
+ {
+ next[0] = 0;
+ trial = prepend_string(PATH, prepend_string("/", name));
+
+ try = fopen(trial, "r");
+ if(NULL != try)
+ {
+ fclose(try);
+ return trial;
+ }
+ PATH = next + 1;
+ next = find_char(PATH, ':');
+ free(trial);
+ }
+ return NULL;
+}
+
+
+/* Function for executing our programs with desired arguments */
+void execute_command(FILE* script, char** envp)
+{
+ tokens = calloc(max_args, sizeof(char*));
+ char* PATH = env_lookup("PATH=", envp);
+ if(NULL != PATH)
+ {
+ PATH = calloc(max_string, sizeof(char));
+ copy_string(PATH, env_lookup("PATH=", envp));
+ }
+
+ char* USERNAME = env_lookup("LOGNAME=", envp);
+ if((NULL == PATH) && (NULL == USERNAME))
+ {
+ PATH = calloc(max_string, sizeof(char));
+ copy_string(PATH, "/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");
+ }
+ else if(NULL == PATH)
+ {
+ PATH = prepend_string("/home/", prepend_string(USERNAME,"/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"));
+ }
+
+ int i = 0;
+ int status = 0;
+ command_done = 0;
+ do
+ {
+ char* result = collect_token(script);
+ if(0 != result)
+ { /* Not a comment string but an actual argument */
+ tokens[i] = result;
+ i = i + 1;
+ }
+ } while(0 == command_done);
+
+ if(VERBOSE && (0 < i))
+ {
+ file_print(" +> ", stdout);
+ int j;
+ for(j = 0; j < i; j = j + 1)
+ {
+ file_print(tokens[j], stdout);
+ fputc(' ', stdout);
+ }
+ file_print("\n", stdout);
+ }
+
+ if(0 < i)
+ { /* Not a line comment */
+ char* program = find_executable(tokens[0], PATH);
+ if(NULL == program)
+ {
+ file_print(tokens[0], stderr);
+ file_print("Some weird shit went down with: ", stderr);
+ file_print("\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ int f = fork();
+ if (f == -1)
+ {
+ file_print("fork() failure", stderr);
+ exit(EXIT_FAILURE);
+ }
+ else if (f == 0)
+ { /* child */
+ /* execve() returns only on error */
+ execve(program, tokens, envp);
+ /* Prevent infinite loops */
+ _exit(EXIT_SUCCESS);
+ }
+
+ /* Otherwise we are the parent */
+ /* And we should wait for it to complete */
+ waitpid(f, &status, 0);
+
+ if(STRICT && (0 != status))
+ { /* Clearly the script hit an issue that should never have happened */
+ file_print("Subprocess error ", stderr);
+ file_print(numerate_number(status), stderr);
+ file_print("\nABORTING HARD\n", stderr);
+ /* stop to prevent damage */
+ exit(EXIT_FAILURE);
+ }
+ /* Then go again */
+ }
+}
+
+
+int main(int argc, char** argv, char** envp)
+{
+ VERBOSE = FALSE;
+ STRICT = FALSE;
+ char* filename = "kaem.run";
+ FILE* script = NULL;
+
+ int i = 1;
+ while(i <= argc)
+ {
+ if(NULL == argv[i])
+ {
+ i = i + 1;
+ }
+ else if(match(argv[i], "-h") || match(argv[i], "--help"))
+ {
+ file_print("kaem only accepts --help, --version, --verbose or no arguments\n", stdout);
+ exit(EXIT_SUCCESS);
+ }
+ else if(match(argv[i], "-f") || match(argv[i], "--file"))
+ {
+ filename = argv[i + 1];
+ i = i + 2;
+ }
+ else if(match(argv[i], "n") || match(argv[i], "--nightmare-mode"))
+ {
+ file_print("Begin nightmare", stdout);
+ envp = NULL;
+ i = i + 1;
+ }
+ else if(match(argv[i], "-V") || match(argv[i], "--version"))
+ {
+ file_print("kaem version 0.1\n", stdout);
+ exit(EXIT_SUCCESS);
+ }
+ else if(match(argv[i], "--verbose"))
+ {
+ VERBOSE = TRUE;
+ i = i + 1;
+ }
+ else if(match(argv[i], "--strict"))
+ {
+ STRICT = TRUE;
+ i = i + 1;
+ }
+ else
+ {
+ file_print("UNKNOWN ARGUMENT\n", stdout);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ script = fopen(filename, "r");
+
+ if(NULL == script)
+ {
+ file_print("The file: ", stderr);
+ file_print(filename, stderr);
+ file_print(" can not be opened!\n", stderr);
+ exit(EXIT_FAILURE);
+ }
+
+ while(1)
+ {
+ execute_command(script, envp);
+ }
+ fclose(script);
+ return EXIT_SUCCESS;
+}