mirror of
https://github.com/utkumaden/libmx.git
synced 2026-05-01 16:49:37 +02:00
178 lines
4.8 KiB
C
178 lines
4.8 KiB
C
#include <mx/options.h>
|
|
#include <mx/assert.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
MX_INLINE char* mx_strdup(const char **pptr, char *nstr, size_t len)
|
|
{
|
|
if (len == 0)
|
|
len = strlen(nstr);
|
|
|
|
char *ptr = realloc(*pptr, len + 1);
|
|
MX_ASSERT_OOM(ptr);
|
|
|
|
memcpy(ptr, nstr, len);
|
|
ptr[len] = '\0';
|
|
|
|
return (*pptr = ptr);
|
|
}
|
|
|
|
MX_IMPL void mx_options_begin_r(mx_options_t *self, mx_optflag_t flags, int argc, const char **argv)
|
|
{
|
|
MX_ASSERT_SELFPTR(self);
|
|
MX_ASSERT_PTR(argv, "Argument array must be non-null.");
|
|
MX_ASSERT(argc > 0, "Arguments count must be greater than zero.");
|
|
|
|
self->flags = flags;
|
|
self->argv = argv;
|
|
self->argc = argc;
|
|
self->i = 0;
|
|
self->kind = MX_OPT_END;
|
|
self->key = NULL;
|
|
self->value = NULL;
|
|
}
|
|
|
|
MX_IMPL mx_optkind_t mx_options_next_r(mx_options_t *self)
|
|
{
|
|
MX_ASSERT_SELFPTR(self);
|
|
|
|
if (self->i >= self->argc)
|
|
{
|
|
return (self->kind = MX_OPT_END);
|
|
}
|
|
|
|
char *current = self->argv[self->i];
|
|
char *next = (self->i + 1 < self->argc) ? self->argv[self->i + 1] : NULL;
|
|
size_t clen = strlen(current);
|
|
|
|
if ((self->flags & MX_OPT_UNIX) && current[0] == '-')
|
|
{
|
|
/* - indicates a UNIX flag sequence. */
|
|
|
|
if (current[1] == '-')
|
|
{
|
|
if (current[2] == '\0')
|
|
{
|
|
/* -- */
|
|
self->i++;
|
|
return (self->kind = MX_OPT_DDASH);
|
|
}
|
|
else
|
|
{
|
|
/* --long-flag or --key=pair*/
|
|
|
|
char *equals = strchr(current, '=');
|
|
|
|
if (equals)
|
|
{
|
|
/* The equals is in this token. */
|
|
size_t len = (size_t)(equals - ¤t[2]);
|
|
mx_strdup(&self->key, ¤t[2], len);
|
|
|
|
if (equals[1] == '\0')
|
|
{
|
|
/* The value is in the next token. */
|
|
next = next ? next : "";
|
|
mx_strdup(&self->value, next, 0);
|
|
|
|
self->i++;
|
|
}
|
|
else
|
|
{
|
|
/* The value is also in this token.*/
|
|
mx_strdup(&self->value, &equals[1], 0);
|
|
}
|
|
|
|
self->i++;
|
|
return (self->kind = MX_OPT_PAIR);
|
|
}
|
|
else if (next && next[0] == '=')
|
|
{
|
|
/* The equals is in the next token. */
|
|
mx_strdup(&self->key, ¤t[2], clen-2);
|
|
mx_strdup(&self->value, &next[1], 0);
|
|
|
|
self->i += 2;
|
|
return (self->kind = MX_OPT_PAIR);
|
|
}
|
|
|
|
/* Don't treat this as a key pair. It's a long flag.*/
|
|
mx_strdup(&self->key, current, clen-2);
|
|
self->i++;
|
|
return (self->kind = MX_OPT_LONG);
|
|
}
|
|
}
|
|
else if (current[1] == '\0')
|
|
{
|
|
self->i++;
|
|
return (self->kind = MX_OPT_DASH);
|
|
}
|
|
else
|
|
{
|
|
mx_strdup(&self->key,¤t[1], clen - 1);
|
|
self->i++;
|
|
return (self->kind = MX_OPT_SHORT);
|
|
}
|
|
}
|
|
|
|
if ((self->flags & MX_OPT_DOS) && current[0] == '/')
|
|
{
|
|
/* / indicated a DOS flag sequence. */
|
|
|
|
char *colon = strchr(current, ':');
|
|
|
|
if (colon)
|
|
{
|
|
/* The colon is in this token. */
|
|
if (colon[1] == '\0')
|
|
{
|
|
/* The value is in the next token. */
|
|
next = next ? next : "";
|
|
mx_strdup(&self->value, next, 0);
|
|
self->i++;
|
|
}
|
|
else
|
|
{
|
|
/* The value is in this token. */
|
|
mx_strdup(&self->value, &colon[1], 0);
|
|
}
|
|
|
|
self->i++;
|
|
mx_strdup(&self->key, ¤t[1], (size_t)(colon-¤t[1]));
|
|
return (self->kind = MX_OPT_PAIR);
|
|
}
|
|
else if (next && next[0]==':')
|
|
{
|
|
/* The colon is in the next token. */
|
|
mx_strdup(&self->key, ¤t[1], clen-1);
|
|
mx_strdup(&self->value, &next[1], 0);
|
|
self->i+=2;
|
|
return (self->kind = MX_OPT_PAIR);
|
|
}
|
|
else
|
|
{
|
|
self->i++;
|
|
mx_strdup(&self->key, ¤t[1], clen - 1);
|
|
return (self->kind = MX_OPT_LONG);
|
|
}
|
|
}
|
|
|
|
/* Otherwise treate as a positional argument. */
|
|
{
|
|
char *ptr = realloc(self->value, clen);
|
|
MX_ASSERT_OOM(ptr);
|
|
|
|
self->i++;
|
|
self->value = memcpy(ptr, current, clen);
|
|
return (self->kind = MX_OPT_POSITIONAL);
|
|
}
|
|
}
|
|
|
|
MX_IMPL void mx_options_end_r(mx_options_t *self)
|
|
{
|
|
if (self)
|
|
{
|
|
free(self->key);
|
|
free(self->value);
|
|
}
|
|
} |