summaryrefslogtreecommitdiff
path: root/assorted/pack.c
diff options
context:
space:
mode:
Diffstat (limited to 'assorted/pack.c')
-rw-r--r--assorted/pack.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/assorted/pack.c b/assorted/pack.c
new file mode 100644
index 0000000..9eec65e
--- /dev/null
+++ b/assorted/pack.c
@@ -0,0 +1,103 @@
+/*
+ * libHX/assorted/pack.c
+ * Copyright Jan Engelhardt, 1999-2005
+ *
+ * This file is part of libHX. libHX is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU Lesser
+ * General Public License as published by the Free Software Foundation;
+ * either version 2.1 or (at your option) any later version.
+ */
+#include <sys/types.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+
+size_t HX_pack(char *buf, size_t buflen, const char *fmt, ...)
+{
+ char *obp = buf;
+ int run = 1;
+ va_list ap;
+ va_start(ap, fmt);
+
+ while (run && *fmt != '\0') {
+ switch (*fmt++) {
+ case 'A': /* string with up to 255 chars */
+ case 'a': {
+ const char *src = va_arg(ap, const char *);
+ size_t slen = strlen(src) & 0xFF;
+ if (buflen < slen + 1) {
+ run = 0;
+ break;
+ }
+ *buf++ = slen;
+ memcpy(buf, src, slen);
+ buf += slen;
+ buflen -= slen + 1;
+ break;
+ }
+ case 'C': /* unsigned char */
+ case 'c':
+ if (buflen-- < 1) {
+ run = 0;
+ break;
+ }
+ /*
+ * Minimum object's size being pushed on the stack is 2
+ * bytes since short int is promoted to int when passed
+ * thru va_arg and stays uncasted. (FIXME)
+ */
+ *buf++ = va_arg(ap, unsigned int);
+ break;
+ case 'H': /* unsigned short */
+ case 'h':
+ if (buflen < sizeof(uint16_t)) {
+ run = 0;
+ break;
+ }
+ *((uint16_t *)buf) = va_arg(ap, uint16_t);
+ buf += sizeof(uint16_t);
+ buflen -= sizeof(uint16_t);
+ break;
+ case 'L': /* unsigned long */
+ case 'l':
+ if (buflen < sizeof(uint32_t)) {
+ run = 0;
+ break;
+ }
+ *((uint32_t *)buf) = va_arg(ap, uint32_t);
+ buf += sizeof(uint32_t);
+ buflen -= sizeof(uint32_t);
+ break;
+ case 'S': /* string with up to 65535 chars */
+ case 's': {
+ const char *src = va_arg(ap, const char *);
+ size_t slen = strlen(src) & 0xFFFF;
+ if (buflen < slen + 2) {
+ run = 0;
+ break;
+ }
+ *((unsigned short *)buf) = slen;
+ memcpy(buf += 2, src, slen);
+ buf += slen;
+ buflen -= slen + 2;
+ break;
+ }
+ case 'V': /* fixed size string */
+ case 'v': {
+ void *src = va_arg(ap, void *);
+ size_t slen = va_arg(ap, size_t);
+ if (buflen < slen) {
+ run = 0;
+ break;
+ }
+ memcpy(buf, src, slen);
+ buf += slen;
+ buflen -= slen;
+ break;
+ }
+ } /* switch */
+ }
+
+ va_end(ap);
+ return buf - obp;
+}