Freeciv-3.3
Loading...
Searching...
No Matches
generate_specenum.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3#
4# Freeciv - Copyright (C) 2009
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2, or (at your option)
8# any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15
16# The maximum number of enumerators.
17max_enum_values=200
18
19# Here are push all defined macros.
20macros=[]
21
22import sys
23
24def make_header(file):
25 file.write('''
26 /**************************************************************************
27 * THIS FILE WAS GENERATED *
28 * Script: utility/generate_specenum.py *
29 * DO NOT CHANGE THIS FILE *
30 **************************************************************************/
31
32/***********************************************************************
33 Freeciv - Copyright (C) 2009
34 This program is free software; you can redistribute it and/or modify
35 it under the terms of the GNU General Public License as published by
36 the Free Software Foundation; either version 2, or (at your option)
37 any later version.
38
39 This program is distributed in the hope that it will be useful,
40 but WITHOUT ANY WARRANTY; without even the implied warranty of
41 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42 GNU General Public License for more details.
43***********************************************************************/
44''')
45
47 file.write('''
48/*
49 * Include this file to define tools to manage enumerators. First of all,
50 * before including this file, you *MUST* define the following macros:
51 * - SPECENUM_NAME: is the name of the enumeration (e.g. 'foo' for defining
52 * 'enum foo').
53 * - SPECENUM_VALUE%d: define like this all values of your enumeration type
54 * (e.g. '#define SPECENUM_VALUE0 FOO_FIRST').
55 *
56 * The following macros *CAN* be defined:
57 * - SPECENUM_INVALID: specifies a value that your 'foo_invalid()' function
58 * will return. Note it cannot be a declared value with SPECENUM_VALUE%d.
59 * - SPECENUM_BITWISE: defines if the enumeration should be like
60 * [1, 2, 4, 8, etc...] instead of the default of [0, 1, 2, 3, etc...].
61 * - SPECENUM_ZERO: can be defined only if SPECENUM_BITWISE was also defined.
62 * It defines a 0 value. Note that if you don't declare this value, 0 passed
63 * to the 'foo_is_valid()' function will return FALSE.
64 * - SPECENUM_COUNT: a name for the maximum enumeration number plus 1. For
65 * enums where every element from 0 to the maximum is defined, this is the
66 * number of elements in the enum. This value is suitable to size an array
67 * indexed by the enum. It can not be used in combination with
68 * SPECENUM_BITWISE. SPECENUM_is_valid() will return the invalid element
69 * for it.
70 *
71 * SPECENUM_VALUE%dNAME, SPECENUM_ZERONAME, SPECENUM_COUNTNAME: Can be used
72 * to bind a string to the particular enumerator to be returned by
73 * SPECENUM_name(), etc. If not defined, the default name for 'FOO_FIRST'
74 * is '"FOO_FIRST"'. A name can be qualified. The qualification will only
75 * be used for its translation. The returned name will be unqualified. To
76 * mark a name as translatable use N_().
77 *
78 * SPECENUM_NAMEOVERRIDE: call callback function foo_name_cb(enum foo),
79 * defined by specenum user, to get name of the enum value. If the function
80 * returns nullptr, compiled in names are used.
81 *
82 * SPECENUM_NAME_UPDATER: call callback function foo_name_update_cb(old_name),
83 * defined by specenum user, to get current name to search enum value with.
84 *
85 * SPECENUM_BITVECTOR: specifies the name of a bit vector for the enum
86 * values. It can not be used in combination with SPECENUM_BITWISE.
87 *
88 * Assuming SPECENUM_NAME were 'foo', including this file would provide
89 * the definition for the enumeration type 'enum foo', and prototypes for
90 * the following functions:
91 * bool foo_is_bitwise(void);
92 * enum foo foo_min(void);
93 * enum foo foo_max(void);
94 * enum foo foo_invalid(void);
95 * bool foo_is_valid(enum foo);
96 *
97 * enum foo foo_begin(void);
98 * enum foo foo_end(void);
99 * enum foo foo_next(enum foo);
100 *
101 * const char *foo_name(enum foo);
102 * const char *foo_translated_name(enum foo);
103 * enum foo foo_by_name(const char *name,
104 * int (*strcmp_func)(const char *, const char *));
105 *
106 * Example:
107 * #define SPECENUM_NAME test
108 * #define SPECENUM_BITWISE
109 * #define SPECENUM_VALUE0 TEST0
110 * #define SPECENUM_VALUE1 TEST1
111 * #define SPECENUM_VALUE3 TEST3
112 * #include "specenum_gen.h"
113 *
114 * {
115 * static const char *strings[] = {
116 * "TEST1", "test3", "fghdf", nullptr
117 * };
118 * enum test e;
119 * int i;
120 *
121 * log_verbose("enum test [%d; %d]%s",
122 * test_min(), test_max(), test_bitwise ? " bitwise" : "");
123 *
124 * for (e = test_begin(); e != test_end(); e = test_next(e)) {
125 * log_verbose("Value %d is %s", e, test_name(e));
126 * }
127 *
128 * for (i = 0; strings[i]; i++) {
129 * e = test_by_name(strings[i], fc_strcasecmp);
130 * if (test_is_valid(e)) {
131 * log_verbose("Value is %d for %s", e, strings[i]);
132 * } else {
133 * log_verbose("%s is not a valid name", strings[i]);
134 * }
135 * }
136 * }
137 *
138 * Will output:
139 * enum test [1, 8] bitwise
140 * Value 1 is TEST0
141 * Value 2 is TEST1
142 * Value 8 is TEST3
143 * Value is 2 for TEST1
144 * Value is 8 for test3
145 * fghdf is not a valid name
146 */
147''')
148
149def make_macros(file):
150 file.write('''
151#ifdef __cplusplus
152extern "C" {
153#endif /* __cplusplus */
154
155/* utility */
156#include "fcintl.h" /* translation */
157#include "log.h" /* fc_assert. */
158#include "support.h" /* bool type. */
159
160#ifndef SPECENUM_NAME
161#error Must define a SPECENUM_NAME to use this header
162#endif
163
164#define SPECENUM_PASTE_(x, y) x ## y
165#define SPECENUM_PASTE(x, y) SPECENUM_PASTE_(x, y)
166
167#define SPECENUM_STRING_(x) #x
168#define SPECENUM_STRING(x) SPECENUM_STRING_(x)
169
170#define SPECENUM_FOO(suffix) SPECENUM_PASTE(SPECENUM_NAME, suffix)
171
172#ifndef SPECENUM_INVALID
173#define SPECENUM_INVALID ((enum SPECENUM_NAME) -1)
174#endif
175
176#ifdef SPECENUM_BITWISE
177#ifdef SPECENUM_COUNT
178#error Cannot define SPECENUM_COUNT when SPECENUM_BITWISE is defined.
179#endif
180#define SPECENUM_VALUE(value) (1 << value)
181#else /* SPECENUM_BITWISE */
182#ifdef SPECENUM_ZERO
183#error Cannot define SPECENUM_ZERO when SPECENUM_BITWISE is not defined.
184#endif
185#define SPECENUM_VALUE(value) (value)
186#endif /* SPECENUM_BITWISE */
187
188#ifdef SPECENUM_BITVECTOR
189#include "bitvector.h"
190#ifdef SPECENUM_BITWISE
191#error SPECENUM_BITWISE and SPECENUM_BITVECTOR cannot both be defined.
192#endif /* SPECENUM_BITWISE */
193#endif /* SPECENUM_BITVECTOR */
194
195#undef SPECENUM_MIN_VALUE
196#undef SPECENUM_MAX_VALUE
197''')
198 macros.append("SPECENUM_NAME")
199 macros.append("SPECENUM_PASTE_")
200 macros.append("SPECENUM_PASTE")
201 macros.append("SPECENUM_STRING_")
202 macros.append("SPECENUM_STRING")
203 macros.append("SPECENUM_FOO")
204 macros.append("SPECENUM_INVALID")
205 macros.append("SPECENUM_BITWISE")
206 macros.append("SPECENUM_VALUE")
207 macros.append("SPECENUM_ZERO")
208 macros.append("SPECENUM_MIN_VALUE")
209 macros.append("SPECENUM_MAX_VALUE")
210 macros.append("SPECENUM_SIZE")
211 macros.append("SPECENUM_NAMEOVERRIDE")
212 macros.append("SPECENUM_NAME_UPDATER")
213 macros.append("SPECENUM_BITVECTOR")
214
215def make_enum(file):
216 file.write('''
217/* Enumeration definition. */
218enum SPECENUM_NAME {
219#ifdef SPECENUM_ZERO
220 SPECENUM_ZERO = 0,
221#endif
222''')
223
224 for i in range(max_enum_values):
225 file.write('''
226#ifdef SPECENUM_VALUE%d
227 SPECENUM_VALUE%d = SPECENUM_VALUE(%d),
228# ifndef SPECENUM_MIN_VALUE
229# define SPECENUM_MIN_VALUE SPECENUM_VALUE%d
230# endif
231# ifdef SPECENUM_MAX_VALUE
232# undef SPECENUM_MAX_VALUE
233# endif
234# define SPECENUM_MAX_VALUE SPECENUM_VALUE%d
235# ifdef SPECENUM_SIZE
236# undef SPECENUM_SIZE
237# endif
238# define SPECENUM_SIZE (%d + 1)
239#endif /* SPECENUM_VALUE%d */
240'''%(i,i,i,i,i,i,i))
241
242 file.write('''
243#ifdef SPECENUM_COUNT
244 SPECENUM_COUNT = (SPECENUM_MAX_VALUE + 1),
245#endif /* SPECENUM_COUNT */
246};
247''')
248
249 macros.append("SPECENUM_COUNT")
250 for i in range(max_enum_values):
251 macros.append("SPECENUM_VALUE%d"%i)
252
254 file.write('''
255/**********************************************************************//**
256 Returns TRUE if this enumeration is in bitwise mode.
257**************************************************************************/
258fc__attribute((const))
259static inline bool SPECENUM_FOO(_is_bitwise)(void)
260{
261#ifdef SPECENUM_BITWISE
262 return TRUE;
263#else
264 return FALSE;
265#endif
266}
267''')
268
269def make_min(file):
270 file.write('''
271/**********************************************************************//**
272 Returns the value of the minimal enumerator.
273**************************************************************************/
274fc__attribute((const))
275static inline enum SPECENUM_NAME SPECENUM_FOO(_min)(void)
276{
277 return SPECENUM_MIN_VALUE;
278}
279''')
280
281def make_max(file):
282 file.write('''
283/**********************************************************************//**
284 Returns the value of the maximal enumerator.
285**************************************************************************/
286fc__attribute((const))
287static inline enum SPECENUM_NAME SPECENUM_FOO(_max)(void)
288{
289 return SPECENUM_MAX_VALUE;
290}
291''')
292
294 file.write('''
295/**********************************************************************//**
296 Returns TRUE if this enumerator was defined.
297**************************************************************************/
298fc__attribute((const))
299static inline bool SPECENUM_FOO(_is_valid)(enum SPECENUM_NAME enumerator)
300{
301#ifdef SPECENUM_BITWISE
302 static const unsigned long valid = (
303 0''')
304
305 for i in range(max_enum_values):
306 file.write('''
307# ifdef SPECENUM_VALUE%d
308 | SPECENUM_VALUE%d
309# endif'''%(i,i))
310
311 file.write('''
312 );
313
314 FC_STATIC_ASSERT(sizeof(valid) * 8 >= SPECENUM_SIZE,
315 valid_sizeof_check);
316
317# ifdef SPECENUM_ZERO
318 if (enumerator == SPECENUM_ZERO) {
319 return TRUE;
320 }
321# endif
322 return (enumerator & valid) == enumerator;
323#else
324 static const bool valid[] = {''')
325
326 for i in range(max_enum_values):
327 file.write('''
328# if %d < SPECENUM_SIZE
329# ifdef SPECENUM_VALUE%d
330 TRUE,
331# else
332 FALSE,
333# endif
334# endif'''%(i,i))
335
336 file.write('''
337 };
338
339 FC_STATIC_ASSERT(ARRAY_SIZE(valid) == SPECENUM_SIZE,
340 valid_array_size_check);
341
342 return ((unsigned)enumerator < ARRAY_SIZE(valid)
343 && valid[enumerator]);
344#endif /* SPECENUM_BITWISE */
345}
346''')
347
348def make_invalid(file):
349 file.write('''
350/**********************************************************************//**
351 Returns an invalid enumerator value.
352**************************************************************************/
353fc__attribute((const))
354static inline enum SPECENUM_NAME SPECENUM_FOO(_invalid)(void)
355{
356 fc_assert(!SPECENUM_FOO(_is_valid(SPECENUM_INVALID)));
357 return SPECENUM_INVALID;
358}
359''')
360
361def make_begin(file):
362 file.write('''
363/**********************************************************************//**
364 Beginning of the iteration of the enumerators.
365**************************************************************************/
366fc__attribute((const))
367static inline enum SPECENUM_NAME SPECENUM_FOO(_begin)(void)
368{
369 return SPECENUM_FOO(_min)();
370}
371''')
372
373def make_end(file):
374 file.write('''
375/**********************************************************************//**
376 End of the iteration of the enumerators.
377**************************************************************************/
378fc__attribute((const))
379static inline enum SPECENUM_NAME SPECENUM_FOO(_end)(void)
380{
381 return SPECENUM_FOO(_invalid)();
382}
383''')
384
385def make_next(file):
386 file.write('''
387/**********************************************************************//**
388 Find the next valid enumerator value.
389**************************************************************************/
390fc__attribute((const))
391static inline enum SPECENUM_NAME SPECENUM_FOO(_next)(enum SPECENUM_NAME e)
392{
393 do {
394#ifdef SPECENUM_BITWISE
395 e = (enum SPECENUM_NAME)(e << 1);
396#else
397 e = (enum SPECENUM_NAME)(e + 1);
398#endif
399
400 if (e > SPECENUM_FOO(_max)()) {
401 /* End of the iteration. */
402 return SPECENUM_FOO(_invalid)();
403 }
404 } while (!SPECENUM_FOO(_is_valid)(e));
405
406 return e;
407}
408''')
409
410def make_name(file):
411 file.write('''
412#ifdef SPECENUM_NAMEOVERRIDE
413const char *SPECENUM_FOO(_name_cb)(enum SPECENUM_NAME value);
414#endif /* SPECENUM_NAMEOVERRIDE */
415
416/**********************************************************************//**
417 Returns the name of the enumerator.
418**************************************************************************/
419#ifndef SPECENUM_NAMEOVERRIDE
420fc__attribute((const))
421#endif
422static inline const char *SPECENUM_FOO(_name)(enum SPECENUM_NAME enumerator)
423{
424#ifdef SPECENUM_COUNT
425 static const char *names[SPECENUM_SIZE + 1];
426#else
427 static const char *names[SPECENUM_SIZE];
428#endif
429 static bool initialized = FALSE;
430
431#ifdef SPECENUM_NAMEOVERRIDE
432 {
433 const char *name = SPECENUM_FOO(_name_cb)(enumerator);
434
435 if (name != nullptr) {
436 return Qn_(name);
437 }
438 }
439#endif /* SPECENUM_NAMEOVERRIDE */
440
441 if (!initialized) {''')
442
443 for i in range(max_enum_values):
444 file.write('''
445#if %d < SPECENUM_SIZE
446# ifndef SPECENUM_VALUE%d
447 names[%d] = nullptr;
448# elif defined(SPECENUM_VALUE%dNAME)
449 names[%d] = Qn_(SPECENUM_VALUE%dNAME);
450# else
451 names[%d] = SPECENUM_STRING(SPECENUM_VALUE%d);
452# endif
453#endif'''%(i,i,i,i,i,i,i,i))
454 macros.append("SPECENUM_VALUE%dNAME"%i)
455
456 file.write('''
457#ifdef SPECENUM_COUNT
458# ifdef SPECENUM_COUNTNAME
459 names[SPECENUM_COUNT] = Qn_(SPECENUM_COUNTNAME);
460# else
461 names[SPECENUM_COUNT] = SPECENUM_STRING(SPECENUM_COUNT);
462# endif
463#endif
464 initialized = TRUE;
465 }
466
467#ifdef SPECENUM_BITWISE
468# ifdef SPECENUM_ZERO
469 if (enumerator == SPECENUM_ZERO) {
470# ifdef SPECENUM_ZERONAME
471 return Qn_(SPECENUM_ZERONAME);
472# else
473 return SPECENUM_STRING(SPECENUM_ZERO);
474# endif
475 }
476# endif
477 {
478 size_t i;
479
480 for (i = 0; i < ARRAY_SIZE(names); i++) {
481 if (1 << i == enumerator) {
482 return names[i];
483 }
484 }
485 }
486#else
487 if ((unsigned)enumerator < ARRAY_SIZE(names)) {
488 return names[enumerator];
489 }
490#endif /* SPECENUM_BITWISE */
491 return nullptr;
492}
493''')
494 macros.append("SPECENUM_COUNTNAME")
495 macros.append("SPECENUM_ZERONAME")
496
497def make_by_name(file):
498 file.write('''
499/**********************************************************************//**
500 Returns the enumerator for the name or *_invalid() if not found.
501**************************************************************************/
502static inline enum SPECENUM_NAME SPECENUM_FOO(_by_name)
503 (const char *name, int (*strcmp_func)(const char *, const char *))
504{
505 enum SPECENUM_NAME e;
506 const char *enum_name;
507 const char *current_name = name;
508
509#ifdef SPECENUM_NAME_UPDATER
510 current_name = SPECENUM_FOO(_name_update_cb)(name);
511#endif
512
513 for (e = SPECENUM_FOO(_begin)(); e != SPECENUM_FOO(_end)();
514 e = SPECENUM_FOO(_next)(e)) {
515 if ((enum_name = SPECENUM_FOO(_name)(e))
516 && 0 == strcmp_func(current_name, enum_name)) {
517 return e;
518 }
519 }
520
521 return SPECENUM_FOO(_invalid)();
522}
523''')
524
526 file.write('''
527/**********************************************************************//**
528 Returns the translated name of the enumerator.
529**************************************************************************/
530#ifndef SPECENUM_NAMEOVERRIDE
531fc__attribute((const))
532#endif
533static inline const char *
534SPECENUM_FOO(_translated_name)(enum SPECENUM_NAME enumerator)
535{
536#ifdef SPECENUM_COUNT
537 static const char *names[SPECENUM_SIZE + 1];
538#else
539 static const char *names[SPECENUM_SIZE];
540#endif
541 static bool initialized = FALSE;
542
543#ifdef SPECENUM_NAMEOVERRIDE
544 {
545 const char *name = SPECENUM_FOO(_name_cb)(enumerator);
546
547 if (name != nullptr) {
548 return Q_(name);
549 }
550 }
551#endif /* SPECENUM_NAMEOVERRIDE */
552
553 if (!initialized) {''')
554
555 for i in range(max_enum_values):
556 file.write('''
557#if %d < SPECENUM_SIZE
558# ifndef SPECENUM_VALUE%d
559 names[%d] = nullptr;
560# elif defined(SPECENUM_VALUE%dNAME)
561 names[%d] = Q_(SPECENUM_VALUE%dNAME);
562# else
563 names[%d] = SPECENUM_STRING(SPECENUM_VALUE%d);
564# endif
565#endif'''%(i,i,i,i,i,i,i,i))
566 macros.append("SPECENUM_VALUE%dNAME"%i)
567
568 file.write('''
569#ifdef SPECENUM_COUNT
570# ifdef SPECENUM_COUNTNAME
571 names[SPECENUM_COUNT] = Q_(SPECENUM_COUNTNAME);
572# else
573 names[SPECENUM_COUNT] = SPECENUM_STRING(SPECENUM_COUNT);
574# endif
575#endif
576 initialized = TRUE;
577 }
578
579#ifdef SPECENUM_BITWISE
580# ifdef SPECENUM_ZERO
581 if (enumerator == SPECENUM_ZERO) {
582# ifdef SPECENUM_ZERONAME
583 return Q_(SPECENUM_ZERONAME);
584# else
585 return SPECENUM_STRING(SPECENUM_ZERO);
586# endif
587 }
588# endif
589 {
590 size_t i;
591
592 for (i = 0; i < ARRAY_SIZE(names); i++) {
593 if (1 << i == enumerator) {
594 return names[i];
595 }
596 }
597 }
598#else
599 if ((unsigned)enumerator < ARRAY_SIZE(names)) {
600 return names[enumerator];
601 }
602#endif /* SPECENUM_BITWISE */
603 return nullptr;
604}
605''')
606
608 file.write('''
609#ifdef SPECENUM_BITVECTOR
610BV_DEFINE(SPECENUM_BITVECTOR, (SPECENUM_MAX_VALUE + 1));
611#endif /* SPECENUM_BITVECTOR */
612''')
613
614def make_undef(file):
615 for macro in macros:
616 file.write('''
617#undef %s'''%macro)
618
619 file.write('''
620''')
621
622# Main function.
623def main():
624 target_name=sys.argv[1]
625
626 with open(target_name, "w") as output:
627
628 make_header(output)
629 make_documentation(output)
630 make_macros(output)
631 make_enum(output)
632 make_is_bitwise(output)
633 make_min(output)
634 make_max(output)
635 make_is_valid(output)
636 make_invalid(output)
637 make_begin(output)
638 make_end(output)
639 make_next(output)
640 make_name(output)
641 make_by_name(output)
643 make_bitvector(output)
644 make_undef(output)
645
646 output.write('''
647#ifdef __cplusplus
648}
649#endif /* __cplusplus */
650''')
651
652main()
char * incite_cost
Definition comments.c:76