aos/lib/getopt/getopt.c
Daniel Schwyn 6d444bf552 Main handout
Signed-off-by: Daniel Schwyn <daniel.schwyn@inf.ethz.ch>
2022-03-03 14:57:51 +01:00

197 lines
4.6 KiB
C

/**
* \file
* \brief Commandline parameter parsing.
*/
/*
* Copyright (c) 2007, 2008, ETH Zurich.
* All rights reserved.
*
* This file is distributed under the terms in the attached LICENSE file.
* If you do not find this file, copies can be found by writing to:
* ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>
#include <limits.h>
#include <getopt/getopt.h>
static int handle_ulong(unsigned long *var, const char *val)
{
assert(var != NULL);
int base;
// determine base (0x -> hex, anything else -> decimal)
if (val[0] == '0' && val[1] == 'x') {
base = 16;
val += 2;
} else {
base = 10;
}
unsigned long long x = strtoull(val, NULL, base);
if (x > ULONG_MAX) {
x = ULONG_MAX;
}
*var = (unsigned long)x;
return 0;
}
static int handle_long(long *var, const char *val)
{
assert(var != NULL);
int base;
// determine base (0x -> hex, anything else -> decimal)
if (val[0] == '0' && val[1] == 'x') {
base = 16;
val += 2;
} else {
base = 10;
}
long long x = strtoll(val, NULL, base);
assert(x >= LONG_MIN && x <= LONG_MAX); // XXX
*var = x;
return 0;
}
static int handle_uint(unsigned int *var, const char *val)
{
assert(var != NULL);
int base;
// determine base (0x -> hex, anything else -> decimal)
if (val[0] == '0' && val[1] == 'x') {
base = 16;
val += 2;
} else {
base = 10;
}
unsigned long x = strtoul(val, NULL, base);
if (x > UINT_MAX) {
x = UINT_MAX;
}
*var = (unsigned)x;
return 0;
}
static int handle_int(int *var, const char *val)
{
assert(var != NULL);
int base;
// determine base (0x -> hex, anything else -> decimal)
if (val[0] == '0' && val[1] == 'x') {
base = 16;
val += 2;
} else {
base = 10;
}
long x = strtol(val, NULL, base);
assert(x >= INT_MIN && x <= INT_MAX); // XXX
*var = (int)x;
return 0;
}
static int handle_bool(bool *var, const char *val)
{
assert(var != NULL);
if(!strncmp(val, "true", 4) || !strncmp(val, "yes", 3)) {
*var = true;
return 0;
} else if(!strncmp(val, "false", 5) || !strncmp(val, "no", 2)) {
*var = false;
return 0;
}
return -1;
}
static int handle_argument(const char *var, const char *val,
struct cmdarg *cmdargs)
{
// compare var against array of recognized arguments
for(int i = 0; cmdargs[i].arg != NULL; i++) {
struct cmdarg *a = &cmdargs[i];
if(!strncmp(var, a->arg, strlen(a->arg))) {
switch(a->type) {
case ArgType_Int:
return handle_int(a->var.integer, val);
case ArgType_UInt:
return handle_uint(a->var.uinteger, val);
case ArgType_Long:
return handle_long(a->var.longinteger, val);
case ArgType_ULong:
return handle_ulong(a->var.ulonginteger, val);
case ArgType_Bool:
return handle_bool(a->var.boolean, val);
case ArgType_Custom:
return a->var.handler(var, val);
default:
assert(!"Unknown type %d in kernel argument array!");
return -1;
}
}
}
return 0;
}
/**
* \brief Search backwards for character 'c' in string 'p'.
*
* Starts at the character, pointed to by 'p', within a string and searches
* backwards for 'c', returning a pointer to its position.
*
* WARNING: 'c' MUST exist prior to calling this function!!
*
* \param p Character to start searching backwards from.
* \param c Character to look for.
*
* \return Pointer to 'c' in string.
*/
static const char *look_back(const char *p, int c)
{
while(*p != c) {
p--;
}
return p;
}
/**
* \brief Parse commandline parameters in 'cmdline'.
*
* Parses 'cmdline' for kernel commandline parameters and sets configuration
* variables accordingly.
*
* \param cmdline Kernel commandline string.
*/
void parse_commandline(const char *cmdline, struct cmdarg *cmdargs)
{
// Parse argument string into whitespace-separated 'var=val' tokens
for(const char *p = strchr(cmdline, '='); p != NULL;
p = strchr(p + 1, '=')) {
const char *var = look_back(p, ' ') + 1, *val = p + 1;
if(handle_argument(var, val, cmdargs) != 0) {
assert(!"parse_commandline: Parse error in commandline");
}
}
}