ref: 100ed8406343f027aa442e79fe59c653c8fc02a4
parent: 74707c5daf432fe8310312021eb775e7a716dbe3
author: Ori Bernstein <ori@eigenstate.org>
date: Mon Feb 22 06:17:40 EST 2016
Extract util functions into separate dir from parse/
--- a/6/Makefile
+++ b/6/Makefile
@@ -12,7 +12,7 @@
simp.o \
typeinfo.o \
-DEPS=../parse/libparse.a ../mi/libmi.a
+DEPS=../parse/libparse.a ../mi/libmi.a ../util/libutil.a
include ../config.mk
include ../mk/c.mk
--- a/6/blob.c
+++ b/6/blob.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/gen.c
+++ b/6/gen.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/gengas.c
+++ b/6/gengas.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/genp9.c
+++ b/6/genp9.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/isel.c
+++ b/6/isel.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/locs.c
+++ b/6/locs.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/main.c
+++ b/6/main.c
@@ -13,6 +13,7 @@
#include <sys/time.h>
#include <sys/wait.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/peep.c
+++ b/6/peep.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/ra.c
+++ b/6/ra.c
@@ -7,6 +7,7 @@
#include <limits.h>
#include <string.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/simp.c
+++ b/6/simp.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/6/typeinfo.c
+++ b/6/typeinfo.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "asm.h"
--- a/Makefile
+++ b/Makefile
@@ -3,6 +3,7 @@
6 \
muse \
rt \
+ util \
doc
EXTRA=buildmyr
--- a/mi/Makefile
+++ b/mi/Makefile
@@ -7,6 +7,6 @@
reaching.o \
-DEPS=../parse/libparse.a
+DEPS=../parse/libparse.a ../util/libutil.a
include ../mk/c.mk
--- a/mi/cfg.c
+++ b/mi/cfg.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
--- a/mi/dfcheck.c
+++ b/mi/dfcheck.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
--- a/mi/flatten.c
+++ b/mi/flatten.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
#include "../config.h"
--- a/mi/match.c
+++ b/mi/match.c
@@ -9,6 +9,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
--- a/mi/reaching.c
+++ b/mi/reaching.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "mi.h"
--- a/muse/Makefile
+++ b/muse/Makefile
@@ -2,7 +2,7 @@
BIN=muse
OBJ=muse.o
-DEPS=../parse/libparse.a
+DEPS=../parse/libparse.a ../util/libutil.a
include ../mk/c.mk
include ../config.mk
--- a/muse/muse.c
+++ b/muse/muse.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "../config.h"
--- a/parse/Makefile
+++ b/parse/Makefile
@@ -1,21 +1,23 @@
LIB=libparse.a
-OBJ=bitset.o \
- dump.o \
- fold.o \
- gram.o \
- htab.o \
- infer.o \
- names.o \
- node.o \
- specialize.o \
- stab.o \
- tok.o \
- type.o \
- use.o \
- util.o
+OBJ=\
+ bitset.o \
+ dump.o \
+ err.o \
+ fold.o \
+ gram.o \
+ infer.o \
+ names.o \
+ node.o \
+ specialize.o \
+ stab.o \
+ tok.o \
+ type.o \
+ use.o \
GENHDR=gram.h
CLEAN=gram.c gram.h
+
+DEPS=../util/libutil.a
include ../mk/lexyacc.mk
include ../mk/c.mk
--- a/parse/bitset.c
+++ b/parse/bitset.c
@@ -6,6 +6,7 @@
#include <limits.h>
#include <string.h>
+#include "util.h"
#include "parse.h"
#define Sizetbits (CHAR_BIT * sizeof(size_t)) /* used in graph reprs */
--- a/parse/dump.c
+++ b/parse/dump.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
/* outputs a fully qualified name */
--- a/parse/fold.c
+++ b/parse/fold.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
static int getintlit(Node *n, vlong *v)
--- a/parse/gram.y
+++ b/parse/gram.y
@@ -14,6 +14,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
--- a/parse/htab.c
+++ /dev/null
@@ -1,288 +1,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <inttypes.h>
-#include <assert.h>
-#include <limits.h>
-#include <string.h>
-
-#include "parse.h"
-
-#define Initsz 16
-
-/* Creates a new empty hash table, using 'hash' as the
- * hash funciton, and 'cmp' to verify that there are no
- * hash collisions. */
-Htab *mkht(ulong (*hash)(void *key), int (*cmp)(void *k1, void *k2))
-{
- Htab *ht;
-
- ht = xalloc(sizeof(Htab));
- ht->nelt = 0;
- ht->ndead = 0;
- ht->sz = Initsz;
- ht->hash = hash;
- ht->cmp = cmp;
- ht->keys = zalloc(Initsz * sizeof(void *));
- ht->vals = zalloc(Initsz * sizeof(void *));
- ht->hashes = zalloc(Initsz * sizeof(void *));
- ht->dead = zalloc(Initsz * sizeof(char));
-
- return ht;
-}
-
-/* Frees a hash table. Passing this function
- * NULL is a no-op. */
-void htfree(Htab *ht)
-{
- if (!ht)
- return;
- free(ht->keys);
- free(ht->vals);
- free(ht->hashes);
- free(ht->dead);
- free(ht);
-}
-
-/* Offsets the hash so that '0' can be
- * used as a 'no valid value */
-static ulong hash(Htab *ht, void *k)
-{
- ulong h;
- h = ht->hash(k);
- if (h == 0)
- return 1;
- else
- return h;
-}
-
-/* Resizes the hash table by copying all
- * the old keys into the right slots in a
- * new table. */
-static void grow(Htab *ht, int sz)
-{
- void **oldk;
- void **oldv;
- ulong *oldh;
- char *oldd;
- int oldsz;
- int i;
-
- oldk = ht->keys;
- oldv = ht->vals;
- oldh = ht->hashes;
- oldd = ht->dead;
- oldsz = ht->sz;
-
- ht->nelt = 0;
- ht->ndead = 0;
- ht->sz = sz;
- ht->keys = zalloc(sz * sizeof(void *));
- ht->vals = zalloc(sz * sizeof(void *));
- ht->hashes = zalloc(sz * sizeof(void *));
- ht->dead = zalloc(sz * sizeof(void *));
-
- for (i = 0; i < oldsz; i++)
- if (oldh[i] && !oldd[i])
- htput(ht, oldk[i], oldv[i]);
-
- free(oldh);
- free(oldk);
- free(oldv);
- free(oldd);
-}
-
-/* Inserts 'k' into the hash table, possibly
- * killing any previous key that compares
- * as equal. */
-int htput(Htab *ht, void *k, void *v)
-{
- int i;
- ulong h;
- int di;
-
- di = 0;
- h = hash(ht, k);
- i = h & (ht->sz - 1);
- while (ht->hashes[i] && !ht->dead[i]) {
- /* second insertion overwrites first. nb, we shouldn't touch the
- * keys for dead values */
- if (ht->hashes[i] == h) {
- if (ht->dead[i])
- break;
- else if (ht->cmp(ht->keys[i], k))
- goto conflicted;
- }
- di++;
- i = (h + di) & (ht->sz - 1);
- }
- ht->nelt++;
-conflicted:
- if (ht->dead[i])
- ht->ndead--;
- ht->hashes[i] = h;
- ht->keys[i] = k;
- ht->vals[i] = v;
- ht->dead[i] = 0;
-
- if (ht->sz < ht->nelt * 2)
- grow(ht, ht->sz * 2);
- if (ht->sz < ht->ndead * 4)
- grow(ht, ht->sz);
- return 1;
-}
-
-/* Finds the index that we would insert
- * the key into */
-static ssize_t htidx(Htab *ht, void *k)
-{
- ssize_t i;
- ulong h;
- int di;
-
- di = 0;
- h = hash(ht, k);
- i = h & (ht->sz - 1);
- while (ht->hashes[i] && !ht->dead[i] && ht->hashes[i] != h) {
-searchmore:
- di++;
- i = (h + di) & (ht->sz - 1);
- }
- if (!ht->hashes[i])
- return -1;
- if ((ht->hashes[i] == h && ht->dead[i]) || !ht->cmp(ht->keys[i], k))
- goto searchmore; /* collision */
- return i;
-}
-
-/* Looks up a key, returning NULL if
- * the value is not present. Note,
- * if NULL is a valid value, you need
- * to check with hthas() to see if it's
- * not there */
-void *htget(Htab *ht, void *k)
-{
- ssize_t i;
-
- i = htidx(ht, k);
- if (i < 0)
- return NULL;
- else
- return ht->vals[i];
-}
-
-void htdel(Htab *ht, void *k)
-{
- ssize_t i;
-
- i = htidx(ht, k);
- if (i < 0)
- return;
- assert(!ht->dead[i]);
- assert(ht->hashes[i]);
- ht->dead[i] = 1;
- ht->nelt--;
- ht->ndead++;
-}
-
-/* Tests for 'k's presence in 'ht' */
-int hthas(Htab *ht, void *k) { return htidx(ht, k) >= 0; }
-
-/* Returns a list of all keys in the hash
- * table, storing the size of the returned
- * array in 'nkeys'. NB: the value returned
- * is allocated on the heap, and it is the
- * job of the caller to free it */
-void **htkeys(Htab *ht, size_t *nkeys)
-{
- void **k;
- size_t i, j;
-
- j = 0;
- k = xalloc(sizeof(void *) * ht->nelt);
- for (i = 0; i < ht->sz; i++)
- if (ht->hashes[i] && !ht->dead[i])
- k[j++] = ht->keys[i];
- *nkeys = ht->nelt;
- return k;
-}
-
-ulong strhash(void *_s)
-{
- char *s;
- ulong h;
- ulong g;
-
- s = _s;
- h = 0;
- while (s && *s) {
- h = ((h << 4) + *s++);
-
- if ((g = (h & 0xF0000000)))
- h ^= (g >> 24);
-
- h &= ~g;
- }
- return h;
-}
-
-int streq(void *a, void *b)
-{
- if (a == b)
- return 1;
- if (a == NULL || b == NULL)
- return 0;
- return !strcmp(a, b);
-}
-
-ulong strlithash(void *_s)
-{
- Str *s;
- ulong h, g, i;
-
- s = _s;
- h = 0;
- for (i = 0; i < s->len; i++) {
- h = ((h << 4) + s->buf[i]);
-
- if ((g = (h & 0xF0000000)))
- h ^= (g >> 24);
-
- h &= ~g;
- }
- return h;
-}
-
-int strliteq(void *_a, void *_b)
-{
- Str *a, *b;
-
- a = _a;
- b = _b;
- if (a == b)
- return 1;
- if (a == NULL || b == NULL)
- return 0;
- if (a->len != b->len)
- return 0;
- return !memcmp(a, b, a->len);
-}
-
-ulong ptrhash(void *key) { return inthash((uintptr_t)key); }
-
-ulong inthash(uint64_t key)
-{
- uintptr_t h;
-
- h = (uintptr_t)key;
- h *= 357913941;
- h ^= h << 24;
- h += ~357913941;
- h ^= h >> 31;
- h ^= h << 31;
- return h;
-}
-
-int inteq(uint64_t a, uint64_t b) { return a == b; }
-
-int ptreq(void *a, void *b) { return a == b; }
--- a/parse/infer.c
+++ b/parse/infer.c
@@ -12,6 +12,7 @@
#include <unistd.h>
#include <assert.h>
+#include "util.h"
#include "parse.h"
typedef struct Inferstate Inferstate;
--- a/parse/names.c
+++ b/parse/names.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
char *opstr[] = {
--- a/parse/node.c
+++ b/parse/node.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
Node **nodes;
--- a/parse/parse.h
+++ b/parse/parse.h
@@ -1,23 +1,6 @@
-#ifdef __GNUC__
-#define FATAL __attribute__((noreturn))
-#else
-#define FATAL
-#endif
-
#define Abiversion 10
-typedef uint8_t byte;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-typedef long long vlong;
-typedef unsigned long long uvlong;
-
typedef struct Srcloc Srcloc;
-typedef struct Bitset Bitset;
-typedef struct Optctx Optctx;
-typedef struct Strbuf Strbuf;
-typedef struct Htab Htab;
-typedef struct Str Str;
typedef struct Tysubst Tysubst;
typedef struct Tok Tok;
@@ -71,22 +54,11 @@
#define Zloc ((Srcloc){-1, 0})
-struct Strbuf {
- char *buf;
- size_t sz;
- size_t len;
-};
-
struct Srcloc {
int line;
int file;
};
-struct Str {
- size_t len;
- char *buf;
-};
-
typedef enum {
Visintern,
Visexport,
@@ -99,23 +71,7 @@
Dclextern = 1 << 1,
} Dclflags;
-struct Bitset {
- size_t nchunks;
- size_t *chunks;
-};
-struct Htab {
- size_t nelt;
- size_t ndead;
- size_t sz;
- ulong (*hash)(void *k);
- int (*cmp)(void *a, void *b);
- void **keys;
- void **vals;
- ulong *hashes;
- char *dead;
-};
-
struct Tok {
int type;
Srcloc loc;
@@ -381,22 +337,6 @@
};
};
-struct Optctx {
- /* public exports */
- char *optarg;
- char **args;
- size_t nargs;
-
- /* internal state */
- char *optstr;
- char **optargs;
- size_t noptargs;
- size_t argidx;
- int optdone; /* seen -- */
- int finished;
- char *curarg;
-};
-
/* globals */
extern Srcloc curloc;
extern char *filename;
@@ -451,24 +391,9 @@
0;
}
-Htab *mkht(ulong (*hash)(void *key), int (*cmp)(void *k1, void *k2));
-void htfree(Htab *ht);
-int htput(Htab *ht, void *k, void *v);
-void htdel(Htab *ht, void *k);
-void *htget(Htab *ht, void *k);
-int hthas(Htab *ht, void *k);
-void **htkeys(Htab *ht, size_t *nkeys);
/* useful key types */
int liteq(Node *a, Node *b);
int litvaleq(Node *a, Node *b);
-ulong strhash(void *key);
-int streq(void *a, void *b);
-ulong strlithash(void *key);
-int strliteq(void *a, void *b);
-ulong ptrhash(void *key);
-int ptreq(void *a, void *b);
-ulong inthash(uint64_t key);
-int inteq(uint64_t a, uint64_t b);
ulong tyhash(void *t);
int tyeq(void *a, void *b);
ulong namehash(void *t);
@@ -476,27 +401,18 @@
ulong nsnamehash(void *t);
int nsnameeq(void *a, void *b);
-/* util functions */
+/* parsing etc */
+void tokinit(char *file);
+int yylex(void);
+int yyparse(void);
+
+/* locations */
char *fname(Srcloc l);
int lnum(Srcloc l);
-void *zalloc(size_t size);
-void *xalloc(size_t size);
-void *zrealloc(void *p, size_t oldsz, size_t size);
-void *xrealloc(void *p, size_t size);
-void die(char *msg, ...) FATAL;
void fatal(Node *n, char *fmt, ...) FATAL;
void lfatal(Srcloc l, char *fmt, ...) FATAL;
void lfatalv(Srcloc l, char *fmt, va_list ap) FATAL;
-char *strdupn(char *s, size_t len);
-char *strjoin(char *u, char *v);
-void *memdup(void *mem, size_t len);
-size_t bprintf(char *buf, size_t len, char *fmt, ...);
-/* parsing etc */
-void tokinit(char *file);
-int yylex(void);
-int yyparse(void);
-
/* stab creation */
Stab *mkstab(int isfunc);
@@ -665,47 +581,8 @@
void ldel(void *l, size_t *len, size_t idx);
void lfree(void *l, size_t *len);
-/* serializing/unserializing */
-void be64(vlong v, byte buf[8]);
-vlong host64(byte buf[8]);
-void be32(long v, byte buf[4]);
-long host32(byte buf[4]);
-static inline intptr_t ptoi(void *p) { return (intptr_t)p; }
-static inline void *itop(intptr_t i) { return (void *)i; }
-
-void wrbuf(FILE *fd, void *buf, size_t sz);
-void rdbuf(FILE *fd, void *buf, size_t sz);
-char rdbyte(FILE *fd);
-void wrbyte(FILE *fd, char val);
-char rdbyte(FILE *fd);
-void wrint(FILE *fd, long val);
-long rdint(FILE *fd);
-void wrstr(FILE *fd, char *val);
-char *rdstr(FILE *fd);
-void wrlenstr(FILE *fd, Str str);
-void rdlenstr(FILE *fd, Str *str);
-void wrflt(FILE *fd, double val);
-double rdflt(FILE *fd);
-void wrbool(FILE *fd, int val);
-int rdbool(FILE *fd);
-
-size_t max(size_t a, size_t b);
-size_t min(size_t a, size_t b);
-size_t align(size_t sz, size_t a);
-
-/* string buffer */
-Strbuf *mksb();
-char *sbfin(Strbuf *sb);
-void sbputs(Strbuf *sb, char *s);
-void sbputb(Strbuf *sb, char b);
-
/* suffix replacement */
char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap);
-
-/* indented printf */
-void indentf(int depth, char *fmt, ...);
-void findentf(FILE *fd, int depth, char *fmt, ...);
-void vfindentf(FILE *fd, int depth, char *fmt, va_list ap);
/* Options to control the compilation */
extern char debugopt[128];
--- a/parse/specialize.c
+++ b/parse/specialize.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
static Node *specializenode(Node *g, Tysubst *tsmap);
--- a/parse/stab.c
+++ b/parse/stab.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
/* Allows us to look up types/traits by name nodes */
--- a/parse/tok.c
+++ b/parse/tok.c
@@ -11,6 +11,7 @@
#include <errno.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
#include "gram.h"
--- a/parse/type.c
+++ b/parse/type.c
@@ -11,6 +11,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
typedef struct Typename Typename;
--- a/parse/use.c
+++ b/parse/use.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <unistd.h>
+#include "util.h"
#include "parse.h"
static void wrtype(FILE *fd, Type *val);
--- a/parse/util.c
+++ /dev/null
@@ -1,553 +1,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <inttypes.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-#include <assert.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "parse.h"
-
-/* malloc wrappers */
-void *zalloc(size_t sz)
-{
- void *mem;
-
- mem = calloc(1, sz);
- if (!mem && sz)
- die("Out of memory");
- return mem;
-}
-
-void *xalloc(size_t sz)
-{
- void *mem;
-
- mem = malloc(sz);
- if (!mem && sz)
- die("Out of memory");
- return mem;
-}
-
-void *zrealloc(void *mem, size_t oldsz, size_t sz)
-{
- char *p;
-
- p = xrealloc(mem, sz);
- if (sz > oldsz)
- memset(&p[oldsz], 0, sz - oldsz);
- return p;
-}
-
-void *xrealloc(void *mem, size_t sz)
-{
- mem = realloc(mem, sz);
- if (!mem && sz)
- die("Out of memory");
- return mem;
-}
-
-/* errors */
-void die(char *msg, ...)
-{
- va_list ap;
-
- va_start(ap, msg);
- vfprintf(stderr, msg, ap);
- fprintf(stderr, "\n");
- va_end(ap);
- abort();
-}
-
-void fatal(Node *n, char *msg, ...)
-{
- va_list ap;
-
- va_start(ap, msg);
- lfatalv(n->loc, msg, ap);
- va_end(ap);
-}
-
-void lfatal(Srcloc l, char *msg, ...)
-{
- va_list ap;
-
- va_start(ap, msg);
- lfatalv(l, msg, ap);
- va_end(ap);
-}
-
-void lfatalv(Srcloc l, char *msg, va_list ap)
-{
- fprintf(stdout, "%s:%d: ", fname(l), lnum(l));
- vfprintf(stdout, msg, ap);
- fprintf(stdout, "\n");
- exit(1);
-}
-
-/* Some systems don't have strndup. */
-char *strdupn(char *s, size_t len)
-{
- char *ret;
-
- ret = xalloc(len + 1);
- memcpy(ret, s, len);
- ret[len] = '\0';
- return ret;
-}
-
-char *strjoin(char *u, char *v)
-{
- size_t n;
- char *s;
-
- n = strlen(u) + strlen(v) + 1;
- s = xalloc(n);
- bprintf(s, n + 1, "%s%s", u, v);
- return s;
-}
-
-void *memdup(void *mem, size_t len)
-{
- void *ret;
-
- if (!mem)
- return NULL;
- ret = xalloc(len);
- return memcpy(ret, mem, len);
-}
-
-/* lists */
-void lappend(void *l, size_t *len, void *n)
-{
- void ***pl;
-
- pl = l;
- *pl = xrealloc(*pl, (*len + 1) * sizeof(void *));
- (*pl)[*len] = n;
- (*len)++;
-}
-
-void *lpop(void *l, size_t *len)
-{
- void ***pl;
- void *v;
-
- pl = l;
- (*len)--;
- v = (*pl)[*len];
- *pl = xrealloc(*pl, *len * sizeof(void *));
- return v;
-}
-
-void linsert(void *p, size_t *len, size_t idx, void *v)
-{
- void ***pl, **l;
-
- pl = p;
- *pl = xrealloc(*pl, (*len + 1) * sizeof(void *));
- l = *pl;
-
- memmove(&l[idx + 1], &l[idx], (*len - idx) * sizeof(void *));
- l[idx] = v;
- (*len)++;
-}
-
-void ldel(void *p, size_t *len, size_t idx)
-{
- void ***pl, **l;
-
- assert(p != NULL);
- assert(idx < *len);
- pl = p;
- l = *pl;
- memmove(&l[idx], &l[idx + 1], (*len - idx - 1) * sizeof(void *));
- (*len)--;
- *pl = xrealloc(l, *len * sizeof(void *));
-}
-
-void lcat(void *dst, size_t *ndst, void *src, size_t nsrc)
-{
- size_t i;
- void ***d, **s;
-
- d = dst;
- s = src;
- for (i = 0; i < nsrc; i++)
- lappend(d, ndst, s[i]);
-}
-
-void lfree(void *l, size_t *len)
-{
- void ***pl;
-
- assert(l != NULL);
- pl = l;
- free(*pl);
- *pl = NULL;
- *len = 0;
-}
-
-/* endian packing */
-void be64(vlong v, byte buf[8])
-{
- buf[0] = (v >> 56) & 0xff;
- buf[1] = (v >> 48) & 0xff;
- buf[2] = (v >> 40) & 0xff;
- buf[3] = (v >> 32) & 0xff;
- buf[4] = (v >> 24) & 0xff;
- buf[5] = (v >> 16) & 0xff;
- buf[6] = (v >> 8) & 0xff;
- buf[7] = (v >> 0) & 0xff;
-}
-
-vlong host64(byte buf[8])
-{
- vlong v = 0;
-
- v |= ((vlong)buf[0] << 56LL);
- v |= ((vlong)buf[1] << 48LL);
- v |= ((vlong)buf[2] << 40LL);
- v |= ((vlong)buf[3] << 32LL);
- v |= ((vlong)buf[4] << 24LL);
- v |= ((vlong)buf[5] << 16LL);
- v |= ((vlong)buf[6] << 8LL);
- v |= ((vlong)buf[7] << 0LL);
- return v;
-}
-
-void be32(long v, byte buf[4])
-{
- buf[0] = (v >> 24) & 0xff;
- buf[1] = (v >> 16) & 0xff;
- buf[2] = (v >> 8) & 0xff;
- buf[3] = (v >> 0) & 0xff;
-}
-
-long host32(byte buf[4])
-{
- int32_t v = 0;
- v |= ((long)buf[0] << 24);
- v |= ((long)buf[1] << 16);
- v |= ((long)buf[2] << 8);
- v |= ((long)buf[3] << 0);
- return v;
-}
-
-void wrbuf(FILE *fd, void *p, size_t sz)
-{
- size_t n;
- char *buf;
-
- n = 0;
- buf = p;
- while (n < sz) {
- n += fwrite(buf + n, 1, sz - n, fd);
- if (feof(fd))
- die("Unexpected EOF");
- if (ferror(fd))
- die("Error writing");
- }
-}
-
-void rdbuf(FILE *fd, void *buf, size_t sz)
-{
- size_t n;
-
- n = sz;
- while (n > 0) {
- n -= fread(buf, 1, n, fd);
- if (feof(fd))
- die("Unexpected EOF");
- if (ferror(fd))
- die("Error writing");
- }
-}
-
-void wrbyte(FILE *fd, char val)
-{
- if (fputc(val, fd) == EOF)
- die("Unexpected EOF");
-}
-
-char rdbyte(FILE *fd)
-{
- int c;
- c = fgetc(fd);
- if (c == EOF)
- die("Unexpected EOF");
- return c;
-}
-
-void wrint(FILE *fd, long val)
-{
- byte buf[4];
- be32(val, buf);
- wrbuf(fd, buf, 4);
-}
-
-long rdint(FILE *fd)
-{
- byte buf[4];
- rdbuf(fd, buf, 4);
- return host32(buf);
-}
-
-void wrstr(FILE *fd, char *val)
-{
- size_t len;
-
- if (!val) {
- wrint(fd, -1);
- } else {
- wrint(fd, strlen(val));
- len = strlen(val);
- wrbuf(fd, val, len);
- }
-}
-
-char *rdstr(FILE *fd)
-{
- ssize_t len;
- char *s;
-
- len = rdint(fd);
- if (len == -1) {
- return NULL;
- } else {
- s = xalloc(len + 1);
- rdbuf(fd, s, len);
- s[len] = '\0';
- return s;
- }
-}
-
-void wrlenstr(FILE *fd, Str str)
-{
- wrint(fd, str.len);
- wrbuf(fd, str.buf, str.len);
-}
-
-void rdlenstr(FILE *fd, Str *str)
-{
- str->len = rdint(fd);
- str->buf = xalloc(str->len + 1);
- rdbuf(fd, str->buf, str->len);
- str->buf[str->len] = '\0';
-}
-
-void wrflt(FILE *fd, double val)
-{
- byte buf[8];
- /* Assumption: We have 'val' in 64 bit IEEE format */
- union {
- uvlong ival;
- double fval;
- } u;
-
- u.fval = val;
- be64(u.ival, buf);
- wrbuf(fd, buf, 8);
-}
-
-double rdflt(FILE *fd)
-{
- byte buf[8];
- union {
- uvlong ival;
- double fval;
- } u;
-
- if (fread(buf, 8, 1, fd) < 8)
- die("Unexpected EOF");
- u.ival = host64(buf);
- return u.fval;
-}
-
-size_t bprintf(char *buf, size_t sz, char *fmt, ...)
-{
- va_list ap;
- size_t n;
-
- va_start(ap, fmt);
- n = vsnprintf(buf, sz, fmt, ap);
- if (n >= sz)
- n = sz;
- va_end(ap);
-
- return n;
-}
-
-void wrbool(FILE *fd, int val) { wrbyte(fd, val); }
-
-int rdbool(FILE *fd) { return rdbyte(fd); }
-
-char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap)
-{
- size_t slen, suflen, swaplen;
-
- slen = strlen(s);
- suflen = strlen(suf);
- swaplen = strlen(swap);
-
- if (slen < suflen)
- return NULL;
- if (slen + swaplen >= sz)
- die("swapsuffix: buf too small");
-
- buf[0] = '\0';
- /* if we have matching suffixes */
- if (suflen < slen && !strcmp(suf, &s[slen - suflen])) {
- strncat(buf, s, slen - suflen);
- strncat(buf, swap, swaplen);
- } else {
- bprintf(buf, sz, "%s%s", s, swap);
- }
-
- return buf;
-}
-
-size_t max(size_t a, size_t b)
-{
- if (a > b)
- return a;
- else
- return b;
-}
-
-size_t min(size_t a, size_t b)
-{
- if (a < b)
- return a;
- else
- return b;
-}
-
-size_t align(size_t sz, size_t a)
-{
- /* align to 0 just returns sz */
- if (a == 0)
- return sz;
- return (sz + a - 1) & ~(a - 1);
-}
-
-void indentf(int depth, char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfindentf(stdout, depth, fmt, ap);
- va_end(ap);
-}
-
-void findentf(FILE *fd, int depth, char *fmt, ...)
-{
- va_list ap;
- va_start(ap, fmt);
- vfindentf(fd, depth, fmt, ap);
- va_end(ap);
-}
-
-void vfindentf(FILE *fd, int depth, char *fmt, va_list ap)
-{
- ssize_t i;
-
- for (i = 0; i < depth; i++)
- fprintf(fd, "\t");
- vfprintf(fd, fmt, ap);
-}
-
-static int optinfo(Optctx *ctx, char arg, int *take, int *mand)
-{
- char *s;
-
- for (s = ctx->optstr; *s != '\0'; s++) {
- if (*s == arg) {
- s++;
- if (*s == ':') {
- *take = 1;
- *mand = 1;
- return 1;
- } else if (*s == '?') {
- *take = 1;
- *mand = 0;
- return 1;
- } else {
- *take = 0;
- *mand = 0;
- return 1;
- }
- }
- }
- return 0;
-}
-
-static int findnextopt(Optctx *ctx)
-{
- size_t i;
-
- for (i = ctx->argidx + 1; i < ctx->noptargs; i++) {
- if (ctx->optargs[i][0] == '-')
- goto foundopt;
- else
- lappend(&ctx->args, &ctx->nargs, ctx->optargs[i]);
- }
- ctx->finished = 1;
- return 0;
-foundopt:
- ctx->argidx = i;
- ctx->curarg = ctx->optargs[i] + 1; /* skip initial '-' */
- return 1;
-}
-
-void optinit(Optctx *ctx, char *optstr, char **optargs, size_t noptargs)
-{
- ctx->args = NULL;
- ctx->nargs = 0;
-
- ctx->optstr = optstr;
- ctx->optargs = optargs;
- ctx->noptargs = noptargs;
- ctx->optdone = 0;
- ctx->finished = 0;
- ctx->argidx = 0;
- ctx->curarg = "";
- findnextopt(ctx);
-}
-
-int optnext(Optctx *ctx)
-{
- int take, mand;
- int c;
-
- c = *ctx->curarg;
- ctx->curarg++;
- if (!optinfo(ctx, c, &take, &mand)) {
- printf("Unexpected argument %c\n", *ctx->curarg);
- exit(1);
- }
-
- ctx->optarg = NULL;
- if (take) {
- if (*ctx->curarg) {
- ctx->optarg = ctx->curarg;
- ctx->curarg += strlen(ctx->optarg);
- } else if (ctx->argidx < ctx->noptargs - 1) {
- ctx->optarg = ctx->optargs[ctx->argidx + 1];
- ctx->argidx++;
- } else if (mand) {
- fprintf(stderr, "expected argument for %c\n", *ctx->curarg);
- }
- findnextopt(ctx);
- } else {
- if (*ctx->curarg == '\0')
- findnextopt(ctx);
- }
- return c;
-}
-
-int optdone(Optctx *ctx) { return *ctx->curarg == '\0' && ctx->finished; }
--- /dev/null
+++ b/util/htab.c
@@ -1,0 +1,288 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
+#include "util.h"
+
+#define Initsz 16
+
+/* Creates a new empty hash table, using 'hash' as the
+ * hash funciton, and 'cmp' to verify that there are no
+ * hash collisions. */
+Htab *mkht(ulong (*hash)(void *key), int (*cmp)(void *k1, void *k2))
+{
+ Htab *ht;
+
+ ht = xalloc(sizeof(Htab));
+ ht->nelt = 0;
+ ht->ndead = 0;
+ ht->sz = Initsz;
+ ht->hash = hash;
+ ht->cmp = cmp;
+ ht->keys = zalloc(Initsz * sizeof(void *));
+ ht->vals = zalloc(Initsz * sizeof(void *));
+ ht->hashes = zalloc(Initsz * sizeof(void *));
+ ht->dead = zalloc(Initsz * sizeof(char));
+
+ return ht;
+}
+
+/* Frees a hash table. Passing this function
+ * NULL is a no-op. */
+void htfree(Htab *ht)
+{
+ if (!ht)
+ return;
+ free(ht->keys);
+ free(ht->vals);
+ free(ht->hashes);
+ free(ht->dead);
+ free(ht);
+}
+
+/* Offsets the hash so that '0' can be
+ * used as a 'no valid value */
+static ulong hash(Htab *ht, void *k)
+{
+ ulong h;
+ h = ht->hash(k);
+ if (h == 0)
+ return 1;
+ else
+ return h;
+}
+
+/* Resizes the hash table by copying all
+ * the old keys into the right slots in a
+ * new table. */
+static void grow(Htab *ht, int sz)
+{
+ void **oldk;
+ void **oldv;
+ ulong *oldh;
+ char *oldd;
+ int oldsz;
+ int i;
+
+ oldk = ht->keys;
+ oldv = ht->vals;
+ oldh = ht->hashes;
+ oldd = ht->dead;
+ oldsz = ht->sz;
+
+ ht->nelt = 0;
+ ht->ndead = 0;
+ ht->sz = sz;
+ ht->keys = zalloc(sz * sizeof(void *));
+ ht->vals = zalloc(sz * sizeof(void *));
+ ht->hashes = zalloc(sz * sizeof(void *));
+ ht->dead = zalloc(sz * sizeof(void *));
+
+ for (i = 0; i < oldsz; i++)
+ if (oldh[i] && !oldd[i])
+ htput(ht, oldk[i], oldv[i]);
+
+ free(oldh);
+ free(oldk);
+ free(oldv);
+ free(oldd);
+}
+
+/* Inserts 'k' into the hash table, possibly
+ * killing any previous key that compares
+ * as equal. */
+int htput(Htab *ht, void *k, void *v)
+{
+ int i;
+ ulong h;
+ int di;
+
+ di = 0;
+ h = hash(ht, k);
+ i = h & (ht->sz - 1);
+ while (ht->hashes[i] && !ht->dead[i]) {
+ /* second insertion overwrites first. nb, we shouldn't touch the
+ * keys for dead values */
+ if (ht->hashes[i] == h) {
+ if (ht->dead[i])
+ break;
+ else if (ht->cmp(ht->keys[i], k))
+ goto conflicted;
+ }
+ di++;
+ i = (h + di) & (ht->sz - 1);
+ }
+ ht->nelt++;
+conflicted:
+ if (ht->dead[i])
+ ht->ndead--;
+ ht->hashes[i] = h;
+ ht->keys[i] = k;
+ ht->vals[i] = v;
+ ht->dead[i] = 0;
+
+ if (ht->sz < ht->nelt * 2)
+ grow(ht, ht->sz * 2);
+ if (ht->sz < ht->ndead * 4)
+ grow(ht, ht->sz);
+ return 1;
+}
+
+/* Finds the index that we would insert
+ * the key into */
+static ssize_t htidx(Htab *ht, void *k)
+{
+ ssize_t i;
+ ulong h;
+ int di;
+
+ di = 0;
+ h = hash(ht, k);
+ i = h & (ht->sz - 1);
+ while (ht->hashes[i] && !ht->dead[i] && ht->hashes[i] != h) {
+searchmore:
+ di++;
+ i = (h + di) & (ht->sz - 1);
+ }
+ if (!ht->hashes[i])
+ return -1;
+ if ((ht->hashes[i] == h && ht->dead[i]) || !ht->cmp(ht->keys[i], k))
+ goto searchmore; /* collision */
+ return i;
+}
+
+/* Looks up a key, returning NULL if
+ * the value is not present. Note,
+ * if NULL is a valid value, you need
+ * to check with hthas() to see if it's
+ * not there */
+void *htget(Htab *ht, void *k)
+{
+ ssize_t i;
+
+ i = htidx(ht, k);
+ if (i < 0)
+ return NULL;
+ else
+ return ht->vals[i];
+}
+
+void htdel(Htab *ht, void *k)
+{
+ ssize_t i;
+
+ i = htidx(ht, k);
+ if (i < 0)
+ return;
+ assert(!ht->dead[i]);
+ assert(ht->hashes[i]);
+ ht->dead[i] = 1;
+ ht->nelt--;
+ ht->ndead++;
+}
+
+/* Tests for 'k's presence in 'ht' */
+int hthas(Htab *ht, void *k) { return htidx(ht, k) >= 0; }
+
+/* Returns a list of all keys in the hash
+ * table, storing the size of the returned
+ * array in 'nkeys'. NB: the value returned
+ * is allocated on the heap, and it is the
+ * job of the caller to free it */
+void **htkeys(Htab *ht, size_t *nkeys)
+{
+ void **k;
+ size_t i, j;
+
+ j = 0;
+ k = xalloc(sizeof(void *) * ht->nelt);
+ for (i = 0; i < ht->sz; i++)
+ if (ht->hashes[i] && !ht->dead[i])
+ k[j++] = ht->keys[i];
+ *nkeys = ht->nelt;
+ return k;
+}
+
+ulong strhash(void *_s)
+{
+ char *s;
+ ulong h;
+ ulong g;
+
+ s = _s;
+ h = 0;
+ while (s && *s) {
+ h = ((h << 4) + *s++);
+
+ if ((g = (h & 0xF0000000)))
+ h ^= (g >> 24);
+
+ h &= ~g;
+ }
+ return h;
+}
+
+int streq(void *a, void *b)
+{
+ if (a == b)
+ return 1;
+ if (a == NULL || b == NULL)
+ return 0;
+ return !strcmp(a, b);
+}
+
+ulong strlithash(void *_s)
+{
+ Str *s;
+ ulong h, g, i;
+
+ s = _s;
+ h = 0;
+ for (i = 0; i < s->len; i++) {
+ h = ((h << 4) + s->buf[i]);
+
+ if ((g = (h & 0xF0000000)))
+ h ^= (g >> 24);
+
+ h &= ~g;
+ }
+ return h;
+}
+
+int strliteq(void *_a, void *_b)
+{
+ Str *a, *b;
+
+ a = _a;
+ b = _b;
+ if (a == b)
+ return 1;
+ if (a == NULL || b == NULL)
+ return 0;
+ if (a->len != b->len)
+ return 0;
+ return !memcmp(a, b, a->len);
+}
+
+ulong ptrhash(void *key) { return inthash((uintptr_t)key); }
+
+ulong inthash(uint64_t key)
+{
+ uintptr_t h;
+
+ h = (uintptr_t)key;
+ h *= 357913941;
+ h ^= h << 24;
+ h += ~357913941;
+ h ^= h >> 31;
+ h ^= h << 31;
+ return h;
+}
+
+int inteq(uint64_t a, uint64_t b) { return a == b; }
+
+int ptreq(void *a, void *b) { return a == b; }
--- /dev/null
+++ b/util/util.c
@@ -1,0 +1,516 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "util.h"
+
+/* malloc wrappers */
+void *zalloc(size_t sz)
+{
+ void *mem;
+
+ mem = calloc(1, sz);
+ if (!mem && sz)
+ die("Out of memory");
+ return mem;
+}
+
+void *xalloc(size_t sz)
+{
+ void *mem;
+
+ mem = malloc(sz);
+ if (!mem && sz)
+ die("Out of memory");
+ return mem;
+}
+
+void *zrealloc(void *mem, size_t oldsz, size_t sz)
+{
+ char *p;
+
+ p = xrealloc(mem, sz);
+ if (sz > oldsz)
+ memset(&p[oldsz], 0, sz - oldsz);
+ return p;
+}
+
+void *xrealloc(void *mem, size_t sz)
+{
+ mem = realloc(mem, sz);
+ if (!mem && sz)
+ die("Out of memory");
+ return mem;
+}
+
+
+/* Some systems don't have strndup. */
+char *strdupn(char *s, size_t len)
+{
+ char *ret;
+
+ ret = xalloc(len + 1);
+ memcpy(ret, s, len);
+ ret[len] = '\0';
+ return ret;
+}
+
+char *strjoin(char *u, char *v)
+{
+ size_t n;
+ char *s;
+
+ n = strlen(u) + strlen(v) + 1;
+ s = xalloc(n);
+ bprintf(s, n + 1, "%s%s", u, v);
+ return s;
+}
+
+void *memdup(void *mem, size_t len)
+{
+ void *ret;
+
+ if (!mem)
+ return NULL;
+ ret = xalloc(len);
+ return memcpy(ret, mem, len);
+}
+
+/* lists */
+void lappend(void *l, size_t *len, void *n)
+{
+ void ***pl;
+
+ pl = l;
+ *pl = xrealloc(*pl, (*len + 1) * sizeof(void *));
+ (*pl)[*len] = n;
+ (*len)++;
+}
+
+void *lpop(void *l, size_t *len)
+{
+ void ***pl;
+ void *v;
+
+ pl = l;
+ (*len)--;
+ v = (*pl)[*len];
+ *pl = xrealloc(*pl, *len * sizeof(void *));
+ return v;
+}
+
+void linsert(void *p, size_t *len, size_t idx, void *v)
+{
+ void ***pl, **l;
+
+ pl = p;
+ *pl = xrealloc(*pl, (*len + 1) * sizeof(void *));
+ l = *pl;
+
+ memmove(&l[idx + 1], &l[idx], (*len - idx) * sizeof(void *));
+ l[idx] = v;
+ (*len)++;
+}
+
+void ldel(void *p, size_t *len, size_t idx)
+{
+ void ***pl, **l;
+
+ assert(p != NULL);
+ assert(idx < *len);
+ pl = p;
+ l = *pl;
+ memmove(&l[idx], &l[idx + 1], (*len - idx - 1) * sizeof(void *));
+ (*len)--;
+ *pl = xrealloc(l, *len * sizeof(void *));
+}
+
+void lcat(void *dst, size_t *ndst, void *src, size_t nsrc)
+{
+ size_t i;
+ void ***d, **s;
+
+ d = dst;
+ s = src;
+ for (i = 0; i < nsrc; i++)
+ lappend(d, ndst, s[i]);
+}
+
+void lfree(void *l, size_t *len)
+{
+ void ***pl;
+
+ assert(l != NULL);
+ pl = l;
+ free(*pl);
+ *pl = NULL;
+ *len = 0;
+}
+
+/* endian packing */
+void be64(vlong v, byte buf[8])
+{
+ buf[0] = (v >> 56) & 0xff;
+ buf[1] = (v >> 48) & 0xff;
+ buf[2] = (v >> 40) & 0xff;
+ buf[3] = (v >> 32) & 0xff;
+ buf[4] = (v >> 24) & 0xff;
+ buf[5] = (v >> 16) & 0xff;
+ buf[6] = (v >> 8) & 0xff;
+ buf[7] = (v >> 0) & 0xff;
+}
+
+vlong host64(byte buf[8])
+{
+ vlong v = 0;
+
+ v |= ((vlong)buf[0] << 56LL);
+ v |= ((vlong)buf[1] << 48LL);
+ v |= ((vlong)buf[2] << 40LL);
+ v |= ((vlong)buf[3] << 32LL);
+ v |= ((vlong)buf[4] << 24LL);
+ v |= ((vlong)buf[5] << 16LL);
+ v |= ((vlong)buf[6] << 8LL);
+ v |= ((vlong)buf[7] << 0LL);
+ return v;
+}
+
+void be32(long v, byte buf[4])
+{
+ buf[0] = (v >> 24) & 0xff;
+ buf[1] = (v >> 16) & 0xff;
+ buf[2] = (v >> 8) & 0xff;
+ buf[3] = (v >> 0) & 0xff;
+}
+
+long host32(byte buf[4])
+{
+ int32_t v = 0;
+ v |= ((long)buf[0] << 24);
+ v |= ((long)buf[1] << 16);
+ v |= ((long)buf[2] << 8);
+ v |= ((long)buf[3] << 0);
+ return v;
+}
+
+void wrbuf(FILE *fd, void *p, size_t sz)
+{
+ size_t n;
+ char *buf;
+
+ n = 0;
+ buf = p;
+ while (n < sz) {
+ n += fwrite(buf + n, 1, sz - n, fd);
+ if (feof(fd))
+ die("Unexpected EOF");
+ if (ferror(fd))
+ die("Error writing");
+ }
+}
+
+void rdbuf(FILE *fd, void *buf, size_t sz)
+{
+ size_t n;
+
+ n = sz;
+ while (n > 0) {
+ n -= fread(buf, 1, n, fd);
+ if (feof(fd))
+ die("Unexpected EOF");
+ if (ferror(fd))
+ die("Error writing");
+ }
+}
+
+void wrbyte(FILE *fd, char val)
+{
+ if (fputc(val, fd) == EOF)
+ die("Unexpected EOF");
+}
+
+char rdbyte(FILE *fd)
+{
+ int c;
+ c = fgetc(fd);
+ if (c == EOF)
+ die("Unexpected EOF");
+ return c;
+}
+
+void wrint(FILE *fd, long val)
+{
+ byte buf[4];
+ be32(val, buf);
+ wrbuf(fd, buf, 4);
+}
+
+long rdint(FILE *fd)
+{
+ byte buf[4];
+ rdbuf(fd, buf, 4);
+ return host32(buf);
+}
+
+void wrstr(FILE *fd, char *val)
+{
+ size_t len;
+
+ if (!val) {
+ wrint(fd, -1);
+ } else {
+ wrint(fd, strlen(val));
+ len = strlen(val);
+ wrbuf(fd, val, len);
+ }
+}
+
+char *rdstr(FILE *fd)
+{
+ ssize_t len;
+ char *s;
+
+ len = rdint(fd);
+ if (len == -1) {
+ return NULL;
+ } else {
+ s = xalloc(len + 1);
+ rdbuf(fd, s, len);
+ s[len] = '\0';
+ return s;
+ }
+}
+
+void wrlenstr(FILE *fd, Str str)
+{
+ wrint(fd, str.len);
+ wrbuf(fd, str.buf, str.len);
+}
+
+void rdlenstr(FILE *fd, Str *str)
+{
+ str->len = rdint(fd);
+ str->buf = xalloc(str->len + 1);
+ rdbuf(fd, str->buf, str->len);
+ str->buf[str->len] = '\0';
+}
+
+void wrflt(FILE *fd, double val)
+{
+ byte buf[8];
+ /* Assumption: We have 'val' in 64 bit IEEE format */
+ union {
+ uvlong ival;
+ double fval;
+ } u;
+
+ u.fval = val;
+ be64(u.ival, buf);
+ wrbuf(fd, buf, 8);
+}
+
+double rdflt(FILE *fd)
+{
+ byte buf[8];
+ union {
+ uvlong ival;
+ double fval;
+ } u;
+
+ if (fread(buf, 8, 1, fd) < 8)
+ die("Unexpected EOF");
+ u.ival = host64(buf);
+ return u.fval;
+}
+
+size_t bprintf(char *buf, size_t sz, char *fmt, ...)
+{
+ va_list ap;
+ size_t n;
+
+ va_start(ap, fmt);
+ n = vsnprintf(buf, sz, fmt, ap);
+ if (n >= sz)
+ n = sz;
+ va_end(ap);
+
+ return n;
+}
+
+void wrbool(FILE *fd, int val) { wrbyte(fd, val); }
+
+int rdbool(FILE *fd) { return rdbyte(fd); }
+
+char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap)
+{
+ size_t slen, suflen, swaplen;
+
+ slen = strlen(s);
+ suflen = strlen(suf);
+ swaplen = strlen(swap);
+
+ if (slen < suflen)
+ return NULL;
+ if (slen + swaplen >= sz)
+ die("swapsuffix: buf too small");
+
+ buf[0] = '\0';
+ /* if we have matching suffixes */
+ if (suflen < slen && !strcmp(suf, &s[slen - suflen])) {
+ strncat(buf, s, slen - suflen);
+ strncat(buf, swap, swaplen);
+ } else {
+ bprintf(buf, sz, "%s%s", s, swap);
+ }
+
+ return buf;
+}
+
+size_t max(size_t a, size_t b)
+{
+ if (a > b)
+ return a;
+ else
+ return b;
+}
+
+size_t min(size_t a, size_t b)
+{
+ if (a < b)
+ return a;
+ else
+ return b;
+}
+
+size_t align(size_t sz, size_t a)
+{
+ /* align to 0 just returns sz */
+ if (a == 0)
+ return sz;
+ return (sz + a - 1) & ~(a - 1);
+}
+
+void indentf(int depth, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfindentf(stdout, depth, fmt, ap);
+ va_end(ap);
+}
+
+void findentf(FILE *fd, int depth, char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vfindentf(fd, depth, fmt, ap);
+ va_end(ap);
+}
+
+void vfindentf(FILE *fd, int depth, char *fmt, va_list ap)
+{
+ ssize_t i;
+
+ for (i = 0; i < depth; i++)
+ fprintf(fd, "\t");
+ vfprintf(fd, fmt, ap);
+}
+
+static int optinfo(Optctx *ctx, char arg, int *take, int *mand)
+{
+ char *s;
+
+ for (s = ctx->optstr; *s != '\0'; s++) {
+ if (*s == arg) {
+ s++;
+ if (*s == ':') {
+ *take = 1;
+ *mand = 1;
+ return 1;
+ } else if (*s == '?') {
+ *take = 1;
+ *mand = 0;
+ return 1;
+ } else {
+ *take = 0;
+ *mand = 0;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static int findnextopt(Optctx *ctx)
+{
+ size_t i;
+
+ for (i = ctx->argidx + 1; i < ctx->noptargs; i++) {
+ if (ctx->optargs[i][0] == '-')
+ goto foundopt;
+ else
+ lappend(&ctx->args, &ctx->nargs, ctx->optargs[i]);
+ }
+ ctx->finished = 1;
+ return 0;
+foundopt:
+ ctx->argidx = i;
+ ctx->curarg = ctx->optargs[i] + 1; /* skip initial '-' */
+ return 1;
+}
+
+void optinit(Optctx *ctx, char *optstr, char **optargs, size_t noptargs)
+{
+ ctx->args = NULL;
+ ctx->nargs = 0;
+
+ ctx->optstr = optstr;
+ ctx->optargs = optargs;
+ ctx->noptargs = noptargs;
+ ctx->optdone = 0;
+ ctx->finished = 0;
+ ctx->argidx = 0;
+ ctx->curarg = "";
+ findnextopt(ctx);
+}
+
+int optnext(Optctx *ctx)
+{
+ int take, mand;
+ int c;
+
+ c = *ctx->curarg;
+ ctx->curarg++;
+ if (!optinfo(ctx, c, &take, &mand)) {
+ printf("Unexpected argument %c\n", *ctx->curarg);
+ exit(1);
+ }
+
+ ctx->optarg = NULL;
+ if (take) {
+ if (*ctx->curarg) {
+ ctx->optarg = ctx->curarg;
+ ctx->curarg += strlen(ctx->optarg);
+ } else if (ctx->argidx < ctx->noptargs - 1) {
+ ctx->optarg = ctx->optargs[ctx->argidx + 1];
+ ctx->argidx++;
+ } else if (mand) {
+ fprintf(stderr, "expected argument for %c\n", *ctx->curarg);
+ }
+ findnextopt(ctx);
+ } else {
+ if (*ctx->curarg == '\0')
+ findnextopt(ctx);
+ }
+ return c;
+}
+
+int optdone(Optctx *ctx) { return *ctx->curarg == '\0' && ctx->finished; }
--- /dev/null
+++ b/util/util.h
@@ -1,0 +1,129 @@
+#ifdef __GNUC__
+#define FATAL __attribute__((noreturn))
+#else
+#define FATAL
+#endif
+
+typedef uint8_t byte;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef long long vlong;
+typedef unsigned long long uvlong;
+
+typedef struct Htab Htab;
+typedef struct Bitset Bitset;
+typedef struct Optctx Optctx;
+typedef struct Str Str;
+typedef struct Strbuf Strbuf;
+
+struct Htab {
+ size_t nelt;
+ size_t ndead;
+ size_t sz;
+ ulong (*hash)(void *k);
+ int (*cmp)(void *a, void *b);
+ void **keys;
+ void **vals;
+ ulong *hashes;
+ char *dead;
+};
+
+struct Bitset {
+ size_t nchunks;
+ size_t *chunks;
+};
+
+struct Optctx {
+ /* public exports */
+ char *optarg;
+ char **args;
+ size_t nargs;
+
+ /* internal state */
+ char *optstr;
+ char **optargs;
+ size_t noptargs;
+ size_t argidx;
+ int optdone; /* seen -- */
+ int finished;
+ char *curarg;
+};
+
+struct Str {
+ size_t len;
+ char *buf;
+};
+
+struct Strbuf {
+ char *buf;
+ size_t sz;
+ size_t len;
+};
+
+/* string buffer */
+Strbuf *mksb();
+char *sbfin(Strbuf *sb);
+void sbputs(Strbuf *sb, char *s);
+void sbputb(Strbuf *sb, char b);
+
+/* hash tables */
+Htab *mkht(ulong (*hash)(void *key), int (*cmp)(void *k1, void *k2));
+void htfree(Htab *ht);
+int htput(Htab *ht, void *k, void *v);
+void htdel(Htab *ht, void *k);
+void *htget(Htab *ht, void *k);
+int hthas(Htab *ht, void *k);
+void **htkeys(Htab *ht, size_t *nkeys);
+ulong strhash(void *key);
+int streq(void *a, void *b);
+ulong strlithash(void *key);
+int strliteq(void *a, void *b);
+ulong ptrhash(void *key);
+int ptreq(void *a, void *b);
+ulong inthash(uint64_t key);
+int inteq(uint64_t a, uint64_t b);
+
+/* util functions */
+void *zalloc(size_t size);
+void *xalloc(size_t size);
+void *zrealloc(void *p, size_t oldsz, size_t size);
+void *xrealloc(void *p, size_t size);
+void die(char *msg, ...) FATAL;
+char *strdupn(char *s, size_t len);
+char *strjoin(char *u, char *v);
+void *memdup(void *mem, size_t len);
+size_t bprintf(char *buf, size_t len, char *fmt, ...);
+
+/* indented printf */
+void indentf(int depth, char *fmt, ...);
+void findentf(FILE *fd, int depth, char *fmt, ...);
+void vfindentf(FILE *fd, int depth, char *fmt, va_list ap);
+
+/* serializing/unserializing */
+void be64(vlong v, byte buf[8]);
+vlong host64(byte buf[8]);
+void be32(long v, byte buf[4]);
+long host32(byte buf[4]);
+static inline intptr_t ptoi(void *p) { return (intptr_t)p; }
+static inline void *itop(intptr_t i) { return (void *)i; }
+
+void wrbuf(FILE *fd, void *buf, size_t sz);
+void rdbuf(FILE *fd, void *buf, size_t sz);
+char rdbyte(FILE *fd);
+void wrbyte(FILE *fd, char val);
+char rdbyte(FILE *fd);
+void wrint(FILE *fd, long val);
+long rdint(FILE *fd);
+void wrstr(FILE *fd, char *val);
+char *rdstr(FILE *fd);
+void wrlenstr(FILE *fd, Str str);
+void rdlenstr(FILE *fd, Str *str);
+void wrflt(FILE *fd, double val);
+double rdflt(FILE *fd);
+void wrbool(FILE *fd, int val);
+int rdbool(FILE *fd);
+
+size_t max(size_t a, size_t b);
+size_t min(size_t a, size_t b);
+size_t align(size_t sz, size_t a);
+