File: console.h

package info (click to toggle)
freespace2 3.7.4%2Brepack-1.1
  • links: PTS, VCS
  • area: non-free
  • in suites: bullseye
  • size: 22,268 kB
  • sloc: cpp: 393,535; ansic: 4,106; makefile: 1,091; xml: 181; sh: 137
file content (279 lines) | stat: -rw-r--r-- 9,914 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
#ifndef _CONSOLE_H
#define _CONSOLE_H
/*
 * z64555's debug console, created for the FreeSpace Source Code project
 *
 * Portions of this source code are based on works by Volition, Inc. circa 1999. You may not sell or otherwise
 * commercially exploit the source or things you created based on the source.
 */

/**
 * @file console.h
 * @brief An overhauled/updated debug console to allow monitoring, testing, and general debugging of new features.
 *
 * @details
 * Of key interest is Volition's DCF macro, which adds the function argument to the available command list in the
 * debug console. These functions may be defined in the .cpp file that they are related to, but it is recommended 
 * that they be in their own .cpp if they have multiple sub-arguments (ex: Git has its sub-arguments delimited by
 * a pair of -'s, or --)
 */

#include "debugconsole/consoleparse.h"
#include "globalincs/pstypes.h"
#include "globalincs/vmallocator.h"

#define DC_MAX_COMMANDS 300

class debug_command;

/**
 * @def DCF
 * 
 * @brief The potent DCF macro, used to define new debug commands for the console.
 * 
 * @param function_name[in] The name of the function, as shown in the debug console
 * @param help_txt[in] The short-help text, as shown as listed from the 'help' command
 *
 * @details 
 * Each DCF is responsible for getting data from the debug console's command line. The parsing functions for the
 * command line have been set up to have similar syntax and usage as the parselo commands. (see consoleparse.h)
 * Most, if not all, argument and subcommand strings should be parsed by the dc_optional_string functions.
 * Usage example:
 * DCF(toggle_it, "description")
 * {
 *     if (dc_optional_string_either("help", "--help")) {
 *         dc_printf("Usage: sample. Toggles This_var on/off\n");
 *
 *     } else if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {
 *         dc_printf("This_var is %s\n", (This_var ? "ON" : "OFF"));
 *
 *     } else {
 *         This_var = !This_var;
 *
 *     }
 * }
 *
 *  In the console, the command would be listed as 'toggle_it', and dcf_help would display it as:
 *      toggle_it  - Usage: sample. Toggles This_var on/off.
 *  Note: The only allowed function type is a void fn( void )
 */
#define DCF(function_name, help_text)	\
		void dcf_##function_name();	\
		debug_command dcmd_##function_name(#function_name, help_text, dcf_##function_name);	\
		void dcf_##function_name()

/**
 *  @def Shortcut for debug commands that toggle a bool, such as Show_lightning
 *  
 *  @param [in] function_name Name of the function, as shown in the debug console
 *  @param [in] bool_variable Name of the variable to allow toggling.
 */
#define DCF_BOOL(function_name, bool_variable)	\
	void dcf_##function_name();		\
	debug_command dcmd_##function_name(#function_name, "Sets or toggles the boolean: "#bool_variable, dcf_##function_name );	\
	void dcf_##function_name() {	\
		bool bool_tmp = bool_variable != 0;	\
		if (dc_optional_string_either("help", "--help")) {	\
				dc_printf( "Usage: %s [bool]\nSets %s to true or false.  If nothing passed, then toggles it.\n", #function_name, #bool_variable );	\
				return;		\
		}	\
		if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {	\
			dc_printf("%s = %s\n", #bool_variable, (bool_variable ? "TRUE" : "FALSE"));		\
			return;		\
		}	\
		if (!dc_maybe_stuff_boolean(&bool_tmp)) {	\
			if (bool_variable != 0) \
				bool_variable = 0; \
			else \
				bool_variable = 1;	\
		} else { \
			if (bool_tmp) \
				bool_variable = 1; \
			else \
				bool_variable = 0;	\
		}	\
		dc_printf("%s set to %s\n", #bool_variable, (bool_variable != 0 ? "TRUE" : "FALSE"));	\
	}


/**
 *  @def Same as DCF_BOOL, but with custom help strings
 *  
 *  @param [in] function_name Name of the function, as shown in the debug console
 *  @param [in] bool_variable Name of the variable to allow toggling.
 */
#define DCF_BOOL2(function_name, bool_variable, short_help, long_help)	\
	void dcf_##function_name();		\
	debug_command dcmd_##function_name(#function_name, short_help, dcf_##function_name );	\
	void dcf_##function_name() {	\
		if (dc_optional_string_either("help", "--help")) {	\
			dc_printf( #long_help );	\
				return;		\
		}	\
		if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {	\
			dc_printf("%s = %s\n", #function_name, (bool_variable ? "TRUE" : "FALSE"));		\
			return;		\
		}	\
		if (!dc_maybe_stuff_boolean(&bool_variable)) {	\
			bool_variable = !bool_variable;	\
		}	\
	}

 /**
  * @def Shortcut for single-variable setters/monitors
  *
  * @param [in] function_name
  * @param [in] float_variable
  * @param [in] short_help
  */
 #define DCF_FLOAT(function_name, float_variable, short_help)	\
	void dcf_##function_name();		\
	debug_command dcmd_##function_name(#function_name, short_help, dcf_##function_name );	\
	void dcf_##function_name() {	\
		float value;	\
		if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {	\
			dc_printf("%s = %f\n", #float_variable, float_variable);		\
			return;		\
		}	\
		dc_stuff_float(&value);	\
		float_variable = value;	\
		dc_printf("%s set to %f\n", #float_variable, float_variable);	\
	}

 /**
  * @def Shortcut for single-variable setters/monitors with lower/upper bounds clamping
  *
  * @param [in] function_name
  * @param [in] float_variable
  * @param [in] lower_bounds
  * @param [in] upper_bounds
  * @param [in] short_help
  */
 #define DCF_FLOAT2(function_name, float_variable, lower_bounds, upper_bounds, short_help)	\
	void dcf_##function_name();		\
	debug_command dcmd_##function_name(#function_name, short_help, dcf_##function_name );	\
	void dcf_##function_name() {	\
		float value;	\
		if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {	\
			dc_printf("%s = %f\n", #float_variable, float_variable);		\
			return;		\
		}	\
		dc_stuff_float(&value);	\
		CLAMP(float_variable, lower_bounds, upper_bounds);	\
		float_variable = value;	\
		dc_printf("%s set to %f\n", #float_variable, float_variable);	\
	}

 /**
  * @def Shortcut for single-variable setters/monitors
  *
  * @param [in] function_name
  * @param [in] int_variable
  * @param [in] short_help
  */
 #define DCF_INT(function_name, int_variable, short_help)	\
	void dcf_##function_name();		\
	debug_command dcmd_##function_name(#function_name, short_help, dcf_##function_name );	\
	void dcf_##function_name() {	\
		int value;	\
		if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {	\
			dc_printf("%s = %i\n", #int_variable, int_variable);		\
			return;		\
		}	\
		dc_stuff_int(&value);	\
		int_variable = value;	\
		dc_printf("%s set to %i\n", #int_variable, int_variable);	\
	}

 /**
  * @def Shortcut for single-variable setters/monitors with lower/upper bounds clamping
  *
  * @param [in] function_name
  * @param [in] int_variable
  * @param [in] lower_bounds
  * @param [in] upper_bounds
  * @param [in] short_help
  */
 #define DCF_INT2(function_name, int_variable, lower_bounds, upper_bounds, short_help)	\
	void dcf_##function_name();		\
	debug_command dcmd_##function_name(#function_name, short_help, dcf_##function_name );	\
	void dcf_##function_name() {	\
		int value;	\
		if (dc_optional_string_either("status", "--status") || dc_optional_string_either("?", "--?")) {	\
			dc_printf("%s = %i\n", #int_variable, int_variable);		\
			return;		\
		}	\
		dc_stuff_int(&value);	\
		CLAMP(int_variable, lower_bounds, upper_bounds);	\
		int_variable = value;	\
		dc_printf("%s set to %i\n", #int_variable, int_variable);	\
	}

/**
 *  @class debug_command
 *  @brief Class to aggregate a debug command with its name (as shown in the console) and short help.
 *  
 *  @details
 *  Note: Long help, as evoked by '<command> help', should be handled by the function itself. It is recommended
 *  that arguments that have sub-arguments be in their own function, so as to aide in organization and to keep the
 *  size of the command function down.
 */
class debug_command {
public:
	const char *name;		//!< The name of the command, as shown in the debug console
	const char *help;		//!< The short help string, as shown by 'help <command>'
	void (*func)();	//!< Pointer to the function that to run when this command is evoked

	debug_command();

	/**
	* @brief Adds a debug command to the debug_commands map, if it isn't in there already.
	*
	* @details The DCF macro more or less guarantees that a command won't be duplicated on compile time. But no harm in
	*   some extra caution.
	*/
	debug_command(const char *name, const char *help, void (*func)());
};

/**
 * @class is_dcmd
 * @brief Predicate class used to search for a dcmd by name
 */
class is_dcmd {
public:
	const char *name;

	is_dcmd(const char *_name) : name(_name) {}

	bool operator() (debug_command* dcmd)
	{
		return (strcmp(name, dcmd->name) == 0);
	}
};

extern bool Dc_debug_on;
extern int dc_commands_size;
extern uint lastline;
extern SCP_string dc_command_str;	// The rest of the command line, from the end of the last processed arg on.

/**
 * @brief   Pauses the output of a command and allows user to scroll through the output history.
 *
 * @details Returns true if user has pressed Esc, returns false otherwise. Use this in your function to (safely?) break
 *     out of the loop it's presumably in.
 */
bool dc_pause_output(void);

/**
 * @brief Prints the given char string to the debug console
 * @details See the doc for std::printf() for formating and more details
 */
void dc_printf(const char *format, ...);

/**
 * @brief Opens and processes the debug console. (Blocking call)
 * @details TODO: Make this a non-blocking call so that the game can still run while the debug console is open.
 */
void debug_console(void (*func)(void) = NULL);

#endif // _CONSOLE_H