maug
Quick and dirty C mini-augmentation library.
Loading...
Searching...
No Matches
marge.h
1
2#ifndef MARGE_H
3#define MARGE_H
4
5#include <merror.h>
6
7#ifdef MAUG_NO_CLI
8
9# define maug_add_arg( arg, arg_sz, help, help_sz, arg_cb, data ) (0)
10
11#else
12
19/*
20 * | ::MAUG_CLI_SIGIL | Specify the sigil prepended to command-line args. |
21 * | MAUG_NO_CLI_SZ | Disable ::MAUG_CLI_SZ command-line args. |
22 */
23
24#ifndef MAUG_CLI_SIGIL_SZ
25# define MAUG_CLI_SIGIL_SZ 1
26#endif /* !MAUG_CLI_SIGIL_SZ */
27
28#if !defined( MAUG_CLI_SIGIL ) && defined( MAUG_OS_WIN )
29# define MAUG_CLI_SIGIL "/"
30#elif !defined( MAUG_CLI_SIGIL ) && defined( MAUG_OS_DOS )
31# define MAUG_CLI_SIGIL "/"
32#elif !defined( MAUG_CLI_SIGIL ) && defined( MAUG_OS_DOS_REAL )
33# define MAUG_CLI_SIGIL "/"
34#elif !defined( MAUG_CLI_SIGIL )
39# define MAUG_CLI_SIGIL "-"
40#endif /* !MAUG_CLI_SIGIL */
41
42#define MAUG_CLI_ARG_C_DEFAULT -1
43
44#ifndef MAUG_CLI_ARG_LIST_SZ_MAX
45# define MAUG_CLI_ARG_LIST_SZ_MAX 20
46#endif /* !MAUG_CLI_ARG_LIST_SZ_MAX */
47
48#ifndef MAUG_CLI_ARG_HELP_SZ_MAX
49# define MAUG_CLI_ARG_HELP_SZ_MAX 127
50#endif /* !MAUG_CLI_ARG_HELP_SZ_MAX */
51
52#ifndef MAUG_CLI_ARG_SZ_MAX
53# define MAUG_CLI_ARG_SZ_MAX 20
54#endif /* !MAUG_CLI_ARG_SZ_MAX */
55
56typedef
57MERROR_RETVAL (*maug_cli_cb)( const char* arg, ssize_t arg_c, void* data );
58
60#define MAUG_CLI( f ) \
61 f( MAUG_CLI_SIGIL "h", 3, "Display help and exit.", maug_cli_h )
62
63int maug_parse_args( int argc, char* argv[] );
64
74 const char* arg, int arg_sz, const char* help, int help_sz,
75 maug_cli_cb arg_cb, void* data );
76
77#ifdef MARGE_C
78
79/* == Global Tables == */
80
81#define MAUG_CLI_ARG_ARG( arg, arg_sz, help, arg_callback ) \
82 arg,
83
84static char g_maug_cli_args[MAUG_CLI_ARG_LIST_SZ_MAX][MAUG_CLI_ARG_SZ_MAX] = {
85 MAUG_CLI( MAUG_CLI_ARG_ARG )
86 ""
87};
88
89#define MAUG_CLI_ARG_SZ( arg, arg_sz, help, arg_callback ) \
90 arg_sz,
91
92static int g_maug_cli_arg_sz[MAUG_CLI_ARG_LIST_SZ_MAX] = {
93 MAUG_CLI( MAUG_CLI_ARG_SZ )
94 0
95};
96
97#define MAUG_CLI_ARG_HELP( arg, arg_sz, help, arg_callback ) \
98 help,
99
100static char g_maug_cli_arg_help[MAUG_CLI_ARG_LIST_SZ_MAX][MAUG_CLI_ARG_HELP_SZ_MAX] = {
101 MAUG_CLI( MAUG_CLI_ARG_HELP )
102 ""
103};
104
105#define MAUG_CLI_ARG_DATA( arg, arg_sz, help, arg_callback ) NULL,
106static void* g_maug_cli_data[MAUG_CLI_ARG_LIST_SZ_MAX] = {
107 MAUG_CLI( MAUG_CLI_ARG_DATA )
108 NULL
109};
110
111#define MAUG_CLI_ARG_CALLED( arg, arg_sz, help, arg_callback ) 0,
112static int g_maug_cli_arg_called[MAUG_CLI_ARG_LIST_SZ_MAX] = {
113 MAUG_CLI( MAUG_CLI_ARG_CALLED )
114 0
115};
116
117/* == Function Definitions = = */
118
119static int maug_cli_h( const char* arg, ssize_t arg_c, void* args ) {
120 int i = 0;
121
122 if( 0 > arg_c ) {
123 /* Just pass by on default case. */
124 return 0;
125 }
126
127 fprintf( stderr, "usage:\n\n" );
128
129 /* Display help for all available options. */
130 while( '\0' != g_maug_cli_args[i][0] ) {
131 fprintf( stderr, "\t%s\t%s\n", g_maug_cli_args[i],
132 g_maug_cli_arg_help[i] );
133 i++;
134 }
135
136 fprintf( stderr, "\n" );
137
138 /* TODO: Coherent error code. */
139 return -1;
140}
141
142/* === */
143
144/* Define these below the built-in callbacks, above. */
145#define MAUG_CLI_ARG_CB( arg, arg_sz, help, arg_callback ) \
146 arg_callback,
147
148maug_cli_cb g_maug_cli_arg_callbacks[MAUG_CLI_ARG_LIST_SZ_MAX] = {
149 MAUG_CLI( MAUG_CLI_ARG_CB )
150 NULL
151};
152
153int maug_parse_args( int argc, char* argv[] ) {
154 int arg_i = 0,
155 const_i = 0,
156 last_i = 0,
157 retval = 0;
158
159 for( arg_i = 1 ; argc > arg_i ; arg_i++ ) {
160 debug_printf( 1, "found arg: %s", argv[arg_i] );
161 const_i = 0;
162 while( '\0' != g_maug_cli_args[const_i][0] ) {
163 if( 0 == strncmp(
164 g_maug_cli_args[const_i],
165 argv[arg_i],
166 g_maug_cli_arg_sz[const_i]
167 ) ) {
168 /* Save this matched index for the next pass. */
169 last_i = const_i;
170
171 /* Increment called count and run the callback. */
172 g_maug_cli_arg_called[const_i]++;
173 retval = g_maug_cli_arg_callbacks[const_i]( argv[arg_i],
174 g_maug_cli_arg_called[const_i], g_maug_cli_data[const_i] );
175 if( MERROR_OK != retval ) {
176 goto cleanup;
177 }
178
179 /* We found a match, so go to the next arg. */
180 break;
181 }
182 const_i++;
183 }
184
185 if( '\0' == g_maug_cli_args[const_i][0] ) {
186 /* No valid arg was found, so we must be passing data to the last one!
187 */
188 g_maug_cli_arg_called[last_i]++;
189 retval = g_maug_cli_arg_callbacks[last_i]( argv[arg_i],
190 g_maug_cli_arg_called[last_i], g_maug_cli_data[last_i] );
191 if( MERROR_OK != retval ) {
192 goto cleanup;
193 }
194 }
195 }
196
197 /* TODO: Run default callbacks for any args not called. */
198 const_i = 0;
199 while( '\0' != g_maug_cli_args[const_i][0] ) {
200 if(
201 0 == g_maug_cli_arg_called[const_i] &&
202 NULL != g_maug_cli_arg_callbacks[const_i]
203 ) {
204 debug_printf( 1, "calling default arg for uncalled \"%s\"...",
205 g_maug_cli_args[const_i] );
206 retval =
207 g_maug_cli_arg_callbacks[const_i](
208 "", MAUG_CLI_ARG_C_DEFAULT, g_maug_cli_data[const_i] );
209 if( MERROR_OK != retval ) {
210 goto cleanup;
211 }
212 }
213 const_i++;
214 }
215
216cleanup:
217
218 return retval;
219}
220
221/* === */
222
224 const char* arg, int arg_sz, const char* help, int help_sz,
225 maug_cli_cb arg_cb, void* data
226) {
227 int slot_idx = 0;
228
229 /* Find empty arg slot. */
230 while(
231 '\0' != g_maug_cli_args[slot_idx][0] &&
232 MAUG_CLI_ARG_LIST_SZ_MAX > slot_idx
233 ) {
234 slot_idx++;
235 }
236
237 /* TODO: Check for duplicate arg. */
238
239 /* Sanity checking and sizing. */
240 if( MAUG_CLI_ARG_LIST_SZ_MAX - 1 <= slot_idx ) {
241 return MERROR_OVERFLOW;
242 }
243
244 if( 0 >= arg_sz ) {
245 arg_sz = maug_strlen( arg );
246 }
247 assert( arg_sz < MAUG_CLI_ARG_SZ_MAX );
248
249 if( 0 >= help_sz ) {
250 help_sz = maug_strlen( help );
251 }
252 assert( help_sz < MAUG_CLI_ARG_HELP_SZ_MAX );
253
254 /* Add arg to arrays. */
255
256 maug_strncpy( g_maug_cli_args[slot_idx], arg, arg_sz );
257 g_maug_cli_args[slot_idx + 1][0] = '\0';
258
259 maug_strncpy( g_maug_cli_arg_help[slot_idx], help, help_sz );
260 g_maug_cli_arg_help[slot_idx + 1][0] = '\0';
261
262 g_maug_cli_arg_sz[slot_idx] = arg_sz;
263 g_maug_cli_arg_sz[slot_idx + 1] = 0;
264
265 g_maug_cli_arg_callbacks[slot_idx] = arg_cb;
266 g_maug_cli_arg_callbacks[slot_idx + 1] = NULL;
267
268 g_maug_cli_arg_called[slot_idx] = 0;
269 g_maug_cli_arg_called[slot_idx + 1] = 0;
270
271 g_maug_cli_data[slot_idx] = data;
272 g_maug_cli_data[slot_idx + 1] = NULL;
273
274 return MERROR_OK;
275}
276
277#endif /* MARGE_C */
278
279 /* maug_cli */
280
281#endif /* MAUG_NO_CLI */
282
283#endif /* MARGE_H */
284
MERROR_RETVAL maug_add_arg(const char *arg, int arg_sz, const char *help, int help_sz, maug_cli_cb arg_cb, void *data)
Add a command-line argument to the built-in parser.
#define MAUG_CLI(f)
Default CLI arguments for all RetroFlat programs.
Definition marge.h:60
int MERROR_RETVAL
Return type indicating function returns a value from this list.
Definition merror.h:19