From cd2caf8b530dd106c58352148233baf35aac8a69 Mon Sep 17 00:00:00 2001 From: Alina Lenk Date: Sun, 24 Sep 2023 09:51:51 +0200 Subject: [PATCH] generate_enums.py: Initial script implementation Introduced new code generation script and enums.def syntax, and replaced the enums in common/terrain.h with it. Files aren't automatically generated yet; devs need to manually run the script and check the generated headers into version control. See osdn #48702 Requested and partially contributed by Marko Lindqvist Signed-off-by: Alina Lenk --- ai/Makefile.am | 11 +- ai/classic/Makefile.am | 3 +- ai/default/Makefile.am | 3 +- ai/stub/Makefile.am | 3 +- ai/tex/Makefile.am | 3 +- client/Makefile.am | 3 +- client/agents/Makefile.am | 1 + client/gui-gtk-3.22/Makefile.am | 1 + client/gui-gtk-4.0/Makefile.am | 1 + client/gui-qt/Makefile.am | 1 + client/gui-sdl2/Makefile.am | 1 + client/gui-stub/Makefile.am | 1 + client/luascript/Makefile.am | 1 + common/Makefile.am | 1 + common/aicore/Makefile.am | 9 +- common/networking/Makefile.am | 1 + common/scriptcore/Makefile.am | 1 + common/terrain.h | 117 +---- configure.ac | 1 + gen_headers/Makefile.am | 3 + gen_headers/enums/.gitignore | 1 + gen_headers/enums/Makefile.am | 9 + gen_headers/enums/terrain_enums.def | 93 ++++ gen_headers/enums/terrain_enums_gen.h | 93 ++++ gen_headers/generate_enums.py | 670 ++++++++++++++++++++++++++ meson.build | 2 +- server/Makefile.am | 1 + server/advisors/Makefile.am | 3 +- server/generator/Makefile.am | 3 +- server/savegame/Makefile.am | 3 +- server/scripting/Makefile.am | 1 + tools/Makefile.am | 3 +- tools/fcmp/Makefile.am | 3 +- tools/manual/Makefile.am | 3 +- tools/ruledit/Makefile.am | 3 +- tools/ruleutil/Makefile.am | 3 +- tools/shared/Makefile.am | 3 +- translations/core/POTFILES.in | 1 + 38 files changed, 931 insertions(+), 133 deletions(-) create mode 100644 gen_headers/enums/.gitignore create mode 100644 gen_headers/enums/Makefile.am create mode 100644 gen_headers/enums/terrain_enums.def create mode 100644 gen_headers/enums/terrain_enums_gen.h create mode 100755 gen_headers/generate_enums.py diff --git a/ai/Makefile.am b/ai/Makefile.am index 5cf801ba5f..51ebf7ab36 100644 --- a/ai/Makefile.am +++ b/ai/Makefile.am @@ -18,10 +18,13 @@ if AI_MOD_STATIC_STUB module_dirs += stub endif -AM_CPPFLAGS = -I$(top_srcdir)/utility -I$(top_srcdir)/common \ - -I$(top_srcdir)/common/aicore \ - -I$(top_srcdir)/common/networking \ - -I$(top_srcdir)/dependencies/tinycthread +AM_CPPFLAGS = \ + -I$(top_srcdir)/utility \ + -I$(top_srcdir)/common \ + -I$(top_srcdir)/common/aicore \ + -I$(top_srcdir)/common/networking \ + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums if AI_MODULES if !AI_MOD_STATIC_CLASSIC diff --git a/ai/classic/Makefile.am b/ai/classic/Makefile.am index 5fae17da1b..7f36efba30 100644 --- a/ai/classic/Makefile.am +++ b/ai/classic/Makefile.am @@ -14,7 +14,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/server \ -I$(top_srcdir)/server/advisors \ -I$(top_srcdir)/ai/default \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums da_sources = \ classicai.c \ diff --git a/ai/default/Makefile.am b/ai/default/Makefile.am index dc4f713d6c..fd7ed7b0c6 100644 --- a/ai/default/Makefile.am +++ b/ai/default/Makefile.am @@ -11,7 +11,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/server/advisors \ -I$(top_srcdir)/ai \ -I$(top_srcdir)/server/generator \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums libdefaultai_la_SOURCES = \ aiair.c \ diff --git a/ai/stub/Makefile.am b/ai/stub/Makefile.am index ea218d811c..0a5ef176b4 100644 --- a/ai/stub/Makefile.am +++ b/ai/stub/Makefile.am @@ -10,7 +10,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/utility \ -I$(top_srcdir)/common \ -I$(top_srcdir)/common/networking \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums if AI_MOD_STATIC_STUB libstubai_la_SOURCES = stubai.c diff --git a/ai/tex/Makefile.am b/ai/tex/Makefile.am index 611b68c786..69b8e5c912 100644 --- a/ai/tex/Makefile.am +++ b/ai/tex/Makefile.am @@ -14,7 +14,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/server/ \ -I$(top_srcdir)/server/advisors \ -I$(top_srcdir)/ai/default \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums da_sources = \ texaicity.c \ diff --git a/client/Makefile.am b/client/Makefile.am index 1e45f86e3f..21dec330c4 100644 --- a/client/Makefile.am +++ b/client/Makefile.am @@ -60,7 +60,8 @@ AM_CPPFLAGS = \ -I$(srcdir)/agents \ $(CLIENT_CFLAGS) $(SOUND_CFLAGS) \ -I$(top_srcdir)/dependencies/cvercmp \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums AM_LIBTOOLFLAGS = --preserve-dup-deps diff --git a/client/agents/Makefile.am b/client/agents/Makefile.am index 23641d3176..d02bf6d0df 100644 --- a/client/agents/Makefile.am +++ b/client/agents/Makefile.am @@ -11,6 +11,7 @@ AM_CPPFLAGS = \ -I$(srcdir)/../include \ -I$(top_srcdir)/utility \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(CLIENT_CFLAGS) libagents_la_SOURCES = \ diff --git a/client/gui-gtk-3.22/Makefile.am b/client/gui-gtk-3.22/Makefile.am index 57586f973e..fcd92599cc 100644 --- a/client/gui-gtk-3.22/Makefile.am +++ b/client/gui-gtk-3.22/Makefile.am @@ -12,6 +12,7 @@ AM_CPPFLAGS = \ -I$(srcdir)/../agents \ -I$(srcdir)/../luascript \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(gui_gtk3_22_cflags) $(SOUND_CFLAGS) libgui_gtk3_22_la_SOURCES = \ diff --git a/client/gui-gtk-4.0/Makefile.am b/client/gui-gtk-4.0/Makefile.am index 2ffc02c236..5a3328c3a4 100644 --- a/client/gui-gtk-4.0/Makefile.am +++ b/client/gui-gtk-4.0/Makefile.am @@ -12,6 +12,7 @@ AM_CPPFLAGS = \ -I$(srcdir)/../agents \ -I$(srcdir)/../luascript \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(gui_gtk4_cflags) $(SOUND_CFLAGS) libgui_gtk4_la_SOURCES = \ diff --git a/client/gui-qt/Makefile.am b/client/gui-qt/Makefile.am index e52d258d58..6a92c18603 100644 --- a/client/gui-qt/Makefile.am +++ b/client/gui-qt/Makefile.am @@ -17,6 +17,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/networking \ -I$(srcdir)/../agents \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(gui_qt_cppflags) $(SOUND_CFLAGS) AM_CFLAGS = $(gui_qt_cflags) diff --git a/client/gui-sdl2/Makefile.am b/client/gui-sdl2/Makefile.am index 56ca89b5bf..ce46f42b13 100644 --- a/client/gui-sdl2/Makefile.am +++ b/client/gui-sdl2/Makefile.am @@ -11,6 +11,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/networking \ -I$(srcdir)/../agents \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(gui_sdl2_cflags) libgui_sdl2_la_SOURCES = \ diff --git a/client/gui-stub/Makefile.am b/client/gui-stub/Makefile.am index cc00241e53..1a5cde870e 100644 --- a/client/gui-stub/Makefile.am +++ b/client/gui-stub/Makefile.am @@ -9,6 +9,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/aicore \ -I$(top_srcdir)/common/networking \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ -I$(top_srcdir)/common $(gui_stub_cflags) libgui_stub_la_SOURCES = \ diff --git a/client/luascript/Makefile.am b/client/luascript/Makefile.am index b0aa13abf0..0a70c57b90 100644 --- a/client/luascript/Makefile.am +++ b/client/luascript/Makefile.am @@ -11,6 +11,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/scriptcore \ -I$(top_srcdir)/client \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(LUA_CFLAGS) $(LUASQL_CFLAGS) $(TOLUA_CFLAGS) # tolua_client_gen.[ch] are now distributed to aid in cross-compiling. diff --git a/common/Makefile.am b/common/Makefile.am index a395594946..e45752ec55 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -10,6 +10,7 @@ AM_CPPFLAGS = \ -I$(srcdir)/networking \ -I$(srcdir)/scriptcore \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(MAPIMG_WAND_CFLAGS) $(JANSSON_CFLAGS) libfreeciv_la_SOURCES = \ diff --git a/common/aicore/Makefile.am b/common/aicore/Makefile.am index e93da8dbec..13ae9b2d62 100644 --- a/common/aicore/Makefile.am +++ b/common/aicore/Makefile.am @@ -2,8 +2,13 @@ noinst_LTLIBRARIES = libaicore.la -AM_CPPFLAGS = -I$(top_srcdir)/utility -I.. -I$(top_srcdir)/common \ - -I$(top_srcdir)/common/networking -I$(top_srcdir)/dependencies/tinycthread +AM_CPPFLAGS = \ + -I$(top_srcdir)/utility \ + -I.. \ + -I$(top_srcdir)/common \ + -I$(top_srcdir)/common/networking \ + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums libaicore_la_SOURCES = \ aiactions.c \ diff --git a/common/networking/Makefile.am b/common/networking/Makefile.am index ccd88ecc7c..21a15e8986 100644 --- a/common/networking/Makefile.am +++ b/common/networking/Makefile.am @@ -8,6 +8,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common \ -I$(top_srcdir)/common/aicore \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(JANSSON_CFLAGS) libfcivnetwork_la_SOURCES = \ diff --git a/common/scriptcore/Makefile.am b/common/scriptcore/Makefile.am index 162d467ff2..975e695d20 100644 --- a/common/scriptcore/Makefile.am +++ b/common/scriptcore/Makefile.am @@ -9,6 +9,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/aicore \ -I$(top_srcdir)/common/networking \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(LUA_CFLAGS) $(LUASQL_CFLAGS) $(TOLUA_CFLAGS) # tolua_[common_a|common_z|game]_gen.[ch] are now distributed to aid in diff --git a/common/terrain.h b/common/terrain.h index c505ab21d4..978c055945 100644 --- a/common/terrain.h +++ b/common/terrain.h @@ -26,6 +26,11 @@ extern "C" { #include "name_translation.h" #include "unittype.h" +/* gen_headers/enums */ +#include "terrain_enums_gen.h" + +#define MAX_NUM_USER_TER_FLAGS (TER_USER_LAST - TER_USER_1 + 1) + struct base_type; struct strvec; /* Actually defined in "utility/string_vector.h". */ struct rgbcolor; @@ -63,118 +68,6 @@ struct resource_type { * Used in the network protocol. */ #define MAX_NUM_TERRAINS (96) -/* Used in the network protocol. */ -#define SPECENUM_NAME terrain_class -#define SPECENUM_VALUE0 TC_LAND -/* TRANS: terrain class: used adjectivally */ -#define SPECENUM_VALUE0NAME N_("Land") -#define SPECENUM_VALUE1 TC_OCEAN -/* TRANS: terrain class: used adjectivally */ -#define SPECENUM_VALUE1NAME N_("Oceanic") -#define SPECENUM_COUNT TC_COUNT -#include "specenum_gen.h" - -/* Types of alterations available to terrain. - * This enum is only used in the effects system; the relevant information - * is encoded in other members of the terrain structure. - * - * Used in the network protocol. */ -#define SPECENUM_NAME terrain_alteration -/* Can build irrigation without changing terrain */ -#define SPECENUM_VALUE0 TA_CAN_IRRIGATE -/* TRANS: this and following strings may rarely be presented to the player - * in ruleset help text, to denote the set of terrains which can be altered - * in a particular way */ -#define SPECENUM_VALUE0NAME N_("CanIrrigate") -/* Can build mine without changing terrain */ -#define SPECENUM_VALUE1 TA_CAN_MINE -#define SPECENUM_VALUE1NAME N_("CanMine") -/* Can build roads and/or railroads */ -#define SPECENUM_VALUE2 TA_CAN_ROAD -#define SPECENUM_VALUE2NAME N_("CanRoad") -/* Can build military base */ -#define SPECENUM_VALUE3 TA_CAN_BASE -#define SPECENUM_VALUE3NAME N_("CanBase") -/* Can place extras with infrapoints */ -#define SPECENUM_VALUE4 TA_CAN_PLACE -#define SPECENUM_VALUE4NAME N_("CanPlace") -#define SPECENUM_COUNT TA_COUNT -#include "specenum_gen.h" - -/* Used in the network protocol. */ -#define SPECENUM_NAME terrain_flag_id -/* No barbarians summoned on this terrain. */ -#define SPECENUM_VALUE0 TER_NO_BARBS -/* TRANS: this and following strings are 'terrain flags', which may rarely - * be presented to the player in ruleset help text */ -#define SPECENUM_VALUE0NAME N_("NoBarbs") -/* No cities on this terrain. */ -#define SPECENUM_VALUE1 TER_NO_CITIES -#define SPECENUM_VALUE1NAME N_("NoCities") -/* Players will start on this terrain type. */ -#define SPECENUM_VALUE2 TER_STARTER -#define SPECENUM_VALUE2NAME N_("Starter") -/* Terrains with this type can have road with "River" flag on them. */ -#define SPECENUM_VALUE3 TER_CAN_HAVE_RIVER -#define SPECENUM_VALUE3NAME N_("CanHaveRiver") -/*this tile is not safe as coast, (all ocean / ice) */ -#define SPECENUM_VALUE4 TER_UNSAFE_COAST -#define SPECENUM_VALUE4NAME N_("UnsafeCoast") -/* Fresh water terrain */ -#define SPECENUM_VALUE5 TER_FRESHWATER -#define SPECENUM_VALUE5NAME N_("FreshWater") -/* Map generator does not place this terrain */ -#define SPECENUM_VALUE6 TER_NOT_GENERATED -#define SPECENUM_VALUE6NAME N_("NotGenerated") -/* Units on this terrain are not generating or subject to zoc */ -#define SPECENUM_VALUE7 TER_NO_ZOC -#define SPECENUM_VALUE7NAME N_("NoZoc") -/* Borders on this terrain are not blocking unit movement */ -#define SPECENUM_VALUE8 TER_ENTER_BORDERS -#define SPECENUM_VALUE8NAME N_("EnterBorders") -/* Ice-covered terrain (affects minimap) */ -#define SPECENUM_VALUE9 TER_FROZEN -#define SPECENUM_VALUE9NAME N_("Frozen") -#define SPECENUM_VALUE10 TER_USER_1 -#define SPECENUM_VALUE11 TER_USER_2 -#define SPECENUM_VALUE12 TER_USER_3 -#define SPECENUM_VALUE13 TER_USER_4 -#define SPECENUM_VALUE14 TER_USER_5 -#define SPECENUM_VALUE15 TER_USER_6 -#define SPECENUM_VALUE16 TER_USER_7 -#define SPECENUM_VALUE17 TER_USER_8 -#define SPECENUM_VALUE18 TER_USER_9 -#define SPECENUM_VALUE19 TER_USER_LAST -#define SPECENUM_NAMEOVERRIDE -#define SPECENUM_BITVECTOR bv_terrain_flags -#include "specenum_gen.h" - -#define MAX_NUM_USER_TER_FLAGS (TER_USER_LAST - TER_USER_1 + 1) - -#define SPECENUM_NAME mapgen_terrain_property -#define SPECENUM_VALUE0 MG_MOUNTAINOUS -#define SPECENUM_VALUE0NAME "mountainous" -#define SPECENUM_VALUE1 MG_GREEN -#define SPECENUM_VALUE1NAME "green" -#define SPECENUM_VALUE2 MG_FOLIAGE -#define SPECENUM_VALUE2NAME "foliage" -#define SPECENUM_VALUE3 MG_TROPICAL -#define SPECENUM_VALUE3NAME "tropical" -#define SPECENUM_VALUE4 MG_TEMPERATE -#define SPECENUM_VALUE4NAME "temperate" -#define SPECENUM_VALUE5 MG_COLD -#define SPECENUM_VALUE5NAME "cold" -#define SPECENUM_VALUE6 MG_FROZEN -#define SPECENUM_VALUE6NAME "frozen" -#define SPECENUM_VALUE7 MG_WET -#define SPECENUM_VALUE7NAME "wet" -#define SPECENUM_VALUE8 MG_DRY -#define SPECENUM_VALUE8NAME "dry" -#define SPECENUM_VALUE9 MG_OCEAN_DEPTH -#define SPECENUM_VALUE9NAME "ocean_depth" -#define SPECENUM_COUNT MG_COUNT -#include "specenum_gen.h" - /* * This struct gives data about each terrain type. There are many ways * it could be extended. diff --git a/configure.ac b/configure.ac index 792a184a30..78d544316f 100644 --- a/configure.ac +++ b/configure.ac @@ -1965,6 +1965,7 @@ AC_CONFIG_FILES([Makefile tools/ruleutil/Makefile tools/shared/Makefile gen_headers/Makefile + gen_headers/enums/Makefile translations/Makefile translations/core/Makefile.in translations/nations/Makefile.in diff --git a/gen_headers/Makefile.am b/gen_headers/Makefile.am index 5543e462a8..d4e6a612f5 100644 --- a/gen_headers/Makefile.am +++ b/gen_headers/Makefile.am @@ -1,6 +1,9 @@ ## Process this file with automake to produce Makefile.in +SUBDIRS = enums + EXTRA_DIST = \ + generate_enums.py \ generate_version_header.sh \ liblua_config.h.in \ freeciv_config.h.in \ diff --git a/gen_headers/enums/.gitignore b/gen_headers/enums/.gitignore new file mode 100644 index 0000000000..10a7e8d6c7 --- /dev/null +++ b/gen_headers/enums/.gitignore @@ -0,0 +1 @@ +/Makefile.in diff --git a/gen_headers/enums/Makefile.am b/gen_headers/enums/Makefile.am new file mode 100644 index 0000000000..a12a025083 --- /dev/null +++ b/gen_headers/enums/Makefile.am @@ -0,0 +1,9 @@ +## Process this file with automake to produce Makefile.in + +ENUMS_GEN = terrain_enums_gen.h + +EXTRA_DIST = \ + terrain_enums.def \ + $(ENUMS_GEN) + +BUILT_SOURCES = $(ENUMS_GEN) diff --git a/gen_headers/enums/terrain_enums.def b/gen_headers/enums/terrain_enums.def new file mode 100644 index 0000000000..4a67bfa112 --- /dev/null +++ b/gen_headers/enums/terrain_enums.def @@ -0,0 +1,93 @@ +# Specenum definitions for common/terrain.h +# See gen_headers/generate_enums.py for syntax + +# When modifying this, remember to regenerate the header. +# From the gen_headers/enums directory, this can be done with +# $ ../generate_enums.py terrain_enums_gen.h terrain_enums.def + +/* Used in the network protocol. */ +enum terrain_class + count TC_COUNT +values + /* TRANS: terrain class: used adjectivally */ + TC_LAND N_("Land") + /* TRANS: terrain class: used adjectivally */ + TC_OCEAN N_("Oceanic") +end + +/* Types of alterations available to terrain. + * This enum is only used in the effects system; the relevant information + * is encoded in other members of the terrain structure. + * + * Used in the network protocol. */ +enum terrain_alteration + count TA_COUNT +values + /* Can build irrigation without changing terrain */ + /* TRANS: this and following strings may rarely be presented to the player + * in ruleset help text, to denote the set of terrains which can be altered + * in a particular way */ + TA_CAN_IRRIGATE N_("CanIrrigate") + /* Can build mine without changing terrain */ + TA_CAN_MINE N_("CanMine") + /* Can build roads and/or railroads */ + TA_CAN_ROAD N_("CanRoad") + /* Can build military base */ + TA_CAN_BASE N_("CanBase") + /* Can place extras with infrapoints */ + TA_CAN_PLACE N_("CanPlace") +end + +/* Used in the network protocol. */ +enum terrain_flag_id + name-override + bitvector bv_terrain_flags +values + /* No barbarians summoned on this terrain. */ + /* TRANS: this and following strings are 'terrain flags', which may rarely + * be presented to the player in ruleset help text */ + TER_NO_BARBS N_("NoBarbs") + /* No cities on this terrain. */ + TER_NO_CITIES N_("NoCities") + /* Players will start on this terrain type. */ + TER_STARTER N_("Starter") + /* Terrains with this type can have road with "River" flag on them. */ + TER_CAN_HAVE_RIVER N_("CanHaveRiver") + /* this tile is not safe as coast, (all ocean / ice) */ + TER_UNSAFE_COAST N_("UnsafeCoast") + /* Fresh water terrain */ + TER_FRESHWATER N_("FreshWater") + /* Map generator does not place this terrain */ + TER_NOT_GENERATED N_("NotGenerated") + /* Units on this terrain are not generating or subject to zoc */ + TER_NO_ZOC N_("NoZoc") + /* Borders on this terrain are not blocking unit movement */ + TER_ENTER_BORDERS N_("EnterBorders") + /* Ice-covered terrain (affects minimap) */ + TER_FROZEN N_("Frozen") + TER_USER_1 + TER_USER_2 + TER_USER_3 + TER_USER_4 + TER_USER_5 + TER_USER_6 + TER_USER_7 + TER_USER_8 + TER_USER_9 + TER_USER_LAST +end + +enum mapgen_terrain_property + count MG_COUNT +values + MG_MOUNTAINOUS "mountainous" + MG_GREEN "green" + MG_FOLIAGE "foliage" + MG_TROPICAL "tropical" + MG_TEMPERATE "temperate" + MG_COLD "cold" + MG_FROZEN "frozen" + MG_WET "wet" + MG_DRY "dry" + MG_OCEAN_DEPTH "ocean_depth" +end diff --git a/gen_headers/enums/terrain_enums_gen.h b/gen_headers/enums/terrain_enums_gen.h new file mode 100644 index 0000000000..7fb341afc8 --- /dev/null +++ b/gen_headers/enums/terrain_enums_gen.h @@ -0,0 +1,93 @@ + /************************************************************************** + * THIS FILE WAS GENERATED * + * Script: gen_headers/generate_enums.py * + * Input: gen_headers/enums/terrain_enums.def * + * DO NOT CHANGE THIS FILE * + **************************************************************************/ + +#ifndef FC__TERRAIN_ENUMS_GEN_H +#define FC__TERRAIN_ENUMS_GEN_H + + +#define SPECENUM_NAME terrain_class +#define SPECENUM_VALUE0 TC_LAND +#define SPECENUM_VALUE0NAME N_("Land") +#define SPECENUM_VALUE1 TC_OCEAN +#define SPECENUM_VALUE1NAME N_("Oceanic") +#define SPECENUM_COUNT TC_COUNT +#include "specenum_gen.h" + +#define SPECENUM_NAME terrain_alteration +#define SPECENUM_VALUE0 TA_CAN_IRRIGATE +#define SPECENUM_VALUE0NAME N_("CanIrrigate") +#define SPECENUM_VALUE1 TA_CAN_MINE +#define SPECENUM_VALUE1NAME N_("CanMine") +#define SPECENUM_VALUE2 TA_CAN_ROAD +#define SPECENUM_VALUE2NAME N_("CanRoad") +#define SPECENUM_VALUE3 TA_CAN_BASE +#define SPECENUM_VALUE3NAME N_("CanBase") +#define SPECENUM_VALUE4 TA_CAN_PLACE +#define SPECENUM_VALUE4NAME N_("CanPlace") +#define SPECENUM_COUNT TA_COUNT +#include "specenum_gen.h" + +#define SPECENUM_NAME terrain_flag_id +#define SPECENUM_VALUE0 TER_NO_BARBS +#define SPECENUM_VALUE0NAME N_("NoBarbs") +#define SPECENUM_VALUE1 TER_NO_CITIES +#define SPECENUM_VALUE1NAME N_("NoCities") +#define SPECENUM_VALUE2 TER_STARTER +#define SPECENUM_VALUE2NAME N_("Starter") +#define SPECENUM_VALUE3 TER_CAN_HAVE_RIVER +#define SPECENUM_VALUE3NAME N_("CanHaveRiver") +#define SPECENUM_VALUE4 TER_UNSAFE_COAST +#define SPECENUM_VALUE4NAME N_("UnsafeCoast") +#define SPECENUM_VALUE5 TER_FRESHWATER +#define SPECENUM_VALUE5NAME N_("FreshWater") +#define SPECENUM_VALUE6 TER_NOT_GENERATED +#define SPECENUM_VALUE6NAME N_("NotGenerated") +#define SPECENUM_VALUE7 TER_NO_ZOC +#define SPECENUM_VALUE7NAME N_("NoZoc") +#define SPECENUM_VALUE8 TER_ENTER_BORDERS +#define SPECENUM_VALUE8NAME N_("EnterBorders") +#define SPECENUM_VALUE9 TER_FROZEN +#define SPECENUM_VALUE9NAME N_("Frozen") +#define SPECENUM_VALUE10 TER_USER_1 +#define SPECENUM_VALUE11 TER_USER_2 +#define SPECENUM_VALUE12 TER_USER_3 +#define SPECENUM_VALUE13 TER_USER_4 +#define SPECENUM_VALUE14 TER_USER_5 +#define SPECENUM_VALUE15 TER_USER_6 +#define SPECENUM_VALUE16 TER_USER_7 +#define SPECENUM_VALUE17 TER_USER_8 +#define SPECENUM_VALUE18 TER_USER_9 +#define SPECENUM_VALUE19 TER_USER_LAST +#define SPECENUM_NAMEOVERRIDE +#define SPECENUM_BITVECTOR bv_terrain_flags +#include "specenum_gen.h" + +#define SPECENUM_NAME mapgen_terrain_property +#define SPECENUM_VALUE0 MG_MOUNTAINOUS +#define SPECENUM_VALUE0NAME "mountainous" +#define SPECENUM_VALUE1 MG_GREEN +#define SPECENUM_VALUE1NAME "green" +#define SPECENUM_VALUE2 MG_FOLIAGE +#define SPECENUM_VALUE2NAME "foliage" +#define SPECENUM_VALUE3 MG_TROPICAL +#define SPECENUM_VALUE3NAME "tropical" +#define SPECENUM_VALUE4 MG_TEMPERATE +#define SPECENUM_VALUE4NAME "temperate" +#define SPECENUM_VALUE5 MG_COLD +#define SPECENUM_VALUE5NAME "cold" +#define SPECENUM_VALUE6 MG_FROZEN +#define SPECENUM_VALUE6NAME "frozen" +#define SPECENUM_VALUE7 MG_WET +#define SPECENUM_VALUE7NAME "wet" +#define SPECENUM_VALUE8 MG_DRY +#define SPECENUM_VALUE8NAME "dry" +#define SPECENUM_VALUE9 MG_OCEAN_DEPTH +#define SPECENUM_VALUE9NAME "ocean_depth" +#define SPECENUM_COUNT MG_COUNT +#include "specenum_gen.h" + +#endif /* FC__TERRAIN_ENUMS_GEN_H */ diff --git a/gen_headers/generate_enums.py b/gen_headers/generate_enums.py new file mode 100755 index 0000000000..3536731c07 --- /dev/null +++ b/gen_headers/generate_enums.py @@ -0,0 +1,670 @@ +#!/usr/bin/env python3 + +# +# Freeciv - Copyright (C) 2023 +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# + +# This script runs under Python 3.6 and up. Please leave it so. +# It might also run under older versions, but no such guarantees are made. + +"""generate_enums.py - code generation script for Freeciv specenums + +This script takes enum definition files and turns them into a C header +defining those enums using specenum_gen.h, which is in turn generated by +utility/generate_specenum.py - the plan is to eventually, once all current +uses of specenum_gen.h have been migrated to this script, fold both scripts +into one. If you're reading this years into the future, it's hopefully +because you're looking through the version history, and *not* because this +convoluted system is still in place. + +See specenum_gen.h or generate_specenum.py for what exactly the various +options mean. + +# Definition file syntax + +Like packets.def, the enum defs can use +# Python-style EOL comments, +// C++-style EOL comments, +/* and C-style comments, + * which can span multiple lines. */ + +Each definition file consists of zero or more enum definitions, which take +the following form, where are placeholders: + +enum + +values + + +# ... +end + +The following are supported: +- bitwise +- zero + (requires bitwise) +- count + (cannot be used with bitwise) +- invalid +- name-override +- name-updater +- bitvector + (cannot be used with bitwise) +""" + + +import re +import argparse +import sys +from pathlib import Path +from contextlib import contextmanager, ExitStack +from itertools import takewhile, zip_longest + +import typing + + +###################### Parsing Command Line Arguments ###################### + +def file_path(s: "str | Path") -> Path: + """Parse the given path and check basic validity.""" + path = Path(s) + + if path.is_reserved() or not path.name: + raise ValueError(f"not a valid file path: {s!r}") + if path.exists() and not path.is_file(): + raise ValueError(f"not a file: {s!r}") + + return path + + +class ScriptConfig: + """Contains configuration info for the script's execution, along with + functions closely tied to that configuration""" + + def_paths: "list[Path]" + """Paths to definition files, in load order""" + out_path: Path + """Path to the output file""" + + verbose: bool + """Whether to enable verbose logging""" + lazy_overwrite: bool + """Whether to lazily overwrite output files""" + + @staticmethod + def get_argparser() -> argparse.ArgumentParser: + """Construct an argument parser for a packet generation script""" + parser = argparse.ArgumentParser( + description = "Generate specenum header files", + add_help = False, # we'll add a help option explicitly + ) + + # Argument groups + # Note the order: + # We want the path arguments to show up *first* in the help text + + paths = parser.add_argument_group( + "Input and output paths", + "The following parameters decide which files to read and write.", + ) + + script = parser.add_argument_group( + "Script configuration", + "The following parameters change how the script operates.", + ) + + # Individual arguments + # Note the order: + # We want the path arguments to show up *last* in the usage summary + + script.add_argument("-h", "--help", action = "help", + help = "show this help message and exit") + + script.add_argument("-v", "--verbose", action = "store_true", + help = "enable log messages during code generation") + + script.add_argument("--lazy-overwrite", action = "store_true", + help = "only overwrite output files when their" + " contents actually changed") + + paths.add_argument("out_path", type = file_path, + help = "path to write the header file to") + paths.add_argument("def_paths", metavar = "def_path", + nargs = "+", type = file_path, + help = "paths to your enums.def files") + + return parser + + def __init__(self, args: "typing.Sequence[str] | None" = None): + __class__.get_argparser().parse_args(args, namespace = self) + + def log_verbose(self, *args): + """Print the given arguments iff verbose logging is enabled""" + if self.verbose: + print(*args) + + @property + def _root_path(self) -> "Path | None": + """Root Freeciv path, if we can find it.""" + path = Path(__file__).resolve() + root = path.parent.parent + if path != root / "gen_headers" / "generate_enums.py": + self.log_verbose("Warning: couldn't find Freeciv root path") + return None + return root + + def _relative_path(self, path: Path) -> Path: + """Find the relative path from the Freeciv root to the given path. + Return the path unmodified if it's outside the Freeciv root, or if + the Freeciv root could not be found.""" + root = self._root_path + if root is not None: + try: + return path.resolve().relative_to(root) + except ValueError: + self.log_verbose(f"Warning: path {path} outside of Freeciv root") + return path + + @property + def _script_path(self) -> Path: + """Relative path of the executed script. Under normal circumstances, + this will be common/generate_packets.py, but it may differ when this + module is imported from another script.""" + return self._relative_path(Path(sys.argv[0])) + + def _write_disclaimer(self, f: typing.TextIO): + f.write(f"""\ + /************************************************************************** + * THIS FILE WAS GENERATED * + * Script: {self._script_path!s:63} * +""") + + for path in self.def_paths: + f.write(f"""\ + * Input: {self._relative_path(path)!s:63} * +""") + + f.write("""\ + * DO NOT CHANGE THIS FILE * + **************************************************************************/ + +""") + + @contextmanager + def _wrap_header(self, file: typing.TextIO, header_name: str) -> typing.Iterator[None]: + """Add multiple inclusion protection to the given file""" + name = f"FC__{header_name.upper()}_H" + file.write(f"""\ +#ifndef {name} +#define {name} + +""") + + yield + + file.write(f"""\ + +#endif /* {name} */ +""") + + @contextmanager + def open_write(self, path: "str | Path") -> typing.Iterator[typing.TextIO]: + """Open a file for writing, write a disclaimer and add multiple + inclusion protection. + + If enabled, lazily overwrites the given file.""" + path = Path(path) # no-op if path is already a Path object + self.log_verbose(f"writing {path}") + + wrap_header = re.sub(r"[^\w]+", "_", path.name.split(".")[0]).upper() + + with ExitStack() as stack: + if self.lazy_overwrite: + file = stack.enter_context(self.lazy_overwrite_open(path)) + else: + file = stack.enter_context(path.open("w")) + + self._write_disclaimer(file) + stack.enter_context(self._wrap_header(file, wrap_header)) + + yield file + self.log_verbose(f"done writing {path}") + + @contextmanager + def lazy_overwrite_open(self, path: "str | Path", suffix: str = ".tmp") -> typing.Iterator[typing.TextIO]: + """Open a file for writing, but only actually overwrite it if the new + content differs from the old content. + + This creates a temporary file by appending the given suffix to the given + file path. In the event of an error, this temporary file might remain in + the target file's directory.""" + + path = Path(path) + tmp_path = path.with_name(path.name + suffix) + + # if tmp_path already exists, assume it's left over from a previous, + # failed run and can be overwritten without trouble + self.log_verbose(f"lazy: using {tmp_path}") + with tmp_path.open("w") as file: + yield file + + if path.exists() and files_equal(tmp_path, path): + self.log_verbose("lazy: no change, deleting...") + tmp_path.unlink() + else: + self.log_verbose("lazy: content changed, replacing...") + tmp_path.replace(path) + + +################### General helper functions and classes ################### + +def files_equal(path_a: "str | Path", path_b: "str | Path") -> bool: + """Return whether the contents of two text files are identical""" + with Path(path_a).open() as file_a, Path(path_b).open() as file_b: + return all(a == b for a, b in zip_longest(file_a, file_b)) + + +class EnumValue: + """Represents a single specenum constant (identifier and name).""" + + LINE_PATTERN = re.compile(r""" + ^\s* + (\w+) # enum value identifier + (?: + \s+ + ( # name (optional) - only capture + \S+(?:\s+\S+)* # the part starting and ending with + ) # non-whitespace + )? + \s*$ + """, re.VERBOSE) + """Matches an enum value definition. + + Groups: + - identifier + - (optional) name""" + + identifier: str + """The identifier (SPECENUM_VALUEx) for this constant""" + + name: "str | None" + """The name (SPECENUM_VALUExNAME) for this constant""" + + @classmethod + def parse(cls, line: str) -> "EnumValue": + """Parse a single line defining an enum value""" + mo = cls.LINE_PATTERN.fullmatch(line) + if mo is None: + raise ValueError(f"invalid enum value definition: {line!r}") + return cls(mo.group(1), mo.group(2)) + + def __init__(self, identifier: str, name: "str | None"): + self.identifier = identifier + self.name = name + + def code_parts_custom(self, value: str) -> typing.Iterable[str]: + """Yield code defining this enum value for either a regular value, + or special values like COUNT and ZERO.""" + yield f"""\ +#define SPECENUM_{value} {self.identifier} +""" + if self.name is not None: + yield f"""\ +#define SPECENUM_{value}NAME {self.name} +""" + + def code_parts_value(self, index: int) -> typing.Iterable[str]: + """Yield code defining this SPECENUM_VALUE""" + yield from self.code_parts_custom(f"VALUE{index}") + + +# NB: avoid confusion with Python's Enum class +class Specenum: + """Represents a single enum definition (i.e. a single use of specenum_gen.h)""" + + VALUES_SEP_PATTERN = re.compile(r"^\s*values\s*$") + """Matches the "values" line separating options from enum values""" + + OPTION_PATTERN = re.compile(r""" + ^\s* + ([\w-]+) # option name + (?: + \s+ + ( # arguments (optional) - only capture + \S+(?:\s+\S+)* # the part starting and ending with + ) # non-whitespace + )? + \s*$ + """, re.VERBOSE) + """Matches a single enum option. + + Groups: + - the option name + - (optional) the option's arguments""" + + name: str + """The SPECENUM_NAME of this enum""" + + bitwise: bool = False + """Whether this enum is bitwise""" + + zero: "EnumValue | None" = None + """The SPECENUM_ZERO identifier and name, if given. + Only valid if this enum is bitwise.""" + + count: "EnumValue | None" = None + """The SPECENUM_COUNT identifier and name, if given""" + + invalid: "str | None" = None + """The SPECENUM_INVALID value, if given""" + + name_override: bool = False + """Whether to request name override calls""" + + name_updater: bool = False + """Whether to request name update calls""" + + bitvector: "str | None" = None + """The SPECENUM_BITVECTOR name, if given""" + + values: "list[EnumValue]" + """The values of this enum""" + + def __init__(self, name: str, lines: typing.Iterable[str]): + self.name = name + + lines_iter = iter(lines) + + for option_text in takewhile( + lambda line: __class__.VALUES_SEP_PATTERN.fullmatch(line) is None, + lines_iter, + ): + mo = __class__.OPTION_PATTERN.fullmatch(option_text) + if mo is None: + raise ValueError(f"malformed option for enum {self.name}: {option_text.strip()!r}") + + option: str = mo.group(1) + arg: "str | None" = mo.group(2) + + if option == "bitwise": + if self.bitwise: + raise ValueError(f"duplicate option {option!r} for enum {self.name}") + if arg is not None: + raise ValueError(f"option {option!r} for enum {self.name} does not support an argument") + self.bitwise = True + elif option == "zero": + if self.zero is not None: + raise ValueError(f"duplicate option {option!r} for enum {self.name}") + if arg is None: + raise ValueError(f"option {option!r} for enum {self.name} requires an argument") + self.zero = EnumValue.parse(arg) + elif option == "count": + if self.count is not None: + raise ValueError(f"duplicate option {option!r} for enum {self.name}") + if arg is None: + raise ValueError(f"option {option!r} for enum {self.name} requires an argument") + self.count = EnumValue.parse(arg) + elif option == "invalid": + if self.invalid is not None: + raise ValueError(f"duplicate option {option!r} for enum {self.name}") + if arg is None: + raise ValueError(f"option {option!r} for enum {self.name} requires an argument") + self.invalid = arg + elif option == "name-override": + if self.name_override: + raise ValueError(f"duplicate option {option!r} for enum {self.name}") + if arg is not None: + raise ValueError(f"option {option!r} for enum {self.name} does not support an argument") + self.name_override = True + elif option == "name-updater": + if self.name_updater: + raise ValueError(f"duplicate option {option!r} for enum {self.name}") + if arg is not None: + raise ValueError(f"option {option!r} for enum {self.name} does not support an argument") + self.name_updater = True + elif option == "bitvector": + if self.bitvector is not None: + raise ValueError(f"duplicate option {option!r} for enum {self.name}") + if arg is None: + raise ValueError(f"option {option!r} for enum {self.name} requires an argument") + self.bitvector = arg + else: + raise ValueError(f"unrecognized option {option!r} for enum {self.name}") + + # check validity + if self.zero and not self.bitwise: + raise ValueError(f"option 'zero' for enum {self.name} requires option 'bitwise'") + if self.count and self.bitwise: + raise ValueError(f"option 'count' conflicts with option 'bitwise' for enum {self.name}") + if self.bitvector and self.bitwise: + raise ValueError(f"option 'bitvector' conflicts with option 'bitwise' for enum {self.name}") + + self.values = [EnumValue.parse(line) for line in lines] + + def code_parts(self) -> typing.Iterable[str]: + """Yield code defining this enum""" + yield f"""\ +#define SPECENUM_NAME {self.name} +""" + + if self.bitwise: + yield f"""\ +#define SPECENUM_BITWISE +""" + if self.zero is not None: + yield from self.zero.code_parts_custom("ZERO") + + for i, value in enumerate(self.values): + yield from value.code_parts_value(i) + + if self.count is not None: + yield from self.count.code_parts_custom("COUNT") + if self.invalid is not None: + yield f"""\ +#define SPECENUM_INVALID {self.invalid} +""" + if self.name_override: + yield f"""\ +#define SPECENUM_NAMEOVERRIDE +""" + if self.name_updater: + yield f"""\ +#define SPECENUM_NAME_UPDATER +""" + if self.bitvector is not None: + yield f"""\ +#define SPECENUM_BITVECTOR {self.bitvector} +""" + yield f"""\ +#include "specenum_gen.h" +""" + + +class EnumsDefinition(typing.Iterable[Specenum]): + """Represents an entire enums definition file""" + + COMMENT_START_PATTERN = re.compile(r""" + ^\s* # strip initial whitespace + (.*?) # actual content; note the reluctant quantifier + \s* # note: this can cause quadratic backtracking + (?: # match a potential comment + (?: # EOL comment (or just EOL) + (?: + (?:\#|//) # opening # or // + .* + )? + ) | (?: # block comment ~> capture remaining text + /\* # opening /* + [^*]* # text that definitely can't end the block comment + (.*) # remaining text, might contain a closing */ + ) + ) + (?:\n)? # optional newline in case those aren't stripped + $ + """, re.VERBOSE) + """Used to clean lines when not starting inside a block comment. Finds + the start of a block comment, if it exists. + + Groups: + - Actual content before any comment starts; stripped. + - Remaining text after the start of a block comment. Not present if no + block comment starts on this line.""" + + COMMENT_END_PATTERN = re.compile(r""" + ^ + .*? # comment; note the reluctant quantifier + (?: # end of block comment ~> capture remaining text + \*/ # closing */ + \s* # strip whitespace after comment + (.*) # remaining text + )? + (?:\n)? # optional newline in case those aren't stripped + $ + """, re.VERBOSE) + """Used to clean lines when starting inside a block comment. Finds the + end of a block comment, if it exists. + + Groups: + - Remaining text after the end of the block comment; lstripped. Not + present if the block comment doesn't end on this line.""" + + ENUM_HEADER_PATTERN = re.compile(r""" + ^\s* + enum + \s+ + (\w+) # enum name + \s* + (?:;\s*)? # optional semicolon (nothing comes after it yet) + $ + """, re.VERBOSE) + """Matches the header line of an enum definition + + Groups: + - enum name""" + + ENUM_END_PATTERN = re.compile(r"^\s*end\s*$") + """Matches the "end" line terminating an enum definition""" + + cfg: ScriptConfig + """Configuration used for code generated from this definition""" + + enums: "list[Specenum]" + """List of all defined enums, in order of definition""" + + enums_by_name: "dict[str, Specenum]" + """Maps enum names to their enum definition""" + + @classmethod + def _clean_lines(cls, lines: typing.Iterable[str]) -> typing.Iterator[str]: + """Strip comments and leading/trailing whitespace from the given + lines. If a block comment starts in one line and ends in another, + the remaining parts are joined together and yielded as one line.""" + inside_comment = False + parts = [] + + for line in lines: + while line: + if inside_comment: + # currently inside a block comment ~> look for */ + mo = cls.COMMENT_END_PATTERN.fullmatch(line) + assert mo, repr(line) + # If the group wasn't captured (None), we haven't found + # a */ to end our comment ~> still inside_comment + # Otherwise, group captured remaining line content + line, = mo.groups(None) + inside_comment = line is None + else: + mo = cls.COMMENT_START_PATTERN.fullmatch(line) + assert mo, repr(line) + # If the second group wasn't captured (None), there is + # no /* to start a block comment ~> not inside_comment + part, line = mo.groups(None) + inside_comment = line is not None + if part: parts.append(part) + + if (not inside_comment) and parts: + # when ending a line outside a block comment, yield what + # we've accumulated + yield " ".join(parts) + parts.clear() + + if inside_comment: + raise ValueError("EOF while scanning block comment") + + def parse_lines(self, lines: typing.Iterable[str]): + """Parse the given lines as type and packet definitions.""" + self.parse_clean_lines(self._clean_lines(lines)) + + def parse_clean_lines(self, lines: typing.Iterable[str]): + """Parse the given lines as specenum definitions. Comments + and blank lines must already be removed beforehand.""" + # hold on to the iterator itself + lines_iter = iter(lines) + for line in lines_iter: + mo = self.ENUM_HEADER_PATTERN.fullmatch(line) + if mo is not None: + enum_name, = mo.groups("") + + if enum_name in self.enums_by_name: + raise ValueError("Duplicate enum name: " + enum_name) + + enum = Specenum( + enum_name, + takewhile( + lambda line: self.ENUM_END_PATTERN.fullmatch(line) is None, + lines_iter, # advance the iterator used by this for loop + ), + ) + + self.enums.append(enum) + self.enums_by_name[enum_name] = enum + continue + + raise ValueError("Unexpected line: " + line) + + def __init__(self, cfg: ScriptConfig): + self.cfg = cfg + self.enums = [] + self.enums_by_name = {} + + def __iter__(self) -> typing.Iterator[Specenum]: + return iter(self.enums) + + +########################### Writing output files ########################### + +def write_header(path: "str | Path | None", enums: EnumsDefinition): + """Write a header with the defined enums to the given path""" + if path is None: + return + with enums.cfg.open_write(path) as output_h: + for specenum in enums: + output_h.write("\n") + output_h.writelines(specenum.code_parts()) + + +def main(raw_args: "typing.Sequence[str] | None" = None): + """Main function. Read the given arguments, or the command line + arguments if raw_args is not given, and run the specenum code generation + script accordingly.""" + script_args = ScriptConfig(raw_args) + + enums = EnumsDefinition(script_args) + for path in script_args.def_paths: + with path.open() as input_file: + enums.parse_lines(input_file) + + write_header(script_args.out_path, enums) + + +if __name__ == "__main__": + main() diff --git a/meson.build b/meson.build index b01e924b89..45aae3ea17 100644 --- a/meson.build +++ b/meson.build @@ -988,7 +988,7 @@ common_inc = include_directories(cross_inc_path, lua_inc_path, 'dependencies/luasql/src', 'dependencies/tinycthread', 'dependencies/tolua-5.2/include', 'dependencies/cvercmp', 'utility', 'common', 'common/networking', 'common/scriptcore', - 'common/aicore') + 'common/aicore', 'gen_headers/enums') server_inc = [common_inc, include_directories('server', 'server/advisors', 'server/scripting', 'server/generator', 'server/savegame', diff --git a/server/Makefile.am b/server/Makefile.am index eb39816b31..f55e98169a 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -18,6 +18,7 @@ AM_CPPFLAGS = \ -I$(srcdir)/savegame \ -I$(srcdir)/scripting \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(LUA_CFLAGS) \ $(FCDB_MYSQL_CFLAGS) $(FCDB_POSTGRES_CFLAGS) $(FCDB_SQLITE3_CFLAGS) diff --git a/server/advisors/Makefile.am b/server/advisors/Makefile.am index 9634485b0f..c65d639017 100644 --- a/server/advisors/Makefile.am +++ b/server/advisors/Makefile.am @@ -8,7 +8,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/aicore \ -I$(top_srcdir)/common/networking \ -I$(top_srcdir)/ai \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums libadvisors_la_SOURCES = \ advbuilding.c \ diff --git a/server/generator/Makefile.am b/server/generator/Makefile.am index 1b091e5a88..0b014426be 100644 --- a/server/generator/Makefile.am +++ b/server/generator/Makefile.am @@ -8,7 +8,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/networking \ -I$(top_srcdir)/server \ -I$(top_srcdir)/server/generator \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums libgenerator_la_SOURCES = \ mapgen.c \ diff --git a/server/savegame/Makefile.am b/server/savegame/Makefile.am index 045e33af34..8438716c45 100644 --- a/server/savegame/Makefile.am +++ b/server/savegame/Makefile.am @@ -12,7 +12,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/server/generator \ -I$(top_srcdir)/server/scripting \ -I$(top_srcdir)/ai \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums libsavegame_la_SOURCES = \ savecompat.c \ diff --git a/server/scripting/Makefile.am b/server/scripting/Makefile.am index 1784b70757..2a3218c756 100644 --- a/server/scripting/Makefile.am +++ b/server/scripting/Makefile.am @@ -15,6 +15,7 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/server/savegame \ -I$(top_srcdir)/ai \ -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums \ $(FCDB_MYSQL_CFLAGS) $(FCDB_POSTGRES_CFLAGS) $(FCDB_SQLITE_CFLAGS) \ $(LUA_CFLAGS) $(LUASQL_CFLAGS) $(TOLUA_CFLAGS) diff --git a/tools/Makefile.am b/tools/Makefile.am index 634f8a949d..ea7fa0abe6 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -27,7 +27,8 @@ common_cppflags = \ -I$(top_srcdir)/server \ -I$(top_srcdir)/tools/ruleutil \ -I$(top_srcdir)/tools/shared \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums AM_CPPFLAGS = $(common_cppflags) diff --git a/tools/fcmp/Makefile.am b/tools/fcmp/Makefile.am index cc7f129377..7d46c90c84 100644 --- a/tools/fcmp/Makefile.am +++ b/tools/fcmp/Makefile.am @@ -33,7 +33,8 @@ common_cppflags = \ -I$(top_srcdir)/client/include \ -I$(top_srcdir)/tools/ruleutil \ -I$(top_srcdir)/tools/shared \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums AM_CPPFLAGS = $(common_cppflags) diff --git a/tools/manual/Makefile.am b/tools/manual/Makefile.am index 6dbf21d648..0cb2b8bc35 100644 --- a/tools/manual/Makefile.am +++ b/tools/manual/Makefile.am @@ -12,7 +12,8 @@ common_cppflags = \ -I$(top_srcdir)/client \ -I$(top_srcdir)/client/include \ -I$(top_srcdir)/tools/shared \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums AM_CPPFLAGS = $(common_cppflags) diff --git a/tools/ruledit/Makefile.am b/tools/ruledit/Makefile.am index 549a0f58f6..773611d4b6 100644 --- a/tools/ruledit/Makefile.am +++ b/tools/ruledit/Makefile.am @@ -19,7 +19,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/server \ -I$(top_srcdir)/tools/shared \ -I$(top_srcdir)/tools/ruleutil \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums freeciv_ruledit_CXXFLAGS = $(ruledit_cxxflags) diff --git a/tools/ruleutil/Makefile.am b/tools/ruleutil/Makefile.am index b26db00dd9..e63f1f422a 100644 --- a/tools/ruleutil/Makefile.am +++ b/tools/ruleutil/Makefile.am @@ -8,7 +8,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/aicore \ -I$(top_srcdir)/common/networking \ -I$(top_srcdir)/server \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums libfcruleutil_la_SOURCES = \ comments.c \ diff --git a/tools/shared/Makefile.am b/tools/shared/Makefile.am index bcc945ba3e..d3ebbf4b17 100644 --- a/tools/shared/Makefile.am +++ b/tools/shared/Makefile.am @@ -8,7 +8,8 @@ AM_CPPFLAGS = \ -I$(top_srcdir)/common/aicore \ -I$(top_srcdir)/common/networking \ -I$(top_srcdir)/server \ - -I$(top_srcdir)/dependencies/tinycthread + -I$(top_srcdir)/dependencies/tinycthread \ + -I$(top_srcdir)/gen_headers/enums libtoolsshared_la_SOURCES = \ tools_fc_interface.c \ diff --git a/translations/core/POTFILES.in b/translations/core/POTFILES.in index e103b6b0be..8909723880 100644 --- a/translations/core/POTFILES.in +++ b/translations/core/POTFILES.in @@ -372,6 +372,7 @@ data/scenarios/japan.sav data/scenarios/north_america.sav data/scenarios/europe_1900_WWI.sav data/scenarios/tutorial.sav +gen_headers/enums/terrain_enums.def translations/Strings.txt tools/ruleup.c tools/fcmp/download.c -- 2.34.1