| // 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, ¶m, &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 |
| } |