* src/tools/apinames.c: adding new tool to extract public API
function names from header files
This commit is contained in:
parent
d7e08f7745
commit
6c5299e44f
21
Jamfile
21
Jamfile
@ -148,6 +148,27 @@ HDRMACRO [ FT2_SubDir include freetype internal internal.h ] ;
|
||||
#
|
||||
SubInclude FT2_TOP $(FT2_SRC_DIR) ;
|
||||
|
||||
# handle the generation of the "ftexport.sym" file which contain the list
|
||||
# of exported symbols. This can be used on Unix by libtool
|
||||
#
|
||||
SubInclude FT2_TOP $(FT2_SRC_DIR) tools ;
|
||||
|
||||
rule GenExportSymbols
|
||||
{
|
||||
local headers = [ Glob $(2) : *.h ] ;
|
||||
|
||||
APINAMES on $(1) = apinames$(SUFEXE) ;
|
||||
|
||||
Depends $(1) : $(headers) ;
|
||||
GenExportSymbols1 $(1) : $(headers) ;
|
||||
}
|
||||
|
||||
actions GenExportSymbols1 bind APINAMES
|
||||
{
|
||||
$(APINAMES) $(2) > $(1)
|
||||
}
|
||||
|
||||
GenExportSymbols ftexport.sym : include/freetype include/freetype/cache ;
|
||||
|
||||
# Test files (hinter debugging). Only used by FreeType developers.
|
||||
#
|
||||
|
319
src/tools/apinames.c
Normal file
319
src/tools/apinames.c
Normal file
@ -0,0 +1,319 @@
|
||||
/* this little program is used to parse the FreeType headers and
|
||||
* find the declaration of all public API. This is easy, because
|
||||
* they all look like the following:
|
||||
*
|
||||
* FT_EXPORT( return_type )
|
||||
* function_name( function arguments );
|
||||
*
|
||||
* you must pass it the list of header files as arguments, wildcards
|
||||
* accepted if you're using GCC on Windows
|
||||
*
|
||||
* Author: David Turner
|
||||
*
|
||||
* This code is explicitely placed in the public domain
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define PROGRAM_NAME "apinames"
|
||||
#define PROGRAM_VERSION "0.1"
|
||||
|
||||
#define LINEBUFF_SIZE 1024
|
||||
|
||||
static void
|
||||
panic( const char* message )
|
||||
{
|
||||
fprintf( stderr, "PANIC: %s\n", message );
|
||||
exit(2);
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
unsigned int hash;
|
||||
|
||||
} NameRec, *Name;
|
||||
|
||||
static Name the_names;
|
||||
static int num_names;
|
||||
static int max_names;
|
||||
|
||||
static void
|
||||
names_add( const char* name,
|
||||
const char* end )
|
||||
{
|
||||
int nn, len, h;
|
||||
Name nm;
|
||||
|
||||
if ( end <= name )
|
||||
return;
|
||||
|
||||
/* compute hash value */
|
||||
len = (int)(end - name);
|
||||
h = 0;
|
||||
for ( nn = 0; nn < len; nn++ )
|
||||
h = h*33 + name[nn];
|
||||
|
||||
/* check for an pre-existing name */
|
||||
for ( nn = 0; nn < num_names; nn++ )
|
||||
{
|
||||
nm = the_names + nn;
|
||||
|
||||
if ( nm->hash == h &&
|
||||
memcmp( name, nm->name, len ) == 0 &&
|
||||
nm->name[len] == 0 )
|
||||
return;
|
||||
}
|
||||
|
||||
/* add new name */
|
||||
if ( num_names >= max_names )
|
||||
{
|
||||
max_names += (max_names >> 1) + 4;
|
||||
the_names = realloc( the_names, sizeof(the_names[0])*max_names );
|
||||
if ( the_names == NULL )
|
||||
panic( "not enough memory" );
|
||||
}
|
||||
nm = &the_names[num_names++];
|
||||
|
||||
nm->hash = h;
|
||||
nm->name = malloc( len+1 );
|
||||
if ( nm->name == NULL )
|
||||
panic( "not enough memory" );
|
||||
|
||||
memcpy( nm->name, name, len );
|
||||
nm->name[len] = 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
name_compare( const void* name1,
|
||||
const void* name2 )
|
||||
{
|
||||
Name n1 = (Name)name1;
|
||||
Name n2 = (Name)name2;
|
||||
|
||||
return strcmp( n1->name, n2->name );
|
||||
}
|
||||
|
||||
static void
|
||||
names_sort( void )
|
||||
{
|
||||
qsort( the_names, (size_t)num_names, sizeof(the_names[0]), name_compare );
|
||||
}
|
||||
|
||||
static void
|
||||
names_dump( FILE* out )
|
||||
{
|
||||
int nn;
|
||||
|
||||
for ( nn = 0; nn < num_names; nn++ )
|
||||
fprintf( out, "%s\n", the_names[nn].name );
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
names_dump_windef( FILE* out )
|
||||
{
|
||||
int nn;
|
||||
|
||||
/* note that we assume that __cdecl was used when compiling the
|
||||
* DLL object files.
|
||||
*/
|
||||
fprintf( out, "DESCRIPTION FreeType 2 DLL\n" );
|
||||
fprintf( out, "EXPORTS\n" );
|
||||
for ( nn = 0; nn < num_names; nn++ )
|
||||
fprintf( out, " %s\n", the_names[nn].name );
|
||||
}
|
||||
|
||||
|
||||
/* states of the line parser */
|
||||
|
||||
typedef enum
|
||||
{
|
||||
STATE_START = 0, /* waiting for FT_EXPORT keyword and return type */
|
||||
STATE_TYPE, /* type was read, waiting for function name */
|
||||
|
||||
} State;
|
||||
|
||||
static int
|
||||
read_header_file( FILE* file, int verbose )
|
||||
{
|
||||
static char buff[ LINEBUFF_SIZE+1 ];
|
||||
State state = STATE_START;
|
||||
|
||||
while ( !feof( file ) )
|
||||
{
|
||||
char* p;
|
||||
|
||||
if ( !fgets( buff, LINEBUFF_SIZE, file ) )
|
||||
break;
|
||||
|
||||
p = buff;
|
||||
|
||||
while ( *p && (*p == ' ' || *p == '\\') ) /* skip leading whitespace */
|
||||
p++;
|
||||
|
||||
if ( *p == '\n' || *p == '\r' ) /* skip empty lines */
|
||||
continue;
|
||||
|
||||
switch ( state )
|
||||
{
|
||||
case STATE_START:
|
||||
{
|
||||
if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 )
|
||||
break;
|
||||
|
||||
p += 10;
|
||||
for (;;)
|
||||
{
|
||||
if ( *p == 0 || *p == '\n' || *p == '\r' )
|
||||
goto NextLine;
|
||||
|
||||
if ( *p == ')' )
|
||||
{
|
||||
p++;
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
state = STATE_TYPE;
|
||||
|
||||
/* sometimes, the name is just after the FT_EXPORT(...), so
|
||||
* skip whitespace, and fall-through if we find an alphanumeric
|
||||
* character
|
||||
*/
|
||||
while ( *p == ' ' || *p == '\t' )
|
||||
p++;
|
||||
|
||||
if ( !isalpha(*p) )
|
||||
break;
|
||||
}
|
||||
/* fall-through */
|
||||
|
||||
case STATE_TYPE:
|
||||
{
|
||||
char* name = p;
|
||||
size_t func_len;
|
||||
|
||||
while ( isalpha(*p) || *p == '_' )
|
||||
p++;
|
||||
|
||||
if ( p > name )
|
||||
{
|
||||
if ( verbose )
|
||||
fprintf( stderr, ">>> %.*s\n", p-name, name );
|
||||
|
||||
names_add( name, p );
|
||||
}
|
||||
|
||||
state = STATE_START;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
NextLine:
|
||||
;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
usage( void )
|
||||
{
|
||||
fprintf( stderr,
|
||||
"%s %s: extract FreeType API names from header files\n\n"
|
||||
"this program is used to extract the list of public FreeType API\n"
|
||||
"functions. It receives the list of header files as argument and\n"
|
||||
"generates a sorted list of unique identifiers\n\n"
|
||||
|
||||
"usage: %s header1 [options] [header2 ...]\n\n"
|
||||
|
||||
"options: - : parse the content of stdin, ignore arguments\n"
|
||||
" -v : verbose mode\n",
|
||||
" -w : output windows .DEF file\n"
|
||||
,
|
||||
PROGRAM_NAME,
|
||||
PROGRAM_VERSION,
|
||||
PROGRAM_NAME
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, const char* const* argv )
|
||||
{
|
||||
int from_stdin = 0;
|
||||
int verbose = 0;
|
||||
int do_win_def = 0;
|
||||
|
||||
if ( argc < 2 )
|
||||
usage();
|
||||
|
||||
/* '-' used as a single argument means read source file from stdin */
|
||||
while ( argc > 1 && argv[1][0] == '-' )
|
||||
{
|
||||
switch ( argv[1][1] )
|
||||
{
|
||||
case 'v':
|
||||
verbose = 1;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
do_win_def = 1;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
from_stdin = 1;
|
||||
break;
|
||||
|
||||
default:
|
||||
usage();
|
||||
}
|
||||
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if ( from_stdin )
|
||||
{
|
||||
read_header_file( stdin, verbose );
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( --argc, argv++; argc > 0; argc--, argv++ )
|
||||
{
|
||||
FILE* file = fopen( argv[0], "rb" );
|
||||
|
||||
if ( file == NULL )
|
||||
fprintf( stderr, "unable to open '%s'\n", argv[0] );
|
||||
else
|
||||
{
|
||||
if ( verbose )
|
||||
fprintf( stderr, "opening '%s'\n", argv[0] );
|
||||
|
||||
read_header_file( file, verbose );
|
||||
fclose( file );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( num_names == 0 )
|
||||
panic( "could not find exported functions !!\n" );
|
||||
|
||||
names_sort();
|
||||
|
||||
if ( do_win_def )
|
||||
names_dump_windef( stdout );
|
||||
else
|
||||
names_dump( stdout );
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user