Well, here I am, typing another blog post… And the reason is because I have stumbled upon X Macros while poking around in C++, and to my great surprise, they also work with Arma 3 config. Never heard of them? Ok then, let’s go!

So what is X Macro? In short, it is C preprocessor macro that can repeat your sub-macro for every item of your list of params. Confused? Let’s see some real examples.

// Action format // ACTION(name, priority, text, show, showWindow, hideOnUse, shortcut, textDefault, textSimple) #define LIST_OF_ACTIONS \ ACTION(None, 0, "", 1, 0, 1, "", "", "")\ ACTION(HookCargo, 3, "Hook", 1, 0, 1, "", "", "")\ ACTION(UnhookCargo, 3, "Unhook", 1, 0, 1, "", "", "")\ class CfgActions { #define ACTION(NAME, PRIORITY, TEXT, SHOW, SHOW_WINDOW, HIDE_ON_USE, SHORTCUT, TEXT_DEFAULT, TEXT_SIMPLE)\ #NAME, actions[] = { LIST_OF_ACTIONS }; #undef ACTION #define ACTION(NAME, PRIORITY, TEXT, SHOW, SHOW_WINDOW, HIDE_ON_USE, SHORTCUT, TEXT_DEFAULT, TEXT_SIMPLE)\ TEXT, texts[] = { LIST_OF_ACTIONS }; #undef ACTION #define ACTION(NAME, PRIORITY, TEXT, SHOW, SHOW_WINDOW, HIDE_ON_USE, SHORTCUT, TEXT_DEFAULT, TEXT_SIMPLE)\ class NAME\ {\ priority = PRIORITY;\ text = TEXT;\ show = SHOW;\ showWindow = SHOW_WINDOW;\ hideOnUse = HIDE_ON_USE;\ shortcut = SHORTCUT;\ textDefault = TEXT_DEFAULT;\ textSimple = TEXT_SIMPLE;\ }; LIST_OF_ACTIONS #undef ACTION };

Here I took 3 actions from real and existing CfgActions just to test it. The key here is the #define LIST_OF_ACTIONS macro. The list consists of param containers, which could be added or removed easily at any time. The list contains 3 actions: None, HookCargo and UnhookCargo. From the comment I left above you can see the order and meaning of the params (Notice the back slash ‘\’, needed it you want to start new line).

Param container has a name, I called it ACTION, but it could be anything, another common use is X (as in X Macro). It is important later in the code to stick with the name you chose. Then we have the body of CfgActions which will be populated with sub-macros.

Now, the next line is where the magic starts as this is where sub-macro is constructed. It starts with #define and finishes with #undef (because otherwise preprocessor complains of macro redefinition). The name is the same as the name of param container (ACTION in this case) and here is where you can give your params the names which will be replaced in sub-macro with the actual param values. Obviously these names should be different from the rest of the sub-macro, i.e if macro has property priority = … then you cannot also use exactly priority for the param name.

So the 1st sub-macro we have is #NAME, and # means the value will be put in “”. The coma , at the end is part of this sub-macro. When macro expands, it will look like this:

"None", "HookCargo", "UnhookCargo",

This list will appear in place of LIST_OF_ACTIONS. That’s it, as simple as that. The final look of the first sub-macro expanded:

actions[] = { "None", "HookCargo", "UnhookCargo", };

Don’t mind the last coma, it is OK with preprocessor and is ignored. Same would happen with 2nd and 3rd sub-macros and the final result of the whole X Macro expansion is this (maybe not as pretty formatted):

class CfgActions { actions[] = {"None","HookCargo","UnhookCargo"}; texts[] = {"","Hook","Unhook"}; class None { priority = 0; text = ""; show = 1; showWindow = 0; hideOnUse = 1; shortcut = ""; textDefault = ""; textSimple = ""; }; class HookCargo { priority = 3; text = "Hook"; show = 1; showWindow = 0; hideOnUse = 1; shortcut = ""; textDefault = ""; textSimple = ""; }; class UnhookCargo { priority = 3; text = "Unhook"; show = 1; showWindow = 0; hideOnUse = 1; shortcut = ""; textDefault = ""; textSimple = ""; }; };

You could try this for yourself. Create a mission in editor, create description.ext and paste the same X Macro in it. Save, preview and then type utils 2 in debug console. In the opened config viewer choose mission config from Select Base menu and untick Classes Only.

So apart from auto cycling through the list of your params and populating whatever list you created saving time, one of the greatest advantages of this functionality is that it allows to create custom collections of elements like we did with actions[] and texts[]. This could prove very useful for searching configs. The indexes and order of the elements are preserved across the lists, so if you search actions[] and find “HookCargo”, rest assured you could simply find out that the text for this action is “Hook”, because it will be at the same index in texts[] array.

If you are interested to see how this X business could be useful in C++, I have a small example code here.

Take care,
And thanks to everyone who donated!

KK