tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

apinames.c (11798B)


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