apinames.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
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   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         /* we must omit the .dll suffix from the library name */
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:  /* LIST */
00184       for ( nn = 0; nn < num_names; nn++ )
00185         fprintf( out, "%s\n", the_names[nn].name );
00186   }
00187 }
00188 
00189 
00190 
00191 
00192 /* states of the line parser */
00193 
00194 typedef enum  State_
00195 {
00196   STATE_START = 0,  /* waiting for FT_EXPORT keyword and return type */
00197   STATE_TYPE        /* type was read, waiting for function name      */
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 == '\\') )  /* skip leading whitespace */
00217       p++;
00218 
00219     if ( *p == '\n' || *p == '\r' )  /* skip empty lines */
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          /* sometimes, the name is just after the FT_EXPORT(...), so
00247           * skip whitespace, and fall-through if we find an alphanumeric
00248           * character
00249           */
00250           while ( *p == ' ' || *p == '\t' )
00251             p++;
00252 
00253           if ( !isalpha(*p) )
00254             break;
00255         }
00256         /* fall-through */
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;  /* the default */
00324   FILE*         out    = stdout;
00325   const char*   library_name = NULL;
00326 
00327   if ( argc < 2 )
00328     usage();
00329 
00330   /* '-' used as a single argument means read source file from stdin */
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 }

Generated on Tue Jul 5 14:13:51 2011 for ROOT_528-00b_version by  doxygen 1.5.1