[code] [blog] [Repos] [GPS Tracker] [Music] [VNC] [Restart VNC] [E-Mail me]

5.2 KB · raw

#include <stdlib.h>
#include "string.h"
#include "util.h"

bool is_special(char c) {
    //ctype takes an int that must be representable as unsigned char or EOF. Passing a
    //plain (signed) char hands it a negative value for every byte above 0x7f, which is
    //undefined - and these protocols carry binary payloads full of them.
    unsigned char u = (unsigned char)c;
    return (isspace(u) || u == '\r' || u == '\n');
}

char * strip_whitespace(char * cmd) {
    for (; strlen(cmd) > 0 && is_special(*cmd); cmd++);

    //a string that is empty, or entirely whitespace, leaves strlen at 0 here and the old
    //"strlen - 1" wrapped to SIZE_MAX, so the loop read cmd[SIZE_MAX] on its first test.
    size_t len = strlen(cmd);

    if (len == 0) {
        return cmd;
    }

    for (size_t idx = len - 1; idx > 0 && is_special(cmd[idx]) ; idx--) {
        char c = cmd[idx];

        if (!isprint(c)) {
            cmd[idx] = ' ';
        }

        if (isspace(c)) {
            cmd[idx] = ' ';
        }

        if (c == '\r' || c == '\n') {
            cmd[idx] = 0;
        }
    }

    return cmd;
}

int parse_int(char * str, size_t count) {
    if (count >= 32) {
        return 0;
    }

    if (0 == str) {
        return 0;
    }

    for (size_t i = 0; i < count && is_special(*str); i++) {
        str++;
    }

    unsigned char tmp[32];
    memset(tmp, 0, 32);
    memcpy(tmp, str, min(count, strlen(str)));
    return atoi((const char *)tmp);
}

float parse_float(char * string) {
    float num = 0, divisor = 10;;
    char ch;
    bool neg = false;

    if (0 == string) {
        return num;
    }

    size_t count = strlen(string);

    for (size_t i = 0; i < count && is_special(*string); i++) {
        string++;
    }

    if (*string == '-') {
        neg = true;
        string++;
    }

    while (isdigit((unsigned char)(ch = *string)) && ch != 0) {
        num = 10 * num + ch - '0';
        string++;
    }

    //the integer loop above used to consume the byte that stopped it. When that byte was
    //the terminator the fractional loop started one past the end of the string and read
    //whatever followed it in memory.
    if (*string == '.' || *string == ',') {
        string++;

        while (isdigit((unsigned char)(ch = *string)) && ch != 0) {
            num = num + (ch - '0') / divisor;
            divisor *= 10;
            string++;
        }
    }

    return neg ? -num : num;
}

int idx(char * string, char c) {
    char * e = strchr(string, c);

    if (e == NULL) {
        return 0;
    }

    return (int)(e - string);
}

/*
 * Where c first appears in the first len bytes of buf, or -1 when it does not.
 *
 * The framing code used idx(), which answers 0 both for "not there" and for "at the very
 * start", and searches with strchr - past read_count, through whatever an earlier message
 * left in the buffer. A frame that was nothing but its terminator ("#" on its own) therefore
 * looked like no frame at all, was never consumed, and every message behind it waited for
 * ever. memchr over the bytes actually received, and a distinct answer for "not found".
 */
long find_byte(const unsigned char * buf, size_t len, unsigned char c) {
    const unsigned char * at = buf ? memchr(buf, c, len) : NULL;
    return at ? (long)(at - buf) : -1;
}

/*
 * Six hex octets out of a scan entry, in whichever layout the protocol uses ("%x:%x:..." or
 * "%2x%2x..."). True only when all six converted, each fits a byte, and the address is not
 * all zeros or all ones - neither of which is an access point. mac is written only then, so
 * a field that does not parse can never hand the lookup whatever was on the stack.
 */
bool parse_mac(const char * text, const char * format, unsigned char mac[6]) {
    unsigned int v[6] = {0};

    if (text == 0 || format == 0 || sscanf(text, format, &v[0], &v[1], &v[2], &v[3], &v[4], &v[5]) != 6) {
        return false;
    }

    bool all_zero = true;
    bool all_ones = true;

    for (int b = 0; b < 6; b++) {
        if (v[b] > 0xff) {
            return false;
        }

        all_zero = all_zero && v[b] == 0;
        all_ones = all_ones && v[b] == 0xff;
    }

    if (all_zero || all_ones) {
        return false;
    }

    for (int b = 0; b < 6; b++) {
        mac[b] = (unsigned char)v[b];
    }

    return true;
}

void rep(unsigned char * in, unsigned char from, unsigned char with, size_t len) {
    for (size_t i = 0; i < len; i++)if (in[i] == from) {
            in[i] = with;
        }
}

size_t split_to(unsigned char delim, unsigned char * src, size_t len, unsigned char ** dest, size_t dest_count) {
    size_t prev_idx = 0;
    size_t str_count = 0;
    len = min(len, strlen(src));

    for (size_t i = 0; i <= len && str_count < dest_count; i++) {
        if (src[i] == delim || src[i] == '\0' || i == len) {
            size_t cur_len = i - prev_idx;
            dest[str_count] = src + prev_idx;

            for (; cur_len > 0 && isspace(dest[str_count][0]) && dest[str_count] < (src + len)  ;)  {
                dest[str_count]++;
                cur_len--;
            }

            str_count++;

            if ( src[i] == '\0' || i == len) {
                return str_count;
            }

            prev_idx = i + 1;
            src[i] = 0;
        }
    }

    return str_count;
}