Support VERSION_REVTYPE git builds on cleanup_checkout.sh
[freeciv.git] / utility / generate_specenum.py
blobc2818f041044b8d74df8f1c2263258d13518a906
1 #!/usr/bin/env python
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.
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.
16 # The maximum number of enumerators.
17 max_enum_values=125
19 # The target file.
20 target="utility/specenum_gen.h"
22 # Here are push all defined macros.
23 macros=[]
25 import os, sys
27 def make_header(file):
28 file.write('''
29 /**************************************************************************
30 * THIS FILE WAS GENERATED *
31 * Script: utility/generate_specenum.py *
32 * DO NOT CHANGE THIS FILE *
33 **************************************************************************/
35 /**********************************************************************
36 Freeciv - Copyright (C) 2009
37 This program is free software; you can redistribute it and/or modify
38 it under the terms of the GNU General Public License as published by
39 the Free Software Foundation; either version 2, or (at your option)
40 any later version.
42 This program is distributed in the hope that it will be useful,
43 but WITHOUT ANY WARRANTY; without even the implied warranty of
44 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
45 GNU General Public License for more details.
46 ***********************************************************************/
47 ''')
49 def make_documentation(file):
50 file.write('''
52 * Include this file to define tools to manage enumerators. First of all,
53 * before including this file, you *MUST* define the following macros:
54 * - SPECENUM_NAME: is the name of the enumeration (e.g. 'foo' for defining
55 * 'enum foo').
56 * - SPECENUM_VALUE%d: define like this all values of your enumeration type
57 * (e.g. '#define SPECENUM_VALUE0 FOO_FIRST').
59 * The following macros *CAN* be defined:
60 * - SPECENUM_INVALID: specifies a value that your 'foo_invalid()' function
61 * will return. Note it cannot be a declared value with SPECENUM_VALUE%d.
62 * - SPECENUM_BITWISE: defines if the enumeration should be like
63 * [1, 2, 4, 8, etc...] instead of the default of [0, 1, 2, 3, etc...].
64 * - SPECENUM_ZERO: can be defined only if SPECENUM_BITWISE was also defined.
65 * It defines a 0 value. Note that if you don't declare this value, 0 passed
66 * to the 'foo_is_valid()' function will return 0.
67 * - SPECENUM_COUNT: a name for the maximum enumeration number plus 1. For
68 * enums where every element from 0 to the maximum is defined, this is the
69 * number of elements in the enum. This value is suitable to size an array
70 * indexed by the enum. It can not be used in combination with
71 * SPECENUM_BITWISE. SPECENUM_is_valid() will return the invalid element
72 * for it.
74 * SPECENUM_VALUE%dNAME, SPECENUM_ZERONAME, SPECENUM_COUNTNAME: Can be used
75 * to bind a string to the particular enumerator to be returned by
76 * SPECENUM_name(), etc. If not defined, the default name for 'FOO_FIRST'
77 * is '"FOO_FIRST"'. A name can be qualified. The qualification will only
78 * be used for its translation. The returned name will be unqualified. To
79 * mark a name as translatable use N_().
81 * SPECENUM_NAMEOVERRIDE: call callback function foo_name_cb(enum foo),
82 * defined by specnum user, to get name of the enum value. If the function
83 * returns NULL, compiled in names are used.
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.
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);
97 * enum foo foo_begin(void);
98 * enum foo foo_end(void);
99 * enum foo foo_next(enum foo);
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 *));
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"
115 * static const char *strings[] = {
116 * "TEST1", "test3", "fghdf", NULL
117 * };
118 * enum test e;
119 * int i;
121 * log_verbose("enum test [%d; %d]%s",
122 * test_min(), test_max(), test_bitwise ? " bitwise" : "");
124 * for (e = test_begin(); e != test_end(); e = test_next(e)) {
125 * log_verbose("Value %d is %s", e, test_name(e));
128 * for (i = 0; strings[i]; i++) {
129 * e = test_by_name(strings[i], mystrcasecmp);
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]);
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
147 ''')
149 def make_macros(file):
150 file.write('''
151 #ifdef __cplusplus
152 extern "C" {
153 #endif /* __cplusplus */
155 /* Utility */
156 #include "fcintl.h" /* translation */
157 #include "log.h" /* fc_assert. */
158 #include "support.h" /* bool type. */
160 #ifndef SPECENUM_NAME
161 #error Must define a SPECENUM_NAME to use this header
162 #endif
164 #define SPECENUM_PASTE_(x, y) x ## y
165 #define SPECENUM_PASTE(x, y) SPECENUM_PASTE_(x, y)
167 #define SPECENUM_STRING_(x) #x
168 #define SPECENUM_STRING(x) SPECENUM_STRING_(x)
170 #define SPECENUM_FOO(suffix) SPECENUM_PASTE(SPECENUM_NAME, suffix)
172 #ifndef SPECENUM_INVALID
173 #define SPECENUM_INVALID ((enum SPECENUM_NAME) -1)
174 #endif
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 */
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 */
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_BITVECTOR")
214 def make_enum(file):
215 file.write('''
216 /* Enumeration definition. */
217 enum SPECENUM_NAME {
218 #ifdef SPECENUM_ZERO
219 SPECENUM_ZERO = 0,
220 #endif
221 ''')
223 for i in range(max_enum_values):
224 file.write('''
225 #ifdef SPECENUM_VALUE%d
226 SPECENUM_VALUE%d = SPECENUM_VALUE(%d),
227 # ifndef SPECENUM_MIN_VALUE
228 # define SPECENUM_MIN_VALUE SPECENUM_VALUE%d
229 # endif
230 # ifdef SPECENUM_MAX_VALUE
231 # undef SPECENUM_MAX_VALUE
232 # endif
233 # define SPECENUM_MAX_VALUE SPECENUM_VALUE%d
234 # ifdef SPECENUM_SIZE
235 # undef SPECENUM_SIZE
236 # endif
237 # define SPECENUM_SIZE (%d + 1)
238 #endif /* SPECENUM_VALUE%d */
239 '''%(i,i,i,i,i,i,i))
241 file.write('''
242 #ifdef SPECENUM_COUNT
243 SPECENUM_COUNT = (SPECENUM_MAX_VALUE + 1),
244 #endif /* SPECENUM_COUNT */
246 ''')
248 macros.append("SPECENUM_COUNT")
249 for i in range(max_enum_values):
250 macros.append("SPECENUM_VALUE%d"%i)
252 def make_is_bitwise(file):
253 file.write('''
254 /**************************************************************************
255 Returns TRUE if this enumeration is in bitwise mode.
256 **************************************************************************/
257 fc__attribute((const))
258 static inline bool SPECENUM_FOO(_is_bitwise)(void)
260 #ifdef SPECENUM_BITWISE
261 return TRUE;
262 #else
263 return FALSE;
264 #endif
266 ''')
268 def make_min(file):
269 file.write('''
270 /**************************************************************************
271 Returns the value of the minimal enumerator.
272 **************************************************************************/
273 fc__attribute((const))
274 static inline enum SPECENUM_NAME SPECENUM_FOO(_min)(void)
276 return SPECENUM_MIN_VALUE;
278 ''')
280 def make_max(file):
281 file.write('''
282 /**************************************************************************
283 Returns the value of the maximal enumerator.
284 **************************************************************************/
285 fc__attribute((const))
286 static inline enum SPECENUM_NAME SPECENUM_FOO(_max)(void)
288 return SPECENUM_MAX_VALUE;
290 ''')
292 def make_is_valid(file):
293 file.write('''
294 /**************************************************************************
295 Returns TRUE if this enumerator was defined.
296 **************************************************************************/
297 fc__attribute((const))
298 static inline bool SPECENUM_FOO(_is_valid)(enum SPECENUM_NAME enumerator)
300 #ifdef SPECENUM_BITWISE
301 static const unsigned long valid = (
302 0''')
304 for i in range(max_enum_values):
305 file.write('''
306 # ifdef SPECENUM_VALUE%d
307 | SPECENUM_VALUE%d
308 # endif'''%(i,i))
310 file.write('''
313 FC_STATIC_ASSERT(sizeof(valid) * 8 >= SPECENUM_SIZE,
314 valid_sizeof_check);
316 # ifdef SPECENUM_ZERO
317 if (enumerator == SPECENUM_ZERO) {
318 return TRUE;
320 # endif
321 return (enumerator & valid) == enumerator;
322 #else
323 static const bool valid[] = {''')
325 for i in range(max_enum_values):
326 file.write('''
327 # if %d < SPECENUM_SIZE
328 # ifdef SPECENUM_VALUE%d
329 TRUE,
330 # else
331 FALSE,
332 # endif
333 # endif'''%(i,i))
335 file.write('''
338 FC_STATIC_ASSERT(ARRAY_SIZE(valid) == SPECENUM_SIZE,
339 valid_array_size_check);
341 return (enumerator >= 0
342 && enumerator < ARRAY_SIZE(valid)
343 && valid[enumerator]);
344 #endif /* SPECENUM_BITWISE */
346 ''')
348 def make_invalid(file):
349 file.write('''
350 /**************************************************************************
351 Returns an invalid enumerator value.
352 **************************************************************************/
353 fc__attribute((const))
354 static inline enum SPECENUM_NAME SPECENUM_FOO(_invalid)(void)
356 fc_assert(!SPECENUM_FOO(_is_valid(SPECENUM_INVALID)));
357 return SPECENUM_INVALID;
359 ''')
361 def make_begin(file):
362 file.write('''
363 /**************************************************************************
364 Beginning of the iteration of the enumerators.
365 **************************************************************************/
366 fc__attribute((const))
367 static inline enum SPECENUM_NAME SPECENUM_FOO(_begin)(void)
369 return SPECENUM_FOO(_min)();
371 ''')
373 def make_end(file):
374 file.write('''
375 /**************************************************************************
376 End of the iteration of the enumerators.
377 **************************************************************************/
378 fc__attribute((const))
379 static inline enum SPECENUM_NAME SPECENUM_FOO(_end)(void)
381 return SPECENUM_FOO(_invalid)();
383 ''')
385 def make_next(file):
386 file.write('''
387 /**************************************************************************
388 Find the next valid enumerator value.
389 **************************************************************************/
390 fc__attribute((const))
391 static inline enum SPECENUM_NAME SPECENUM_FOO(_next)(enum SPECENUM_NAME e)
393 do {
394 #ifdef SPECENUM_BITWISE
395 e = (enum SPECENUM_NAME)(e << 1);
396 #else
397 e = (enum SPECENUM_NAME)(e + 1);
398 #endif
400 if (e > SPECENUM_FOO(_max)()) {
401 /* End of the iteration. */
402 return SPECENUM_FOO(_invalid)();
404 } while (!SPECENUM_FOO(_is_valid)(e));
406 return e;
408 ''')
410 def make_name(file):
411 file.write('''
412 #ifdef SPECENUM_NAMEOVERRIDE
413 const char *SPECENUM_FOO(_name_cb)(enum SPECENUM_NAME value);
414 #endif /* SPECENUM_NAMEOVERRIDE */
416 /**************************************************************************
417 Returns the name of the enumerator.
418 **************************************************************************/
419 #ifndef SPECENUM_NAMEOVERRIDE
420 fc__attribute((const))
421 #endif
422 static inline const char *SPECENUM_FOO(_name)(enum SPECENUM_NAME enumerator)
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;
431 #ifdef SPECENUM_NAMEOVERRIDE
433 const char *name = SPECENUM_FOO(_name_cb)(enumerator);
435 if (name != NULL) {
436 return Qn_(name);
439 #endif /* SPECENUM_NAMEOVERRIDE */
441 if (!initialized) {''')
443 for i in range(max_enum_values):
444 file.write('''
445 #if %d < SPECENUM_SIZE
446 # ifndef SPECENUM_VALUE%d
447 names[%d] = NULL;
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)
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;
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
476 # endif
478 size_t i;
480 for (i = 0; i < ARRAY_SIZE(names); i++) {
481 if (1 << i == enumerator) {
482 return names[i];
486 #else
487 if (enumerator >= 0 && enumerator < ARRAY_SIZE(names)) {
488 return names[enumerator];
490 #endif /* SPECENUM_BITWISE */
491 return NULL;
493 ''')
494 macros.append("SPECENUM_COUNTNAME")
495 macros.append("SPECENUM_ZERONAME")
497 def make_by_name(file):
498 file.write('''
499 /**************************************************************************
500 Returns the enumerator for the name or *_invalid() if not found.
501 **************************************************************************/
502 static inline enum SPECENUM_NAME SPECENUM_FOO(_by_name)
503 (const char *name, int (*strcmp_func)(const char *, const char *))
505 enum SPECENUM_NAME e;
506 const char *enum_name;
508 for (e = SPECENUM_FOO(_begin)(); e != SPECENUM_FOO(_end)();
509 e = SPECENUM_FOO(_next)(e)) {
510 if ((enum_name = SPECENUM_FOO(_name)(e))
511 && 0 == strcmp_func(name, enum_name)) {
512 return e;
516 return SPECENUM_FOO(_invalid)();
518 ''')
520 def make_translated_name(file):
521 file.write('''
522 /**************************************************************************
523 Returns the translated name of the enumerator.
524 **************************************************************************/
525 #ifndef SPECENUM_NAMEOVERRIDE
526 fc__attribute((const))
527 #endif
528 static inline const char *
529 SPECENUM_FOO(_translated_name)(enum SPECENUM_NAME enumerator)
531 #ifdef SPECENUM_COUNT
532 static const char *names[SPECENUM_SIZE + 1];
533 #else
534 static const char *names[SPECENUM_SIZE];
535 #endif
536 static bool initialized = FALSE;
538 #ifdef SPECENUM_NAMEOVERRIDE
540 const char *name = SPECENUM_FOO(_name_cb)(enumerator);
542 if (name != NULL) {
543 return Q_(name);
546 #endif /* SPECENUM_NAMEOVERRIDE */
548 if (!initialized) {''')
550 for i in range(max_enum_values):
551 file.write('''
552 #if %d < SPECENUM_SIZE
553 # ifndef SPECENUM_VALUE%d
554 names[%d] = NULL;
555 # elif defined(SPECENUM_VALUE%dNAME)
556 names[%d] = Q_(SPECENUM_VALUE%dNAME);
557 # else
558 names[%d] = SPECENUM_STRING(SPECENUM_VALUE%d);
559 # endif
560 #endif'''%(i,i,i,i,i,i,i,i))
561 macros.append("SPECENUM_VALUE%dNAME"%i)
563 file.write('''
564 #ifdef SPECENUM_COUNT
565 # ifdef SPECENUM_COUNTNAME
566 names[SPECENUM_COUNT] = Q_(SPECENUM_COUNTNAME);
567 # else
568 names[SPECENUM_COUNT] = SPECENUM_STRING(SPECENUM_COUNT);
569 # endif
570 #endif
571 initialized = TRUE;
574 #ifdef SPECENUM_BITWISE
575 # ifdef SPECENUM_ZERO
576 if (enumerator == SPECENUM_ZERO) {
577 # ifdef SPECENUM_ZERONAME
578 return Q_(SPECENUM_ZERONAME);
579 # else
580 return SPECENUM_STRING(SPECENUM_ZERO);
581 # endif
583 # endif
585 size_t i;
587 for (i = 0; i < ARRAY_SIZE(names); i++) {
588 if (1 << i == enumerator) {
589 return names[i];
593 #else
594 if (enumerator >= 0 && enumerator < ARRAY_SIZE(names)) {
595 return names[enumerator];
597 #endif /* SPECENUM_BITWISE */
598 return NULL;
600 ''')
602 def make_bitvector(file):
603 file.write('''
604 #ifdef SPECENUM_BITVECTOR
605 BV_DEFINE(SPECENUM_BITVECTOR, (SPECENUM_MAX_VALUE + 1));
606 #endif /* SPECENUM_BITVECTOR */
607 ''')
609 def make_undef(file):
610 for macro in macros:
611 file.write('''
612 #undef %s'''%macro)
614 file.write('''
615 ''')
617 # Main function.
618 def main():
619 src_dir=os.path.dirname(sys.argv[0])
620 src_root=src_dir+"/.."
621 target_name=src_root+'/'+target
623 output=open(target_name,"w")
625 make_header(output)
626 make_documentation(output)
627 make_macros(output)
628 make_enum(output)
629 make_is_bitwise(output)
630 make_min(output)
631 make_max(output)
632 make_is_valid(output)
633 make_invalid(output)
634 make_begin(output)
635 make_end(output)
636 make_next(output)
637 make_name(output)
638 make_by_name(output)
639 make_translated_name(output)
640 make_bitvector(output)
641 make_undef(output)
643 output.write('''
644 #ifdef __cplusplus
646 #endif /* __cplusplus */
647 ''')
649 output.close()
651 main()