mirror of
https://github.com/EnderIce2/Fennix.git
synced 2025-05-28 15:34:31 +00:00
feat(kernel): update cargs to v1.2.0
Signed-off-by: EnderIce2 <enderice2@protonmail.com>
This commit is contained in:
parent
7b42b46942
commit
9304cafe0c
@ -33,10 +33,14 @@ SOFTWARE.
|
|||||||
#ifndef CAG_LIBRARY_H
|
#ifndef CAG_LIBRARY_H
|
||||||
#define CAG_LIBRARY_H
|
#define CAG_LIBRARY_H
|
||||||
|
|
||||||
#include <types.h>
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
typedef unsigned int FILE; // TODO: Implement FILE
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The following defines CAG_EXPORT and CAG_IMPORT which are required to export
|
||||||
|
* shared library functions.
|
||||||
|
*/
|
||||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||||
#define CAG_EXPORT __declspec(dllexport)
|
#define CAG_EXPORT __declspec(dllexport)
|
||||||
#define CAG_IMPORT __declspec(dllimport)
|
#define CAG_IMPORT __declspec(dllimport)
|
||||||
@ -48,6 +52,10 @@ typedef unsigned int FILE; // TODO: Implement FILE
|
|||||||
#define CAG_IMPORT
|
#define CAG_IMPORT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This block defines CAG_PUBLIC, which only uses CAG_EXPORT and CAG_IMPORT if
|
||||||
|
* the cargs is compiled as a shared library.
|
||||||
|
*/
|
||||||
#if defined(CAG_SHARED)
|
#if defined(CAG_SHARED)
|
||||||
#if defined(CAG_EXPORTS)
|
#if defined(CAG_EXPORTS)
|
||||||
#define CAG_PUBLIC CAG_EXPORT
|
#define CAG_PUBLIC CAG_EXPORT
|
||||||
@ -58,6 +66,16 @@ typedef unsigned int FILE; // TODO: Implement FILE
|
|||||||
#define CAG_PUBLIC
|
#define CAG_PUBLIC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This block defines CAG_DEPRECATED which can be used to deprecate library
|
||||||
|
* functions including a comment on the deprecation.
|
||||||
|
*/
|
||||||
|
#if (!__cplusplus && __STDC_VERSION__ >= 202311L) || (__cplusplus >= 201402L)
|
||||||
|
#define CAG_DEPRECATED(comment) [[deprecated(comment)]]
|
||||||
|
#else
|
||||||
|
#define CAG_DEPRECATED(comment)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -88,29 +106,24 @@ extern "C"
|
|||||||
char **argv;
|
char **argv;
|
||||||
int index;
|
int index;
|
||||||
int inner_index;
|
int inner_index;
|
||||||
|
int error_index;
|
||||||
|
char error_letter;
|
||||||
bool forced_end;
|
bool forced_end;
|
||||||
char identifier;
|
char identifier;
|
||||||
char *value;
|
char *value;
|
||||||
} cag_option_context;
|
} cag_option_context;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prototype for printer used in cag_option_printer. For example fprintf have
|
||||||
|
* same prototype
|
||||||
|
*/
|
||||||
|
typedef int (*cag_printer)(void *ctx, const char *fmt, ...);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is just a small macro which calculates the size of an array.
|
* This is just a small macro which calculates the size of an array.
|
||||||
*/
|
*/
|
||||||
#define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
#define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Prints all options to the terminal.
|
|
||||||
*
|
|
||||||
* This function prints all options to the terminal. This can be used to
|
|
||||||
* generate the output for a "--help" option.
|
|
||||||
*
|
|
||||||
* @param options The options which will be printed.
|
|
||||||
* @param option_count The option count which will be printed.
|
|
||||||
* @param destination The destination where the output will be printed.
|
|
||||||
*/
|
|
||||||
CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count,
|
|
||||||
FILE *destination);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prepare argument options context for parsing.
|
* @brief Prepare argument options context for parsing.
|
||||||
*
|
*
|
||||||
@ -125,7 +138,7 @@ extern "C"
|
|||||||
* @param argc The amount of arguments the user supplied in the main function.
|
* @param argc The amount of arguments the user supplied in the main function.
|
||||||
* @param argv A pointer to the arguments of the main function.
|
* @param argv A pointer to the arguments of the main function.
|
||||||
*/
|
*/
|
||||||
CAG_PUBLIC void cag_option_prepare(cag_option_context *context,
|
CAG_PUBLIC void cag_option_init(cag_option_context *context,
|
||||||
const cag_option *options, size_t option_count, int argc, char **argv);
|
const cag_option *options, size_t option_count, int argc, char **argv);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -154,7 +167,7 @@ extern "C"
|
|||||||
* @param context The context from which the option was fetched.
|
* @param context The context from which the option was fetched.
|
||||||
* @return Returns the identifier of the option.
|
* @return Returns the identifier of the option.
|
||||||
*/
|
*/
|
||||||
CAG_PUBLIC char cag_option_get(const cag_option_context *context);
|
CAG_PUBLIC char cag_option_get_identifier(const cag_option_context *context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the value from the option.
|
* @brief Gets the value from the option.
|
||||||
@ -180,6 +193,105 @@ extern "C"
|
|||||||
*/
|
*/
|
||||||
CAG_PUBLIC int cag_option_get_index(const cag_option_context *context);
|
CAG_PUBLIC int cag_option_get_index(const cag_option_context *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the index of an invalid option.
|
||||||
|
*
|
||||||
|
* This function retrieves the index of an invalid option if the provided option
|
||||||
|
* does not match any of the options specified in the `cag_option` list. This is
|
||||||
|
* particularly useful when detailed information about an invalid option is
|
||||||
|
* required.
|
||||||
|
*
|
||||||
|
* @param context Pointer to the context from which the option was fetched.
|
||||||
|
* @return Returns the index of the invalid option, or -1 if it is not invalid.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC int cag_option_get_error_index(const cag_option_context *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Retrieves the letter character of the invalid option.
|
||||||
|
*
|
||||||
|
* This function retrieves the character of the invalid option character
|
||||||
|
* if the provided option does not match any of the options specified in the
|
||||||
|
* `cag_option` list.
|
||||||
|
*
|
||||||
|
* @param context Pointer to the context from which the option was fetched.
|
||||||
|
* @return Returns the letter that was unknown, or 0 otherwise.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC char cag_option_get_error_letter(const cag_option_context *context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints the error associated with the invalid option to the specified
|
||||||
|
* destination.
|
||||||
|
*
|
||||||
|
* This function prints information about the error associated with the invalid
|
||||||
|
* option to the specified destination (such as a file stream). It helps in
|
||||||
|
* displaying the error of the current context.
|
||||||
|
*
|
||||||
|
* @param context Pointer to the context from which the option was fetched.
|
||||||
|
* @param destination Pointer to the file stream where the error information
|
||||||
|
* will be printed.
|
||||||
|
*/
|
||||||
|
#ifndef CAG_NO_FILE
|
||||||
|
CAG_PUBLIC void cag_option_print_error(const cag_option_context *context,
|
||||||
|
FILE *destination);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints the error associated with the invalid option using user
|
||||||
|
* callback.
|
||||||
|
*
|
||||||
|
* This function prints information about the error associated with the invalid
|
||||||
|
* option using user callback. Callback prototype is same with fprintf. It helps
|
||||||
|
* in displaying the error of the current context.
|
||||||
|
*
|
||||||
|
* @param context Pointer to the context from which the option was fetched.
|
||||||
|
* @param printer The printer callback function. For example fprintf.
|
||||||
|
* @param printer_ctx The parameter for printer callback. For example fprintf
|
||||||
|
* could use parameter stderr.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC void cag_option_printer_error(const cag_option_context *context,
|
||||||
|
cag_printer printer, void *printer_ctx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints all options to the terminal.
|
||||||
|
*
|
||||||
|
* This function prints all options to the terminal. This can be used to
|
||||||
|
* generate the output for a "--help" option.
|
||||||
|
*
|
||||||
|
* @param options The options which will be printed.
|
||||||
|
* @param option_count The option count which will be printed.
|
||||||
|
* @param destination The destination where the output will be printed.
|
||||||
|
*/
|
||||||
|
#ifndef CAG_NO_FILE
|
||||||
|
CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count,
|
||||||
|
FILE *destination);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Prints all options using user callback.
|
||||||
|
*
|
||||||
|
* This function prints all options using user callback. This can be used to
|
||||||
|
* generate the output for a "--help" option.
|
||||||
|
* Using user callback is useful in tiny system without FILE support
|
||||||
|
*
|
||||||
|
* @param options The options which will be printed.
|
||||||
|
* @param option_count The option count which will be printed.
|
||||||
|
* @param destination The destination where the output will be printed.
|
||||||
|
* @param printer The printer callback function. For example fprintf.
|
||||||
|
* @param printer_ctx The parameter for printer callback. For example fprintf
|
||||||
|
* could use parameter stderr.
|
||||||
|
*/
|
||||||
|
CAG_PUBLIC void cag_option_printer(const cag_option *options,
|
||||||
|
size_t option_count, cag_printer printer, void *printer_ctx);
|
||||||
|
|
||||||
|
CAG_DEPRECATED(
|
||||||
|
"cag_option_prepare has been deprecated. Use cag_option_init instead.")
|
||||||
|
CAG_PUBLIC void cag_option_prepare(cag_option_context *context,
|
||||||
|
const cag_option *options, size_t option_count, int argc, char **argv);
|
||||||
|
|
||||||
|
CAG_DEPRECATED(
|
||||||
|
"cag_option_get has been deprecated. Use cag_option_get_identifier instead.")
|
||||||
|
CAG_PUBLIC char cag_option_get(const cag_option_context *context);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,22 +27,24 @@ SOFTWARE.
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <cargs.h>
|
#include <cargs.h>
|
||||||
#include <convert.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#define CAG_OPTION_PRINT_DISTANCE 4
|
#define CAG_OPTION_PRINT_DISTANCE 4
|
||||||
#define CAG_OPTION_PRINT_MIN_INDENTION 20
|
#define CAG_OPTION_PRINT_MIN_INDENTION 20
|
||||||
|
|
||||||
static void cag_option_print_value(const cag_option *option,
|
static void cag_option_print_value(const cag_option *option,
|
||||||
size_t *accessor_length, FILE *destination)
|
size_t *accessor_length, cag_printer printer, void *printer_ctx)
|
||||||
{
|
{
|
||||||
if (option->value_name != NULL)
|
if (option->value_name != NULL)
|
||||||
{
|
{
|
||||||
*accessor_length += fprintf(destination, "=%s", option->value_name);
|
*accessor_length += printer(printer_ctx, "=%s", option->value_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void cag_option_print_letters(const cag_option *option, bool *first,
|
static void cag_option_print_letters(const cag_option *option, bool *first,
|
||||||
size_t *accessor_length, FILE *destination)
|
size_t *accessor_length, cag_printer printer, void *printer_ctx)
|
||||||
{
|
{
|
||||||
const char *access_letter;
|
const char *access_letter;
|
||||||
access_letter = option->access_letters;
|
access_letter = option->access_letters;
|
||||||
@ -52,12 +54,12 @@ static void cag_option_print_letters(const cag_option *option, bool *first,
|
|||||||
{
|
{
|
||||||
if (*first)
|
if (*first)
|
||||||
{
|
{
|
||||||
*accessor_length += fprintf(destination, "-%c", *access_letter);
|
*accessor_length += printer(printer_ctx, "-%c", *access_letter);
|
||||||
*first = false;
|
*first = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*accessor_length += fprintf(destination, ", -%c", *access_letter);
|
*accessor_length += printer(printer_ctx, ", -%c", *access_letter);
|
||||||
}
|
}
|
||||||
++access_letter;
|
++access_letter;
|
||||||
}
|
}
|
||||||
@ -65,17 +67,18 @@ static void cag_option_print_letters(const cag_option *option, bool *first,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void cag_option_print_name(const cag_option *option, bool *first,
|
static void cag_option_print_name(const cag_option *option, bool *first,
|
||||||
size_t *accessor_length, FILE *destination)
|
size_t *accessor_length, cag_printer printer, void *printer_ctx)
|
||||||
{
|
{
|
||||||
if (option->access_name != NULL)
|
if (option->access_name != NULL)
|
||||||
{
|
{
|
||||||
if (*first)
|
if (*first)
|
||||||
{
|
{
|
||||||
*accessor_length += fprintf(destination, "--%s", option->access_name);
|
*accessor_length += printer(printer_ctx, "--%s", option->access_name);
|
||||||
|
*first = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*accessor_length += fprintf(destination, ", --%s", option->access_name);
|
*accessor_length += printer(printer_ctx, ", --%s", option->access_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,40 +122,7 @@ static size_t cag_option_get_print_indention(const cag_option *options,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cag_option_print(const cag_option *options, size_t option_count,
|
void cag_option_init(cag_option_context *context, const cag_option *options,
|
||||||
FILE *destination)
|
|
||||||
{
|
|
||||||
size_t option_index, indention, i, accessor_length;
|
|
||||||
const cag_option *option;
|
|
||||||
bool first;
|
|
||||||
|
|
||||||
indention = cag_option_get_print_indention(options, option_count);
|
|
||||||
|
|
||||||
for (option_index = 0; option_index < option_count; ++option_index)
|
|
||||||
{
|
|
||||||
option = &options[option_index];
|
|
||||||
accessor_length = 0;
|
|
||||||
first = true;
|
|
||||||
|
|
||||||
fputs(" ", destination);
|
|
||||||
|
|
||||||
cag_option_print_letters(option, &first, &accessor_length, destination);
|
|
||||||
cag_option_print_name(option, &first, &accessor_length, destination);
|
|
||||||
cag_option_print_value(option, &accessor_length, destination);
|
|
||||||
|
|
||||||
for (i = accessor_length; i < indention; ++i)
|
|
||||||
{
|
|
||||||
fputs(" ", destination);
|
|
||||||
}
|
|
||||||
|
|
||||||
fputs(" ", destination);
|
|
||||||
fputs(option->description, destination);
|
|
||||||
|
|
||||||
fprintf(destination, "\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void cag_option_prepare(cag_option_context *context, const cag_option *options,
|
|
||||||
size_t option_count, int argc, char **argv)
|
size_t option_count, int argc, char **argv)
|
||||||
{
|
{
|
||||||
// This just initialized the values to the beginning of all the arguments.
|
// This just initialized the values to the beginning of all the arguments.
|
||||||
@ -163,6 +133,8 @@ void cag_option_prepare(cag_option_context *context, const cag_option *options,
|
|||||||
context->index = 1;
|
context->index = 1;
|
||||||
context->inner_index = 0;
|
context->inner_index = 0;
|
||||||
context->forced_end = false;
|
context->forced_end = false;
|
||||||
|
context->error_index = -1;
|
||||||
|
context->error_letter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const cag_option *cag_option_find_by_name(cag_option_context *context,
|
static const cag_option *cag_option_find_by_name(cag_option_context *context,
|
||||||
@ -187,7 +159,7 @@ static const cag_option *cag_option_find_by_name(cag_option_context *context,
|
|||||||
// Try to compare the name of the access name. We can use the name_size or
|
// Try to compare the name of the access name. We can use the name_size or
|
||||||
// this comparison, since we are guaranteed to have null-terminated access
|
// this comparison, since we are guaranteed to have null-terminated access
|
||||||
// names.
|
// names.
|
||||||
if (strncmp(option->access_name, name, name_size) == 0)
|
if (strncmp(option->access_name, name, name_size) == 0 && option->access_name[name_size] == '\0')
|
||||||
{
|
{
|
||||||
return option;
|
return option;
|
||||||
}
|
}
|
||||||
@ -289,14 +261,8 @@ static void cag_option_parse_access_name(cag_option_context *context, char **c)
|
|||||||
// this option has one or not. Since we don't set any identifier specifically,
|
// this option has one or not. Since we don't set any identifier specifically,
|
||||||
// it will remain '?' within the context.
|
// it will remain '?' within the context.
|
||||||
option = cag_option_find_by_name(context, n, (size_t)(*c - n));
|
option = cag_option_find_by_name(context, n, (size_t)(*c - n));
|
||||||
if (option == NULL)
|
if (option != NULL)
|
||||||
{
|
{
|
||||||
// Since this option is invalid, we will move on to the next index. There is
|
|
||||||
// nothing we can do about this.
|
|
||||||
++context->index;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We found an option and now we can specify the identifier within the
|
// We found an option and now we can specify the identifier within the
|
||||||
// context.
|
// context.
|
||||||
context->identifier = option->identifier;
|
context->identifier = option->identifier;
|
||||||
@ -304,6 +270,12 @@ static void cag_option_parse_access_name(cag_option_context *context, char **c)
|
|||||||
// And now we try to parse the value. This function will also check whether
|
// And now we try to parse the value. This function will also check whether
|
||||||
// this option is actually supposed to have a value.
|
// this option is actually supposed to have a value.
|
||||||
cag_option_parse_value(context, option, c);
|
cag_option_parse_value(context, option, c);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Remember the error index so that we can print a error message.
|
||||||
|
context->error_index = context->index;
|
||||||
|
}
|
||||||
|
|
||||||
// And finally we move on to the next index.
|
// And finally we move on to the next index.
|
||||||
++context->index;
|
++context->index;
|
||||||
@ -313,8 +285,9 @@ static void cag_option_parse_access_letter(cag_option_context *context,
|
|||||||
char **c)
|
char **c)
|
||||||
{
|
{
|
||||||
const cag_option *option;
|
const cag_option *option;
|
||||||
char *n = *c;
|
char *n, *v, letter;
|
||||||
char *v;
|
|
||||||
|
n = *c;
|
||||||
|
|
||||||
// Figure out which option this letter belongs to. This might return NULL if
|
// Figure out which option this letter belongs to. This might return NULL if
|
||||||
// the letter is not registered, which means the user supplied an unknown
|
// the letter is not registered, which means the user supplied an unknown
|
||||||
@ -322,22 +295,24 @@ static void cag_option_parse_access_letter(cag_option_context *context,
|
|||||||
// option. We have to skip the value parsing since we don't know whether the
|
// option. We have to skip the value parsing since we don't know whether the
|
||||||
// user thinks this option has one or not. Since we don't set any identifier
|
// user thinks this option has one or not. Since we don't set any identifier
|
||||||
// specifically, it will remain '?' within the context.
|
// specifically, it will remain '?' within the context.
|
||||||
option = cag_option_find_by_letter(context, n[context->inner_index]);
|
letter = n[context->inner_index];
|
||||||
|
option = cag_option_find_by_letter(context, letter);
|
||||||
|
v = &n[++context->inner_index];
|
||||||
if (option == NULL)
|
if (option == NULL)
|
||||||
{
|
{
|
||||||
++context->index;
|
context->error_index = context->index;
|
||||||
context->inner_index = 0;
|
context->error_letter = letter;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
// We found an option and now we can specify the identifier within the
|
// We found an option and now we can specify the identifier within the
|
||||||
// context.
|
// context.
|
||||||
context->identifier = option->identifier;
|
context->identifier = option->identifier;
|
||||||
|
|
||||||
// And now we try to parse the value. This function will also check whether
|
// And now we try to parse the value. This function will also check whether
|
||||||
// this option is actually supposed to have a value.
|
// this option is actually supposed to have a value.
|
||||||
v = &n[++context->inner_index];
|
|
||||||
cag_option_parse_value(context, option, &v);
|
cag_option_parse_value(context, option, &v);
|
||||||
|
}
|
||||||
|
|
||||||
// Check whether we reached the end of this option argument.
|
// Check whether we reached the end of this option argument.
|
||||||
if (*v == '\0')
|
if (*v == '\0')
|
||||||
@ -351,18 +326,24 @@ static void cag_option_shift(cag_option_context *context, int start, int option,
|
|||||||
int end)
|
int end)
|
||||||
{
|
{
|
||||||
char *tmp;
|
char *tmp;
|
||||||
int a_index, shift_index, shift_count, left_index, right_index;
|
int a_index, shift_index, left_shift, right_shift, target_index, source_index;
|
||||||
|
|
||||||
shift_count = option - start;
|
// The block between start and option will be shifted to the end, and the
|
||||||
|
// order of everything will be preserved. Left shift is the amount of indexes
|
||||||
|
// the block between option and end will shift towards the start, and right
|
||||||
|
// shift is the amount of indexes the block between start and option will be
|
||||||
|
// shifted towards the end.
|
||||||
|
left_shift = option - start;
|
||||||
|
right_shift = end - option;
|
||||||
|
|
||||||
// There is no shift is required if the start and the option have the same
|
// There is no shift is required if the start and the option have the same
|
||||||
// index.
|
// index.
|
||||||
if (shift_count == 0)
|
if (left_shift == 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lets loop through the option strings first, which we will move towards the
|
// Let's loop through the option strings first, which we will move towards the
|
||||||
// beginning.
|
// beginning.
|
||||||
for (a_index = option; a_index < end; ++a_index)
|
for (a_index = option; a_index < end; ++a_index)
|
||||||
{
|
{
|
||||||
@ -372,20 +353,33 @@ static void cag_option_shift(cag_option_context *context, int start, int option,
|
|||||||
|
|
||||||
// Let's loop over all option values and shift them one towards the end.
|
// Let's loop over all option values and shift them one towards the end.
|
||||||
// This will override the option value we just stored temporarily.
|
// This will override the option value we just stored temporarily.
|
||||||
for (shift_index = 0; shift_index < shift_count; ++shift_index)
|
for (shift_index = 0; shift_index < left_shift; ++shift_index)
|
||||||
{
|
{
|
||||||
left_index = a_index - shift_index;
|
target_index = a_index - shift_index;
|
||||||
right_index = a_index - shift_index - 1;
|
source_index = a_index - shift_index - 1;
|
||||||
context->argv[left_index] = context->argv[right_index];
|
context->argv[target_index] = context->argv[source_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now restore the saved option value at the beginning.
|
// Now restore the saved option value at the beginning.
|
||||||
context->argv[a_index - shift_count] = tmp;
|
context->argv[a_index - left_shift] = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The new index will be before all non-option values, in such a way that they
|
// The new index will be before all non-option values, in such a way that they
|
||||||
// all will be moved again in the next fetch call.
|
// all will be moved again in the next fetch call.
|
||||||
context->index = end - shift_count;
|
context->index = end - left_shift;
|
||||||
|
|
||||||
|
// The error index may have changed, we need to fix that as well.
|
||||||
|
if (context->error_index >= start)
|
||||||
|
{
|
||||||
|
if (context->error_index < option)
|
||||||
|
{
|
||||||
|
context->error_index += right_shift;
|
||||||
|
}
|
||||||
|
else if (context->error_index < end)
|
||||||
|
{
|
||||||
|
context->error_index -= left_shift;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool cag_option_is_argument_string(const char *c)
|
static bool cag_option_is_argument_string(const char *c)
|
||||||
@ -395,17 +389,22 @@ static bool cag_option_is_argument_string(const char *c)
|
|||||||
|
|
||||||
static int cag_option_find_next(cag_option_context *context)
|
static int cag_option_find_next(cag_option_context *context)
|
||||||
{
|
{
|
||||||
int next_index, next_option_index;
|
// Prepare to search the next option at the next index.
|
||||||
|
int next_index;
|
||||||
char *c;
|
char *c;
|
||||||
|
|
||||||
// Prepare to search the next option at the next index.
|
|
||||||
next_index = context->index;
|
next_index = context->index;
|
||||||
next_option_index = next_index;
|
|
||||||
|
|
||||||
// Grab a pointer to the string and verify that it is not the end. If it is
|
// Let's verify that it is not the end If it is
|
||||||
// the end, we have to return false to indicate that we finished.
|
// the end we have to return -1 to indicate that we finished.
|
||||||
c = context->argv[next_option_index];
|
if (next_index >= context->argc)
|
||||||
if (context->forced_end || c == NULL || (uintptr_t)c == (uintptr_t)0xfffffffffffff000 /* TODO: workaround */)
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grab a pointer to the argument string.
|
||||||
|
c = context->argv[next_index];
|
||||||
|
if (context->forced_end || c == NULL)
|
||||||
{
|
{
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -415,18 +414,23 @@ static int cag_option_find_next(cag_option_context *context)
|
|||||||
// as an option neither.
|
// as an option neither.
|
||||||
while (!cag_option_is_argument_string(c))
|
while (!cag_option_is_argument_string(c))
|
||||||
{
|
{
|
||||||
c = context->argv[++next_option_index];
|
if (++next_index >= context->argc)
|
||||||
if (c == NULL)
|
|
||||||
{
|
{
|
||||||
// We reached the end and did not find any argument anymore. Let's tell
|
// We reached the end and did not find any argument anymore. Let's tell
|
||||||
// our caller that we reached the end.
|
// our caller that we reached the end.
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c = context->argv[next_index];
|
||||||
|
if (c == NULL)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Indicate that we found an option which can be processed. The index of the
|
// Indicate that we found an option which can be processed. The index of the
|
||||||
// next option will be returned.
|
// next option will be returned.
|
||||||
return next_option_index;
|
return next_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cag_option_fetch(cag_option_context *context)
|
bool cag_option_fetch(cag_option_context *context)
|
||||||
@ -439,6 +443,8 @@ bool cag_option_fetch(cag_option_context *context)
|
|||||||
// parameter from the previous option to this one.
|
// parameter from the previous option to this one.
|
||||||
context->identifier = '?';
|
context->identifier = '?';
|
||||||
context->value = NULL;
|
context->value = NULL;
|
||||||
|
context->error_index = -1;
|
||||||
|
context->error_letter = 0;
|
||||||
|
|
||||||
// Check whether there are any options left to parse and remember the old
|
// Check whether there are any options left to parse and remember the old
|
||||||
// index as well as the new index. In the end we will move the option junk to
|
// index as well as the new index. In the end we will move the option junk to
|
||||||
@ -493,7 +499,7 @@ bool cag_option_fetch(cag_option_context *context)
|
|||||||
return context->forced_end == false;
|
return context->forced_end == false;
|
||||||
}
|
}
|
||||||
|
|
||||||
char cag_option_get(const cag_option_context *context)
|
char cag_option_get_identifier(const cag_option_context *context)
|
||||||
{
|
{
|
||||||
// We just return the identifier here.
|
// We just return the identifier here.
|
||||||
return context->identifier;
|
return context->identifier;
|
||||||
@ -510,3 +516,98 @@ int cag_option_get_index(const cag_option_context *context)
|
|||||||
// Either we point to a value item,
|
// Either we point to a value item,
|
||||||
return context->index;
|
return context->index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CAG_PUBLIC int cag_option_get_error_index(const cag_option_context *context)
|
||||||
|
{
|
||||||
|
// This is set
|
||||||
|
return context->error_index;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAG_PUBLIC char cag_option_get_error_letter(const cag_option_context *context)
|
||||||
|
{
|
||||||
|
// This is set to the unknown option letter if it was parsed.
|
||||||
|
return context->error_letter;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAG_PUBLIC void cag_option_printer_error(const cag_option_context *context,
|
||||||
|
cag_printer printer, void *printer_ctx)
|
||||||
|
{
|
||||||
|
int error_index;
|
||||||
|
char error_letter;
|
||||||
|
|
||||||
|
error_index = cag_option_get_error_index(context);
|
||||||
|
if (error_index < 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_letter = cag_option_get_error_letter(context);
|
||||||
|
if (error_letter)
|
||||||
|
{
|
||||||
|
printer(printer_ctx, "Unknown option '%c' in '%s'.\n", error_letter,
|
||||||
|
context->argv[error_index]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printer(printer_ctx, "Unknown option '%s'.\n", context->argv[error_index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CAG_PUBLIC void cag_option_printer(const cag_option *options,
|
||||||
|
size_t option_count, cag_printer printer, void *printer_ctx)
|
||||||
|
{
|
||||||
|
size_t option_index, indention, i, accessor_length;
|
||||||
|
const cag_option *option;
|
||||||
|
bool first;
|
||||||
|
|
||||||
|
indention = cag_option_get_print_indention(options, option_count);
|
||||||
|
|
||||||
|
for (option_index = 0; option_index < option_count; ++option_index)
|
||||||
|
{
|
||||||
|
option = &options[option_index];
|
||||||
|
accessor_length = 0;
|
||||||
|
first = true;
|
||||||
|
|
||||||
|
printer(printer_ctx, " ");
|
||||||
|
|
||||||
|
cag_option_print_letters(option, &first, &accessor_length, printer,
|
||||||
|
printer_ctx);
|
||||||
|
cag_option_print_name(option, &first, &accessor_length, printer,
|
||||||
|
printer_ctx);
|
||||||
|
cag_option_print_value(option, &accessor_length, printer, printer_ctx);
|
||||||
|
|
||||||
|
for (i = accessor_length; i < indention; ++i)
|
||||||
|
{
|
||||||
|
printer(printer_ctx, " ");
|
||||||
|
}
|
||||||
|
|
||||||
|
printer(printer_ctx, " %s\n", option->description);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef CAG_NO_FILE
|
||||||
|
CAG_PUBLIC void cag_option_print_error(const cag_option_context *context,
|
||||||
|
FILE *destination)
|
||||||
|
{
|
||||||
|
cag_option_printer_error(context, (cag_printer)fprintf, destination);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CAG_NO_FILE
|
||||||
|
void cag_option_print(const cag_option *options, size_t option_count,
|
||||||
|
FILE *destination)
|
||||||
|
{
|
||||||
|
cag_option_printer(options, option_count, (cag_printer)fprintf, destination);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void cag_option_prepare(cag_option_context *context, const cag_option *options,
|
||||||
|
size_t option_count, int argc, char **argv)
|
||||||
|
{
|
||||||
|
cag_option_init(context, options, option_count, argc, argv);
|
||||||
|
}
|
||||||
|
|
||||||
|
char cag_option_get(const cag_option_context *context)
|
||||||
|
{
|
||||||
|
return cag_option_get_identifier(context);
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user