/* argparse functions Copyright (C) 2018 Dominik Meyer This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ /** * @file argparse.c * @brief file for all argparse functions * @author Dominik Meyer * @copyright 2018 by Dominik Meyer */ #include #include #include #include "argparse.h" /** * @brief initialize the argparse context * * This function has to be called at every start of the programm and before * any other argparse functions are called!!! * * @return returns an initialized arg parse structure */ struct arg_parse_ctx * argparse_init() { // allocate memory for the arg_parse_ctx structure struct arg_parse_ctx *ctx = (struct arg_parse_ctx *) calloc(sizeof(struct arg_parse_ctx),1); if (ctx == NULL) { return NULL; } // allocate memory for the arg_parse_cmd array ctx->arguments=(void **)calloc(sizeof(void *), ARGPARSE_INITIAL_COMMAND_NR); if (ctx->arguments == NULL) { free(ctx); return NULL; } return ctx; } /** * @brief free an arg_parse context (all memory will be freed) * * this function should be called at the end of the programm * * @param ctx - the arg_parse_ctx structure to free */ void argparse_free(struct arg_parse_ctx *ctx) { // free the arg_parse_cmd array free(ctx->arguments); // free the context itself free(ctx); } /** * @brief add an arg_parse_cmd to the context for later parsing * * @param ctx - the context the command should be added to * @param cmd - the command to add to the context * * @return 0 = everything is fine, -1 error occured */ int argparse_add_command(struct arg_parse_ctx *ctx, struct arg_parse_cmd *cmd) { if (ctx == NULL || cmd == NULL) { return -1; } cmd->base.type=ARG_CMD; // check if the array size has to be increased if (ctx->nr_arguments % ARGPARSE_INITIAL_COMMAND_NR == 0) { ctx->arguments= (void **) realloc(ctx->arguments, sizeof(void *)*(ctx->nr_arguments+ARGPARSE_INITIAL_COMMAND_NR)); } // append the command to the array ctx->arguments[ctx->nr_arguments]=cmd; ctx->nr_arguments++; return 0; } /** * @brief add an arg_str to the context for later parsing * * @param ctx - the context the command should be added to * @param str - the arg_str to add * * @return 0 = everything is fine, -1 error occured */ int argparse_add_string(struct arg_parse_ctx *ctx, struct arg_str *str) { if (ctx == NULL || str == NULL) { return -1; } str->base.type=ARG_STR; // check if the array size has to be increased if (ctx->nr_arguments % ARGPARSE_INITIAL_COMMAND_NR == 0) { ctx->arguments= (void **) realloc(ctx->arguments, sizeof(void *)*(ctx->nr_arguments+ARGPARSE_INITIAL_COMMAND_NR)); } // append the command to the array ctx->arguments[ctx->nr_arguments]=str; ctx->nr_arguments++; return 0; } /** * @brief internal function to print usage information, not exported to user * * @param ctx - the context for which to print the usage information * @param program - the program name the application was called with * */ void argparse_usage(struct arg_parse_ctx *ctx, char *program) { int i=0; printf("usage: %s []\n",program); printf("\n"); printf("Available commands: \n"); for(i=0; inr_arguments; i++) { switch (to_argbase(ctx->arguments[i])->type) { case ARG_CMD: printf("\t%20s\t\t%s\n", to_cmd(ctx->arguments[i])->command, to_cmd(ctx->arguments[i])->description); break; default: break; }; } printf("\nAvailable Arguments: \n"); for(i=0; inr_arguments; i++) { switch (to_argbase(ctx->arguments[i])->type) { case ARG_STR: printf("\t-%c |--%s=\t\t%s\n", to_str(ctx->arguments[i])->short_flag, to_str(ctx->arguments[i])->long_flag, to_str(ctx->arguments[i])->description); default: break; }; } printf("\n"); } /** * @brief internal function to print usage information, if an unknown command has been found * * @param ctx - the context for which to print the usage information * @param program - the program name the application was called with * @param command - the command found * */ void argparse_unknown_command(struct arg_parse_ctx *ctx, char *program, char *command) { printf("%s: \'%s\' is not a supported command.\n\n", program, command); argparse_usage(ctx, program); } /** * @brief parse the given commandline * * @param ctx - the arg parse context to use * @param argc - the argument count of the commandline * @param argv - the argument list of the commandline * * @return 0 - everything is fine * @return <0 - parsing failed */ int argparse_parse(struct arg_parse_ctx *ctx, int argc, char **argv) { int i=0; int r=0; int found=0; int newargc=argc; char **newargv=argv; if (ctx == NULL) { return -1; } // check if there are arguments to check for if (ctx->nr_arguments == 0) { return 0; } // check if one of the command line args matches a given argument type if (argc > 1) { for (i=1; i< argc; i++) { found=0; for(r=0; r < ctx->nr_arguments; r++) { // check if the argument is a command if (argv[i][0]!='-' && to_argbase(ctx->arguments[r])->type == ARG_CMD ) { if (strcmp(to_cmd(ctx->arguments[r])->command,argv[i])==0) { found=1; newargc--; newargv=&argv[i]; return to_cmd(ctx->arguments[r])->cb(newargc,newargv); } } // check if the argument is a string argument else if (argv[i][0]=='-' && to_argbase(ctx->arguments[r])->type == ARG_STR) { // check for long argument format or short if(argv[i][1]=='-') { } else { if(argv[i][1] == to_str(ctx->arguments[r])->short_flag) { found=1; if (i+1arguments[r])->value, argv[i+1], to_str(ctx->arguments[r])->maxchars); i++; } else { printf("value missing for -%c parameter\n\n",to_str(ctx->arguments[r])->short_flag); argparse_usage(ctx, argv[0]); return -1; } to_argbase(ctx->arguments[r])->set=1; } } } } if (found == 0) { printf("%s is an unknown command/argument\n\n", argv[i]); argparse_usage(ctx, argv[0]); return -1; } } } // check if all mandatory parameters have been found for(i=0; inr_arguments; i++) { if (to_argbase(ctx->arguments[i])->mandatory==1 && to_argbase(ctx->arguments[i])->set==0) { printf("mandatory parameter missing "); switch (to_argbase(ctx->arguments[i])->type) { case ARG_STR: printf("-%c|--%s\n\n",to_str(ctx->arguments[i])->short_flag,to_str(ctx->arguments[i])->long_flag); break; default: printf("\n"); break; }; argparse_usage(ctx, argv[0]); return -1; } } return 0; }