(root)/
freetype-2.13.2/
src/
tools/
apinames.c
       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: FreeType team, 2005-2019
      14   *
      15   * This code is explicitly placed into the public domain.
      16   *
      17   */
      18  
      19  #include <stdio.h>
      20  #include <stdlib.h>
      21  #include <stdarg.h>
      22  #include <string.h>
      23  #include <ctype.h>
      24  
      25  #include "vms_shorten_symbol.c"
      26  
      27  #define  PROGRAM_NAME     "apinames"
      28  #define  PROGRAM_VERSION  "0.5"
      29  
      30  #define  LINEBUFF_SIZE  1024
      31  
      32  
      33  typedef enum  OutputFormat_
      34  {
      35    OUTPUT_LIST = 0,      /* output the list of names, one per line             */
      36    OUTPUT_WINDOWS_DEF,   /* output a Windows .DEF file for Visual C++ or Mingw */
      37    OUTPUT_BORLAND_DEF,   /* output a Windows .DEF file for Borland C++         */
      38    OUTPUT_WATCOM_LBC,    /* output a Watcom Linker Command File                */
      39    OUTPUT_VMS_OPT,       /* output an OpenVMS Linker Option File               */
      40    OUTPUT_NETWARE_IMP,   /* output a NetWare ImportFile                        */
      41    OUTPUT_GNU_VERMAP     /* output a version map for GNU or Solaris linker     */
      42  
      43  } OutputFormat;
      44  
      45  
      46  static void
      47  panic( const char*  fmt,
      48         ... )
      49  {
      50    va_list  ap;
      51  
      52  
      53    fprintf( stderr, "PANIC: " );
      54  
      55    va_start( ap, fmt );
      56    vfprintf( stderr, fmt, ap );
      57    va_end( ap );
      58  
      59    fprintf( stderr, "\n" );
      60  
      61    exit(2);
      62  }
      63  
      64  
      65  typedef struct  NameRec_
      66  {
      67    char*         name;
      68    unsigned int  hash;
      69  
      70  } NameRec, *Name;
      71  
      72  
      73  static Name  the_names;
      74  static int   num_names;
      75  static int   max_names;
      76  
      77  
      78  static void
      79  names_add( const char*  name,
      80             const char*  end )
      81  {
      82    unsigned int  h;
      83    int           nn, len;
      84    Name          nm;
      85  
      86  
      87    if ( end <= name )
      88      return;
      89  
      90    /* compute hash value */
      91    len = (int)( end - name );
      92    h   = 0;
      93  
      94    for ( nn = 0; nn < len; nn++ )
      95      h = h * 33 + name[nn];
      96  
      97    /* check for an pre-existing name */
      98    for ( nn = 0; nn < num_names; nn++ )
      99    {
     100      nm = the_names + nn;
     101  
     102      if ( (int)nm->hash                 == h &&
     103           memcmp( name, nm->name, len ) == 0 &&
     104           nm->name[len]                 == 0 )
     105        return;
     106    }
     107  
     108    /* add new name */
     109    if ( num_names >= max_names )
     110    {
     111      max_names += ( max_names >> 1 ) + 4;
     112      the_names  = (NameRec*)realloc( the_names,
     113                                      sizeof ( the_names[0] ) * max_names );
     114      if ( !the_names )
     115        panic( "not enough memory" );
     116    }
     117    nm = &the_names[num_names++];
     118  
     119    nm->hash = h;
     120    nm->name = (char*)malloc( len + 1 );
     121    if ( !nm->name )
     122      panic( "not enough memory" );
     123  
     124    memcpy( nm->name, name, len );
     125    nm->name[len] = 0;
     126  }
     127  
     128  
     129  static int
     130  name_compare( const void*  name1,
     131                const void*  name2 )
     132  {
     133    Name  n1 = (Name)name1;
     134    Name  n2 = (Name)name2;
     135  
     136    return strcmp( n1->name, n2->name );
     137  }
     138  
     139  
     140  static void
     141  names_sort( void )
     142  {
     143    qsort( the_names, (size_t)num_names,
     144           sizeof ( the_names[0] ), name_compare );
     145  }
     146  
     147  
     148  static void
     149  names_dump( FILE*         out,
     150              OutputFormat  format,
     151              const char*   dll_name )
     152  {
     153    int  nn;
     154  
     155  
     156    switch ( format )
     157    {
     158    case OUTPUT_WINDOWS_DEF:
     159      if ( dll_name )
     160        fprintf( out, "LIBRARY %s\n", dll_name );
     161  
     162      fprintf( out, "DESCRIPTION  FreeType 2 DLL\n" );
     163      fprintf( out, "EXPORTS\n" );
     164  
     165      for ( nn = 0; nn < num_names; nn++ )
     166        fprintf( out, "  %s\n", the_names[nn].name );
     167  
     168      break;
     169  
     170    case OUTPUT_BORLAND_DEF:
     171      if ( dll_name )
     172        fprintf( out, "LIBRARY %s\n", dll_name );
     173  
     174      fprintf( out, "DESCRIPTION  FreeType 2 DLL\n" );
     175      fprintf( out, "EXPORTS\n" );
     176  
     177      for ( nn = 0; nn < num_names; nn++ )
     178        fprintf( out, "  _%s\n", the_names[nn].name );
     179  
     180      break;
     181  
     182    case OUTPUT_WATCOM_LBC:
     183      {
     184        const char*  dot;
     185  
     186  
     187        if ( !dll_name )
     188        {
     189          fprintf( stderr,
     190                   "you must provide a DLL name with the -d option!\n" );
     191          exit( 4 );
     192        }
     193  
     194        /* we must omit the `.dll' suffix from the library name */
     195        dot = strchr( dll_name, '.' );
     196        if ( dot )
     197        {
     198          char  temp[512];
     199          int   len = dot - dll_name;
     200  
     201  
     202          if ( len > (int)( sizeof ( temp ) - 1 ) )
     203            len = sizeof ( temp ) - 1;
     204  
     205          memcpy( temp, dll_name, len );
     206          temp[len] = 0;
     207  
     208          dll_name = (const char*)temp;
     209        }
     210  
     211        for ( nn = 0; nn < num_names; nn++ )
     212          fprintf( out, "++_%s.%s.%s\n",
     213                        the_names[nn].name, dll_name, the_names[nn].name );
     214      }
     215  
     216      break;
     217  
     218    case OUTPUT_VMS_OPT:
     219      fprintf( out, "case_sensitive=YES\n" );
     220  
     221      for ( nn = 0; nn < num_names; nn++ )
     222      {
     223        char  short_symbol[32];
     224  
     225  
     226        if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 )
     227          panic( "could not shorten name '%s'", the_names[nn].name );
     228        fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol );
     229  
     230        /* Also emit a 64-bit symbol, as created by the `vms_auto64` tool. */
     231        /* It has the string '64__' appended to its name.                  */
     232        strcat( the_names[nn].name , "64__" );
     233        if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 )
     234          panic( "could not shorten name '%s'", the_names[nn].name );
     235        fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol );
     236      }
     237  
     238      break;
     239  
     240    case OUTPUT_NETWARE_IMP:
     241      if ( dll_name )
     242        fprintf( out, "  (%s)\n", dll_name );
     243  
     244      for ( nn = 0; nn < num_names - 1; nn++ )
     245        fprintf( out, "  %s,\n", the_names[nn].name );
     246      fprintf( out, "  %s\n", the_names[num_names - 1].name );
     247  
     248      break;
     249  
     250    case OUTPUT_GNU_VERMAP:
     251      fprintf( out, "{\n\tglobal:\n" );
     252  
     253      for ( nn = 0; nn < num_names; nn++ )
     254        fprintf( out, "\t\t%s;\n", the_names[nn].name );
     255  
     256      fprintf( out, "\tlocal:\n\t\t*;\n};\n" );
     257  
     258      break;
     259  
     260    default:  /* LIST */
     261      for ( nn = 0; nn < num_names; nn++ )
     262        fprintf( out, "%s\n", the_names[nn].name );
     263  
     264      break;
     265    }
     266  }
     267  
     268  
     269  /* states of the line parser */
     270  
     271  typedef enum  State_
     272  {
     273    STATE_START = 0,  /* waiting for FT_EXPORT keyword and return type */
     274    STATE_TYPE        /* type was read, waiting for function name      */
     275  
     276  } State;
     277  
     278  
     279  static int
     280  read_header_file( FILE*  file,
     281                    int    verbose )
     282  {
     283    static char  buff[LINEBUFF_SIZE + 1];
     284    State        state = STATE_START;
     285  
     286  
     287    while ( !feof( file ) )
     288    {
     289      char*  p;
     290  
     291  
     292      if ( !fgets( buff, LINEBUFF_SIZE, file ) )
     293        break;
     294  
     295      p = buff;
     296  
     297      /* skip leading whitespace */
     298      while ( *p && ( *p == ' ' || *p == '\\' ) )
     299        p++;
     300  
     301      /* skip empty lines */
     302      if ( *p == '\n' || *p == '\r' )
     303        continue;
     304  
     305      switch ( state )
     306      {
     307      case STATE_START:
     308        if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 )
     309          break;
     310  
     311        p += 10;
     312        for (;;)
     313        {
     314          if ( *p == 0 || *p == '\n' || *p == '\r' )
     315            goto NextLine;
     316  
     317          if ( *p == ')' )
     318          {
     319            p++;
     320            break;
     321          }
     322  
     323          p++;
     324        }
     325  
     326        state = STATE_TYPE;
     327  
     328        /*
     329         * Sometimes, the name is just after `FT_EXPORT(...)', so skip
     330         * whitespace and fall-through if we find an alphanumeric character.
     331         */
     332        while ( *p == ' ' || *p == '\t' )
     333          p++;
     334  
     335        if ( !isalpha( *p ) )
     336          break;
     337  
     338        /* fall-through */
     339  
     340      case STATE_TYPE:
     341        {
     342          char*   name = p;
     343  
     344  
     345          while ( isalnum( *p ) || *p == '_' )
     346            p++;
     347  
     348          if ( p > name )
     349          {
     350            if ( verbose )
     351              fprintf( stderr, ">>> %.*s\n", (int)( p - name ), name );
     352  
     353            names_add( name, p );
     354          }
     355  
     356          state = STATE_START;
     357        }
     358  
     359        break;
     360  
     361      default:
     362        ;
     363      }
     364  
     365  NextLine:
     366      ;
     367    } /* end of while loop */
     368  
     369    return 0;
     370  }
     371  
     372  
     373  static void
     374  usage( void )
     375  {
     376    static const char* const  format =
     377      "%s %s: extract FreeType API names from header files\n"
     378      "\n"
     379      "This program extracts the list of public FreeType API functions.\n"
     380      "It receives a list of header files as an argument and\n"
     381      "generates a sorted list of unique identifiers in various formats.\n"
     382      "\n"
     383      "usage: %s header1 [options] [header2 ...]\n"
     384      "\n"
     385      "options:   -       parse the contents of stdin, ignore arguments\n"
     386      "           -v      verbose mode, output sent to standard error\n"
     387      "           -oFILE  write output to FILE instead of standard output\n"
     388      "           -dNAME  indicate DLL file name, 'freetype.dll' by default\n"
     389      "           -w      output .DEF file for Visual C++ and Mingw\n"
     390      "           -wB     output .DEF file for Borland C++\n"
     391      "           -wW     output Watcom Linker Response File\n"
     392      "           -wV     output OpenVMS Linker Options File\n"
     393      "           -wN     output NetWare Import File\n"
     394      "           -wL     output version map for GNU or Solaris linker\n"
     395      "\n";
     396  
     397    fprintf( stderr,
     398             format,
     399             PROGRAM_NAME,
     400             PROGRAM_VERSION,
     401             PROGRAM_NAME );
     402  
     403    exit( 1 );
     404  }
     405  
     406  
     407  int
     408  main( int                 argc,
     409        const char* const*  argv )
     410  {
     411    int           from_stdin   = 0;
     412    int           verbose      = 0;
     413    OutputFormat  format       = OUTPUT_LIST;  /* the default */
     414    FILE*         out          = stdout;
     415    const char*   library_name = NULL;
     416  
     417  
     418    if ( argc < 2 )
     419      usage();
     420  
     421    /* `-' used as a single argument means read source file from stdin */
     422    while ( argc > 1 && argv[1][0] == '-' )
     423    {
     424      const char*  arg = argv[1];
     425  
     426  
     427      switch ( arg[1] )
     428      {
     429      case 'v':
     430        verbose = 1;
     431  
     432        break;
     433  
     434      case 'o':
     435        if ( arg[2] == 0 )
     436        {
     437          if ( argc < 2 )
     438            usage();
     439  
     440          arg = argv[2];
     441          argv++;
     442          argc--;
     443        }
     444        else
     445          arg += 2;
     446  
     447        out = fopen( arg, "wt" );
     448        if ( !out )
     449        {
     450          fprintf( stderr, "could not open '%s' for writing\n", arg );
     451          exit( 3 );
     452        }
     453  
     454        break;
     455  
     456      case 'd':
     457        if ( arg[2] == 0 )
     458        {
     459          if ( argc < 2 )
     460            usage();
     461  
     462          arg = argv[2];
     463          argv++;
     464          argc--;
     465        }
     466        else
     467          arg += 2;
     468  
     469        library_name = arg;
     470  
     471        break;
     472  
     473      case 'w':
     474        format = OUTPUT_WINDOWS_DEF;
     475  
     476        switch ( arg[2] )
     477        {
     478        case 'B':
     479          format = OUTPUT_BORLAND_DEF;
     480          break;
     481  
     482        case 'W':
     483          format = OUTPUT_WATCOM_LBC;
     484          break;
     485  
     486        case 'V':
     487          format = OUTPUT_VMS_OPT;
     488          break;
     489  
     490        case 'N':
     491          format = OUTPUT_NETWARE_IMP;
     492          break;
     493  
     494        case 'L':
     495          format = OUTPUT_GNU_VERMAP;
     496          break;
     497  
     498        case 0:
     499          break;
     500  
     501        default:
     502          usage();
     503        }
     504  
     505        break;
     506  
     507      case 0:
     508        from_stdin = 1;
     509  
     510        break;
     511  
     512      default:
     513        usage();
     514      }
     515  
     516      argc--;
     517      argv++;
     518  
     519    } /* end of while loop */
     520  
     521    if ( from_stdin )
     522      read_header_file( stdin, verbose );
     523    else
     524    {
     525      for ( --argc, argv++; argc > 0; argc--, argv++ )
     526      {
     527        FILE*  file = fopen( argv[0], "rb" );
     528  
     529  
     530        if ( !file )
     531          fprintf( stderr, "unable to open '%s'\n", argv[0] );
     532        else
     533        {
     534          if ( verbose )
     535            fprintf( stderr, "opening '%s'\n", argv[0] );
     536  
     537          read_header_file( file, verbose );
     538          fclose( file );
     539        }
     540      }
     541    }
     542  
     543    if ( num_names == 0 )
     544      panic( "could not find exported functions\n" );
     545  
     546    names_sort();
     547    names_dump( out, format, library_name );
     548  
     549    if ( out != stdout )
     550      fclose( out );
     551  
     552    return 0;
     553  }
     554  
     555  
     556  /* END */