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