blob: 9842ecdcf178f0c310394a10ce292e1a52af2183 [file] [log] [blame]
// Package ref provides the reference implementation for kernel command line
// parsing as present in the Linux kernel. This is a separate package and
// not part of the bootparam tests because Go does not let you use cgo in
// tests.
package ref
// Reference implementation from the kernel
/*
#include <stdlib.h>
#include <ctype.h>
#include <stddef.h>
#define _U 0x01
#define _L 0x02
#define _D 0x04
#define _C 0x08
#define _P 0x10
#define _S 0x20
#define _X 0x40
#define _SP 0x80
#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
#define kisspace(c) ((__ismask(c)&(_S)) != 0)
const unsigned char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C,
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,
_C,_C,_C,_C,_C,_C,_C,_C,
_C,_C,_C,_C,_C,_C,_C,_C,
_S|_SP,_P,_P,_P,_P,_P,_P,_P,
_P,_P,_P,_P,_P,_P,_P,_P,
_D,_D,_D,_D,_D,_D,_D,_D,
_D,_D,_P,_P,_P,_P,_P,_P,
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,
_U,_U,_U,_U,_U,_U,_U,_U,
_U,_U,_U,_U,_U,_U,_U,_U,
_U,_U,_U,_P,_P,_P,_P,_P,
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,
_L,_L,_L,_L,_L,_L,_L,_L,
_L,_L,_L,_L,_L,_L,_L,_L,
_L,_L,_L,_P,_P,_P,_P,_C,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};
char *skip_spaces(const char *str)
{
while (kisspace(*str))
++str;
return (char *)str;
}
// * Parse a string to get a param value pair.
// * You can use " around spaces, but can't escape ".
// * Hyphens and underscores equivalent in parameter names.
char *next_arg(char *args, char **param, char **val)
{
unsigned int i, equals = 0;
int in_quote = 0, quoted = 0;
if (*args == '"') {
args++;
in_quote = 1;
quoted = 1;
}
for (i = 0; args[i]; i++) {
if (kisspace(args[i]) && !in_quote)
break;
if (equals == 0) {
if (args[i] == '=')
equals = i;
}
if (args[i] == '"')
in_quote = !in_quote;
}
*param = args;
if (!equals)
*val = NULL;
else {
args[equals] = '\0';
*val = args + equals + 1;
// Don't include quotes in value.
if (**val == '"') {
(*val)++;
if (args[i-1] == '"')
args[i-1] = '\0';
}
}
if (quoted && i > 0 && args[i-1] == '"')
args[i-1] = '\0';
if (args[i]) {
args[i] = '\0';
args += i + 1;
} else
args += i;
// Chew up trailing spaces.
return skip_spaces(args);
}
*/
import "C"
import (
"unsafe"
"source.monogon.dev/metropolis/pkg/bootparam"
)
func Parse(str string) (params bootparam.Params, rest string) {
cs := C.CString(bootparam.TrimLeftSpace(str))
csAllocPtr := cs
var param, val *C.char
for *cs != 0 {
var p bootparam.Param
cs = C.next_arg(cs, &param, &val)
p.Param = C.GoString(param)
if val != nil {
p.Value = C.GoString(val)
}
if p.Param == "--" {
rest = C.GoString(cs)
return
}
params = append(params, p)
}
C.free(unsafe.Pointer(csAllocPtr))
return
}