| // Copyright 2016 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <cmdline.h> |
| |
| #include <ctype.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "osboot.h" |
| |
| #include <stdio.h> |
| |
| #define CMDLINE_MAX_ITEMS 128 |
| #define CMDLINE_MAX_STRINGDATA (PAGE_SIZE * 3) |
| |
| static char buffer[CMDLINE_MAX_STRINGDATA]; |
| static size_t buffer_next = 0; |
| |
| typedef struct { |
| char* key; |
| char* val; |
| size_t klen; |
| size_t vlen; |
| } kv_t; |
| |
| static kv_t entry[CMDLINE_MAX_ITEMS]; |
| static size_t entry_count; |
| |
| size_t cmdline_to_string(char* ptr, size_t max) { |
| char* start = ptr; |
| |
| if (max == 0) { |
| return 0; |
| } |
| |
| for (size_t n = 0; n < entry_count; n++) { |
| if ((entry[n].klen + entry[n].vlen + 3) > max) { |
| // require space for: space + key + equal + value + null |
| break; |
| } |
| if (n > 0) { |
| *ptr++ = ' '; |
| max--; |
| } |
| memcpy(ptr, entry[n].key, entry[n].klen); |
| ptr += entry[n].klen; |
| max -= entry[n].klen; |
| if (entry[n].vlen) { |
| *ptr++ = '='; |
| max--; |
| memcpy(ptr, entry[n].val, entry[n].vlen); |
| ptr += entry[n].vlen; |
| max -= entry[n].vlen; |
| } |
| } |
| *ptr++ = 0; |
| return ptr - start; |
| } |
| |
| static void entry_add(const char* key, size_t klen, const char* val, size_t vlen) { |
| if (klen == 0) { |
| // empty keys are not allowed |
| return; |
| } |
| |
| if ((klen > 1024) || (vlen > 1024)) { |
| // huge keys and values are not allowed |
| return; |
| } |
| |
| if ((sizeof(buffer) - buffer_next) < (klen + vlen + 2)) { |
| // give up if it won't fit |
| return; |
| } |
| |
| size_t n; |
| for (n = 0; n < entry_count; n++) { |
| if ((entry[n].klen == klen) && !memcmp(key, entry[n].key, klen)) { |
| goto write_value; |
| } |
| } |
| if (n == CMDLINE_MAX_ITEMS) { |
| // no space in table |
| return; |
| } |
| |
| // new entry |
| entry_count++; |
| entry[n].key = buffer + buffer_next; |
| entry[n].klen = klen; |
| memcpy(entry[n].key, key, klen); |
| entry[n].key[klen] = 0; |
| buffer_next += klen + 1; |
| |
| write_value: |
| entry[n].val = buffer + buffer_next; |
| entry[n].vlen = vlen; |
| memcpy(entry[n].val, val, vlen); |
| entry[n].val[vlen] = 0; |
| buffer_next += vlen + 1; |
| } |
| |
| void cmdline_set(const char* key, const char* val) { |
| entry_add(key, strlen(key), val, strlen(val)); |
| } |
| |
| void cmdline_append(const char* ptr, size_t len) { |
| const char* key; |
| const char* val; |
| |
| restart: |
| while (len > 0) { |
| if (isspace(*ptr)) { |
| ptr++; |
| len--; |
| continue; |
| } |
| key = ptr; |
| while (len > 0) { |
| if (*ptr == '=') { |
| size_t klen = ptr - key; |
| ptr++; |
| len--; |
| val = ptr; |
| while ((len > 0) && !isspace(*ptr)) { |
| len--; |
| ptr++; |
| } |
| size_t vlen = ptr - val; |
| entry_add(key, klen, val, vlen); |
| goto restart; |
| } |
| if (isspace(*ptr)) { |
| break; |
| } |
| ptr++; |
| len--; |
| } |
| size_t klen = ptr - key; |
| entry_add(key, klen, NULL, 0); |
| } |
| } |
| |
| const char* cmdline_get(const char* key, const char* _default) { |
| size_t klen = strlen(key); |
| for (size_t n = 0; n < entry_count; n++) { |
| if ((entry[n].klen == klen) && !memcmp(key, entry[n].key, klen)) { |
| return entry[n].val; |
| } |
| } |
| return _default; |
| } |
| |
| uint32_t cmdline_get_uint32(const char* key, uint32_t _default) { |
| const char* val = cmdline_get(key, NULL); |
| if (val == NULL) { |
| return _default; |
| } |
| return atol(val); |
| } |