getopt wrapper

This commit is contained in:
overflowerror 2018-02-10 18:12:47 +01:00
parent de2946c9fa
commit 7c783adc6e
4 changed files with 208 additions and 3 deletions

View file

@ -28,6 +28,5 @@ The compiled files are in `./bin/`.
## TODO ## TODO
- automated getopt-wrapper (ev with help message generator)
- simplified socket-management - simplified socket-management
- simplified process-management (fork/exec, shm, semaphores, pthread, ...) - simplified process-management (fork/exec, shm, semaphores, pthread, ...)

View file

@ -2,6 +2,7 @@
#include "seaboot.h" #include "seaboot.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <time.h> #include <time.h>
BOOT(init); BOOT(init);
@ -10,7 +11,20 @@ void init() {
printf("Hello World!\n"); printf("Hello World!\n");
boot.mode = WAIT; boot.mode = WAIT;
boot.debug = true; boot.debug = false;
int test = 0;
boot.options.add('t', "test", OPTIONAL_ARGUMENT, true, lambda(bool, (const char* argument) {
if (argument != NULL)
test = strtol(argument, NULL, 10);
return true;
}));
if (boot.options.parse() < 0) {
fprintf(stderr, "Error: %s\n", boot.error);
fprintf(stderr, "The only possible option is -t.\n");
exit(EXIT_ERROR);
}
printf("Test-value is %d.\n", test);
boot.events.addEventListener(SHUTDOWN, lambda(void, (event_t event) { boot.events.addEventListener(SHUTDOWN, lambda(void, (event_t event) {
fprintf(stderr, "Shuting down.\n"); fprintf(stderr, "Shuting down.\n");

View file

@ -11,8 +11,21 @@
#include <unistd.h> #include <unistd.h>
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <getopt.h>
#include <assert.h>
static const char* getEventName(event_t event) { static const char* getEventName(event_t event) {
// TODO
if (IS_SIGNAL(event))
return strsignal(event);
switch(event) {
case SHUTDOWN: return "Shutdown"; break;
case LIBERROR: return "Lib-Error"; break;
default: return "Unknown"; break;
}
}
static const char* getEventDescription(event_t event) {
if (IS_SIGNAL(event)) if (IS_SIGNAL(event))
return strsignal(event); return strsignal(event);
switch(event) { switch(event) {
@ -45,11 +58,17 @@ static void eventHandler(event_t);
static void* allocate(size_t); static void* allocate(size_t);
static void* reallocate(void*, size_t); static void* reallocate(void*, size_t);
static bool addOption(char, const char*, optionArgument_t, bool, optionHandler_t);
static int parseOptions(void);
static const char* getNextArgument();
struct boot boot = { struct boot boot = {
.events.addEventListener = addEventListener, .events.addEventListener = addEventListener,
.events.removeEventListener = removeEventListener, .events.removeEventListener = removeEventListener,
.events.enableSignal = enableSignal, .events.enableSignal = enableSignal,
.events.disableSignal = disableSignal, .events.disableSignal = disableSignal,
.events.getName = getEventName,
.events.getDescription = getEventDescription,
.time.getRealTime = getRealTime, .time.getRealTime = getRealTime,
.time.getRelativeTime = getRelativeTime, .time.getRelativeTime = getRelativeTime,
@ -63,6 +82,10 @@ struct boot boot = {
.time.stopTimer = stopTimer, .time.stopTimer = stopTimer,
.time.deleteTimer = deleteTimer, .time.deleteTimer = deleteTimer,
.options.add = addOption,
.options.parse = parseOptions,
.options.getNextArgument = getNextArgument,
.allocate = allocate, .allocate = allocate,
.reallocate = reallocate, .reallocate = reallocate,
@ -332,7 +355,150 @@ void* reallocate(void* pointer, size_t size) {
return result; return result;
} }
int main(char** argv, int argc) { struct optionHandlers {
char shortOption;
const char* longOption;
optionArgument_t argument;
bool required;
optionHandler_t handler;
int seen;
};
int optionNumber = 0;
struct optionHandlers options[MAX_OPTIONS];
char** arguments;
int argumentCount;
bool addOption(char shortOption, const char* longOption, optionArgument_t argument, bool required, optionHandler_t handler) {
if ((shortOption == NO_SHORT_OPTION && longOption == NO_LONG_OPTION) || handler == NULL) {
boot.error = "Option settings are invalid.";
return false;
}
options[optionNumber++] = (struct optionHandlers) {
.shortOption = shortOption,
.longOption = longOption,
.argument = argument,
.required = required,
.handler = handler,
.seen = 0
};
return true;
}
int parseOptions() {
debug("Parseing options. Got %d options.\n", optionNumber);
if (optionNumber == 0)
return argumentCount - 1;
debug("Generating short-option-string & long-option-array.\n");
int number_short = 0;
char short_options[optionNumber * 3 + 1];
memset(short_options, 0, optionNumber * 3 + 1);
int number_long = 0;
struct option long_options[optionNumber + 1];
memset(long_options, 0, (optionNumber + 1) * sizeof(struct option));
for (int i = 0; i < optionNumber; i++) {
struct optionHandlers handler = options[i];
if (handler.shortOption != NO_SHORT_OPTION) {
short_options[number_short++] = handler.shortOption;
debug("Got short option: %c\n", handler.shortOption);
if (handler.argument == REQUIRED_ARGUMENT)
short_options[number_short++] = ':';
if (handler.argument == OPTIONAL_ARGUMENT) {
short_options[number_short++] = ':';
short_options[number_short++] = ':';
}
}
if (handler.longOption != NO_LONG_OPTION) {
int arg;
switch(handler.argument) {
case NO_ARGUMENT:
arg = no_argument;
break;
case OPTIONAL_ARGUMENT:
arg = optional_argument;
break;
case REQUIRED_ARGUMENT:
arg = required_argument;
break;
default:
assert(false);
}
debug("Got long option: %s (arg: %d, short: %c)\n", handler.longOption, arg, handler.shortOption);
long_options[number_long++] = (struct option) {
.name = handler.longOption,
.has_arg = arg,
.flag = NULL,
.val = handler.shortOption
};
}
}
long_options[number_long] = (struct option) {
.name = NULL,
.has_arg = 0,
.flag = NULL,
.val = 0
};
int tmp, option_index;
debug("getopt_long(%d, %x, %s, %x, %x)\n", argumentCount, arguments, short_options, long_options, option_index);
while((tmp = getopt_long(argumentCount, arguments, short_options, long_options, &option_index)) != -1) {
debug("getopt: %d\n", tmp);
struct optionHandlers* handler = NULL;
if (tmp == '?') {
boot.error = "Unknown option.";
return OPTION_UNKNOWN;
} else if (tmp == NO_SHORT_OPTION) {
for (int i = 0; i < optionNumber; i++) {
if (strcmp(options[i].longOption, long_options[option_index].name) == 0) {
handler = &(options[i]);
break;
}
}
if (handler == NULL)
assert(false);
} else {
for (int i = 0; i < optionNumber; i++) {
debug("Checking %c (%d) - %c (%d).\n", tmp, tmp, options[i].shortOption, options[i].shortOption);
if (tmp == options[i].shortOption) {
handler = &(options[i]);
break;
}
}
if (handler == NULL)
assert(false);
}
handler->seen++;
debug("Starting handler for %s (%c).\n", handler->longOption, (handler->shortOption == NO_SHORT_OPTION) ? '-' : handler->shortOption);
if (!(handler->handler(optarg))) {
boot.error = "Option handler returned an error.";
return OPTION_HANDLER_ERROR;
}
}
for (int i = 0; i < optionNumber; i++) {
if (options[i].seen == 0 && options[i].required) {
boot.error = "Required option is missing.";
return OPTION_MISSING;
}
}
return argumentCount - optind;
}
const char* getNextArgument() {
if (argumentCount == optind)
return NULL;
return arguments[optind++];
}
int main(int argc, char** argv) {
arguments = argv;
argumentCount = argc;
for(int i = 0; i < NUMBER_OF_EVENTS; i++) { for(int i = 0; i < NUMBER_OF_EVENTS; i++) {
debug("Setup %s %d (%s)...\n", IS_SIGNAL(i) ? "signal" : "event", i, getEventName(i)); debug("Setup %s %d (%s)...\n", IS_SIGNAL(i) ? "signal" : "event", i, getEventName(i));
events[i].number = 0; events[i].number = 0;

View file

@ -14,6 +14,8 @@
#define IS_SIGNAL(v) (v >= 1 && v <= 31) #define IS_SIGNAL(v) (v >= 1 && v <= 31)
#define MAX_OPTIONS 20
typedef unsigned long long int nstime_t; typedef unsigned long long int nstime_t;
typedef enum bootmode { typedef enum bootmode {
@ -72,6 +74,8 @@ struct events {
bool (*removeEventListener)(event_t, eventListener_t); bool (*removeEventListener)(event_t, eventListener_t);
bool (*enableSignal)(event_t); bool (*enableSignal)(event_t);
bool (*disableSignal)(event_t); bool (*disableSignal)(event_t);
const char* (*getName)(event_t event);
const char* (*getDescription)(event_t event);
}; };
struct time { struct time {
@ -89,12 +93,34 @@ struct time {
void (*deleteTimer)(timer_t); void (*deleteTimer)(timer_t);
}; };
#define OPTION_UNKNOWN (-1)
#define OPTION_MISSING (-2)
#define OPTION_HANDLER_ERROR (-3)
#define NO_SHORT_OPTION 0
#define NO_LONG_OPTION NULL
typedef enum optionArgument {
NO_ARGUMENT,
OPTIONAL_ARGUMENT,
REQUIRED_ARGUMENT
} optionArgument_t;
typedef bool (*optionHandler_t)(const char*);
struct options {
bool (*add)(char, const char*, optionArgument_t, bool, optionHandler_t);
int (*parse)(void);
const char* (*getNextArgument)();
};
extern struct boot { extern struct boot {
init_t init; init_t init;
loop_t loop; loop_t loop;
struct events events; struct events events;
struct time time; struct time time;
struct options options;
void* (*allocate)(size_t); void* (*allocate)(size_t);
void* (*reallocate)(void*, size_t); void* (*reallocate)(void*, size_t);