/*
 * Copyright (C) 2015-2016 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#define DEBUG	1

#include <assert.h>
#include <errno.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "xml-schem.h"

#define MAX_PINS    128
#define MAX_NAME    128
#define MAX_ELEMENTS	1024

struct pair {
	double x;
	double y;
};

/* gets the maximal image size */
static void
getXY(struct xml_schem_ge *ge, struct pair *pair)
{
	for (; ge; ge = ge->next) {
		switch(ge->type) {
		case GE_LINE:
			if (ge->line.x0 > pair->x) {
				pair->x = ge->line.x0;
			}
			if (ge->line.x1 > pair->x) {
				pair->x = ge->line.x1;
			}
			if (ge->line.y0 > pair->y) {
				pair->y = ge->line.y0;
			}
			if (ge->line.y1 > pair->y) {
				pair->y = ge->line.y1;
			}
			break;
		case GE_BOX:
			if (ge->box.x0 > pair->x) {
				pair->x = ge->box.x0;
			}
			if (ge->box.x1 > pair->x) {
				pair->x = ge->box.x1;
			}
			if (ge->box.y0 > pair->y) {
				pair->y = ge->box.y0;
			}
			if (ge->box.y1 > pair->y) {
				pair->y = ge->box.y1;
			}
			break;
		case GE_TEXT:
			if (ge->text.x > pair->x) {
				pair->x = ge->text.x;
			}
			if (ge->text.y > pair->y) {
				pair->y = ge->text.y;
			}
			break;
		case GE_CIRCLE:
			if ((ge->circle.x + ge->circle.r) > pair->x) {
				pair->x = ge->circle.x + ge->circle.r;
			}
			if ((ge->circle.y + ge->circle.r) > pair->y) {
				pair->y = ge->circle.y + ge->circle.r;
			}
			break;
		}
	}
	return;
}

/* Hashmap implementation similar to
 * http://www2.informatik.hu-berlin.de/~weber/slipOff/
 * to find all connected signals*/

/* this should be prime */
#define TABLE_STARTSIZE 5717

#define ACTIVE 1

typedef struct {
	char data;
	int flags;
	long long key;
} hEntry;

struct s_hashmap {
	hEntry* table;
	long size, count;
};
typedef struct s_hashmap hashmap;

/*forward*/ static void
hashmapInsert(hashmap*, char data, unsigned long long key);

static unsigned long
isPrime(unsigned long val)
{
	int i, p, exp, a;

	for (i = 9; i --;) {
		a = (rand() % (val - 4)) + 2;
		p = 1;
		exp = val - 1;
		while (exp) {
			if (exp & 1)
				p = (p * a) % val;

			a = (a * a) % val;
			exp >>= 1;
		}

		if (p != 1) {
			return 0;
		}
	}

	return 1;
}

static int
findPrimeGreaterThan(int val)
{
	if (val & 1) {
		val += 2;
	} else {
		val++;
	}

	while (! isPrime(val)) {
		val += 2;
	}

	return val;
}

static void
rehash(hashmap* hm)
{
	long size = hm->size;
	hEntry* table = hm->table;

	hm->size = findPrimeGreaterThan(size << 1);
	hm->table = (hEntry*)calloc(sizeof(hEntry), hm->size);
	hm->count = 0;

	while (--size >= 0) {
		if (table[size].flags == ACTIVE) {
			hashmapInsert(hm, table[size].data, table[size].key);
		}
	}

	free(table);
}

static hashmap *
hashmapCreate(int startsize)
{
	hashmap* hm = (hashmap*)malloc(sizeof(hashmap));

	if (! startsize) {
		startsize = TABLE_STARTSIZE;
	} else {
		startsize = findPrimeGreaterThan(startsize-2);
	}

	hm->table = (hEntry*) calloc(sizeof(hEntry), startsize);
	hm->size = startsize;
	hm->count = 0;

	return hm;
}

static void
hashmapInsert(hashmap* hash, char data, unsigned long long key)
{
	long index, i, step;

	if (hash->size <= hash->count) {
		rehash(hash);
	}
	do {
		index = key % hash->size;
		step = (key % (hash->size-2)) + 1;

		for (i = 0; i < hash->size; i++) {
			if (hash->table[index].flags & ACTIVE) {
				if (hash->table[index].key == key) {
					hash->table[index].data = data;
					return;
				}
			} else {
				hash->table[index].flags |= ACTIVE;
				hash->table[index].data = data;
				hash->table[index].key = key;
				++hash->count;
				return;
			}
			index = (index + step) % hash->size;
		}

		rehash(hash);
	}
	while (1);
}

static char
hashmapRemove(hashmap* hash, unsigned long long key)
{
	long index, i, step;

	index = key % hash->size;
	step = (key % (hash->size - 2)) + 1;

	for (i = 0; i < hash->size; i++) {
		if (hash->table[index].data) {
			if (hash->table[index].key == key) {
				if (hash->table[index].flags & ACTIVE) {
					hash->table[index].flags &= ~ACTIVE;
					--hash->count;
					return hash->table[index].data;
				}
				else {/* in, but not active (i.e. deleted) */
					return 0;
				}
			}
		} else {/* found an empty place (can't be in) */
			return 0;
		}

		index = (index + step) % hash->size;
	}
	/* everything searched through, but not in */
	return 0;
}

static char
hashmapGet(hashmap* hash, unsigned long long key)
{
	if (hash->count) {
		long index, i, step;
		index = key % hash->size;
		step = (key % (hash->size - 2)) + 1;

		for (i = 0; i < hash->size; i++) {
			if (hash->table[index].key == key) {
				if (hash->table[index].flags & ACTIVE) {
					return hash->table[index].data;
				}
				break;
			} else {
				if (! hash->table[index].data) {
					break;
				}
			}
			index = (index + step) % hash->size;
		}
	}
	return 0;
}

static char *
mangle(const char *name)
{
	static char buf[16][1024];
	static int n = 0;
	char *to;
	int x;

	to = buf[n];
	n = (n + 1) % 16;

	x = 0;

	while (*name != '\0') {
		if (('0' <= *name && *name <= '9')
		    || ('A' <= *name && *name <= 'Z')
		    || ('a' <= *name && *name <= 'z')) {
			to[x++] = *name++;
		} else {
			unsigned char c;

			c = *name++;
			to[x++] = '_';
			to[x++] = (c / 16 < 10) ? (c / 16 + '0')
				: (c / 16 - 10 + 'A');
			to[x++] = (c % 16 < 10) ? (c % 16 + '0')
				: (c % 16 - 10 + 'A');
		}
	}

	to[x] = '\0';

	return to;
}

static char *
mangle_vcd(const char *name)
{
	static char buf[16][1024];
	static int n = 0;
	char *to;
	int x;

	to = buf[n];
	n = (n + 1) % 16;

	x = 0;

	while (*name != '\0') {
		if (*name == '\\') {
			to[x++] = '\\';
			to[x++] = '\\';
			to[x++] = *name++;
		} else if (33 <= *name && *name <= 126) {
			to[x++] = *name++;
		} else {
			unsigned char c;

			c = *name++;
			to[x++] = '\\';
			to[x++] = '\\';
			to[x++] = 'x';
			to[x++] = (c / 16 < 10) ? (c / 16 + '0')
				: (c / 16 - 10 + 'A');
			to[x++] = (c % 16 < 10) ? (c % 16 + '0')
				: (c % 16 - 10 + 'A');
		}
	}

	to[x] = '\0';

	return to;
}

static void
create_gui_gtk_c(const char* inname, struct xml_schem *schem)
{
	FILE *f;
	char filename[MAX_NAME];
	strncpy(filename, inname, MAX_NAME-strlen("_gui_gtk.c"));
	strcat(filename, "_gui_gtk.c");

	f = fopen(filename, "w");
	if (f == NULL) {
		fprintf(stderr, "Can't open output file %s!\n",
			filename);
		exit(EXIT_FAILURE);
	}

	if (strrchr(inname, '/')) {
		inname = strrchr(inname, '/') + 1;
	}
	struct xml_schem_component *comp;
	struct xml_schem_port *port;
	struct xml_schem_signal *sig;
	struct xml_schem_ge *ge;

	fprintf(f, "/*\n");
	fprintf(f, " * Copyright (C) 2014 FAUmachine Team "
		"<info@faumachine.org>.\n");
	fprintf(f, " * This program is free software. "
		"You can redistribute it and/or modify it\n");
	fprintf(f, " * under the terms of the GNU General Public License, "
		"either version 2 of\n");
	fprintf(f, " * the License, or (at your option) any later version. "
		"See COPYING.\n");
	fprintf(f, " */\n");
	fprintf(f, "\n");
	fprintf(f, "#define DEBUG 0\n");
	fprintf(f, "#define TRACE 1\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"config.h\"\n");
	fprintf(f, "\n");
	fprintf(f, "#include <assert.h>\n");
	fprintf(f, "#include <stdio.h>\n");
	fprintf(f, "#include <stdlib.h>\n");
	fprintf(f, "#include <string.h>\n");
	fprintf(f, "\n");
	fprintf(f, "#include <gtk/gtk.h>\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"glue-gui-gtk.h\"\n");
	fprintf(f, "#include \"glue-gui-gtk-monitor.h\"\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"glue.h\"\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"%s_gui_gtk.h\"\n", inname);
	fprintf(f, "\n");
	fprintf(f, "#define COMP_(x) %s_ ## x\n", inname);
	fprintf(f, "\n");

	fprintf(f, "struct cpssp {\n");
	fprintf(f, "\tGtkWidget *gui;\n");

	fprintf(f, "\tint pixmap_init;\n");
	fprintf(f, "\tGdkPixmap *pixmap;\n");
	fprintf(f, "\tGtkWidget *darea;\n");

	fprintf(f, "\t/* colors */\n");
	fprintf(f, "\tGdkColor gdk_red;\n");
	fprintf(f, "\tGdkColor gdk_green;\n");
	fprintf(f, "\tGdkColor gdk_blue;\n");
	fprintf(f, "\tGdkColor gdk_black;\n");
	fprintf(f, "\tFILE *f;\n");
	fprintf(f, "\tint scale;\n");
	fprintf(f, "\n");
	fprintf(f, "\tint x_size;\n");
	fprintf(f, "\tint y_size;\n");

	fprintf(f, "\t/* ports */\n");

	/* twice, so change is detected */
	fprintf(f, "\t/* two ints per signal, "
		"so changes are detectable lateron */\n");

	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tunsigned int oldport_%s;\n", mangle(port->name));
		fprintf(f, "\tunsigned int port_%s;\n", mangle(port->name));
	}

	fprintf(f, "\t/* gui ports */\n");
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tunsigned int oldport_%s;\n", sig->id);
		fprintf(f, "\tunsigned int port_%s;\n", sig->id);
	}
	fprintf(f, "};\n\n");

	fprintf(f, "static void COMP_(draw_all)(struct cpssp*);\n");

	fprintf(f, "\n");

	/* get max window size */
	struct pair pair;
	pair.x = 0;
	pair.y = 0;
	for (sig = schem->sig_first; sig; sig = sig->next) {
		getXY(sig->ge_first, &pair);
	}
	for (comp = schem->comp_first; comp; comp = comp->next) {
		getXY(comp->ge_first, &pair);
	}
	for (port = schem->port_first; port; port = port->next) {
		getXY(port->ge_first, &pair);
	}
	for (comp = schem->comp_first; comp; comp = comp->next) {
		for (port = comp->port_first; port; port = port->next) {
			getXY(port->ge_first, &pair);
		}
	}
	/* add a border */
	pair.x += 150;
	pair.y += 150;

	/* pixmap */
	fprintf(f, "/* Create a new backing pixmap "
		"of the appropriate size */\n");
	fprintf(f, "static gboolean\n");
	fprintf(f, "create_pixmap(struct cpssp *cpssp)\n");
	fprintf(f, "{\n");

	fprintf(f, "\tif (gtk_widget_get_realized (cpssp->darea)) {\n");
	fprintf(f, "\t\tcpssp->pixmap_init = 1;\n");
	fprintf(f, "\t} else {\n");
	fprintf(f, "\t\treturn FALSE;\n");
	fprintf(f, "\t}\n");

	fprintf(f, "\tif ((6 - cpssp->scale)"
		"!= GUI_GTK_MONITOR(cpssp->gui)->zoom_step) {\n");
	fprintf(f, "\t\tcpssp->scale = 6 "
		"- GUI_GTK_MONITOR(cpssp->gui)->zoom_step;\n");
	fprintf(f, "\t\tgtk_widget_set_size_request (cpssp->darea,\n"
		"\t\t\t\t\t     cpssp->x_size / cpssp->scale,\n"
		"\t\t\t\t\t     cpssp->y_size / cpssp->scale);\n");
	fprintf(f, "\t}\n");

	fprintf(f, "\tcpssp->pixmap = gdk_pixmap_new(cpssp->darea->window,\n");
	fprintf(f, "\t\t\t\t       cpssp->x_size,\n");
	fprintf(f, "\t\t\t\t       cpssp->y_size,\n");
	fprintf(f, "\t\t\t\t       -1);\n");

	fprintf(f, "\tCOMP_(draw_all)(cpssp);\n");

	fprintf(f, "\treturn TRUE;\n");
	fprintf(f, "}\n");
	fprintf(f, "\n");

	/* draw line */
	fprintf(f, "static void\n");
	fprintf(f, "draw_line(struct cpssp *cpssp, GtkWidget *widget,\n"
		"\t  int x1, int y1, int x2, int y2, unsigned int val)\n");
	fprintf(f, "{\n");

	fprintf(f, "\t/* check for init */\n");
	fprintf(f, "\tif (! cpssp->pixmap_init) {\n");
	fprintf(f, "\t\tif (! create_pixmap(cpssp)) {\n");
	fprintf(f, "\t\t\treturn;\n");
	fprintf(f, "\t\t}\n");
	fprintf(f, "\t}\n");

	fprintf(f, "\t/* set color */\n");

	fprintf(f, "\tGdkColor color;\n");
	fprintf(f, "\tif (val == SIG_STD_LOGIC_1 "
		"|| val == SIG_STD_LOGIC_H) {\n");
	fprintf(f, "\t\tcolor = cpssp->gdk_green;\n");
	fprintf(f, "\t} else if (val == SIG_STD_LOGIC_0) {\n");
	fprintf(f, "\t\tcolor = cpssp->gdk_red;\n");
	fprintf(f, "\t} else if (val == SIG_STD_LOGIC_Z) {\n");
	fprintf(f, "\t\tcolor = cpssp->gdk_blue;\n");
	fprintf(f, "\t} else {\n");
	fprintf(f, "\t\tcolor = cpssp->gdk_black;\n");
	fprintf(f, "\t}\n");
	fprintf(f, "\tgtk_widget_modify_fg "
		"(widget, GTK_STATE_NORMAL, &color);\n");
	fprintf(f, "\n");
	fprintf(f, "\tint tmp_x1 = x1 / cpssp->scale;\n");
	fprintf(f, "\tint tmp_y1 = y1 / cpssp->scale;\n");
	fprintf(f, "\tint tmp_x2 = x2 / cpssp->scale;\n");
	fprintf(f, "\tint tmp_y2 = y2 / cpssp->scale;\n");
	fprintf(f, "\n");
	fprintf(f, "\t/* draw a line acoording to the color set */\n");
	fprintf(f, "\tgdk_draw_line(cpssp->pixmap,\n");
	fprintf(f, "\t\t      widget->style->fg_gc[gtk_widget_get_state "
		"(widget)],\n");
	fprintf(f, "\t\t      tmp_x1,\n");
	fprintf(f, "\t\t      tmp_y1,\n");
	fprintf(f, "\t\t      tmp_x2,\n");
	fprintf(f, "\t\t      tmp_y2);\n");
	fprintf(f, "}\n");
	fprintf(f, "\n");

	/* draw text */
	fprintf(f, "static void\n");
	fprintf(f, "draw_text(struct cpssp* cpssp, GtkWidget *widget,\n"
		"\t  int x, int y, const char* text)\n");
	fprintf(f, "{\n");

	fprintf(f, "\t/* check for init */\n");
	fprintf(f, "\tif (! cpssp->pixmap_init) {\n");
	fprintf(f, "\t\tif (! create_pixmap(cpssp)) {\n");
	fprintf(f, "\t\t\treturn;\n");
	fprintf(f, "\t\t}\n");
	fprintf(f, "\t}\n");


	fprintf(f, "\tGdkColor color = cpssp->gdk_black;\n");
	fprintf(f, "\tgtk_widget_modify_fg "
		"(widget, GTK_STATE_NORMAL, &color);\n");
	fprintf(f, "\tint tmp_x = x / cpssp->scale;\n");
	fprintf(f, "\tint tmp_y = y / cpssp->scale;\n");
	fprintf(f, "\tif (cpssp->scale > 3) {\n");
	fprintf(f, "\t\tgdk_draw_text(cpssp->pixmap,\n");
	fprintf(f, "\t\t\t      gdk_fontset_load(\"-*-fixed-medium-r-\"\n");
	fprintf(f, "\t\t\t\t\t       \"normal--9-87-*-*-*-*-iso10646-1\"),\n");
	fprintf(f, "\t\t\t      widget->style->fg_gc"
		"[gtk_widget_get_state (widget)],\n");
	fprintf(f, "\t\t\t      tmp_x,\n");
	fprintf(f, "\t\t\t      tmp_y,\n");
	fprintf(f, "\t\t\t      text,\n");
	fprintf(f, "\t\t\t      strlen(text));\n");
	fprintf(f, "\t} else {\n");
	fprintf(f, "\t\tgdk_draw_text(cpssp->pixmap,\n");
	fprintf(f, "\t\t\t      gdk_fontset_load(\"-*-fixed-medium-r-s*-\"\n");
	fprintf(f, "\t\t\t\t\t       \"-12-87-*-*-*-*-iso10646-1\"),\n");
	fprintf(f, "\t\t\t      widget->style->fg_gc"
		"[gtk_widget_get_state (widget)],\n");
	fprintf(f, "\t\t\t      tmp_x,\n");
	fprintf(f, "\t\t\t      tmp_y,\n");
	fprintf(f, "\t\t\t      text,\n");
	fprintf(f, "\t\t\t      strlen(text));\n");
	fprintf(f, "\t}\n");
	fprintf(f, "}\n");
	fprintf(f, "\n");

	/* draw box */
	fprintf(f, "static void\n");
	fprintf(f, "draw_box(struct cpssp *cpssp, GtkWidget *widget,\n"
		"\t int x1, int y1, int x2, int y2)\n");
	fprintf(f, "{\n");

	fprintf(f, "\t/* check for init */\n");
	fprintf(f, "\tif (! cpssp->pixmap_init) {\n");
	fprintf(f, "\t\tif (! create_pixmap(cpssp)) {\n");
	fprintf(f, "\t\t\treturn;\n");
	fprintf(f, "\t\t}\n");
	fprintf(f, "\t}\n");

	fprintf(f, "\tGdkColor color = cpssp->gdk_black;\n");
	fprintf(f, "\tgtk_widget_modify_fg"
		"(widget, GTK_STATE_NORMAL, &color);\n");

	fprintf(f, "\tint tmp_x1 = x1 / cpssp->scale;\n");
	fprintf(f, "\tint tmp_y1 = y1 / cpssp->scale;\n");
	fprintf(f, "\tint tmp_x2 = x2 / cpssp->scale;\n");
	fprintf(f, "\tint tmp_y2 = y2 / cpssp->scale;\n");
	fprintf(f, "\n");

	fprintf(f, "\tgdk_draw_rectangle(cpssp->pixmap,\n");
	fprintf(f, "\t\t\t   widget->style->fg_gc"
		"[gtk_widget_get_state (widget)],\n");
	fprintf(f, "\t\t\t   FALSE,\n");
	fprintf(f, "\t\t\t   tmp_x1,\n");
	fprintf(f, "\t\t\t   tmp_y1,\n");
	fprintf(f, "\t\t\t   tmp_x2 - tmp_x1,\n");
	fprintf(f, "\t\t\t   tmp_y2 - tmp_y1);\n");
	fprintf(f, "}\n");
	fprintf(f, "\n");

	/* draw circle */
	fprintf(f, "static void\n");
	fprintf(f, "draw_circle(struct cpssp *cpssp, GtkWidget *widget,\n"
		"\t    int x, int y, int r, gboolean filled)\n");
	fprintf(f, "{\n");

	fprintf(f, "\t/* check for init */\n");
	fprintf(f, "\tif (! cpssp->pixmap_init) {\n");
	fprintf(f, "\t\tif (! create_pixmap(cpssp)) {\n");
	fprintf(f, "\t\t\treturn;\n");
	fprintf(f, "\t\t}\n");
	fprintf(f, "\t}\n");

	fprintf(f, "\tGdkColor color = cpssp->gdk_black;\n");
	fprintf(f, "\tgtk_widget_modify_fg"
		"(widget, GTK_STATE_NORMAL, &color);\n");

	fprintf(f, "\tint tmp_x = x / cpssp->scale;\n");
	fprintf(f, "\tint tmp_y = y / cpssp->scale;\n");
	fprintf(f, "\tint tmp_r;\n");
	fprintf(f, "\tif (r < 10) {\n");
	fprintf(f, "\t\ttmp_r = r;\n");
	fprintf(f, "\t} else {\n");
	fprintf(f, "\t\ttmp_r = r / cpssp->scale;\n");
	fprintf(f, "\t}\n");
	fprintf(f, "\n");

	fprintf(f, "\tgdk_draw_arc(cpssp->pixmap,\n");
	fprintf(f, "\t\t     widget->style->fg_gc"
		"[gtk_widget_get_state (widget)],\n");
	fprintf(f, "\t\t     filled,\n");
	fprintf(f, "\t\t     tmp_x - tmp_r,\n");
	fprintf(f, "\t\t     tmp_y - tmp_r,\n");
	fprintf(f, "\t\t     2 * tmp_r,\n");
	fprintf(f, "\t\t     2 * tmp_r,\n");
	fprintf(f, "\t\t     0,\n");
	fprintf(f, "\t\t     64 * 360);\n");
	fprintf(f, "}\n");
	fprintf(f, "\n");

	/* draw all method for init */

	fprintf(f, "static void\n");
	fprintf(f, "COMP_(draw_all)(struct cpssp *cpssp)\n");
	fprintf(f, "{\n");

	fprintf(f, "\t/* clear screen */\n");
	fprintf(f, "\tgdk_draw_rectangle(cpssp->pixmap,\n");
	fprintf(f, "\t\t\t   cpssp->darea->style->white_gc,\n");
	fprintf(f, "\t\t\t   TRUE,\n");
	fprintf(f, "\t\t\t   0, 0,\n");
	fprintf(f, "\t\t\t   cpssp->x_size,\n");
	fprintf(f, "\t\t\t   cpssp->y_size);\n");


	/* draw comps */
	fprintf(f, "\t/* draw comps */\n");
	for (comp = schem->comp_first; comp; comp = comp->next) {
		for (ge = comp->ge_first; ge; ge = ge->next) {
			switch(ge->type) {
			case GE_LINE:
				fprintf(f, "\tdraw_line(cpssp, "
					"cpssp->darea,\n");
				fprintf(f, "\t\t  %f, %f, %f, %f, 1);\n",
					ge->line.x0, ge->line.y0,
					ge->line.x1, ge->line.y1);
				break;
			case GE_BOX:
				fprintf(f, "\tdraw_box(cpssp, cpssp->darea,\n");
				fprintf(f, "\t\t %f, %f, %f, %f);\n",
					ge->box.x0, ge->box.y0,
					ge->box.x1, ge->box.y1);
				break;
			case GE_TEXT:
				fprintf(f, "\tdraw_text(cpssp, "
					"cpssp->darea,\n");
				fprintf(f, "\t\t  %f, %f, \"%s\");\n",
					ge->text.x, ge->text.y, ge->text.str);
				break;
			case GE_CIRCLE:
				fprintf(f, "\tdraw_circle(cpssp, "
					"cpssp->darea,\n");
				fprintf(f, "\t\t    %f, %f, %f, FALSE);\n",
					ge->circle.x, ge->circle.y,
					ge->circle.r);
				break;

			}
		}
		for (port = comp->port_first; port; port = port->next) {
			for (ge = port->ge_first; ge; ge = ge->next) {
				switch(ge->type) {



				case GE_LINE:
					fprintf(f, "\tdraw_line(cpssp, "
						"cpssp->darea,\n");
					fprintf(f, "\t\t  %f, %f, %f, %f, "
						"1);\n",
						ge->line.x0, ge->line.y0,
						ge->line.x1, ge->line.y1);
					break;
				case GE_BOX:
					fprintf(f, "\tdraw_box(cpssp, "
						"cpssp->darea,\n");
					fprintf(f, "\t\t %f, %f, %f, %f);\n",
						ge->box.x0, ge->box.y0,
						ge->box.x1, ge->box.y1);
					break;
				case GE_TEXT:
					fprintf(f, "\tdraw_text(cpssp, "
						"cpssp->darea,\n");
					fprintf(f, "\t\t  %f, %f, \"%s\");\n",
						ge->text.x, ge->text.y,
						ge->text.str);
					break;
				case GE_CIRCLE:
					fprintf(f, "\tdraw_circle(cpssp, "
						"cpssp->darea,\n");
					fprintf(f, "\t\t    %f, %f, %f, "
						"FALSE);\n",
						ge->circle.x, ge->circle.y,
						ge->circle.r);
					break;



				}
			}
		}
	}

	/* draw ports */
	fprintf(f, "\t/* draw ports */\n");
	for (port = schem->port_first; port; port = port->next) {
		for (ge = port->ge_first; ge; ge = ge->next) {
			switch(ge->type) {
			case GE_LINE:
				fprintf(f, "\tdraw_line(cpssp, cpssp->darea,\n"
					"\t\t  %f, %f, %f, %f,\n"
					"\t\t  cpssp->port_%s);\n",
					ge->line.x0, ge->line.y0, ge->line.x1,
					ge->line.y1, mangle(port->name));
				break;
			case GE_BOX:
				fprintf(f, "\tdraw_box(cpssp, cpssp->darea,\n"
					"\t\t %f, %f, %f, %f);\n",
					ge->box.x0, ge->box.y0,
					ge->box.x1, ge->box.y1);
				break;
			case GE_TEXT:
				fprintf(f, "\tdraw_text(cpssp, cpssp->darea,\n"
					"\t\t  %f, %f, \"%s\");\n",
					ge->text.x, ge->text.y, ge->text.str);
				break;
			case GE_CIRCLE:
				fprintf(f, "\tdraw_circle(cpssp, "
					"cpssp->darea,\n");
				fprintf(f, "\t\t   %f, %f, %f, FALSE);\n",
					ge->circle.x, ge->circle.y,
					ge->circle.r);
				break;

			}
		}
	}

	/* draw signals */
	fprintf(f, "\t/* draw signals */\n");
	for (sig = schem->sig_first; sig; sig = sig->next) {
		for (ge = sig->ge_first; ge; ge = ge->next) {
			switch(ge->type) {
			case GE_LINE:
				fprintf(f, "\tdraw_line(cpssp, "
					"cpssp->darea,\n");
				fprintf(f, "\t\t  %f, %f, %f, %f,\n"
					"\t\t  cpssp->port_%s);\n",
					ge->line.x0, ge->line.y0,
					ge->line.x1, ge->line.y1, sig->id);
				break;
			case GE_BOX:
				fprintf(f, "\tdraw_box(cpssp, cpssp->darea,\n"
					"\t\t %f, %f, %f, %f);\n",
					ge->box.x0, ge->box.y0,
					ge->box.x1, ge->box.y1);
				break;
			case GE_TEXT:
				fprintf(f, "\tdraw_text(cpssp, cpssp->darea,\n"
					"\t\t  %f, %f, \"%s\");\n",
					ge->text.x, ge->text.y, ge->text.str);
				break;
			case GE_CIRCLE:
				fprintf(f, "\tdraw_circle(cpssp, "
					"cpssp->darea,\n"
					"\t\t   %f, %f, %f, FALSE);\n",
					ge->circle.x, ge->circle.y,
					ge->circle.r);
				break;

			}
		}
	}

	/* find all connected signals */
	hashmap *map = hashmapCreate(0);
	unsigned long key = 0;
	char first = 'f';
	char second = 's';
	char printed = 'p';

	fprintf(f, "\t/* draw connectors between signals */\n");
	for (sig = schem->sig_first; sig; sig = sig->next) {
		for (ge = sig->ge_first; ge; ge = ge->next) {
			if (ge->type == GE_LINE) {
				/* to get a uniq key for x0 and y0
				 * i cast them to unsigned long
				 * with an accuracy of three digits
				 * after the decimal point*/
				unsigned long a = (unsigned long)
					(ge->line.x0 * 1000 + 0.5);
				unsigned long b = (unsigned long)
					(ge->line.y0 * 1000 + 0.5);
				key = a << 16 | b;
				if (! hashmapGet(map, key)) {
					/* first signal to end here, add*/
					hashmapInsert(map, first, key);
				}else if (first == hashmapGet(map, key)) {
					/* second signal to end here */
					if ((ge->line.x0 == ge->line.x1)
					    && (ge->line.y0 == ge->line.y1)) {
						/* self reference... */
						continue;
					}
					hashmapRemove(map, key);
					hashmapInsert(map, second, key);
				} else if (second == hashmapGet(map, key)) {
					/* 3d signal to end here -> draw */
					hashmapRemove(map, key);
					hashmapInsert(map, printed, key);
					fprintf(f, "\tdraw_circle(cpssp, "
						"cpssp->darea, %f, %f, 3, "
						"TRUE);\n",
						ge->line.x0, ge->line.y0);
				}
				/* else at least 3d, x.y set to printed
				 * -> nothing else to do */

				a = (unsigned long) (ge->line.x1 * 1000 + 0.5);
				b = (unsigned long) (ge->line.y1 * 1000 + 0.5);
				key = a << 16 | b;
				if (! hashmapGet(map, key)) {
					/* first signal to end here, add*/
					hashmapInsert(map, first, key);
				}else if (first == hashmapGet(map, key)) {
					/* second signal to end here */
					if ((ge->line.x0 == ge->line.x1)
					    && (ge->line.y0 == ge->line.y1)) {
						/* self reference... */
						continue;
					}
					hashmapRemove(map, key);
					hashmapInsert(map, second, key);
				} else if (second == hashmapGet(map, key)) {
					/* 3d signal to end here -> draw */
					hashmapRemove(map, key);
					hashmapInsert(map, printed, key);
					fprintf(f, "\tdraw_circle(cpssp, "
						"cpssp->darea, %f, %f, 3, "
						"TRUE);\n",
						ge->line.x1, ge->line.y1);
				}
				/* else at least 3d, x.y set to printed */
			}
		}
	}

	fprintf(f, "\n");
	fprintf(f, "}\n");

	fprintf(f, "\n");

	/* identify values for debug/gtkwave */
	fprintf(f, "#if DEBUG || TRACE\n");
	fprintf(f, "static char\n");
	fprintf(f, "COMP_(get_value)(int val)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tchar c;\n");
	fprintf(f, "\n");
	fprintf(f, "\tswitch (val) {\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_U: c = 'U'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_X: c = 'X'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_0: c = '0'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_1: c = '1'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_Z: c = 'Z'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_W: c = 'W'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_L: c = 'L'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_H: c = 'H'; break;\n");
	fprintf(f, "\tdefault: c = 'X'; break;\n");
	fprintf(f, "\t}\n");
	fprintf(f, "\treturn c;\n");
	fprintf(f, "}\n");
	fprintf(f, "#endif /* DEBUG || TRACE */\n");

	fprintf(f, "\n");

	/* each port and signal gets his personal drawing method */
	fprintf(f, "/* draw ports */\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "static void\n");
		fprintf(f, "COMP_(draw_%s)"
			"(struct cpssp *cpssp, unsigned int val)\n",
			mangle(port->name));
		fprintf(f, "{\n");
		for (ge = port->ge_first; ge; ge = ge->next) {
			switch(ge->type) {
			case GE_LINE:
				fprintf(f, "\tdraw_line(cpssp, cpssp->darea,\n"
					"\t\t  %f, %f, %f, %f, val);\n",
					ge->line.x0, ge->line.y0,
					ge->line.x1, ge->line.y1);
				break;
			case GE_BOX:
				break;
			case GE_TEXT:
				break;
			case GE_CIRCLE:
				break;

			}
		}
		fprintf(f, "}\n");
		fprintf(f, "\n");
	}

	fprintf(f, "/* draw gui ports */\n");
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "static void\n");
		fprintf(f, "COMP_(draw_%s)"
			"(struct cpssp *cpssp, unsigned int val)\n", sig->id);
		fprintf(f, "{\n");
		for (ge = sig->ge_first; ge; ge = ge->next) {
			switch(ge->type) {
			case GE_LINE:
				fprintf(f, "\tdraw_line(cpssp, cpssp->darea,\n"
					"\t\t  %f, %f, %f, %f, val);\n",
					ge->line.x0, ge->line.y0,
					ge->line.x1, ge->line.y1);
				break;
			case GE_BOX:
				break;
			case GE_TEXT:
				break;
			case GE_CIRCLE:
				break;
			}
		}
		fprintf(f, "}\n");
		fprintf(f, "\n");
	}

	fprintf(f, "static void\n");
	fprintf(f, "COMP_(refresh_monitor)(void *_cpssp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\tif (! cpssp->pixmap_init) {\n");
	fprintf(f, "\t\tif (! create_pixmap(cpssp)) {\n");
	fprintf(f, "\t\t\ttime_real_event_add(time_real() + TIME_HZ / 4,\n"
		"\t\t\t\t\t    COMP_(refresh_monitor), cpssp);\n");
	fprintf(f, "\t\t\treturn;\n");
	fprintf(f, "\t\t}\n");
	fprintf(f, "\t}\n");

	fprintf(f, "\tif ((6 - cpssp->scale) "
		"!= GUI_GTK_MONITOR(cpssp->gui)->zoom_step) {\n");
	fprintf(f, "\t\tcpssp->scale = "
		"6 - GUI_GTK_MONITOR(cpssp->gui)->zoom_step;\n");
	fprintf(f, "\t\tCOMP_(draw_all)(cpssp);\n");
	fprintf(f, "\t\tgtk_widget_set_size_request (cpssp->darea,\n"
		"\t\t\t\t\t     cpssp->x_size / cpssp->scale,\n"
		"\t\t\t\t\t     cpssp->y_size / cpssp->scale);\n");
	fprintf(f, "\t}\n");

	/* redraw comps if something changed */
	fprintf(f, "\t/* redraw ports if something changed */\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tif (cpssp->oldport_%s != cpssp->port_%s) {\n",
			mangle(port->name), mangle(port->name));
		fprintf(f, "\t\tCOMP_(draw_%s)(cpssp, cpssp->port_%s);\n",
			mangle(port->name), mangle(port->name));
		fprintf(f, "\t\tcpssp->oldport_%s = cpssp->port_%s;\n",
			mangle(port->name), mangle(port->name));
		fprintf(f, "\t}\n");
	}
	fprintf(f, "\t/* redraw gui ports if something changed */\n");
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tif (cpssp->oldport_%s != cpssp->port_%s) {\n",
			sig->id, sig->id);
		fprintf(f, "\t\tCOMP_(draw_%s)(cpssp, cpssp->port_%s);\n",
			sig->id, sig->id);
		fprintf(f, "\t\tcpssp->oldport_%s = cpssp->port_%s;\n",
			sig->id, sig->id);
		fprintf(f, "\t}\n");
	}

	/* redraw */
	fprintf(f, "\t/* redraw the full size */\n");
	fprintf(f, "\tgdk_draw_drawable(cpssp->darea->window,\n");
	fprintf(f, "\t\t\t  cpssp->darea->style->fg_gc\n"
		"\t\t\t  [gtk_widget_get_state (cpssp->darea)],\n");
	fprintf(f, "\t\t\t  cpssp->pixmap,\n");
	fprintf(f, "\t\t\t  0, 0,\n");
	fprintf(f, "\t\t\t  0, 0,\n");
	fprintf(f, "\t\t\t  -1, -1);\n");
	fprintf(f, "\tgui_gtk_flush();\n");

	fprintf(f, "\ttest(GUI_GTK_MONITOR(cpssp->gui), cpssp->pixmap);\n");

	fprintf(f, "\ttime_real_event_add(time_real() + TIME_HZ / 4,\n"
		"\t\t\t    COMP_(refresh_monitor), cpssp);\n");
	fprintf(f, "}\n");

	fprintf(f, "\n");

	/* draw mponitor when its created */
	fprintf(f, "gboolean\n");
	fprintf(f, "COMP_(expose_event_callback) (GtkWidget *widget, "
		"GdkEventExpose *event,\n\t\t\t      gpointer _cpssp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tstruct cpssp *cpssp =_cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\t/* redraw the full size */\n");
	fprintf(f, "\tgdk_draw_drawable(widget->window,\n");
	fprintf(f, "\t\t\t  widget->style->fg_gc"
		"[gtk_widget_get_state (widget)],\n");
	fprintf(f, "\t\t\t  cpssp->pixmap,\n");
	fprintf(f, "\t\t\t  event->area.x, event->area.y,\n");
	fprintf(f, "\t\t\t  event->area.x, event->area.y,\n");
	fprintf(f, "\t\t\t  event->area.width, event->area.height);\n");
	fprintf(f, "\n");
	fprintf(f, "\tgui_gtk_flush();\n");
	fprintf(f, "\treturn TRUE;\n");
	fprintf(f, "}\n");

	fprintf(f, "\n");

	/* ports */
	fprintf(f, "/* ports */\n");

	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "static void\n");
		fprintf(f, "COMP_(port_%s_set)"
			"(void *_cpssp, unsigned int val)\n",
			mangle(port->name));
		fprintf(f, "{\n");
		fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
		fprintf(f, "\n");
		fprintf(f, "\tcpssp->port_%s = val;\n", mangle(port->name));
		fprintf(f, "#if TRACE\n");
		fprintf(f, "\tfprintf(cpssp->f, \"#%%lu\\n%%c%s_%s\\n\",\n"
			"\t\ttime_virt(), COMP_(get_value)(val));\n",
			inname, mangle(port->name));
		fprintf(f, "#endif /* TRACE */\n");
		fprintf(f, "#if DEBUG\n");
		fprintf(f, "\tfprintf(stderr, \"%s: "
			"gui port %s sets to %%c\\n\",\n"
			"\t\tCOMP_(get_value)(val));\n",
			inname , mangle(port->name));
		fprintf(f, "\tprintlogic(val);\n");
		fprintf(f, "#endif /* DEBUG */\n");
		fprintf(f, "}\n");

		fprintf(f, "\n");
	}

	/* gui ports */
	fprintf(f, "/* gui ports */\n");

	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "static void\n");
		fprintf(f, "COMP_(gui_port_%s_set)"
			"(void *_cpssp, unsigned int val)\n", sig->id);
		fprintf(f, "{\n");
		fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
		fprintf(f, "\n");
		/* trying to find the name of the signal */
		char sig_name[2048];
		int flag = 0;

		if (sig->name_first) {
			strcpy(sig_name, mangle_vcd(sig->name_first->name));
			flag = 1;
		} else {
			for (comp = schem->comp_first; comp && ! flag;
			     comp = comp->next) {
				for (port = comp->port_first;
				     port && ! flag; port = port->next) {
					if (strcmp(port->signal, sig->id)
					    == 0) {
						snprintf(sig_name, 2048,
							 "%s_%s", comp->name,
							 mangle_vcd
							 (port->name));
						flag = 1;
					}
				}
			}
		}
		if (! flag) {
			strcpy(sig_name, sig->id);
			flag = 1;
		}

		fprintf(f, "\tcpssp->port_%s = val;\n", sig->id);
		fprintf(f, "#if TRACE\n");
		fprintf(f, "\tfprintf(cpssp->f, \"#%%lu\\n%%c%s_%s\\n\",\n"
			"\t\ttime_virt(), COMP_(get_value)(val));\n",
			inname, sig_name);
		fprintf(f, "#endif /* TRACE */\n");
		fprintf(f, "#if DEBUG\n");
		fprintf(f, "\tfprintf(stderr, \"%s: gui signal %s "
			"sets to \");\n",
			inname, sig->id);
		fprintf(f, "\tprintlogic(val);\n");
		fprintf(f, "#endif /* DEBUG */\n");
		fprintf(f, "}\n");

		fprintf(f, "\n");
	}

	/* create */
	fprintf(f, "/* create */\n");

	fprintf(f, "void *\n");
	fprintf(f, "COMP_(gui_gtk_create)(\n");
	fprintf(f, "\t\t      unsigned int page,\n");
	fprintf(f, "\t\t      const char *name,\n");
	fprintf(f, "\t\t      struct sig_manage *port_manage,\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\t\t      struct sig_std_logic *port_%s,\n",
			mangle(port->name));
	}

	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\t\t      struct sig_std_logic *gui_port_%s",
			sig->id);
		if (sig->next) {
			fprintf(f, ",");
		}
		fprintf(f, "\n");
	}
	fprintf(f, "\t\t      )\n");
	fprintf(f, "{\n");

	fprintf(f, "\tstruct cpssp *cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\tcpssp = shm_alloc(sizeof(*cpssp));\n");
	fprintf(f, "\tassert(cpssp);\n");
	fprintf(f, "\n");

	fprintf(f, "#if TRACE\n");
	fprintf(f, "\tcpssp->f = fopen(\"debug_%s.out\", \"w\");\n", inname);
	for (sig = schem->sig_first; sig; sig = sig->next) {

		/* trying to find the name of the signal */
		char sig_name[2048];
		int flag = 0;

		if (sig->name_first) {
			strcpy(sig_name, mangle_vcd(sig->name_first->name));
			flag = 1;
		} else {
			for (comp = schem->comp_first;
			     comp && ! flag; comp = comp->next) {
				for (port = comp->port_first;
				     port && ! flag; port = port->next) {
					if (! strcmp(port->signal, sig->id)) {
						snprintf(sig_name, 2048,
							 "%s_%s", comp->name,
							 mangle_vcd(port->name));
						flag = 1;
					}
				}
			}
		}
		if (! flag) {
			strcpy(sig_name, sig->id);
			flag = 1;
		}
		fprintf(f, "\tfprintf(cpssp->f, "
			"\"$var wire 1 %s_%s \"\n\t\t\"%s_%s $end\\n\");\n",
			inname, sig_name, inname, sig_name);
	}
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tfprintf(cpssp->f, "
			"\"$var wire 1 %s_%s \"\n\t\t\"%s_%s $end\\n\");\n",
			inname, mangle(port->name),
			inname, mangle(port->name));
	}
	fprintf(f, "\tfprintf(cpssp->f, \"$enddefinitions $end\\n\");\n");
	fprintf(f, "\tfprintf(cpssp->f, \"$dumpvars\\n\");\n");
	fprintf(f, "#else /* ! TRACE */\n");
	fprintf(f, "\tcpssp->f = NULL;\n");
	fprintf(f, "#endif /* ! TRACE */\n");

	fprintf(f, "\n");

	fprintf(f, "\t/* parse colors */\n");
	fprintf(f, "\tgdk_color_parse (\"red\", &cpssp->gdk_red);\n");
	fprintf(f, "\tgdk_color_parse (\"green\", &cpssp->gdk_green);\n");
	fprintf(f, "\tgdk_color_parse (\"blue\", &cpssp->gdk_blue);\n");
	fprintf(f, "\tgdk_color_parse (\"black\", &cpssp->gdk_black);\n");
	fprintf(f, "\n");
	fprintf(f, "\t/* main window */\n");
	fprintf(f, "\tcpssp->gui = "
		"gui_gtk_monitor_new(\"VGA\", 1600, 1200);\n");
	fprintf(f, "\tgtk_widget_show(cpssp->gui);\n");
	fprintf(f, "\n");
	fprintf(f, "\t/* sync it once, initially */\n");
	fprintf(f, "\tgui_gtk_monitor_sync(GUI_GTK_MONITOR(cpssp->gui));\n");
	fprintf(f, "\n");
	fprintf(f, "\tgui_gtk_comp_add(page, name, name, cpssp->gui, "
		"TRUE, TRUE, NULL);\n");
	fprintf(f, "\n");
	fprintf(f, "\tgui_gtk_monitor_grab_focus"
		"(GUI_GTK_MONITOR(cpssp->gui));\n");
	fprintf(f, "\n");
	fprintf(f, "\t/* drawing area */\n");
	fprintf(f, "\tcpssp->darea = "
		"(GUI_GTK_MONITOR(cpssp->gui))->screen;\n");
	fprintf(f, "\tGTK_WIDGET_SET_FLAGS(cpssp->darea, GTK_CAN_FOCUS);\n");
	fprintf(f, "\tcpssp->scale = 4;\n");
	fprintf(f, "\tcpssp->x_size = %i;\n", (int) pair.x);
	fprintf(f, "\tcpssp->y_size = %i;\n", (int) pair.y);
	fprintf(f, "\tgtk_widget_set_size_request (cpssp->darea,\n"
		"\t\t\t\t     cpssp->x_size / cpssp->scale,\n"
		"\t\t\t\t     cpssp->y_size / cpssp->scale);\n");
	fprintf(f, "\tg_signal_connect(cpssp->darea, \"expose-event\",\n");
	fprintf(f, "\t\t\t G_CALLBACK(COMP_(expose_event_callback)), "
		"cpssp);\n");
	fprintf(f, "\n");
	fprintf(f, "\tgui_gtk_monitor_sync(GUI_GTK_MONITOR(cpssp->gui));\n");
	fprintf(f, "\t/* underlying pixmap */\n");
	fprintf(f, "\tcreate_pixmap(cpssp);\n");

	/* port std_logic funcs */
	fprintf(f, "\t/* port std_logic funcs */\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tstatic const struct sig_std_logic_funcs "
			"port_func_%s = {\n", mangle(port->name));
		fprintf(f, "\t\t.set_ext = COMP_(port_%s_set),\n",
			mangle(port->name));
		fprintf(f, "\t};\n");
	}
	fprintf(f, "\n");

	/* gui port std_logic funcs */
	fprintf(f, "\t/* gui port std_logic funcs */\n");
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tstatic const struct sig_std_logic_funcs "
			"gui_port_func_%s = {\n", sig->id);
		fprintf(f, "\t\t.set_ext = "
			"COMP_(gui_port_%s_set),\n", sig->id);
		fprintf(f, "\t};\n");
	}
	fprintf(f, "\n");

	/* connect ports as in */
	fprintf(f, "\t/* connect ports as in */\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tsig_std_logic_connect_in(port_%s,\n"
			"\t\t\t\t cpssp, &port_func_%s);\n",
			mangle(port->name), mangle(port->name));
	}
	fprintf(f, "\n");

	/* connect gui_ports as in */
	fprintf(f, "\t/* connect gui ports as in */\n");
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tsig_std_logic_connect_in(gui_port_%s, cpssp, "
			"&gui_port_func_%s);\n", sig->id, sig->id);
	}
	fprintf(f, "\n");

	fprintf(f, "\tCOMP_(refresh_monitor)((void *) cpssp);\n");
	fprintf(f, "\n");
	fprintf(f, "\treturn cpssp;\n");
	fprintf(f, "}\n");

	fprintf(f, "void\n");
	fprintf(f, "COMP_(gui_gtk_destroy)(void *_cpssp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\tshm_free(cpssp);\n");
	fprintf(f, "}\n");
	fprintf(f, "\n");
	fprintf(f, "void\n");
	fprintf(f, "COMP_(gui_gtk_suspend)(void *_cpssp, FILE *fp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\tgeneric_suspend(cpssp, sizeof(*cpssp), fp);\n");
	fprintf(f, "}\n");
	fprintf(f, "\n");
	fprintf(f, "void\n");
	fprintf(f, "COMP_(gui_gtk_resume)(void *_cpssp, FILE *fp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\tgeneric_resume(cpssp, sizeof(*cpssp), fp);\n");
	fprintf(f, "}\n");

}

static void
create_gui_c(const char* inname, struct xml_schem *schem)
{

	FILE *f;
	char filename[MAX_NAME];
	strncpy(filename, inname, MAX_NAME-strlen("_gui.c"));
	strcat(filename, "_gui.c");

	f = fopen(filename, "w");
	if (f == NULL) {
		fprintf(stderr, "Can't open output file %s!\n",
			filename);
		exit(EXIT_FAILURE);
	}

	if (strrchr(inname, '/')) {
		inname = strrchr(inname, '/') + 1;
	}
	struct xml_schem_port *port;
	struct xml_schem_signal *sig;

	fprintf(f, "/*\n");
	fprintf(f, " * Copyright (C) 2014 FAUmachine Team "
		"<info@faumachine.org>.\n");
	fprintf(f, " * This program is free software. "
		"You can redistribute it and/or modify it\n");
	fprintf(f, " * under the terms of the GNU General Public License, "
		"either version 2 of\n");
	fprintf(f, " * the License, or (at your option) any later version. "
		"See COPYING.\n");
	fprintf(f, " */\n");
	fprintf(f, "\n");
	fprintf(f, "#include <assert.h>\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"config.h\"\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"glue-gui.h\"\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"%s_gui.h\"\n", inname);
	fprintf(f, "\n");
	fprintf(f, "#ifdef HAVE_GTK\n");
	fprintf(f, "#include \"%s_gui_gtk.h\"\n", inname);
	fprintf(f, "#endif\n");
	fprintf(f, "\n");
	fprintf(f, "#define COMP_(x)                %s_ ## x\n", inname);
	fprintf(f, "#define COMP                    %s\n", inname);
	fprintf(f, "\n");
	fprintf(f, "void *\n");
	fprintf(f, "COMP_(gui_create)(\n");
	fprintf(f, "\tunsigned int page,\n");
	fprintf(f, "\tconst char *name,\n");
	fprintf(f, "\tstruct sig_manage *port_manage,\n");

	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tstruct sig_std_logic *port_%s,\n",
			mangle(port->name));
	}

	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tstruct sig_std_logic *port_%s", sig->id);
		if (sig->next) {
			fprintf(f, ",");
		}
		fprintf(f, "\n");
	}
	fprintf(f, ")\n");

	fprintf(f, "{\n");
	fprintf(f, "\tswitch (selected_gui) {\n");
	fprintf(f, "#ifdef HAVE_GTK\n");
	fprintf(f, "\tcase GUI_GTK:\n");
	fprintf(f, "\t\treturn COMP_(gui_gtk_create)(page,\n");
	fprintf(f, "\t\t\t\tname,\n");
	fprintf(f, "\t\t\t\tport_manage,\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\t\t\t\tport_%s,\n", mangle(port->name));
	}

	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\t\t\t\tport_%s", sig->id);
		if (sig->next) {
			fprintf(f, ",");
		} else {
			fprintf(f, ");");
		}
		fprintf(f, "\n");
	}

	fprintf(f, "#endif\n");
	fprintf(f, "\tcase GUI_NULL:\n");
	fprintf(f, "\t\treturn (void *) 1;\n");
	fprintf(f, "\tdefault:\n");
	fprintf(f, "\t\tassert(0);\n");
	fprintf(f, "\t}\n");
	fprintf(f, "}\n");

	fprintf(f, "\n");

	fprintf(f, "void\n");
	fprintf(f, "COMP_(gui_destroy)(void *_cpssp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tswitch (selected_gui) {\n");
	fprintf(f, "#ifdef HAVE_GTK\n");
	fprintf(f, "\tcase GUI_GTK:\n");
	fprintf(f, "\t\tCOMP_(gui_gtk_destroy)(_cpssp);\n");
	fprintf(f, "\t\tbreak;\n");
	fprintf(f, "#endif\n");
	fprintf(f, "\tcase GUI_NULL:\n");
	fprintf(f, "\t\tbreak;\n");
	fprintf(f, "\tdefault:\n");
	fprintf(f, "\t\tassert(0);\n");
	fprintf(f, "\t}\n");
	fprintf(f, "}\n");

	fprintf(f, "\n");

	fprintf(f, "void\n");
	fprintf(f, "COMP_(gui_suspend)(void *_cpssp, FILE *fp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tswitch(selected_gui) {\n");
	fprintf(f, "#ifdef HAVE_GTK\n");
	fprintf(f, "\tcase GUI_GTK:\n");
	fprintf(f, "\t\tCOMP_(gui_gtk_suspend)(_cpssp, fp);\n");
	fprintf(f, "\t\tbreak;\n");
	fprintf(f, "#endif\n");
	fprintf(f, "\tcase GUI_NULL:\n");
	fprintf(f, "\t\tbreak;\n");
	fprintf(f, "\tdefault:\n");
	fprintf(f, "\t\tassert(0);\n");
	fprintf(f, "\t}\n");
	fprintf(f, "}\n");

	fprintf(f, "\n");

	fprintf(f, "void\n");
	fprintf(f, "COMP_(gui_resume)(void *_cpssp, FILE *fp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tswitch(selected_gui) {\n");
	fprintf(f, "#ifdef HAVE_GTK\n");
	fprintf(f, "\tcase GUI_GTK:\n");
	fprintf(f, "\t\tCOMP_(gui_gtk_resume)(_cpssp, fp);\n");
	fprintf(f, "\t\tbreak;\n");
	fprintf(f, "#endif\n");
	fprintf(f, "\tcase GUI_NULL:\n");
	fprintf(f, "\t\tbreak;\n");
	fprintf(f, "\tdefault:\n");
	fprintf(f, "\t\tassert(0);\n");
	fprintf(f, "\t}\n");
	fprintf(f, "}\n");

	fclose(f);
}

static void
create_src(const char *inname, struct xml_schem *schem)
{
	char filename[MAX_NAME];
	FILE *f;

	strncpy(filename, inname, MAX_NAME-4);
	strcat(filename, ".src");

	f = fopen(filename, "w");
	if (f == NULL) {
		fprintf(stderr, "Can't open output file %s!\n",
			filename);
		exit(EXIT_FAILURE);
	}

	struct xml_schem_port *port;
	struct xml_schem_signal *sig;

	/* copyright */
	fprintf(f, "#\n");
	fprintf(f, "# Copyright (C) 2015 FAUmachine Team "
		"<info@faumachine.org>.\n");
	fprintf(f, "# This program is free software. "
		"You can redistribute it and/or modify it\n");
	fprintf(f, "# under the terms of the GNU General Public License, "
		"either version 2 of\n");
	fprintf(f, "# the License, or (at your option) any later version. "
		"See COPYING.\n");
	fprintf(f, "#\n");

	fprintf(f, "\n");
	fprintf(f, "\n");
	fprintf(f, "[options]\n");
	fprintf(f, "wordswap=yes\n");
	fprintf(f, "rotate_labels=yes\n");
	fprintf(f, "sort_labels=no\n");
	fprintf(f, "generate_pinseq=no\n");
	fprintf(f, "sym_width=900\n");
	fprintf(f, "pinwidthvertical=300\n");
	fprintf(f, "pinwidthhorizontal=500\n");
	fprintf(f, "\n");
	fprintf(f, "[geda_attr]\n");
	char buff[26];
	time_t now = time (0);
	strftime (buff, 26, "%Y%m%d", localtime (&now));
	fprintf(f, "version=%s\n", buff);
	fprintf(f, "name=Zuse23 simulation\n");
	fprintf(f, "device=zusesym\n");
	fprintf(f, "refdes=U?\n");
	fprintf(f, "footprint=SO20\n");
	fprintf(f, "description=Zuse23 simulation\n");
	fprintf(f, "documentation=http://\n");
	fprintf(f, "author=Christian Schlumberger "
		"<spchsclu@stud.cs.fau.de>\n");
	fprintf(f, "numslots=0\n");
	fprintf(f, "\n");
	fprintf(f, "\n");
	fprintf(f, "[pins]\n");
	fprintf(f, "#-----------------------------------------------------\n");
	fprintf(f, "#pinnr  seq     type    style   posit.  net     label\n");
	fprintf(f, "#-----------------------------------------------------\n");

	int i = 1;
	char type[4];
	for (port = schem->port_first; port; port = port->next) {
		type[0] = '\0';
		if (strcmp(port->inout, "inout") == 0) {
			strcat(type, "io");
		} else {
			strncat(type, port->inout, 3);
		}
		fprintf(f, "%i\t%i\t%s\tline\tl\t\tport_%s\tstd_logic\n",
			i, i, type, mangle(port->name));
		i++;
	}
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "%i\t%i\tio\tline\tl\t\tport_%s\tstd_logic\n",
			i, i, sig->id);
		i++;
	}
	fclose(f);
}

static void
create_c(const char *inname, struct xml_schem *schem)
{
	FILE *f;

	char filename[MAX_NAME];
	strncpy(filename, inname, MAX_NAME-2);
	strcat(filename, ".c");

	f = fopen(filename, "w");
	if (f == NULL) {
		fprintf(stderr, "Can't open output file %s!\n",
			filename);
		exit(EXIT_FAILURE);
	}

	if (strrchr(inname, '/')) {
		inname = strrchr(inname, '/') + 1;
	}

	struct xml_schem_port *port, *port2, *pin;
	struct xml_schem_signal *sig;
	struct xml_schem_component *comp;

	/* copyright */
	fprintf(f, "/*\n");
	fprintf(f, " * Copyright (C) 2015 FAUmachine Team "
		"<info@faumachine.org>.\n");
	fprintf(f, " * This program is free software. "
		"You can redistribute it and/or modify it\n");
	fprintf(f, " * under the terms of the GNU General Public License, "
		"either version 2 of\n");
	fprintf(f, " * the License, or (at your option) any later version. "
		"See COPYING.\n");
	fprintf(f, " */\n");

	fprintf(f, "\n");

	fprintf(f, "#define DEBUG 0\n");

	fprintf(f, "\n");

	/* includes */
	fprintf(f, "#include <assert.h>\n");
	fprintf(f, "#include <stdio.h>\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"glue.h\"\n");
	fprintf(f, "\n");
	fprintf(f, "#include \"%s.h\"\n", inname);

	fprintf(f, "\n");

	/* defines */
	fprintf(f, "#define COMP_(x)\t\t%s_ ## x\n", inname);

	fprintf(f, "\n");

	/* cpssp */
	fprintf(f, "struct cpssp {\n");

	/* signals */
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tunsigned int state_%s;\n", sig->id);
	}

	fprintf(f, "\n");

	/* ports */
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tunsigned int state_%s_out;\n",
			mangle(port->name));
		fprintf(f, "\tunsigned int state_%s_in;\n",
			mangle(port->name));
	}

	fprintf(f, "\n");

	/* pins */
	for (comp = schem->comp_first; comp; comp = comp->next) {
		for (port = comp->port_first; port; port = port->next) {
			if (strcmp(port->inout, "out") == 0
			    || strcmp(port->inout, "inout") == 0) {
				fprintf(f, "\tunsigned int state_%s_%s_out;\n",
					comp->name, port->name);
			}
		}
	}

	fprintf(f, "\n");

	/* elements */
	for (comp = schem->comp_first; comp; comp = comp->next) {
		fprintf(f, "#define STATE\n");
		fprintf(f, "#define SNAME \"xml2c_%s\"\n", mangle(comp->name));
		fprintf(f, "#define NAME xml2c_%s\n", mangle(comp->name));
		fprintf(f, "#define NAME_(x) xml2c_%s_ ## x\n",
			mangle(comp->name));
		fprintf(f, "#include \"%s.c\"\n", comp->type);
		fprintf(f, "#undef SNAME\n");
		fprintf(f, "#undef NAME\n");
		fprintf(f, "#undef NAME_\n");
		fprintf(f, "#undef STATE\n");

		fprintf(f, "\n");
	}

	/* ports */
	fprintf(f, "\t/* ports */\n");

	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tstruct sig_std_logic *port_%s;\n",
			mangle(port->name));
	}

	/* gui ports */
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tstruct sig_std_logic *gui_port_%s;\n", sig->id);
	}

	fprintf(f, "};\n");

	fprintf(f, "\n");

	/* forward declarations */

	for (comp = schem->comp_first; comp; comp = comp->next) {
		for (port = comp->port_first; port; port = port->next) {
			if (strcmp(port->inout, "out") == 0
			    || strcmp(port->inout, "inout") == 0) {
				fprintf(f, "static void\nxml2c_%s_%s_out_set"
					"(struct cpssp *, unsigned int);\n",
					mangle(comp->name), port->name);
			}
		}
	}
	fprintf(f, "\n");

	/* element update funcs */
	fprintf(f, "/* element update funcs */\n");
	for (comp = schem->comp_first; comp; comp = comp->next) {
		fprintf(f, "#define BEHAVIOUR\n");
		fprintf(f, "#define SNAME \"xml2c_%s\"\n", mangle(comp->name));
		fprintf(f, "#define NAME xml2c_%s\n", mangle(comp->name));
		fprintf(f, "#define NAME_(x) xml2c_%s_ ## x\n",
			mangle(comp->name));
		fprintf(f, "#include \"%s.c\"\n", comp->type);
		fprintf(f, "#undef SNAME\n");
		fprintf(f, "#undef NAME\n");
		fprintf(f, "#undef NAME_\n");
		fprintf(f, "#undef BEHAVIOUR\n");

		fprintf(f, "\n");
	}

#if DEBUG
	fprintf(f, "#if DEBUG\n");
	fprintf(f, "static void\n");
	fprintf(f, "printlogic(unsigned int val)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tchar c;\n");
	fprintf(f, "\n");
	fprintf(f, "\tswitch (val) {\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_U: c = 'U'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_X: c = 'X'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_0: c = '0'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_1: c = '1'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_Z: c = 'Z'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_W: c = 'W'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_L: c = 'L'; break;\n");
	fprintf(f, "\tcase SIG_STD_LOGIC_H: c = 'H'; break;\n");
	fprintf(f, "\tdefault: c = '?'; break;\n");
	fprintf(f, "\t};\n");
	fprintf(f, "\n");
	fprintf(f, "\tfprintf(stderr, \"%%c\\n\", c);\n");
	fprintf(f, "}\n");
	fprintf(f, "#endif /* DEBUG */\n");
#endif /* DEBUG */

	fprintf(f, "\n");

	/* signal resolves */
	fprintf(f, "/* signal resolves */\n");

	for (sig = schem->sig_first; sig; sig = sig->next) {
		/* resolve function is only necessary if there are
		 * ports or comps attached to it */
		int external = 0;
		int internal = 0;
		for (port = schem->port_first;
		     ! external && port; port = port->next) {
			if (strcmp(port->signal, sig->id) == 0) {
				external = 1;
			}
		}
		for (comp = schem->comp_first;
		     ! internal && comp; comp = comp->next) {
			for (port = comp->port_first;
			     port; port = port->next) {
				if (strcmp(port->signal, sig->id) == 0 &&
				    strcmp(port->inout, "in") != 0 &&
				    strcmp(port->inout, "unknown-pin") != 0) {
					internal = 1;
				}
			}
		}
		if (! external && ! internal) {
			continue;
		}

		fprintf(f, "static void\n");
		fprintf(f, "COMP_(resolve_sig_%s)(struct cpssp *cpssp)\n",
			sig->id);
		fprintf(f, "{\n");
		fprintf(f, "\tunsigned int res;\n");
		fprintf(f, "\n");

		for (port = schem->port_first; port; port = port->next) {
			if (strcmp(port->signal, sig->id) != 0) {
				continue;
			}

			fprintf(f, "\tres = SIG_STD_LOGIC_Z;\n");
			for (port2 = schem->port_first;
			     port2; port2 = port2->next) {
				if (strcmp(port2->signal, sig->id) != 0
				    || port == port2) {
					continue;
				}

				fprintf(f, "\tres = sig_std_logic_resolve"
					"(res, cpssp->state_%s_out);\n",
					mangle(port2->name));
			}
			for (comp = schem->comp_first;
			     comp; comp = comp->next) {
				for (pin = comp->port_first;
				     pin; pin = pin->next) {
					if (strcmp(pin->signal, sig->id) != 0
					    || strcmp(pin->inout, "in") == 0
					    || strcmp(pin->inout,
						      "unknown-pin") == 0) {
						continue;
					}

					fprintf(f, "\tres = "
						"sig_std_logic_resolve(res, "
						"cpssp->state_%s_%s_out);\n",
						comp->name, pin->name);
				}
			}

			fprintf(f, "\tif (res != cpssp->state_%s_in) {\n",
				mangle(port->name));
			fprintf(f, "\t\tcpssp->state_%s_in = res;\n",
				mangle(port->name));
			fprintf(f, "\t\tsig_std_logic_set(cpssp->port_%s, "
				"cpssp, res);\n", mangle(port->name));
			fprintf(f, "\t}\n");
		}

		fprintf(f, "\tres = SIG_STD_LOGIC_Z;\n");
		for (port2 = schem->port_first; port2; port2 = port2->next) {
			if (strcmp(port2->signal, sig->id) != 0) {
				continue;
			}

			fprintf(f, "\tres = sig_std_logic_resolve(res, "
				"cpssp->state_%s_out);\n", mangle(port2->name));
		}
		for (comp = schem->comp_first; comp; comp = comp->next) {
			for (pin = comp->port_first; pin; pin = pin->next) {
				if (strcmp(pin->signal, sig->id) != 0) {
					continue;
				}

				if (strcmp(pin->inout, "out") == 0
				    || strcmp(pin->inout, "inout") == 0) {
					fprintf(f, "\tres = "
						"sig_std_logic_resolve(res, "
						"cpssp->state_%s_%s_out);\n",
						comp->name, pin->name);
				}
			}
		}

		fprintf(f, "\tif (res != cpssp->state_%s) {\n", sig->id);
		fprintf(f, "\t\tcpssp->state_%s = res;\n", sig->id);
		for (comp = schem->comp_first; comp; comp = comp->next) {
			for (pin = comp->port_first; pin; pin = pin->next) {
				if (strcmp(pin->signal, sig->id) != 0) {
					continue;
				}
				if (strcmp(pin->inout, "in") == 0
				    || strcmp(pin->inout, "inout") == 0) {
					fprintf(f, "\t\txml2c_%s_%s_in_set"
						"(cpssp, res);\n",
						mangle(comp->name), pin->name);
				}
			}
		}
		fprintf(f, "\t\tsig_std_logic_set(cpssp->gui_port_%s, "
			"cpssp, res);\n", sig->id);
		fprintf(f, "\t}\n");

		fprintf(f, "}\n");

		fprintf(f, "\n");
	}

	/* pins */
	fprintf(f, "/* pins */\n");
	for (comp = schem->comp_first; comp; comp = comp->next) {
		for (port = comp->port_first; port; port = port->next) {
			if (strcmp(port->inout, "out") == 0
			    || strcmp(port->inout, "inout") == 0) {
				fprintf(f, "static void\n");
				fprintf(f, "xml2c_%s_%s_out_set(struct cpssp "
					"*cpssp, unsigned int val)\n",
					mangle(comp->name), port->name);
				fprintf(f, "{\n");
				fprintf(f, "\tcpssp->state_%s_%s_out = val;\n",
					comp->name, port->name);
				fprintf(f, "#if DEBUG\n");
				fprintf(f, "\tfprintf(stderr, \"%s: "
					"pin %s_%s sets to \");\n",
					inname, comp->name, port->name);
				fprintf(f, "\tprintlogic(val);\n");
				fprintf(f, "#endif /* DEBUG */\n");
				fprintf(f, "\tCOMP_(resolve_sig_%s)(cpssp);\n",
					port->signal);
				fprintf(f, "}\n");

				fprintf(f, "\n");
			}
		}
	}

	/* ports */
	fprintf(f, "/* ports */\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "static void\n");
		fprintf(f, "COMP_(port_%s_set)"
			"(void *_cpssp, unsigned int val)\n",
			mangle(port->name));
		fprintf(f, "{\n");
		fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
		fprintf(f, "\n");
		fprintf(f, "\tcpssp->state_%s_out = val;\n",
			mangle(port->name));
		fprintf(f, "#if DEBUG\n");
		fprintf(f, "\tfprintf(stderr, \"%s: port %s changes to \");\n",
			inname, mangle(port->name));
		fprintf(f, "\tprintlogic(val);\n");
		fprintf(f, "#endif /* DEBUG */\n");
		fprintf(f, "\tCOMP_(resolve_sig_%s)(cpssp);\n", port->signal);
		fprintf(f, "}\n");

		fprintf(f, "\n");
	}

	/* create */
	fprintf(f, "void *\n");
	fprintf(f, "COMP_(create)(\n");
	fprintf(f, "\tconst char *name,\n");
	fprintf(f, "\tstruct sig_manage *port_manage,\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tstruct sig_std_logic *port_%s,\n",
			mangle(port->name));
	}
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tstruct sig_std_logic *gui_port_%s", sig->id);
		if (sig->next) {
			fprintf(f, ",");
		}
		fprintf(f, "\n");
	}
	fprintf(f, ")\n");
	fprintf(f, "{\n");

	/* port std_logic funcs */
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tstatic const struct "
			"sig_std_logic_funcs port_func_%s = {\n",
			mangle(port->name));
		fprintf(f, "\t\t.set_ext = COMP_(port_%s_set),\n",
			mangle(port->name));
		fprintf(f, "\t};\n");
	}

	/** cpssp */
	fprintf(f, "\tstruct cpssp *cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\tcpssp = shm_alloc(sizeof(*cpssp));\n");
	fprintf(f, "\tassert(cpssp);\n");

	fprintf(f, "\n");

	/* init signals */
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tcpssp->state_%s = SIG_STD_LOGIC_Z;\n", sig->id);
	}

	fprintf(f, "\n");

	/* init ports */
	fprintf(f, "\t/* init external ports */\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tcpssp->state_%s_out = SIG_STD_LOGIC_Z;\n",
			mangle(port->name));
		fprintf(f, "\tcpssp->state_%s_in = SIG_STD_LOGIC_Z;\n",
			mangle(port->name));
	}

	fprintf(f, "\n");

	/* connect ports as out */
	fprintf(f, "\t/* connect ports as out */\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tcpssp->port_%s = port_%s;\n",
			mangle(port->name), mangle(port->name));
		fprintf(f, "\tsig_std_logic_connect_out(port_%s, "
			"cpssp, SIG_STD_LOGIC_Z);\n",
			mangle(port->name));
	}

	fprintf(f, "\n");

	/* connect gui ports as out */
	fprintf(f, "\t/* connect gui ports as out */\n");
	for (sig = schem->sig_first; sig; sig = sig->next) {
		fprintf(f, "\tcpssp->gui_port_%s = gui_port_%s;\n",
			sig->id, sig->id);
		fprintf(f, "\tsig_std_logic_connect_out(gui_port_%s, cpssp, "
			"SIG_STD_LOGIC_Z);\n", sig->id);
	}

	fprintf(f, "\n");

	/* connect ports as in */
	fprintf(f, "\t/* connect ports as in */\n");
	for (port = schem->port_first; port; port = port->next) {
		fprintf(f, "\tsig_std_logic_connect_in(port_%s, "
			"cpssp, &port_func_%s);\n",
			mangle(port->name), mangle(port->name));
	}

	fprintf(f, "\n");

	/* create all elements */
	fprintf(f, "\t/* create all elements */\n");
	for (comp = schem->comp_first; comp; comp = comp->next) {
		fprintf(f, "\txml2c_%s_create(cpssp);\n", mangle(comp->name));
		/* pins to std Z */
		for (port = comp->port_first; port; port = port->next) {
			if (strcmp(port->inout, "out") == 0
			    || strcmp(port->inout, "inout") == 0) {
				fprintf(f, "\tcpssp->state_%s_%s_out = "
					"SIG_STD_LOGIC_Z;\n",
					comp->name, mangle(port->name));
			}
		}
		fprintf(f, "\n");
	}

	fprintf(f, "\treturn cpssp;\n");
	fprintf(f, "}\n\n");


	/* generic suspend and destroy funcs */
	fprintf(f, "void\n");
	fprintf(f, "COMP_(destroy)(void *_cpssp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\t/* destroy elements */\n");
	for (comp = schem->comp_first; comp; comp = comp->next) {
		fprintf(f, "\txml2c_%s_destroy(cpssp);\n", mangle(comp->name));
	}
	fprintf(f, "\n");
	fprintf(f, "\tshm_free(cpssp);\n");
	fprintf(f, "}\n");

	fprintf(f, "\n");

	fprintf(f, "void\n");
	fprintf(f, "COMP_(suspend)(void *_cpssp, FILE *fp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\tgeneric_suspend(cpssp, sizeof(*cpssp), fp);\n");
	fprintf(f, "}\n");

	fprintf(f, "\n");

	fprintf(f, "void\n");
	fprintf(f, "COMP_(resume)(void *_cpssp, FILE *fp)\n");
	fprintf(f, "{\n");
	fprintf(f, "\tstruct cpssp *cpssp = _cpssp;\n");
	fprintf(f, "\n");
	fprintf(f, "\tgeneric_resume(cpssp, sizeof(*cpssp), fp);\n");
	fprintf(f, "}\n");

	fclose(f);
}


static void __attribute__((noreturn))
usage(int retval, char *progname)
{
	fprintf(stderr, "Usage: %s <*.xml> [-o output]\n", progname);
	exit(retval);
}

int
main(int argc, char **argv)
{
	FILE *fp;
	struct xml_schem *schem;
	char *inname;
	char* progname = *argv;
	int opt_o = 0;
	char output[MAX_NAME];
	argv++;
	argc--;

	/*
	 * Get options.
	 */
	int c = getopt(argc, argv, "o:");
	if (c != -1) {
		if (c == 'o') {
			strncpy(output, optarg, MAX_NAME);
			opt_o = 1;
		} else {
			usage(1, progname);
		}
	} else {
		strcpy(output, ".");
	}
	if (argc == 1 ||
	    (argc == 3 && opt_o) ) {
		inname = argv[0];
	} else {
		usage(1, progname);
	}

	if (! strchr(inname, '.')) {
		usage(1, progname);
	}

	if (strchr(inname, '/')) {
		strcat(output, strrchr(inname, '/'));
	} else {
		strcat(output, "/");
		strcat(output, inname);
	}
	*strrchr(output, '.') = '\0';

	/*
	 * Read xml file.
	 */
	fp = fopen(inname, "r");
	if (! fp) {
		fprintf(stderr, "ERROR: %s: %s: %s.\n", progname,
			inname, strerror(errno));
		usage(1, progname);
		exit(1);
	}
	assert(fp);

	schem = xml_schem_read(fp);

	fclose(fp);

	create_c(output, schem);
	create_gui_c(output, schem);
	create_gui_gtk_c(output, schem);
	create_src(output, schem);

	return 0;
}
