A metaprogramming utility to generate enumerated constants from plain-text for C and Python.
C's support for enumerated constants is less than stellar. Member values of
enum
don't contain any identifying information at runtime, which makes
employing them as waymarks awkward when parsing textual data. An easy way to
ameliorate this is by ingesting some simple input schema containing enumeration
members and generating a header file which exposes both the enumeration and a
lookup table mapping string values to members.
metang
is a simple implementation of such a program. Its feature-set is basic,
yet allows a user to customize the content of their generated header as they see
fit. The headers that it generates are usable both in data parsing programs in
need of its lookup tables and in production code where only the enumeration
itself is desired.
metang
takes its moniker from the Pokémon of the same name.
> git clone https://github.com/lhearachel/metang.git
> cd metang
> make install
Once installed, verify that you can run the executable:
> metang -v
0.1.1
By default, metang
will install to ~/.local/bin
. If you wish to install it
to a different directory, run make install
with your desired directory as an
argument:
> DESTDIR=path/to/target make install
metang
will install itself into the bin
subdirectory of the given value for
DESTDIR
.
metang
also ships with a meson.build
file to support integration as a Meson
subproject. To add metang
's tooling support to your project, create the
following metang.wrap
file in your subprojects
directory:
[wrap-git]
url = https://github.com/lhearachel/metang.git
; Replace <main> here with a release tag or commit hash, if desired.
revision = main
depth = 1
[provide]
program_names = metang
metang
will generate a C header from some input file with the following
content sections, each of which is surrounded by a corresponding preprocessor
guard:
- An
enum
type definition. - Preprocessor definitions.
- A lookup table mapping enumerators to a string identifier.
To illustrate, suppose that we have the following input listing, fed from standard input:
Bulbasaur
Ivysaur
Venusaur
Charmander
Charmeleon
Charizard
Squirtle
Wartortle
Blastoise
Porygon2
Porygon-Z
Farfetch'd
Mr. Mime
Mime Jr.
metang
will then emit the following to standard output:
/*
* This file was generated by metang; DO NOT MODIFY IT!!
* Base command: enum
* Source file: stdin
* Program options:
*/
#ifndef METANG_STDOUT
#define METANG_STDOUT
#ifdef __cplusplus
extern "C" {
#endif
#ifdef METANG_ENUM
enum stdin {
BULBASAUR = 0,
IVYSAUR = 1,
VENUSAUR = 2,
CHARMANDER = 3,
CHARMELEON = 4,
CHARIZARD = 5,
SQUIRTLE = 6,
WARTORTLE = 7,
BLASTOISE = 8,
PORYGON2 = 9,
PORYGON_Z = 10,
FARFETCHD = 11,
MR_MIME = 12,
MIME_JR = 13,
};
#else
#define BULBASAUR 0
#define IVYSAUR 1
#define VENUSAUR 2
#define CHARMANDER 3
#define CHARMELEON 4
#define CHARIZARD 5
#define SQUIRTLE 6
#define WARTORTLE 7
#define BLASTOISE 8
#define PORYGON2 9
#define PORYGON_Z 10
#define FARFETCHD 11
#define MR_MIME 12
#define MIME_JR 13
#endif /* METANG_ENUM */
#ifdef METANG_LOOKUP
typedef struct entry__stdin {
const long value;
const char *def;
} entry__stdin;
#ifndef METANG_LOOKUP_IMPL
extern const long lengthof__stdin;
extern const entry__stdin lookup__stdin[];
#else
const long lengthof__stdin = 14;
const entry__stdin lookup__stdin[] = {
{ BLASTOISE, "BLASTOISE", },
{ BULBASAUR, "BULBASAUR", },
{ CHARIZARD, "CHARIZARD", },
{ CHARMANDER, "CHARMANDER", },
{ CHARMELEON, "CHARMELEON", },
{ FARFETCHD, "FARFETCHD", },
{ IVYSAUR, "IVYSAUR", },
{ MIME_JR, "MIME_JR", },
{ MR_MIME, "MR_MIME", },
{ PORYGON2, "PORYGON2", },
{ PORYGON_Z, "PORYGON_Z", },
{ SQUIRTLE, "SQUIRTLE", },
{ VENUSAUR, "VENUSAUR", },
{ WARTORTLE, "WARTORTLE", },
};
#endif /* METANG_LOOKUP_IMPL */
#endif /* METANG_LOOKUP */
#ifdef __cplusplus
}
#endif
#endif /* METANG_STDOUT */
The default values in this emission are worth noting:
METANG_
as a prefix on all preprocessor guards. This is a simple default to make output consistent.STDOUT
as the suffix on the inclusion sentinels and leading prefix on the generated symbols. This is adapted from the output file name.stdin
as theenum
tag. This is adapted from the input file name.- A starting index of
0
for the enumeration.
All of these defaults are configurable via program options. As a summary of
available options, metang
's built-in help-text should be sufficient. For
further reading, each of these options has a corresponding example in the
tests
directory to illustrate how its behavior differs from the defaults.
> metang help
metang - Generate enumerated constants from plain-text
Usage: metang COMMAND [OPTIONS] [<FILE>]
Commands:
enum Generate an integral enumeration.
mask Generate a bitmask enumeration.
help Display this help text.
version Display the version number of this program.
Global Options:
-L, --lang <LANG> Generate the enumeration for a target language.
If unspecified, generate for the C language.
Options: c, py
-o, --output <OFILE> Write output to <OFILE>.
If unspecified, write to standard output.
-l, --leader <LEADER> Use <LEADER> as a prefix for generated symbols.
-t, --tag-name <NAME> Use <NAME> as the base tag for enums and lookup
tables.
If unspecified, <NAME> will be derived from the
input file's basename, minus any extension.
-G, --guard <GUARD> Prefix conditional directives with <GUARD>. For
example, in C, this will prefix inclusion guards.
When using the “enum” command, the following additional options are supported:
-a, --append <ENTRY> Append <ENTRY> to the input listing.
-p, --prepend <ENTRY> Prepend <ENTRY> to the input listing.
-n, --start-from <NUMBER> Start enumeration from <NUMBER>.
When using the “mask” command, the user should mind the following:
1. The magic values NONE and ANY are automatically prepended and appended
to user input, respectively. The NONE value is always assigned the value
0; the ANY value is always assigned the sum of all previous mask indices.
2. Overrides on assignment values from user input are not permitted. This is
to ensure that the generated bitmask is contiguous.
3. As a consequence of (1) and (2), overrides to the starting value are not
permitted.
For more detailed reading on the various options, metang
's installation
procedure will install manual page in section 1. You can view this page by
invoking man metang
, as with any other shell-based utility.
metang
can also generate constants-files for Python using the --lang
option
with argument py
:
> metang --lang py
"""
This file was generated by metang; DO NOT MODIFY IT!!
Base command: enum
Source file: stdin
Program options:
--lang py
"""
import enum
class stdin(enum.IntEnum):
BULBASAUR = 0
IVYSAUR = 1
VENUSAUR = 2
CHARMANDER = 3
CHARMELEON = 4
CHARIZARD = 5
SQUIRTLE = 6
WARTORTLE = 7
BLASTOISE = 8
PORYGON2 = 9
PORYGON_Z = 10
FARFETCHD = 11
MR_MIME = 12
MIME_JR = 13
metang
's small size and problem-scope mean that contribution guidelines are
loose. Feel free to file an issue or a pull request!
metang
is free software licensed under the Apache License, version 2.0. For
further details, refer to the included license text.