tizen 2.3.1 release
[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-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 }