diff lwasm/input.c @ 329:c15cca3ae6a2

Created first pass of input layer
author lost
date Sun, 28 Feb 2010 05:01:31 +0000
parents 591d01b343b9
children 81c005b82775
line wrap: on
line diff
--- a/lwasm/input.c	Sat Feb 13 06:08:26 2010 +0000
+++ b/lwasm/input.c	Sun Feb 28 05:01:31 2010 +0000
@@ -27,57 +27,316 @@
 less difficult.
 */
 
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
 #include <lw_alloc.h>
 #include <lw_stringlist.h>
+#include <lw_string.h>
+#include "lwasm.h"
 
-struct input_layer
+/*
+Data type for storing input buffers
+*/
+
+enum input_types_e
 {
-	lw_stringlist_t inputlist;
-	struct input_layer *nextlayer;
-	
-	FILE *fp;
+	input_type_file,			// regular file, no search path
+	input_type_include,			// include path, start from "local"
+	input_type_string,			// input from a string
+
+	input_type_error			// invalid input type
+};
+
+struct input_stack
+{
+	struct input_stack *next;
+	int type;
+	void *data;
+	int data2;
+	char *filespec;
 };
 
+static struct input_stack *is = NULL;
 
-static struct input_layer *layerstack = NULL;
+void input_init(asmstate_t *as)
+{
+	struct input_stack *t;
+	
+	lw_stringlist_reset(as -> input_files);
+	while (is)
+	{
+		t = is;
+		is = is -> next;
+		lw_free(t);
+	}
+}
 
-void input_push(lw_stringlist_t list)
+void input_pushpath(asmstate_t *as, char *fn)
 {
-	struct input_layer *i;
+	/* take apart fn into path and filename then push the path */
+	/* onto the current file path stack */
+	char *dn, *dp;
+	int o;
+	
+	dn = lw_strdup(fn);
+	dp = dn + strlen(dp);
+	
+	while (--dp != dn)
+	{
+		if (*dp == '/')
+			break;
+	}
+	if (*dp == '/')
+		*dp = '\0';
 	
-	i = lw_alloc(sizeof(struct input_layer));
-	i -> nextlayer = layerstack;
-	layerstack = i;
-	i -> inputlist = lw_stringlist_copy(list);
+	if (dp == dn)
+	{
+		lw_free(dn);
+		dn = lw_strdup(".");
+		lw_stack_push(as -> file_dir, dn);
+		return;
+	}
+	dp = lw_strdup(dn);
+	lw_free(dn);
+	lw_stack_push(as -> file_dir, dp);
+}
+
+void input_openstring(asmstate_t *as, char *s, char *str)
+{
+	struct input_stack *t;
+	
+	t = lw_alloc(sizeof(struct input_stack));
+	t -> filespec = lw_strdup(s);
+
+	t -> type = input_type_string;
+	t -> data = lw_strdup(str);
+	t -> data2 = 0;
+	t -> next = is;
+	is = t;
+	t -> filespec = lw_strdup(s);
 }
 
-/* fetch a line of input from the top of the input stack */
-/* return NULL if no input left */
-char *input_fetchline(void)
+void input_open(asmstate_t *as, char *s)
 {
-again:
-	if (!layerstack)
-		return NULL;
-	
-	if (!layerstack -> fp)
+	struct input_stack *t;
+	char *s2;
+	char *p, *p2;
+
+	t = lw_alloc(sizeof(struct input_stack));
+	t -> filespec = lw_strdup(s);
+
+	for (s2 = s; *s2 && *s2 != ':'; s2++)
+		/* do nothing */ ;
+	if (!s2)
+	{
+		t -> type = input_type_file;
+	}
+	else
 	{
-		// no open file
-		char *fn;
+		char *ts;
+		
+		ts = lw_strndup(s, s2 - s);
+		s = s2 + 1;
 		
-		fn = lw_stringlist_current(layerstack -> inputlist);
-		lw_stringlist_next(layerstack -> inputlist);
-		if (!fn)
+		if (!strcmp(ts, "include"))
+			t -> type = input_type_include;
+		else if (!strcmp(ts, "file"))
+			t -> type = input_type_file;
+		else
+			t -> type = input_type_error;
+	}
+		
+	t -> next = is;
+	is = t;
+	
+	switch (is -> type)
+	{
+	case input_type_include:
+		/* first check for absolute path and if so, skip path */
+		if (*s == '/')
 		{
-			struct input_list *t;
-			t = layerstack;
-			layerstack = layerstack -> nextlayer;
-			lw_stringlist_destroy(t -> inputlist);
-			lw_free(t);
-			goto again;
+			/* absolute path */
+			is -> data = fopen(s, "rb");
+			if (!is -> data)
+			{
+				lw_error("Cannot open file '%s': %s", s, strerror(errno));
+			}
+			input_pushpath(as, s);
+			break;
 		}
 		
-		// open the file here
+		/* relative path, check relative to "current file" directory */
+		p = lw_stack_top(as -> file_dir);
+		0 == asprintf(&p2, "%s/%s", p, s);
+		is -> data = fopen(p2, "rb");
+		if (is -> data)
+		{
+			input_pushpath(as, p2);
+			lw_free(p2);
+			break;
+		}
+		lw_free(p2);
+
+		/* now check relative to entries in the search path */
+		lw_stringlist_reset(as -> include_list);
+		while (p = lw_stringlist_current(as -> include_list))
+		{
+			0 == asprintf(&p2, "%s/%s", p, s);
+			is -> data = fopen(p2, "rb");
+			if (is -> data)
+			{
+				input_pushpath(as, p2);
+				lw_free(p2);
+				return;
+			}
+			lw_free(p2);
+			lw_stringlist_next(as -> include_list);
+		}
+		lw_error("Cannot open include file '%s': %s", s, strerror(errno));
+
+	case input_type_file:
+		is -> data = fopen(s, "rb");
+
+		if (!is -> data)
+		{
+			lw_error("Cannot open file '%s': %s", s, strerror(errno));
+		}
+		input_pushpath(as, s);
+		return;
+	}
+
+	lw_error("Cannot figure out how to open '%s'.", s);
+}
+
+char *input_readline(asmstate_t *as)
+{
+	char *s;
+	char linebuff[2049];
+	int lbloc;
+	int eol = 0;
+	
+	/* if no file is open, open one */
+nextfile:
+	if (!is) {
+		s = lw_stringlist_current(as -> input_files);
+		if (!s)
+			return NULL;
+		lw_stringlist_next(as -> input_files);
+		input_open(as, s);
 	}
 	
+	switch (is -> type)
+	{
+	case input_type_file:
+	case input_type_include:
+		/* read from a file */
+		for (;;)
+		{
+			int c, c2;
+			c = fgetc(is -> data);
+			lbloc = 0;
+			if (c == EOF)
+			{
+				if (lbloc == 0)
+				{
+					struct input_stack *t;
+					fclose(is -> data);
+					lw_free(lw_stack_pop(as -> file_dir));
+					lw_free(is -> filespec);
+					t = is -> next;
+					lw_free(is);
+					is = t;
+					goto nextfile;
+				}
+				linebuff[lbloc] = '\0';
+				eol = 1;
+			}
+			else if (c == '\r')
+			{
+				linebuff[lbloc] = '\0';
+				eol = 1;
+				c2 = fgetc(is -> data);
+				if (c2 == EOF)
+					c = EOF;  
+				else if (c2 != '\n')
+					ungetc(c2, is -> data);  
+			}
+			else if (c == '\n')
+			{
+				linebuff[lbloc] = '\0';
+				eol = 1;
+				c2 = fgetc(is -> data);
+				if (c2 == EOF)
+					c = EOF;  
+				else if (c2 != '\r')
+					ungetc(c2, is -> data);  
+			}
+			else
+			{
+				if (lbloc < 2048)
+					linebuff[lbloc++] = c;
+			}
+			if (eol)
+			{
+				s = lw_strdup(linebuff);
+				return s;
+			}
+		}
+
+	case input_type_string:
+		/* read from a string */
+		if (((char *)(is -> data))[is -> data2] == '\0')
+		{
+			struct input_stack *t;
+			lw_free(is -> data);
+			lw_free(is -> filespec);
+			t = is -> next;
+			lw_free(is);
+			is = t;
+			goto nextfile;
+		}
+		s = (char *)(is -> data);
+		lbloc = 0;
+		for (;;)
+		{
+			int c;
+			c = s[is -> data2];
+			if (c)
+				is -> data2++;
+			if (c == '\0')
+			{
+				linebuff[lbloc] = '\0';
+				eol = 1;
+			}
+			else if (c == '\r')
+			{
+				linebuff[lbloc] = '\0';
+				eol = 1;
+				if (s[is -> data2] == '\n')
+					is -> data2++;
+			}
+			else if (c == '\n')
+			{
+				linebuff[lbloc] = '\0';
+				eol = 1;
+				if (s[is -> data2] == '\r')
+					is -> data2++;
+			}
+			else
+			{
+				if (lbloc < 2048)
+					linebuff[lbloc++] = c;
+			}
+			if (eol)
+			{
+				s = lw_strdup(linebuff);
+				return s;
+			}
+		}
 	
+	default:
+		lw_error("Problem reading from unknown input type");
+	}
 }