Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

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