summaryrefslogtreecommitdiff
path: root/lib/pattern.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pattern.c')
-rw-r--r--lib/pattern.c472
1 files changed, 0 insertions, 472 deletions
diff --git a/lib/pattern.c b/lib/pattern.c
deleted file mode 100644
index 0aeb9352..00000000
--- a/lib/pattern.c
+++ /dev/null
@@ -1,472 +0,0 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <limits.h>
-#include <errno.h>
-#include <assert.h>
-
-#include "strntol.h"
-#include "pattern.h"
-#include "../minmax.h"
-#include "../oslib/strcasestr.h"
-
-/**
- * parse_string() - parses string in double quotes, like "abc"
- * @beg - string input
- * @out - output buffer where parsed number should be put
- * @out_len - length of the output buffer
- * @filled - pointer where number of bytes successfully
- * parsed will be put
- *
- * Returns the end pointer where parsing has been stopped.
- * In case of parsing error or lack of bytes in output buffer
- * NULL will be returned.
- */
-static const char *parse_string(const char *beg, char *out,
- unsigned int out_len,
- unsigned int *filled)
-{
- const char *end;
-
- if (!out_len)
- return NULL;
-
- assert(*beg == '"');
- beg++;
- end = strchr(beg, '"');
- if (!end)
- return NULL;
- if (end - beg > out_len)
- return NULL;
-
- memcpy(out, beg, end - beg);
- *filled = end - beg;
-
- /* Catch up quote */
- return end + 1;
-}
-
-/**
- * parse_number() - parses numbers
- * @beg - string input
- * @out - output buffer where parsed number should be put
- * @out_len - length of the output buffer
- * @filled - pointer where number of bytes successfully
- * parsed will be put
- *
- * Supports decimals in the range [INT_MIN, INT_MAX] and
- * hexidecimals of any size, which should be started with
- * prefix 0x or 0X.
- *
- * Returns the end pointer where parsing has been stopped.
- * In case of parsing error or lack of bytes in output buffer
- * NULL will be returned.
- */
-static const char *parse_number(const char *beg, char *out,
- unsigned int out_len,
- unsigned int *filled)
-{
- const char *end;
- unsigned int val;
- long lval;
- int num, i;
-
- if (!out_len)
- return NULL;
-
- num = 0;
- sscanf(beg, "0%*[xX]%*[0-9a-fA-F]%n", &num);
- if (num == 0) {
- /* Here we are trying to parse decimal */
-
- char *_end;
-
- /* Looking ahead */
- _end = strcasestr(beg, "0x");
- if (_end)
- num = _end - beg;
- if (num)
- lval = strntol(beg, num, &_end, 10);
- else
- lval = strtol(beg, &_end, 10);
- if (beg == _end || lval > INT_MAX || lval < INT_MIN)
- return NULL;
- end = _end;
- i = 0;
- if (!lval) {
- num = 0;
- out[i] = 0x00;
- i = 1;
- } else {
- val = (unsigned int)lval;
- for (; val && out_len; out_len--, i++, val >>= 8)
- out[i] = val & 0xff;
- if (val)
- return NULL;
- }
- } else {
- assert(num > 2);
-
- /* Catch up 0x prefix */
- num -= 2;
- beg += 2;
-
- /* Look back, handle this combined string: 0xff0x14 */
- if (beg[num] && !strncasecmp(&beg[num - 1], "0x", 2))
- num--;
-
- end = beg + num;
-
- for (i = 0; num && out_len;
- out_len--, i++, num -= 2, beg += 2) {
- const char *fmt;
-
- fmt = (num & 1 ? "%1hhx" : "%2hhx");
- sscanf(beg, fmt, &out[i]);
- if (num & 1) {
- num++;
- beg--;
- }
- }
- if (num)
- return NULL;
- }
-
- *filled = i;
- return end;
-
-}
-
-/**
- * parse_format() - parses formats, like %o, etc
- * @in - string input
- * @out - output buffer where space for format should be reserved
- * @parsed - number of bytes which were already parsed so far
- * @out_len - length of the output buffer
- * @fmt_desc - format descritor array, what we expect to find
- * @fmt_desc_sz - size of the format descritor array
- * @fmt - format array, the output
- * @fmt_sz - size of format array
- *
- * This function tries to find formats, e.g.:
- * %o - offset of the block
- *
- * In case of successfull parsing it fills the format param
- * with proper offset and the size of the expected value, which
- * should be pasted into buffer using the format 'func' callback.
- *
- * Returns the end pointer where parsing has been stopped.
- * In case of parsing error or lack of bytes in output buffer
- * NULL will be returned.
- */
-static const char *parse_format(const char *in, char *out, unsigned int parsed,
- unsigned int out_len, unsigned int *filled,
- const struct pattern_fmt_desc *fmt_desc,
- unsigned int fmt_desc_sz,
- struct pattern_fmt *fmt, unsigned int fmt_sz)
-{
- int i;
- struct pattern_fmt *f = NULL;
- unsigned int len = 0;
-
- if (!out_len || !fmt_desc || !fmt_desc_sz || !fmt || !fmt_sz)
- return NULL;
-
- assert(*in == '%');
-
- for (i = 0; i < fmt_desc_sz; i++) {
- const struct pattern_fmt_desc *desc;
-
- desc = &fmt_desc[i];
- len = strlen(desc->fmt);
- if (0 == strncmp(in, desc->fmt, len)) {
- fmt->desc = desc;
- fmt->off = parsed;
- f = fmt;
- break;
- }
- }
-
- if (!f)
- return NULL;
- if (f->desc->len > out_len)
- return NULL;
-
- memset(out, '\0', f->desc->len);
- *filled = f->desc->len;
-
- return in + len;
-}
-
-/**
- * parse_and_fill_pattern() - Parses combined input, which consists of strings,
- * numbers and pattern formats.
- * @in - string input
- * @in_len - size of the input string
- * @out - output buffer where parsed result will be put
- * @out_len - lengths of the output buffer
- * @fmt_desc - array of pattern format descriptors [input]
- * @fmt_desc_sz - size of the format descriptor array
- * @fmt - array of pattern formats [output]
- * @fmt_sz - pointer where the size of pattern formats array stored [input],
- * after successfull parsing this pointer will contain the number
- * of parsed formats if any [output].
- *
- * strings:
- * bytes sequence in double quotes, e.g. "123".
- * NOTE: there is no way to escape quote, so "123\"abc" does not work.
- *
- * numbers:
- * hexidecimal - sequence of hex bytes starting from 0x or 0X prefix,
- * e.g. 0xff12ceff1100ff
- * decimal - decimal number in range [INT_MIN, INT_MAX]
- *
- * formats:
- * %o - offset of block, reserved 8 bytes.
- *
- * Explicit examples of combined string:
- * #1 #2 #3 #4
- * in="abcd" in=-1024 in=66 in=0xFF0X1
- * out=61 62 63 64 out=00 fc ff ff out=42 out=ff 01
- *
- * #5 #6
- * in=%o in="123"0xFFeeCC
- * out=00 00 00 00 00 00 00 00 out=31 32 33 ff ec cc
- *
- * #7
- * in=-100xab"1"%o"2"
- * out=f6 ff ff ff ab 31 00 00 00 00 00 00 00 00 32
- *
- * #9
- * in=%o0xdeadbeef%o
- * out=00 00 00 00 00 00 00 00 de ad be ef 00 00 00 00 00 00 00 00
- *
- * #10
- * in=0xfefefefefefefefefefefefefefefefefefefefefe
- * out=fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe fe
- *
- * Returns number of bytes filled or err < 0 in case of failure.
- */
-int parse_and_fill_pattern(const char *in, unsigned int in_len,
- char *out, unsigned int out_len,
- const struct pattern_fmt_desc *fmt_desc,
- unsigned int fmt_desc_sz,
- struct pattern_fmt *fmt,
- unsigned int *fmt_sz_out)
-{
- const char *beg, *end, *out_beg = out;
- unsigned int total = 0, fmt_rem = 0;
-
- if (!in || !in_len || !out || !out_len)
- return -EINVAL;
- if (fmt_sz_out)
- fmt_rem = *fmt_sz_out;
-
- beg = in;
- do {
- unsigned int filled;
- int parsed_fmt;
-
- filled = 0;
- parsed_fmt = 0;
-
- switch (*beg) {
- case '"':
- end = parse_string(beg, out, out_len, &filled);
- break;
- case '%':
- end = parse_format(beg, out, out - out_beg, out_len,
- &filled, fmt_desc, fmt_desc_sz,
- fmt, fmt_rem);
- parsed_fmt = 1;
- break;
- default:
- end = parse_number(beg, out, out_len, &filled);
- break;
- }
-
- if (!end)
- return -EINVAL;
-
- if (parsed_fmt) {
- assert(fmt_rem);
- fmt_rem--;
- fmt++;
- }
-
- assert(end - beg <= in_len);
- in_len -= end - beg;
- beg = end;
-
- assert(filled);
- assert(filled <= out_len);
- out_len -= filled;
- out += filled;
- total += filled;
-
- } while (in_len);
-
- if (fmt_sz_out)
- *fmt_sz_out -= fmt_rem;
- return total;
-}
-
-/**
- * dup_pattern() - Duplicates part of the pattern all over the buffer.
- *
- * Returns 0 in case of success or errno < 0 in case of failure.
- */
-static int dup_pattern(char *out, unsigned int out_len, unsigned int pattern_len)
-{
- unsigned int left, len, off;
-
- if (out_len <= pattern_len)
- /* Normal case */
- return 0;
-
- off = pattern_len;
- left = (out_len - off);
- len = min(left, off);
-
- /* Duplicate leftover */
- while (left) {
- memcpy(out + off, out, len);
- left -= len;
- off <<= 1;
- len = min(left, off);
- }
-
- return 0;
-}
-
-/**
- * cpy_pattern() - Copies pattern to the buffer.
- *
- * Function copies pattern along the whole buffer.
- *
- * Returns 0 in case of success or errno < 0 in case of failure.
- */
-int cpy_pattern(const char *pattern, unsigned int pattern_len,
- char *out, unsigned int out_len)
-{
- unsigned int len;
-
- if (!pattern || !pattern_len || !out || !out_len)
- return -EINVAL;
-
- /* Copy pattern */
- len = min(pattern_len, out_len);
- memcpy(out, pattern, len);
-
- /* Spread filled chunk all over the buffer */
- return dup_pattern(out, out_len, pattern_len);
-}
-
-/**
- * cmp_pattern() - Compares pattern and buffer.
- *
- * For the sake of performance this function avoids any loops.
- * Firstly it tries to compare the buffer itself, checking that
- * buffer consists of repeating patterns along the buffer size.
- *
- * If the difference is not found then the function tries to compare
- * buffer and pattern.
- *
- * Returns 0 in case of success or errno < 0 in case of failure.
- */
-int cmp_pattern(const char *pattern, unsigned int pattern_size,
- unsigned int off, const char *buf, unsigned int len)
-{
- int rc;
- unsigned int size;
-
- /* Find the difference in buffer */
- if (len > pattern_size) {
- rc = memcmp(buf, buf + pattern_size, len - pattern_size);
- if (rc)
- return -EILSEQ;
- }
- /* Compare second part of the pattern with buffer */
- if (off) {
- size = min(len, pattern_size - off);
- rc = memcmp(buf, pattern + off, size);
- if (rc)
- return -EILSEQ;
- buf += size;
- len -= size;
- }
- /* Compare first part of the pattern or the whole pattern
- * with buffer */
- if (len) {
- size = min(len, (off ? off : pattern_size));
- rc = memcmp(buf, pattern, size);
- if (rc)
- return -EILSEQ;
- }
-
- return 0;
-}
-
-/**
- * paste_format_inplace() - Pastes parsed formats to the pattern.
- *
- * This function pastes formats to the pattern. If @fmt_sz is 0
- * function does nothing and pattern buffer is left untouched.
- *
- * Returns 0 in case of success or errno < 0 in case of failure.
- */
-int paste_format_inplace(char *pattern, unsigned int pattern_len,
- struct pattern_fmt *fmt, unsigned int fmt_sz,
- void *priv)
-{
- int i, rc;
- unsigned int len;
-
- if (!pattern || !pattern_len || !fmt)
- return -EINVAL;
-
- /* Paste formats for first pattern chunk */
- for (i = 0; i < fmt_sz; i++) {
- struct pattern_fmt *f;
-
- f = &fmt[i];
- if (pattern_len <= f->off)
- break;
- len = min(pattern_len - f->off, f->desc->len);
- rc = f->desc->paste(pattern + f->off, len, priv);
- if (rc)
- return rc;
- }
-
- return 0;
-}
-
-/**
- * paste_format() - Pastes parsed formats to the buffer.
- *
- * This function copies pattern to the buffer, pastes format
- * into it and then duplicates pattern all over the buffer size.
- *
- * Returns 0 in case of success or errno < 0 in case of failure.
- */
-int paste_format(const char *pattern, unsigned int pattern_len,
- struct pattern_fmt *fmt, unsigned int fmt_sz,
- char *out, unsigned int out_len, void *priv)
-{
- int rc;
- unsigned int len;
-
- if (!pattern || !pattern_len || !out || !out_len)
- return -EINVAL;
-
- /* Copy pattern */
- len = min(pattern_len, out_len);
- memcpy(out, pattern, len);
-
- rc = paste_format_inplace(out, len, fmt, fmt_sz, priv);
- if (rc)
- return rc;
-
- /* Spread filled chunk all over the buffer */
- return dup_pattern(out, out_len, pattern_len);
-}