summaryrefslogtreecommitdiffabout
Side-by-side diff
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--src/pack.c178
1 files changed, 177 insertions, 1 deletions
diff --git a/src/pack.c b/src/pack.c
index 701d82a..b71823a 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -22,6 +22,8 @@
#include <ctype.h>
#include <inttypes.h>
#include <limits.h>
+#include <arpa/inet.h>
+#include <errno.h>
#include "pack.h"
/* Data format specification is a simplified form of Perl pack() template.
@@ -47,6 +49,14 @@
i A signed integer value.
I A unsigned integer value.
+ n An unsigned short (16-bit) in "network" (big-endian) order.
+ N An unsigned long (32-bit) in "network" (big-endian) order.
+ v An unsigned short (16-bit) in "VAX" (little-endian) order.
+ V An unsigned long (32-bit) in "VAX" (little-endian) order.
+
+ f A single-precision float in native format.
+ d A double-precision float in native format.
+
x A null byte (a.k.a ASCII NUL, "\000", chr(0))
X Back up a byte.
@ Null-fill or truncate to absolute position, counted from the
@@ -328,6 +338,166 @@ I_unpacker(struct packenv *env, int rep)
env->buf_pos += sizeof(unsigned);
}
+/* n - An unsigned short (16-bit) in "network" (big-endian) order. */
+static void
+n_packer(struct packenv *env, int rep)
+{
+ if (env->buf_base) {
+ char *arg = packenv_get(env);
+ if (arg) {
+ uintmax_t x;
+ if (getunum(arg, UINT16_MAX, &x) == 0) {
+ uint16_t v = htons((uint16_t) x);
+ memcpy(env->buf_base + env->buf_pos,
+ &v, sizeof(v));
+ }
+ }
+ }
+ env->buf_pos += sizeof(uint16_t);
+}
+
+static void
+n_unpacker(struct packenv *env, int rep)
+{
+ uint16_t v = ntohs(*(uint16_t *)(env->buf_base + env->buf_pos));
+ printunum(env->fp, v);
+ env->buf_pos += sizeof(uint16_t);
+}
+
+/* N - An unsigned long (32-bit) in "network" (big-endian) order. */
+static void
+N_packer(struct packenv *env, int rep)
+{
+ if (env->buf_base) {
+ char *arg = packenv_get(env);
+ if (arg) {
+ uintmax_t x;
+ if (getunum(arg, UINT32_MAX, &x) == 0) {
+ uint32_t v = htonl((uint32_t) x);
+ memcpy(env->buf_base + env->buf_pos,
+ &v, sizeof(v));
+ }
+ }
+ }
+ env->buf_pos += sizeof(uint32_t);
+}
+
+static void
+N_unpacker(struct packenv *env, int rep)
+{
+ uint32_t v = ntohl(*(uint32_t *)(env->buf_base + env->buf_pos));
+ printunum(env->fp, v);
+ env->buf_pos += sizeof(uint32_t);
+}
+
+/* v - An unsigned short (16-bit) in "VAX" (little-endian) order. */
+static void
+v_packer(struct packenv *env, int rep)
+{
+ if (env->buf_base) {
+ char *arg = packenv_get(env);
+ if (arg) {
+ uintmax_t x;
+ if (getunum(arg, UINT16_MAX, &x) == 0) {
+ uint16_t v = ntohs((uint16_t) x);
+ memcpy(env->buf_base + env->buf_pos,
+ &v, sizeof(v));
+ }
+ }
+ }
+ env->buf_pos += sizeof(uint16_t);
+}
+
+static void
+v_unpacker(struct packenv *env, int rep)
+{
+ uint16_t v = htons(*(uint16_t *)(env->buf_base + env->buf_pos));
+ printunum(env->fp, v);
+ env->buf_pos += sizeof(uint16_t);
+}
+
+/* V - An unsigned long (32-bit) in "VAX" (little-endian) order. */
+static void
+V_packer(struct packenv *env, int rep)
+{
+ if (env->buf_base) {
+ char *arg = packenv_get(env);
+ if (arg) {
+ uintmax_t x;
+ if (getunum(arg, UINT32_MAX, &x) == 0) {
+ uint32_t v = ntohl((uint32_t) x);
+ memcpy(env->buf_base + env->buf_pos,
+ &v, sizeof(v));
+ }
+ }
+ }
+ env->buf_pos += sizeof(uint32_t);
+}
+
+static void
+V_unpacker(struct packenv *env, int rep)
+{
+ uint32_t v = htonl(*(uint32_t *)(env->buf_base + env->buf_pos));
+ printunum(env->fp, v);
+ env->buf_pos += sizeof(uint32_t);
+}
+
+/* f - A single-precision float in native format. */
+static void
+f_packer(struct packenv *env, int rep)
+{
+ if (env->buf_base) {
+ char *arg = packenv_get(env);
+ if (arg) {
+ float v;
+ char *p;
+
+ errno = 0;
+ v = strtof(arg, &p);
+ if (*p == 0 && errno == 0)
+ memcpy(env->buf_base + env->buf_pos,
+ &v, sizeof(v));
+ }
+ }
+ env->buf_pos += sizeof(float);
+}
+
+static void
+f_unpacker(struct packenv *env, int rep)
+{
+ float v = *(float *)(env->buf_base + env->buf_pos);
+ fprintf(env->fp, "%f", v); /* FIXME: Format? */
+ env->buf_pos += sizeof(uint32_t);
+}
+
+/* d - A double-precision float in native format. */
+static void
+d_packer(struct packenv *env, int rep)
+{
+ if (env->buf_base) {
+ char *arg = packenv_get(env);
+ if (arg) {
+ double v;
+ char *p;
+
+ errno = 0;
+ v = strtod(arg, &p);
+ if (*p == 0 && errno == 0)
+ memcpy(env->buf_base + env->buf_pos,
+ &v, sizeof(v));
+ }
+ }
+ env->buf_pos += sizeof(double);
+}
+
+static void
+d_unpacker(struct packenv *env, int rep)
+{
+ double v = *(double *)(env->buf_base + env->buf_pos);
+ fprintf(env->fp, "%g", v); /* FIXME: Format? */
+ env->buf_pos += sizeof(double);
+}
+
static void
x_packer(struct packenv *env, int rep)
{
@@ -393,7 +563,13 @@ static struct packspec packspec[] = {
{ 'Q', 0, Q_packer, Q_unpacker },
{ 'i', 0, i_packer, i_unpacker },
{ 'I', 0, I_packer, I_unpacker },
- /* FIXME: n N v V f d */
+ { 'n', 0, n_packer, n_unpacker },
+ { 'N', 0, N_packer, N_unpacker },
+ { 'v', 0, v_packer, v_unpacker },
+ { 'V', 0, V_packer, V_unpacker },
+ { 'f', 0, f_packer, f_unpacker },
+ { 'd', 0, d_packer, d_unpacker },
+
{ 'x', 0, x_packer, x_unpacker },
{ 'X', 0, X_packer, X_packer },
{ '@', F_REP, at_packer, at_unpacker },

Return to:

Send suggestions and report system problems to the System administrator.