MYNEWT-740 Rudimentary Text parsing package.
Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/8374b5a1 Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/8374b5a1 Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/8374b5a1 Branch: refs/heads/bluetooth5 Commit: 8374b5a179253c5ab2d091e6677a80b168a58090 Parents: 369df92 Author: Christopher Collins <ccoll...@apache.org> Authored: Mon Apr 24 19:13:53 2017 -0700 Committer: Christopher Collins <ccoll...@apache.org> Committed: Fri Apr 28 17:27:51 2017 -0700 ---------------------------------------------------------------------- util/parse/include/parse/parse.h | 47 ++++++ util/parse/pkg.yml | 32 +++++ util/parse/src/parse.c | 263 ++++++++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8374b5a1/util/parse/include/parse/parse.h ---------------------------------------------------------------------- diff --git a/util/parse/include/parse/parse.h b/util/parse/include/parse/parse.h new file mode 100644 index 0000000..39be885 --- /dev/null +++ b/util/parse/include/parse/parse.h @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#ifndef H_UTIL_PARSE_ +#define H_UTIL_PARSE_ + +long long +parse_ll_bounds(const char *sval, long long min, long long max, + int *out_status); + +unsigned long long +parse_ull_bounds(const char *sval, + unsigned long long min, unsigned long long max, + int *out_status); +long long +parse_ll(const char *sval, int *out_status); + +long long +parse_ull(const char *sval, int *out_status); + +int +parse_byte_stream_delim(const char *sval, const char *delims, int max_len, + uint8_t *dst, int *out_len); + +int +parse_byte_stream(const char *sval, int max_len, uint8_t *dst, int *out_len); + +int +parse_byte_stream_exact_length(const char *sval, uint8_t *dst, int len); + +#endif http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8374b5a1/util/parse/pkg.yml ---------------------------------------------------------------------- diff --git a/util/parse/pkg.yml b/util/parse/pkg.yml new file mode 100644 index 0000000..69389f7 --- /dev/null +++ b/util/parse/pkg.yml @@ -0,0 +1,32 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +pkg.name: util/parse +pkg.description: Library containing miscellaneous utilities. +pkg.author: "Apache Mynewt <d...@mynewt.incubator.apache.org>" +pkg.homepage: "http://mynewt.apache.org/" +pkg.keywords: + - parse + +pkg.cflags: + # Required for [U]LLONG_{MIN,MAX} + - "-std=c99" + +pkg.deps: + - "@apache-mynewt-core/sys/defs" http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/8374b5a1/util/parse/src/parse.c ---------------------------------------------------------------------- diff --git a/util/parse/src/parse.c b/util/parse/src/parse.c new file mode 100644 index 0000000..c278592 --- /dev/null +++ b/util/parse/src/parse.c @@ -0,0 +1,263 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +#include <string.h> +#include <stdlib.h> +#include <stdarg.h> +#include <limits.h> +#include <inttypes.h> +#include <errno.h> +#include <assert.h> +#include "defs/error.h" + +/** + * Determines which numeric base the specified string should be parsed with. + * Strings with leading zeroes are not parsed as octal. + */ +static int +parse_num_base(const char *sval) +{ + /* Skip optional sign. */ + if (sval[0] == '+' || sval[0] == '-') { + sval++; + } + + if (sval[0] == '0' && sval[1] == 'x') { + return 0; + } else { + return 10; + } +} + +/** + * Parses a long long within an imposed range. + * + * @param sval The string to parse. + * @param min Values less than this are rejected. + * @param max Values greater than this are rejected. + * @param out_status Written on completion; + * 0: success; + * SYS_EINVAL: invalid string or number out of + * range. + * + * @return The parsed number on success; + * unspecified on error. + */ +long long +parse_ll_bounds(const char *sval, long long min, long long max, + int *out_status) +{ + char *endptr; + long long llval; + + llval = strtoll(sval, &endptr, parse_num_base(sval)); + if (sval[0] != '\0' && *endptr == '\0' && + llval >= min && llval <= max) { + + *out_status = 0; + return llval; + } + + *out_status = SYS_EINVAL; + return 0; +} + +/** + * Parses an unsigned long long within an imposed range. + * + * @param sval The string to parse. + * @param min Values less than this are rejected. + * @param max Values greater than this are rejected. + * @param out_status Written on completion; + * 0: success; + * SYS_EINVAL: invalid string or number out of + * range. + * + * @return The parsed number on success; + * unspecified on error. + */ +unsigned long long +parse_ull_bounds(const char *sval, + unsigned long long min, unsigned long long max, + int *out_status) +{ + char *endptr; + unsigned long long ullval; + + ullval = strtoull(sval, &endptr, parse_num_base(sval)); + if (sval[0] != '\0' && *endptr == '\0' && + ullval >= min && ullval <= max) { + + *out_status = 0; + return ullval; + } + + *out_status = SYS_EINVAL; + return 0; +} + +/** + * Parses a long long. + * + * @param sval The string to parse. + * @param out_status Written on completion; + * 0: success; + * SYS_EINVAL: invalid string or number out of + * range. + * + * @return The parsed number on success; + * unspecified on error. + */ +long long +parse_ll(const char *sval, int *out_status) +{ + return parse_ll_bounds(sval, LLONG_MIN, LLONG_MAX, out_status); +} + +/** + * Parses an unsigned long long. + * + * @param sval The string to parse. + * @param out_status Written on completion; + * 0: success; + * SYS_EINVAL: invalid string or number out of + * range. + * + * @return The parsed number on success; + * unspecified on error. + */ +long long +parse_ull(const char *sval, int *out_status) +{ + return parse_ull_bounds(sval, 0, ULLONG_MAX, out_status); +} + +/** + * Parses a stream of bytes with the specified delimiter(s). + * + * @param sval The string to parse. + * @param delims String containing delimiters; each character + * can act as a delimiter. + * @param max_len The maximum number of bytes to write. + * @param dst The destination buffer to write bytes to. + * @param out_len Written on success; total number of bytes + * written to the destination buffer. + * + * @return 0 on success; + * SYS_EINVAL on invalid byte stream; + * SYS_ERANGE if result only partially written to + * buffer due to insufficient space. + */ +int +parse_byte_stream_delim(const char *sval, const char *delims, int max_len, + uint8_t *dst, int *out_len) +{ + unsigned long ul; + const char *cur; + char *endptr; + int i; + + i = 0; + cur = sval; + while (*cur != '\0') { + if (i >= max_len) { + return SYS_ERANGE; + } + + ul = strtoul(cur, &endptr, parse_num_base(cur)); + if (endptr == cur) { + return SYS_EINVAL; + } + cur = endptr; + + if (*cur != '\0') { + if (strspn(cur, delims) != 1) { + return SYS_EINVAL; + } + cur++; + if (*cur == '\0') { + /* Ended with a delimiter. */ + return SYS_EINVAL; + } + } + + if (ul > UINT8_MAX) { + return SYS_EINVAL; + } + + dst[i] = ul; + i++; + } + + *out_len = i; + + return 0; +} + +/** + * Parses a stream of bytes using ':' or '-' as delimiters. + * + * @param sval The string to parse. + * @param max_len The maximum number of bytes to write. + * @param dst The destination buffer to write bytes to. + * @param out_len Written on success; total number of bytes + * written to the destination buffer. + * + * @return 0 on success; + * SYS_EINVAL on invalid byte stream; + * SYS_ERANGE if result only partially written to + * buffer due to insufficient space. + */ +int +parse_byte_stream(const char *sval, int max_len, uint8_t *dst, int *out_len) +{ + return parse_byte_stream_delim(sval, ":-", max_len, dst, out_len); +} + +/** + * Parses a stream of bytes using ':' or '-' as delimiters. The number of + * bytes must be the exact value specified. + * + * @param sval The string to parse. + * @param max_len The maximum number of bytes to write. + * @param dst The destination buffer to write bytes to. + * @param len Number of bytes to parse. + * + * @return 0 on success; + * SYS_EINVAL on invalid byte stream or if source + * string contains an unexpected number of + * bytes; + */ +int +parse_byte_stream_exact_length(const char *sval, uint8_t *dst, int len) +{ + int actual_len; + int rc; + + rc = parse_byte_stream(sval, len, dst, &actual_len); + if (rc != 0) { + return rc; + } + + if (actual_len != len) { + return SYS_EINVAL; + } + + return 0; +}