Mercurial > code
changeset 153:a6a7cd08be72
pack.c:
o added two new functions pack_fmtlen, pack_vfmtlen, compute the number
of bytes needed for format.
o added support for buffer, pack_swrite, pack_vswrite, pack_sread,
pack_vsread. Buffer will be automatically allocated for _write
functions.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sun, 15 Jul 2012 20:40:54 +0200 |
parents | 54976019a5a8 |
children | c7ad101ed4a1 |
files | pack.c pack.h |
diffstat | 2 files changed, 272 insertions(+), 120 deletions(-) [+] |
line wrap: on
line diff
--- a/pack.c Wed Jun 27 11:23:54 2012 +0200 +++ b/pack.c Sun Jul 15 20:40:54 2012 +0200 @@ -30,6 +30,18 @@ * -------------------------------------------------------- */ typedef void (*ConvertFn)(void *); +typedef void (*WriteFn)(uint64_t, size_t, void *, void *); + +struct value { + char tok; /* token found */ + int nelem; /* number element for this value */ + size_t size; /* size of this element */ + + union { + uint8_t *array; /* if (nelem > 1) */ + uint64_t value; /* if (nelem == 1) */ + } data; +}; /* -------------------------------------------------------- * prototypes @@ -41,8 +53,11 @@ static void pack_convert16(uint16_t *); static void pack_convert32(uint32_t *); static void pack_convert64(uint64_t *); -static void pack_write_one(int, FILE *, uint64_t, size_t); -static void pack_write_multiple(int, FILE *, uint8_t *, int, size_t); + +static void pack_writefunc_fp(uint64_t, size_t, FILE *, void *); +static void pack_writefunc_buffer(uint64_t, size_t, uint8_t *, size_t *); +static void pack_convert_write(const struct value *, int, + WriteFn, void *, void *); /* -------------------------------------------------------- * private functions @@ -68,45 +83,6 @@ }; /* - * Parse the format, return 0 on success or -1 on failure. - */ - -#define PACK_GETARG(i, ap, tok) \ -do { \ - switch ((tok)) { \ - case 'c': \ - case 's': \ - case 'i': \ - (i) = va_arg((ap), unsigned); \ - break; \ - case 'l': \ - (i) = va_arg((ap), uint64_t); \ - default: \ - break; \ - } \ -} while (/* CONSTCOND */ 0) - -/* - * Little helper to get number of element when the user wants a array of - * objects. Sets the nelem to 0 on array failure or 1 on normal count. - */ - -#define PACK_GETNELEM(nelem, p) \ -do { \ - if (p[1] == '[') { \ - if (p[2] != ']') \ - nelem = (int)strtol(p + 2, NULL, 10); \ - else if (p[2] == ']') \ - nelem = va_arg(ap, int); \ - \ - /* Go to the end of fmt and find ']' */ \ - while (*p != ']' && *p != '\0') \ - ++p; \ - } else \ - nelem = 1; \ -} while (/* CONSTCOND */ 0) - -/* * Get the appropriate size associated with the `tok' character. If * the token is not found the result is 0. */ @@ -182,39 +158,140 @@ } static void -pack_write_one(int ptype, FILE *fp, uint64_t it, size_t size) +pack_writefunc_fp(uint64_t i, size_t size, FILE *fp, void *unused) { - uint64_t cv = it; + fwrite(&i, size, 1, fp); - if (ptype != PACK_HOST_BYTEORDER) { - ConvertFn conv = pack_getconvert_by_size(size); - - if (conv != NULL) - conv(&cv); - } - - fwrite(&cv, size, 1, fp); + (void)unused; } static void -pack_write_multiple(int ptype, FILE *fp, uint8_t *arr, int length, size_t size) +pack_writefunc_buffer(uint64_t i, size_t size, uint8_t *buffer, size_t *offset) +{ + memcpy(&buffer[*offset], &i, size); + + (*offset) += size; +} + +/* + * Convert data and write it using write func function. + */ + +static void +pack_convert_write(const struct value *val, int ptype, + WriteFn writefunc, void *data1, void *data2) { - uint64_t cv; + ConvertFn conv = NULL; + uint64_t it = 0; int i; + + if (ptype != PACK_HOST_BYTEORDER) + conv = pack_getconvert_by_size(val->size); + + for (i = 0; i < val->nelem; ++i) { + it = 0; + + if (val->nelem == 1) + memcpy(&it, &val->data.value, val->size); + else + memcpy(&it, &val->data.array[i * val->size], val->size); + + /* Converts and bring back to array */ + if (conv != NULL) + conv(&it); + + writefunc(it, val->size, data1, data2); + } +} + +/* + * Convert value for reading, dst pointer will be converted if + * necessary. + */ + +static void +pack_convert_read(const struct value *val, uint8_t *dst, int ptype) +{ ConvertFn conv = NULL; + int i; + uint64_t it = 0; if (ptype != PACK_HOST_BYTEORDER) - conv = pack_getconvert_by_size(size); + conv = pack_getconvert_by_size(val->size); + + for (i = 0; i < val->nelem; ++i) { + it = 0; + memcpy(&it, &dst[i * val->size], val->size); + + if (conv != NULL) { + conv(&it); + memset(&dst[i * val->size], 0, val->size); + } + + memcpy(&dst[i * val->size], &it, val->size); + } +} + +/* + * Store the argument into the corrent .data member. + */ - for (i = 0; i < length; ++i) { - cv = 0; - memcpy(&cv, &arr[i * size], size); +static void +pack_get_arg(struct value *val, va_list ap, int ptype) +{ + if (val->nelem == 1) { + switch (val->tok) { + case 'c': + case 's': + case 'i': + val->data.value = va_arg(ap, unsigned); + break; + case 'l': + val->data.value = va_arg(ap, uint64_t); + default: + break; + } + } else if (val->nelem > 1) + val->data.array = va_arg(ap, uint8_t *); +} - if (conv != NULL) - conv(&cv); +/* + * Get the properties, the token size, the number of element to read. + */ + +static void +pack_get_properties(struct value *val, char **p, va_list ap, int ptype) +{ + memset(val, 0, sizeof (struct value)); + + if (isspace(**p)) + goto skip; + if ((val->size = pack_getsize(**p)) == 0) + goto skip; + + val->tok = **p; - fwrite(&cv, size, 1, fp); + /* + * Now there is valid char, c, s, i or l, we must determine + * if the next character is [ (array) or anything else. + */ + if ((*p)[1] == '[') { + if ((*p)[2] != ']') + val->nelem = (int)strtol((*p) + 2, NULL, 10); + else if ((*p)[2] == ']') + val->nelem = va_arg(ap, int); + + /* Go to the end of fmt and find ']' */ + while (**p != ']' && **p != '\0') + ++ (*p); + } else { + val->nelem = 1; + ++ (*p); } + + return; +skip: + ++ (*p); } /* -------------------------------------------------------- @@ -222,6 +299,87 @@ * -------------------------------------------------------- */ /* + * Returns the number of bytes needed to write the specified format. + */ + +size_t +pack_fmtlen(int ptype, const char *fmt, ...) +{ + va_list ap; + size_t count; + + va_start(ap, fmt); + count = pack_vfmtlen(ptype, fmt, ap); + va_end(ap); + + return count; +} + +size_t +pack_vfmtlen(int ptype, const char *fmt, va_list ap) +{ + const char *p; + struct value v; + size_t count = 0; + + p = fmt; + while (*p != '\0') { + pack_get_properties(&v, (char **)&p, ap, ptype); + count += (v.size * v.nelem); + } + + return count; +} + +/* + * Functions that write anything to the buffer, the buffer is automatically + * allocated for you. Argument buflen will be set to the buffer length and + * must not be NULL. + */ + +int +pack_swrite(int ptype, uint8_t **buf, size_t *buflen, const char *fmt, ...) +{ + va_list ap; + int rv; + + va_start(ap, fmt); + rv = pack_vswrite(ptype, buf, buflen, fmt, ap); + va_end(ap); + + return rv; +} + +int +pack_vswrite(int ptype, uint8_t **buf, size_t *len, const char *fmt, va_list ap) +{ + const char *p; + uint8_t *b = NULL; + size_t offset = 0; + struct value v; + + p = fmt; + while (*p != '\0') { + pack_get_properties(&v, (char **)&p, ap, ptype); + pack_get_arg(&v, ap, ptype); + + if ((b = realloc(b, offset + (v.nelem * v.size))) == NULL) { + *buf = NULL; + *len = 0; + return -1; + } + + pack_convert_write(&v, ptype, + (WriteFn)pack_writefunc_buffer, b, &offset); + } + + *buf = b; + *len = offset; + + return 0; +} + +/* * Function that writes everything to the file `path'. These functions * does not append to the file, so if you want successive call to append * variables use fpack instead. @@ -277,41 +435,52 @@ int pack_vfwrite(int ptype, FILE *fp, const char *fmt, va_list ap) { - int nelem; - size_t size; - char tok; const char *p; + struct value v; + + p = fmt; + while (*p != '\0') { + pack_get_properties(&v, (char **)&p, ap, ptype); + pack_get_arg(&v, ap, ptype); + pack_convert_write(&v, ptype, + (WriteFn)pack_writefunc_fp, fp, NULL); + } + + return 0; +} + +int +pack_sread(int ptype, uint8_t *buf, size_t len, const char *fmt, ...) +{ + va_list ap; + int rv; - for (p = fmt; *p != '\0'; ++p) { - if (isspace(*p)) - continue; + va_start(ap, fmt); + rv = pack_vsread(ptype, buf, len, fmt, ap); + va_end(ap); + + return rv; +} - tok = *p; - size = pack_getsize(tok); +int +pack_vsread(int ptype, uint8_t *buf, size_t len, const char *fmt, va_list ap) +{ + const char *p; + uint8_t *ptr; + size_t offset = 0; + struct value v; - /* Bad character */ - if (size == 0) + p = fmt; + while (*p != '\0' && offset <= len) { + pack_get_properties(&v, (char **)&p, ap, ptype); + + if ((ptr = va_arg(ap, uint8_t *)) == NULL || v.nelem == 0) continue; - PACK_GETNELEM(nelem, p); - if (nelem == 0) - continue; + memcpy(ptr, &buf[offset], v.nelem * v.size); + pack_convert_read(&v, ptr, ptype); - /* - * If i is 1, then we only have one integer, if it's more - * than one, user may have given an array of something else. - */ - if (nelem == 1) { - uint64_t item; - - PACK_GETARG(item, ap, tok); - pack_write_one(ptype, fp, item, size); - } else { - uint8_t *arr; - - arr = va_arg(ap, uint8_t *); - pack_write_multiple(ptype, fp, arr, nelem, size); - } + offset += (v.nelem * v.size); } return 0; @@ -349,7 +518,6 @@ fclose(fp); return status; - } int @@ -370,41 +538,17 @@ { const char *p; uint8_t *ptr; - size_t tocopy; - ConvertFn convert; - - for (p = fmt; *p != '\0'; ++p) { - char tok; - int nelem, i; + struct value v; - if (isspace(*p)) - continue; + p = fmt; + while (*p != '\0') { + pack_get_properties(&v, (char **)&p, ap, ptype); - tok = *p; - tocopy = pack_getsize(tok); - - /* Bad character */ - if (tocopy == 0) + if ((ptr = va_arg(ap, uint8_t *)) == NULL || v.nelem == 0) continue; - /* Determine how many element to read and copy */ - PACK_GETNELEM(nelem, p); - if (nelem == 0) - continue; - - if ((ptr = va_arg(ap, uint8_t *)) == NULL) - continue; - - for (i = 0; i < nelem; ++i) { - memset(&ptr[tocopy * i], 0, tocopy); - if (fread(&ptr[tocopy * i], tocopy, 1, fp) <= 0) - return -1; - - /* Convert if needed */ - convert = pack_getconvert_by_tok(tok); - if (ptype != PACK_HOST_BYTEORDER && convert != NULL) - convert((char *)ptr + (tocopy * i)); - } + fread(ptr, v.size, v.nelem, fp); + pack_convert_read(&v, ptr, ptype); } return 0;
--- a/pack.h Wed Jun 27 11:23:54 2012 +0200 +++ b/pack.h Sun Jul 15 20:40:54 2012 +0200 @@ -20,6 +20,7 @@ #define _PACK_H_ #include <stdarg.h> +#include <stdint.h> #ifdef __cplusplus extern "C" { @@ -56,11 +57,18 @@ ((uint32_t) pack_swap32((uint32_t) (((x) << 32) >> 32))) << 32) \ | (uint32_t) pack_swap32((uint32_t) ((x) >> 32))) +size_t pack_fmtlen(int, const char *, ...); +size_t pack_vfmtlen(int, const char *, va_list); + +int pack_swrite(int, uint8_t **, size_t *, const char *, ...); +int pack_vswrite(int, uint8_t **, size_t *, const char *, va_list); int pack_write(int, const char *, const char *, ...); int pack_vwrite(int, const char *, const char *, va_list); int pack_fwrite(int, FILE *, const char *, ...); int pack_vfwrite(int, FILE *, const char *, va_list); +int pack_sread(int, uint8_t *, size_t, const char *, ...); +int pack_vsread(int, uint8_t *, size_t, const char *, va_list); int pack_read(int, const char *, const char *, ...); int pack_vread(int, const char *, const char *, va_list); int pack_fread(int, FILE *, const char *, ...);