+#include <float.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <unistd.h>
static uint8_t *data;
-static size_t n;
+static size_t n, pos;
+
+#define XSTR(x) #x
+#define STR(x) XSTR(x)
+#define WHERE __FILE__":" STR(__LINE__)
+
+static unsigned int
+get_u32(void)
+{
+ uint32_t x;
+ memcpy(&x, &data[pos], 4);
+ pos += 4;
+ return x;
+}
+
+static double
+get_double(void)
+{
+ double x;
+ memcpy(&x, &data[pos], 8);
+ pos += 8;
+ return x;
+}
+
+static bool
+match_u32(uint32_t x)
+{
+ if (get_u32() == x)
+ return true;
+ pos -= 4;
+ return false;
+}
+
+static void
+match_u32_assert(uint32_t x, const char *where)
+{
+ unsigned int y = get_u32();
+ if (x != y)
+ {
+ fprintf(stderr, "%s: 0x%x: expected i%u, got i%u\n", where, pos - 4, x, y);
+ exit(1);
+ }
+}
+#define match_u32_assert(x) match_u32_assert(x, WHERE)
+
+static bool
+all_ascii(const uint8_t *p)
+{
+ for (; *p; p++)
+ if (*p < 32 || *p > 126)
+ return false;
+ return true;
+}
+
+static char *
+get_fixed_string(int len, const char *where)
+{
+ if (pos + len > n || !memchr(&data[pos], 0, len) || !all_ascii(&data[pos]))
+ {
+ fprintf(stderr, "%s: 0x%x: bad fixed-width string\n", where, pos);
+ exit(1);
+ }
+ char *s = (char *) &data[pos];
+ pos += len;
+ return s;
+}
+#define get_fixed_string(len) get_fixed_string(len, WHERE)
+
+static bool
+all_ascii2(const uint8_t *p, size_t n)
+{
+ for (size_t i = 0; i < n; i++)
+ if (p[i] < 32 || p[i] > 126)
+ return false;
+ return true;
+}
+
+static char *
+get_string(const char *where)
+{
+ if (1
+ /*data[pos + 1] == 0 && data[pos + 2] == 0 && data[pos + 3] == 0*/
+ /*&& all_ascii(&data[pos + 4], data[pos])*/)
+ {
+ int len = data[pos] + data[pos + 1] * 256;
+ char *s = malloc(len + 1);
+
+ memcpy(s, &data[pos + 4], len);
+ s[len] = 0;
+ pos += 4 + len;
+ return s;
+ }
+ else
+ {
+ fprintf(stderr, "%s: 0x%x: expected string\n", where, pos);
+ exit(1);
+ }
+}
+#define get_string() get_string(WHERE)
+
+static void
+dump_raw(FILE *stream, int start, int end, const char *separator)
+{
+ for (size_t i = start; i < end; )
+ {
+ if (i + 5 <= n
+ && data[i] > 0
+ //&& !data[i + 1]
+ && !data[i + 2]
+ && !data[i + 3]
+ && i + 4 + data[i] + data[i + 1] * 256 <= end
+ && all_ascii2(&data[i + 4], data[i] + data[i + 1] * 256))
+ {
+ fprintf(stream, "%s\"", separator);
+ fwrite(&data[i + 4], 1, data[i] + data[i + 1] * 256, stream);
+ fputs("\" ", stream);
+
+ i += 4 + data[i] + data[i + 1] * 256;
+ }
+ else if (i + 12 <= end
+ && data[i + 1] == 40
+ && data[i + 2] == 5
+ && data[i + 3] == 0)
+ {
+ double d;
+
+ memcpy (&d, &data[i + 4], 8);
+ fprintf (stream, "F40.%d(%.*f)%s", data[i], data[i], d, separator);
+ i += 12;
+ }
+ else if (i + 12 <= end
+ && data[i + 1] == 40
+ && data[i + 2] == 31
+ && data[i + 3] == 0)
+ {
+ double d;
+
+ memcpy (&d, &data[i + 4], 8);
+ fprintf (stream, "PCT40.%d(%.*f)%s", data[i], data[i], d, separator);
+ i += 12;
+ }
+ else if (i + 4 <= end
+ && !data[i + 1]
+ && !data[i + 2]
+ && !data[i + 3])
+ {
+ fprintf (stream, "i%d ", data[i]);
+ i += 4;
+ }
+ else
+ {
+ fprintf(stream, "%02x ", data[i]);
+ i++;
+ }
+ }
+}
int
main(int argc, char **argv)
exit(1);
}
- if (argc < 3)
+ pos = 0;
+ match_u32_assert(0x1b000);
+ match_u32_assert(s.st_size);
+
+ printf ("%08x:", pos);
+ int count = get_u32(), n_series = get_u32();
+ printf (" %d series, %d observations per series\n", n_series, count);
+ printf ("%08x\n\n", pos);
+
+ const union
{
- fprintf(stderr, "bad arguments");
- exit(1);
+ uint8_t b[8];
+ double d;
+ }
+ sysmis = {.b = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xef, 0xff}};
+ pos = 0x58;
+ for (int i = 0; i < n_series; i++)
+ {
+ printf ("%08x:", pos);
+ printf (" %s\n", get_fixed_string(288));
+ printf ("%08x:", pos);
+ for (int i = 0; i < count; i++)
+ {
+ double d = get_double();
+ if (d == sysmis.d)
+ printf (" .");
+ else
+ printf (" %.*g", DBL_DIG, d);
+ }
+ printf ("\n");
}
- start = strtol(argv[1], NULL, 0);
- int end = strtol(argv[2], NULL, 0);
- for (int pos = start; pos < end; pos += 8)
+ printf ("%08x:", pos);
+ printf (" %d", get_u32());
+ printf (", \"%s\"\n", get_string());
+
+ printf ("\n%08x:", pos);
+ int n_more_series = get_u32();
+ printf (" %d series to come\n", n_more_series);
+
+ for (int i = 0; i < n_more_series; i++)
{
- double d;
- memcpy(&d, &data[pos], sizeof d);
- printf("%g\n", d);
+ printf ("%08x:", pos);
+ printf (" \"%s\"", get_string());
+ int n_pairs = get_u32();
+ for (int j = 0; j < n_pairs; j++)
+ {
+ int x = get_u32();
+ int y = get_u32();
+ printf (" (%d,%d)", x, y);
+ }
+ printf ("\n");
}
+
+ printf ("\n%08x:", pos);
+ int n_strings = get_u32();
+ printf (" %d strings\n", n_strings);
+ for (int i = 0; i < n_strings; i++)
+ {
+ int x = get_u32();
+ char *s = get_string();
+ printf ("%d: \"%s\" (%d)\n", i, s, x);
+ }
+
+ dump_raw (stdout, pos, n, "\n");
+ putchar('\n');
return 0;
}