00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <ctype.h>
00023
00024 #define PROGRAM_NAME "apinames"
00025 #define PROGRAM_VERSION "0.1"
00026
00027 #define LINEBUFF_SIZE 1024
00028
00029 typedef enum OutputFormat_
00030 {
00031 OUTPUT_LIST = 0,
00032 OUTPUT_WINDOWS_DEF,
00033 OUTPUT_BORLAND_DEF,
00034 OUTPUT_WATCOM_LBC
00035
00036 } OutputFormat;
00037
00038
00039 static void
00040 panic( const char* message )
00041 {
00042 fprintf( stderr, "PANIC: %s\n", message );
00043 exit(2);
00044 }
00045
00046
00047 typedef struct NameRec_
00048 {
00049 char* name;
00050 unsigned int hash;
00051
00052 } NameRec, *Name;
00053
00054 static Name the_names;
00055 static int num_names;
00056 static int max_names;
00057
00058 static void
00059 names_add( const char* name,
00060 const char* end )
00061 {
00062 int nn, len, h;
00063 Name nm;
00064
00065 if ( end <= name )
00066 return;
00067
00068
00069 len = (int)(end - name);
00070 h = 0;
00071 for ( nn = 0; nn < len; nn++ )
00072 h = h*33 + name[nn];
00073
00074
00075 for ( nn = 0; nn < num_names; nn++ )
00076 {
00077 nm = the_names + nn;
00078
00079 if ( (int)nm->hash == h &&
00080 memcmp( name, nm->name, len ) == 0 &&
00081 nm->name[len] == 0 )
00082 return;
00083 }
00084
00085
00086 if ( num_names >= max_names )
00087 {
00088 max_names += (max_names >> 1) + 4;
00089 the_names = (NameRec*)realloc( the_names, sizeof(the_names[0])*max_names );
00090 if ( the_names == NULL )
00091 panic( "not enough memory" );
00092 }
00093 nm = &the_names[num_names++];
00094
00095 nm->hash = h;
00096 nm->name = (char*)malloc( len+1 );
00097 if ( nm->name == NULL )
00098 panic( "not enough memory" );
00099
00100 memcpy( nm->name, name, len );
00101 nm->name[len] = 0;
00102 }
00103
00104
00105 static int
00106 name_compare( const void* name1,
00107 const void* name2 )
00108 {
00109 Name n1 = (Name)name1;
00110 Name n2 = (Name)name2;
00111
00112 return strcmp( n1->name, n2->name );
00113 }
00114
00115 static void
00116 names_sort( void )
00117 {
00118 qsort( the_names, (size_t)num_names, sizeof(the_names[0]), name_compare );
00119 }
00120
00121
00122 static void
00123 names_dump( FILE* out,
00124 OutputFormat format,
00125 const char* dll_name )
00126 {
00127 int nn;
00128
00129 switch ( format )
00130 {
00131 case OUTPUT_WINDOWS_DEF:
00132 if ( dll_name )
00133 fprintf( out, "LIBRARY %s\n", dll_name );
00134
00135 fprintf( out, "DESCRIPTION FreeType 2 DLL\n" );
00136 fprintf( out, "EXPORTS\n" );
00137 for ( nn = 0; nn < num_names; nn++ )
00138 fprintf( out, " %s\n", the_names[nn].name );
00139 break;
00140
00141 case OUTPUT_BORLAND_DEF:
00142 if ( dll_name )
00143 fprintf( out, "LIBRARY %s\n", dll_name );
00144
00145 fprintf( out, "DESCRIPTION FreeType 2 DLL\n" );
00146 fprintf( out, "EXPORTS\n" );
00147 for ( nn = 0; nn < num_names; nn++ )
00148 fprintf( out, " _%s\n", the_names[nn].name );
00149 break;
00150
00151 case OUTPUT_WATCOM_LBC:
00152 {
00153
00154 char temp[512];
00155 char* dot;
00156
00157 if ( dll_name == NULL )
00158 {
00159 fprintf( stderr,
00160 "you must provide a DLL name with the -d option !!\n" );
00161 exit(4);
00162 }
00163
00164 dot = strchr( dll_name, '.' );
00165 if ( dot != NULL )
00166 {
00167 int len = (dot - dll_name);
00168 if ( len > (int)(sizeof(temp)-1) )
00169 len = sizeof(temp)-1;
00170
00171 memcpy( temp, dll_name, len );
00172 temp[len] = 0;
00173
00174 dll_name = (const char*)temp;
00175 }
00176
00177 for ( nn = 0; nn < num_names; nn++ )
00178 fprintf( out, "++_%s.%s.%s\n", the_names[nn].name, dll_name,
00179 the_names[nn].name );
00180 }
00181 break;
00182
00183 default:
00184 for ( nn = 0; nn < num_names; nn++ )
00185 fprintf( out, "%s\n", the_names[nn].name );
00186 }
00187 }
00188
00189
00190
00191
00192
00193
00194 typedef enum State_
00195 {
00196 STATE_START = 0,
00197 STATE_TYPE
00198
00199 } State;
00200
00201 static int
00202 read_header_file( FILE* file, int verbose )
00203 {
00204 static char buff[ LINEBUFF_SIZE+1 ];
00205 State state = STATE_START;
00206
00207 while ( !feof( file ) )
00208 {
00209 char* p;
00210
00211 if ( !fgets( buff, LINEBUFF_SIZE, file ) )
00212 break;
00213
00214 p = buff;
00215
00216 while ( *p && (*p == ' ' || *p == '\\') )
00217 p++;
00218
00219 if ( *p == '\n' || *p == '\r' )
00220 continue;
00221
00222 switch ( state )
00223 {
00224 case STATE_START:
00225 {
00226 if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 )
00227 break;
00228
00229 p += 10;
00230 for (;;)
00231 {
00232 if ( *p == 0 || *p == '\n' || *p == '\r' )
00233 goto NextLine;
00234
00235 if ( *p == ')' )
00236 {
00237 p++;
00238 break;
00239 }
00240
00241 p++;
00242 }
00243
00244 state = STATE_TYPE;
00245
00246
00247
00248
00249
00250 while ( *p == ' ' || *p == '\t' )
00251 p++;
00252
00253 if ( !isalpha(*p) )
00254 break;
00255 }
00256
00257
00258 case STATE_TYPE:
00259 {
00260 char* name = p;
00261
00262 while ( isalnum(*p) || *p == '_' )
00263 p++;
00264
00265 if ( p > name )
00266 {
00267 if ( verbose )
00268 fprintf( stderr, ">>> %.*s\n", (int)(p - name), name );
00269
00270 names_add( name, p );
00271 }
00272
00273 state = STATE_START;
00274 }
00275 break;
00276
00277 default:
00278 ;
00279 }
00280
00281 NextLine:
00282 ;
00283 }
00284
00285 return 0;
00286 }
00287
00288
00289 static void
00290 usage( void )
00291 {
00292 static const char* const format =
00293 "%s %s: extract FreeType API names from header files\n\n"
00294 "this program is used to extract the list of public FreeType API\n"
00295 "functions. It receives the list of header files as argument and\n"
00296 "generates a sorted list of unique identifiers\n\n"
00297
00298 "usage: %s header1 [options] [header2 ...]\n\n"
00299
00300 "options: - : parse the content of stdin, ignore arguments\n"
00301 " -v : verbose mode, output sent to standard error\n"
00302 " -oFILE : write output to FILE instead of standard output\n"
00303 " -dNAME : indicate DLL file name, 'freetype.dll' by default\n"
00304 " -w : output .DEF file for Visual C++ and Mingw\n"
00305 " -wB : output .DEF file for Borland C++\n"
00306 " -wW : output Watcom Linker Response File\n"
00307 "\n";
00308
00309 fprintf( stderr,
00310 format,
00311 PROGRAM_NAME,
00312 PROGRAM_VERSION,
00313 PROGRAM_NAME
00314 );
00315 exit(1);
00316 }
00317
00318
00319 int main( int argc, const char* const* argv )
00320 {
00321 int from_stdin = 0;
00322 int verbose = 0;
00323 OutputFormat format = OUTPUT_LIST;
00324 FILE* out = stdout;
00325 const char* library_name = NULL;
00326
00327 if ( argc < 2 )
00328 usage();
00329
00330
00331 while ( argc > 1 && argv[1][0] == '-' )
00332 {
00333 const char* arg = argv[1];
00334
00335 switch ( arg[1] )
00336 {
00337 case 'v':
00338 verbose = 1;
00339 break;
00340
00341 case 'o':
00342 if ( arg[2] == 0 )
00343 {
00344 if ( argc < 2 )
00345 usage();
00346
00347 arg = argv[2];
00348 argv++;
00349 argc--;
00350 }
00351 else
00352 arg += 2;
00353
00354 out = fopen( arg, "wt" );
00355 if ( out == NULL )
00356 {
00357 fprintf( stderr, "could not open '%s' for writing\n", argv[2] );
00358 exit(3);
00359 }
00360 break;
00361
00362 case 'd':
00363 if ( arg[2] == 0 )
00364 {
00365 if ( argc < 2 )
00366 usage();
00367
00368 arg = argv[2];
00369 argv++;
00370 argc--;
00371 }
00372 else
00373 arg += 2;
00374
00375 library_name = arg;
00376 break;
00377
00378 case 'w':
00379 format = OUTPUT_WINDOWS_DEF;
00380 switch ( arg[2] )
00381 {
00382 case 'B':
00383 format = OUTPUT_BORLAND_DEF;
00384 break;
00385
00386 case 'W':
00387 format = OUTPUT_WATCOM_LBC;
00388 break;
00389
00390 case 0:
00391 break;
00392
00393 default:
00394 usage();
00395 }
00396 break;
00397
00398 case 0:
00399 from_stdin = 1;
00400 break;
00401
00402 default:
00403 usage();
00404 }
00405
00406 argc--;
00407 argv++;
00408 }
00409
00410 if ( from_stdin )
00411 {
00412 read_header_file( stdin, verbose );
00413 }
00414 else
00415 {
00416 for ( --argc, argv++; argc > 0; argc--, argv++ )
00417 {
00418 FILE* file = fopen( argv[0], "rb" );
00419
00420 if ( file == NULL )
00421 fprintf( stderr, "unable to open '%s'\n", argv[0] );
00422 else
00423 {
00424 if ( verbose )
00425 fprintf( stderr, "opening '%s'\n", argv[0] );
00426
00427 read_header_file( file, verbose );
00428 fclose( file );
00429 }
00430 }
00431 }
00432
00433 if ( num_names == 0 )
00434 panic( "could not find exported functions !!\n" );
00435
00436 names_sort();
00437 names_dump( out, format, library_name );
00438
00439 if ( out != stdout )
00440 fclose( out );
00441
00442 return 0;
00443 }