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