The libparamset
is a software development kit, written in plain C, for handling command-line parameters and program tasks. Parameters can be read from command line and a task can be extracted that matches with the given input. Process is covered with error detection and functions that generate helpful feedback messages to the user.
The libparamset
provides the following functionality:
- Parameters can be parsed from command line, read from configuration file, or inserted from the code.
- Short and long parameters are recognised (
-a
and--long
). - Concatenating of flags with length 1 (
-ab
instead of-a -b
). - One alias for the parameter name (e.g.
--load
and-l
or--version
and--VERSION
). - Individual parsing options for parameters:
- Parameter with multiple coexisting values (
-a v1 -a v2 ... -a vn
, where-a = {v1, v2, ..., vn}
). - Parameter that never takes a value (
-a v1 -a -a
, where-a = {NULL, NULL, NULL}
andv1
is unknown token). - Parameter that always takes a value (
-a -a
, where-a = {-a}
). - Existing parameter break that takes next token as it's value only if it's not an existing parameter.
- Possible parameter break that takes next token as it's value only if it does not look like possible parameter (
-a v1 -a -b
, where-a = {v1, NULL}
). - Parameter value sequence with (existing or possible) parameter break (
-a v1 v2 ... vn -b
, where-a = {v1, v2, ..., vn}
). - Parameter that is hidden from the command line but can be inserted from the code or configuration file.
- Parameter that does not generate any typo errors (useful when hiding a parameter from command line).
- Value collectors:
- Parameter
--
, that will redirect every next token to a specified parameter(s). - Parameter that collects values that are not bound with any parameter (
-i x y ...
, wherex
is bound with-i
buty
is not). - Parameter that collects all unknown parameters (
--unknown unknown
, where--unknown
is collected andunknown
is unknown token). - Individual collector count limiters (e.g. no more than
5
values).
- Parameter
- Parameter with multiple coexisting values (
- Values can be filtered by name (e.g.
-i
asi
and--long
aslong
), source (e.g.default
), priority (e.g.3
) and index (0 - n
). - Values can be counted by name, source and priority (e.g.
3
). - Values can be filtered as the last or the first with the highest or the lowest priority.
- Values can be counted as the highest or the lowest priority.
- Parameter default name that is shown in error messages (print name) can be replaced with custom string (constant or generated).
- Auto-generated typo suggestions (e.g. Did You mean
--long
instead of--song
?). - Auto-generated unknown parameter error messages.
- Abstract format and content check functionality with auto-generated error messages.
- Abstract parameter transformation or repair functionality.
- Abstract Wildcard expander (can be used to make
-i *
work on Windows).- Implemented wildcards for Windows file system.
- Abstract object parsing functionality (e.g. extract double or file).
- Multiple parameter sets can be merged.
- Task set, composed of multiple tasks, where from a task can be extracted by specified parameter set.
- Auto-generated suggestions between multiple tasks for the user when it is not possible to resolve which task the user wants to perform.
- Auto-generated suggestions how to fix the task user tries to perform.
- Parameters can be bound with description and formatted to human readable list for help text.
The API full reference is available here https://guardtime.github.io/libparamset/.
To use libparamset
in your C/C++ project, link it against the libparamset
binary.
In order to install the libparamset
on CentOS/RHEL:
cd /etc/yum.repos.d
# In case of RHEL/CentOS 7
sudo curl -O https://download.guardtime.com/ksi/configuration/guardtime.el7.repo
# In case of RHEL/CentOS 8
sudo curl -O https://download.guardtime.com/ksi/configuration/guardtime.el8.repo
# In case of RHEL/CentOS 9
sudo curl -O https://download.guardtime.com/ksi/configuration/guardtime.el9.repo
yum install libparamset
In order to install the libparamset
on Debian / Ubuntu:
# Add Guardtime pgp key.
sudo curl https://download.guardtime.com/ksi/GUARDTIME-GPG-KEY-2 | sudo apt-key add -
# In case of Debian 12 (Bookworm)
sudo curl -o /etc/apt/sources.list.d/guardtime.list https://download.guardtime.com/ksi/configuration/guardtime.bookworm.list
sudo apt update
apt-get install libparamset
In order to install the libparamset
on OS X:
brew tap guardtime/ksi
brew install libparamset
If the latest version is needed or the package is not available for the platform you are using, check out source code from Github and build it using gcc
or VS
. To build the libparamset
, you need to have gcc
and autotools
. For building in Windows you need the Windows SDK.
- Include
param_set.h
andtask_def.h
. - Configure parameters:
- Create new
PARAM_SET
object with set of parametersPARAM_SET_new
. - Add implementations for format, control (and convert) functions with
PARAM_SET_addControl
. - Add implementation for wildcard expander (e.g. to implement wildcards when getting file input on Windows
-i *.txt
)PARAM_SET_setWildcardExpander
. - Add parsing options for parameters with
PARAM_SET_setParseOptions
.
- Create new
- Configure tasks:
- Create new
TASK_SET
object withTASK_SET_new
. - Add task definitions to the
TASK_SET
withTASK_SET_add
.
- Create new
- Get parameters:
- Parse command line with
PARAM_SET_parseCMD
. - Read parameters from configuration file with
PARAM_SET_readFromFile
. - Check and report user if configuration file contained some syntax errors with
PARAM_SET_isSyntaxError
andPARAM_SET_syntaxErrorsToString
. - Merge different
PARAM_SET
objects withPARAM_SET_IncludeSet
. - Check for unknown parameters and typos with
PARAM_SET_isUnknown
andPARAM_SET_isTypoFailure
. - Check for invalid parameters that failed format or content checks with
PARAM_SET_isFormatOK
. - If there are some errors, help user with error messages by using following functions:
PARAM_SET_unknownsToString
,PARAM_SET_typosToString
andPARAM_SET_invalidParametersToString
.
- Parse command line with
- Analyze task set against given input:
- Analyze the
TASK_SET
againstPARAM_SET
withTASK_SET_analyzeConsistency
. - Extract consistent task from
TASK_SET
withTASK_SET_getConsistentTask
. - In case of failure, check if there is an invalid task that stands out from the others and give user some hints how to fix it with functions
TASK_SET_isOneFromSetTheTarget
andTASK_SET_howToRepair_toString
. When it's hard to distinguish which task user is trying to accomplish, give some suggestions that do have the most similar pattern to the given input withTASK_SET_suggestions_toString
.
- Analyze the
- Use functions
TASK_getID
andTASK_getSet
and perform the selected task:- To check if a parameter is set, use function
PARAM_SET_isSetByName
. - To get parameters value from the set, use functions
PARAM_SET_getStr
andPARAM_SET_getObj
. - To get parameter value count, use function
PARAM_SET_getValueCount
.
- To check if a parameter is set, use function
- Release object with
TASK_SET_free
andPARAM_SET_free
.
A very basic example that illustrates how to parse the command-line options without any error handling and perform the task. See Example 2 for more advanced use case.
#include <stdio.h>
#include <param_set/param_set.h>
int main(int argc, char** argv) {
PARAM_SET *set = NULL;
char buf[0xffff];
/* Create new param_set object. */
PARAM_SET_new("{i}{o}{dump}{debug}{r}{help|h}", &set);
/* Parse command-line. */
PARAM_SET_parseCMD(set, argc, argv, NULL, 0);
/* Document options. */
PARAM_SET_setHelpText(set, "i", "file", "File input. To specify multiple input files, use -i multiple times.");
PARAM_SET_setHelpText(set, "o", "file", "Output file.");
PARAM_SET_setHelpText(set, "r", NULL, "Reverse file.");
PARAM_SET_setHelpText(set, "help", NULL, "Show help message (You are reading it right now!).");
PARAM_SET_setHelpText(set, "dump", NULL, "Dump file content.");
PARAM_SET_setHelpText(set, "debug", NULL, "Print param_setobject.");
/*
* See PARAM_SET_isSetByName, PARAM_SET_isOneOfSetByName, PARAM_SET_getStr,
* PARAM_SET_getValueCount and PARAM_SET_getObj to work with parameters.
*/
if (PARAM_SET_isSetByName(set, "h")) {
printf( "Usage:\n"
" util -i file [-r -o file][--dump]\n"
" util --debug\n\n");
printf( "Options:\n%s", PARAM_SET_helpToString(set, "i,o,r,h,dump,debug", 2, 10, 80, buf, sizeof(buf)));
} else if (PARAM_SET_isSetByName(set, "i,dump") && !PARAM_SET_isSetByName(set, "r,o,debug")) {
printf("Dump File.\n");
} else if (PARAM_SET_isSetByName(set, "i,r,o") && !PARAM_SET_isSetByName(set, "debug")) {
printf("Reverse File.\n");
} else if (PARAM_SET_isSetByName(set, "debug")) {
printf("Debug information:\n%s\n", PARAM_SET_toString(set, buf, sizeof(buf)));
} else {
printf("Unknown task. Use -h to get some help.\n");
}
PARAM_SET_free(set);
}
A simple example of a command-line tool that uses libparamset
to specify parameter set and task set, parse the command line, handle errors and give some feedback to the user to help get things working.
#include <stdio.h>
#include <param_set/param_set.h>
#include <param_set/task_def.h>
#ifdef _WIN32
# include <param_set/wildcardexpanders.h>
#endif
enum {
VALUE_OK = 0,
VALUE_IS_NULL = 0x01,
VALUE_IS_EMPTY = 0x02,
VALUE_FILE_DOES_NOT_EXIST = 0x03,
};
int convertRepair_path(const char* arg, char* buf, unsigned len);
int isContentOk_path(const char* fname);
int isFormatOk_path(const char* fname);
const char *parameter_error_to_string(int err);
int main(int argc, char** argv, char **envp) {
PARAM_SET *set = NULL;
TASK_SET *task_set = NULL;
TASK *pTask = NULL;
char buf[1024];
char debug[0xffff];
/*
* Configure parameter set and its parameters.
* 1) Both o and i must not be NULL or empty string.
* 2) Both o and i converts '\' into '/'.
* 3) i must be a path to a file that must exist.
* 4) Next token after o and i is always bound with the flag.
* 5) All options with true or false do not bound anything.
*/
PARAM_SET_new("{i}{o}{dump}{debug}{r}{help|h}", &set);
PARAM_SET_addControl(set, "o", isFormatOk_path, NULL, convertRepair_path, NULL);
PARAM_SET_addControl(set, "i", isFormatOk_path, isContentOk_path, convertRepair_path, NULL);
PARAM_SET_setParseOptions(set, "o", PST_PRSCMD_HAS_VALUE);
PARAM_SET_setParseOptions(set, "dump,debug,h,r", PST_PRSCMD_HAS_NO_VALUE);
/* Document options. */
PARAM_SET_setHelpText(set, "i", "file", "File input. To specify multiple input files, use -i multiple times.");
PARAM_SET_setHelpText(set, "o", "file", "Output file.");
PARAM_SET_setHelpText(set, "r", NULL, "Reverse file.");
PARAM_SET_setHelpText(set, "help", NULL, "Show help message (You are reading it right now!).");
PARAM_SET_setHelpText(set, "dump", NULL, "Dump file content.");
PARAM_SET_setHelpText(set, "debug", NULL, "Print param_setobject.");
/*
* To enable Windows file system wildcards, specify the wildcard expander
* function implementation and enable parsing option that enable wildcard
* processor.
*/
#ifdef _WIN32
PARAM_SET_setWildcardExpander(set, "i", NULL, NULL, NULL, PST_WCF_Win32FileWildcard);
PARAM_SET_setParseOptions(set, "i", PST_PRSCMD_HAS_VALUE | PST_PRSCMD_EXPAND_WILDCARD);
#else
PARAM_SET_setParseOptions(set, "i", PST_PRSCMD_HAS_VALUE);
#endif
/*
* Describe different tasks:
* util -h
* util -i file_in --dump
* util -i file_in -o file_out -r
* util --debug [options, except -h]
*/
TASK_SET_new(&task_set);
TASK_SET_add(task_set, 0, "Help", "h", NULL, NULL, NULL);
TASK_SET_add(task_set, 1, "Only Dump file", "i,dump", NULL, "h,r,o,debug",NULL);
TASK_SET_add(task_set, 2, "Reverse file", "i,r,o", NULL, "h,debug", NULL);
TASK_SET_add(task_set, 3, "Debug", "debug", NULL, "h", NULL);
/* Parse command-line. */
PARAM_SET_parseCMD(set, argc, argv, NULL, 0);
/* Check for typos and unknown parameters. */
if (PARAM_SET_isTypoFailure(set)) {
printf("%s\n", PARAM_SET_typosToString(set, NULL, buf, sizeof(buf)));
goto cleanup;
} else if (PARAM_SET_isUnknown(set)){
printf("%s\n", PARAM_SET_unknownsToString(set, "Error: ", buf, sizeof(buf)));
goto cleanup;
}
/* Check for invalid values. */
if (!PARAM_SET_isFormatOK(set)) {
printf("%s\n", PARAM_SET_invalidParametersToString(set, NULL, parameter_error_to_string, buf, sizeof(buf)));
goto cleanup;
}
/* As input parameter passed all checks try to extract a consistent task. */
TASK_SET_analyzeConsistency(task_set, set, 0.2);
TASK_SET_getConsistentTask(task_set, &pTask);
/* If task is not extracted try to give user some suggestions what to do to make things work. */
if (pTask == NULL) {
int ID;
if (TASK_SET_isOneFromSetTheTarget(task_set, 0.1, &ID)) {
printf("%s", TASK_SET_howToRepair_toString(task_set, set, ID, NULL, buf, sizeof(buf)));
} else {
printf("%s", TASK_SET_suggestions_toString(task_set, 3, buf, sizeof(buf)));
}
goto cleanup;
}
/*
* Task is extracted, check which one to run.
* See PARAM_SET_isSetByName, PARAM_SET_isOneOfSetByName, PARAM_SET_getStr,
* PARAM_SET_getValueCount and PARAM_SET_getObj to work with parameters.
*/
switch(TASK_getID(pTask)) {
case 0:
printf( "Usage:\n"
" util -i file [-r -o file][--dump]\n"
" util --debug\n\n");
printf( "Options:\n%s", PARAM_SET_helpToString(set, "i,o,r,h,dump,debug", 2, 10, 80, buf, sizeof(buf)));
break;
case 1:
printf("Dump File.\n");
break;
case 2:
printf("Reverse File.\n");
break;
case 3:
printf("Debug information:\n%s\n", PARAM_SET_toString(set, debug, sizeof(debug)));
break;
default:
printf("Error.\n");
break;
}
cleanup:
TASK_SET_free(task_set);
PARAM_SET_free(set);
}
const char *parameter_error_to_string(int err) {
switch(err) {
case VALUE_OK: return "OK";
case VALUE_IS_NULL: return "Parameter must have value";
case VALUE_IS_EMPTY: return "Parameter must have content";
case VALUE_FILE_DOES_NOT_EXIST: return "File does not exist";
default: return "Unknown error";
}
}
int isFormatOk_path(const char* fname) {
if (fname == NULL) return VALUE_IS_NULL;
else if (*fname == '\0');
else return VALUE_OK;
}
int isContentOk_path(const char* fname) {
int result = 1;
FILE *f = NULL;
f = fopen(fname, "r");
result = f == NULL ? VALUE_FILE_DOES_NOT_EXIST : 0;
if (f != NULL) fclose(f);
return result;
}
int convertRepair_path(const char* arg, char* buf, unsigned len){
char *toBeReplaced = NULL;
if (arg == NULL || buf == NULL) return PST_INVALID_ARGUMENT;
strncpy(buf, arg, len - 1);
toBeReplaced = buf;
while ((toBeReplaced = strchr(toBeReplaced, '\\')) != NULL){
*toBeReplaced = '/';
toBeReplaced++;
}
return PST_OK;
}
See the LICENSE
file.
See the CONTRIBUTING.md
file.
Dependency | Version | License type | Source | Notes |
---|---|---|---|---|
CuTest | 1.5 | Zlib | Required only for testing. |
OS / Platform | Compatibility |
---|---|
CentOS/RHEL 7,8,9, x86_64 architecture | Fully compatible and tested. |
Debian 12+ | Fully compatible and tested. |
Ubuntu | Compatible but not tested on regular basis. |
OS X | Compatible but not tested on regular basis. |
Windows 7, 8, 10, 11 | Compatible but not tested on a regular basis. Build combination of DLL=dll and RTL=MT(d) not supported. |