diff options
author | pgen <p.gen.progs@gmail.com> | 2019-09-15 23:40:37 +0200 |
---|---|---|
committer | pgen <p.gen.progs@gmail.com> | 2019-10-01 00:32:56 +0200 |
commit | 24037bdfe6aaf3ba6fa3453869466b6fd7b2579d (patch) | |
tree | 5fc9a1e3eb2d9998d64cfc7b6f0d63e2042ed695 /ctxopt.c | |
parent | a2adfc0f3c304aec4a573478838ea769c3f590a8 (diff) |
Use ctxopt.[ch] for options management
The old getopt, derived from egetopt, was too restrictive, so I developed
ctxopt to better manage smenu options.
Diffstat (limited to 'ctxopt.c')
-rw-r--r-- | ctxopt.c | 3525 |
1 files changed, 3525 insertions, 0 deletions
diff --git a/ctxopt.c b/ctxopt.c new file mode 100644 index 0000000..3ff3fae --- /dev/null +++ b/ctxopt.c @@ -0,0 +1,3525 @@ +//#include "config.h" +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <ctype.h> +#include <sys/types.h> +#include <regex.h> +#include <stdarg.h> +#include <string.h> +#include "ctxopt.h" + +errors ctxopterrno = CTXOPTNOERR; + +/* *********************** */ +/* Static global variables */ +/* *********************** */ +static void * contexts_bst; +static void * options_bst; + +/* Prototypes */ + +/* ****************** */ +/* Messages interface */ +/* ****************** */ + +static void (**err_functions)(char *, char *, char *, char *, char *); + +static void +fatal(errors e, char * opt_par, char * opt_params, char * opt_name, + char * ctx_par, char * ctx_name, const char * format, ...); + +static void +error(const char * format, ...); + +static int user_rc; /* Used by various callback functions */ +static int user_value; /* Used by various callback functions */ +static char * user_string; /* Used by various callback functions */ +static void * user_object; /* Used by various callback functions */ + +/* *************************** */ +/* Memory management interface */ +/* *************************** */ + +static void * +xmalloc(size_t size); + +static void * +xcalloc(size_t num, size_t size); + +static void * +xrealloc(void * ptr, size_t size); + +static char * +xstrdup(const char * p); + +static char * +xstrndup(const char * str, size_t len); + +/* ************* */ +/* BST interface */ +/* ************* */ +typedef struct bst_s bst_t; + +typedef enum +{ + preorder, + postorder, + endorder, + leaf +} walk_order_e; + +static void * +bst_delete(const void * vkey, void ** vrootp, + int (*compar)(const void *, const void *)); + +static void +bst_destroy_recurse(bst_t * root, void (*free_action)(void *)); + +static void +bst_destroy(void * vrootp, void (*freefct)(void *)); + +static void * +bst_find(const void * vkey, void * const * vrootp, + int (*compar)(const void *, const void *)); + +static void * +bst_search(const void * vkey, void ** vrootp, + int (*compar)(const void *, const void *)); + +static void +bst_walk_recurse(const bst_t * root, + void (*action)(const void *, walk_order_e, int), int level); + +static void +bst_walk(const void * vroot, void (*action)(const void *, walk_order_e, int)); + +/* ********************* */ +/* Linked list Interface */ +/* ********************* */ + +typedef struct ll_node_s ll_node_t; +typedef struct ll_s ll_t; + +static void +ll_append(ll_t * const list, void * const data); + +static void +ll_prepend(ll_t * const list, void * const data); + +static void +ll_insert_after(ll_t * const list, ll_node_t * node, void * const data); + +static void +ll_insert_before(ll_t * const list, ll_node_t * node, void * const data); + +static int +ll_delete(ll_t * const list, ll_node_t * node); + +static ll_node_t * +ll_find(ll_t * const, void * const, int (*)(const void *, const void *)); + +static void +ll_init(ll_t * list); + +static ll_node_t * +ll_new_node(void); + +static ll_t * +ll_new(void); + +static int +ll_strarray(ll_t * list, ll_node_t * start_node, int * count, char *** array); + +/* ****************** */ +/* various interfaces */ +/* ****************** */ + +static void +ltrim(char * str, const char * trim_str); + +static void +rtrim(char * str, const char * trim_str, size_t min); + +static int +strchrcount(char * str, char c); + +int +strpref(char * s1, char * s2); + +static char * +xstrtok_r(char * str, const char * delim, char ** end); + +/* ************* */ +/* cop interface */ +/* ************* */ + +typedef struct opt_s opt_t; +typedef struct par_s par_t; +typedef struct ctx_s ctx_t; +typedef struct constraint_s constraint_t; +typedef struct ctx_inst_s ctx_inst_t; +typedef struct opt_inst_s opt_inst_t; +typedef struct seen_opt_s seen_opt_t; + +static char * +strtoken(char * s, char * token, size_t tok_len, char * pattern, int * pos); + +static int +ctx_compare(const void * c1, const void * c2); + +static int +opt_compare(const void * o1, const void * o2); + +static int +par_compare(const void * a1, const void * a2); + +static int +seen_opt_compare(const void * so1, const void * so2); + +static int +str_compare(const void * s1, const void * s2); + +static ctx_t * +locate_ctx(char * name); + +static opt_t * +locate_opt(char * name); + +static par_t * +locate_par(char * name, ctx_t * ctx); + +static void +bst_seen_opt_cb(const void * node, walk_order_e kind, int level); + +static void +bst_seen_opt_seen_cb(const void * node, walk_order_e kind, int level); + +static void +bst_print_ctx_cb(const void * node, walk_order_e kind, int level); + +static void +match_prefix_cb(const void * node, walk_order_e kind, int level); + +static int +has_unseen_mandatory_opt(ctx_inst_t * ctx_inst); + +static int +opt_parse(char * s, opt_t ** opt); + +static int +init_opts(char * spec, ctx_t * ctx); + +static int +ctxopt_build_cmdline_list(int nb_words, char ** words); + +static int +opt_set_parms(char * opt_name, char * par_str); + +static ctx_inst_t * +new_ctx_inst(ctx_t * ctx, ctx_inst_t * prev_ctx_inst); + +static void +evaluate_ctx_inst(ctx_inst_t * ctx_inst); + +/* ====================== */ +/* Message implementation */ +/* ====================== */ +static void +fatal(errors e, char * opt_par, char * opt_params, char * opt_name, + char * ctx_par, char * ctx_name, const char * format, ...) +{ + va_list args; + + ctxopterrno = e; + + if (e == CTXOPTINTERNAL) + fprintf(stderr, "ctxopt internal: "); + + if (err_functions[e] != NULL) + err_functions[e](opt_par, opt_params, opt_name, ctx_par, ctx_name); + else + { + va_start(args, format); + vfprintf(stderr, format, args); + fprintf(stderr, "\n"); + } + + if (opt_par != NULL) + ctxopt_disp_usage(continue_after); + + va_end(args); + + exit(EXIT_FAILURE); +} + +static void +error(const char * format, ...) +{ + va_list args; + + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + ctxopt_disp_usage(exit_after); +} + +/* ******************************** */ +/* Memory management implementation */ +/* ******************************** */ + +/* ================= */ +/* Customized malloc */ +/* ================= */ +static void * +xmalloc(size_t size) +{ + void * allocated; + size_t real_size; + + real_size = (size > 0) ? size : 1; + allocated = malloc(real_size); + if (allocated == NULL) + fatal(CTXOPTINTERNAL, NULL, NULL, NULL, NULL, NULL, + "Insufficient memory (attempt to malloc %lu bytes)\n", + (unsigned long int)size); + + return allocated; +} + +/* ================= */ +/* Customized calloc */ +/* ================= */ +static void * +xcalloc(size_t n, size_t size) +{ + void * allocated; + + n = (n > 0) ? n : 1; + size = (size > 0) ? size : 1; + allocated = calloc(n, size); + if (allocated == NULL) + fatal(CTXOPTINTERNAL, NULL, NULL, NULL, NULL, NULL, + "Insufficient memory (attempt to calloc %lu bytes)\n", + (unsigned long int)size); + + return allocated; +} + +/* ================== */ +/* Customized realloc */ +/* ================== */ +static void * +xrealloc(void * p, size_t size) +{ + void * allocated; + + allocated = realloc(p, size); + if (allocated == NULL && size > 0) + fatal(CTXOPTINTERNAL, NULL, NULL, NULL, NULL, NULL, + "Insufficient memory (attempt to xrealloc %lu bytes)\n", + (unsigned long int)size); + + return allocated; +} + +/* =================================== */ +/* strdup implementation using xmalloc */ +/* =================================== */ +static char * +xstrdup(const char * p) +{ + char * allocated; + + allocated = xmalloc(strlen(p) + 1); + strcpy(allocated, p); + + return allocated; +} + +/* ================================================== */ +/* strndup implementation using xmalloc */ +/* This version guarantees that there is a final '\0' */ +/* ================================================== */ +static char * +xstrndup(const char * str, size_t len) +{ + char * p; + + p = memchr(str, '\0', len); + + if (p) + len = p - str; + + p = xmalloc(len + 1); + memcpy(p, str, len); + p[len] = '\0'; + + return p; +} + +/* ************************** */ +/* Linked list implementation */ +/* ************************** */ + +/* Linked list node structure */ +/* """""""""""""""""""""""""" */ +struct ll_node_s +{ + void * data; + struct ll_node_s * next; + struct ll_node_s * prev; +}; + +/* Linked List structure */ +/* """"""""""""""""""""" */ +struct ll_s +{ + ll_node_t * head; + ll_node_t * tail; + long len; +}; + +/* ======================== */ +/* Create a new linked list */ +/* ======================== */ +static ll_t * +ll_new(void) +{ + ll_t * ret = xmalloc(sizeof(ll_t)); + ll_init(ret); + + return ret; +} + +/* ======================== */ +/* Initialize a linked list */ +/* ======================== */ +static void +ll_init(ll_t * list) +{ + list->head = NULL; + list->tail = NULL; + list->len = 0; +} + +/* ==================================================== */ +/* Allocate the space for a new node in the linked list */ +/* ==================================================== */ +static ll_node_t * +ll_new_node(void) +{ + ll_node_t * ret = xmalloc(sizeof(ll_node_t)); + + return ret; +} + +/* ==================================================================== */ +/* Append a new node filled with its data at the end of the linked list */ +/* The user is responsible for the memory management of the data */ +/* ==================================================================== */ +static void +ll_append(ll_t * const list, void * const data) +{ + ll_node_t * node; + + node = ll_new_node(); /* ll_new_node cannot return NULL because it * + | uses xmalloc which does not return if there * + | is an allocation error. */ + + node->data = data; + node->next = NULL; + + node->prev = list->tail; + if (list->tail) + list->tail->next = node; + else + list->head = node; + + list->tail = node; + + ++list->len; +} + +/* =================================================================== */ +/* Put a new node filled with its data at the beginning of the linked */ +/* list. The user is responsible for the memory management of the data */ +/* =================================================================== */ +static void +ll_prepend(ll_t * const list, void * const data) +{ + ll_node_t * node; + + node = ll_new_node(); /* ll_new_node cannot return NULL because it * + | uses xmalloc which does not return if there * + | is an allocation error. */ + + node->data = data; + node->prev = NULL; + + node->next = list->head; + if (list->head) + list->head->prev = node; + else + list->tail = node; + + list->head = node; + + ++list->len; +} + +/* ======================================================= */ +/* Insert a new node before the specified node in the list */ +/* ======================================================= */ +static void +ll_insert_before(ll_t * const list, ll_node_t * node, void * const data) +{ + ll_node_t * new_node; + + if (node->prev == NULL) + ll_prepend(list, data); + else + { + new_node = ll_new_node(); /* ll_new_node cannot return NULL because it * + | uses xmalloc which does not return if there * + | is an allocation error. */ + + new_node->data = data; + new_node->next = node; + new_node->prev = node->prev; + node->prev->next = new_node; + node->prev = new_node; + + ++list->len; + } +} + +/* ====================================================== */ +/* Insert a new node after the specified node in the list */ +/* ====================================================== */ +void +ll_insert_after(ll_t * const list, ll_node_t * node, void * const data) +{ + ll_node_t * new_node; + + if (node->next == NULL) + ll_append(list, data); + else + { + new_node = ll_new_node(); /* ll_new_node cannot return NULL because it * + | uses xmalloc which does not return if there * + | is an allocation error. */ + + new_node->data = data; + new_node->prev = node; + new_node->next = node->next; + node->next->prev = new_node; + node->next = new_node; + + ++list->len; + } +} + +/* ================================================================ */ +/* Remove a node from a linked list */ +/* The memory taken by the deleted node must be freed by the caller */ +/* ================================================================ */ +static int +ll_delete(ll_t * const list, ll_node_t * node) +{ + if (list->head == list->tail) + { + if (list->head != NULL) + list->head = list->tail = NULL; + else + return 0; + } + else if (node->prev == NULL) + { + list->head = node->next; + list->head->prev = NULL; + } + else if (node->next == NULL) + { + list->tail = node->prev; + list->tail->next = NULL; + } + else + { + node->next->prev = node->prev; + node->prev->next = node->next; + } + + --list->len; + + return 1; +} + +/* =========================================================================*/ +/* Find a node in the list containing data. Return the node pointer or NULL */ +/* if not found. */ +/* A comparison function must be provided to compare a and b (strcmp like). */ +/* =========================================================================*/ +static ll_node_t * +ll_find(ll_t * const list, void * const data, + int (*cmpfunc)(const void * a, const void * b)) +{ + ll_node_t * node; + + if (NULL == (node = list->head)) + return NULL; + + do + { + if (0 == cmpfunc(node->data, data)) + return node; + } while (NULL != (node = node->next)); + + return NULL; +} + +/* ==================================================================== */ +/* Allocates and fills an array of strings from a list */ +/* WARNINGS: */ +/* 1) The list node must contain strings (char *) */ +/* 2) The strings in the resulting array MUST NOT be freed as the are */ +/* NOT copied from the strings of the list. */ +/* */ +/* IN list : The list from which the array is generated */ +/* IN start_node : The node of the list which will be the first node to */ +/* consider to create the array */ +/* OUT: count : The number of elements of the resulting array. */ +/* OUT: array : The resulting array. */ +/* RC : : The number of elements of the resulting array. */ +/* ==================================================================== */ +static int +ll_strarray(ll_t * list, ll_node_t * start_node, int * count, char *** array) +{ + int n = 0; + ll_node_t * node; + + *count = 0; + + node = start_node; + + if (list == NULL || node == NULL) + return 0; + + *array = xmalloc((list->len + 1) * sizeof(char **)); + while (node != NULL) + { + (*array)[n++] = (char *)(node->data); + (*count)++; + + node = node->next; + } + + (*array)[*count] = NULL; + *array = xrealloc(*array, ((*count) + 1) * sizeof(char **)); + + return *count; +} + +/* ******************************************************************* */ +/* BST (search.h compatible) implementation */ +/* */ +/* Tree search generalized from Knuth (6.2.2) Algorithm T just like */ +/* the AT&T man page says. */ +/* */ +/* Written by reading the System V Interface Definition, not the code. */ +/* */ +/* Totally public domain. */ +/* ******************************************************************* */ + +struct bst_s +{ + void * key; + struct bst_s * llink; + struct bst_s * rlink; +}; + +/* ========================== */ +/* delete node with given key */ +/* ========================== */ +static void * +bst_delete(const void * vkey, void ** vrootp, + int (*compar)(const void *, const void *)) +{ + bst_t ** rootp = (bst_t **)vrootp; + bst_t * p, *q, *r; + int cmp; + + if (rootp == NULL || (p = *rootp) == NULL) + return NULL; + + while ((cmp = (*compar)(vkey, (*rootp)->key)) != 0) + { + p = *rootp; + rootp = (cmp < 0) ? &(*rootp)->llink /* follow llink branch */ + : &(*rootp)->rlink; /* follow rlink branch */ + if (*rootp == NULL) + return NULL; /* key not found */ + } + r = (*rootp)->rlink; /* D1: */ + if ((q = (*rootp)->llink) == NULL) /* Left NULL? */ + q = r; + else if (r != NULL) + { /* Right link is NULL? */ + if (r->llink == NULL) + { /* D2: Find successor */ + r->llink = q; + q = r; + } + else + { /* D3: Find NULL link */ + for (q = r->llink; q->llink != NULL; q = r->llink) + r = q; + r->llink = q->rlink; + q->llink = (*rootp)->llink; + q->rlink = (*rootp)->rlink; + } + } + if (p != *rootp) + free(*rootp); /* D4: Free node */ + *rootp = q; /* link parent to new node */ + return p; +} + +/* ============== */ +/* destroy a tree */ +/* ============== */ +static void +bst_destroy_recurse(bst_t * root, void (*free_action)(void *)) +{ + if (root->llink != NULL) + bst_destroy_recurse(root->llink, free_action); + if (root->rlink != NULL) + bst_destroy_recurse(root->rlink, free_action); + + (*free_action)((void *)root->key); + free(root); +} + +static void +bst_destroy(void * vrootp, void (*freefct)(void *)) +{ + bst_t * root = (bst_t *)vrootp; + + if (root != NULL) + bst_destroy_recurse(root, freefct); +} + +/* ======================== */ +/* find a node, or return 0 */ +/* ======================== */ +static void * +bst_find(const void * vkey, void * const * vrootp, + int (*compar)(const void *, const void *)) +{ + bst_t * const * rootp = (bst_t * const *)vrootp; + + if (rootp == NULL) + return NULL; + + while (*rootp != NULL) + { /* T1: */ + int r; + + if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */ + return *rootp; /* key found */ + rootp = (r < 0) ? &(*rootp)->llink /* T3: follow left branch */ + : &(*rootp)->rlink; /* T4: follow right branch */ + } + return NULL; +} + +/* ===================================== */ +/* find or insert datum into search tree */ +/* ===================================== */ +static void * +bst_search(const void * vkey, void ** vrootp, + int (*compar)(const void *, const void *)) +{ + bst_t * q; + bst_t ** rootp = (bst_t **)vrootp; + + if (rootp == NULL) + return NULL; + + while (*rootp != NULL) + { /* Knuth's T1: */ + int r; + + if ((r = (*compar)(vkey, (*rootp)->key)) == 0) /* T2: */ + return *rootp; /* we found it! */ + + rootp = (r < 0) ? &(*rootp)->llink /* T3: follow left branch */ + : &(*rootp)->rlink; /* T4: follow right branch */ + } + + q = xmalloc(sizeof(bst_t)); /* T5: key not found */ + if (q != 0) + { /* make new node */ + *rootp = q; /* link new node to old */ + q->key = (void *)vkey; /* initialize new node */ + q->llink = q->rlink = NULL; + } + return q; +} + +/* ======================== */ +/* Walk the nodes of a tree */ +/* ======================== */ +static void +bst_walk_recurse(const bst_t * root, + void (*action)(const void *, walk_order_e, int), int level) +{ + if (root->llink == NULL && root->rlink == NULL) + (*action)(root, leaf, level); + else + { + (*action)(root, preorder, level); + if (root->llink != NULL) + bst_walk_recurse(root->llink, action, level + 1); + (*action)(root, postorder, level); + if (root->rlink != NULL) + bst_walk_recurse(root->rlink, action, level + 1); + (*action)(root, endorder, level); + } +} + +static void +bst_walk(const void * vroot, void (*action)(const void *, walk_order_e, int)) +{ + if (vroot != NULL && action != NULL) + bst_walk_recurse(vroot, action, 0); +} + +/* *********************** */ +/* various implementations */ +/* *********************** */ + +/* ======================= */ +/* Trim leading characters */ +/* ======================= */ +static void +ltrim(char * str, const char * trim_str) +{ + size_t len = strlen(str); + size_t begin = strspn(str, trim_str); + size_t i; + + if (begin > 0) + for (i = begin; i <= len; ++i) + str[i - begin] = str[i]; +} + +/* ================================================= */ +/* Trim trailing characters */ +/* The resulting string will have at least min bytes */ +/* even if trailing spaces remain. */ +/* ================================================= */ +static void +rtrim(char * str, const char * trim_str, size_t min) +{ + size_t len = strlen(str); + while (len > min && strchr(trim_str, str[len - 1])) + str[--len] = '\0'; +} + +/* ================================================== */ +/* Count the number of occurrences of the character c */ +/* in the string str. */ +/* The str pointer is assumed to be not NULL */ +/* ================================================== */ +static int +strchrcount(char * str, char c) +{ + int count = 0; + + while (*str) + if (*str++ == c) + count++; + + return count; +} + +/* =============================================== */ +/* Is the string str2 a prefix of the string str1? */ +/* =============================================== */ +int +strpref(char * str1, char * str2) +{ + while (*str1 != '\0' && *str1 == *str2) + { + str1++; + str2++; + } + + return *str2 == '\0'; +} + +/*===================================================================== */ +/* Allocate memory and safely concatenate strings. Stolen from a public */ +/* domain implementation which can be found here: */ +/* http://openwall.info/wiki/people/solar/software/\ */ +/* public-domain-source-code */ +/* ==================================================================== */ +static char * +concat(const char * s1, ...) +{ + va_list args; + const char * s; + char * p, *result; + size_t l, m, n; + + m = n = strlen(s1); + va_start(args, s1); + while ((s = va_arg(args, char *))) + { + l = strlen(s); + if ((m += l) < l) + break; + } + va_end(args); + if (s || m >= INT_MAX) + return NULL; + + result = (char *)xmalloc(m + 1); + + memcpy(p = result, s1, n); + p += n; + va_start(args, s1); + while ((s = va_arg(args, char *))) + { + l = strlen(s); + if ((n += l) < l || n > m) + break; + memcpy(p, s, l); + p += l; + } + va_end(args); + if (s || m != n || p != result + n) + { + free(result); + return NULL; + } + + *p = 0; + return result; +} + +/* ====================================================================== */ +/* public domain strtok_r() by Charlie Gordon */ +/* from comp.lang.c 9/14/2007 */ +/* http://groups.google.com/group/comp.lang.c/msg/2ab1ecbb86646684 */ +/* */ +/* (Declaration that it's public domain): */ +/* http://groups.google.com/group/comp.lang.c/msg/7c7b39328fefab9c */ +/* */ +/* Also, fixed by Fletcher T. Penney --- added the "return NULL" when */ +/* *end == NULL */ +/* ====================================================================== */ +static char * +xstrtok_r(char * str, const char * delim, char ** end) +{ + char * ret; + + if (str == NULL) + str = *end; + + if (str == NULL) + return NULL; + + str += strspn(str, delim); + + if (*str == '\0') + return NULL; + + ret = str; + + str += strcspn(str, delim); + + if (*str) + *str++ = '\0'; + + *end = str; + + return ret; +} + +/* =========================================================== */ +/* Fills an array of strings from the words composing a string */ +/* */ +/* str: initial string which will be altered */ +/* args: array of pointers to the start of the words in str */ +/* max: maximum number of words used before giving up */ +/* return: the number of words (<=max) */ +/* =========================================================== */ +static int +str2argv(char * str, char ** args, int max) +{ + int nb_args = 0; + + while (*str) + { + if (nb_args >= max) + return nb_args; + + while (*str == ' ' || *str == '\t') + *(str++) = '\0'; + + if (!*str) + return nb_args; + + args[nb_args] = str; + nb_args++; + + while (*str && (*str != ' ') && (*str != '\t')) + str++; + } + + return nb_args; +} + +/* ****************** */ +/* cop implementation */ +/* ****************** */ + +static int ctxopt_initialized = 0; /* cap_init has not yet been called */ + +/* context structure */ +/* """"""""""""""""" */ +struct ctx_s +{ + char * name; + ll_t * opt_list; /* list of options allowed in this context */ + ll_t * incomp_list; /* list of strings containing incompatible names * + | of options separated by spaces or tabs */ + int (*action)(char * name, int type, char * new_ctx, int ctx_nb_data, + void ** ctx_data); + void * par_bst; + int nb_data; + void ** data; +}; + +/* https://textik.com/#488ce3649b6c60f5 */ +/* */ +/* +--------------+ */ +/* |first_ctx_inst| */ +/* +---+----------+ */ +/* | */ +/* +--v-----+ +--------+ +--------+ +-----+ */ +/* +---+-->ctx_inst+------>opt_inst+----->opt_inst+------> ... | */ +/* | | +-+------+ +----+---+ +----+---+ +-----+ */ +/* | | | | | */ +/* | | +-v------+ | | */ +/* | +--+ctx_inst<-----------+ | */ +/* | +-+------+ | */ +/* | | | */ +/* | +-v------+ | */ +/* +------+ctx_inst<--------------------------+ */ +/* +-+------+ */ +/* | */ +/* +-v---+ */ +/* | ... | */ +/* +-----+ */ + +/* option structure */ +/* """""""""""""""" */ +struct opt_s +{ + char * name; /* option name */ + char * next_ctx; /* new context this option may lead to */ + ll_t * ctx_list; /* list of contexts allowing this option */ + char * params; /* string containing all the parameters of the option */ + + void (*action)(char * ctx_name, char * opt_name, char * par, int nb_args, + char ** args, int nb_opt_data, void ** opt_data, + int nb_ctx_data, + void ** ctx_data); /* The option associated action */ + int nb_data; /* number of the data passed as argument to action */ + void ** data; /* void data passed as argument to action */ + + int args; /* pointer to the data passed to the action function */ + + int optional; /* 1 if the option is optional, else 0 */ + int multiple; /* 1 if the option can appear more than one time in a * + | context, else 0 */ + + int opt_count_matter; /* 1 if we must restrict the count, else 0 */ + int occurrences; /* Number of occurrences of the option in a context */ + char opt_count_oper; /* <, = or > */ + int opt_count_mark; /* Value to be compared to with opt_count_oper */ + char * arg; /* text represent the argument in in description of * + | the option. */ + int optional_args; /* 1 of option is optional else 0 */ + int multiple_args; /* 1 is option can appear more than once in a * + | context instance */ + + int opt_args_count_matter; /* 1 if we must restrict the count, else 0 */ + char opt_args_count_oper; /* <, = or > */ + int opt_args_count_mark; /* Value to be compared to with opt_count_oper */ + int eval_first; /* 1 if this option must be evaluated before * + |the options without this mark */ + + ll_t * constraints_list; /* List of constraints checking functions * + | pointers. */ +}; + +/* context instance structure */ +/* """""""""""""""""""""""""" */ +struct ctx_inst_s +{ + ctx_t * ctx; /* the context whose this is an instance of */ + ctx_inst_t * prev_ctx_inst; /* ctx_inst of the opt_inst which led to the * + | creation of this ctx_inst structure. */ + opt_inst_t * gen_opt_inst; /* opt_inst which led to the creation of a * + | instance of this structure */ + ll_t * incomp_bst_list; /* list of seen_opt_t bst */ + void * seen_opt_bst; /* tree of seen_opt_t */ + ll_t * opt_inst_list; /* The list of option instances in this * + | context instance */ + char * par_name; /* parameter which created this instance */ +}; + +/* Option instance structure */ +/* """"""""""""""""""""""""" */ +struct opt_inst_s +{ + opt_t * opt; /* The option this is an instance of */ + char * opt_name; /* The option which led to this creation */ + char * par; /* The parameter which led to this creation */ + ll_t * values_list; /* The list of arguments of this option */ + ctx_inst_t * next_ctx_inst; /* The new context instance this option * + | instance may create */ +}; + +/* Structure used to check if an option has bee seen or not */ +/* in a context instance */ +/* """""""""""""""""""""""""""""""""""""""""""""""""""""""" */ +struct seen_opt_s +{ + opt_t * opt; /* The concerned option */ + char * par; /* Parameter which led to the making of this structure */ + char * count; /* Number of seen occurrences of this parameter */ + int seen; /* 1 if seen in the context instances, else 0 */ +}; + +/* parameter structure which links a parameter to the option it belongs to */ +/* """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" */ +struct par_s +{ + char * name; /* Parameter name (with the leading - */ + opt_t * opt; /* Attached option */ +}; + +/* Constraint structure */ +/* """""""""""""""""""" */ +struct constraint_s +{ + int (*constraint)(int nb_args, char ** args, char * value); + int nb_args; + char ** args; +}; + +static ll_t * cmdline_list; +static ctx_t * main_ctx = NULL; +static ctx_inst_t * first_ctx_inst = NULL; /* Pointer to the fist context * + | instance which holds the * + | options instances */ +static ll_t * ctx_inst_list; + +/* ====================================================== */ < |