2013-04-22 19:58:06 +00:00
#!/usr/bin/env python
"""
uhub - A tiny ADC p2p connection hub
Copyright ( C ) 2007 - 2013 , Jan Vidar Krey
"""
from xml . dom import minidom , Node
from datetime import datetime
import argparse
class OptionParseError ( Exception ) :
pass
class Option ( object ) :
def _get ( self , node , name ) :
self . __dict__ [ name ] = None
if ( node . getElementsByTagName ( name ) ) :
self . __dict__ [ name ] = node . getElementsByTagName ( name ) [ 0 ] . firstChild . nodeValue
def _attr ( self , node , name , required = False ) :
try :
return node . attributes [ name ] . value
except Exception :
pass
if ( required ) :
raise OptionParseError ( " Option %s is required but not found! " % name )
return None
def __init__ ( self , node ) :
self . otype = self . _attr ( node , ' type ' , True )
# Verify that the type is known
if not self . otype in [ " int " , " boolean " , " string " , " message " , " file " ] :
raise OptionParseError ( " Option %s has unknown type " % self . name )
self . name = self . _attr ( node , ' name ' , True )
self . default = self . _attr ( node , ' default ' , True )
self . advanced = self . _attr ( node , ' advanced ' , False )
self . is_string = self . otype in [ " string " , " message " , " file " ]
self . _get ( node , " short " ) ;
self . _get ( node , " description " ) ;
self . _get ( node , " syntax " ) ;
self . _get ( node , " since " ) ;
self . _get ( node , " example " ) ;
check = node . getElementsByTagName ( " check " )
if ( check ) :
check = node . getElementsByTagName ( " check " ) [ 0 ]
self . check_min = self . _attr ( check , ' min ' , False )
self . check_max = self . _attr ( check , ' max ' , False )
self . check_regexp = self . _attr ( check , ' regexp ' , False )
else :
self . check_min = None
self . check_max = None
self . check_regexp = None
def c_type ( self ) :
if self . otype == " boolean " :
return " int "
elif self . is_string :
return " char* "
else :
return self . otype
def sql_type ( self ) :
if self . otype == " int " :
return " integer "
return self . otype
def c_comment ( self ) :
comment = " "
if ( self . otype == " message " ) :
comment = self . formatted_default ( )
elif len ( self . short ) :
comment = " %s (default: %s ) " % ( self . short , self . formatted_default ( ) )
return comment
def formatted_default ( self ) :
if self . is_string :
return " \" %s \" " % self . default
return self . default
class SourceGenerator ( object ) :
def __init__ ( self , filename , cppStyle = True ) :
2013-10-03 02:13:00 +00:00
print ( " Generating %s ... " % filename )
2013-04-22 19:58:06 +00:00
self . f = open ( filename , ' w ' ) ;
def write_header ( self , Comment = True ) :
if Comment :
s = " /* \n * uhub - A tiny ADC p2p connection hub \n "
s + = " * Copyright (C) 2007- %s , Jan Vidar Krey \n * \n " % datetime . now ( ) . strftime ( " % Y " )
s + = " * THIS FILE IS AUTOGENERATED - DO NOT MODIFY \n "
s + = " * Created %s , by config.py \n */ \n \n " % datetime . now ( ) . strftime ( " % Y- % m- %d % H: % M " )
self . f . write ( s )
class CHeaderGenerator ( SourceGenerator ) :
def __init__ ( self , filename ) :
super ( CHeaderGenerator , self ) . __init__ ( filename )
def _write_declaration ( self , option ) :
comment = ' ' * ( 32 - len ( option . name ) ) + " /*<<< %s */ " % option . c_comment ( )
ptype = option . c_type ( ) + ( 5 - len ( option . c_type ( ) ) ) * ' '
self . f . write ( " \t %(type)s %(name)s ; %(comment)s \n " % {
" type " : ptype ,
" name " : option . name ,
" comment " : comment } )
def write ( self , options ) :
self . write_header ( )
self . f . write ( " struct hub_config \n { \n " )
for option in options :
self . _write_declaration ( option )
self . f . write ( " }; \n \n " )
class CSourceGenerator ( SourceGenerator ) :
def __init__ ( self , filename ) :
super ( CSourceGenerator , self ) . __init__ ( filename )
def _write_default_impl ( self , option ) :
s = " \t config-> %s = " % option . name
if option . is_string :
s + = " hub_strdup( %s ); \n " % option . formatted_default ( )
else :
s + = option . formatted_default ( ) + " ; \n "
self . f . write ( s )
def _write_apply_impl ( self , option ) :
s = " \t if (!strcmp(key, \" %s \" )) \n \t { \n " % option . name
if option . otype == " int " :
s_min = " 0 "
s_max = " 0 "
if ( option . check_min ) :
s + = " \t \t min = %s ; \n " % option . check_min
s_min = " &min "
if ( option . check_max ) :
s + = " \t \t max = %s ; \n " % option . check_max
s_max = " &max "
s + = " \t \t if (!apply_integer(key, data, &config-> %s , %s , %s )) \n " % ( option . name , s_min , s_max )
elif option . otype == " boolean " :
s + = " \t \t if (!apply_boolean(key, data, &config-> %s )) \n " % option . name
elif option . is_string :
s + = " \t \t if (!apply_string(key, data, &config-> %s , (char*) \" \" )) \n " % option . name
s + = " \t \t { \n \t \t \t LOG_ERROR( \" Configuration parse error on line %d \" , line_count); \n \t \t \t return -1; \n \t \t } \n \t \t return 0; \n \t } \n \n "
self . f . write ( s )
def _write_free_impl ( self , option ) :
if option . is_string :
self . f . write ( " \t hub_free(config-> %s ); \n \n " % option . name )
def _write_dump_impl ( self , option ) :
s = " "
fmt = " %s "
val = " config-> %s " % option . name
test = " config-> %s != %s " % ( option . name , option . default )
if ( option . otype == " int " ) :
fmt = " %d "
elif ( option . otype == " boolean " ) :
val = " config-> %s ? \" yes \" : \" no \" " % option . name
elif ( option . is_string ) :
fmt = " \\ \" %s \\ \" " ;
test = " strcmp(config-> %s , %s ) != 0 " % ( option . name , option . formatted_default ( ) )
s + = " \t if (!ignore_defaults || %s ) \n " % test ;
s + = " \t \t fprintf(stdout, \" %s = %s \\ n \" , %s ); \n \n " % ( option . name , fmt , val )
self . f . write ( s )
def write ( self , options ) :
self . write_header ( )
self . f . write ( " void config_defaults(struct hub_config* config) \n { \n " )
for option in options :
self . _write_default_impl ( option )
self . f . write ( " } \n \n " )
self . f . write ( " static int apply_config(struct hub_config* config, char* key, char* data, int line_count) \n { \n \t int max = 0; \n \t int min = 0; \n \n " )
for option in options :
self . _write_apply_impl ( option )
self . f . write ( " \t /* Still here -- unknown directive */ \n \t LOG_ERROR( \" Unknown configuration directive: ' %s ' \" , key); \n \t return -1; \n } \n \n " )
self . f . write ( " void free_config(struct hub_config* config) \n { \n " )
for option in options :
self . _write_free_impl ( option )
self . f . write ( " } \n \n " )
self . f . write ( " void dump_config(struct hub_config* config, int ignore_defaults) \n { \n " )
for option in options :
self . _write_dump_impl ( option )
self . f . write ( " } \n \n " )
class SqlWebsiteDocsGenerator ( SourceGenerator ) :
def __init__ ( self , filename , sqlite_support = False ) :
self . sqlite_support = sqlite_support
super ( SqlWebsiteDocsGenerator , self ) . __init__ ( filename )
def _sql_escape ( self , s ) :
if self . sqlite_support :
return s . replace ( " \" " , " \" \" " )
return s . replace ( " \" " , " \\ \" " )
def _write_or_null ( self , s ) :
if ( not s or len ( s ) == 0 ) :
return " NULL "
return " \" %s \" " % self . _sql_escape ( s )
def write ( self , options ) :
self . write_header ( False )
table = " uhub_config "
s = " "
if not self . sqlite_support :
s + = " START TRANSACTION; \n \n DROP TABLE %(table)s IF EXISTS; " % { " table " : table }
s + = " \n \n CREATE TABLE %(table)s ( \n \t name VARCHAR(32) UNIQUE NOT NULL, \n \t defaultValue TINYTEXT NOT NULL, \n \t description LONGTEXT NOT NULL, \n \t type TINYTEXT NOT NULL, \n \t advanced BOOLEAN, \n \t example LONGTEXT, \n \t since TINYTEXT \n ); \n \n " % { " table " : table }
self . f . write ( s )
for option in options :
s = " INSERT INTO %(table)s VALUES( \" %(name)s \" , \" %(default)s \" , \" %(description)s \" , \" %(type)s \" , %(example)s , %(since)s , %(advanced)s ); \n " % {
" table " : table ,
" name " : self . _sql_escape ( option . name ) ,
" default " : self . _sql_escape ( option . formatted_default ( ) ) ,
" description " : self . _sql_escape ( option . description ) ,
" type " : option . sql_type ( ) ,
" example " : self . _write_or_null ( option . example ) ,
" since " : self . _write_or_null ( option . since ) ,
" advanced " : self . _write_or_null ( option . example ) ,
}
self . f . write ( s )
if not self . sqlite_support :
self . f . write ( " \n \n COMMIT; \n \n " )
if __name__ == " __main__ " :
# parser = argparse.ArgumentParser(description = "Configuration file parser and source generator")
# parser.add_argument("--in", nargs=1, type=argparse.FileType('r'), default="config.xml", help="Input file (config.xml)", required = True)
# parser.add_argument("--c-decl", nargs=1, type=argparse.FileType('w'), default="gen_config.h", help="Output file for C declarations (gen_config.h)")
# parser.add_argument("--c-impl", nargs=1, type=argparse.FileType('w'), default="gen_config.c", help="Output file for C implementation (gen_config.c)")
# parser.add_argument("--doc-sql", nargs=1, type=argparse.FileType('w'), help="Output file for SQL documentation")
# args = parser.parse_args()
xmldoc = minidom . parse ( " ./config.xml " )
opt_tags = xmldoc . getElementsByTagName ( ' option ' )
options = [ ]
for option in opt_tags :
opt = Option ( option )
options . append ( opt )
header = CHeaderGenerator ( " ./gen_config.h " ) ;
header . write ( options ) ;
source = CSourceGenerator ( " ./gen_config.c " ) ;
source . write ( options ) ;
#sql = SqlWebsiteDocsGenerator("./gen_config.sql", True);
#sql.write(options);