5-malloc.md (#25)
[lunaix-os.git] / lunaix-os / kernel / kcmd.c
1 #include <lunaix/kcmd.h>
2 #include <lunaix/syslog.h>
3 #include <lunaix/mm/valloc.h>
4 #include <lunaix/spike.h>
5
6 #include <klibc/string.h>
7
8 LOG_MODULE("kcmd");
9
10 struct substr {
11     int pos;
12     size_t len;
13 };
14
15 struct extractor {
16     char* cmdline;
17     int pos;
18
19     struct substr key;
20     struct substr val;
21 };
22
23 static DECLARE_HASHTABLE(options, 8);
24
25 static bool
26 extract_next_option(struct extractor* ctx) 
27 {
28 #define is_valid_char(c) ((unsigned int)(((c) & ~0x80) - 'A') < 'Z')
29 #define PARSE_KEY 0
30 #define PARSE_VAL 1
31     char c;
32     int i = ctx->pos, state = PARSE_KEY;
33     struct substr* s = &ctx->key;
34     s->len = 0;
35     s->pos = i;
36
37     if (!ctx->cmdline[i]) {
38         return false;
39     }
40
41     while((c = ctx->cmdline[i++])) {
42         if (c == ' ') {
43             while ((c = ctx->cmdline[i++]) && c == ' ');
44             break;
45         }
46
47         if (c == '=') {
48             if (state == PARSE_KEY) {
49                 if (s->len == 0) {
50                     WARN("unexpected character: '=' (pos:%d). skipping...\n", i + 1);
51                     while ((c = ctx->cmdline[i++]) && c != ' ');
52                     break;
53                 }
54                 state = PARSE_VAL;
55                 s = &ctx->val;
56                 s->len = 0;
57                 s->pos = i;
58                 continue;
59             }
60         }
61
62         s->len++;
63     }
64
65     ctx->pos = i - 1;
66
67     return true;
68 }
69
70 #define MAX_KEYSIZE 16
71
72 void 
73 kcmd_parse_cmdline(char* cmd_line) 
74 {
75     struct extractor ctx = { .cmdline = cmd_line, .pos = 0 };
76     
77     while(extract_next_option(&ctx)) {
78         if (!ctx.key.len) {
79             continue;
80         }
81         
82         size_t maxlen = sizeof(struct koption) - offsetof(struct koption, buf);
83
84         if (ctx.key.len >= maxlen) {
85             WARN("option key too big. skipping...\n");
86             continue;
87         }
88
89         if (ctx.val.len >= 256) {
90             WARN("option value too big. skipping...\n");
91             continue;
92         }
93
94         struct koption* kopt = 
95             (struct koption*) vzalloc(sizeof(*kopt));
96         
97         memcpy(kopt->buf, &cmd_line[ctx.key.pos], ctx.key.len);
98         
99         if (ctx.val.len) {
100             kopt->value = &kopt->buf[ctx.key.len + 1];
101             size_t max_val_len = maxlen - ctx.key.len;
102
103             // value too big to fit inplace
104             if (max_val_len <= ctx.val.len) {
105                 kopt->value = vzalloc(ctx.val.len + 1);
106             }
107
108             memcpy(kopt->value, &cmd_line[ctx.val.pos], ctx.val.len);
109         }
110         
111         kopt->hashkey = HSTR(kopt->buf, ctx.key.len);
112         hstr_rehash(&kopt->hashkey, HSTR_FULL_HASH);
113
114         hashtable_hash_in(options, &kopt->node, kopt->hashkey.hash);
115     }
116 }
117
118 bool 
119 kcmd_get_option(char* key, char** out_value) 
120 {
121     struct hstr hkey = HSTR(key, strlen(key));
122     hstr_rehash(&hkey, HSTR_FULL_HASH);
123
124     struct koption *pos, *n;
125     hashtable_hash_foreach(options, hkey.hash, pos, n, node) {
126         if (HSTR_EQ(&pos->hashkey, &hkey)) {
127             goto found;
128         }
129     }
130
131     return false;
132
133 found:
134     if (out_value) {
135         *out_value = pos->value;
136     }
137
138     return true;
139 }