blob: 9842ecdcf178f0c310394a10ce292e1a52af2183 [file] [log] [blame]
Lorenz Brun1cf17952023-02-13 17:41:59 +01001// Package ref provides the reference implementation for kernel command line
2// parsing as present in the Linux kernel. This is a separate package and
3// not part of the bootparam tests because Go does not let you use cgo in
4// tests.
5package ref
6
7// Reference implementation from the kernel
8
9/*
10#include <stdlib.h>
11#include <ctype.h>
12#include <stddef.h>
13
14#define _U 0x01
15#define _L 0x02
16#define _D 0x04
17#define _C 0x08
18#define _P 0x10
19#define _S 0x20
20#define _X 0x40
21#define _SP 0x80
22
23#define __ismask(x) (_ctype[(int)(unsigned char)(x)])
24#define kisspace(c) ((__ismask(c)&(_S)) != 0)
25
26const unsigned char _ctype[] = {
27_C,_C,_C,_C,_C,_C,_C,_C,
28_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,
29_C,_C,_C,_C,_C,_C,_C,_C,
30_C,_C,_C,_C,_C,_C,_C,_C,
31_S|_SP,_P,_P,_P,_P,_P,_P,_P,
32_P,_P,_P,_P,_P,_P,_P,_P,
33_D,_D,_D,_D,_D,_D,_D,_D,
34_D,_D,_P,_P,_P,_P,_P,_P,
35_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,
36_U,_U,_U,_U,_U,_U,_U,_U,
37_U,_U,_U,_U,_U,_U,_U,_U,
38_U,_U,_U,_P,_P,_P,_P,_P,
39_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,
40_L,_L,_L,_L,_L,_L,_L,_L,
41_L,_L,_L,_L,_L,_L,_L,_L,
42_L,_L,_L,_P,_P,_P,_P,_C,
430,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
45_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,
46_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,
47_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,
48_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,
49_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,
50_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};
51
52
53
54char *skip_spaces(const char *str)
55{
56 while (kisspace(*str))
57 ++str;
58 return (char *)str;
59}
60
61
62// * Parse a string to get a param value pair.
63// * You can use " around spaces, but can't escape ".
64// * Hyphens and underscores equivalent in parameter names.
65 char *next_arg(char *args, char **param, char **val)
66 {
67 unsigned int i, equals = 0;
68 int in_quote = 0, quoted = 0;
69
70 if (*args == '"') {
71 args++;
72 in_quote = 1;
73 quoted = 1;
74 }
75
76 for (i = 0; args[i]; i++) {
77 if (kisspace(args[i]) && !in_quote)
78 break;
79 if (equals == 0) {
80 if (args[i] == '=')
81 equals = i;
82 }
83 if (args[i] == '"')
84 in_quote = !in_quote;
85 }
86
87 *param = args;
88 if (!equals)
89 *val = NULL;
90 else {
91 args[equals] = '\0';
92 *val = args + equals + 1;
93
94 // Don't include quotes in value.
95 if (**val == '"') {
96 (*val)++;
97 if (args[i-1] == '"')
98 args[i-1] = '\0';
99 }
100 }
101 if (quoted && i > 0 && args[i-1] == '"')
102 args[i-1] = '\0';
103
104 if (args[i]) {
105 args[i] = '\0';
106 args += i + 1;
107 } else
108 args += i;
109
110 // Chew up trailing spaces.
111 return skip_spaces(args);
112 }
113*/
114import "C"
115import (
116 "unsafe"
117
118 "source.monogon.dev/metropolis/pkg/bootparam"
119)
120
121func Parse(str string) (params bootparam.Params, rest string) {
122 cs := C.CString(bootparam.TrimLeftSpace(str))
123 csAllocPtr := cs
124 var param, val *C.char
125 for *cs != 0 {
126 var p bootparam.Param
127 cs = C.next_arg(cs, &param, &val)
128 p.Param = C.GoString(param)
129 if val != nil {
130 p.Value = C.GoString(val)
131 }
132 if p.Param == "--" {
133 rest = C.GoString(cs)
134 return
135 }
136 params = append(params, p)
137 }
138 C.free(unsafe.Pointer(csAllocPtr))
139 return
140}