ADD: added current version of parser
This commit is contained in:
parent
f6c876cb70
commit
768096ab3a
313
src/argparse.c
Normal file
313
src/argparse.c
Normal file
@ -0,0 +1,313 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file argparse.c
|
||||||
|
* @brief file for all argparse functions
|
||||||
|
* @author Dominik Meyer <dmeyer@federationhq.de>
|
||||||
|
* @copyright 2018 by Dominik Meyer
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#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 <command> [<args>]\n",program);
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
printf("Available commands: \n");
|
||||||
|
|
||||||
|
for(i=0; i<ctx->nr_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; i<ctx->nr_arguments; i++)
|
||||||
|
{
|
||||||
|
switch (to_argbase(ctx->arguments[i])->type)
|
||||||
|
{
|
||||||
|
case ARG_STR:
|
||||||
|
printf("\t-%c <string>|--%s=<string>\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+1<argc)
|
||||||
|
{
|
||||||
|
strncpy(to_str(ctx->arguments[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; i<ctx->nr_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;
|
||||||
|
}
|
133
src/argparse.h
Normal file
133
src/argparse.h
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
#ifndef __ARGPARSE_H__
|
||||||
|
#define __ARGPARSE_H__
|
||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file argparse.h
|
||||||
|
* @brief header file for all argparse functions
|
||||||
|
* @author Dominik Meyer <dmeyer@federationhq.de>
|
||||||
|
* @copyright 2018 by Dominik Meyer
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/** @mainpage
|
||||||
|
*
|
||||||
|
* \section intro_sec Introduction
|
||||||
|
* YAAP is a simple command line argument parser for C.
|
||||||
|
* It uses functions and structures to add arguments to the parsing context and
|
||||||
|
* parse the command line.
|
||||||
|
* \section Features
|
||||||
|
* - git like command support (git commit)
|
||||||
|
* - short and long flag support ( -t YAAP or --title=YAAP)
|
||||||
|
* - string argument support ( -t YAAP or -- title=YAAP)
|
||||||
|
*
|
||||||
|
* \section coming
|
||||||
|
* - simple flags (-v, -V, -h, --help)
|
||||||
|
* - integer arguments (-c 10)
|
||||||
|
* - hex arguments ( -c 0x5A)
|
||||||
|
*
|
||||||
|
* \section Installation
|
||||||
|
* YAAP is intented to be copied into your project directory. Different approaches are
|
||||||
|
* available:
|
||||||
|
* - simpe copy argparse.h and argparse.c into your source directory
|
||||||
|
* - add the github repository as a submodule
|
||||||
|
* - add the github repository as a subtree
|
||||||
|
* - add the github repository as a subrepo
|
||||||
|
*
|
||||||
|
* In all cases you have to make sure that argparse.c is compiled into an object file
|
||||||
|
* and is appended to your link stage.
|
||||||
|
*
|
||||||
|
* \section Functions
|
||||||
|
* All available functions can be found in argparse.c.
|
||||||
|
*
|
||||||
|
* @example example1.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define ARGPARSE_INITIAL_COMMAND_NR 5 ///< initial size for the command array
|
||||||
|
|
||||||
|
#define to_argbase(ptr) ((struct arg_base *) ptr) ///< convert a pointer to an arg_base structure pointer
|
||||||
|
#define to_cmd(ptr) ((struct arg_parse_cmd *)ptr) ///< convert a pointer to an arg_parse_cmd structure pointer
|
||||||
|
#define to_str(ptr) ((struct arg_str *)ptr) ///< convert a pointer to an arg_str structure pointer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief supported argument types
|
||||||
|
*/
|
||||||
|
enum argtypes {
|
||||||
|
ARG_CMD, ///< a command argument like git uses it (git commit)
|
||||||
|
ARG_FLAG, ///< a simple flag like -v without additional parameter
|
||||||
|
ARG_STR, ///< an argument with a string parameter (-t hallo, --title=hallo)
|
||||||
|
ARG_INT ///< an argument with a integer parameter (-s 10, --size=10)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief base structure for a command line argument
|
||||||
|
*/
|
||||||
|
struct arg_base
|
||||||
|
{
|
||||||
|
enum argtypes type; ///< type of the argument
|
||||||
|
int mandatory; ///< is the argument mandatory
|
||||||
|
int set; ///< has the argument been set
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief structure representing a command
|
||||||
|
*/
|
||||||
|
struct arg_parse_cmd
|
||||||
|
{
|
||||||
|
struct arg_base base; ///< base of the command line argument
|
||||||
|
int no_command; ///< if this is 1, the callback will be called if no command is given
|
||||||
|
const char *command; ///< the name of the command on the commandline, no spaces or special chars allowed, only ascii
|
||||||
|
const char *description; ///< short description of the command
|
||||||
|
int (*cb)(int argc, char **argv); ///< function to call if the command is found on commandline
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief structure representing a string command line argument
|
||||||
|
*/
|
||||||
|
struct arg_str {
|
||||||
|
struct arg_base base; ///< base of the command line argument
|
||||||
|
const char short_flag; ///< one char flag identifying the argument, ignored if NULL
|
||||||
|
const char *long_flag; ///< multi char flag identifying the argument, ignore if NULL
|
||||||
|
char *value; ///< memory already allocated for the string parameter
|
||||||
|
int maxchars; ///< the maximum number of chars for the string parameters
|
||||||
|
const char *description; ///< short description of the argument
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief structure for the argparse context, holding argparse specific data structures
|
||||||
|
*/
|
||||||
|
struct arg_parse_ctx
|
||||||
|
{
|
||||||
|
void **arguments; ///< array for all argparse elementsdd
|
||||||
|
int nr_arguments; ///< how many arguments are currently registered
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct arg_parse_ctx * argparse_init(); ///< initialize parsing context
|
||||||
|
void argparse_free(struct arg_parse_ctx *ctx); ///< free the parsing context at program end
|
||||||
|
int argparse_add_command(struct arg_parse_ctx *ctx, struct arg_parse_cmd *cmd); ///< add a commandline command to the context
|
||||||
|
int argparse_add_string(struct arg_parse_ctx *ctx, struct arg_str *str); ///< add a string argument to the context
|
||||||
|
int argparse_parse(struct arg_parse_ctx *ctx,int argc, char **argv); ///< parse the given commandline in the context
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user