3 * libneuro, a light weight abstraction of high or lower libraries
4 * and toolkit for applications.
5 * Copyright (C) 2005-2006 Nicholas Niro, Robert Lemay
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 /* the struct type that contains the list of options used
35 * by this application.
36 * TODO find a better name
38 typedef struct LOPTIONS
42 void (*action
)(char *data
);
48 /* struct buffer to keep the input arguments */
49 typedef struct BUFINPUT
52 u8 type
; /* 0 is unknown, 1 is option, 2 is data and 3 is a nest of options */
53 u8 used
; /* if this is 0 it will do an error, with a nest of options, at least
54 one option needs to be invalid to make an error. */
66 static EBUF
*bufinput
; /* buffer of argv */
67 static EBUF
*loptions
; /* Buffer of the list of options */
70 clean_loptions(void *src
)
76 if (!Neuro_EBufIsEmpty(buf
->datas
))
77 Neuro_CleanEBuf(&buf
->datas
);
81 /* printf("cleaning %s\n", buf->string); */
86 /* finds a data option and diminish its presence by 1 */
89 Find_DATA_And_Revoke()
94 ototal = Neuro_GiveEBufCount(loptions) + 1;
98 option = Neuro_GiveEBuf(loptions, ototal);
100 if (option->string == NULL)
109 Push_Data(LOPTIONS
*option
, char *string
)
115 Neuro_CreateEBuf(&option
->datas
);
118 Neuro_AllocEBuf(option
->datas
, sizeof(DATA
*), sizeof(DATA
));
120 dta
= Neuro_GiveCurEBuf(option
->datas
);
127 Handle_Option_Argument(LOPTIONS
*option
, u32 i
, char *input_string
)
133 /* completely useless because the caller of this function filters the strings
134 * and only matches those in loptions (meaning none can in theory have a '='
137 if ((temp
= memchr(input_string
, '=', strlen(input_string
))))
143 /* option->data = &temp[1]; */
144 Push_Data(option
, &temp
[1]);
150 input
= Neuro_GiveEBuf(bufinput
, i
+ 1);
153 if (input
->type
== TYPE_DATA
)
155 /* option->data = input->string; */
156 Push_Data(option
, input
->string
);
158 /* Find_DATA_And_Revoke(); */
166 input
= Neuro_GiveEBuf(bufinput
, i
);
171 Debug_Val(0, "Missing a DATA argument to the option %s\n", option
->string
);
175 Debug_Val(2, " includes data \"%s\" ", option->data);
182 Handle_Options_nest(BUFINPUT
*input
, LOPTIONS
*option
, char *input_string
,
183 char *sep_string
, u32 current
)
188 Debug_Val(4, " N %s -%c", sep_string
, input_string
[0]);
190 /* we drop any checks with long options (--) */
191 if (strlen(sep_string
) > 2)
194 if (input_string
[0] == sep_string
[1])
198 Debug_Val(4, " <- found %c ", input
->used
);
200 if (option
->options
& OPTION_NESTED
)
206 if (option
->options
& OPTION_ARGUMENT
)
207 _err
= Handle_Option_Argument(option
, current
, input
->string
);
212 Debug_Val(0, "Invalid option in a nest of options %d \n", input
->used
);
220 /* TODO find a better name eheh */
222 Handle_Options(BUFINPUT
*input
, LOPTIONS
*option
, char *sep_string
, u32 current
)
224 char *sep
; /* will contain the - or -- prefix plus the option */
225 int len
; /* sep_string len */
228 len
= strlen(sep_string
);
230 sep
= calloc(1, len
+ 4);
232 if (len
> 1 /* && sep_string[0] != '-'*/)
234 /* could be either a long option (ie email) or a
235 * short option ( ie -e ) but with extra options in
236 * it ( ie -eau ). An error would be that the
237 * extra option contains invalid nested options, a
238 * '=' character when a small option.
242 strncpy(&sep
[2], sep_string
, len
);
248 sep
[1] = sep_string
[0];
253 _err = Handle_Options(input, option, sep, current);
257 sep[2] = sep_string[1];
263 Debug_Val(4, "%s %s", sep
, input
->string
);
266 tmp = strchr(input->string, '=');
271 printf(" <- data included ");
275 /* check if we have an element in bufinput that is a nest of options
278 if (input
->type
== TYPE_NEST
)
281 int ilen
= strlen(input
->string
);
283 Debug_Val(4, " <- nested options \n");
285 /* input->used = 0; */
290 _err
= Handle_Options_nest(input
, option
, &input
->string
[i
], sep
, current
);
299 if (!strncmp(input
->string
, sep
, strlen(sep
)))
303 Debug_Val(4, " <- found ");
309 if (option
->options
& OPTION_ARGUMENT
)
310 _err
= Handle_Option_Argument(option
, current
, input
->string
);
314 if (input->used != 1)
327 Neuro_ArgInit(int argc
, char **argv
)
339 Neuro_CreateEBuf(&bufinput
);
340 Neuro_CreateEBuf(&loptions
);
342 if (!bufinput
|| !loptions
)
345 Neuro_SetcallbEBuf(loptions
, clean_loptions
);
347 /* since 0 is the name of the executed command */
351 Neuro_AllocEBuf(bufinput
, sizeof(BUFINPUT
*), sizeof(BUFINPUT
));
352 buf
= Neuro_GiveCurEBuf(bufinput
);
354 buf
->string
= argv
[i
];
359 /* a test to see if everything works */
360 i
= Neuro_GiveEBufCount(bufinput
) + 1;
363 buf
= Neuro_GiveEBuf(bufinput
, i
);
364 Debug_Val(10, "arg output %s\n", buf
->string
);
366 #endif /* init_test */
372 Neuro_ArgOption(char *string
, int options
, void (*action
)(char *data
))
381 Neuro_AllocEBuf(loptions
, sizeof(LOPTIONS
*), sizeof(LOPTIONS
));
382 buf
= Neuro_GiveCurEBuf(loptions
);
387 buf
->string
= calloc(1, strlen(string
) + 1);
388 strncpy(buf
->string
, string
, strlen(string
));
391 buf
->options
= options
;
394 buf
->action
= action
;
400 /* interesting notes :
401 * - options can contain more than one option in it
402 * options only with the OPTION_NESTED flag can go in it.
403 * - options with the flag OPTION_ARGUMENT can't contain a
404 * = character in it, the next input argument is read to see
405 * if it is a DATA type, if it is not, it will do an error.
407 * -- options can only contain a single option but the string
408 * of the option can be of any lenght (unlike - ). In presence
409 * of OPTION_ARGUMENT, the algorithm doesn't loop for the next
410 * input argument like for -, it will look for the -- option and
411 * try to find a '=' character which should follow a string that
412 * is the argument or else it will do an error.
419 u32 i
= 0, i2
= 0, i3
= 0;
424 ototal
= Neuro_GiveEBufCount(loptions
) + 1;
426 /* in case there is no arguments inputed
427 * we search the loptions to see if an
428 * option contains the OPTION_VOID tag
429 * so we can run it. Normally, only one
430 * option should have this tag so we
431 * will only run the first we find.
433 if (Neuro_EBufIsEmpty(bufinput
))
437 option
= Neuro_GiveEBuf(loptions
, i
);
439 if (option
->options
& OPTION_VOID
)
442 (option
->action
)(NULL
);
451 itotal
= Neuro_GiveEBufCount(bufinput
) + 1;
453 /* printf("TOTAL %d\n", itotal); */
454 Debug_Val(3, "TOTAL %d\n", itotal
);
458 /* flag the input arguments with their types */
461 input
= Neuro_GiveEBuf(bufinput
, i
);
463 Debug_Val(6, "input %s", input
->string
);
465 if (input
->string
[0] == '-')
467 if (input
->string
[1] != '-' && strlen(input
->string
) > 2)
469 if (strchr(input
->string
, '='))
472 Debug_Val(0, "Invalid use of the option character \'-\', it may only be used alone or with other options, \n");
473 Debug_Val(0, "to pass an argument to it, please use either the long version of the option (ie --foo=bar)\n");
474 Debug_Val(0, "or have a space between the option and the argument (ie -f bar).\n");
478 input
->type
= TYPE_NEST
;
480 Debug_Val(6, " nest\n");
485 input
->type
= TYPE_OPTION
;
487 Debug_Val(6, " option\n");
492 input
->type
= TYPE_DATA
;
494 Debug_Val(6, " data\n");
500 /* loop the options & arguments and process(change flags only except
501 * some exceptions like arguments to options which it will handle) the
504 * nested(-au), <done>
506 * and required <done>
509 while (i
< itotal
&& !_err
)
511 input
= Neuro_GiveEBuf(bufinput
, i
);
513 while (i2
< ototal
&& !_err
)
515 option
= Neuro_GiveEBuf(loptions
, i2
);
519 sepchr
= Neuro_SepChr2(',', option
->string
);
521 i3
= Neuro_GiveEBufCount(sepchr
) + 1;
522 while (i3
-- > 0 && !_err
)
524 sep
= Neuro_GiveEBuf(sepchr
, i3
);
526 /* TODO find a better name eheh */
527 _err
= Handle_Options(input
, option
, sep
->string
, i
);
531 /* an error occured */
536 /* 3 means the current option
541 if (option
->options
& OPTION_QUIT
)
548 Neuro_CleanEBuf(&sepchr
);
553 Debug_Val(4, "DATA %s", input
->string
);
555 if (input
->type
== TYPE_DATA
&& input
->used
== 0)
559 /* option->data = input->string; */
560 Push_Data(option
, input
->string
);
562 Debug_Val(4, " <- found ");
575 /* loop the options to see if all the required
576 * options are present and also check if options
577 * don't have more than one iteration of themselves
578 * unless they have the multi option.
582 option
= Neuro_GiveEBuf(loptions
, i
);
584 if (option
->options
& OPTION_REQUIRED
&& option
->present
== 0)
587 Debug_Val(0, "Required option %s is not present.\n", option
->string
);
589 Debug_Val(0, "Required option DATA is not present.\n");
594 if (!(option
->options
& OPTION_MULTI
) && option
->present
> 1)
597 Debug_Val(0, "Invalid use of more than one iteration of the option %s.\n", option
->string
);
599 Debug_Val(0, "Invalid use of more than one iteration of the option DATA.\n");
611 /* loop the bufinput elements and check to see if theres
612 * invalid arguments and print the according errors.
616 input
= Neuro_GiveEBuf(bufinput
, i
);
618 if (input
->used
== 0)
620 Debug_Val(0, "Invalid option used %s\n", input
->string
);
625 if (input
->type
== TYPE_NEST
)
627 if (input
->used
< strlen(input
->string
) - 1)
629 Debug_Val(0, "One or more options in the option nest \"%s\" is invalid\n", input
->string
);
642 /* loop the options and call the callbacks if theres no errors */
645 option
= Neuro_GiveEBuf(loptions
, i
);
652 (option->action)(option->data);
654 if (!Neuro_EBufIsEmpty(option
->datas
))
659 dtotal
= Neuro_GiveEBufCount(option
->datas
);
663 dta
= Neuro_GiveEBuf(option
->datas
, dtotal
);
664 (option
->action
)(dta
->data
);
668 (option
->action
)(NULL
);
670 if (option
->options
& OPTION_QUIT
)
687 Neuro_CleanEBuf(&bufinput
);
688 Neuro_CleanEBuf(&loptions
);