text: /* tag: forth bootstrap environment
   *
   * Copyright (C) 2003-2006 Stefan Reinauer, Patrick Mauritz
   *
   * See the file "COPYING" for further information about
   * the copyright and warranty status of this work.
   */
  
  #include "sysinclude.h"
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <signal.h>
  #include <fcntl.h>
  #include <unistd.h>
  #include <termios.h>
  #include <sys/stat.h>
  
  #ifdef __GLIBC__
  #define _GNU_SOURCE
  #include <getopt.h>
  #endif
  
  #include "config.h"
  #include "kernel/stack.h"
  #include "sysinclude.h"
  #include "kernel/kernel.h"
  #include "dict.h"
  #include "cross.h"
  #include "openbios-version.h"
  
  #define MAX_PATH_LEN 256
  
  #define MEMORY_SIZE (1024*1024)	/* 1M ram for hosted system */
  #define DICTIONARY_SIZE (256*1024) /* 256k for the dictionary   */
  #define TRAMPOLINE_SIZE (4*sizeof(cell)) /* 4 cells for the trampoline */
  
  /* state variables */
  static ucell *latest, *state, *base;
  static ucell *memory;
  ucell *trampoline;
  
  /* local variables */
  static int errors = 0;
  static int segfault = 0;
  static int verbose = 0;
  
  #define MAX_SRC_FILES 128
  
  static FILE *srcfiles[MAX_SRC_FILES];
  static char *srcfilenames[MAX_SRC_FILES];
  static int srclines[MAX_SRC_FILES];
  static unsigned int cursrc = 0;
  
  static char *srcbasedict;
  
  /* console variables */
  static FILE *console;
  
  #ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH
  unsigned long base_address;
  #endif
  
  /* include path handling */
  typedef struct include_path include;
  struct include_path {
          const char *path;
  	include *next;
  };
  
  static include includes = { ".", NULL };
  static FILE *depfile;
  
  static ucell * relocation_address=NULL;
  static int     relocation_length=0;
  
  /* the word names are used to generate the prim words in the
   * dictionary. This is done by the C written interpreter.
   */
  static const char *wordnames[] = {
  	"(semis)", "", "(lit)", "", "", "", "", "(do)", "(?do)", "(loop)",
  	"(+loop)", "", "", "", "dup", "2dup", "?dup", "over", "2over", "pick", "drop",
  	"2drop", "nip", "roll", "rot", "-rot", "swap", "2swap", ">r", "r>",
  	"r@", "depth", "depth!", "rdepth", "rdepth!", "+", "-", "*", "u*",
  	"mu/mod", "abs", "negate", "max", "min", "lshift", "rshift", ">>a",
  	"and", "or", "xor", "invert", "d+", "d-", "m*", "um*", "@", "c@",
  	"w@", "l@", "!", "+!", "c!", "w!", "l!", "=", ">", "<", "u>", "u<",
  	"sp@", "move", "fill", "(emit)", "(key?)", "(key)", "execute",
  	"here", "here!", "dobranch", "do?branch", "unaligned-w@",
  	"unaligned-w!", "unaligned-l@", "unaligned-l!", "ioc@", "iow@",
  	"iol@", "ioc!", "iow!", "iol!", "i", "j", "call", "sys-debug",
  	"$include", "$encode-file", "(debug", "(debug-off)"
  };
  
  /*
   * dictionary related functions.
   */
  
  /*
   * Compare two dictionaries constructed at different addresses. When
   * the cells don't match, a need for relocation is detected and the
   * corresponding bit in reloc_table bitmap is set.
   */
  static void relocation_table(unsigned char * dict_one, unsigned char *dict_two, int length)
  {
  	ucell *d1=(ucell *)dict_one, *d2=(ucell *)dict_two;
  	ucell *reloc_table;
  	int pos, bit;
  	int l=(length+(sizeof(cell)-1))/sizeof(ucell), i;
  
  	/* prepare relocation table */
  	relocation_length=(length+BITS-1)/BITS;
  	reloc_table = malloc(relocation_length*sizeof(cell));
  	memset(reloc_table,0,relocation_length*sizeof(cell));
  
  	for (i=0; i<l; i++) {
  
  		pos=i/BITS;
  		bit=i&~(-BITS);
  
  		if(d1[i]==d2[i]) {
                          reloc_table[pos] &= target_ucell(~((ucell)1ULL << bit));
  
  			// This check might bring false positives in data.
  			//if(d1[i] >= pointer2cell(dict_one) &&
  			//		d1[i] <= pointer2cell(dict_one+length))
  			//	printk("\nWARNING: inconsistent relocation (%x:%x)!\n", d1[i], d2[i]);
  		} else {
  			/* This is a pointer, it needs relocation, d2==dict */
                          reloc_table[pos] |= target_ucell((ucell)1ULL << bit);
  			d2[i] = target_ucell(target_ucell(d2[i]) - pointer2cell(d2));
  		}
  	}
  
  #ifdef CONFIG_DEBUG_DICTIONARY
  	printk("dict1 %lx dict2 %lx dict %lx\n",dict_one, dict_two, dict);
  	for (i=0; i< relocation_length ; i++)
  		printk("reloc %d %lx\n",i+1, reloc_table[i]);
  #endif
  	relocation_address=reloc_table;
  }
  
  static void write_dictionary(const char *filename)
  {
  	FILE *f;
  	unsigned char *write_data, *walk_data;
  	int  write_len;
  	dictionary_header_t *header;
  	u32 checksum=0;
  
  	/*
  	 * get memory for dictionary
  	 */
  
  	write_len  = sizeof(dictionary_header_t)+dicthead+relocation_length*sizeof(cell);
  	write_data = malloc(write_len);
  	if(!write_data) {
  		printk("panic: can't allocate memory for output dictionary (%d"
  			" bytes\n", write_len);
  		exit(1);
  	}
  	memset(write_data, 0, write_len);
  
  	/*
  	 * prepare dictionary header
  	 */
  
  	header = (dictionary_header_t *)write_data;
  	*header = (dictionary_header_t){
  		.signature	= DICTID,
  		.version	= 2,
  		.cellsize	= sizeof(ucell),
  #ifdef CONFIG_BIG_ENDIAN
  		.endianess	= -1,
  #else
  		.endianess	= 0,
  #endif
  		.checksum	= 0,
  		.compression	= 0,
  		.relocation	= -1,
                  .length         = target_ulong((uint32_t)dicthead),
                  .last           = target_ucell((ucell)((unsigned long)last
                                                         - (unsigned long)dict)),
  	};
  
  	/*
  	 * prepare dictionary data
  	 */
  
  	walk_data=write_data+sizeof(dictionary_header_t);
  	memcpy (walk_data, dict, dicthead);
  
  	/*
  	 * prepare relocation data.
  	 * relocation_address is zero when writing a dictionary core.
  	 */
  
  	if (relocation_address) {
  #ifdef CONFIG_DEBUG_DICTIONARY
  		printk("writing %d reloc cells \n",relocation_length);
  #endif
  		walk_data += dicthead;
  		memcpy(walk_data, relocation_address,
  				relocation_length*sizeof(cell));
  		/* free relocation information */
  		free(relocation_address);
  		relocation_address=NULL;
  	} else {
  		header->relocation=0;
  	}
  
  	/*
  	 * Calculate Checksum
  	 */
  
  	walk_data=write_data;
  	while (walk_data<write_data+write_len) {
  		checksum+=read_long(walk_data);
  		walk_data+=sizeof(u32);
  	}
  	checksum=(u32)-checksum;
  
  	header->checksum=target_long(checksum);
  
          if (verbose) {
                  dump_header(header);
          }
  
  	f = fopen(filename, "w");
  	if (!f) {
  		printk("panic: can't write to dictionary '%s'.\n", filename);
  		exit(1);
  	}
  
  	fwrite(write_data, write_len, 1, f);
  
  	free(write_data);
  	fclose(f);
  
  #ifdef CONFIG_DEBUG_DICTIONARY
  	printk("wrote dictionary to file %s.\n", filename);
  #endif
  }
  
  /*
   * Write dictionary as a list of ucell hex values to filename. Array
   * header and end lines are not generated.
   *
   * Cells with relocations are output using the expression
   * DICTIONARY_BASE + value.
   *
   * Define some helpful constants.
   */
  static void write_dictionary_hex(const char *filename)
  {
      FILE *f;
      ucell *walk;
  
      f = fopen(filename, "w");
      if (!f) {
          printk("panic: can't write to dictionary '%s'.\n", filename);
          exit(1);
      }
  
      for (walk = (ucell *)dict; walk < (ucell *)(dict + dicthead); walk++) {
          int pos, bit, l;
          ucell val;
  
          l = (walk - (ucell *)dict);
          pos = l / BITS;
          bit = l & ~(-BITS);
  
          val = read_ucell(walk);
          if (relocation_address[pos] & target_ucell((ucell)1ULL << bit)) {
              fprintf(f, "DICTIONARY_BASE + 0x%" FMT_CELL_x
                      ",\n", val);
          } else {
              fprintf(f, "0x%" FMT_CELL_x",\n", val);
          }
      }
  
      fprintf(f, "#define FORTH_DICTIONARY_LAST 0x%" FMT_CELL_x"\n",
              (ucell)((unsigned long)last - (unsigned long)dict));
      fprintf(f, "#define FORTH_DICTIONARY_END 0x%" FMT_CELL_x"\n",
              (ucell)dicthead);
      fclose(f);
  
  #ifdef CONFIG_DEBUG_DICTIONARY
      printk("wrote dictionary to file %s.\n", filename);
  #endif
  }
  
  static ucell read_dictionary(char *fil)
  {
  	int ilen;
  	ucell ret;
  	char *mem;
  	FILE *f;
  	struct stat finfo;
  
  	if (stat(fil, &finfo))
  		return 0;
  
  	ilen = finfo.st_size;
  
  	if ((mem = malloc(ilen)) == NULL) {
  		printk("panic: not enough memory.\n");
  		exit(1);
  	}
  
  	f = fopen(fil, "r");
  	if (!f) {
  		printk("panic: can't open dictionary.\n");
  		exit(1);
  	}
  
  	if (fread(mem, ilen, 1, f) != 1) {
  		printk("panic: can't read dictionary.\n");
  		fclose(f);
  		exit(1);
  	}
  	fclose(f);
  
  	ret = load_dictionary(mem, ilen);
  
  	free(mem);
  	return ret;
  }
  
  
  /*
   * C Parser related functions
   */
  
  /*
   * skipws skips all whitespaces (space, tab, newline) from the input file
   */
  
  static void skipws(FILE * f)
  {
  	int c;
  	while (!feof(f)) {
  		c = getc(f);
  
  		if (c == ' ' || c == '\t')
  			continue;
  
  		if (c == '\n') {
  			srclines[cursrc - 1]++;
  			continue;
  		}
  
  		ungetc(c, f);
  		break;
  	}
  }
  
  /*
   * parse gets the next word from the input stream, delimited by
   * delim. If delim is 0, any word delimiter will end the stream
   * word delimiters are space, tab and newline. The resulting word
   * will be put zero delimited to the char array line.
   */
  
  static int parse(FILE * f, char *line, char delim)
  {
  	int cnt = 0, c = 0;
  
  	while (!feof(f)) {
  		c = getc(f);
  
  		if (delim && c == delim)
  			break;
  
  		if ((!delim) && (c == ' ' || c == '\t' || c == '\n'))
  			break;
  
  		line[cnt++] = c;
  	}
  
  	/* Update current line number */
  	if (c == '\n') {
  		srclines[cursrc - 1]++;
  	}
  
  	line[cnt] = 0;
  
  	return cnt;
  }
  
  /*
   * parse_word is a small helper that skips whitespaces before a word.
   * it's behaviour is similar to the forth version parse-word.
   */
  
  static void parse_word(FILE * f, char *line)
  {
  	skipws(f);
  	parse(f, line, 0);
  }
  
  
  static void writestring(const char *str)
  {
  	unsigned int i;
  	for (i = 0; i < strlen(str); i++) {
  		dict[dicthead + i] = str[i];
  	}
  	dicthead += i + 1;
  	dict[dicthead - 1] = (char) strlen(str) + 128;
  }
  
  #define writebyte(value) {write_byte(dict+dicthead,value); dicthead++;}
  #define writecell(value) {write_cell(dict+dicthead, value); dicthead+=sizeof(cell);}
  
  /*
   * reveal a word, ie. make it visible.
   */
  
  static void reveal(void)
  {
  	*last = *latest;
  }
  
  /*
   * dictionary padding
   */
  
  static void paddict(ucell align)
  {
  	while (dicthead % align != 0)
  		writebyte(0);
  }
  
  /*
   * generic forth word creator function.
   */
  
  static void fcreate(const char *word, ucell cfaval)
  {
  	if (strlen(word) == 0) {
  		printk("WARNING: tried to create unnamed word.\n");
  		return;
  	}
  
  	writestring(word);
  	/* get us at least 1 byte for flags */
  	writebyte(0);
  	paddict(sizeof(cell));
  	/* set flags high bit. */
  	dict[dicthead - 1] = 128;
  	/* lfa and cfa */
  	writecell(read_ucell(latest));
  	*latest = target_ucell(pointer2cell(dict) + dicthead - sizeof(cell));
  	writecell(cfaval);
  }
  
  
  static ucell *buildvariable(const char *name, cell defval)
  {
  	fcreate(name, DOVAR);	/* see dict.h for DOVAR and other CFA ids */
  	writecell(defval);
  	return (ucell *) (dict + dicthead - sizeof(cell));
  }
  
  static void buildconstant(const char *name, cell defval)
  {
  	fcreate(name, DOCON);	/* see dict.h for DOCON and other CFA ids */
  	writecell(defval);
  }
  
  static void builddefer(const char *name)
  {
  	fcreate(name, DODFR);	/* see dict.h for DODFR and other CFA ids */
          writecell((ucell)0);
  	writecell((ucell)findword("(semis)"));
  }
  
  /*
   * Include file handling
   */
  
  static void add_includepath(char *path)
  {
  	include *incl = &includes;
  	include *newpath;
  
  	while (incl->next)
  		incl = incl->next;
  
  	newpath = malloc(sizeof(include));
  	if (!newpath) {
  		printk("panic: not enough memory for include path.\n");
  		exit(1);
  	}
  
  	incl->next = newpath;
  	newpath->path = path;
  	newpath->next = NULL;
  }
  
  
  static FILE *fopen_include(const char *fil)
  {
  	char fullpath[MAX_PATH_LEN];
  	FILE *ret;
  	include *incl = &includes;
  
  	while (incl) {
                  snprintf(fullpath, sizeof(fullpath), "%s/%s", incl->path, fil);
  
  		ret = fopen(fullpath, "r");
  		if (ret != NULL) {
  
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("Including '%s'\n", fil);
  #endif
  			srcfilenames[cursrc] = strdup(fil);
  			srclines[cursrc] = 1;
  			srcfiles[cursrc++] = ret;
  
                          if (depfile) {
                                  fprintf(depfile, " %s", fullpath);
                          }
  
  			return ret;
  		}
  
  		incl = incl->next;
  	}
  	return NULL;
  }
  
  
  /*
   * Forth exception handler
   */
  
  void exception(cell no)
  {
  	printk("%s:%d: ", srcfilenames[cursrc - 1], srclines[cursrc - 1]);
  
  	/* See also forth/bootstrap/interpreter.fs */
  	switch (no) {
  	case -1:
  	case -2:
  		printk("Aborted.\n");
  		break;
  	case -3:
  		printk("Stack Overflow.\n");
  		break;
  	case -4:
  		printk("Stack Underflow.\n");
  		break;
  	case -5:
  		printk("Return Stack Overflow.\n");
  		break;
  	case -6:
  		printk("Return Stack Underflow.\n");
  		break;
  	case -19:
  		printk("undefined word.\n");
  		break;
  	case -21:
  		printk("out of memory.\n");
  		break;
  	case -33:
  		printk("undefined method.\n");
  		break;
  	case -34:
  		printk("no such device.\n");
  		break;
  	default:
  		printk("error %" FMT_CELL_d " occurred.\n", no);
  	}
  	exit(1);
  }
  
  
  /*
   * This is the C version of the forth interpreter
   */
  
  static int interpret_source(char *fil)
  {
  	FILE *f;
  	char tib[160];
          cell num;
  	char *test;
  
  	const ucell SEMIS = (ucell)findword("(semis)");
  	const ucell LIT = (ucell)findword("(lit)");
  	const ucell DOBRANCH = (ucell)findword("dobranch");
  
  	if ((f = fopen_include(fil)) == NULL) {
  		printk("error while loading source file '%s'\n", fil);
  		errors++;
  		exit(1);
  	}
  
  	/* FIXME: We should read this file at
  	 * once. No need to get it char by char
  	 */
  
  	while (!feof(f)) {
  		xt_t res;
  		parse_word(f, tib);
  
  		/* if there is actually no word, we continue right away */
  		if (strlen(tib) == 0) {
  			continue;
  		}
  
  		/* Checking for builtin words that are needed to
  		 * bootstrap the forth base dictionary.
  		 */
  
  		if (!strcmp(tib, "(")) {
  			parse(f, tib, ')');
  			continue;
  		}
  
  		if (!strcmp(tib, "\\")) {
  			parse(f, tib, '\n');
  			continue;
  		}
  
  		if (!strcmp(tib, ":")) {
  			parse_word(f, tib);
  
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("create colon word %s\n\n", tib);
  #endif
  			fcreate(tib, DOCOL);	/* see dict.h for DOCOL and other CFA ids */
  			*state = (ucell) (-1);
  			continue;
  		}
  
  		if (!strcmp(tib, ";")) {
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("finish colon definition\n\n");
  #endif
  			writecell((cell)SEMIS);
  			*state = (ucell) 0;
  			reveal();
  			continue;
  		}
  
  		if (!strcasecmp(tib, "variable")) {
  			parse_word(f, tib);
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("defining variable %s\n\n", tib);
  #endif
  			buildvariable(tib, 0);
  			reveal();
  			continue;
  		}
  
  		if (!strcasecmp(tib, "constant")) {
  			parse_word(f, tib);
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("defining constant %s\n\n", tib);
  #endif
  			buildconstant(tib, POP());
  			reveal();
  			continue;
  		}
  
  		if (!strcasecmp(tib, "value")) {
  			parse_word(f, tib);
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("defining value %s\n\n", tib);
  #endif
  			buildconstant(tib, POP());
  			reveal();
  			continue;
  		}
  
  		if (!strcasecmp(tib, "defer")) {
  			parse_word(f, tib);
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("defining defer word %s\n\n", tib);
  #endif
  			builddefer(tib);
  			reveal();
  			continue;
  		}
  
  		if (!strcasecmp(tib, "include")) {
  			parse_word(f, tib);
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("including file %s\n\n", tib);
  #endif
  			interpret_source(tib);
  			continue;
  		}
  
  		if (!strcmp(tib, "[']")) {
  			xt_t xt;
  			parse_word(f, tib);
  			xt = findword(tib);
  			if (*state == 0) {
  #ifdef CONFIG_DEBUG_INTERPRETER
  				printk
  				    ("writing address of %s to stack\n\n",
  				     tib);
  #endif
  				PUSH_xt(xt);
  			} else {
  #ifdef CONFIG_DEBUG_INTERPRETER
  				printk("writing lit, addr(%s) to dict\n\n",
  				       tib);
  #endif
  				writecell(LIT);	/* lit */
  				writecell((cell)xt);
  			}
  			continue;
  			/* we have no error detection here */
  		}
  
  		if (!strcasecmp(tib, "s\"")) {
  			int cnt;
  			cell loco;
  
  			cnt = parse(f, tib, '"');
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("compiling string %s\n", tib);
  #endif
  			loco = dicthead + (6 * sizeof(cell));
  			writecell(LIT);
  			writecell(pointer2cell(dict) + loco);
  			writecell(LIT);
                          writecell((ucell)cnt);
  			writecell(DOBRANCH);
  			loco = cnt + sizeof(cell) - 1;
  			loco &= ~(sizeof(cell) - 1);
  			writecell(loco);
  			memcpy(dict + dicthead, tib, cnt);
  			dicthead += cnt;
  			paddict(sizeof(cell));
  			continue;
  		}
  
  		/* look if tib is in dictionary. */
  		/* should the dictionary be searched before the builtins ? */
  		res = findword(tib);
  		if (res) {
  			u8 flags = read_byte((u8*)cell2pointer(res) -
  						sizeof(cell) - 1);
  #ifdef CONFIG_DEBUG_INTERPRETER
                          printk("%s is 0x%" FMT_CELL_x "\n", tib, (ucell) res);
  #endif
  			if (!(*state) || (flags & 3)) {
  #ifdef CONFIG_DEBUG_INTERPRETER
                                  printk("executing %s, %" FMT_CELL_d
                                         " (flags: %s %s)\n",
  				       tib, res,
  				       (flags & 1) ? "immediate" : "",
  				       (flags & 2) ? "compile-only" : "");
  #endif
  				PC = (ucell)res;
  				enterforth(res);
  			} else {
  #ifdef CONFIG_DEBUG_INTERPRETER
  				printk("writing %s to dict\n\n", tib);
  #endif
  				writecell((cell)res);
  			}
  			continue;
  		}
  
  		/* if not look if it's a number */
  		if (tib[0] == '-')
  			num = strtoll(tib, &test, read_ucell(base));
  		else
  			num = strtoull(tib, &test, read_ucell(base));
  
  
  		if (*test != 0) {
  			/* what is it?? */
  			printk("%s:%d: %s is not defined.\n\n", srcfilenames[cursrc - 1], srclines[cursrc - 1], tib);
  			errors++;
  #ifdef CONFIG_DEBUG_INTERPRETER
  			continue;
  #else
  			return -1;
  #endif
  		}
  
  		if (*state == 0) {
  #ifdef CONFIG_DEBUG_INTERPRETER
                          printk("pushed %" FMT_CELL_x " to stack\n\n", num);
  #endif
  			PUSH(num);
  		} else {
  #ifdef CONFIG_DEBUG_INTERPRETER
                          printk("writing lit, %" FMT_CELL_x " to dict\n\n", num);
  #endif
  			writecell(LIT);	/* lit */
  			writecell(num);
  		}
  	}
  
  	fclose(f);
  	cursrc--;
  
  	return 0;
  }
  
  static int build_dictionary(void)
  {
  	ucell lfa = 0;
  	unsigned int i;
  
  	/* we need a temporary place for latest outside the dictionary */
  	latest = &lfa;
  
  	/* starting a new dictionary: clear dicthead */
  	dicthead = 0;
  
  #ifdef CONFIG_DEBUG_DICTIONARY
  	printk("building dictionary, %d primitives.\nbuilt words:",
  	       sizeof(wordnames) / sizeof(void *));
  #endif
  
  	for (i = 0; i < sizeof(wordnames) / sizeof(void *); i++) {
  		if (strlen(wordnames[i]) != 0) {
  			fcreate((char *) wordnames[i], i);
  #ifdef CONFIG_DEBUG_DICTIONARY
  			printk(" %s", wordnames[i]);
  #endif
  		}
  	}
  #ifdef CONFIG_DEBUG_DICTIONARY
  	printk(".\n");
  #endif
  
  	/* get last/latest and state */
  	state = buildvariable("state", 0);
  	last = buildvariable("forth-last", 0);
  	latest = buildvariable("latest", 0);
  
  	*latest = target_ucell(pointer2cell(latest)-2*sizeof(cell));
  
  	base=buildvariable("base", 10);
  
  	buildconstant("/c", sizeof(u8));
  	buildconstant("/w", sizeof(u16));
  	buildconstant("/l", sizeof(u32));
  	buildconstant("/n", sizeof(ucell));
  	buildconstant("/x", sizeof(u64));
  
  	reveal();
          if (verbose) {
                  printk("Dictionary initialization finished.\n");
          }
  	return 0;
  }
  
  /*
   * functions used by primitives
   */
  
  int availchar(void)
  {
  	int tmp;
  	if( cursrc < 1 ) {
  		interruptforth |= FORTH_INTSTAT_STOP;
  		/* return -1 in order to exit the loop in key() */
  		return -1;
  	}
  
  	tmp = getc( srcfiles[cursrc-1] );
  	if (tmp != EOF) {
  		ungetc(tmp, srcfiles[cursrc-1]);
  		return -1;
  	}
  
  	fclose(srcfiles[--cursrc]);
  
  	return availchar();
  }
  
  int get_inputbyte( void )
  {
  	int tmp;
  
  	if( cursrc < 1 ) {
  		interruptforth |= FORTH_INTSTAT_STOP;
  		return 0;
  	}
  
  	tmp = getc( srcfiles[cursrc-1] );
  
  	/* Update current line number */
  	if (tmp == '\n') {
  		srclines[cursrc - 1]++;
  	}
  
  	if (tmp != EOF) {
  		return tmp;
  	}
  
  	fclose(srcfiles[--cursrc]);
  
  	return get_inputbyte();
  }
  
  void put_outputbyte( int c )
  {
  	if (console)
  		fputc(c, console);
  }
  
  /*
   *  segmentation fault handler. linux specific?
   */
  
  static void
  segv_handler(int signo __attribute__ ((unused)),
  	     siginfo_t * si, void *context __attribute__ ((unused)))
  {
  	static int count = 0;
  	ucell addr = 0xdeadbeef;
  
  	if (count) {
  		printk("Died while dumping forth dictionary core.\n");
  		goto out;
  	}
  
  	count++;
  
  	if (PC >= pointer2cell(dict) && PC <= pointer2cell(dict) + dicthead)
  		addr = read_cell(cell2pointer(PC));
  
  	printk("panic: segmentation violation at %p\n", (char *)si->si_addr);
  	printk("dict=%p here=%p(dict+0x%" FMT_CELL_x ") pc=0x%" FMT_CELL_x "(dict+0x%" FMT_CELL_x ")\n",
  	       dict, dict + dicthead, dicthead, PC, PC - pointer2cell(dict));
  	printk("dstackcnt=%d rstackcnt=%d instruction=%" FMT_CELL_x "\n",
  	       dstackcnt, rstackcnt, addr);
  
  	printdstack();
  	printrstack();
  
  	printk("Writing dictionary core file\n");
  	write_dictionary("forth.dict.core");
  
        out:
  	exit(1);
  }
  
  /*
   * allocate memory and prepare engine for memory management.
   */
  
  static void init_memory(void)
  {
  	memset(memory, 0, MEMORY_SIZE);
  
  	/* we push start and end of memory to the stack
  	 * so that it can be used by the forth word QUIT
  	 * to initialize the memory allocator.
  	 * Add a cell to the start address so we don't end
  	 * up with a start address of zero during bootstrap
  	 */
  
  	PUSH(pointer2cell(memory)+sizeof(cell));
  	PUSH(pointer2cell(memory) + MEMORY_SIZE-1);
  }
  
  
  void
  include_file( const char *name )
  {
  	FILE *file;
  
  	if( cursrc >= sizeof(srcfiles)/sizeof(srcfiles[0]) ) {
  		printk("\npanic: Maximum include depth reached!\n");
  		exit(1);
  	}
  
  	file = fopen_include( name );
  	if( !file ) {
  		printk("\npanic: Failed opening file '%s'\n", name );
  		exit(1);
  	}
  }
  
  
  void
  encode_file( const char *name )
  {
  	FILE *file = fopen_include(name);
  	int size;
  
  	if( !file ) {
  		printk("\npanic: Can't open '%s'\n", name );
  		exit(1);
  	}
  	fseek( file, 0, SEEK_END );
  	size = ftell( file );
  	fseek( file, 0, SEEK_SET );
  
          if (verbose) {
                  printk("\nEncoding %s [%d bytes]\n", name, size );
          }
  	fread( dict + dicthead, size, 1, file );
  	PUSH( pointer2cell(dict + dicthead) );
  	PUSH( size );
  	dicthead += size;
  	paddict(sizeof(cell));
  }
  
  
  static void run_dictionary(char *basedict, char *confile)
  {
  	if(!basedict)
  		return;
  
  	read_dictionary(basedict);
  	PC = (ucell)findword("initialize");
  
  	if (!PC) {
  		if (verbose) {
  			printk("Unable to find initialize word in dictionary %s; ignoring\n", basedict);
  		}
  		return;
  	}
  
  	if(!srcfiles[0]) {
  		cursrc = 1;
  		srcfiles[cursrc-1] = stdin;
  	}
  
  	dstackcnt=0;
  	rstackcnt=0;
  
  	init_memory();
  	if (verbose)
  		printk("Jumping to dictionary %s...\n", basedict);
  
  	/* If a console file has been specified, open it */
  	if (confile)
  		console = fopen(confile, "w");
  
  	srcbasedict = basedict;	
  
  	enterforth((xt_t)PC);
  
  	/* Close the console file */
  	if (console)
  		fclose(console);
  }
  
  static void new_dictionary(const char *source)
  {
  	build_dictionary();
  
  	interpret_source((char *)source);
  
          if (verbose || errors > 0) {
                  printk("interpretion finished. %d errors occurred.\n",
                         errors);
          }
  }
  
  /*
   * main loop
   */
  
  #define BANNER	"OpenBIOS bootstrap kernel. (C) 2003-2006 Patrick Mauritz, Stefan Reinauer\n"\
  		"This software comes with absolutely no warranty. "\
  		"All rights reserved.\n\n"
  
  #ifdef __GLIBC__
  #define USAGE   "Usage: %s [options] [dictionary file|source file]\n\n" \
  		"   -h|--help		show this help\n"		\
  		"   -V|--version	print version and exit\n"	\
  		"   -v|--verbose        print debugging information\n"	\
  		"   -I|--include dir	add dir to include path\n"	\
  		"   -d|--source-dictionary bootstrap.dict\n"		\
  		"			use this dictionary as base\n"	\
  		"   -D|--target-dictionary output.dict\n"		\
  		"			write to output.dict\n"		\
  		"   -c|--console output.log\n"		\
  		"			write kernel console output to log file\n"	\
  		"   -s|--segfault	install segfault handler\n"     \
                  "   -M|--dependency-dump file\n"                         \
                  "                       dump dependencies in Makefile format\n\n" \
                  "   -x|--hexdump        output format is C language hex dump\n"
  #else
  #define USAGE   "Usage: %s [options] [dictionary file|source file]\n\n" \
  		"   -h		show this help\n"		\
  		"   -V		print version and exit\n"	\
  		"   -v		print debugging information\n"	\
  		"   -I		add dir to include path\n"	\
  		"   -d bootstrap.dict\n"			\
  		"		use this dictionary as base\n"	\
  		"   -D output.dict\n"				\
  		"		write to output.dict\n"		\
  		"   -c output.log\n"		\
  		"		write kernel console output to log file\n"	\
  		"   -s		install segfault handler\n\n"   \
                  "   -M file     dump dependencies in Makefile format\n\n" \
                  "   -x          output format is C language hex dump\n"
  #endif
  
  int main(int argc, char *argv[])
  {
  	struct sigaction sa;
  
  	unsigned char *ressources=NULL; /* All memory used by us */
          const char *dictname = NULL;
  	char *basedict = NULL;
  	char *consolefile = NULL;
          char *depfilename = NULL;
  
  	unsigned char *bootstrapdict[2];
          int c, cnt, hexdump = 0;
  
          const char *optstring = "VvhsI:d:D:c:M:x?";
  
  	while (1) {
  #ifdef __GLIBC__
  		int option_index = 0;
  		static struct option long_options[] = {
  			{"version", 0, NULL, 'V'},
  			{"verbose", 0, NULL, 'v'},
  			{"help", 0, NULL, 'h'},
  			{"segfault", 0, NULL, 's'},
  			{"include", 1, NULL, 'I'},
  			{"source-dictionary", 1, NULL, 'd'},
  			{"target-dictionary", 1, NULL, 'D'},
  			{"console", 1, NULL, 'c'},
                          {"dependency-dump", 1, NULL, 'M'},
                          {"hexdump", 0, NULL, 'x'},
  		};
  
  		/*
  		 * option handling
  		 */
  
  		c = getopt_long(argc, argv, optstring, long_options,
  				&option_index);
  #else
  		c = getopt(argc, argv, optstring);
  #endif
  		if (c == -1)
  			break;
  
  		switch (c) {
  		case 'V':
                          printk("Version " OPENBIOS_VERSION_STR "\n");
  			return 0;
  		case 'h':
  		case '?':
                          printk("Version " OPENBIOS_VERSION_STR "\n" USAGE,
                                 argv[0]);
  			return 0;
  		case 'v':
  			verbose = 1;
  			break;
  		case 's':
  			segfault = 1;
  			break;
  		case 'I':
  #ifdef CONFIG_DEBUG_INTERPRETER
  			printk("adding '%s' to include path\n", optarg);
  #endif
  			add_includepath(optarg);
  			break;
  		case 'd':
  			if (!basedict) {
  				basedict = optarg;
  			}
  			break;
  		case 'D':
  			if(!dictname) {
  				dictname = optarg;
  			}
  			break;
  		case 'c':
  			if (!consolefile) {
  				consolefile = optarg;
  			}
  			break;
                  case 'M':
                          if (!depfilename) {
                                  depfilename = optarg;
                          }
                          break;
                  case 'x':
                          hexdump = 1;
                          break;
  		default:
  			return 1;
  		}
  	}
  
          if (!dictname) {
              dictname = "bootstrap.dict";
          }
          if (verbose) {
                  printk(BANNER);
                  printk("Using source dictionary '%s'\n", basedict);
                  printk("Dumping final dictionary to '%s'\n", dictname);
                  printk("Dumping dependencies to '%s'\n", depfilename);
          }
  
          if (argc < optind) {
  		printk(USAGE, argv[0]);
  		return 1;
  	}
  
          if (depfilename) {
              depfile = fopen(depfilename, "w");
              if (!depfile) {
                  printk("panic: can't write to dependency file '%s'.\n",
                         depfilename);
                  exit(1);
              }
              fprintf(depfile, "%s:", dictname);
          }
  
  	/*
  	 * Get all required resources
  	 */
  
  
  	ressources = malloc(MEMORY_SIZE + (2 * DICTIONARY_SIZE) + TRAMPOLINE_SIZE);
  	if (!ressources) {
  		printk("panic: not enough memory on host system.\n");
  		return 1;
  	}
  
  #ifdef NATIVE_BITWIDTH_SMALLER_THAN_HOST_BITWIDTH
  	base_address=(unsigned long)ressources;
  #endif
  
  	memory = (ucell *)ressources;
  
  	bootstrapdict[0] = ressources + MEMORY_SIZE;
  	bootstrapdict[1] = ressources + MEMORY_SIZE + DICTIONARY_SIZE;
  	trampoline = (ucell *)(ressources + MEMORY_SIZE + DICTIONARY_SIZE + DICTIONARY_SIZE);
  
  #ifdef CONFIG_DEBUG_INTERPRETER
  	printf("memory: %p\n",memory);
  	printf("dict1: %p\n",bootstrapdict[0]);
  	printf("dict2: %p\n",bootstrapdict[1]);
  	printf("trampoline: %p\n",trampoline);
  	printf("size=%d, trampoline_size=%d\n",MEMORY_SIZE + (2 *
  				DICTIONARY_SIZE) + TRAMPOLINE_SIZE,
  			TRAMPOLINE_SIZE);
  #endif
  
  	if (trampoline == NULL) {
  		/* We're using side effects which is to some extent nasty */
  		printf("WARNING: no trampoline!\n");
  	} else {
  		init_trampoline(trampoline);
  	}
  
  	if (!segfault) {
  		if (verbose)
  			printk("Installing SIGSEGV handler...");
  
  		sa.sa_sigaction = segv_handler;
  		sigemptyset(&sa.sa_mask);
  		sa.sa_flags = SA_SIGINFO | SA_NODEFER;
                  sigaction(SIGSEGV, &sa, NULL);
  
  		if (verbose)
  			printk("done.\n");
  	}
  
  	/*
  	 * Now do the real work
  	 */
  
  	for (cnt=0; cnt<2; cnt++) {
                  if (verbose) {
                          printk("Compiling dictionary %d/%d\n", cnt+1, 2);
                  }
  		dict=bootstrapdict[cnt];
  		if(!basedict) {
  			new_dictionary(argv[optind]);
  		} else {
  			for (c=argc-1; c>=optind; c--)
  				include_file(argv[c]);
  
  			run_dictionary(basedict, consolefile);
  		}
                  if (depfile) {
                          fprintf(depfile, "\n");
                          fclose(depfile);
                          depfile = NULL;
                  }
  		if(errors)
  			break;
  	}
  
  #ifndef CONFIG_DEBUG_INTERPRETER
  	if (errors)
  		printk("dictionary not dumped to file.\n");
  	else
  #endif
  	{
  		relocation_table( bootstrapdict[0], bootstrapdict[1], dicthead);
                  if (hexdump) {
                      write_dictionary_hex(dictname);
                  } else {
                      write_dictionary(dictname);
                  }
  	}
  
  	free(ressources);
  
          if (errors)
              return 1;
          else
              return 0;
  }
  