changeset 103:7fefa3a34461

pack.c now directly write to the file
author David Demelier <markand@malikania.fr>
date Tue, 17 Jan 2012 13:38:54 +0100
parents 735d6c774f7a
children c66fb578a7c4
files pack.c
diffstat 1 files changed, 88 insertions(+), 122 deletions(-) [+]
line wrap: on
line diff
--- a/pack.c	Tue Jan 17 12:01:22 2012 +0100
+++ b/pack.c	Tue Jan 17 13:38:54 2012 +0100
@@ -16,7 +16,6 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/queue.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -30,41 +29,20 @@
  * structure definitions
  * -------------------------------------------------------- */
 
-/*
- * Conversion function pointer.
- */
-typedef void (*convert_fn)(void *);
-
-/*
- * Item structure store the integer into the largest data type
- * uint64_t.
- */
-
-struct item {
-	size_t		size;	/* 8, 16, 32 or 64 bits? */
-	uint64_t	i;	/* the data */
-	convert_fn	conv;	/* conversion function */
-	STAILQ_ENTRY(item) next;
-};
-
-/*
- * List of item structure.
- */
-
-STAILQ_HEAD(item_list, item);
+typedef void (*ConvertFn)(void *);
 
 /* --------------------------------------------------------
  * prototypes
  * -------------------------------------------------------- */
 
-static int		pack_item_add(struct item_list *, const struct item *);
-static int		pack_parse(struct item_list *, const char *, va_list);
 static size_t		pack_getsize(char);
-static convert_fn	pack_getconvert(char);
+static ConvertFn	pack_getconvert_by_tok(char);
+static ConvertFn	pack_getconvert_by_size(size_t);
 static void		pack_convert16(void *);
 static void		pack_convert32(void *);
 static void		pack_convert64(void *);
-static int		pack_fatal(struct item_list *);
+static void		pack_write_one(int, FILE *, uint64_t, size_t);
+static void		pack_write_multiple(int, FILE *, uint8_t *, int, size_t);
 
 /* --------------------------------------------------------
  * private functions
@@ -81,7 +59,7 @@
 static struct integer {
 	char		tok;		/* format char */
 	size_t		tocopy;		/* size */
-	convert_fn	convert;	/* conversion function */
+	ConvertFn	convert;	/* conversion function */
 } sizes[] = {
 	{ 'c',		sizeof (uint8_t),	NULL		},
 	{ 's',		sizeof (uint16_t),	&pack_convert16	},
@@ -90,29 +68,6 @@
 };
 
 /*
- * Try to append a new item to the list. The function create a new item
- * object since the pack_parse() use a stack'ed item and not an
- * allocated object. Returns 0 or -1 on failure.
- */
-
-static int
-pack_item_add(struct item_list *list, const struct item *item)
-{
-	struct item *res;
-
-	if ((res = malloc(sizeof (struct item))) == NULL)
-		return -1;
-
-	res->size	= item->size;
-	res->i		= item->i;
-	res->conv	= item->conv;
-
-	STAILQ_INSERT_TAIL(list, res, next);
-
-	return 0;
-}
-
-/*
  * Parse the format, return 0 on success or -1 on failure.
  */
 
@@ -151,56 +106,6 @@
 		nelem = 1;						\
 } while (/* CONSTCOND */ 0)
 
-static int
-pack_parse(struct item_list *list, const char *fmt, va_list ap)
-{
-	const char *p;
-	char tok;
-	struct item item;
-	int nelem;
-
-	STAILQ_INIT(list);
-
-	for (p = fmt; *p != '\0'; ++p) {
-		if (isspace(*p))
-			continue;
-
-		tok = *p;
-		item.size = pack_getsize(tok);
-
-		/* Bad character */
-		if (item.size == 0)
-			continue;
-
-		PACK_GETNELEM(nelem, p);
-		if (nelem == 0)
-			continue;
-
-		/*
-		 * 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) {
-			PACK_GETARG(item.i, ap, tok);
-			item.conv = pack_getconvert(tok);
-
-			if (pack_item_add(list, &item) < 0)
-				return pack_fatal(list);
-		} else {
-			uint8_t *arr = va_arg(ap, void *);
-			int i;
-
-			for (i = 0; i < nelem; ++i) {
-				memcpy(&item.i, &arr[i * item.size], item.size);
-				if (pack_item_add(list, &item) < 0)
-					return pack_fatal(list);
-			}
-		}
-	}
-
-	return 0;
-}
-
 /*
  * Get the appropriate size associated with the `tok' character. If
  * the token is not found the result is 0.
@@ -223,8 +128,8 @@
  * Return the conversion function.
  */
 
-static convert_fn
-pack_getconvert(char tok)
+static ConvertFn
+pack_getconvert_by_tok(char tok)
 {
 	struct integer *s;
 	unsigned int i;
@@ -237,6 +142,23 @@
 }
 
 /*
+ * Same but by size.
+ */
+
+static ConvertFn
+pack_getconvert_by_size(size_t size)
+{
+	struct integer *s;
+	unsigned int i;
+
+	for (s = sizes, i = 0; i < LENGTH(sizes); ++s, ++i)
+		if (s->tocopy == size)
+			return s->convert;
+
+	return NULL;
+}
+
+/*
  * Conversion functions. They reverse the bytes without any
  * check.
  */
@@ -265,17 +187,41 @@
 	*x = pack_swap64(*x);
 }
 
-static int
-pack_fatal(struct item_list *list)
+static void
+pack_write_one(int ptype, FILE *fp, uint64_t it, size_t size)
 {
-	struct item *item, *tmp;
+	uint64_t cv = it;
+
+	if (ptype != PACK_HOST_BYTEORDER) {
+		ConvertFn conv = pack_getconvert_by_size(size);
+
+		if (conv != NULL)
+			conv(&cv);
+	}
+
+	fwrite(&cv, size, 1, fp);
+}
 
-	STAILQ_FOREACH_SAFE(item, list, next, tmp)
-		free(item);
+static void
+pack_write_multiple(int ptype, FILE *fp, uint8_t *arr, int length, size_t size)
+{
+	uint64_t cv;
+	int i;
+	ConvertFn conv = NULL;
+
+	if (ptype != PACK_HOST_BYTEORDER)
+		conv = pack_getconvert_by_size(size);
 
-	return -1;
+	for (i = 0; i < length; ++i) {
+		cv = arr[i * size];
+		if (conv != NULL)
+			conv(&cv);
+
+		fwrite(&cv, size, 1, fp);
+	}
 }
 
+
 /* --------------------------------------------------------
  * public functions
  * -------------------------------------------------------- */
@@ -336,24 +282,44 @@
 int
 pack_vfwrite(int ptype, FILE *fp, const char *fmt, va_list ap)
 {
-	struct item_list list;
-	int status;
+	int nelem;
+	size_t size;
+	char tok;
+	const char *p;
 
-	if ((status = pack_parse(&list, fmt, ap)) == 0) {
-		struct item *item, *tmp;
+	for (p = fmt; *p != '\0'; ++p) {
+		if (isspace(*p))
+			continue;
+
+		tok = *p;
+		size = pack_getsize(tok);
+
+		/* Bad character */
+		if (size == 0)
+			continue;
 
-		STAILQ_FOREACH_SAFE(item, &list, next, tmp) {
-			/* 8 bits does not need to be converted */
-			if (ptype != PACK_HOST_BYTEORDER && item->conv != NULL)
-				item->conv(&item->i);
+		PACK_GETNELEM(nelem, p);
+		if (nelem == 0)
+			continue;
 
-			fwrite(&item->i, item->size, 1, fp);
+		/*
+		 * 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;
 
-			free(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);
 		}
 	}
 
-	return status;
+	return 0;
 }
 
 /*
@@ -410,7 +376,7 @@
 	const char *p;
 	void *ptr;
 	size_t tocopy;
-	convert_fn convert;
+	ConvertFn convert;
 
 	for (p = fmt; *p != '\0'; ++p) {
 		char tok;
@@ -438,7 +404,7 @@
 			fread((char *) ptr + (tocopy * i), tocopy, 1, fp);
 
 			/* Convert if needed */
-			convert = pack_getconvert(tok);
+			convert = pack_getconvert_by_tok(tok);
 			if (ptype != PACK_HOST_BYTEORDER && convert != NULL)
 				convert((char *) ptr + (tocopy * i));
 		}