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