2004-11-02 17:52:23 +03:00
#!/usr/bin/python -u
#
# generate a tester program for the API
#
import sys
2004-11-04 20:34:35 +03:00
import os
2004-11-02 17:52:23 +03:00
import string
try :
import libxml2
except :
print " libxml2 python bindings not available, skipping testapi.c generation "
sys . exit ( 0 )
#
# Modules we don't want skip in API test
#
skipped_modules = [ " SAX " , " SAX2 " , " xlink " , " threads " , " globals " ,
2004-11-05 17:30:41 +03:00
" xpathInternals " , " parserInternals " , " xmlmemory " ,
2004-11-04 02:25:47 +03:00
" xmlversion " , " debugXML " , " xmlexports " , " DOCBparser " ,
2004-11-03 20:07:05 +03:00
# temporary
2004-11-04 13:49:00 +03:00
" xmlautomata " , " xmlregexp " , " c14n " ,
2004-11-03 20:07:05 +03:00
]
2004-11-02 17:52:23 +03:00
#
# Some function really need to be skipped for the tests.
#
2004-11-03 17:20:29 +03:00
skipped_functions = [
# block on I/O
" xmlFdRead " , " xmlReadFd " , " xmlCtxtReadFd " ,
" htmlFdRead " , " htmlReadFd " , " htmlCtxtReadFd " ,
2004-11-04 15:32:18 +03:00
" xmlReaderNewFd " , " xmlReaderForFd " ,
2004-11-04 02:25:47 +03:00
" xmlIORead " , " xmlReadIO " , " xmlCtxtReadIO " ,
" htmlIORead " , " htmlReadIO " , " htmlCtxtReadIO " ,
2004-11-05 14:50:11 +03:00
" xmlReaderNewIO " , " xmlBufferDump " , " xmlNanoFTPConnect " ,
" xmlNanoFTPConnectTo " ,
2004-11-03 17:20:29 +03:00
# library state cleanup, generate false leak informations and other
# troubles, heavillyb tested otherwise.
2004-11-05 13:03:46 +03:00
" xmlCleanupParser " , " xmlRelaxNGCleanupTypes " , " xmlSetListDoc " ,
" xmlSetTreeDoc " , " xmlUnlinkNode " ,
2004-11-03 17:20:29 +03:00
# hard to avoid leaks in the tests
2004-11-04 02:25:47 +03:00
" xmlStrcat " , " xmlStrncat " , " xmlCatalogAddLocal " ,
2004-11-03 17:20:29 +03:00
# unimplemented
" xmlTextReaderReadInnerXml " , " xmlTextReaderReadOuterXml " ,
2004-11-03 20:07:05 +03:00
" xmlTextReaderReadString " ,
# destructor
2004-11-05 14:50:11 +03:00
" xmlListDelete " , " xmlOutputBufferClose " , " xmlNanoFTPClose " ,
2004-11-03 20:07:05 +03:00
# deprecated
" xmlCatalogGetPublic " , " xmlCatalogGetSystem " , " xmlEncodeEntities " ,
2004-11-04 02:25:47 +03:00
# allocators
" xmlMemFree " ,
2004-11-03 17:20:29 +03:00
]
2004-11-02 17:52:23 +03:00
#
# Those functions have side effect on the global state
# and hence generate errors on memory allocation tests
#
skipped_memcheck = [ " xmlLoadCatalog " , " xmlAddEncodingAlias " ,
" xmlSchemaInitTypes " , " xmlNanoFTPProxy " , " xmlNanoFTPScanProxy " ,
" xmlNanoHTTPScanProxy " , " xmlResetLastError " , " xmlCatalogConvert " ,
" xmlCatalogRemove " , " xmlLoadCatalogs " , " xmlCleanupCharEncodingHandlers " ,
2004-11-02 21:45:30 +03:00
" xmlInitCharEncodingHandlers " , " xmlCatalogCleanup " ,
" htmlParseFile " # loads the catalogs
]
#
# Extra code needed for some test cases
#
2004-11-04 20:34:35 +03:00
extra_pre_call = {
" xmlSAXUserParseFile " :
2004-11-05 13:03:46 +03:00
" if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; " ,
2004-11-04 20:34:35 +03:00
" xmlSAXUserParseMemory " :
2004-11-05 13:03:46 +03:00
" if (sax == (xmlSAXHandlerPtr)&xmlDefaultSAXHandler) user_data = NULL; " ,
2004-11-04 20:34:35 +03:00
}
2004-11-02 21:45:30 +03:00
extra_post_call = {
" xmlAddChild " :
" if (ret_val == NULL) { xmlFreeNode(cur) ; cur = NULL ; } " ,
" xmlAddChildList " :
" if (ret_val == NULL) { xmlFreeNodeList(cur) ; cur = NULL ; } " ,
" xmlAddSibling " :
" if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; } " ,
" xmlAddNextSibling " :
" if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; } " ,
" xmlAddPrevSibling " :
" if (ret_val == NULL) { xmlFreeNode(elem) ; elem = NULL ; } " ,
" xmlDocSetRootElement " :
" if (doc == NULL) { xmlFreeNode(root) ; root = NULL ; } " ,
" xmlReplaceNode " :
2004-11-05 13:03:46 +03:00
""" if (cur != NULL) {
xmlUnlinkNode ( cur ) ;
xmlFreeNode ( cur ) ; cur = NULL ; }
if ( old != NULL ) {
xmlUnlinkNode ( old ) ;
xmlFreeNode ( old ) ; old = NULL ; }
ret_val = NULL ; """ ,
2004-11-02 21:45:30 +03:00
" xmlTextMerge " :
""" if ((first != NULL) && (first->type != XML_TEXT_NODE)) {
2004-11-05 13:03:46 +03:00
xmlUnlinkNode ( second ) ;
2004-11-02 21:45:30 +03:00
xmlFreeNode ( second ) ; second = NULL ; } """ ,
2004-11-03 01:10:16 +03:00
" xmlBuildQName " :
""" if ((ret_val != NULL) && (ret_val != ncname) &&
( ret_val != prefix ) & & ( ret_val != memory ) )
xmlFree ( ret_val ) ;
ret_val = NULL ; """ ,
2004-11-04 15:32:18 +03:00
" xmlDictReference " : " xmlDictFree(dict); " ,
2004-11-04 13:49:00 +03:00
# Functions which deallocates one of their parameters
" xmlXPathConvertBoolean " : """ val = NULL; """ ,
" xmlXPathConvertNumber " : """ val = NULL; """ ,
" xmlXPathConvertString " : """ val = NULL; """ ,
" xmlSaveFileTo " : """ buf = NULL; """ ,
2004-11-04 20:34:35 +03:00
" xmlSaveFormatFileTo " : """ buf = NULL; """ ,
" xmlIOParseDTD " : " input = NULL; " ,
2004-11-05 13:03:46 +03:00
" xmlRemoveProp " : " cur = NULL; " ,
2004-11-02 21:45:30 +03:00
}
2004-11-02 17:52:23 +03:00
modules = [ ]
def is_skipped_module ( name ) :
for mod in skipped_modules :
if mod == name :
return 1
return 0
def is_skipped_function ( name ) :
for fun in skipped_functions :
if fun == name :
return 1
# Do not test destructors
if string . find ( name , ' Free ' ) != - 1 :
return 1
return 0
def is_skipped_memcheck ( name ) :
for fun in skipped_memcheck :
if fun == name :
return 1
return 0
missing_types = { }
def add_missing_type ( name , func ) :
try :
list = missing_types [ name ]
list . append ( func )
except :
missing_types [ name ] = [ func ]
2004-11-04 20:34:35 +03:00
missing_functions = { }
2004-11-05 17:30:41 +03:00
missing_functions_nr = 0
2004-11-04 20:34:35 +03:00
def add_missing_functions ( name , module ) :
2004-11-05 17:30:41 +03:00
global missing_functions_nr
missing_functions_nr = missing_functions_nr + 1
2004-11-04 20:34:35 +03:00
try :
list = missing_functions [ module ]
list . append ( name )
except :
missing_functions [ module ] = [ name ]
2004-11-02 17:52:23 +03:00
#
# Provide the type generators and destructors for the parameters
#
2004-11-02 21:45:30 +03:00
def type_convert ( str , name , info , module , function , pos ) :
2004-11-02 17:52:23 +03:00
res = string . replace ( str , " * " , " _ptr " )
res = string . replace ( res , " " , " _ " )
2004-11-02 21:45:30 +03:00
res = string . replace ( res , " htmlNode " , " xmlNode " )
res = string . replace ( res , " htmlDoc " , " xmlDoc " )
res = string . replace ( res , " htmlParser " , " xmlParser " )
2004-11-02 17:52:23 +03:00
if res == ' const_char_ptr ' :
if string . find ( name , " file " ) != - 1 or \
string . find ( name , " uri " ) != - 1 or \
string . find ( name , " URI " ) != - 1 or \
string . find ( info , " filename " ) != - 1 or \
string . find ( info , " URI " ) != - 1 or \
string . find ( info , " URL " ) != - 1 :
if string . find ( function , " Save " ) != - 1 :
return ( ' fileoutput ' )
return ( ' filepath ' )
if res == ' void_ptr ' :
if module == ' nanoftp ' and name == ' ctx ' :
return ( ' xmlNanoFTPCtxtPtr ' )
2004-11-04 02:25:47 +03:00
if function == ' xmlNanoFTPNewCtxt ' :
return ( ' xmlNanoFTPCtxtPtr ' )
2004-11-02 17:52:23 +03:00
if module == ' nanohttp ' and name == ' ctx ' :
return ( ' xmlNanoHTTPCtxtPtr ' )
2004-11-04 02:25:47 +03:00
if function == ' xmlIOHTTPOpenW ' :
return ( ' xmlNanoHTTPCtxtPtr ' )
2004-11-03 01:10:16 +03:00
if string . find ( name , " data " ) != - 1 :
return ( ' userdata ' ) ;
2004-11-03 20:07:05 +03:00
if string . find ( name , " user " ) != - 1 :
return ( ' userdata ' ) ;
2004-11-04 13:49:00 +03:00
if res == ' xmlDoc_ptr ' :
res = ' xmlDocPtr ' ;
if res == ' xmlNode_ptr ' :
res = ' xmlNodePtr ' ;
if res == ' xmlDict_ptr ' :
res = ' xmlDictPtr ' ;
2004-11-02 21:45:30 +03:00
if res == ' xmlNodePtr ' and pos != 0 :
if ( function == ' xmlAddChild ' and pos == 2 ) or \
( function == ' xmlAddChildList ' and pos == 2 ) or \
( function == ' xmlAddNextSibling ' and pos == 2 ) or \
( function == ' xmlAddSibling ' and pos == 2 ) or \
( function == ' xmlDocSetRootElement ' and pos == 2 ) or \
( function == ' xmlReplaceNode ' and pos == 2 ) or \
( function == ' xmlTextMerge ' ) or \
( function == ' xmlAddPrevSibling ' and pos == 2 ) :
return ( ' xmlNodePtr_in ' ) ;
2004-11-04 20:34:35 +03:00
if res == ' const xmlBufferPtr ' :
res = ' xmlBufferPtr ' ;
2004-11-05 14:50:11 +03:00
if res == ' xmlChar_ptr ' and name == ' name ' and \
string . find ( function , " EatName " ) != - 1 :
return ( ' eaten_name ' )
2004-11-02 17:52:23 +03:00
return res
2004-11-04 20:34:35 +03:00
known_param_types = [ ]
2004-11-02 17:52:23 +03:00
def is_known_param_type ( name ) :
for type in known_param_types :
if type == name :
return 1
return 0
2004-11-04 20:34:35 +03:00
#
# Provide the type destructors for the return values
#
2004-11-03 14:50:29 +03:00
2004-11-04 20:34:35 +03:00
known_return_types = [ ]
2004-11-03 17:20:29 +03:00
2004-11-04 20:34:35 +03:00
def is_known_return_type ( name ) :
for type in known_return_types :
if type == name :
return 1
return 0
2004-11-03 20:07:05 +03:00
2004-11-04 20:34:35 +03:00
#
# Copy the beginning of the C test program result
#
2004-11-03 20:07:05 +03:00
2004-11-04 20:34:35 +03:00
input = open ( " testapi.c " , " r " )
test = open ( ' testapi.c.new ' , ' w ' )
2004-11-03 20:07:05 +03:00
2004-11-04 20:34:35 +03:00
def compare_and_save ( ) :
global test
2004-11-03 20:07:05 +03:00
2004-11-04 20:34:35 +03:00
test . close ( )
input = open ( " testapi.c " , " r " ) . read ( )
test = open ( ' testapi.c.new ' , " r " ) . read ( )
if input != test :
os . system ( " rm testapi.c ; mv testapi.c.new testapi.c " )
print ( " Updated testapi.c " )
else :
print ( " Generated testapi.c is identical " )
line = input . readline ( )
while line != " " :
if line == " /* CUT HERE: everything below that line is generated */ \n " :
break ;
if line [ 0 : 15 ] == " #define gen_nb_ " :
type = string . split ( line [ 15 : ] ) [ 0 ]
known_param_types . append ( type )
if line [ 0 : 19 ] == " static void desret_ " :
type = string . split ( line [ 19 : ] , ' ( ' ) [ 0 ]
known_return_types . append ( type )
test . write ( line )
line = input . readline ( )
input . close ( )
if line == " " :
print " Could not find the CUT marker in testapi.c skipping generation "
test . close ( )
sys . exit ( 0 )
2004-11-03 20:07:05 +03:00
2004-11-04 20:34:35 +03:00
print ( " Scanned testapi.c: found %d parameters types and %d return types \n " % (
len ( known_param_types ) , len ( known_return_types ) ) )
test . write ( " /* CUT HERE: everything below that line is generated */ \n " )
2004-11-04 13:49:00 +03:00
2004-11-02 17:52:23 +03:00
#
2004-11-04 20:34:35 +03:00
# Open the input API description
2004-11-02 17:52:23 +03:00
#
2004-11-04 20:34:35 +03:00
doc = libxml2 . readFile ( ' doc/libxml2-api.xml ' , None , 0 )
if doc == None :
print " Failed to load doc/libxml2-api.xml "
sys . exit ( 1 )
ctxt = doc . xpathNewContext ( )
headers = ctxt . xpathEval ( " /api/files/file " )
2004-11-02 17:52:23 +03:00
2004-11-04 20:34:35 +03:00
#
# Load the interfaces
#
for file in headers :
name = file . xpathEval ( ' string(@name) ' )
if ( name == None ) or ( name == ' ' ) :
continue
2004-11-02 17:52:23 +03:00
2004-11-04 20:34:35 +03:00
#
# Some module may be skipped because they don't really consists
# of user callable APIs
#
if is_skipped_module ( name ) :
continue
2004-11-02 17:52:23 +03:00
2004-11-04 20:34:35 +03:00
#
# do not test deprecated APIs
#
desc = file . xpathEval ( ' string(description) ' )
if string . find ( desc , ' DEPRECATED ' ) != - 1 :
print " Skipping deprecated interface %s " % name
continue ;
test . write ( " #include <libxml/ %s .h> \n " % name )
modules . append ( name )
#
# Generate the callers signatures
#
for module in modules :
test . write ( " static int test_ %s (void); \n " % module ) ;
2004-11-02 17:52:23 +03:00
#
# Generate the top caller
#
test . write ( """
/ * *
* testlibxml2 :
*
* Main entry point of the tester for the full libxml2 module ,
* it calls all the tester entry point for each module .
*
* Returns the number of error found
* /
static int
testlibxml2 ( void )
{
int ret = 0 ;
""" )
for module in modules :
test . write ( " ret += test_ %s (); \n " % module )
test . write ( """
2004-11-04 13:49:00 +03:00
printf ( " Total: %d functions, %d tests, %d errors \\ n " ,
function_tests , call_tests , ret ) ;
2004-11-02 17:52:23 +03:00
return ( ret ) ;
}
""" )
#
# How to handle a function
#
nb_tests = 0
def generate_test ( module , node ) :
global test
global nb_tests
nb_cond = 0
no_gen = 0
name = node . xpathEval ( ' string(@name) ' )
if is_skipped_function ( name ) :
return
#
# check we know how to handle the args and return values
# and store the informations for the generation
#
try :
args = node . xpathEval ( " arg " )
except :
args = [ ]
t_args = [ ]
2004-11-02 21:45:30 +03:00
n = 0
2004-11-02 17:52:23 +03:00
for arg in args :
2004-11-02 21:45:30 +03:00
n = n + 1
2004-11-02 17:52:23 +03:00
rtype = arg . xpathEval ( " string(@type) " )
if rtype == ' void ' :
break ;
info = arg . xpathEval ( " string(@info) " )
nam = arg . xpathEval ( " string(@name) " )
2004-11-02 21:45:30 +03:00
type = type_convert ( rtype , nam , info , module , name , n )
2004-11-02 17:52:23 +03:00
if is_known_param_type ( type ) == 0 :
add_missing_type ( type , name ) ;
no_gen = 1
t_args . append ( ( nam , type , rtype , info ) )
try :
rets = node . xpathEval ( " return " )
except :
rets = [ ]
t_ret = None
for ret in rets :
rtype = ret . xpathEval ( " string(@type) " )
info = ret . xpathEval ( " string(@info) " )
2004-11-02 21:45:30 +03:00
type = type_convert ( rtype , ' return ' , info , module , name , 0 )
2004-11-02 17:52:23 +03:00
if rtype == ' void ' :
break
if is_known_return_type ( type ) == 0 :
add_missing_type ( type , name ) ;
no_gen = 1
t_ret = ( type , rtype , info )
break
2004-11-05 17:30:41 +03:00
test . write ( """
static int
test_ % s ( void ) {
int ret = 0 ;
""" % (name))
2004-11-02 17:52:23 +03:00
if no_gen == 1 :
2004-11-04 20:34:35 +03:00
add_missing_functions ( name , module )
2004-11-02 17:52:23 +03:00
test . write ( """
/ * missing type support * /
return ( ret ) ;
}
""" )
return
try :
conds = node . xpathEval ( " cond " )
for cond in conds :
test . write ( " #ifdef %s \n " % ( cond . get_content ( ) ) )
nb_cond = nb_cond + 1
except :
pass
# Declare the memory usage counter
no_mem = is_skipped_memcheck ( name )
if no_mem == 0 :
test . write ( " int mem_base; \n " ) ;
# Declare the return value
if t_ret != None :
test . write ( " %s ret_val; \n " % ( t_ret [ 1 ] ) )
# Declare the arguments
for arg in t_args :
( nam , type , rtype , info ) = arg ;
# add declaration
test . write ( " %s %s ; /* %s */ \n " % ( rtype , nam , info ) )
test . write ( " int n_ %s ; \n " % ( nam ) )
test . write ( " \n " )
# Cascade loop on of each argument list of values
for arg in t_args :
( nam , type , rtype , info ) = arg ;
#
test . write ( " for (n_ %s = 0;n_ %s < gen_nb_ %s ;n_ %s ++) { \n " % (
nam , nam , type , nam ) )
# log the memory usage
if no_mem == 0 :
test . write ( " mem_base = xmlMemBlocks(); \n " ) ;
# prepare the call
2004-11-04 13:49:00 +03:00
i = 0 ;
2004-11-02 17:52:23 +03:00
for arg in t_args :
( nam , type , rtype , info ) = arg ;
#
2004-11-04 13:49:00 +03:00
test . write ( " %s = gen_ %s (n_ %s , %d ); \n " % ( nam , type , nam , i ) )
i = i + 1 ;
2004-11-02 17:52:23 +03:00
# do the call, and clanup the result
2004-11-04 20:34:35 +03:00
if extra_pre_call . has_key ( name ) :
test . write ( " %s \n " % ( extra_pre_call [ name ] ) )
2004-11-02 17:52:23 +03:00
if t_ret != None :
test . write ( " \n ret_val = %s ( " % ( name ) )
need = 0
for arg in t_args :
( nam , type , rtype , info ) = arg
if need :
test . write ( " , " )
else :
need = 1
test . write ( " %s " % nam ) ;
2004-11-03 01:10:16 +03:00
test . write ( " ); \n " )
if extra_post_call . has_key ( name ) :
test . write ( " %s \n " % ( extra_post_call [ name ] ) )
test . write ( " desret_ %s (ret_val); \n " % t_ret [ 0 ] )
2004-11-02 17:52:23 +03:00
else :
test . write ( " \n %s ( " % ( name ) ) ;
need = 0 ;
for arg in t_args :
( nam , type , rtype , info ) = arg ;
if need :
test . write ( " , " )
else :
need = 1
test . write ( " %s " % nam )
test . write ( " ); \n " )
2004-11-03 01:10:16 +03:00
if extra_post_call . has_key ( name ) :
test . write ( " %s \n " % ( extra_post_call [ name ] ) )
2004-11-02 17:52:23 +03:00
2004-11-03 01:10:16 +03:00
test . write ( " call_tests++; \n " ) ;
2004-11-02 21:45:30 +03:00
2004-11-02 17:52:23 +03:00
# Free the arguments
2004-11-04 13:49:00 +03:00
i = 0 ;
2004-11-02 17:52:23 +03:00
for arg in t_args :
( nam , type , rtype , info ) = arg ;
#
2004-11-04 13:49:00 +03:00
test . write ( " des_ %s (n_ %s , %s , %d ); \n " % ( type , nam , nam , i ) )
i = i + 1 ;
2004-11-02 17:52:23 +03:00
test . write ( " xmlResetLastError(); \n " ) ;
# Check the memory usage
if no_mem == 0 :
test . write ( """ if (mem_base != xmlMemBlocks()) {
2004-11-02 21:45:30 +03:00
printf ( " Leak of %% d blocks found in %s " ,
2004-11-02 17:52:23 +03:00
xmlMemBlocks ( ) - mem_base ) ;
ret + + ;
""" % (name));
2004-11-02 21:45:30 +03:00
for arg in t_args :
( nam , type , rtype , info ) = arg ;
test . write ( """ printf( " %% d " , n_ %s ); \n """ % ( nam ) )
test . write ( """ printf( " \\ n " ); \n """ )
test . write ( " } \n " )
2004-11-02 17:52:23 +03:00
for arg in t_args :
test . write ( " } \n " )
#
# end of conditional
#
while nb_cond > 0 :
test . write ( " #endif \n " )
nb_cond = nb_cond - 1
nb_tests = nb_tests + 1 ;
test . write ( """
2004-11-04 13:49:00 +03:00
function_tests + + ;
2004-11-02 17:52:23 +03:00
return ( ret ) ;
}
""" )
#
# Generate all module callers
#
for module in modules :
# gather all the functions exported by that module
try :
functions = ctxt . xpathEval ( " /api/symbols/function[@file= ' %s ' ] " % ( module ) )
except :
print " Failed to gather functions from module %s " % ( module )
continue ;
# iterate over all functions in the module generating the test
2004-11-04 15:32:18 +03:00
i = 0
nb_tests_old = nb_tests
2004-11-02 17:52:23 +03:00
for function in functions :
2004-11-04 15:32:18 +03:00
i = i + 1
2004-11-02 17:52:23 +03:00
generate_test ( module , function ) ;
# header
test . write ( """ static int
test_ % s ( void ) {
int ret = 0 ;
2004-11-04 15:32:18 +03:00
printf ( " Testing %s : %d of %d functions ... \\ n " ) ;
""" % (module, module, nb_tests - nb_tests_old, i))
2004-11-02 17:52:23 +03:00
# iterate over all functions in the module generating the call
for function in functions :
name = function . xpathEval ( ' string(@name) ' )
if is_skipped_function ( name ) :
continue
test . write ( " ret += test_ %s (); \n " % ( name ) )
# footer
test . write ( """
if ( ret != 0 )
printf ( " Module %s : %% d errors \\ n " , ret ) ;
return ( ret ) ;
}
""" % (module))
2004-11-05 13:03:46 +03:00
#
# Generate direct module caller
#
test . write ( """ static int
test_module ( const char * module ) {
""" );
for module in modules :
test . write ( """ if (!strcmp(module, " %s " )) return(test_ %s ()); \n """ % (
module , module ) )
test . write ( """ return(0);
}
""" );
2004-11-02 17:52:23 +03:00
print " Generated test for %d modules and %d functions " % ( len ( modules ) , nb_tests )
2004-11-04 15:32:18 +03:00
2004-11-04 20:34:35 +03:00
compare_and_save ( )
2004-11-04 15:32:18 +03:00
missing_list = [ ]
2004-11-02 17:52:23 +03:00
for missing in missing_types . keys ( ) :
2004-11-04 15:32:18 +03:00
if missing == ' va_list ' or missing == ' ... ' :
2004-11-04 02:25:47 +03:00
continue ;
2004-11-04 15:32:18 +03:00
2004-11-02 17:52:23 +03:00
n = len ( missing_types [ missing ] )
2004-11-04 15:32:18 +03:00
missing_list . append ( ( n , missing ) )
def compare_missing ( a , b ) :
return b [ 0 ] - a [ 0 ]
missing_list . sort ( compare_missing )
2004-11-05 17:30:41 +03:00
print " Missing support for %d functions and %d types see missing.lst " % ( missing_functions_nr , len ( missing_list ) )
2004-11-04 15:32:18 +03:00
lst = open ( " missing.lst " , " w " )
2004-11-04 20:34:35 +03:00
lst . write ( " Missing support for %d types " % ( len ( missing_list ) ) )
lst . write ( " \n " )
2004-11-04 15:32:18 +03:00
for miss in missing_list :
lst . write ( " %s : %d : " % ( miss [ 1 ] , miss [ 0 ] ) )
i = 0
for n in missing_types [ miss [ 1 ] ] :
i = i + 1
if i > 5 :
lst . write ( " ... " )
break
lst . write ( " %s " % ( n ) )
lst . write ( " \n " )
2004-11-04 20:34:35 +03:00
lst . write ( " \n " )
lst . write ( " \n " )
lst . write ( " Missing support per module " ) ;
for module in missing_functions . keys ( ) :
lst . write ( " module %s : \n %s \n " % ( module , missing_functions [ module ] ) )
2004-11-04 15:32:18 +03:00
lst . close ( )
2004-11-04 02:25:47 +03:00
2004-11-02 17:52:23 +03:00