#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# install pyparsing with: easy_install pyparsing
#
# eet.py
# Creates all the C boilerplate to use with the EET library.
#
# Author: Leandro A. F. Pereira <leandro@profusion.mobi>
# Copyright (C) 2010 ProFUSION Embedded Systems
# Licensed under the same terms as EET itself; see COPYING for
# details.
#

from pyparsing import *
import os
import string
import sys

identifier = Word(string.letters + "_")
digits = Word(string.digits)
default_value = Keyword('default').suppress() + QuotedString(quoteChar = '"', endQuoteChar = '"')
enum = ZeroOrMore(identifier + Literal(',').suppress()) + identifier
type = Keyword('str') + Optional(default_value) | \
  Keyword('int') | \
  Keyword('uint') | \
  Keyword('float') | \
  Keyword('double') | \
  Keyword('char') | \
  Keyword('uchar') | \
  Keyword('enum') + Keyword('of').suppress() + enum | \
  Keyword('image') + (Keyword('raw') | (Keyword('compress') + digits) | Keyword('lossy') + digits) | \
  Keyword('list') + Keyword('of').suppress() + identifier | \
  Keyword('hash') + Keyword('of').suppress() + identifier + Keyword('by').suppress() + identifier | \
  Keyword('pointer') + Keyword('to').suppress() + identifier
definition = Group(identifier + \
  Literal(':').suppress() + \
  type + \
  Optional(Keyword('noencode')) + \
  Literal(';').suppress())
block = OneOrMore( \
  Group(identifier + \
  Literal('{').suppress() + \
  Group(OneOrMore(definition)) + \
  Literal('}').suppress()) + \
  Optional(Keyword(';').suppress()))
block.ignore(cppStyleComment)

EINA_HASH_FUNCTIONS = {
  "str"    : "eina_hash_stringshared_new",
  "int"    : "eina_hash_int32_new",
  "enum"   : "eina_hash_int32_new",
  "uint"   : "eina_hash_int32_new",
  "char"   : "eina_hash_int32_new",
  "uchar"  : "eina_hash_int32_new",
  "image"  : "eina_hash_pointer_new",
}

FIELD_CONVERTER = {
  "str"    : "const char *",
  "int"    : "int",
  "uint"   : "unsigned int",
  "float"  : "float",
  "double" : "double",
  "list"   : "Eina_List *",
  "hash"   : "Eina_Hash *",
  "char"   : "char",
  "uchar"  : "unsigned char",
  "image"  : "Evas_Object *",
  "enum"   : "unsigned int",
}

FIELD_CONVERTER_EET = {
  "str"    : "EET_T_STRING",
  "int"    : "EET_T_INT",
  "uint"   : "EET_T_UINT",
  "float"  : "EET_T_FLOAT",
  "double" : "EET_T_DOUBLE",
  "char"   : "EET_T_CHAR",
  "uchar"  : "EET_T_UCHAR",
  "enum"   : "EET_T_UINT",
}

__images = set()
__deps = set()
__structs = {}
__subtypes = {}

def check(base_name, parsed_block):
  blocks = set()
  for name, fields in parsed_block:
    if name in blocks:
      raise NameError('Block %s already defined' % name)

    blocks.add(name)
    for field in fields:
      if field[1] in ('list', 'hash', 'pointer'):
        if not field[2] in blocks:
          raise NameError('Block %s is not defined' % field[2])

        __deps.add((name, field[2], field[0]))

  for block in blocks:
    if base_name.lower() == block.lower():
      raise NameError('Block %s has the same name as the output file' % base_name)

def _write_headers(header, impl):
  print >> header, "/* This file has been automatically generated by geneet.py */"
  print >> header, "/*                      DO NOT MODIFY                      */\n"
  print >> impl, "/* This file has been automatically generated by geneet.py */"
  print >> impl, "/*                      DO NOT MODIFY                      */\n"

def _write_includes(parsed_block, base_name, header, impl):
  print >> impl, """#include <limits.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "%s"
""" % header.name

  print >> header, """#ifndef __%s_H__
#define __%s_H__

#include <Eina.h>
#include <Eet.h>""" % (
    base_name.upper(),
    base_name.upper()
  )

  if any(field[1] == 'image' for name, fields in parsed_block for field in fields):
    print >> header, "#include <Evas.h>"
  print >> header, ""

def _write_structs(parsed_block, header, impl):
  for name, fields in parsed_block:
    __structs[name] = {}
    __subtypes[name] = {}

    print >> impl, """struct _%s {""" % name
    for field in fields:
      __structs[name][field[0]] = field[1]

      if field[1] == 'hash':
        __subtypes[name][field[0]] = (field[2], field[3])
      elif field[1] == 'list':
        __subtypes[name][field[0]] = (field[2], None)

      if field[1] == 'enum':
        print >> impl, "    %s_%s %s;" % (name, field[0].title(), field[0])
      elif field[1] == 'pointer':
        print >> impl, "    %s *%s;" % (field[2], field[2].lower())
      else:
        print >> impl, "    %s %s;" % (FIELD_CONVERTER[field[1]], field[0])
      if field[1] == 'image':
        print >> impl, "    unsigned int %s__id;" % field[0]

    if not any(dep[1] == name for dep in __deps):
      print >> impl, "    const char *__eet_filename;";

    print >> impl, """};\n"""

    print >> header, "typedef struct _%s %s;" % (name, name)

    for field in fields:
      if field[1] == 'enum':
       print >> header, "typedef enum {"
       for value in field[2:]:
         print >> header, "    %s_%s_%s%s," % (name.upper(), field[0].upper(), value.upper(), value is field[2] and " = 0" or "")
       print >> header, "    %s_%s_LAST_VALUE" % (name.upper(), field[0].upper())
       print >> header, "} %s_%s;" % (name, field[0].title())

def _write_reprs(parsed_block, header, impl):
  have_reprs = False
  for name, fields in parsed_block:
    for field in fields:
      if field[1] == 'enum':
        print >> impl, "static const char *%s_%s_REPR[] = { %s, NULL };" % (
          name.upper(), field[0].upper(),
          ", ".join('"%s"' % f for f in field[2:])
        )
        have_reprs = True
  if have_reprs:
    print >> impl, ""

def _write_entry_names(parsed_block, header, impl):
  for name, fields in parsed_block:
    print >> impl, """static const char %s_ENTRY[] = "%s";""" % (name.upper(), name.lower())
  print >> impl, ""

def _write_descriptors(parsed_block, header, impl):
  for name, fields in parsed_block:
    print >> impl, """static Eet_Data_Descriptor *_%s_descriptor = NULL;""" % (name.lower())

def _write_initializers(name, fields, header, impl):
    print >> impl, """\nstatic inline void
_%s_init(void)
{
    Eet_Data_Descriptor_Class eddc;

    if (_%s_descriptor) return;

    EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, %s);
    _%s_descriptor = eet_data_descriptor_stream_new(&eddc);
""" % (name.lower(), name.lower(), name, name.lower())

    for field in fields:
      if field[-1] == 'noencode':
        continue

      if field[1] == 'list':
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_LIST(_%s_descriptor, %s, "%s", %s, _%s_descriptor);""" % (
          name.lower(),
          name,
          field[0],
          field[0],
          field[2].lower()
        )
      elif field[1] == 'hash':
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_HASH(_%s_descriptor, %s, "%s", %s, _%s_descriptor);""" % (
          name.lower(),
          name,
          field[0],
          field[0],
          field[2].lower()
        )
      elif field[1] == 'image':
        __images.add(name)
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_BASIC(_%s_descriptor, %s, "%s", %s, EET_T_UINT);""" % (
          name.lower(),
          name,
          field[0] + '__id',
          field[0] + '__id'
        )
      elif field[1] == 'pointer':
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_SUB(_%s_descriptor, %s, "%s", %s, _%s_descriptor);""" % (
          name.lower(),
          name,
          field[0],
          field[0],
          field[2].lower()
        )
      else:
        type = FIELD_CONVERTER_EET[field[1]]
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_BASIC(_%s_descriptor, %s, "%s", %s, %s);""" % (
          name.lower(),
          name,
          field[0],
          field[0],
          type
        )
    print >> impl, """}\n"""

def _write_shutdowns(name, fields, header, impl):
    print >> impl, """static inline void
_%s_shutdown(void)
{
    if (!_%s_descriptor) return;
    eet_data_descriptor_free(_%s_descriptor);
    _%s_descriptor = NULL;
}\n""" % (name.lower(), name.lower(), name.lower(), name.lower())

def _write_allocators(name, fields, header, impl):
    arg_fields = []
    for field in fields:
      if field[1] == 'hash':
        continue
      elif field[1] == 'image':
        arg_fields.append('Evas_Object * %s' % field[0])
      elif field[1] == 'enum':
        arg_fields.append('%s_%s %s' % (
          name,
          field[0].title(),
          field[0]
        ))
      elif field[1] == 'pointer':
        arg_fields.append('%s *%s' % (
          field[2],
          field[2].lower(),
        ))
      else:
        type = FIELD_CONVERTER[field[1]]
        arg_fields.append('%s %s' % (type, field[0]))

    print >> header, """%s *%s_new(%s);""" % (name, name.lower(), ', '.join(arg_fields))
    print >> impl, """%s *
%s_new(%s)
{
    %s *%s = calloc(1, sizeof(%s));

    if (!%s)
       {
          fprintf(stderr, "ERROR: could not calloc %s\\n");
          return NULL;
       }
""" % (
      name,
      name.lower(),
      ', '.join(arg_fields),
      name,
      name.lower(),
      name,
      name.lower(),
      name)

    for field in fields:
      if field[1] == 'str':
        if len(field) > 2:
          print >> impl, """    %s->%s = eina_stringshare_add(%s ? %s : "%s");""" % (
            name.lower(),
            field[0],
            field[0],
            field[0],
            field[2]
          )
        else:
          print >> impl, """    %s->%s = eina_stringshare_add(%s);""" % (
            name.lower(),
            field[0],
            field[0]
          )
      elif field[1] == 'hash':
        hashed_type = field[2]
        hashed_field = field[3]

        if hashed_field in __structs[hashed_type]:
          print >> impl, """    %s->%s = %s(EINA_FREE_CB(%s_free));""" % (
            name.lower(),
            field[0],
            EINA_HASH_FUNCTIONS[__structs[hashed_type][hashed_field]],
            hashed_type.lower()
          )
        else:
          print >> impl, """    %s->%s = NULL;""" % (
            name.lower(),
            field[0]
          )
      elif field[1] == 'list':
        print >> impl, """    %s->%s = %s;""" % (
          name.lower(),
          field[0],
          field[0]
        )
      elif field[1] == 'image':
        print >> impl, """    %s->%s = %s;""" % (
          name.lower(),
          field[0],
          field[0]
        )
        print >> impl, """    %s->%s__id = 0;""" % (
          name.lower(),
          field[0],
        )
      elif field[1] == 'pointer':
        print >> impl, """    %s->%s = %s;""" % (
          name.lower(),
          field[2].lower(),
          field[2].lower()
        )
      else:
        print >> impl, """    %s->%s = %s;""" % (
          name.lower(),
          field[0],
          field[0]
        )
    print >> impl, "\n    return %s;\n}\n" % name.lower()

def _write_deallocators(name, fields, header, impl):
    has_pointer = any(field[1] == 'pointer' for field in fields)
    if has_pointer:
      print >> header, """void %s_free(%s *%s, Eina_Bool free_contents);""" % (name.lower(), name, name.lower())
      print >> impl, """void
%s_free(%s *%s, Eina_Bool free_contents)
{""" % (
        name.lower(),
        name,
        name.lower()
      )
    else:
      print >> header, """void %s_free(%s *%s);""" % (name.lower(), name, name.lower())
      print >> impl, """void
%s_free(%s *%s)
{""" % (
        name.lower(),
        name,
        name.lower()
      )

    for field in fields:
      if isinstance(field[1], str):
        if field[1] == 'str':
          print >> impl, """    eina_stringshare_del(%s->%s);""" % (
            name.lower(),
            field[0]
          )
        elif field[1] == 'pointer':
          if any(field == 'pointer' for field in __structs[field[2]].values()):
            print >> impl, """    if (free_contents) %s_free(%s->%s, free_contents);""" % (field[2].lower(), name.lower(), field[2].lower())
          else:
            print >> impl, """    if (free_contents) %s_free(%s->%s);""" % (field[2].lower(), name.lower(), field[2].lower())
        elif field[1] == 'list':
          print >> impl, """    if (%s->%s)
       {
          %s *%s_elem;
          EINA_LIST_FREE(%s->%s, %s_elem)
             %s_free(%s_elem);
       }""" % (
            name.lower(),
            field[0],
            field[2],
            field[0],
            name.lower(),
            field[0],
            field[0],
            field[2].lower(),
            field[0]
          )
        elif field[1] == 'image':
          print >> impl, """    if (%s->%s) evas_object_del(%s->%s);""" %(
            name.lower(),
            field[0],
            name.lower(),
            field[0]
          )
        elif field[1] == 'hash':
          print >> impl, """    if (%s->%s) eina_hash_free(%s->%s);""" %(
            name.lower(),
            field[0],
            name.lower(),
            field[0]
          )

    print >> impl, "    free(%s);\n}\n" % name.lower()

def _write_loaders(name, fields, header, impl):
  extra = ''
  for field in fields:
    if field[-1] == 'noencode':
      continue
    if field[1] == 'image':
      extra = 'Evas *evas, '
      break

  print >> header, """%s *%s_load(%sconst char *filename);""" % (name, name.lower(), extra)
  print >> impl, """%s *
%s_load(%sconst char *filename)
{
    %s *%s = NULL;
    Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ);
    if (!ef)
      {
        fprintf(stderr, "ERROR: could not open '%%s' for read\\n", filename);
        return NULL;
      }

    %s = eet_data_read(ef, _%s_descriptor, %s_ENTRY);
    if (!%s) goto end;""" % (
  name,
  name.lower(),
  extra,
  name,
  name.lower(),
  name.lower(),
  name.lower(),
  name.upper(),
  name.lower())

  print >> impl, "    %s->__eet_filename = eina_stringshare_add(filename);" % name.lower();

  for field in fields:
    if field[-1] == 'noencode':
      continue
    if field[1] == 'pointer':
      for pointee_field, pointee_type in __structs[field[2]].items():
        if pointee_type != 'hash': continue
        hashed_type, hashed_field = __subtypes[field[2]][pointee_field]
        allocator = "%s(EINA_FREE_CB(%s_free))" % (
          EINA_HASH_FUNCTIONS[__structs[hashed_type][hashed_field]],
          hashed_type.lower()
        )
        if pointee_type == 'hash':
          print >> impl, """    if (!%(pname)s->%(bname)s->%(fname)s) %(pname)s->%(bname)s->%(fname)s = %(allocator)s;""" % {
            "bname" : field[0],
            "fname" : pointee_field,
            "pname" : name.lower(),
            "allocator" : allocator
          }
    elif field[1] == 'hash':
      hashed_type = field[2]
      hashed_field = field[3]

      if hashed_field in __structs[hashed_type]:
        allocator = "%s(EINA_FREE_CB(%s_free))" % (
          EINA_HASH_FUNCTIONS[__structs[hashed_type][hashed_field]],
          hashed_type.lower()
        )
        print >> impl, """\n    if (!%(bname)s->%(fname)s) %(bname)s->%(fname)s = %(allocator)s;""" % {
          "bname" : name.lower(),
          "fname" : field[0],
          "allocator" : allocator
        }
    elif field[1] == 'image':
      print >> impl, """\n    if (%(bname)s->%(fname)s__id)
       {
          char %(fname)s_buf[256];
          unsigned int %(fname)s_w, %(fname)s_h;
          int %(fname)s_alpha, %(fname)s_compress, %(fname)s_quality, %(fname)s_lossy;
          void *%(fname)s_data;
          sprintf(%(fname)s_buf, "/image/%(perc)sd", %(bname)s->%(fname)s__id);
          %(fname)s_data = eet_data_image_read(ef, %(fname)s_buf, &%(fname)s_w, &%(fname)s_h, &%(fname)s_alpha, &%(fname)s_compress, &%(fname)s_quality, &%(fname)s_lossy);
          if (%(fname)s_data)
             {
                %(bname)s->%(fname)s = evas_object_image_add(evas);
                evas_object_image_size_set(%(bname)s->%(fname)s, %(fname)s_w, %(fname)s_h);
                evas_object_image_alpha_set(%(bname)s->%(fname)s, %(fname)s_alpha);
                evas_object_image_data_set(%(bname)s->%(fname)s, %(fname)s_data);
             }
       }""" % {
     "bname": name.lower(),
     "fname": field[0],
     "perc": "%"
   }

  print >> impl, "\nend:"
  print >> impl, "    eet_close(ef);"
  print >> impl, "    return %s;\n}\n" % name.lower();

def _write_dumpers(name, fields, header, impl):
  print >> header, """Eina_Bool %s_save(%s *%s, const char *filename);""" % (name.lower(), name, name.lower())
  print >> impl, """Eina_Bool
%s_save(%s *%s, const char *filename)
{
    Eet_File *ef;
    Eina_Bool ret;

    if (filename) eina_stringshare_replace(&(%s->__eet_filename), filename);
    else if (%s->__eet_filename) filename = %s->__eet_filename;
    else return EINA_FALSE;

    ef = eet_open(filename, EET_FILE_MODE_READ_WRITE);
    if (!ef)
       {
          fprintf(stderr, "ERROR: could not open '%%s' for write\\n", filename);
          return EINA_FALSE;
       }
""" % (
   name.lower(),
   name,
   name.lower(),
   name.lower(),
   name.lower(),
   name.lower(),
)

  has_images = any(field[-1] != 'noencode' and field[1] == 'image' for field in fields)
  dep_has_images = any(dep in __images for struct, dep, depee in __deps)

  if has_images or dep_has_images:
    print >> impl, "    i = 1;"

  if has_images:
    print >> impl, "    i = _write_%s_images(%s, ef, i);" % (
      name.lower(), name.lower()
    )

  if dep_has_images:
    for struct, dep, depee in __deps:
      if dep in __images:
        if __structs[name][depee] == 'list':
          print >> impl, """    if (%s->%s)
       {
          %s *%s;
          Eina_List *%s_list;
          EINA_LIST_FOREACH(%s->%s, %s_list, %s)
             i = _write_%s_images(%s, ef, i);
       }""" % (
            name.lower(), depee,
            dep, dep.lower(),
            dep.lower(),
            name.lower(), depee, dep.lower(), dep.lower(),
            dep.lower(), dep.lower()
          )
        elif __structs[name][depee] == 'hash':
          # Too lazy right now
          pass

  print >> impl, """    ret = !!eet_data_write(ef, _%s_descriptor, %s_ENTRY, %s, EINA_TRUE);
    eet_close(ef);

    return ret;
}""" % (
     name.lower(),
     name.upper(),
     name.lower()
  )

def _write_getters_setters(name, fields, header, impl):
  for field in fields:
    if field[1] == 'pointer':
      print >> header, """void %s_%s_set(%s *%s, %s *%s);
%s *%s_%s_get(%s *%s);""" % (
        name.lower(), field[2].lower(), name, name.lower(), field[2], field[2].lower(),
        field[2], name.lower(), field[2].lower(), name, name.lower()
      )
      print >> impl, """void %s_%s_set(%s *%s, %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = %s;
}

%s *%s_%s_get(%s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return %s->%s;
}
""" % (
          name.lower(), field[2].lower(), name, name.lower(), field[2], field[2].lower(),
          name.lower(),
          name.lower(), field[2].lower(), field[2].lower(),
          field[2], name.lower(), field[2].lower(), name, name.lower(),
          name.lower(),
          name.lower(), field[2].lower()
       )
    elif field[1] == 'list':
      print >> header, """void %s_%s_add(%s *%s, %s *%s);
void %s_%s_del(%s *%s, %s *%s);
%s *%s_%s_get(const %s *%s, unsigned int nth);
unsigned int %s_%s_count(const %s *%s);
Eina_List *%s_%s_list_get(const %s *%s);
void %s_%s_list_clear(%s *%s);
void %s_%s_list_set(%s *%s, Eina_List *list);""" % (
        name.lower(), field[0], name, name.lower(), field[2],
        field[2].lower(), name.lower(), field[0], name,
        name.lower(), field[2], field[2].lower(), field[2],
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower()
      )
      print >> impl, """inline void
%s_%s_add(%s *%s, %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = eina_list_append(%s->%s, %s);
}
""" % (
        name.lower(), field[0], name, name.lower(),
        field[2], field[2].lower(), name.lower(),
        name.lower(), field[0], name.lower(),
        field[0], field[2].lower()
      )

      print >> impl, """inline void
%s_%s_del(%s *%s, %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = eina_list_remove(%s->%s, %s);
}
""" % (
        name.lower(), field[0], name, name.lower(), field[2],
        field[2].lower(), name.lower(), name.lower(), field[0],
        name.lower(), field[0], field[2].lower()
      )

      print >> impl, """inline %s *
%s_%s_get(const %s *%s, unsigned int nth)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return eina_list_nth(%s->%s, nth);
}
""" % (
        field[2], name.lower(), field[0], name, name.lower(),
        name.lower(), name.lower(), field[0]
      )

      print >> impl, """inline unsigned int
%s_%s_count(const %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, 0);
    return eina_list_count(%s->%s);
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0]
      )

      print >> impl, """void
%s_%s_list_clear(%s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s *data;
    EINA_LIST_FREE(%s->%s, data) %s_free(data);
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        field[2],
        name.lower(), field[0], field[2].lower(),
      )

      print >> impl, """inline Eina_List *
%s_%s_list_get(const %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return %s->%s;
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0]
      )
      print >> impl, """inline void
%s_%s_list_set(%s *%s, Eina_List *list)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = list;
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0]
      )
    elif field[1] == 'hash':
      hashed_type = field[2]
      hashed_field = field[3]

      print >> header, """void %s_%s_add(%s *%s, %s %s, %s *%s);
void %s_%s_del(%s *%s, %s %s);
%s *%s_%s_get(const %s *%s, %s key);
Eina_Hash *%s_%s_hash_get(const %s *%s);
void %s_%s_modify(%s *%s, %s key, void *value);""" % (
        name.lower(), field[0], name, name.lower(),
        FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
        hashed_type, hashed_type.lower(), name.lower(), field[0], name,
        name.lower(), FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
        hashed_type, name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[__structs[hashed_type][hashed_field]],
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[__structs[hashed_type][hashed_field]]
      )
      print >> impl, """void
%s_%s_add(%s *%s, %s %s, %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    eina_hash_add(%s->%s, %s, %s);
}
""" % (
      name.lower(), field[0], name, name.lower(),
      FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
      hashed_type, hashed_type.lower(), name.lower(), name.lower(), field[0],
      hashed_field, hashed_type.lower()
    )

      print >> impl, """void
%s_%s_del(%s *%s, %s %s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    eina_hash_del(%s->%s, %s, NULL);
}
""" % (
      name.lower(), field[0], name, name.lower(),
      FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
      name.lower(), name.lower(), field[0], hashed_field
    )

      print >> impl, """inline %s *
%s_%s_get(const %s *%s, %s %s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return eina_hash_find(%s->%s, %s);
}
""" % (
      hashed_type, name.lower(), field[0], name, name.lower(),
      FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
      name.lower(), name.lower(), field[0], hashed_field
    )

      print >> impl, """inline Eina_Hash *
%s_%s_hash_get(const %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return %s->%s;
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0]
      )

      print >> impl, """void
%s_%s_modify(%s *%s, %s key, void *value)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    eina_hash_modify(%s->%s, key, value);
}
""" % (
        name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[__structs[hashed_type][hashed_field]],
        name.lower(),
        name.lower(), field[0]
      )

    elif field[1] == 'image':
      print >> header, """void %s_%s_set(%s *%s, Evas_Object *%s);
Evas_Object *%s_%s_get(const %s *%s, Evas *evas, const char *eet_file);""" % (
        name.lower(), field[0], name, name.lower(), field[0],
        name.lower(), field[0], name, name.lower()
      )
      print >> impl, """void
%s_%s_set(%s *%s, Evas_Object *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    if (%s->%s) evas_object_del(%s->%s);
    %s->%s__id = 0;
    %s->%s = %s;
}
""" % (
        name.lower(), field[0], name, name.lower(), field[0],
        name.lower(),
        name.lower(), field[0], name.lower(), field[0],
        name.lower(), field[0],
        name.lower(), field[0], field[0]
    )
      print >> impl, """Evas_Object *
%s_%s_get(const %s *%s, Evas *evas, const char *eet_file)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    if (%s->%s) return %s->%s;
    _load_%s_images(%s, evas, eet_file);
    return %s->%s;
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0], name.lower(), field[0],
        name.lower(), name.lower(),
        name.lower(), field[0]
    )
    elif field[1] == 'enum':
      print >> header, """void %s_%s_set(%s *%s, %s %s);
%s %s_%s_get(const %s *%s);
const char * %s_%s_repr_get(const %s *%s);
const char * %s_%s_str_get(%s %s);""" % (
        name.lower(), field[0], name, name.lower(), name + '_' + field[0].title(),
        field[0], name + '_' + field[0].title(), name.lower(), field[0],
        name, name.lower(),
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name + '_' + field[0].title(), field[0]
      )
      print >> impl, """inline %s
%s_%s_get(const %s *%s)
{
    return %s->%s;
}
""" % (
      name + '_' + field[0].title(),
      name.lower(), field[0],
      name, name.lower(),
      name.lower(), field[0]
    )
      print >> impl, """inline const char *
%s_%s_repr_get(const %s *%s)
{
    return %s_%s_REPR[%s->%s];
}
""" % (
      name.lower(), field[0],
      name, name.lower(),
      name.upper(), field[0].upper(),
      name.lower(), field[0]
    )

      print >> impl, """inline void
%s_%s_set(%s *%s, %s %s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    if (%s >= %s_%s_LAST_VALUE) return;
    %s->%s = %s;
}
""" % (
      name.lower(), field[0], name, name.lower(),
      name + '_' + field[0].title(), field[0],
      name.lower(),
      field[0], name.upper(), field[0].upper(),
      name.lower(), field[0], field[0]
    )

      print >> impl, """inline const char *
%s_%s_str_get(%s %s)
{
    if (%s >= %s_%s_LAST_VALUE) return NULL;
    return %s_%s_REPR[%s];
}
""" % (
      name.lower(), field[0],
      name + '_' + field[0].title(), field[0],
      field[0], name.upper(), field[0].upper(),
      name.upper(), field[0].upper(), field[0]
    )
    else:
      print >> header, """void %s_%s_set(%s *%s, %s %s);
%s %s_%s_get(const %s *%s);""" % (
        name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[field[1]],
        field[0], FIELD_CONVERTER[field[1]], name.lower(), field[0], name, name.lower(),
      )

      print >> impl, """inline %s
%s_%s_get(const %s *%s)
{
    return %s->%s;
}
""" % (
      FIELD_CONVERTER[field[1]],
      name.lower(), field[0],
      name, name.lower(),
      name.lower(), field[0]
    )
      if field[1] == 'str':
        print >> impl, """inline void
%s_%s_set(%s *%s, const char *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    eina_stringshare_replace(&(%s->%s), %s);
}
""" % (
          name.lower(), field[0], name, name.lower(), field[0],
          name.lower(),
          name.lower(), field[0], field[0]
      )
      else:
        print >> impl, """inline void
%s_%s_set(%s *%s, %s %s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = %s;
}
""" % (
          name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[field[1]], field[0],
          name.lower(),
          name.lower(), field[0], field[0]
      )

def _write_image_loaders(name, fields, impl):
  if not any(field[1] == 'image' for field in fields):
    return

  print >> impl, """static void
_load_%s_images(%s *%s, Evas *evas, const char *filename)
{
    Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ);
    if (!ef)
       {
          fprintf(stderr, "ERROR: could not open '%%s' for read\\n", filename);
          return;
       }""" % (
    name.lower(), name, name.lower()
  )

  for field in (f for f in fields if f[1] == 'image'):
    print >> impl, """\n    if (%(bname)s->%(fname)s__id)
       {
          char %(fname)s_buf[256];
          unsigned int %(fname)s_w, %(fname)s_h;
          int %(fname)s_alpha, %(fname)s_compress, %(fname)s_quality, %(fname)s_lossy;
          void *%(fname)s_data;
          sprintf(%(fname)s_buf, "/image/%(perc)sd", %(bname)s->%(fname)s__id);
          %(fname)s_data = eet_data_image_read(ef, %(fname)s_buf, &%(fname)s_w, &%(fname)s_h, &%(fname)s_alpha, &%(fname)s_compress, &%(fname)s_quality, &%(fname)s_lossy);
          if (%(fname)s_data)
             {
                %(bname)s->%(fname)s = evas_object_image_add(evas);
                evas_object_image_size_set(%(bname)s->%(fname)s, %(fname)s_w, %(fname)s_h);
                evas_object_image_alpha_set(%(bname)s->%(fname)s, %(fname)s_alpha);
                evas_object_image_data_set(%(bname)s->%(fname)s, %(fname)s_data);
             }
       }""" % {
   "bname": name.lower(),
   "fname": field[0],
   "perc": "%"
 }

  print >> impl, "\n    eet_close(ef);\n}\n"

def _write_image_savers(name, fields, impl):
  if not any(field[1] == 'image' for field in fields):
    return

  print >> impl, """static int
_write_%s_images(%s *%s, Eet_File *ef, int image_id)
{""" % (
    name.lower(), name, name.lower()
  )

  for field in fields:
    if field[-1] == 'noencode':
      continue

    if field[1] == 'image':
      if field[2] == "raw":
        compress = False
        lossy = False
        quality = 100
      elif field[2] == "lossy":
        compress = True
        lossy = True
        quality = int(field[3])
      else:
        compress = True
        lossy = False
        quality = int(field[3])

      print >> impl, """    if (%(bname)s->%(fname)s)
       {
          char %(fname)s_buf[256];
          int %(fname)s_w, %(fname)s_h;
          int %(fname)s_alpha;
          void *%(fname)s_data;
          %(bname)s->%(fname)s__id = image_id;
          sprintf(%(fname)s_buf, "/image/%(perc)sd", image_id++);
          evas_object_image_size_get(%(bname)s->%(fname)s, &%(fname)s_w, &%(fname)s_h);
          %(fname)s_alpha = evas_object_image_alpha_get(%(bname)s->%(fname)s);
          %(fname)s_data = evas_object_image_data_get(%(bname)s->%(fname)s, EINA_FALSE);
          eet_data_image_write(ef, %(fname)s_buf, %(fname)s_data, %(fname)s_w, %(fname)s_h, %(fname)s_alpha, %(compress)d, %(quality)d, %(lossy)d);
       }""" % {
     "bname": name.lower(),
     "fname": field[0],
     "perc": "%",
     "lossy": lossy,
     "compress": compress,
     "quality": quality
   }

  print >> impl, """    return image_id;
}
"""

def _write_block(parsed_block, header, impl):
  print >> header, ""

  for name, fields in parsed_block:
    print >> header, """/* %s */""" % name
    _write_initializers(name, fields, header, impl)
    _write_shutdowns(name, fields, header, impl)

    _write_allocators(name, fields, header, impl)
    _write_deallocators(name, fields, header, impl)

    print >> header, ""
    _write_image_loaders(name, fields, impl)
    _write_image_savers(name, fields, impl)
    _write_getters_setters(name, fields, header, impl)

    if not any(dep[1] == name for dep in __deps):
      print >> header, ""
      _write_loaders(name, fields, header, impl)
      _write_dumpers(name, fields, header, impl)

    print >> header, ""

def _write_global_initializers(parsed_block, base_name, header, impl):
  print >> header, "/* Global initializer / shutdown functions */"
  print >> header, "void %s_init(void);" % base_name
  print >> header, "void %s_shutdown(void);" % base_name
  print >> header, ""

  print >> impl, """\nvoid
%s_init(void)
{""" % base_name
  for name, fields in parsed_block:
    print >> impl, "    _%s_init();" % name.lower()
  print >> impl, "}\n"

  print >> impl, """void
%s_shutdown(void)
{""" % base_name
  for name, fields in parsed_block:
    print >> impl, "    _%s_shutdown();" % name.lower()
  print >> impl, "}\n"

def write_output(parsed_block, base_name, dir_name):
  header = file(dir_name + base_name + '.h', 'w')
  impl = file(dir_name + base_name + '.c', 'w')

  _write_headers(header, impl)
  _write_includes(parsed_block, base_name, header, impl)
  _write_structs(parsed_block, header, impl)
  _write_reprs(parsed_block, header, impl)
  _write_entry_names(parsed_block, header, impl)
  _write_descriptors(parsed_block, header, impl)
  _write_block(parsed_block, header, impl)
  _write_global_initializers(parsed_block, base_name, header, impl)

  print >> header, """#endif /* __%s_H__ */""" % base_name.upper()

  header.close()
  impl.close()

if __name__ == '__main__':
  if len(sys.argv) < 2:
    print 'Usage: %s file.geneet' % sys.argv[0]
  else:
    dir_name = os.path.dirname(sys.argv[1])
    if dir_name:
        dir_name = dir_name + '/'
    base_name = os.path.basename('.'.join(sys.argv[1].split('.')[:-1]))

    try:
      parsed_block = block.parseFile(sys.argv[1])
    except ParseException, e:
      print 'Syntax error:', e
      sys.exit(1)

    check(base_name, parsed_block)
    write_output(parsed_block, base_name, dir_name)


2b4a1c9738bc0cd070d74f8611954c39cb3376c6
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# install pyparsing with: easy_install pyparsing
#
# eet.py
# Creates all the C boilerplate to use with the EET library.
#
# Author: Leandro A. F. Pereira <leandro@profusion.mobi>
# Copyright (C) 2010 ProFUSION Embedded Systems
# Licensed under the same terms as EET itself; see COPYING for
# details.
#

from pyparsing import *
import os
import string
import sys

identifier = Word(string.letters + "_")
digits = Word(string.digits)
default_value = Keyword('default').suppress() + QuotedString(quoteChar = '"', endQuoteChar = '"')
enum = ZeroOrMore(identifier + Literal(',').suppress()) + identifier
type = Keyword('str') + Optional(default_value) | \
  Keyword('int') | \
  Keyword('uint') | \
  Keyword('float') | \
  Keyword('double') | \
  Keyword('char') | \
  Keyword('uchar') | \
  Keyword('enum') + Keyword('of').suppress() + enum | \
  Keyword('image') + (Keyword('raw') | (Keyword('compress') + digits) | Keyword('lossy') + digits) | \
  Keyword('list') + Keyword('of').suppress() + identifier | \
  Keyword('hash') + Keyword('of').suppress() + identifier + Keyword('by').suppress() + identifier | \
  Keyword('pointer') + Keyword('to').suppress() + identifier
definition = Group(identifier + \
  Literal(':').suppress() + \
  type + \
  Optional(Keyword('noencode')) + \
  Literal(';').suppress())
block = OneOrMore( \
  Group(identifier + \
  Literal('{').suppress() + \
  Group(OneOrMore(definition)) + \
  Literal('}').suppress()) + \
  Optional(Keyword(';').suppress()))
block.ignore(cppStyleComment)

EINA_HASH_FUNCTIONS = {
  "str"    : "eina_hash_stringshared_new",
  "int"    : "eina_hash_int32_new",
  "enum"   : "eina_hash_int32_new",
  "uint"   : "eina_hash_int32_new",
  "char"   : "eina_hash_int32_new",
  "uchar"  : "eina_hash_int32_new",
  "image"  : "eina_hash_pointer_new",
}

FIELD_CONVERTER = {
  "str"    : "const char *",
  "int"    : "int",
  "uint"   : "unsigned int",
  "float"  : "float",
  "double" : "double",
  "list"   : "Eina_List *",
  "hash"   : "Eina_Hash *",
  "char"   : "char",
  "uchar"  : "unsigned char",
  "image"  : "Evas_Object *",
  "enum"   : "unsigned int",
}

FIELD_CONVERTER_EET = {
  "str"    : "EET_T_STRING",
  "int"    : "EET_T_INT",
  "uint"   : "EET_T_UINT",
  "float"  : "EET_T_FLOAT",
  "double" : "EET_T_DOUBLE",
  "char"   : "EET_T_CHAR",
  "uchar"  : "EET_T_UCHAR",
  "enum"   : "EET_T_UINT",
}

__images = set()
__deps = set()
__structs = {}
__subtypes = {}

def check(base_name, parsed_block):
  blocks = set()
  for name, fields in parsed_block:
    if name in blocks:
      raise NameError('Block %s already defined' % name)

    blocks.add(name)
    for field in fields:
      if field[1] in ('list', 'hash', 'pointer'):
        if not field[2] in blocks:
          raise NameError('Block %s is not defined' % field[2])

        __deps.add((name, field[2], field[0]))

  for block in blocks:
    if base_name.lower() == block.lower():
      raise NameError('Block %s has the same name as the output file' % base_name)

def _write_headers(header, impl):
  print >> header, "/* This file has been automatically generated by geneet.py */"
  print >> header, "/*                      DO NOT MODIFY                      */\n"
  print >> impl, "/* This file has been automatically generated by geneet.py */"
  print >> impl, "/*                      DO NOT MODIFY                      */\n"

def _write_includes(parsed_block, base_name, header, impl):
  print >> impl, """#include <limits.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include "%s"
""" % header.name

  print >> header, """#ifndef __%s_H__
#define __%s_H__

#include <Eina.h>
#include <Eet.h>""" % (
    base_name.upper(),
    base_name.upper()
  )

  if any(field[1] == 'image' for name, fields in parsed_block for field in fields):
    print >> header, "#include <Evas.h>"
  print >> header, ""

def _write_structs(parsed_block, header, impl):
  for name, fields in parsed_block:
    __structs[name] = {}
    __subtypes[name] = {}

    print >> impl, """struct _%s {""" % name
    for field in fields:
      __structs[name][field[0]] = field[1]

      if field[1] == 'hash':
        __subtypes[name][field[0]] = (field[2], field[3])
      elif field[1] == 'list':
        __subtypes[name][field[0]] = (field[2], None)

      if field[1] == 'enum':
        print >> impl, "    %s_%s %s;" % (name, field[0].title(), field[0])
      elif field[1] == 'pointer':
        print >> impl, "    %s *%s;" % (field[2], field[2].lower())
      else:
        print >> impl, "    %s %s;" % (FIELD_CONVERTER[field[1]], field[0])
      if field[1] == 'image':
        print >> impl, "    unsigned int %s__id;" % field[0]

    if not any(dep[1] == name for dep in __deps):
      print >> impl, "    const char *__eet_filename;";

    print >> impl, """};\n"""

    print >> header, "typedef struct _%s %s;" % (name, name)

    for field in fields:
      if field[1] == 'enum':
       print >> header, "typedef enum {"
       for value in field[2:]:
         print >> header, "    %s_%s_%s%s," % (name.upper(), field[0].upper(), value.upper(), value is field[2] and " = 0" or "")
       print >> header, "    %s_%s_LAST_VALUE" % (name.upper(), field[0].upper())
       print >> header, "} %s_%s;" % (name, field[0].title())

def _write_reprs(parsed_block, header, impl):
  have_reprs = False
  for name, fields in parsed_block:
    for field in fields:
      if field[1] == 'enum':
        print >> impl, "static const char *%s_%s_REPR[] = { %s, NULL };" % (
          name.upper(), field[0].upper(),
          ", ".join('"%s"' % f for f in field[2:])
        )
        have_reprs = True
  if have_reprs:
    print >> impl, ""

def _write_entry_names(parsed_block, header, impl):
  for name, fields in parsed_block:
    print >> impl, """static const char %s_ENTRY[] = "%s";""" % (name.upper(), name.lower())
  print >> impl, ""

def _write_descriptors(parsed_block, header, impl):
  for name, fields in parsed_block:
    print >> impl, """static Eet_Data_Descriptor *_%s_descriptor = NULL;""" % (name.lower())

def _write_initializers(name, fields, header, impl):
    print >> impl, """\nstatic inline void
_%s_init(void)
{
    Eet_Data_Descriptor_Class eddc;

    if (_%s_descriptor) return;

    EET_EINA_STREAM_DATA_DESCRIPTOR_CLASS_SET(&eddc, %s);
    _%s_descriptor = eet_data_descriptor_stream_new(&eddc);
""" % (name.lower(), name.lower(), name, name.lower())

    for field in fields:
      if field[-1] == 'noencode':
        continue

      if field[1] == 'list':
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_LIST(_%s_descriptor, %s, "%s", %s, _%s_descriptor);""" % (
          name.lower(),
          name,
          field[0],
          field[0],
          field[2].lower()
        )
      elif field[1] == 'hash':
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_HASH(_%s_descriptor, %s, "%s", %s, _%s_descriptor);""" % (
          name.lower(),
          name,
          field[0],
          field[0],
          field[2].lower()
        )
      elif field[1] == 'image':
        __images.add(name)
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_BASIC(_%s_descriptor, %s, "%s", %s, EET_T_UINT);""" % (
          name.lower(),
          name,
          field[0] + '__id',
          field[0] + '__id'
        )
      elif field[1] == 'pointer':
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_SUB(_%s_descriptor, %s, "%s", %s, _%s_descriptor);""" % (
          name.lower(),
          name,
          field[0],
          field[0],
          field[2].lower()
        )
      else:
        type = FIELD_CONVERTER_EET[field[1]]
        print >> impl, """    EET_DATA_DESCRIPTOR_ADD_BASIC(_%s_descriptor, %s, "%s", %s, %s);""" % (
          name.lower(),
          name,
          field[0],
          field[0],
          type
        )
    print >> impl, """}\n"""

def _write_shutdowns(name, fields, header, impl):
    print >> impl, """static inline void
_%s_shutdown(void)
{
    if (!_%s_descriptor) return;
    eet_data_descriptor_free(_%s_descriptor);
    _%s_descriptor = NULL;
}\n""" % (name.lower(), name.lower(), name.lower(), name.lower())

def _write_allocators(name, fields, header, impl):
    arg_fields = []
    for field in fields:
      if field[1] == 'hash':
        continue
      elif field[1] == 'image':
        arg_fields.append('Evas_Object * %s' % field[0])
      elif field[1] == 'enum':
        arg_fields.append('%s_%s %s' % (
          name,
          field[0].title(),
          field[0]
        ))
      elif field[1] == 'pointer':
        arg_fields.append('%s *%s' % (
          field[2],
          field[2].lower(),
        ))
      else:
        type = FIELD_CONVERTER[field[1]]
        arg_fields.append('%s %s' % (type, field[0]))

    print >> header, """%s *%s_new(%s);""" % (name, name.lower(), ', '.join(arg_fields))
    print >> impl, """%s *
%s_new(%s)
{
    %s *%s = calloc(1, sizeof(%s));

    if (!%s)
       {
          fprintf(stderr, "ERROR: could not calloc %s\\n");
          return NULL;
       }
""" % (
      name,
      name.lower(),
      ', '.join(arg_fields),
      name,
      name.lower(),
      name,
      name.lower(),
      name)

    for field in fields:
      if field[1] == 'str':
        if len(field) > 2:
          print >> impl, """    %s->%s = eina_stringshare_add(%s ? %s : "%s");""" % (
            name.lower(),
            field[0],
            field[0],
            field[0],
            field[2]
          )
        else:
          print >> impl, """    %s->%s = eina_stringshare_add(%s);""" % (
            name.lower(),
            field[0],
            field[0]
          )
      elif field[1] == 'hash':
        hashed_type = field[2]
        hashed_field = field[3]

        if hashed_field in __structs[hashed_type]:
          print >> impl, """    %s->%s = %s(EINA_FREE_CB(%s_free));""" % (
            name.lower(),
            field[0],
            EINA_HASH_FUNCTIONS[__structs[hashed_type][hashed_field]],
            hashed_type.lower()
          )
        else:
          print >> impl, """    %s->%s = NULL;""" % (
            name.lower(),
            field[0]
          )
      elif field[1] == 'list':
        print >> impl, """    %s->%s = %s;""" % (
          name.lower(),
          field[0],
          field[0]
        )
      elif field[1] == 'image':
        print >> impl, """    %s->%s = %s;""" % (
          name.lower(),
          field[0],
          field[0]
        )
        print >> impl, """    %s->%s__id = 0;""" % (
          name.lower(),
          field[0],
        )
      elif field[1] == 'pointer':
        print >> impl, """    %s->%s = %s;""" % (
          name.lower(),
          field[2].lower(),
          field[2].lower()
        )
      else:
        print >> impl, """    %s->%s = %s;""" % (
          name.lower(),
          field[0],
          field[0]
        )
    print >> impl, "\n    return %s;\n}\n" % name.lower()

def _write_deallocators(name, fields, header, impl):
    has_pointer = any(field[1] == 'pointer' for field in fields)
    if has_pointer:
      print >> header, """void %s_free(%s *%s, Eina_Bool free_contents);""" % (name.lower(), name, name.lower())
      print >> impl, """void
%s_free(%s *%s, Eina_Bool free_contents)
{""" % (
        name.lower(),
        name,
        name.lower()
      )
    else:
      print >> header, """void %s_free(%s *%s);""" % (name.lower(), name, name.lower())
      print >> impl, """void
%s_free(%s *%s)
{""" % (
        name.lower(),
        name,
        name.lower()
      )

    for field in fields:
      if isinstance(field[1], str):
        if field[1] == 'str':
          print >> impl, """    eina_stringshare_del(%s->%s);""" % (
            name.lower(),
            field[0]
          )
        elif field[1] == 'pointer':
          if any(field == 'pointer' for field in __structs[field[2]].values()):
            print >> impl, """    if (free_contents) %s_free(%s->%s, free_contents);""" % (field[2].lower(), name.lower(), field[2].lower())
          else:
            print >> impl, """    if (free_contents) %s_free(%s->%s);""" % (field[2].lower(), name.lower(), field[2].lower())
        elif field[1] == 'list':
          print >> impl, """    if (%s->%s)
       {
          %s *%s_elem;
          EINA_LIST_FREE(%s->%s, %s_elem)
             %s_free(%s_elem);
       }""" % (
            name.lower(),
            field[0],
            field[2],
            field[0],
            name.lower(),
            field[0],
            field[0],
            field[2].lower(),
            field[0]
          )
        elif field[1] == 'image':
          print >> impl, """    if (%s->%s) evas_object_del(%s->%s);""" %(
            name.lower(),
            field[0],
            name.lower(),
            field[0]
          )
        elif field[1] == 'hash':
          print >> impl, """    if (%s->%s) eina_hash_free(%s->%s);""" %(
            name.lower(),
            field[0],
            name.lower(),
            field[0]
          )

    print >> impl, "    free(%s);\n}\n" % name.lower()

def _write_loaders(name, fields, header, impl):
  extra = ''
  for field in fields:
    if field[-1] == 'noencode':
      continue
    if field[1] == 'image':
      extra = 'Evas *evas, '
      break

  print >> header, """%s *%s_load(%sconst char *filename);""" % (name, name.lower(), extra)
  print >> impl, """%s *
%s_load(%sconst char *filename)
{
    %s *%s = NULL;
    Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ);
    if (!ef)
      {
        fprintf(stderr, "ERROR: could not open '%%s' for read\\n", filename);
        return NULL;
      }

    %s = eet_data_read(ef, _%s_descriptor, %s_ENTRY);
    if (!%s) goto end;""" % (
  name,
  name.lower(),
  extra,
  name,
  name.lower(),
  name.lower(),
  name.lower(),
  name.upper(),
  name.lower())

  print >> impl, "    %s->__eet_filename = eina_stringshare_add(filename);" % name.lower();

  for field in fields:
    if field[-1] == 'noencode':
      continue
    if field[1] == 'pointer':
      for pointee_field, pointee_type in __structs[field[2]].items():
        if pointee_type != 'hash': continue
        hashed_type, hashed_field = __subtypes[field[2]][pointee_field]
        allocator = "%s(EINA_FREE_CB(%s_free))" % (
          EINA_HASH_FUNCTIONS[__structs[hashed_type][hashed_field]],
          hashed_type.lower()
        )
        if pointee_type == 'hash':
          print >> impl, """    if (!%(pname)s->%(bname)s->%(fname)s) %(pname)s->%(bname)s->%(fname)s = %(allocator)s;""" % {
            "bname" : field[0],
            "fname" : pointee_field,
            "pname" : name.lower(),
            "allocator" : allocator
          }
    elif field[1] == 'hash':
      hashed_type = field[2]
      hashed_field = field[3]

      if hashed_field in __structs[hashed_type]:
        allocator = "%s(EINA_FREE_CB(%s_free))" % (
          EINA_HASH_FUNCTIONS[__structs[hashed_type][hashed_field]],
          hashed_type.lower()
        )
        print >> impl, """\n    if (!%(bname)s->%(fname)s) %(bname)s->%(fname)s = %(allocator)s;""" % {
          "bname" : name.lower(),
          "fname" : field[0],
          "allocator" : allocator
        }
    elif field[1] == 'image':
      print >> impl, """\n    if (%(bname)s->%(fname)s__id)
       {
          char %(fname)s_buf[256];
          unsigned int %(fname)s_w, %(fname)s_h;
          int %(fname)s_alpha, %(fname)s_compress, %(fname)s_quality, %(fname)s_lossy;
          void *%(fname)s_data;
          sprintf(%(fname)s_buf, "/image/%(perc)sd", %(bname)s->%(fname)s__id);
          %(fname)s_data = eet_data_image_read(ef, %(fname)s_buf, &%(fname)s_w, &%(fname)s_h, &%(fname)s_alpha, &%(fname)s_compress, &%(fname)s_quality, &%(fname)s_lossy);
          if (%(fname)s_data)
             {
                %(bname)s->%(fname)s = evas_object_image_add(evas);
                evas_object_image_size_set(%(bname)s->%(fname)s, %(fname)s_w, %(fname)s_h);
                evas_object_image_alpha_set(%(bname)s->%(fname)s, %(fname)s_alpha);
                evas_object_image_data_set(%(bname)s->%(fname)s, %(fname)s_data);
             }
       }""" % {
     "bname": name.lower(),
     "fname": field[0],
     "perc": "%"
   }

  print >> impl, "\nend:"
  print >> impl, "    eet_close(ef);"
  print >> impl, "    return %s;\n}\n" % name.lower();

def _write_dumpers(name, fields, header, impl):
  print >> header, """Eina_Bool %s_save(%s *%s, const char *filename);""" % (name.lower(), name, name.lower())
  print >> impl, """Eina_Bool
%s_save(%s *%s, const char *filename)
{
    Eet_File *ef;
    Eina_Bool ret;

    if (filename) eina_stringshare_replace(&(%s->__eet_filename), filename);
    else if (%s->__eet_filename) filename = %s->__eet_filename;
    else return EINA_FALSE;

    ef = eet_open(filename, EET_FILE_MODE_READ_WRITE);
    if (!ef)
       {
          fprintf(stderr, "ERROR: could not open '%%s' for write\\n", filename);
          return EINA_FALSE;
       }
""" % (
   name.lower(),
   name,
   name.lower(),
   name.lower(),
   name.lower(),
   name.lower(),
)

  has_images = any(field[-1] != 'noencode' and field[1] == 'image' for field in fields)
  dep_has_images = any(dep in __images for struct, dep, depee in __deps)

  if has_images or dep_has_images:
    print >> impl, "    i = 1;"

  if has_images:
    print >> impl, "    i = _write_%s_images(%s, ef, i);" % (
      name.lower(), name.lower()
    )

  if dep_has_images:
    for struct, dep, depee in __deps:
      if dep in __images:
        if __structs[name][depee] == 'list':
          print >> impl, """    if (%s->%s)
       {
          %s *%s;
          Eina_List *%s_list;
          EINA_LIST_FOREACH(%s->%s, %s_list, %s)
             i = _write_%s_images(%s, ef, i);
       }""" % (
            name.lower(), depee,
            dep, dep.lower(),
            dep.lower(),
            name.lower(), depee, dep.lower(), dep.lower(),
            dep.lower(), dep.lower()
          )
        elif __structs[name][depee] == 'hash':
          # Too lazy right now
          pass

  print >> impl, """    ret = !!eet_data_write(ef, _%s_descriptor, %s_ENTRY, %s, EINA_TRUE);
    eet_close(ef);

    return ret;
}""" % (
     name.lower(),
     name.upper(),
     name.lower()
  )

def _write_getters_setters(name, fields, header, impl):
  for field in fields:
    if field[1] == 'pointer':
      print >> header, """void %s_%s_set(%s *%s, %s *%s);
%s *%s_%s_get(%s *%s);""" % (
        name.lower(), field[2].lower(), name, name.lower(), field[2], field[2].lower(),
        field[2], name.lower(), field[2].lower(), name, name.lower()
      )
      print >> impl, """void %s_%s_set(%s *%s, %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = %s;
}

%s *%s_%s_get(%s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return %s->%s;
}
""" % (
          name.lower(), field[2].lower(), name, name.lower(), field[2], field[2].lower(),
          name.lower(),
          name.lower(), field[2].lower(), field[2].lower(),
          field[2], name.lower(), field[2].lower(), name, name.lower(),
          name.lower(),
          name.lower(), field[2].lower()
       )
    elif field[1] == 'list':
      print >> header, """void %s_%s_add(%s *%s, %s *%s);
void %s_%s_del(%s *%s, %s *%s);
%s *%s_%s_get(const %s *%s, unsigned int nth);
unsigned int %s_%s_count(const %s *%s);
Eina_List *%s_%s_list_get(const %s *%s);
void %s_%s_list_clear(%s *%s);
void %s_%s_list_set(%s *%s, Eina_List *list);""" % (
        name.lower(), field[0], name, name.lower(), field[2],
        field[2].lower(), name.lower(), field[0], name,
        name.lower(), field[2], field[2].lower(), field[2],
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower()
      )
      print >> impl, """inline void
%s_%s_add(%s *%s, %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = eina_list_append(%s->%s, %s);
}
""" % (
        name.lower(), field[0], name, name.lower(),
        field[2], field[2].lower(), name.lower(),
        name.lower(), field[0], name.lower(),
        field[0], field[2].lower()
      )

      print >> impl, """inline void
%s_%s_del(%s *%s, %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = eina_list_remove(%s->%s, %s);
}
""" % (
        name.lower(), field[0], name, name.lower(), field[2],
        field[2].lower(), name.lower(), name.lower(), field[0],
        name.lower(), field[0], field[2].lower()
      )

      print >> impl, """inline %s *
%s_%s_get(const %s *%s, unsigned int nth)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return eina_list_nth(%s->%s, nth);
}
""" % (
        field[2], name.lower(), field[0], name, name.lower(),
        name.lower(), name.lower(), field[0]
      )

      print >> impl, """inline unsigned int
%s_%s_count(const %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, 0);
    return eina_list_count(%s->%s);
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0]
      )

      print >> impl, """void
%s_%s_list_clear(%s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s *data;
    EINA_LIST_FREE(%s->%s, data) %s_free(data);
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        field[2],
        name.lower(), field[0], field[2].lower(),
      )

      print >> impl, """inline Eina_List *
%s_%s_list_get(const %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return %s->%s;
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0]
      )
      print >> impl, """inline void
%s_%s_list_set(%s *%s, Eina_List *list)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = list;
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0]
      )
    elif field[1] == 'hash':
      hashed_type = field[2]
      hashed_field = field[3]

      print >> header, """void %s_%s_add(%s *%s, %s %s, %s *%s);
void %s_%s_del(%s *%s, %s %s);
%s *%s_%s_get(const %s *%s, %s key);
Eina_Hash *%s_%s_hash_get(const %s *%s);
void %s_%s_modify(%s *%s, %s key, void *value);""" % (
        name.lower(), field[0], name, name.lower(),
        FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
        hashed_type, hashed_type.lower(), name.lower(), field[0], name,
        name.lower(), FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
        hashed_type, name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[__structs[hashed_type][hashed_field]],
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[__structs[hashed_type][hashed_field]]
      )
      print >> impl, """void
%s_%s_add(%s *%s, %s %s, %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    eina_hash_add(%s->%s, %s, %s);
}
""" % (
      name.lower(), field[0], name, name.lower(),
      FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
      hashed_type, hashed_type.lower(), name.lower(), name.lower(), field[0],
      hashed_field, hashed_type.lower()
    )

      print >> impl, """void
%s_%s_del(%s *%s, %s %s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    eina_hash_del(%s->%s, %s, NULL);
}
""" % (
      name.lower(), field[0], name, name.lower(),
      FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
      name.lower(), name.lower(), field[0], hashed_field
    )

      print >> impl, """inline %s *
%s_%s_get(const %s *%s, %s %s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return eina_hash_find(%s->%s, %s);
}
""" % (
      hashed_type, name.lower(), field[0], name, name.lower(),
      FIELD_CONVERTER[__structs[hashed_type][hashed_field]], hashed_field,
      name.lower(), name.lower(), field[0], hashed_field
    )

      print >> impl, """inline Eina_Hash *
%s_%s_hash_get(const %s *%s)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    return %s->%s;
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0]
      )

      print >> impl, """void
%s_%s_modify(%s *%s, %s key, void *value)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    eina_hash_modify(%s->%s, key, value);
}
""" % (
        name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[__structs[hashed_type][hashed_field]],
        name.lower(),
        name.lower(), field[0]
      )

    elif field[1] == 'image':
      print >> header, """void %s_%s_set(%s *%s, Evas_Object *%s);
Evas_Object *%s_%s_get(const %s *%s, Evas *evas, const char *eet_file);""" % (
        name.lower(), field[0], name, name.lower(), field[0],
        name.lower(), field[0], name, name.lower()
      )
      print >> impl, """void
%s_%s_set(%s *%s, Evas_Object *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    if (%s->%s) evas_object_del(%s->%s);
    %s->%s__id = 0;
    %s->%s = %s;
}
""" % (
        name.lower(), field[0], name, name.lower(), field[0],
        name.lower(),
        name.lower(), field[0], name.lower(), field[0],
        name.lower(), field[0],
        name.lower(), field[0], field[0]
    )
      print >> impl, """Evas_Object *
%s_%s_get(const %s *%s, Evas *evas, const char *eet_file)
{
    EINA_SAFETY_ON_NULL_RETURN_VAL(%s, NULL);
    if (%s->%s) return %s->%s;
    _load_%s_images(%s, evas, eet_file);
    return %s->%s;
}
""" % (
        name.lower(), field[0], name, name.lower(),
        name.lower(),
        name.lower(), field[0], name.lower(), field[0],
        name.lower(), name.lower(),
        name.lower(), field[0]
    )
    elif field[1] == 'enum':
      print >> header, """void %s_%s_set(%s *%s, %s %s);
%s %s_%s_get(const %s *%s);
const char * %s_%s_repr_get(const %s *%s);
const char * %s_%s_str_get(%s %s);""" % (
        name.lower(), field[0], name, name.lower(), name + '_' + field[0].title(),
        field[0], name + '_' + field[0].title(), name.lower(), field[0],
        name, name.lower(),
        name.lower(), field[0], name, name.lower(),
        name.lower(), field[0], name + '_' + field[0].title(), field[0]
      )
      print >> impl, """inline %s
%s_%s_get(const %s *%s)
{
    return %s->%s;
}
""" % (
      name + '_' + field[0].title(),
      name.lower(), field[0],
      name, name.lower(),
      name.lower(), field[0]
    )
      print >> impl, """inline const char *
%s_%s_repr_get(const %s *%s)
{
    return %s_%s_REPR[%s->%s];
}
""" % (
      name.lower(), field[0],
      name, name.lower(),
      name.upper(), field[0].upper(),
      name.lower(), field[0]
    )

      print >> impl, """inline void
%s_%s_set(%s *%s, %s %s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    if (%s >= %s_%s_LAST_VALUE) return;
    %s->%s = %s;
}
""" % (
      name.lower(), field[0], name, name.lower(),
      name + '_' + field[0].title(), field[0],
      name.lower(),
      field[0], name.upper(), field[0].upper(),
      name.lower(), field[0], field[0]
    )

      print >> impl, """inline const char *
%s_%s_str_get(%s %s)
{
    if (%s >= %s_%s_LAST_VALUE) return NULL;
    return %s_%s_REPR[%s];
}
""" % (
      name.lower(), field[0],
      name + '_' + field[0].title(), field[0],
      field[0], name.upper(), field[0].upper(),
      name.upper(), field[0].upper(), field[0]
    )
    else:
      print >> header, """void %s_%s_set(%s *%s, %s %s);
%s %s_%s_get(const %s *%s);""" % (
        name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[field[1]],
        field[0], FIELD_CONVERTER[field[1]], name.lower(), field[0], name, name.lower(),
      )

      print >> impl, """inline %s
%s_%s_get(const %s *%s)
{
    return %s->%s;
}
""" % (
      FIELD_CONVERTER[field[1]],
      name.lower(), field[0],
      name, name.lower(),
      name.lower(), field[0]
    )
      if field[1] == 'str':
        print >> impl, """inline void
%s_%s_set(%s *%s, const char *%s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    eina_stringshare_replace(&(%s->%s), %s);
}
""" % (
          name.lower(), field[0], name, name.lower(), field[0],
          name.lower(),
          name.lower(), field[0], field[0]
      )
      else:
        print >> impl, """inline void
%s_%s_set(%s *%s, %s %s)
{
    EINA_SAFETY_ON_NULL_RETURN(%s);
    %s->%s = %s;
}
""" % (
          name.lower(), field[0], name, name.lower(), FIELD_CONVERTER[field[1]], field[0],
          name.lower(),
          name.lower(), field[0], field[0]
      )

def _write_image_loaders(name, fields, impl):
  if not any(field[1] == 'image' for field in fields):
    return

  print >> impl, """static void
_load_%s_images(%s *%s, Evas *evas, const char *filename)
{
    Eet_File *ef = eet_open(filename, EET_FILE_MODE_READ);
    if (!ef)
       {
          fprintf(stderr, "ERROR: could not open '%%s' for read\\n", filename);
          return;
       }""" % (
    name.lower(), name, name.lower()
  )

  for field in (f for f in fields if f[1] == 'image'):
    print >> impl, """\n    if (%(bname)s->%(fname)s__id)
       {
          char %(fname)s_buf[256];
          unsigned int %(fname)s_w, %(fname)s_h;
          int %(fname)s_alpha, %(fname)s_compress, %(fname)s_quality, %(fname)s_lossy;
          void *%(fname)s_data;
          sprintf(%(fname)s_buf, "/image/%(perc)sd", %(bname)s->%(fname)s__id);
          %(fname)s_data = eet_data_image_read(ef, %(fname)s_buf, &%(fname)s_w, &%(fname)s_h, &%(fname)s_alpha, &%(fname)s_compress, &%(fname)s_quality, &%(fname)s_lossy);
          if (%(fname)s_data)
             {
                %(bname)s->%(fname)s = evas_object_image_add(evas);
                evas_object_image_size_set(%(bname)s->%(fname)s, %(fname)s_w, %(fname)s_h);
                evas_object_image_alpha_set(%(bname)s->%(fname)s, %(fname)s_alpha);
                evas_object_image_data_set(%(bname)s->%(fname)s, %(fname)s_data);
             }
       }""" % {
   "bname": name.lower(),
   "fname": field[0],
   "perc": "%"
 }

  print >> impl, "\n    eet_close(ef);\n}\n"

def _write_image_savers(name, fields, impl):
  if not any(field[1] == 'image' for field in fields):
    return

  print >> impl, """static int
_write_%s_images(%s *%s, Eet_File *ef, int image_id)
{""" % (
    name.lower(), name, name.lower()
  )

  for field in fields:
    if field[-1] == 'noencode':
      continue

    if field[1] == 'image':
      if field[2] == "raw":
        compress = False
        lossy = False
        quality = 100
      elif field[2] == "lossy":
        compress = True
        lossy = True
        quality = int(field[3])
      else:
        compress = True
        lossy = False
        quality = int(field[3])

      print >> impl, """    if (%(bname)s->%(fname)s)
       {
          char %(fname)s_buf[256];
          int %(fname)s_w, %(fname)s_h;
          int %(fname)s_alpha;
          void *%(fname)s_data;
          %(bname)s->%(fname)s__id = image_id;
          sprintf(%(fname)s_buf, "/image/%(perc)sd", image_id++);
          evas_object_image_size_get(%(bname)s->%(fname)s, &%(fname)s_w, &%(fname)s_h);
          %(fname)s_alpha = evas_object_image_alpha_get(%(bname)s->%(fname)s);
          %(fname)s_data = evas_object_image_data_get(%(bname)s->%(fname)s, EINA_FALSE);
          eet_data_image_write(ef, %(fname)s_buf, %(fname)s_data, %(fname)s_w, %(fname)s_h, %(fname)s_alpha, %(compress)d, %(quality)d, %(lossy)d);
       }""" % {
     "bname": name.lower(),
     "fname": field[0],
     "perc": "%",
     "lossy": lossy,
     "compress": compress,
     "quality": quality
   }

  print >> impl, """    return image_id;
}
"""

def _write_block(parsed_block, header, impl):
  print >> header, ""

  for name, fields in parsed_block:
    print >> header, """/* %s */""" % name
    _write_initializers(name, fields, header, impl)
    _write_shutdowns(name, fields, header, impl)

    _write_allocators(name, fields, header, impl)
    _write_deallocators(name, fields, header, impl)

    print >> header, ""
    _write_image_loaders(name, fields, impl)
    _write_image_savers(name, fields, impl)
    _write_getters_setters(name, fields, header, impl)

    if not any(dep[1] == name for dep in __deps):
      print >> header, ""
      _write_loaders(name, fields, header, impl)
      _write_dumpers(name, fields, header, impl)

    print >> header, ""

def _write_global_initializers(parsed_block, base_name, header, impl):
  print >> header, "/* Global initializer / shutdown functions */"
  print >> header, "void %s_init(void);" % base_name
  print >> header, "void %s_shutdown(void);" % base_name
  print >> header, ""

  print >> impl, """\nvoid
%s_init(void)
{""" % base_name
  for name, fields in parsed_block:
    print >> impl, "    _%s_init();" % name.lower()
  print >> impl, "}\n"

  print >> impl, """void
%s_shutdown(void)
{""" % base_name
  for name, fields in parsed_block:
    print >> impl, "    _%s_shutdown();" % name.lower()
  print >> impl, "}\n"

def write_output(parsed_block, base_name, dir_name):
  header = file(dir_name + base_name + '.h', 'w')
  impl = file(dir_name + base_name + '.c', 'w')

  _write_headers(header, impl)
  _write_includes(parsed_block, base_name, header, impl)
  _write_structs(parsed_block, header, impl)
  _write_reprs(parsed_block, header, impl)
  _write_entry_names(parsed_block, header, impl)
  _write_descriptors(parsed_block, header, impl)
  _write_block(parsed_block, header, impl)
  _write_global_initializers(parsed_block, base_name, header, impl)

  print >> header, """#endif /* __%s_H__ */""" % base_name.upper()

  header.close()
  impl.close()

if __name__ == '__main__':
  if len(sys.argv) < 2:
    print 'Usage: %s file.geneet' % sys.argv[0]
  else:
    dir_name = os.path.dirname(sys.argv[1])
    if dir_name:
        dir_name = dir_name + '/'
    base_name = os.path.basename('.'.join(sys.argv[1].split('.')[:-1]))

    try:
      parsed_block = block.parseFile(sys.argv[1])
    except ParseException, e:
      print 'Syntax error:', e
      sys.exit(1)

    check(base_name, parsed_block)
    write_output(parsed_block, base_name, dir_name)

