xref: /nrf52832-nimble/packages/NimBLE-latest/apps/btshell/src/parse.c (revision 042d53a763ad75cb1465103098bb88c245d95138)
1*042d53a7SEvalZero /*
2*042d53a7SEvalZero  * Licensed to the Apache Software Foundation (ASF) under one
3*042d53a7SEvalZero  * or more contributor license agreements.  See the NOTICE file
4*042d53a7SEvalZero  * distributed with this work for additional information
5*042d53a7SEvalZero  * regarding copyright ownership.  The ASF licenses this file
6*042d53a7SEvalZero  * to you under the Apache License, Version 2.0 (the
7*042d53a7SEvalZero  * "License"); you may not use this file except in compliance
8*042d53a7SEvalZero  * with the License.  You may obtain a copy of the License at
9*042d53a7SEvalZero  *
10*042d53a7SEvalZero  *  http://www.apache.org/licenses/LICENSE-2.0
11*042d53a7SEvalZero  *
12*042d53a7SEvalZero  * Unless required by applicable law or agreed to in writing,
13*042d53a7SEvalZero  * software distributed under the License is distributed on an
14*042d53a7SEvalZero  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15*042d53a7SEvalZero  * KIND, either express or implied.  See the License for the
16*042d53a7SEvalZero  * specific language governing permissions and limitations
17*042d53a7SEvalZero  * under the License.
18*042d53a7SEvalZero  */
19*042d53a7SEvalZero 
20*042d53a7SEvalZero #include <string.h>
21*042d53a7SEvalZero #include <stdlib.h>
22*042d53a7SEvalZero #include <limits.h>
23*042d53a7SEvalZero #include <stdarg.h>
24*042d53a7SEvalZero #include <errno.h>
25*042d53a7SEvalZero #include <assert.h>
26*042d53a7SEvalZero #include "host/ble_hs.h"
27*042d53a7SEvalZero #include "host/ble_uuid.h"
28*042d53a7SEvalZero #include "host/ble_eddystone.h"
29*042d53a7SEvalZero #include "cmd.h"
30*042d53a7SEvalZero #include "btshell.h"
31*042d53a7SEvalZero 
32*042d53a7SEvalZero #include "nimble/npl_shell.h"
33*042d53a7SEvalZero 
34*042d53a7SEvalZero #define CMD_MAX_ARGS        16
35*042d53a7SEvalZero 
36*042d53a7SEvalZero static char *cmd_args[CMD_MAX_ARGS][2];
37*042d53a7SEvalZero static int cmd_num_args;
38*042d53a7SEvalZero 
39*042d53a7SEvalZero int
parse_arg_find_idx(const char * key)40*042d53a7SEvalZero parse_arg_find_idx(const char *key)
41*042d53a7SEvalZero {
42*042d53a7SEvalZero     int i;
43*042d53a7SEvalZero 
44*042d53a7SEvalZero     for (i = 0; i < cmd_num_args; i++) {
45*042d53a7SEvalZero         if (strcmp(cmd_args[i][0], key) == 0) {
46*042d53a7SEvalZero             return i;
47*042d53a7SEvalZero         }
48*042d53a7SEvalZero     }
49*042d53a7SEvalZero 
50*042d53a7SEvalZero     return -1;
51*042d53a7SEvalZero }
52*042d53a7SEvalZero 
53*042d53a7SEvalZero char *
parse_arg_peek(const char * key)54*042d53a7SEvalZero parse_arg_peek(const char *key)
55*042d53a7SEvalZero {
56*042d53a7SEvalZero     int i;
57*042d53a7SEvalZero 
58*042d53a7SEvalZero     for (i = 0; i < cmd_num_args; i++) {
59*042d53a7SEvalZero         if (strcmp(cmd_args[i][0], key) == 0) {
60*042d53a7SEvalZero             return cmd_args[i][1];
61*042d53a7SEvalZero         }
62*042d53a7SEvalZero     }
63*042d53a7SEvalZero 
64*042d53a7SEvalZero     return NULL;
65*042d53a7SEvalZero }
66*042d53a7SEvalZero 
67*042d53a7SEvalZero char *
parse_arg_extract(const char * key)68*042d53a7SEvalZero parse_arg_extract(const char *key)
69*042d53a7SEvalZero {
70*042d53a7SEvalZero     int i;
71*042d53a7SEvalZero 
72*042d53a7SEvalZero     for (i = 0; i < cmd_num_args; i++) {
73*042d53a7SEvalZero         if (strcmp(cmd_args[i][0], key) == 0) {
74*042d53a7SEvalZero             /* Erase parameter. */
75*042d53a7SEvalZero             cmd_args[i][0][0] = '\0';
76*042d53a7SEvalZero 
77*042d53a7SEvalZero             return cmd_args[i][1];
78*042d53a7SEvalZero         }
79*042d53a7SEvalZero     }
80*042d53a7SEvalZero 
81*042d53a7SEvalZero     return NULL;
82*042d53a7SEvalZero }
83*042d53a7SEvalZero 
84*042d53a7SEvalZero /**
85*042d53a7SEvalZero  * Determines which number base to use when parsing the specified numeric
86*042d53a7SEvalZero  * string.  This just avoids base '0' so that numbers don't get interpreted as
87*042d53a7SEvalZero  * octal.
88*042d53a7SEvalZero  */
89*042d53a7SEvalZero static int
parse_arg_long_base(char * sval)90*042d53a7SEvalZero parse_arg_long_base(char *sval)
91*042d53a7SEvalZero {
92*042d53a7SEvalZero     if (sval[0] == '0' && sval[1] == 'x') {
93*042d53a7SEvalZero         return 0;
94*042d53a7SEvalZero     } else {
95*042d53a7SEvalZero         return 10;
96*042d53a7SEvalZero     }
97*042d53a7SEvalZero }
98*042d53a7SEvalZero 
99*042d53a7SEvalZero long
parse_long_bounds(char * sval,long min,long max,int * out_status)100*042d53a7SEvalZero parse_long_bounds(char *sval, long min, long max, int *out_status)
101*042d53a7SEvalZero {
102*042d53a7SEvalZero     char *endptr;
103*042d53a7SEvalZero     long lval;
104*042d53a7SEvalZero 
105*042d53a7SEvalZero     lval = strtol(sval, &endptr, parse_arg_long_base(sval));
106*042d53a7SEvalZero     if (sval[0] != '\0' && *endptr == '\0' &&
107*042d53a7SEvalZero         lval >= min && lval <= max) {
108*042d53a7SEvalZero 
109*042d53a7SEvalZero         *out_status = 0;
110*042d53a7SEvalZero         return lval;
111*042d53a7SEvalZero     }
112*042d53a7SEvalZero 
113*042d53a7SEvalZero     *out_status = EINVAL;
114*042d53a7SEvalZero     return 0;
115*042d53a7SEvalZero }
116*042d53a7SEvalZero 
117*042d53a7SEvalZero long
parse_arg_long_bounds_peek(char * name,long min,long max,int * out_status)118*042d53a7SEvalZero parse_arg_long_bounds_peek(char *name, long min, long max, int *out_status)
119*042d53a7SEvalZero {
120*042d53a7SEvalZero     char *sval;
121*042d53a7SEvalZero 
122*042d53a7SEvalZero     sval = parse_arg_peek(name);
123*042d53a7SEvalZero     if (sval == NULL) {
124*042d53a7SEvalZero         *out_status = ENOENT;
125*042d53a7SEvalZero         return 0;
126*042d53a7SEvalZero     }
127*042d53a7SEvalZero     return parse_long_bounds(sval, min, max, out_status);
128*042d53a7SEvalZero }
129*042d53a7SEvalZero 
130*042d53a7SEvalZero long
parse_arg_long_bounds(char * name,long min,long max,int * out_status)131*042d53a7SEvalZero parse_arg_long_bounds(char *name, long min, long max, int *out_status)
132*042d53a7SEvalZero {
133*042d53a7SEvalZero     char *sval;
134*042d53a7SEvalZero 
135*042d53a7SEvalZero     sval = parse_arg_extract(name);
136*042d53a7SEvalZero     if (sval == NULL) {
137*042d53a7SEvalZero         *out_status = ENOENT;
138*042d53a7SEvalZero         return 0;
139*042d53a7SEvalZero     }
140*042d53a7SEvalZero     return parse_long_bounds(sval, min, max, out_status);
141*042d53a7SEvalZero }
142*042d53a7SEvalZero 
143*042d53a7SEvalZero long
parse_arg_long_bounds_dflt(char * name,long min,long max,long dflt,int * out_status)144*042d53a7SEvalZero parse_arg_long_bounds_dflt(char *name, long min, long max,
145*042d53a7SEvalZero                               long dflt, int *out_status)
146*042d53a7SEvalZero {
147*042d53a7SEvalZero     long val;
148*042d53a7SEvalZero     int rc;
149*042d53a7SEvalZero 
150*042d53a7SEvalZero     val = parse_arg_long_bounds(name, min, max, &rc);
151*042d53a7SEvalZero     if (rc == ENOENT) {
152*042d53a7SEvalZero         rc = 0;
153*042d53a7SEvalZero         val = dflt;
154*042d53a7SEvalZero     }
155*042d53a7SEvalZero 
156*042d53a7SEvalZero     *out_status = rc;
157*042d53a7SEvalZero 
158*042d53a7SEvalZero     return val;
159*042d53a7SEvalZero }
160*042d53a7SEvalZero 
161*042d53a7SEvalZero uint64_t
parse_arg_uint64_bounds(char * name,uint64_t min,uint64_t max,int * out_status)162*042d53a7SEvalZero parse_arg_uint64_bounds(char *name, uint64_t min, uint64_t max, int *out_status)
163*042d53a7SEvalZero {
164*042d53a7SEvalZero     char *endptr;
165*042d53a7SEvalZero     char *sval;
166*042d53a7SEvalZero     uint64_t lval;
167*042d53a7SEvalZero 
168*042d53a7SEvalZero     sval = parse_arg_extract(name);
169*042d53a7SEvalZero     if (sval == NULL) {
170*042d53a7SEvalZero         *out_status = ENOENT;
171*042d53a7SEvalZero         return 0;
172*042d53a7SEvalZero     }
173*042d53a7SEvalZero 
174*042d53a7SEvalZero     lval = strtoull(sval, &endptr, parse_arg_long_base(sval));
175*042d53a7SEvalZero     if (sval[0] != '\0' && *endptr == '\0' &&
176*042d53a7SEvalZero         lval >= min && lval <= max) {
177*042d53a7SEvalZero 
178*042d53a7SEvalZero         *out_status = 0;
179*042d53a7SEvalZero         return lval;
180*042d53a7SEvalZero     }
181*042d53a7SEvalZero 
182*042d53a7SEvalZero     *out_status = EINVAL;
183*042d53a7SEvalZero     return 0;
184*042d53a7SEvalZero }
185*042d53a7SEvalZero 
186*042d53a7SEvalZero long
parse_arg_long(char * name,int * out_status)187*042d53a7SEvalZero parse_arg_long(char *name, int *out_status)
188*042d53a7SEvalZero {
189*042d53a7SEvalZero     return parse_arg_long_bounds(name, LONG_MIN, LONG_MAX, out_status);
190*042d53a7SEvalZero }
191*042d53a7SEvalZero 
192*042d53a7SEvalZero uint8_t
parse_arg_bool(char * name,int * out_status)193*042d53a7SEvalZero parse_arg_bool(char *name, int *out_status)
194*042d53a7SEvalZero {
195*042d53a7SEvalZero     return parse_arg_long_bounds(name, 0, 1, out_status);
196*042d53a7SEvalZero }
197*042d53a7SEvalZero 
198*042d53a7SEvalZero uint8_t
parse_arg_bool_dflt(char * name,uint8_t dflt,int * out_status)199*042d53a7SEvalZero parse_arg_bool_dflt(char *name, uint8_t dflt, int *out_status)
200*042d53a7SEvalZero {
201*042d53a7SEvalZero     return parse_arg_long_bounds_dflt(name, 0, 1, dflt, out_status);
202*042d53a7SEvalZero }
203*042d53a7SEvalZero 
204*042d53a7SEvalZero uint8_t
parse_arg_uint8(char * name,int * out_status)205*042d53a7SEvalZero parse_arg_uint8(char *name, int *out_status)
206*042d53a7SEvalZero {
207*042d53a7SEvalZero     return parse_arg_long_bounds(name, 0, UINT8_MAX, out_status);
208*042d53a7SEvalZero }
209*042d53a7SEvalZero 
210*042d53a7SEvalZero uint16_t
parse_arg_uint16(char * name,int * out_status)211*042d53a7SEvalZero parse_arg_uint16(char *name, int *out_status)
212*042d53a7SEvalZero {
213*042d53a7SEvalZero     return parse_arg_long_bounds(name, 0, UINT16_MAX, out_status);
214*042d53a7SEvalZero }
215*042d53a7SEvalZero 
216*042d53a7SEvalZero uint16_t
parse_arg_uint16_peek(char * name,int * out_status)217*042d53a7SEvalZero parse_arg_uint16_peek(char *name, int *out_status)
218*042d53a7SEvalZero {
219*042d53a7SEvalZero     return parse_arg_long_bounds_peek(name, 0, UINT16_MAX, out_status);
220*042d53a7SEvalZero }
221*042d53a7SEvalZero 
222*042d53a7SEvalZero uint32_t
parse_arg_uint32(char * name,int * out_status)223*042d53a7SEvalZero parse_arg_uint32(char *name, int *out_status)
224*042d53a7SEvalZero {
225*042d53a7SEvalZero     return parse_arg_uint64_bounds(name, 0, UINT32_MAX, out_status);
226*042d53a7SEvalZero }
227*042d53a7SEvalZero 
228*042d53a7SEvalZero uint64_t
parse_arg_uint64(char * name,int * out_status)229*042d53a7SEvalZero parse_arg_uint64(char *name, int *out_status)
230*042d53a7SEvalZero {
231*042d53a7SEvalZero     return parse_arg_uint64_bounds(name, 0, UINT64_MAX, out_status);
232*042d53a7SEvalZero }
233*042d53a7SEvalZero 
234*042d53a7SEvalZero uint8_t
parse_arg_uint8_dflt(char * name,uint8_t dflt,int * out_status)235*042d53a7SEvalZero parse_arg_uint8_dflt(char *name, uint8_t dflt, int *out_status)
236*042d53a7SEvalZero {
237*042d53a7SEvalZero     uint8_t val;
238*042d53a7SEvalZero     int rc;
239*042d53a7SEvalZero 
240*042d53a7SEvalZero     val = parse_arg_uint8(name, &rc);
241*042d53a7SEvalZero     if (rc == ENOENT) {
242*042d53a7SEvalZero         val = dflt;
243*042d53a7SEvalZero         rc = 0;
244*042d53a7SEvalZero     }
245*042d53a7SEvalZero 
246*042d53a7SEvalZero     *out_status = rc;
247*042d53a7SEvalZero     return val;
248*042d53a7SEvalZero }
249*042d53a7SEvalZero 
250*042d53a7SEvalZero uint16_t
parse_arg_uint16_dflt(char * name,uint16_t dflt,int * out_status)251*042d53a7SEvalZero parse_arg_uint16_dflt(char *name, uint16_t dflt, int *out_status)
252*042d53a7SEvalZero {
253*042d53a7SEvalZero     uint16_t val;
254*042d53a7SEvalZero     int rc;
255*042d53a7SEvalZero 
256*042d53a7SEvalZero     val = parse_arg_uint16(name, &rc);
257*042d53a7SEvalZero     if (rc == ENOENT) {
258*042d53a7SEvalZero         val = dflt;
259*042d53a7SEvalZero         rc = 0;
260*042d53a7SEvalZero     }
261*042d53a7SEvalZero 
262*042d53a7SEvalZero     *out_status = rc;
263*042d53a7SEvalZero     return val;
264*042d53a7SEvalZero }
265*042d53a7SEvalZero 
266*042d53a7SEvalZero uint32_t
parse_arg_uint32_dflt(char * name,uint32_t dflt,int * out_status)267*042d53a7SEvalZero parse_arg_uint32_dflt(char *name, uint32_t dflt, int *out_status)
268*042d53a7SEvalZero {
269*042d53a7SEvalZero     uint32_t val;
270*042d53a7SEvalZero     int rc;
271*042d53a7SEvalZero 
272*042d53a7SEvalZero     val = parse_arg_uint32(name, &rc);
273*042d53a7SEvalZero     if (rc == ENOENT) {
274*042d53a7SEvalZero         val = dflt;
275*042d53a7SEvalZero         rc = 0;
276*042d53a7SEvalZero     }
277*042d53a7SEvalZero 
278*042d53a7SEvalZero     *out_status = rc;
279*042d53a7SEvalZero     return val;
280*042d53a7SEvalZero }
281*042d53a7SEvalZero 
282*042d53a7SEvalZero const struct kv_pair *
parse_kv_find(const struct kv_pair * kvs,char * name)283*042d53a7SEvalZero parse_kv_find(const struct kv_pair *kvs, char *name)
284*042d53a7SEvalZero {
285*042d53a7SEvalZero     const struct kv_pair *kv;
286*042d53a7SEvalZero     int i;
287*042d53a7SEvalZero 
288*042d53a7SEvalZero     for (i = 0; kvs[i].key != NULL; i++) {
289*042d53a7SEvalZero         kv = kvs + i;
290*042d53a7SEvalZero         if (strcmp(name, kv->key) == 0) {
291*042d53a7SEvalZero             return kv;
292*042d53a7SEvalZero         }
293*042d53a7SEvalZero     }
294*042d53a7SEvalZero 
295*042d53a7SEvalZero     return NULL;
296*042d53a7SEvalZero }
297*042d53a7SEvalZero 
298*042d53a7SEvalZero int
parse_arg_kv(char * name,const struct kv_pair * kvs,int * out_status)299*042d53a7SEvalZero parse_arg_kv(char *name, const struct kv_pair *kvs, int *out_status)
300*042d53a7SEvalZero {
301*042d53a7SEvalZero     const struct kv_pair *kv;
302*042d53a7SEvalZero     char *sval;
303*042d53a7SEvalZero 
304*042d53a7SEvalZero     sval = parse_arg_extract(name);
305*042d53a7SEvalZero     if (sval == NULL) {
306*042d53a7SEvalZero         *out_status = ENOENT;
307*042d53a7SEvalZero         return -1;
308*042d53a7SEvalZero     }
309*042d53a7SEvalZero 
310*042d53a7SEvalZero     kv = parse_kv_find(kvs, sval);
311*042d53a7SEvalZero     if (kv == NULL) {
312*042d53a7SEvalZero         *out_status = EINVAL;
313*042d53a7SEvalZero         return -1;
314*042d53a7SEvalZero     }
315*042d53a7SEvalZero 
316*042d53a7SEvalZero     *out_status = 0;
317*042d53a7SEvalZero     return kv->val;
318*042d53a7SEvalZero }
319*042d53a7SEvalZero 
320*042d53a7SEvalZero int
parse_arg_kv_dflt(char * name,const struct kv_pair * kvs,int def_val,int * out_status)321*042d53a7SEvalZero parse_arg_kv_dflt(char *name, const struct kv_pair *kvs, int def_val,
322*042d53a7SEvalZero                      int *out_status)
323*042d53a7SEvalZero {
324*042d53a7SEvalZero     int val;
325*042d53a7SEvalZero     int rc;
326*042d53a7SEvalZero 
327*042d53a7SEvalZero     val = parse_arg_kv(name, kvs, &rc);
328*042d53a7SEvalZero     if (rc == ENOENT) {
329*042d53a7SEvalZero         rc = 0;
330*042d53a7SEvalZero         val = def_val;
331*042d53a7SEvalZero     }
332*042d53a7SEvalZero 
333*042d53a7SEvalZero     *out_status = rc;
334*042d53a7SEvalZero 
335*042d53a7SEvalZero     return val;
336*042d53a7SEvalZero }
337*042d53a7SEvalZero 
338*042d53a7SEvalZero 
339*042d53a7SEvalZero static int
parse_arg_byte_stream_delim(char * sval,char * delims,int max_len,uint8_t * dst,int * out_len)340*042d53a7SEvalZero parse_arg_byte_stream_delim(char *sval, char *delims, int max_len,
341*042d53a7SEvalZero                             uint8_t *dst, int *out_len)
342*042d53a7SEvalZero {
343*042d53a7SEvalZero     unsigned long ul;
344*042d53a7SEvalZero     char *endptr;
345*042d53a7SEvalZero     char *token;
346*042d53a7SEvalZero     int i;
347*042d53a7SEvalZero 
348*042d53a7SEvalZero     i = 0;
349*042d53a7SEvalZero     for (token = strtok(sval, delims);
350*042d53a7SEvalZero          token != NULL;
351*042d53a7SEvalZero          token = strtok(NULL, delims)) {
352*042d53a7SEvalZero 
353*042d53a7SEvalZero         if (i >= max_len) {
354*042d53a7SEvalZero             return EINVAL;
355*042d53a7SEvalZero         }
356*042d53a7SEvalZero 
357*042d53a7SEvalZero         ul = strtoul(token, &endptr, 16);
358*042d53a7SEvalZero         if (sval[0] == '\0' || *endptr != '\0' || ul > UINT8_MAX) {
359*042d53a7SEvalZero             return -1;
360*042d53a7SEvalZero         }
361*042d53a7SEvalZero 
362*042d53a7SEvalZero         dst[i] = ul;
363*042d53a7SEvalZero         i++;
364*042d53a7SEvalZero     }
365*042d53a7SEvalZero 
366*042d53a7SEvalZero     *out_len = i;
367*042d53a7SEvalZero 
368*042d53a7SEvalZero     return 0;
369*042d53a7SEvalZero }
370*042d53a7SEvalZero 
371*042d53a7SEvalZero int
parse_arg_byte_stream(char * name,int max_len,uint8_t * dst,int * out_len)372*042d53a7SEvalZero parse_arg_byte_stream(char *name, int max_len, uint8_t *dst, int *out_len)
373*042d53a7SEvalZero {
374*042d53a7SEvalZero     char *sval;
375*042d53a7SEvalZero 
376*042d53a7SEvalZero     sval = parse_arg_extract(name);
377*042d53a7SEvalZero     if (sval == NULL) {
378*042d53a7SEvalZero         return ENOENT;
379*042d53a7SEvalZero     }
380*042d53a7SEvalZero 
381*042d53a7SEvalZero     return parse_arg_byte_stream_delim(sval, ":-", max_len, dst, out_len);
382*042d53a7SEvalZero }
383*042d53a7SEvalZero 
384*042d53a7SEvalZero int
parse_arg_byte_stream_exact_length(char * name,uint8_t * dst,int len)385*042d53a7SEvalZero parse_arg_byte_stream_exact_length(char *name, uint8_t *dst, int len)
386*042d53a7SEvalZero {
387*042d53a7SEvalZero     int actual_len;
388*042d53a7SEvalZero     int rc;
389*042d53a7SEvalZero 
390*042d53a7SEvalZero     rc = parse_arg_byte_stream(name, len, dst, &actual_len);
391*042d53a7SEvalZero     if (rc != 0) {
392*042d53a7SEvalZero         return rc;
393*042d53a7SEvalZero     }
394*042d53a7SEvalZero 
395*042d53a7SEvalZero     if (actual_len != len) {
396*042d53a7SEvalZero         return EINVAL;
397*042d53a7SEvalZero     }
398*042d53a7SEvalZero 
399*042d53a7SEvalZero     return 0;
400*042d53a7SEvalZero }
401*042d53a7SEvalZero 
402*042d53a7SEvalZero static void
parse_reverse_bytes(uint8_t * bytes,int len)403*042d53a7SEvalZero parse_reverse_bytes(uint8_t *bytes, int len)
404*042d53a7SEvalZero {
405*042d53a7SEvalZero     uint8_t tmp;
406*042d53a7SEvalZero     int i;
407*042d53a7SEvalZero 
408*042d53a7SEvalZero     for (i = 0; i < len / 2; i++) {
409*042d53a7SEvalZero         tmp = bytes[i];
410*042d53a7SEvalZero         bytes[i] = bytes[len - i - 1];
411*042d53a7SEvalZero         bytes[len - i - 1] = tmp;
412*042d53a7SEvalZero     }
413*042d53a7SEvalZero }
414*042d53a7SEvalZero 
415*042d53a7SEvalZero int
parse_arg_mac(char * name,uint8_t * dst)416*042d53a7SEvalZero parse_arg_mac(char *name, uint8_t *dst)
417*042d53a7SEvalZero {
418*042d53a7SEvalZero     int rc;
419*042d53a7SEvalZero 
420*042d53a7SEvalZero     rc = parse_arg_byte_stream_exact_length(name, dst, 6);
421*042d53a7SEvalZero     if (rc != 0) {
422*042d53a7SEvalZero         return rc;
423*042d53a7SEvalZero     }
424*042d53a7SEvalZero 
425*042d53a7SEvalZero     parse_reverse_bytes(dst, 6);
426*042d53a7SEvalZero 
427*042d53a7SEvalZero     return 0;
428*042d53a7SEvalZero }
429*042d53a7SEvalZero 
430*042d53a7SEvalZero int
parse_arg_uuid(char * str,ble_uuid_any_t * uuid)431*042d53a7SEvalZero parse_arg_uuid(char *str, ble_uuid_any_t *uuid)
432*042d53a7SEvalZero {
433*042d53a7SEvalZero     uint16_t uuid16;
434*042d53a7SEvalZero     uint8_t val[16];
435*042d53a7SEvalZero     int len;
436*042d53a7SEvalZero     int rc;
437*042d53a7SEvalZero 
438*042d53a7SEvalZero     uuid16 = parse_arg_uint16_peek(str, &rc);
439*042d53a7SEvalZero     switch (rc) {
440*042d53a7SEvalZero     case ENOENT:
441*042d53a7SEvalZero         parse_arg_extract(str);
442*042d53a7SEvalZero         return ENOENT;
443*042d53a7SEvalZero 
444*042d53a7SEvalZero     case 0:
445*042d53a7SEvalZero         len = 2;
446*042d53a7SEvalZero         val[0] = uuid16;
447*042d53a7SEvalZero         val[1] = uuid16 >> 8;
448*042d53a7SEvalZero         parse_arg_extract(str);
449*042d53a7SEvalZero         break;
450*042d53a7SEvalZero 
451*042d53a7SEvalZero     default:
452*042d53a7SEvalZero         len = 16;
453*042d53a7SEvalZero         rc = parse_arg_byte_stream_exact_length(str, val, 16);
454*042d53a7SEvalZero         if (rc != 0) {
455*042d53a7SEvalZero             return EINVAL;
456*042d53a7SEvalZero         }
457*042d53a7SEvalZero         parse_reverse_bytes(val, 16);
458*042d53a7SEvalZero         break;
459*042d53a7SEvalZero     }
460*042d53a7SEvalZero 
461*042d53a7SEvalZero     rc = ble_uuid_init_from_buf(uuid, val, len);
462*042d53a7SEvalZero     if (rc != 0) {
463*042d53a7SEvalZero         return EINVAL;
464*042d53a7SEvalZero     } else {
465*042d53a7SEvalZero         return 0;
466*042d53a7SEvalZero     }
467*042d53a7SEvalZero }
468*042d53a7SEvalZero 
469*042d53a7SEvalZero int
parse_arg_all(int argc,char ** argv)470*042d53a7SEvalZero parse_arg_all(int argc, char **argv)
471*042d53a7SEvalZero {
472*042d53a7SEvalZero     char *key;
473*042d53a7SEvalZero     char *val;
474*042d53a7SEvalZero     int i;
475*042d53a7SEvalZero 
476*042d53a7SEvalZero     cmd_num_args = 0;
477*042d53a7SEvalZero 
478*042d53a7SEvalZero     for (i = 0; i < argc; i++) {
479*042d53a7SEvalZero         key = strtok(argv[i], "=");
480*042d53a7SEvalZero         val = strtok(NULL, "=");
481*042d53a7SEvalZero 
482*042d53a7SEvalZero         if (key != NULL && val != NULL) {
483*042d53a7SEvalZero             if (strlen(key) == 0) {
484*042d53a7SEvalZero                 console_printf("Error: invalid argument: %s\n", argv[i]);
485*042d53a7SEvalZero                 return -1;
486*042d53a7SEvalZero             }
487*042d53a7SEvalZero 
488*042d53a7SEvalZero             if (cmd_num_args >= CMD_MAX_ARGS) {
489*042d53a7SEvalZero                 console_printf("Error: too many arguments");
490*042d53a7SEvalZero                 return -1;
491*042d53a7SEvalZero             }
492*042d53a7SEvalZero 
493*042d53a7SEvalZero             cmd_args[cmd_num_args][0] = key;
494*042d53a7SEvalZero             cmd_args[cmd_num_args][1] = val;
495*042d53a7SEvalZero             cmd_num_args++;
496*042d53a7SEvalZero         }
497*042d53a7SEvalZero     }
498*042d53a7SEvalZero 
499*042d53a7SEvalZero     return 0;
500*042d53a7SEvalZero }
501*042d53a7SEvalZero 
502*042d53a7SEvalZero int
parse_eddystone_url(char * full_url,uint8_t * out_scheme,char * out_body,uint8_t * out_body_len,uint8_t * out_suffix)503*042d53a7SEvalZero parse_eddystone_url(char *full_url, uint8_t *out_scheme, char *out_body,
504*042d53a7SEvalZero                     uint8_t *out_body_len, uint8_t *out_suffix)
505*042d53a7SEvalZero {
506*042d53a7SEvalZero     static const struct {
507*042d53a7SEvalZero         char *s;
508*042d53a7SEvalZero         uint8_t scheme;
509*042d53a7SEvalZero     } schemes[] = {
510*042d53a7SEvalZero         { "http://www.", BLE_EDDYSTONE_URL_SCHEME_HTTP_WWW },
511*042d53a7SEvalZero         { "https://www.", BLE_EDDYSTONE_URL_SCHEME_HTTPS_WWW },
512*042d53a7SEvalZero         { "http://", BLE_EDDYSTONE_URL_SCHEME_HTTP },
513*042d53a7SEvalZero         { "https://", BLE_EDDYSTONE_URL_SCHEME_HTTPS },
514*042d53a7SEvalZero     };
515*042d53a7SEvalZero 
516*042d53a7SEvalZero     static const struct {
517*042d53a7SEvalZero         char *s;
518*042d53a7SEvalZero         uint8_t code;
519*042d53a7SEvalZero     } suffixes[] = {
520*042d53a7SEvalZero         { ".com/", BLE_EDDYSTONE_URL_SUFFIX_COM_SLASH },
521*042d53a7SEvalZero         { ".org/", BLE_EDDYSTONE_URL_SUFFIX_ORG_SLASH },
522*042d53a7SEvalZero         { ".edu/", BLE_EDDYSTONE_URL_SUFFIX_EDU_SLASH },
523*042d53a7SEvalZero         { ".net/", BLE_EDDYSTONE_URL_SUFFIX_NET_SLASH },
524*042d53a7SEvalZero         { ".info/", BLE_EDDYSTONE_URL_SUFFIX_INFO_SLASH },
525*042d53a7SEvalZero         { ".biz/", BLE_EDDYSTONE_URL_SUFFIX_BIZ_SLASH },
526*042d53a7SEvalZero         { ".gov/", BLE_EDDYSTONE_URL_SUFFIX_GOV_SLASH },
527*042d53a7SEvalZero         { ".com", BLE_EDDYSTONE_URL_SUFFIX_COM },
528*042d53a7SEvalZero         { ".org", BLE_EDDYSTONE_URL_SUFFIX_ORG },
529*042d53a7SEvalZero         { ".edu", BLE_EDDYSTONE_URL_SUFFIX_EDU },
530*042d53a7SEvalZero         { ".net", BLE_EDDYSTONE_URL_SUFFIX_NET },
531*042d53a7SEvalZero         { ".info", BLE_EDDYSTONE_URL_SUFFIX_INFO },
532*042d53a7SEvalZero         { ".biz", BLE_EDDYSTONE_URL_SUFFIX_BIZ },
533*042d53a7SEvalZero         { ".gov", BLE_EDDYSTONE_URL_SUFFIX_GOV },
534*042d53a7SEvalZero     };
535*042d53a7SEvalZero 
536*042d53a7SEvalZero     char *prefix;
537*042d53a7SEvalZero     char *suffix;
538*042d53a7SEvalZero     int full_url_len;
539*042d53a7SEvalZero     int prefix_len;
540*042d53a7SEvalZero     int suffix_len;
541*042d53a7SEvalZero     int suffix_idx;
542*042d53a7SEvalZero     int rc;
543*042d53a7SEvalZero     int i;
544*042d53a7SEvalZero 
545*042d53a7SEvalZero     full_url_len = strlen(full_url);
546*042d53a7SEvalZero 
547*042d53a7SEvalZero     rc = BLE_HS_EINVAL;
548*042d53a7SEvalZero     for (i = 0; i < sizeof schemes / sizeof schemes[0]; i++) {
549*042d53a7SEvalZero         prefix = schemes[i].s;
550*042d53a7SEvalZero         prefix_len = strlen(schemes[i].s);
551*042d53a7SEvalZero 
552*042d53a7SEvalZero         if (full_url_len >= prefix_len &&
553*042d53a7SEvalZero             memcmp(full_url, prefix, prefix_len) == 0) {
554*042d53a7SEvalZero 
555*042d53a7SEvalZero             *out_scheme = i;
556*042d53a7SEvalZero             rc = 0;
557*042d53a7SEvalZero             break;
558*042d53a7SEvalZero         }
559*042d53a7SEvalZero     }
560*042d53a7SEvalZero     if (rc != 0) {
561*042d53a7SEvalZero         return rc;
562*042d53a7SEvalZero     }
563*042d53a7SEvalZero 
564*042d53a7SEvalZero     rc = BLE_HS_EINVAL;
565*042d53a7SEvalZero     for (i = 0; i < sizeof suffixes / sizeof suffixes[0]; i++) {
566*042d53a7SEvalZero         suffix = suffixes[i].s;
567*042d53a7SEvalZero         suffix_len = strlen(suffixes[i].s);
568*042d53a7SEvalZero 
569*042d53a7SEvalZero         suffix_idx = full_url_len - suffix_len;
570*042d53a7SEvalZero         if (suffix_idx >= prefix_len &&
571*042d53a7SEvalZero             memcmp(full_url + suffix_idx, suffix, suffix_len) == 0) {
572*042d53a7SEvalZero 
573*042d53a7SEvalZero             *out_suffix = i;
574*042d53a7SEvalZero             rc = 0;
575*042d53a7SEvalZero             break;
576*042d53a7SEvalZero         }
577*042d53a7SEvalZero     }
578*042d53a7SEvalZero     if (rc != 0) {
579*042d53a7SEvalZero         *out_suffix = BLE_EDDYSTONE_URL_SUFFIX_NONE;
580*042d53a7SEvalZero         *out_body_len = full_url_len - prefix_len;
581*042d53a7SEvalZero     } else {
582*042d53a7SEvalZero         *out_body_len = full_url_len - prefix_len - suffix_len;
583*042d53a7SEvalZero     }
584*042d53a7SEvalZero 
585*042d53a7SEvalZero     memcpy(out_body, full_url + prefix_len, *out_body_len);
586*042d53a7SEvalZero 
587*042d53a7SEvalZero     return 0;
588*042d53a7SEvalZero }
589