/*
 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
 *
 * 
 * This program 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 2 of the
 * License, or (at your option) any later version.
 *
 *  This program 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 this program; if not, write to the Free Software          
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 
 *                                                                   USA 
 */

#include "dtc.h"
#include "srcpos.h"

extern FILE *yyin;
extern int yyparse(void);
extern void yyerror(char const *);

struct boot_info *the_boot_info;

struct boot_info *dt_from_source(const char *fname)
{
	the_boot_info = NULL;

	push_input_file(fname);

	if (yyparse() != 0)
		return NULL;

	fill_fullpaths(the_boot_info->dt, "");

	return the_boot_info;
}

static void write_prefix(FILE *f, int level)
{
	int i;

	for (i = 0; i < level; i++)
		fputc('\t', f);
}

enum proptype {
	PROP_EMPTY,
	PROP_STRING,
	PROP_CELLS,
	PROP_BYTES,
};

static enum proptype guess_type(struct property *prop)
{
	int len = prop->val.len;
	char *p = prop->val.val;
	int nnoprint = 0;
	int i;

	if (len == 0)
		return PROP_EMPTY;

	for (i = 0; i < len; i++) {
		if (! isprint(p[i]))
			nnoprint++;
	}

	if ((nnoprint == 1) && (p[len-1] == '\0'))
		return PROP_STRING;
	else if ((len % sizeof(cell_t)) == 0)
		return PROP_CELLS;
	else
		return PROP_BYTES;
		
}


static void write_tree_source_node(FILE *f, struct node *tree, int level)
{
	struct property *prop;
	struct node *child;

	write_prefix(f, level);
	if (tree->name && (*tree->name))
		fprintf(f, "%s {\n", tree->name);
	else
		fprintf(f, "/ {\n");

	for_each_property(tree, prop) {
		cell_t *cp;
		char *bp;
		void *propend;
		enum proptype type;

		write_prefix(f, level);
		fprintf(f, "\t%s", prop->name);
		type = guess_type(prop);
		propend = prop->val.val + prop->val.len;

		switch (type) {
		case PROP_EMPTY:
			fprintf(f, ";\n");
			break;

		case PROP_STRING:
			fprintf(f, " = \"%s\";\n", (char *)prop->val.val);
			break;

		case PROP_CELLS:
			fprintf(f, " = <");
			cp = (cell_t *)prop->val.val;
			for (;;) {
				fprintf(f, "%x", be32_to_cpu(*cp++));
				if ((void *)cp >= propend)
					break;
				fprintf(f, " ");
			}
			fprintf(f, ">;\n");
			break;

		case PROP_BYTES:
			fprintf(f, " = [");
			bp = prop->val.val;
			for (;;) {
				fprintf(f, "%02hhx", *bp++);
				if ((void *)bp >= propend)
					break;
				fprintf(f, " ");
			}
			fprintf(f, "];\n");
			break;
		}
	}
	for_each_child(tree, child) {
		fprintf(f, "\n");
		write_tree_source_node(f, child, level+1);
	}
	write_prefix(f, level);
	fprintf(f, "};\n");
}


void dt_to_source(FILE *f, struct boot_info *bi)
{
	struct reserve_info *re;

	for (re = bi->reservelist; re; re = re->next) {
		fprintf(f, "/memreserve/\t%016llx-%016llx;\n",
			(unsigned long long)re->re.address,
			(unsigned long long)(re->re.address + re->re.size - 1));
	}

	write_tree_source_node(f, bi->dt, 0);
}

