misc/libfreetype/src/tools/apinames.c
branchspacecampaign
changeset 9382 f1464fa10c0b
parent 9346 1245c7636380
parent 9380 563ab624522c
child 9384 557ae509547b
equal deleted inserted replaced
9346:1245c7636380 9382:f1464fa10c0b
     1 /*
       
     2  * This little program is used to parse the FreeType headers and
       
     3  * find the declaration of all public APIs.  This is easy, because
       
     4  * they all look like the following:
       
     5  *
       
     6  *   FT_EXPORT( return_type )
       
     7  *   function_name( function arguments );
       
     8  *
       
     9  * You must pass the list of header files as arguments.  Wildcards are
       
    10  * accepted if you are using GCC for compilation (and probably by
       
    11  * other compilers too).
       
    12  *
       
    13  * Author: David Turner, 2005, 2006, 2008, 2009, 2010
       
    14  *
       
    15  * This code is explicitly placed into the public domain.
       
    16  *
       
    17  */
       
    18 
       
    19 #include <stdio.h>
       
    20 #include <stdlib.h>
       
    21 #include <string.h>
       
    22 #include <ctype.h>
       
    23 
       
    24 #define  PROGRAM_NAME     "apinames"
       
    25 #define  PROGRAM_VERSION  "0.1"
       
    26 
       
    27 #define  LINEBUFF_SIZE  1024
       
    28 
       
    29 typedef enum  OutputFormat_
       
    30 {
       
    31   OUTPUT_LIST = 0,      /* output the list of names, one per line             */
       
    32   OUTPUT_WINDOWS_DEF,   /* output a Windows .DEF file for Visual C++ or Mingw */
       
    33   OUTPUT_BORLAND_DEF,   /* output a Windows .DEF file for Borland C++         */
       
    34   OUTPUT_WATCOM_LBC     /* output a Watcom Linker Command File                */
       
    35 
       
    36 } OutputFormat;
       
    37 
       
    38 
       
    39 static void
       
    40 panic( const char*  message )
       
    41 {
       
    42   fprintf( stderr, "PANIC: %s\n", message );
       
    43   exit(2);
       
    44 }
       
    45 
       
    46 
       
    47 typedef struct  NameRec_
       
    48 {
       
    49   char*         name;
       
    50   unsigned int  hash;
       
    51 
       
    52 } NameRec, *Name;
       
    53 
       
    54 static Name  the_names;
       
    55 static int   num_names;
       
    56 static int   max_names;
       
    57 
       
    58 static void
       
    59 names_add( const char*  name,
       
    60            const char*  end )
       
    61 {
       
    62   int   nn, len, h;
       
    63   Name  nm;
       
    64 
       
    65   if ( end <= name )
       
    66     return;
       
    67 
       
    68   /* compute hash value */
       
    69   len = (int)(end - name);
       
    70   h   = 0;
       
    71   for ( nn = 0; nn < len; nn++ )
       
    72     h = h*33 + name[nn];
       
    73 
       
    74   /* check for an pre-existing name */
       
    75   for ( nn = 0; nn < num_names; nn++ )
       
    76   {
       
    77     nm = the_names + nn;
       
    78 
       
    79     if ( (int)nm->hash                 == h &&
       
    80          memcmp( name, nm->name, len ) == 0 &&
       
    81          nm->name[len]                 == 0 )
       
    82       return;
       
    83   }
       
    84 
       
    85   /* add new name */
       
    86   if ( num_names >= max_names )
       
    87   {
       
    88     max_names += (max_names >> 1) + 4;
       
    89     the_names  = (NameRec*)realloc( the_names, sizeof(the_names[0])*max_names );
       
    90     if ( the_names == NULL )
       
    91       panic( "not enough memory" );
       
    92   }
       
    93   nm = &the_names[num_names++];
       
    94 
       
    95   nm->hash = h;
       
    96   nm->name = (char*)malloc( len+1 );
       
    97   if ( nm->name == NULL )
       
    98     panic( "not enough memory" );
       
    99 
       
   100   memcpy( nm->name, name, len );
       
   101   nm->name[len] = 0;
       
   102 }
       
   103 
       
   104 
       
   105 static int
       
   106 name_compare( const void*  name1,
       
   107               const void*  name2 )
       
   108 {
       
   109   Name  n1 = (Name)name1;
       
   110   Name  n2 = (Name)name2;
       
   111 
       
   112   return strcmp( n1->name, n2->name );
       
   113 }
       
   114 
       
   115 static void
       
   116 names_sort( void )
       
   117 {
       
   118   qsort( the_names, (size_t)num_names, sizeof(the_names[0]), name_compare );
       
   119 }
       
   120 
       
   121 
       
   122 static void
       
   123 names_dump( FILE*         out,
       
   124             OutputFormat  format,
       
   125             const char*   dll_name )
       
   126 {
       
   127   int  nn;
       
   128 
       
   129 
       
   130   switch ( format )
       
   131   {
       
   132     case OUTPUT_WINDOWS_DEF:
       
   133       if ( dll_name )
       
   134         fprintf( out, "LIBRARY %s\n", dll_name );
       
   135 
       
   136       fprintf( out, "DESCRIPTION  FreeType 2 DLL\n" );
       
   137       fprintf( out, "EXPORTS\n" );
       
   138       for ( nn = 0; nn < num_names; nn++ )
       
   139         fprintf( out, "  %s\n", the_names[nn].name );
       
   140       break;
       
   141 
       
   142     case OUTPUT_BORLAND_DEF:
       
   143       if ( dll_name )
       
   144         fprintf( out, "LIBRARY %s\n", dll_name );
       
   145 
       
   146       fprintf( out, "DESCRIPTION  FreeType 2 DLL\n" );
       
   147       fprintf( out, "EXPORTS\n" );
       
   148       for ( nn = 0; nn < num_names; nn++ )
       
   149         fprintf( out, "  _%s\n", the_names[nn].name );
       
   150       break;
       
   151 
       
   152     case OUTPUT_WATCOM_LBC:
       
   153       {
       
   154         /* we must omit the .dll suffix from the library name */
       
   155         char         temp[512];
       
   156         const char*  dot;
       
   157 
       
   158 
       
   159         if ( dll_name == NULL )
       
   160         {
       
   161           fprintf( stderr,
       
   162                    "you must provide a DLL name with the -d option!\n" );
       
   163           exit( 4 );
       
   164         }
       
   165 
       
   166         dot = strchr( dll_name, '.' );
       
   167         if ( dot != NULL )
       
   168         {
       
   169           int  len = dot - dll_name;
       
   170 
       
   171 
       
   172           if ( len > (int)( sizeof( temp ) - 1 ) )
       
   173             len = sizeof ( temp ) - 1;
       
   174 
       
   175           memcpy( temp, dll_name, len );
       
   176           temp[len] = 0;
       
   177 
       
   178           dll_name = (const char*)temp;
       
   179         }
       
   180 
       
   181         for ( nn = 0; nn < num_names; nn++ )
       
   182           fprintf( out, "++_%s.%s.%s\n", the_names[nn].name, dll_name,
       
   183                         the_names[nn].name );
       
   184       }
       
   185       break;
       
   186 
       
   187     default:  /* LIST */
       
   188       for ( nn = 0; nn < num_names; nn++ )
       
   189         fprintf( out, "%s\n", the_names[nn].name );
       
   190   }
       
   191 }
       
   192 
       
   193 
       
   194 
       
   195 
       
   196 /* states of the line parser */
       
   197 
       
   198 typedef enum  State_
       
   199 {
       
   200   STATE_START = 0,  /* waiting for FT_EXPORT keyword and return type */
       
   201   STATE_TYPE        /* type was read, waiting for function name      */
       
   202 
       
   203 } State;
       
   204 
       
   205 static int
       
   206 read_header_file( FILE*  file, int  verbose )
       
   207 {
       
   208   static char  buff[ LINEBUFF_SIZE+1 ];
       
   209   State        state = STATE_START;
       
   210 
       
   211   while ( !feof( file ) )
       
   212   {
       
   213     char*  p;
       
   214 
       
   215     if ( !fgets( buff, LINEBUFF_SIZE, file ) )
       
   216       break;
       
   217 
       
   218     p = buff;
       
   219 
       
   220     while ( *p && (*p == ' ' || *p == '\\') )  /* skip leading whitespace */
       
   221       p++;
       
   222 
       
   223     if ( *p == '\n' || *p == '\r' )  /* skip empty lines */
       
   224       continue;
       
   225 
       
   226     switch ( state )
       
   227     {
       
   228       case STATE_START:
       
   229         {
       
   230           if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 )
       
   231             break;
       
   232 
       
   233           p += 10;
       
   234           for (;;)
       
   235           {
       
   236             if ( *p == 0 || *p == '\n' || *p == '\r' )
       
   237               goto NextLine;
       
   238 
       
   239             if ( *p == ')' )
       
   240             {
       
   241               p++;
       
   242               break;
       
   243             }
       
   244 
       
   245             p++;
       
   246           }
       
   247 
       
   248           state = STATE_TYPE;
       
   249 
       
   250          /* sometimes, the name is just after the FT_EXPORT(...), so
       
   251           * skip whitespace, and fall-through if we find an alphanumeric
       
   252           * character
       
   253           */
       
   254           while ( *p == ' ' || *p == '\t' )
       
   255             p++;
       
   256 
       
   257           if ( !isalpha(*p) )
       
   258             break;
       
   259         }
       
   260         /* fall-through */
       
   261 
       
   262       case STATE_TYPE:
       
   263         {
       
   264           char*   name = p;
       
   265 
       
   266           while ( isalnum(*p) || *p == '_' )
       
   267             p++;
       
   268 
       
   269           if ( p > name )
       
   270           {
       
   271             if ( verbose )
       
   272               fprintf( stderr, ">>> %.*s\n", (int)(p - name), name );
       
   273 
       
   274             names_add( name, p );
       
   275           }
       
   276 
       
   277           state = STATE_START;
       
   278         }
       
   279         break;
       
   280 
       
   281       default:
       
   282         ;
       
   283     }
       
   284 
       
   285   NextLine:
       
   286     ;
       
   287   }
       
   288 
       
   289   return 0;
       
   290 }
       
   291 
       
   292 
       
   293 static void
       
   294 usage( void )
       
   295 {
       
   296   static const char* const  format =
       
   297    "%s %s: extract FreeType API names from header files\n\n"
       
   298    "this program is used to extract the list of public FreeType API\n"
       
   299    "functions. It receives the list of header files as argument and\n"
       
   300    "generates a sorted list of unique identifiers\n\n"
       
   301 
       
   302    "usage: %s header1 [options] [header2 ...]\n\n"
       
   303 
       
   304    "options:   -      : parse the content of stdin, ignore arguments\n"
       
   305    "           -v     : verbose mode, output sent to standard error\n"
       
   306    "           -oFILE : write output to FILE instead of standard output\n"
       
   307    "           -dNAME : indicate DLL file name, 'freetype.dll' by default\n"
       
   308    "           -w     : output .DEF file for Visual C++ and Mingw\n"
       
   309    "           -wB    : output .DEF file for Borland C++\n"
       
   310    "           -wW    : output Watcom Linker Response File\n"
       
   311    "\n";
       
   312 
       
   313   fprintf( stderr,
       
   314            format,
       
   315            PROGRAM_NAME,
       
   316            PROGRAM_VERSION,
       
   317            PROGRAM_NAME
       
   318            );
       
   319   exit(1);
       
   320 }
       
   321 
       
   322 
       
   323 int  main( int argc, const char* const*  argv )
       
   324 {
       
   325   int           from_stdin = 0;
       
   326   int           verbose = 0;
       
   327   OutputFormat  format = OUTPUT_LIST;  /* the default */
       
   328   FILE*         out    = stdout;
       
   329   const char*   library_name = NULL;
       
   330 
       
   331   if ( argc < 2 )
       
   332     usage();
       
   333 
       
   334   /* '-' used as a single argument means read source file from stdin */
       
   335   while ( argc > 1 && argv[1][0] == '-' )
       
   336   {
       
   337     const char*  arg = argv[1];
       
   338 
       
   339     switch ( arg[1] )
       
   340     {
       
   341       case 'v':
       
   342         verbose = 1;
       
   343         break;
       
   344 
       
   345       case 'o':
       
   346         if ( arg[2] == 0 )
       
   347         {
       
   348           if ( argc < 2 )
       
   349             usage();
       
   350 
       
   351           arg = argv[2];
       
   352           argv++;
       
   353           argc--;
       
   354         }
       
   355         else
       
   356           arg += 2;
       
   357 
       
   358         out = fopen( arg, "wt" );
       
   359         if ( out == NULL )
       
   360         {
       
   361           fprintf( stderr, "could not open '%s' for writing\n", argv[2] );
       
   362           exit(3);
       
   363         }
       
   364         break;
       
   365 
       
   366       case 'd':
       
   367         if ( arg[2] == 0 )
       
   368         {
       
   369           if ( argc < 2 )
       
   370             usage();
       
   371 
       
   372           arg = argv[2];
       
   373           argv++;
       
   374           argc--;
       
   375         }
       
   376         else
       
   377           arg += 2;
       
   378 
       
   379         library_name = arg;
       
   380         break;
       
   381 
       
   382       case 'w':
       
   383         format = OUTPUT_WINDOWS_DEF;
       
   384         switch ( arg[2] )
       
   385         {
       
   386           case 'B':
       
   387             format = OUTPUT_BORLAND_DEF;
       
   388             break;
       
   389 
       
   390           case 'W':
       
   391             format = OUTPUT_WATCOM_LBC;
       
   392             break;
       
   393 
       
   394           case 0:
       
   395             break;
       
   396 
       
   397           default:
       
   398             usage();
       
   399         }
       
   400         break;
       
   401 
       
   402       case 0:
       
   403         from_stdin = 1;
       
   404         break;
       
   405 
       
   406       default:
       
   407         usage();
       
   408     }
       
   409 
       
   410     argc--;
       
   411     argv++;
       
   412   }
       
   413 
       
   414   if ( from_stdin )
       
   415   {
       
   416     read_header_file( stdin, verbose );
       
   417   }
       
   418   else
       
   419   {
       
   420     for ( --argc, argv++; argc > 0; argc--, argv++ )
       
   421     {
       
   422       FILE*  file = fopen( argv[0], "rb" );
       
   423 
       
   424       if ( file == NULL )
       
   425         fprintf( stderr, "unable to open '%s'\n", argv[0] );
       
   426       else
       
   427       {
       
   428         if ( verbose )
       
   429           fprintf( stderr, "opening '%s'\n", argv[0] );
       
   430 
       
   431         read_header_file( file, verbose );
       
   432         fclose( file );
       
   433       }
       
   434     }
       
   435   }
       
   436 
       
   437   if ( num_names == 0 )
       
   438     panic( "could not find exported functions !!\n" );
       
   439 
       
   440   names_sort();
       
   441   names_dump( out, format, library_name );
       
   442 
       
   443   if ( out != stdout )
       
   444     fclose( out );
       
   445 
       
   446   return 0;
       
   447 }