mirror of
https://github.com/sigmasternchen/seaboot
synced 2025-03-15 04:08:54 +00:00
getopt wrapper
This commit is contained in:
parent
de2946c9fa
commit
7c783adc6e
4 changed files with 208 additions and 3 deletions
|
@ -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, ...)
|
||||||
|
|
|
@ -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");
|
||||||
|
|
168
src/seaboot.c
168
src/seaboot.c
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue