| // 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 | 
 | } |