Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
4349 Serge 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 
20
#include 
21
#include 
22
#include 
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
}