1 // Copyright 2016 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <cmdline.h>
6
7 #include <ctype.h>
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "osboot.h"
12
13 #include <stdio.h>
14
15 #define CMDLINE_MAX_ITEMS 128
16 #define CMDLINE_MAX_STRINGDATA (PAGE_SIZE * 3)
17
18 static char buffer[CMDLINE_MAX_STRINGDATA];
19 static size_t buffer_next = 0;
20
21 typedef struct {
22 char* key;
23 char* val;
24 size_t klen;
25 size_t vlen;
26 } kv_t;
27
28 static kv_t entry[CMDLINE_MAX_ITEMS];
29 static size_t entry_count;
30
cmdline_to_string(char * ptr,size_t max)31 size_t cmdline_to_string(char* ptr, size_t max) {
32 char* start = ptr;
33
34 if (max == 0) {
35 return 0;
36 }
37
38 for (size_t n = 0; n < entry_count; n++) {
39 if ((entry[n].klen + entry[n].vlen + 3) > max) {
40 // require space for: space + key + equal + value + null
41 break;
42 }
43 if (n > 0) {
44 *ptr++ = ' ';
45 max--;
46 }
47 memcpy(ptr, entry[n].key, entry[n].klen);
48 ptr += entry[n].klen;
49 max -= entry[n].klen;
50 if (entry[n].vlen) {
51 *ptr++ = '=';
52 max--;
53 memcpy(ptr, entry[n].val, entry[n].vlen);
54 ptr += entry[n].vlen;
55 max -= entry[n].vlen;
56 }
57 }
58 *ptr++ = 0;
59 return ptr - start;
60 }
61
entry_add(const char * key,size_t klen,const char * val,size_t vlen)62 static void entry_add(const char* key, size_t klen, const char* val, size_t vlen) {
63 if (klen == 0) {
64 // empty keys are not allowed
65 return;
66 }
67
68 if ((klen > 1024) || (vlen > 1024)) {
69 // huge keys and values are not allowed
70 return;
71 }
72
73 if ((sizeof(buffer) - buffer_next) < (klen + vlen + 2)) {
74 // give up if it won't fit
75 return;
76 }
77
78 size_t n;
79 for (n = 0; n < entry_count; n++) {
80 if ((entry[n].klen == klen) && !memcmp(key, entry[n].key, klen)) {
81 goto write_value;
82 }
83 }
84 if (n == CMDLINE_MAX_ITEMS) {
85 // no space in table
86 return;
87 }
88
89 // new entry
90 entry_count++;
91 entry[n].key = buffer + buffer_next;
92 entry[n].klen = klen;
93 memcpy(entry[n].key, key, klen);
94 entry[n].key[klen] = 0;
95 buffer_next += klen + 1;
96
97 write_value:
98 entry[n].val = buffer + buffer_next;
99 entry[n].vlen = vlen;
100 memcpy(entry[n].val, val, vlen);
101 entry[n].val[vlen] = 0;
102 buffer_next += vlen + 1;
103 }
104
cmdline_set(const char * key,const char * val)105 void cmdline_set(const char* key, const char* val) {
106 entry_add(key, strlen(key), val, strlen(val));
107 }
108
cmdline_append(const char * ptr,size_t len)109 void cmdline_append(const char* ptr, size_t len) {
110 const char* key;
111 const char* val;
112
113 restart:
114 while (len > 0) {
115 if (isspace(*ptr)) {
116 ptr++;
117 len--;
118 continue;
119 }
120 key = ptr;
121 while (len > 0) {
122 if (*ptr == '=') {
123 size_t klen = ptr - key;
124 ptr++;
125 len--;
126 val = ptr;
127 while ((len > 0) && !isspace(*ptr)) {
128 len--;
129 ptr++;
130 }
131 size_t vlen = ptr - val;
132 entry_add(key, klen, val, vlen);
133 goto restart;
134 }
135 if (isspace(*ptr)) {
136 break;
137 }
138 ptr++;
139 len--;
140 }
141 size_t klen = ptr - key;
142 entry_add(key, klen, NULL, 0);
143 }
144 }
145
cmdline_get(const char * key,const char * _default)146 const char* cmdline_get(const char* key, const char* _default) {
147 size_t klen = strlen(key);
148 for (size_t n = 0; n < entry_count; n++) {
149 if ((entry[n].klen == klen) && !memcmp(key, entry[n].key, klen)) {
150 return entry[n].val;
151 }
152 }
153 return _default;
154 }
155
cmdline_get_uint32(const char * key,uint32_t _default)156 uint32_t cmdline_get_uint32(const char* key, uint32_t _default) {
157 const char* val = cmdline_get(key, NULL);
158 if (val == NULL) {
159 return _default;
160 }
161 return atol(val);
162 }
163