sdk-world v2026.11.05
PS2 SDK - world tier (copyleft-allowed, non-essential packages)
Loading...
Searching...
No Matches
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: FreeType team, 2005-2023
14 *
15 * This code is explicitly placed into the public domain.
16 *
17 */
18
19#include <stdio.h>
20#include <stdlib.h>
21#include <stdarg.h>
22#include <string.h>
23#include <ctype.h>
24
25#include "vms_shorten_symbol.c"
26
27#define PROGRAM_NAME "apinames"
28#define PROGRAM_VERSION "0.5"
29
30#define LINEBUFF_SIZE 1024
31
32
33typedef enum OutputFormat_
34{
35 OUTPUT_LIST = 0, /* output the list of names, one per line */
36 OUTPUT_WINDOWS_DEF, /* output a Windows .DEF file for Visual C++ or Mingw */
37 OUTPUT_BORLAND_DEF, /* output a Windows .DEF file for Borland C++ */
38 OUTPUT_WATCOM_LBC, /* output a Watcom Linker Command File */
39 OUTPUT_VMS_OPT, /* output an OpenVMS Linker Option File */
40 OUTPUT_NETWARE_IMP, /* output a NetWare ImportFile */
41 OUTPUT_GNU_VERMAP /* output a version map for GNU or Solaris linker */
42
43} OutputFormat;
44
45#define SUFFIX_VMS_64ADDR "64__"
46
47static void
48panic( const char* fmt,
49 ... )
50{
51 va_list ap;
52
53
54 fprintf( stderr, "PANIC: " );
55
56 va_start( ap, fmt );
57 vfprintf( stderr, fmt, ap );
58 va_end( ap );
59
60 fprintf( stderr, "\n" );
61
62 exit(2);
63}
64
65
66typedef struct NameRec_
67{
68 char* name;
69 unsigned int hash;
70
71} NameRec, *Name;
72
73
74static Name the_names;
75static int num_names;
76static int max_names;
77
78
79static void
80names_add( const char* name,
81 const char* end,
82 OutputFormat format )
83{
84 unsigned int h;
85 int nn, len, len_suffix;
86 Name nm;
87
88
89 if ( end <= name )
90 return;
91
92 /* compute hash value */
93 len = (int)( end - name );
94 h = 0;
95
96 for ( nn = 0; nn < len; nn++ )
97 h = h * 33 + name[nn];
98
99 /* check for an pre-existing name */
100 for ( nn = 0; nn < num_names; nn++ )
101 {
102 nm = the_names + nn;
103
104 if ( (int)nm->hash == h &&
105 memcmp( name, nm->name, len ) == 0 &&
106 nm->name[len] == 0 )
107 return;
108 }
109
110 /* add new name */
111 if ( num_names >= max_names )
112 {
113 max_names += ( max_names >> 1 ) + 4;
114 the_names = (NameRec*)realloc( the_names,
115 sizeof ( the_names[0] ) * max_names );
116 if ( !the_names )
117 panic( "not enough memory" );
118 }
119 nm = &the_names[num_names++];
120
121 switch ( format )
122 {
123 case OUTPUT_VMS_OPT:
124 /* VMS mode would join the symbol name with a suffix */
125 len_suffix = sizeof ( SUFFIX_VMS_64ADDR );
126 break;
127 default:
128 len_suffix = 0;
129 }
130
131 nm->hash = h;
132 nm->name = (char*)malloc( len + len_suffix + 1 );
133 if ( !nm->name )
134 panic( "not enough memory" );
135
136 memcpy( nm->name, name, len );
137 nm->name[len] = 0;
138}
139
140
141static int
142name_compare( const void* name1,
143 const void* name2 )
144{
145 Name n1 = (Name)name1;
146 Name n2 = (Name)name2;
147
148 return strcmp( n1->name, n2->name );
149}
150
151
152static void
153names_sort( void )
154{
155 qsort( the_names, (size_t)num_names,
156 sizeof ( the_names[0] ), name_compare );
157}
158
159
160static void
161names_dump( FILE* out,
162 OutputFormat format,
163 const char* dll_name )
164{
165 int nn;
166
167
168 switch ( format )
169 {
170 case OUTPUT_WINDOWS_DEF:
171 if ( dll_name )
172 fprintf( out, "LIBRARY %s\n", dll_name );
173
174 fprintf( out, "DESCRIPTION FreeType 2 DLL\n" );
175 fprintf( out, "EXPORTS\n" );
176
177 for ( nn = 0; nn < num_names; nn++ )
178 fprintf( out, " %s\n", the_names[nn].name );
179
180 break;
181
182 case OUTPUT_BORLAND_DEF:
183 if ( dll_name )
184 fprintf( out, "LIBRARY %s\n", dll_name );
185
186 fprintf( out, "DESCRIPTION FreeType 2 DLL\n" );
187 fprintf( out, "EXPORTS\n" );
188
189 for ( nn = 0; nn < num_names; nn++ )
190 fprintf( out, " _%s\n", the_names[nn].name );
191
192 break;
193
194 case OUTPUT_WATCOM_LBC:
195 {
196 char temp[512];
197 const char* dot;
198
199
200 if ( !dll_name )
201 {
202 fprintf( stderr,
203 "you must provide a DLL name with the -d option!\n" );
204 exit( 4 );
205 }
206
207 /* we must omit the `.dll' suffix from the library name */
208 dot = strchr( dll_name, '.' );
209 if ( dot )
210 {
211 int len = dot - dll_name;
212
213
214 if ( len > (int)( sizeof ( temp ) - 1 ) )
215 len = sizeof ( temp ) - 1;
216
217 memcpy( temp, dll_name, len );
218 temp[len] = 0;
219
220 dll_name = (const char*)temp;
221 }
222
223 for ( nn = 0; nn < num_names; nn++ )
224 fprintf( out, "++_%s.%s.%s\n",
225 the_names[nn].name, dll_name, the_names[nn].name );
226 }
227
228 break;
229
230 case OUTPUT_VMS_OPT:
231 fprintf( out, "case_sensitive=YES\n" );
232
233 for ( nn = 0; nn < num_names; nn++ )
234 {
235 char short_symbol[32];
236
237
238 if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 )
239 panic( "could not shorten name '%s'", the_names[nn].name );
240 fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol );
241
242 /* Also emit a 64-bit symbol, as created by the `vms_auto64` tool. */
243 /* It has the string '64__' appended to its name. */
244 strcat( the_names[nn].name , SUFFIX_VMS_64ADDR );
245 if ( vms_shorten_symbol( the_names[nn].name, short_symbol, 1 ) == -1 )
246 panic( "could not shorten name '%s'", the_names[nn].name );
247 fprintf( out, "symbol_vector = ( %s = PROCEDURE)\n", short_symbol );
248 }
249
250 break;
251
252 case OUTPUT_NETWARE_IMP:
253 if ( dll_name )
254 fprintf( out, " (%s)\n", dll_name );
255
256 for ( nn = 0; nn < num_names - 1; nn++ )
257 fprintf( out, " %s,\n", the_names[nn].name );
258 fprintf( out, " %s\n", the_names[num_names - 1].name );
259
260 break;
261
262 case OUTPUT_GNU_VERMAP:
263 fprintf( out, "{\n\tglobal:\n" );
264
265 for ( nn = 0; nn < num_names; nn++ )
266 fprintf( out, "\t\t%s;\n", the_names[nn].name );
267
268 fprintf( out, "\tlocal:\n\t\t*;\n};\n" );
269
270 break;
271
272 default: /* LIST */
273 for ( nn = 0; nn < num_names; nn++ )
274 fprintf( out, "%s\n", the_names[nn].name );
275
276 break;
277 }
278}
279
280
281/* states of the line parser */
282
283typedef enum State_
284{
285 STATE_START = 0, /* waiting for FT_EXPORT keyword and return type */
286 STATE_TYPE /* type was read, waiting for function name */
287
288} State;
289
290
291static int
292read_header_file( FILE* file,
293 int verbose,
294 OutputFormat format )
295{
296 static char buff[LINEBUFF_SIZE + 1];
297 State state = STATE_START;
298
299
300 while ( !feof( file ) )
301 {
302 char* p;
303
304
305 if ( !fgets( buff, LINEBUFF_SIZE, file ) )
306 break;
307
308 p = buff;
309
310 /* skip leading whitespace */
311 while ( *p == ' ' || *p == '\t' )
312 p++;
313
314 /* skip empty lines */
315 if ( *p == '\n' || *p == '\r' )
316 continue;
317
318 switch ( state )
319 {
320 case STATE_START:
321 if ( memcmp( p, "FT_EXPORT(", 10 ) != 0 )
322 break;
323
324 p += 10;
325 for (;;)
326 {
327 if ( *p == 0 || *p == '\n' || *p == '\r' )
328 goto NextLine;
329
330 if ( *p == ')' )
331 {
332 p++;
333 break;
334 }
335
336 p++;
337 }
338
339 state = STATE_TYPE;
340
341 /*
342 * Sometimes, the name is just after `FT_EXPORT(...)', so skip
343 * whitespace and fall-through if we find an alphanumeric character.
344 */
345 while ( *p == ' ' || *p == '\t' )
346 p++;
347
348 if ( !isalpha( *p ) )
349 break;
350
351 /* fall-through */
352
353 case STATE_TYPE:
354 {
355 char* name = p;
356
357
358 while ( isalnum( *p ) || *p == '_' )
359 p++;
360
361 if ( p > name )
362 {
363 if ( verbose )
364 fprintf( stderr, ">>> %.*s\n", (int)( p - name ), name );
365
366 names_add( name, p, format );
367 }
368
369 state = STATE_START;
370 }
371
372 break;
373
374 default:
375 ;
376 }
377
378NextLine:
379 ;
380 } /* end of while loop */
381
382 return 0;
383}
384
385
386static void
387usage( void )
388{
389 static const char* const format =
390 "%s %s: extract FreeType API names from header files\n"
391 "\n"
392 "This program extracts the list of public FreeType API functions.\n"
393 "It receives a list of header files as an argument and\n"
394 "generates a sorted list of unique identifiers in various formats.\n"
395 "\n"
396 "usage: %s [options] header1 [header2 ...]\n"
397 "\n"
398 "options: - parse the contents of stdin, ignore arguments\n"
399 " -v verbose mode, output sent to standard error\n"
400 " -oFILE write output to FILE instead of standard output\n"
401 " -dNAME indicate DLL file name, 'freetype.dll' by default\n"
402 " -w output .DEF file for Visual C++ and Mingw\n"
403 " -wB output .DEF file for Borland C++\n"
404 " -wW output Watcom Linker Response File\n"
405 " -wV output OpenVMS Linker Options File\n"
406 " -wN output NetWare Import File\n"
407 " -wL output version map for GNU or Solaris linker\n"
408 "\n";
409
410 fprintf( stderr,
411 format,
412 PROGRAM_NAME,
413 PROGRAM_VERSION,
414 PROGRAM_NAME );
415
416 exit( 1 );
417}
418
419
420int
421main( int argc,
422 const char* const* argv )
423{
424 int from_stdin = 0;
425 int verbose = 0;
426 OutputFormat format = OUTPUT_LIST; /* the default */
427 FILE* out = stdout;
428 const char* library_name = NULL;
429
430
431 if ( argc < 2 )
432 usage();
433
434 /* `-' used as a single argument means read source file from stdin */
435 while ( argc > 1 && argv[1][0] == '-' )
436 {
437 const char* arg = argv[1];
438
439
440 switch ( arg[1] )
441 {
442 case 'v':
443 verbose = 1;
444
445 break;
446
447 case 'o':
448 if ( arg[2] == 0 )
449 {
450 if ( argc < 2 )
451 usage();
452
453 arg = argv[2];
454 argv++;
455 argc--;
456 }
457 else
458 arg += 2;
459
460 out = fopen( arg, "wt" );
461 if ( !out )
462 {
463 fprintf( stderr, "could not open '%s' for writing\n", arg );
464 exit( 3 );
465 }
466
467 break;
468
469 case 'd':
470 if ( arg[2] == 0 )
471 {
472 if ( argc < 2 )
473 usage();
474
475 arg = argv[2];
476 argv++;
477 argc--;
478 }
479 else
480 arg += 2;
481
482 library_name = arg;
483
484 break;
485
486 case 'w':
487 format = OUTPUT_WINDOWS_DEF;
488
489 switch ( arg[2] )
490 {
491 case 'B':
492 format = OUTPUT_BORLAND_DEF;
493 break;
494
495 case 'W':
496 format = OUTPUT_WATCOM_LBC;
497 break;
498
499 case 'V':
500 format = OUTPUT_VMS_OPT;
501 break;
502
503 case 'N':
504 format = OUTPUT_NETWARE_IMP;
505 break;
506
507 case 'L':
508 format = OUTPUT_GNU_VERMAP;
509 break;
510
511 case 0:
512 break;
513
514 default:
515 usage();
516 }
517
518 break;
519
520 case 0:
521 from_stdin = 1;
522
523 break;
524
525 default:
526 usage();
527 }
528
529 argc--;
530 argv++;
531
532 } /* end of while loop */
533
534 if ( from_stdin )
535 read_header_file( stdin, verbose, format );
536 else
537 {
538 for ( --argc, argv++; argc > 0; argc--, argv++ )
539 {
540 FILE* file = fopen( argv[0], "rb" );
541
542
543 if ( !file )
544 fprintf( stderr, "unable to open '%s'\n", argv[0] );
545 else
546 {
547 if ( verbose )
548 fprintf( stderr, "opening '%s'\n", argv[0] );
549
550 read_header_file( file, verbose, format );
551 fclose( file );
552 }
553 }
554 }
555
556 if ( num_names == 0 )
557 panic( "could not find exported functions\n" );
558
559 names_sort();
560 names_dump( out, format, library_name );
561
562 if ( out != stdout )
563 fclose( out );
564
565 return 0;
566}
567
568
569/* END */