Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenapinames.c
Go to the documentation of this file.
00001 /* 00002 * This little program is used to parse the FreeType headers and 00003 * find the declaration of all public APIs. This is easy, because 00004 * they all look like the following: 00005 * 00006 * FT_EXPORT( return_type ) 00007 * function_name( function arguments ); 00008 * 00009 * You must pass the list of header files as arguments. Wildcards are 00010 * accepted if you are using GCC for compilation (and probably by 00011 * other compilers too). 00012 * 00013 * Author: David Turner, 2005, 2006, 2008, 2009, 2010 00014 * 00015 * This code is explicitly placed into the public domain. 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, /* output the list of names, one per line */ 00032 OUTPUT_WINDOWS_DEF, /* output a Windows .DEF file for Visual C++ or Mingw */ 00033 OUTPUT_BORLAND_DEF, /* output a Windows .DEF file for Borland C++ */ 00034 OUTPUT_WATCOM_LBC /* output a Watcom Linker Command File */ 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 /* compute hash value */ 00069 len = (int)(end - name); 00070 h = 0; 00071 for ( nn = 0; nn < len; nn++ ) 00072 h = h*33 + name[nn]; 00073 00074 /* check for an pre-existing name */ 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 /* add new name */ 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 00130 switch ( format ) 00131 { 00132 case OUTPUT_WINDOWS_DEF: 00133 if ( dll_name ) 00134 fprintf( out, "LIBRARY %s\n", dll_name ); 00135 00136 fprintf( out, "DESCRIPTION FreeType 2 DLL\n" ); 00137 fprintf( out, "EXPORTS\n" ); 00138 for ( nn = 0; nn < num_names; nn++ ) 00139 fprintf( out, " %s\n", the_names[nn].name ); 00140 break; 00141 00142 case OUTPUT_BORLAND_DEF: 00143 if ( dll_name ) 00144 fprintf( out, "LIBRARY %s\n", dll_name ); 00145 00146 fprintf( out, "DESCRIPTION FreeType 2 DLL\n" ); 00147 fprintf( out, "EXPORTS\n" ); 00148 for ( nn = 0; nn < num_names; nn++ ) 00149 fprintf( out, " _%s\n", the_names[nn].name ); 00150 break; 00151 00152 case OUTPUT_WATCOM_LBC: 00153 { 00154 /* we must omit the .dll suffix from the library name */ 00155 char temp[512]; 00156 const char* dot; 00157 00158 00159 if ( dll_name == NULL ) 00160 { 00161 fprintf( stderr, 00162 "you must provide a DLL name with the -d option!\n" ); 00163 exit( 4 ); 00164 } 00165 00166 dot = strchr( dll_name, '.' ); 00167 if ( dot != NULL ) 00168 { 00169 int len = dot - dll_name; 00170 00171 00172 if ( len > (int)( sizeof( temp ) - 1 ) ) 00173 len = sizeof ( temp ) - 1; 00174 00175 memcpy( temp, dll_name, len ); 00176 temp[len] = 0; 00177 00178 dll_name = (const char*)temp; 00179 } 00180 00181 for ( nn = 0; nn < num_names; nn++ ) 00182 fprintf( out, "++_%s.%s.%s\n", the_names[nn].name, dll_name, 00183 the_names[nn].name ); 00184 } 00185 break; 00186 00187 default: /* LIST */ 00188 for ( nn = 0; nn < num_names; nn++ ) 00189 fprintf( out, "%s\n", the_names[nn].name ); 00190 } 00191 } 00192 00193 00194 00195 00196 /* states of the line parser */ 00197 00198 typedef enum State_ 00199 { 00200 STATE_START = 0, /* waiting for FT_EXPORT keyword and return type */ 00201 STATE_TYPE /* type was read, waiting for function name */ 00202 00203 } State; 00204 00205 static int 00206 read_header_file( FILE* file, int verbose ) 00207 { 00208 static char buff[ LINEBUFF_SIZE+1 ]; 00209 State state = STATE_START; 00210 00211 while ( !feof( file ) ) 00212 { 00213 char* p; 00214 00215 if ( !fgets( buff, LINEBUFF_SIZE, file ) ) 00216 break; 00217 00218 p = buff; 00219 00220 while ( *p && (*p == ' ' || *p == '\\') ) /* skip leading whitespace */ 00221 p++; 00222 00223 if ( *p == '\n' || *p == '\r' ) /* skip empty lines */ 00224 continue; 00225 00226 switch ( state ) 00227 { 00228 case STATE_START: 00229 { 00230 if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 ) 00231 break; 00232 00233 p += 10; 00234 for (;;) 00235 { 00236 if ( *p == 0 || *p == '\n' || *p == '\r' ) 00237 goto NextLine; 00238 00239 if ( *p == ')' ) 00240 { 00241 p++; 00242 break; 00243 } 00244 00245 p++; 00246 } 00247 00248 state = STATE_TYPE; 00249 00250 /* sometimes, the name is just after the FT_EXPORT(...), so 00251 * skip whitespace, and fall-through if we find an alphanumeric 00252 * character 00253 */ 00254 while ( *p == ' ' || *p == '\t' ) 00255 p++; 00256 00257 if ( !isalpha(*p) ) 00258 break; 00259 } 00260 /* fall-through */ 00261 00262 case STATE_TYPE: 00263 { 00264 char* name = p; 00265 00266 while ( isalnum(*p) || *p == '_' ) 00267 p++; 00268 00269 if ( p > name ) 00270 { 00271 if ( verbose ) 00272 fprintf( stderr, ">>> %.*s\n", (int)(p - name), name ); 00273 00274 names_add( name, p ); 00275 } 00276 00277 state = STATE_START; 00278 } 00279 break; 00280 00281 default: 00282 ; 00283 } 00284 00285 NextLine: 00286 ; 00287 } 00288 00289 return 0; 00290 } 00291 00292 00293 static void 00294 usage( void ) 00295 { 00296 static const char* const format = 00297 "%s %s: extract FreeType API names from header files\n\n" 00298 "this program is used to extract the list of public FreeType API\n" 00299 "functions. It receives the list of header files as argument and\n" 00300 "generates a sorted list of unique identifiers\n\n" 00301 00302 "usage: %s header1 [options] [header2 ...]\n\n" 00303 00304 "options: - : parse the content of stdin, ignore arguments\n" 00305 " -v : verbose mode, output sent to standard error\n" 00306 " -oFILE : write output to FILE instead of standard output\n" 00307 " -dNAME : indicate DLL file name, 'freetype.dll' by default\n" 00308 " -w : output .DEF file for Visual C++ and Mingw\n" 00309 " -wB : output .DEF file for Borland C++\n" 00310 " -wW : output Watcom Linker Response File\n" 00311 "\n"; 00312 00313 fprintf( stderr, 00314 format, 00315 PROGRAM_NAME, 00316 PROGRAM_VERSION, 00317 PROGRAM_NAME 00318 ); 00319 exit(1); 00320 } 00321 00322 00323 int main( int argc, const char* const* argv ) 00324 { 00325 int from_stdin = 0; 00326 int verbose = 0; 00327 OutputFormat format = OUTPUT_LIST; /* the default */ 00328 FILE* out = stdout; 00329 const char* library_name = NULL; 00330 00331 if ( argc < 2 ) 00332 usage(); 00333 00334 /* '-' used as a single argument means read source file from stdin */ 00335 while ( argc > 1 && argv[1][0] == '-' ) 00336 { 00337 const char* arg = argv[1]; 00338 00339 switch ( arg[1] ) 00340 { 00341 case 'v': 00342 verbose = 1; 00343 break; 00344 00345 case 'o': 00346 if ( arg[2] == 0 ) 00347 { 00348 if ( argc < 2 ) 00349 usage(); 00350 00351 arg = argv[2]; 00352 argv++; 00353 argc--; 00354 } 00355 else 00356 arg += 2; 00357 00358 out = fopen( arg, "wt" ); 00359 if ( out == NULL ) 00360 { 00361 fprintf( stderr, "could not open '%s' for writing\n", argv[2] ); 00362 exit(3); 00363 } 00364 break; 00365 00366 case 'd': 00367 if ( arg[2] == 0 ) 00368 { 00369 if ( argc < 2 ) 00370 usage(); 00371 00372 arg = argv[2]; 00373 argv++; 00374 argc--; 00375 } 00376 else 00377 arg += 2; 00378 00379 library_name = arg; 00380 break; 00381 00382 case 'w': 00383 format = OUTPUT_WINDOWS_DEF; 00384 switch ( arg[2] ) 00385 { 00386 case 'B': 00387 format = OUTPUT_BORLAND_DEF; 00388 break; 00389 00390 case 'W': 00391 format = OUTPUT_WATCOM_LBC; 00392 break; 00393 00394 case 0: 00395 break; 00396 00397 default: 00398 usage(); 00399 } 00400 break; 00401 00402 case 0: 00403 from_stdin = 1; 00404 break; 00405 00406 default: 00407 usage(); 00408 } 00409 00410 argc--; 00411 argv++; 00412 } 00413 00414 if ( from_stdin ) 00415 { 00416 read_header_file( stdin, verbose ); 00417 } 00418 else 00419 { 00420 for ( --argc, argv++; argc > 0; argc--, argv++ ) 00421 { 00422 FILE* file = fopen( argv[0], "rb" ); 00423 00424 if ( file == NULL ) 00425 fprintf( stderr, "unable to open '%s'\n", argv[0] ); 00426 else 00427 { 00428 if ( verbose ) 00429 fprintf( stderr, "opening '%s'\n", argv[0] ); 00430 00431 read_header_file( file, verbose ); 00432 fclose( file ); 00433 } 00434 } 00435 } 00436 00437 if ( num_names == 0 ) 00438 panic( "could not find exported functions !!\n" ); 00439 00440 names_sort(); 00441 names_dump( out, format, library_name ); 00442 00443 if ( out != stdout ) 00444 fclose( out ); 00445 00446 return 0; 00447 } Generated on Fri May 25 2012 04:32:32 for ReactOS by
1.7.6.1
|