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