Commits

Anonymous committed 6e683ed

bunch of changes, forgot I had a repo already

Comments (0)

Files changed (39)

anagrams/sortwords.c

 
 	setlocale(LC_ALL, "");
 	while ((wc = fgetwc(stdin)) != WEOF) {
-		fputwc(wc, stdout);
 		if (iswspace(wc)) {
+            fputwc(L' ', stdout);
 			qsort(word, (p - word) / 2, sizeof(wchar_t) * 2, wcscoll_cmp);
 			for (wchar_t *q = word; q < p; q += 2)
 				fputwc(*q, stdout);
 			fputwc(L'\n', stdout);
 			p = word;
 		} else {
+            fputwc(wc, stdout);
 			*p++ = wc;
 			*p++ = L'\0';
 		}

arrange_opts.bash

+arrange_opts() {
+    local flags args optstr=$1
+    shift
+
+    while (($#)); do
+        case $1 in
+            --) args+=("$@")
+                break;
+                ;;
+            -*) flags+=("$1")
+                if [[ $optstr == *"${1: -1}:"* ]]; then
+                    flags+=("$2")
+                    shift
+                fi
+                ;;
+            * ) args+=("$1")
+                ;;
+        esac
+        shift
+    done
+    OPTARR=("${flags[@]}" "${args[@]}")
+}
+
+example() {
+    local OPTIND optstring=ab:cd
+
+    printf 'before arrange:'
+    printf '<%s>' "$@"
+    echo
+
+    arrange_opts "$optstring" "$@"
+    set -- "${OPTARR[@]}"
+
+    printf 'after  arrange:'
+    printf '<%s>' "$@"
+    printf \\n\\n
+
+    printf flag:arg\\n
+
+    OPTIND=1
+    while getopts "$optstring" opt; do
+        case $opt in
+            a|c|d) printf        %s\\n "$opt"    ;;
+            b    ) printf      b:%s\\n "$OPTARG" ;;
+            \?   ) printf badopt:%s\\n "$OPTARG" ;;
+            :    ) printf  noarg:%s\\n "$OPTARG" ;;
+            *    ) printf    wtf:%s\\n "$opt"    ;;
+        esac
+    done
+    shift $((OPTIND-1))
+
+    printf \\nargs:
+    printf '<%s>' "$@"
+    echo
+}
+
+example -ad foo -b bar baz
+++++[>++++++<-]>[>+++++>+++++++<<-]>>++++<[[>[[>>+<<-]<]>>>-]>-[>+>+<<-]>]
++++++[>+++++++<<++>-]>.<<.
+[]++++++++++[>>+>+>++++++[<<+<+++>>>-]<<<<-]
+"A*$";?@![#>>+<<]>[>>]<<<<[>++<[-]]>.>.
 # notes: mktemp -d because --suffix isn't portable
 #        seems that gnu sed doesn't get rid of multibyte characters with that first line
 #        1s/// and $s/// instead of 1i and $a as some seds expect \<newline> following i and a
-#        could add #include <stdio.h> but gcc doesn't seem to mind...
 #        int main instead of void main so we get an exit status of 0
 
 d="$(mktemp -d)" || exit 1
 	exit 1
 fi
 
-stop=-1 prog=() ni=0 bfm=() p=0 input=""
+stop=-1 prog=() ni=0 bfm=() p=0
 read_script "$1" && run_script
+>,[
+    [
+        ----------[
+            >>>[>>>>]+[[-]+<[->>>>++>>>>+[>>>>]++[->+<<<<<]]<<<]
+            ++++++[>------<-]>--[>>[->>>>]+>+[<<<<]>-],<
+        ]>
+    ]>>>++>+>>[
+        <<[>>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<<]]<[>+<-]>]
+        >[>[>>>>]+[[-]<[+[->>>>]>+<]>[<+>[<<<<]]+<<<<]>>>[->>>>]+>+[<<<<]]
+        >[[>+>>[<<<<+>>>>-]>]<<<<[-]>[-<<<<]]>>>>>>>
+    ]>>+[[-]++++++>>>>]<<<<[[<++++++++>-]<.[-]<[-]<[-]<]<,
+]
+>,>+++++++++,>+++++++++++[<++++++<++++++<+>>>-]<<.>.<<-.>.>.<<.
+++++++++++[>+++++++>++++++++++>+++>+<<<<-]>++.>+.+++++++..+++.>++.<<+++++++++++++++.>.+++.------.--------.>+.>.
+99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
+++++++[>++++++++<-]>+.---.>>>+>>+>++>+>+>+>>+>+++>
++>>+>+>+>>+>>>>+>>>>+>++>>>>+>+<[[>>>]<<<[>>>>>>>>
+>+<<<<<<<<[>>>>>>>>>+<<<<<<<<<-]<-<<<]>>>>>>+>>>+[
+<<<]<<<<<[>>>+<<[>>>+<<<-]<-<<<]>>>+<<<<<<<<[<<]>>
+>>[->[<<<+>>>>[>>]>+<<<[<<]>-]<<<-[>>>+<<<-]+>>>>[
+>>]+>[-[-[-<->>>>>>[[>>>]>>]<<<<<[>+<-<<<]<<[<<<]>
+>>[->>>[>>>]>>[>>>]+[<<<]<<[<<<]+>>>]>>>[<[-]+>->>
+>]<[>>>]<<<[>+++++++++<<<<]<<[<<<]>>>[->[<<+>+>-]<
+[>+<-]>[>>[>>>]>>>>[>>>]<-<<[<<<]<<<<[<<<]>-]>>[>>
+>]>>>>[>>>]+[<<<]<<<<[<<<]<[>>+<<-]>+>>>]>>>>[->>>
+]<<[>>>]<<<[>[-[-[-[-[-[-[-[-[-<->[<+>[-]>+<]]]]]]
+]]]]<[[>>[<<<+>>>-]<[-]<-<<<]>>>]<<<]>+>[-<-<<<[[<
+<<]<<]<<<[<<]+>>->>[>>]>>>>>>>-<[[>>>]>>]<]<[-<<<[
+[<<<]<<]<<<[<<]+[<<]>>->>[>>]>>>>>>[[>>>]>>]<<]<<<
+[[<<<]<<]]<[->>>>>>>+[<<+>+>-]<-[>+<-]+<[-[-[-[-[-
+[-[-[-[-[->>-<<<<<<<<<[<<]+>>>>>>>>->>[>>]>>>>>]]]
+]]]]]]]<<<<<]>]<[->>>>>>>[<<<+>+>>-]<<[>>+<<-]+<[>
+-<[>>[>>>]>>[>>>]>>[>>>]<<<[-<<<]<<[<<<]<<[<<<]>>>
+[->[<<+>+>-]<[>+<-]<[>>>>[>>>]>>[>>>]>>[>>>]>++<<<
+<[<<<]<<[<<<]<<[<<<]<-]>>>>[>>>]>>[>>>]>>[>>>]+[<<
+<]<<[<<<]<<[<<<]+>>>]<<<[<<<]>-]>>[>>>]>>[>>>]>>[-
+>[<+>>+<-]<[[<+>>+<-]<[>+<-]>->-[<->-[<->-[<->-[<-
+>-[<->-[<->-[<->-[<->-[<->[-]>---------->[-]+>+<<<
+]]]]]]]]]<]+>>[<+>-]>]<<<[[<<<]<<]>>>>>>[<<+>>>+<-
+]>[<+>-]<<<[>[[>>>]>>]<+<<<<[[<<<]<<]>>>>-]>[[>>>]
+>>]>+<<-[>+<-]>[>+++<-[>+++++<-[>--->>+>+<<<<-[>->
+>>+<<<<-[>+>>>+<<<<-[>+++>>>+<<<<-[>----->>>++<<<<
+-[>--->>>++<<<<-]]]]]]]]+[[<<<]<<]>>>]>[->[[>>>]>>
+]+>>>>>+[[<<<]<<]>>>>]<<<<<]>]<[->>>>>>[[>>>]>>]<<
+<<<[<<<]>>>[-<<<[<<<]<<[<<<]>>[>>>]+>[>>>]>>[>>>]>
+[<<<<[<<<]<<[<<<]>>[>>>]<<<+>[>>>]>>[>>>]>-]<+>>>]
+<<<[-<<<]<<[<<<]>>[->>>]<<[<<<]>>>[++++++++<[>-<-]
+>[>+<-]+>>>]<<<[<<<]>>>>+<[->[<<+>+>-]<[-[-[-[-[-[
+-[-[-[-[<---------->>>>[-]+>+<<<<[-]]]]]]]]]]]<[>>
++<<-]>+>>>]<<[-<]<<[<<<]>>>->[<<+>>-]>>[>>>]<<<[>>
++<[>-<<[<<<]>]>[-<<-<]<<]+<[>>+<<-]>[[<<<]<<]<]<<[
+<<]+>>]>+>[>+++++[>++>++<<-]<-]>>>>>[<<<+>+>+>-]<-
+[>+<-]+<<[<[<+>-]<<[>>+<<-]>[<+>-]>>-]<<<[-]>>[<+>
+>>-<<-]++++++[>++++++++<-]>>[<+>--]<.[-]>>[>>>]>>]
+  ++++++++++>>>+[[+++++[<++++++++>-]<.>++++++
+  [<-------->-]+>>]<<[<<]<.>>>[->>[>>]+<<[<[>
+  >+<<-]<]>+<<[->>-<+<]>[-<+>]+>>>>]<<[<<]>>]
+,
+[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
+[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
+[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
+[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
+[>++++++++++++++<-
+[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
+[>>+++++[<----->-]<<-
+[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
+[>++++++++++++++<-
+[>+<-[>+<-[>+<-[>+<-[>+<-
+[>++++++++++++++<-
+[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
+[>>+++++[<----->-]<<-
+[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-[>+<-
+[>++++++++++++++<-
+[>+<-]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]
+]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]>.[-]<,]
+
+++++[>+++++<-]>[<+++++>-]+<+[
+    >[>+>+<<-]++>>[<<+>>-]>>>[-]++>[-]+
+    >>>+[[-]++++++>>>]<<<[[<++++++++<++>>-]+<.<[>----<-]<]
+    <<[>>>>>[>>>[-]+++++++++<[>-<-]+++++++++>[-[<->-]+[<<<]]<[>+<-]>]<<-]<<-
+]

c++/find_if_member_function_boost_bind.cpp

+#include <algorithm>
+#include <iostream>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include <boost/bind.hpp>
+
+class Sim {
+public:
+    Sim(std::string aName) : mName(aName) {}
+    std::string getName() const { return mName; }
+
+private:
+    std::string mName;
+};
+
+std::ostream& operator<<(std::ostream &os, const Sim &aSim) {
+    os << aSim.getName();
+    return os;
+}
+
+class Acc {
+public:
+    Acc(std::vector<Sim> aSims) : mSims(aSims) {}
+    void addSim(Sim aSim) {
+        std::vector<Sim>::iterator it = std::find_if(mSims.begin(), mSims.end(), boost::bind(&Sim::getName, _1) == aSim.getName());
+        if (it == mSims.end()) std::cout << "end" << std::endl;
+        else                   std::cout << *it   << std::endl;
+        mSims.push_back(aSim);
+    }
+    void print() const {
+        std::copy(mSims.begin(), mSims.end(), std::ostream_iterator<Sim>(std::cout, ","));
+        std::cout << std::endl;
+    }
+
+private:
+    std::vector<Sim> mSims;
+};
+
+int main()
+{
+    std::vector<Sim> sims;
+    sims.push_back(Sim("foo")); sims.push_back(Sim("bar")); sims.push_back(Sim("baz"));
+
+    Acc acc(sims);
+    acc.print();
+    acc.addSim(Sim("bar"));
+    acc.print();
+    return 0;
+}

c++/for_each_member_function_boost_bind.cpp

+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+#include <boost/bind.hpp>
+
+class D {
+public:
+    D(const std::vector<int> &v)
+    {
+        std::for_each(v.begin(), v.end(), boost::bind(&D::print, this, _1));
+    }
+
+    void print(int i)
+    {
+        std::cout << i << std::endl;
+    }
+};
+
+int main()
+{
+    std::vector<int> v;
+    v.push_back(1); v.push_back(2); v.push_back(3);
+
+    D d(v);
+
+    return 0;
+}
+dedup() {
+    (($#)) || return 1
+
+    local    arg
+    local -A set
+
+    for arg; do
+        set["$arg"]=1
+    done
+    printf "%s\0" "${!set[@]}"
+}
+
+dedup_to_array() {
+    (($# > 1)) || return 1
+
+    local arr=$1 element i
+    shift
+
+    unset "$arr"
+    while IFS= read -rd '' element; do
+        printf -v "$arr[i++]" %s "$element"
+    done < <(dedup "$@")
+}
+
+example() {
+    # our test array
+    myarr=(foo bar baz qux foo 'two words' bonzai baz 'two words' baz bar)
+
+    dedup_to_array myarr "${myarr[@]}"
+
+    # print the new array
+    printf '<%s>' "${myarr[@]}"
+    echo
+}
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+#define MAX_ERRNO   132
+
+int main(int argc, char **argv)
+{
+    int   i;
+    char *s;
+
+    if (argc > 1)
+        while (*++argv)
+            printf("%d: %s\n", atoi(*argv), strerror(atoi(*argv)));
+    else
+        for (i = errno = 0; i <= MAX_ERRNO && (s = strerror(i)) && !errno; i++)
+            printf("%d: %s\n", i, s);
+
+    return 0;
+}

fb/raytrace.c

-#include <fcntl.h>
-#include <math.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <linux/fb.h>
-
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#define SWAP(a, b, t) do{ (t) = (a); (a) = (b); (b) = (t); }while(0)
-#define BLACK      (Color){ .val = 0x00000000 }
-#define FAR_PLANE  100.
-#define NEAR_PLANE   1.1
-#define M_PI         3.14159265358979323846
-
-// TODO: fix for endianness
-typedef union {
-    uint32_t val;
-    struct {
-        uint8_t b, g, r, t;
-    };
-} Color;
-
-typedef struct {
-    double x, y, z;
-} Point;
-
-typedef Point Vector;
-
-typedef struct {
-    Point  origin;
-    Vector direction;
-    double tmin;
-    double tmax;
-} Ray;
-
-typedef struct {
-    Point  center;
-    Vector normal;
-} Plane;
-
-typedef struct {
-    Point  center;
-    double radius;
-} Sphere;
-
-typedef struct {
-    Point  center;
-    Vector normal;
-    double radius;
-} Disk;
-
-typedef union {
-    Sphere sphere;
-    Plane  plane;
-    Disk   disk;
-} Shape;
-
-typedef struct {
-    Shape shape;
-    Color color;
-    int (*intersect)(Shape, Ray*);
-} Object;
-
-typedef struct {
-    Point position;
-} Light;
-
-typedef struct {
-    Color *buf;
-    int xres;
-    int yres;
-    double fov; // radians
-    Point  position;
-    Vector direction;
-} Camera;
-
-double dot            (Vector a, Vector b) { return a.x * b.x + a.y * b.y + a.z * b.z;                  }
-double magnitude      (Vector a)           { return sqrt(dot(a, a));                                    }
-Vector scalar_multiply(double s, Vector a) { return (Vector){ a.x * s  , a.y * s  , a.z * s   };        }
-Vector add            (Vector a, Vector b) { return (Vector){ a.x + b.x, a.y + b.y, a.z + b.z };        }
-Vector normalize      (Vector a) { double m; return (m = magnitude(a)) ? scalar_multiply(1 / m, a) : a; }
-
-double radians(double degrees)
-{
-    return degrees * M_PI / 180;
-}
-
-Ray new_primary_ray(Camera c, int x, int y)
-{
-    double aspect_ratio = (double)c.xres / c.yres;
-    double t = tan(c.fov / 2);
-    Vector pixel;
-
-    pixel.x = (-1 + 2 * (x + 0.5) / c.xres) * t * aspect_ratio;
-    pixel.y = ( 1 - 2 * (y + 0.5) / c.yres) * t;
-    pixel.z =   1;
-    pixel = normalize(pixel);
-
-    //TODO: transform pixel to camera coordinates
-    return (Ray){ c.position, pixel, NEAR_PLANE, FAR_PLANE };
-}
-
-int qroots(double a, double b, double c, double *r1, double *r2)
-{
-    double q, d = b * b - 4 * a * c;
-
-    if (d <  0) return 0;
-    if (d == 0) {
-        *r1 = *r2 = -0.5 * b / a;
-        return 1;
-    }
-    q = (b > 0) ? -0.5 * (b + sqrt(d)) : -0.5 * (b - sqrt(d));
-    *r1 = q / a;
-    *r2 = c / q;
-
-    if (*r1 > *r2)
-        SWAP(*r1, *r2, q);
-    return 2;
-}
-
-int intersect_sphere(Shape s, Ray *r)
-{
-    double t0, t1;
-    Vector ro = add(r->origin, scalar_multiply(-1, s.sphere.center));
-    double a  = 1; // direction is normalized. if not: a = dot(r->direction, r->direction);
-    double b  = dot(r->direction, ro) * 2;
-    double c  = dot(ro, ro) - s.sphere.radius * s.sphere.radius;
-
-    if (!qroots(a, b, c, &t0, &t1))       return 0;
-    if (t0 > r->tmax || t0 < r->tmin) return 0;
-    r->tmax = t0;
-    return 1;
-}
-
-int intersect_plane(Shape p, Ray *r)
-{
-    double d = dot(p.plane.normal, r->direction);
-    Vector v = add(p.plane.center, scalar_multiply(-1, r->origin));
-
-    if (fabs(d) < 1E-6) return 0;
-    d = dot(v, p.plane.normal) / d;
-    if (d < r->tmin || d > r->tmax) return 0;
-    r->tmax = d;
-    return 1;
-}
-
-int intersect_disk(Shape d, Ray *r)
-{
-    Ray t = *r;
-
-    if (!intersect_plane((Shape){ .plane = { d.disk.center, d.disk.normal } }, &t)) return 0;
-
-    Point  p = add(t.origin, scalar_multiply(t.tmax, t.direction));
-    Vector v = add(p, scalar_multiply(-1, d.disk.center));
-    if (dot(v, v) > d.disk.radius * d.disk.radius) return 0;
-    r->tmax = t.tmax;
-    return 1;
-}
-
-Color trace(Ray r, Object *o, Light *l, Color bg, int depth)
-{
-    Object *p, *hit = NULL;
-    Light  *i;
-
-    for (p = o; p->intersect; p++)
-        if (p->intersect(p->shape, &r))
-            hit = p;
-
-    if (!hit) return bg;
-
-    // TODO: add light intensity (perhaps color)
-    // TODO: fix hitting self problem (moving towards light by 0.000001 * distance is ugly)
-    for (i = l; dot(i->position, i->position); i++) {
-        Point  intersect = add(r.origin, scalar_multiply(r.tmax, r.direction));
-        Vector delta     = add(i->position, scalar_multiply(-1, intersect));
-        Ray    shadow    = { add(intersect, scalar_multiply(0.000001, delta)), normalize(delta), 0, magnitude(delta) };
-
-        for (p = o; p->intersect; p++)
-            if (p->intersect(p->shape, &shadow))
-                break; // no light from this source
-
-        if (p->intersect)
-            continue;
-
-        return hit->color;
-    }
-    return BLACK;
-}
-
-void render(Camera c, Object *o, Light *l, Color bg)
-{
-    int x, y;
-    Object *hit;
-
-    for (y = 0; y < c.yres; y++)
-        for (x = 0; x < c.xres; x++)
-            *(c.buf + y * c.xres + x) = trace(new_primary_ray(c, x, y), o, l, bg, 5);
-}
-
-int main(void)
-{
-    Camera c = { NULL, 0, 0, radians(90), { 0 }, { 0, 0, 1 } };
-    Object objects[] = {
-        { { .sphere = { {   0,   0, 10 },                   2                   } }, { .val = 0x000000ffUL }, intersect_sphere },
-        { { .sphere = { {   1,   1,  9 },                   1.5                 } }, { .val = 0x0000ff00UL }, intersect_sphere },
-        { { .plane  = { {   0,   0, 20 },                   {  0,  0, -1 }      } }, { .val = 0x0000ffffUL }, intersect_plane  },
-        { { .plane  = { { -10,   0,  0 },                   {  1,  0,  0 }      } }, { .val = 0x00ff0000UL }, intersect_plane  },
-        { { .plane  = { {  10,   0,  0 },                   { -1,  0,  0 }      } }, { .val = 0x00ffff00UL }, intersect_plane  },
-        { { .plane  = { {   0,  10,  0 },                   {  0, -1,  0 }      } }, { .val = 0x00ffffffUL }, intersect_plane  },
-        { { .plane  = { {   0, -10,  0 },                   {  0,  1,  0 }      } }, { .val = 0x00ffffffUL }, intersect_plane  },
-        { { .disk   = { {  -5,  -7, 10 }, normalize((Vector){ .5, .5,  1 }),  1 } }, { .val = 0x00ff00ffUL }, intersect_disk   },
-        { { .disk   = { {  -1,  -1,  8 }, normalize((Vector){ -1,  0, .5 }), .4 } }, { .val = 0x00ff00ffUL }, intersect_disk   },
-        { 0 }
-    };
-    Light lights[] = {
-        { { -5, 0, 7 } },
-        //{ {  0, 0, 15} },
-        { 0 }
-    };
-
-    int fd;
-    uint8_t *fbm;
-    struct fb_var_screeninfo vi;
-    struct fb_fix_screeninfo fi;
-
-    if ((fd = open("/dev/fb0", O_RDWR))     < 0) return 1;
-    if (ioctl(fd, FBIOGET_FSCREENINFO, &fi) < 0) return 2;
-    if (ioctl(fd, FBIOGET_VSCREENINFO, &vi) < 0) return 3;
-    if (vi.bits_per_pixel != 32)                 return 4;
-    if ((c.buf = mmap(NULL, vi.xres * vi.yres * sizeof(Color), PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0)) == MAP_FAILED) {
-        perror("mmap failed");
-        return 5;
-    }
-    c.xres = vi.xres;
-    c.yres = vi.yres;
-
-    render(c, objects, lights, (Color){ .val = 0x00ffffff });
-
-    munmap(c.buf, c.xres * c.yres * sizeof(Color));
-    close(fd);
-
-    return 0;
-}
 done
 shift $((OPTIND-1))
 
-pm() { case "$1" in $2) return 0;; esac; return 1; }
+pm() { case $1 in $2) return 0;; esac; return 1; }
 num() {
     if                     ! pm "$1"      "*[![:digit:]]*" ; then return 0; fi
     if pm "$1" "0[xX]*" && ! pm "${1#??}" "*[![:xdigit:]]*"; then return 0; fi
 #include <stdio.h>
-//void swap(char **p, char **q) { if (*p == *q) return; char *t = *p; *p = *q; *q = t; }
 void swap(char **p, char **q) { char *t = *p; *p = *q; *q = t; }
 void perm(char **s, char **p) {
 	if (*p) for (char **q = p; *q; q++) swap(p, q), perm(s, p + 1), swap(p, q);
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#define RAND_PATH "/dev/urandom"
+#define BAIL() do { status = -1; goto cleanup; } while (0)
+
+char *prog;
+
+// Random number generation from
+// http://www0.cs.ucl.ac.uk/staff/d.jones/GoodPracticeRNG.pdf
+uint32_t s[4]; // Seed
+uint32_t rand32(void)
+{
+    uint64_t t;
+    //uint32_t r;
+    s[0] = 314527869 * s[0] + 1234567;
+    s[1] ^= s[1] << 5; s[1] ^= s[1] >> 7; s[1] ^= s[1] << 22;
+    t = 4294584393ULL * s[2] + s[3]; s[3] = t >> 32; s[2] = t;
+    return s[0] + s[1] + s[2];
+}
+
+int srand32(void)
+{
+    int status = 0, e = 0, fd;
+    if (0 > (fd = open(RAND_PATH, O_RDONLY))) BAIL();
+    if (sizeof(s) != read(fd, s, sizeof(s)))  BAIL();
+
+cleanup:
+    e = errno;
+    if (fd > 0 && close(fd) < 0) perror(prog);
+    errno = e;
+    return status;
+}
+
+uint64_t s2[2];
+uint32_t s3[4];
+uint64_t rand64(void)
+{
+    uint64_t t;
+    s2[0] = 1490024343005336237ULL * s2[0] + 123456789;
+    s2[1] ^= s2[1] << 21; s2[1] ^= s2[1] >> 17; s2[1] ^= s2[1] << 30;
+    t = 4294584393ULL * s3[0] + s3[1]; s3[1] = t >> 32; s3[0] = t;
+    t = 4246477509ULL * s3[2] + s3[3]; s3[3] = t >> 32; s3[2] = t;
+
+    return s2[0] + s2[1] + s3[0] + ((uint64_t)s3[2] << 32);
+}
+
+int srand64(void)
+{
+    int status = 0, e = 0, fd;
+    if (0 > (fd = open(RAND_PATH, O_RDONLY))) BAIL();
+    if (sizeof(s2) != read(fd, s2, sizeof(s2)))  BAIL();
+    if (sizeof(s3) != read(fd, s3, sizeof(s3)))  BAIL();
+
+cleanup:
+    e = errno;
+    if (fd > 0 && close(fd) < 0) perror(prog);
+    errno = e;
+    return status;
+}
+
+int main(int argc, char **argv)
+{
+    prog = *argv;
+
+    if (srand32()) return 1;
+
+    uint32_t r[1024], *p;
+    do for (p = r; r + sizeof(r)/sizeof(*r) - p; *(p++) = rand32());
+    while (write(1, r, sizeof(r)) == sizeof(r));
+
+    /*
+    if (srand64()) return 1;
+
+    uint64_t r[4096], *p;
+    do for (p = r; r + sizeof(r)/sizeof(*r) - p; *(p++) = rand64());
+    while (write(1, r, sizeof(r)) == sizeof(r));
+    */
+
+    perror("");
+    return 0;
+}
+#!/bin/sh
+
+usage() {
+cat >&2 << DOG
+Usage: rand_lines n [file...]
+Print n lines chosen at random. Lines are not shuffled.
+
+n       The number of lines to choose
+file... Files from which to choose lines
+        If no files are given, stdin is read
+DOG
+exit 1
+}
+
+pm() { case $1 in $2) return 0;; esac; return 1; }
+
+
+[ "$#" -gt 0 ]           || usage
+pm "$1" '*[![:digit:]]*' && usage
+
+num_lines=$1
+shift
+
+# FIXME: need to get a good seed for srand()
+awk -vn="$num_lines" '
+BEGIN            { srand()                           }
+NR     <= n      { lines[NR - 1         ] = $0; next }
+rand() <  n / NR { lines[int(rand() * n)] = $0;      }
+END              { for (k in lines) print lines[k]   }
+' "$@"
     return status;
 }
 
-// Starting at *file, read n lines ending widht eolbyte or up to *len bytes and
+// Starting at *file, read n lines ending with eolbyte or up to *len bytes and
 // store Lines in array at lines. If last line has no eolbyte, ignore it.
 // Update *file and *len accordingly.
+// Return number of lines read.
 int read_lines(char eolbyte, size_t n, Line *lines, char **file, off_t *len)
 {
     size_t i = n;

raytrace/raytrace.c

 #include <sys/stat.h>
 
 #define SWAP(a, b, t) do{ (t) = (a); (a) = (b); (b) = (t); }while(0)
-#define BLACK      (Color){ 0, 0, 0 }
-#define M_PI         3.14159265358979323846
+#define BLACK         (Color){ 0, 0, 0 }
+#define M_PI          3.14159265358979323846
 
 typedef struct {
     double x, y, z;
 
     return 0;
 }
-
 #include <unistd.h>
 #define x(s,d,...)if(s){o=errno;fputs(*v,stderr);fprintf(stderr,": "__VA_ARGS__\
 );errno=o;perror(0);d;}
-#define s(r,s,d,...)while((r=s)<0&&errno==EINTR);x(r<0,d,__VA_ARGS__)
+#define l while
+#define s(r,s,d,...)l((r=s)<0&&errno==EINTR);x(r<0,d,__VA_ARGS__)
 #define z " %s: ",(c>1?v[i]:"stdin")
-#define l s(w,close(f),,"close"z)
 #define w(c)s(w,write(1,c,1),,"write: ")
 int main(int c,char**v){int o,r,f,i=1,w,n;f=n=0;char*b,*e,*p,*q;b=e=p=0;do{if(c>
 1){s(f,open(v[i],O_RDONLY),n=1;continue,"cannot open %s: ",v[i])}do{do{if(p==e){
-q=p=b;b=realloc(b,(e-p)*2+1);x(!b,{free(q);l return 1;},"realloc: ")p=e-p+b;e=b+
-(p-b)*2+1;}s(r,read(f,p,1),n=1,"read"z)}while(r>0&&*p++-10);if(r+1&&p-b){while(p
--b)if(*--p-10){w(p)}w("\n")}}while(r>0);l}while(++i<c);free(b);return n;}
+q=p=b;b=realloc(b,(e-p)*2+1);x(!b,{free(q);close(f);return 1;},"realloc: ")p=e-p
++b;e=b+(p-b)*2+1;}s(r,read(f,p,1),n=1,"read"z)}l(r>0&&*p++-10);if(r+1&&p-b){l(p-
+b)if(*--p-10){w(p)}w("\n")}}l(r>0);close(f);}l(++i<c);free(b);return n;}
+# reverse mapping of keys -> values in given array
+function reverse_mapping(array,        tmp_key, tmp_element, done) {
+    # user shouldn't have passed these, but let's be safe
+    tmp_key = tmp_element = ""
+    for (key in done)
+        delete done[key]
+
+    for (key in array) {
+        # if we already reversed this pair to avoid a collision, continue
+        if (key in done)
+            continue
+
+        # if this swap would cause a colision, store those values
+        if (array[key] in array) {
+            tmp_key     = array[    key]
+            tmp_element = array[tmp_key]
+        }
+
+        # reverse the mapping of our current key -> element pair
+        array[array[key]] = key
+
+        # delete the now old mapping
+        delete array[key]
+
+        # if we had a collision, reverse those values, too
+        if (tmp_key) {
+            array[tmp_element] = tmp_key
+            done [tmp_key    ]
+            tmp_key = ""
+        }
+    }
+}
+
+# example
+BEGIN {
+    a["b"] = 1
+    a[1] = "a"
+    a[2] = "b"
+    a[3] = "c"
+
+    for (k in a)
+        printf("a[%s] = %s\n", k, a[k])
+
+    reverse_mapping(a)
+
+    printf("\n")
+    for (k in a)
+        printf("a[%s] = %s\n", k, a[k])
+}
+// for memmem()
+#define _GNU_SOURCE
+
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+int main(int argc, char **argv)
+{
+    if (argc < 6) return 1; // not enough arguments
+
+    char beg  = **++argv; // begin   group e.g. '('
+    char end  = **++argv; // end     group e.g. ')'
+    char find = **++argv; // find in group e.g. ' '
+    char repl = **++argv; // replace with  e.g. ':'
+
+    while (*++argv) {
+        int    fd;
+        off_t  size;
+        char  *file, *fend, *p, *q;
+
+        if (0 > (fd   = open (*argv, O_RDWR)  )) return 2; // failed to open file
+        if (0 > (size = lseek(fd, 0, SEEK_END))) return 3; // failed to find end of file
+
+        if (size == 0) {
+            if (0 > close(fd)) return 4;
+            continue;
+        }
+
+        if (MAP_FAILED == (file = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, 0))) return 5; // failed to map file
+
+        for (p = file, fend = p + size; (p = memmem(p, fend - p, &beg, 1)); p = q) {
+            if (!(q = memmem(p, fend - p, &end, 1))) return 6; // failed to find matching paren
+            while ((p = memmem(p, q - p, &find, 1))) *p = repl;
+        }
+
+        if (0 > munmap(file, size)) return 7; // failed to unmap
+        if (0 > close (fd)        ) return 8; // failed to close file
+    }
+    return 0; // success
+}
+#include <stdio.h>
+
+#define LEN(x) (sizeof(x) / sizeof(*x))
+typedef enum { X = -1, E = 0, O = 1, C } P;
+char glyphs[] = "X O";
+char *outcomes[] = { "X wins", "", "O wins", "Cat's game" };
+int rows[][2] = { // start-increment pairs to check for wins
+    { 0, 1 }, { 0, 3 }, { 0, 4 }, { 1, 3 }, { 2, 2 }, { 2, 3 }, { 3, 1 }, { 6, 1 },
+};
+P board[9];
+
+void print_board(void)
+{
+    for (size_t i = 0; i < LEN(board); i++)
+        printf(" %c %s", board[i] == E ? '0' + (int)i : glyphs[board[i] + 1],
+                         i + 1 == LEN(board) ? "\n\n" :
+                         i % 3 != 2          ? "|"    : "\n---+---+---\n");
+}
+
+P whose_row(int beg, int inc)
+{
+    return (board[beg] + board[beg + inc] + board[beg + 2 * inc]) / 3;
+}
+
+P state(void)
+{
+    P w;
+    for (int i = LEN(rows); i--;)
+        if ((w = whose_row(rows[i][0], rows[i][1])) != E)
+            return w; // we have a winner
+    for (int i = LEN(board); i--;)
+        if (board[i] == E)
+            return E; // still empty spaces
+    return C;         // cat's game
+}
+
+int negamax(P turn, int depth, int a, int b)
+{
+    int s = -1, m = 0, t;
+    P   w = state();
+
+    if (w != E)
+        return w == C ? 0 : w * turn;
+
+    for (int i = LEN(board); i--;) {
+        if (board[i] != E) continue;
+        board[i] = turn;
+        if ((t = -negamax(-turn, depth + 1, -b, -a)) > s) {
+            s = t;
+            m = i;
+            if (t > a) a = t;
+        }
+        board[i] = E;
+        if (a > b) break;
+    }
+    if (depth == 0)
+        board[m] = turn;
+    return s;
+}
+
+int main(int argc, char **argv)
+{
+    P p = X;
+
+    if (argc > 1 && **++argv == 'O') {
+        p = O;
+        negamax(-p, 0, -1, 1);
+    }
+    print_board();
+
+    do {
+        size_t m;
+        if (scanf("%zu", &m) < 1 || m >= LEN(board) || board[m] != E) {
+            puts("Illegal move. Try again.");
+            continue;
+        }
+        board[m] = p;
+        print_board();
+        negamax(-p, 0, -1, 1);
+        print_board();
+    } while (state() == E);
+
+    puts(outcomes[state() + 1]);
+    return 0;
+}
+#include <stdio.h>
+#include <string.h>
+
+#define LEN(x) (sizeof(x) / sizeof(*x))
+typedef enum { X = -1, E = 0, O = 1, C } P;
+char glyphs[] = "X O";
+P match[] = { ['X'] = X, ['O'] = O };
+int rows[][2] = { // start-increment pairs to check for wins
+    { 0, 1 }, { 0, 3 }, { 0, 4 }, { 1, 3 }, { 2, 2 }, { 2, 3 }, { 3, 1 }, { 6, 1 },
+};
+P board[9], turn;
+
+void pretty_print_board(void)
+{
+    for (size_t i = 0; i < LEN(board); i++)
+        fprintf(stderr, " %c %s", glyphs[board[i] + 1],
+                                  i + 1 == LEN(board) ? "\n\n" :
+                                  i % 3 != 2          ? "|"    : "\n---+---+---\n");
+}
+
+void print_board(void)
+{
+    putc(glyphs[turn + 1], stdout);
+    for (size_t i = 0; i < LEN(board); i++)
+        putc(glyphs[board[i] + 1], stdout);
+    putc('\n', stdout);
+    fflush(stdout);
+}
+
+int read_move(void)
+{
+    int p, m, n;
+    p = getchar();
+    m = getchar();
+    n = getchar();
+    if (p == EOF || m == EOF || n == EOF)                 { fprintf(stderr, "read EOF\n");                 return 0; }
+    if (p != 'O' && p != 'X')                             { fprintf(stderr, "invalid piece %c\n", p);      return 0; }
+    if (match[p] != turn)                                 { fprintf(stderr, "out of turn %c\n", p);        return 0; }
+    m -= '0';
+    if (m < 0 || (size_t)m > LEN(board) || board[m] != E) { fprintf(stderr, "invalid move %c\n", m + '0'); return 0; }
+    if (n != '\n')                                        { fprintf(stderr, "extra characters\n");         return 0; }
+    board[m] = turn;
+    return 1;
+}
+
+P whose_row(int beg, int inc)
+{
+    return (board[beg] + board[beg + inc] + board[beg + 2 * inc]) / 3;
+}
+
+P state(void)
+{
+    P w;
+    for (int i = LEN(rows); i--;)
+        if ((w = whose_row(rows[i][0], rows[i][1])) != E)
+            return w; // we have a winner
+    for (int i = LEN(board); i--;)
+        if (board[i] == E)
+            return E; // still empty spaces
+    return C;         // cat's game
+}
+
+int main(void)
+{
+    for (int i = 1000; i--;) {
+        memset(board, 0, sizeof(board));
+        turn = X;
+
+        do {
+            print_board();
+            //pretty_print_board();
+            if (!read_move()) break;
+            turn = -turn;
+        } while (state() == E);
+        //pretty_print_board();
+
+        switch (state()) {
+            case X: fputs("X wins\n"    , stderr); break;
+            case O: fputs("O wins\n"    , stderr); break;
+            case C: fputs("Cat's game\n", stderr); break;
+            case E: fputs("Failure\n "  , stderr); return 0;
+        }
+    }
+    return 0;
+}

ttt/ttt_negamax.c

+#include <stdio.h>
+
+#define LEN(x) (sizeof(x) / sizeof(*x))
+typedef enum { X = -1, E = 0, O = 1, C } P;
+char glyphs[] = "X O";
+P match[] = { ['X'] = X, [' '] = E, ['O'] = O };
+int rows[][2] = { // start-increment pairs to check for wins
+    { 0, 1 }, { 0, 3 }, { 0, 4 }, { 1, 3 }, { 2, 2 }, { 2, 3 }, { 3, 1 }, { 6, 1 },
+};
+P board[9];
+
+int read_board(P *t)
+{
+    int c = getchar();
+    if (c == EOF) return 1;
+    *t = match[c];
+    for (size_t i = 0; i < LEN(board) && (c = getchar()) != EOF; i++)
+        board[i] = match[c];
+    return c == EOF || getchar() != '\n';
+}
+
+P whose_row(int beg, int inc)
+{
+    return (board[beg] + board[beg + inc] + board[beg + 2 * inc]) / 3;
+}
+
+P state(void)
+{
+    P w;
+    for (int i = LEN(rows); i--;)
+        if ((w = whose_row(rows[i][0], rows[i][1])) != E)
+            return w; // we have a winner
+    for (int i = LEN(board); i--;)
+        if (board[i] == E)
+            return E; // still empty spaces
+    return C;         // cat's game
+}
+
+int negamax(P turn, int depth, int a, int b)
+{
+    int s = -1, m = 0, t;
+    P   w = state();
+
+    if (w != E)
+        return w == C ? 0 : w * turn;
+
+    for (int i = LEN(board); i--;) {
+        if (board[i] != E) continue;
+        board[i] = turn;
+        if ((t = -negamax(-turn, depth + 1, -b, -a)) > s) {
+            s = t;
+            m = i;
+            if (t > a) a = t;
+        }
+        board[i] = E;
+        if (a > b) break;
+    }
+    if (depth == 0)
+        fprintf(stdout, "%c%d\n", glyphs[turn + 1], m);
+    return s;
+}
+
+int main(int argc, char **argv)
+{
+    P t, p = X;
+
+    if (argc > 1 && **++argv == 'O')
+        p = O;
+
+    for (;;) {
+        if (read_board(&t)) break;
+        if (t != p) continue;
+        negamax(p, 0, -1, 1);
+        fflush(stdout);
+    }
+    return 0;
+}
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+#define LEN(x) (sizeof(x) / sizeof(*x))
+typedef enum { X = -1, E = 0, O = 1, C } P;
+char glyphs[] = "X O";
+P match[] = { ['X'] = X, [' '] = E, ['O'] = O };
+P board[9];
+
+int read_board(P *t)
+{
+    int c = getchar();
+    if (c == EOF) return 1;
+    *t = match[c];
+    for (size_t i = 0; i < LEN(board) && (c = getchar()) != EOF; i++)
+        board[i] = match[c];
+    return c == EOF || getchar() != '\n';
+}
+
+int main(int argc, char **argv)
+{
+    P t, p = X;
+
+    srand(time(NULL));
+
+    if (argc > 1 && **++argv == 'O')
+        p = O;
+
+    for (;;) {
+        int r;
+        if (read_board(&t)) break;
+        if (t != p) continue;
+        do r = rand() % LEN(board);
+        while (board[r] != E);
+        fprintf(stdout, "%c%d\n", glyphs[p + 1], r);
+        fflush(stdout);
+    }
+    return 0;
+}

types/demo.c

-#include <time.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include "vector.h"
-#include "list.h"
-#include "heap.h"
-#include "bstree.h"
-#include "splaytree.h"
-
-vector_def(Stack, int) // use vector as stack
-list_def  (Listn, int) // use list node as list
-heap_def  (Max_heap, int, a < b)
-
-#define LENGTH(x) (sizeof(x) / sizeof(*x))
-int main(void)
-{
-    setbuf(stdout, NULL);
-    srand(time(NULL));
-    /* Vector demo */
-    Stack *s = Stack_new(4); // minimum capacity 4
-    int   i = 20;
-    while (i--)
-        Stack_push(s, i);
-    Stack_for_each(s, print_int);
-    printf("\n");
-    while (s->size)
-        printf("%d,", Stack_pop(s));
-    printf("\n");
-    Stack_del(s);
-
-    /* List demo */
-    Listn *head = NULL;
-    i = 5;
-    while (i--)
-        Listn_insert(&head, i);
-    Listn_for_each(head, print_int);
-    printf("\n");
-    Listn_del(head->prev->prev);
-
-    // reverse traversal
-    Listn *p = head->prev;
-    do {
-        printf("%d,",p->data);
-        p = p->prev;
-    } while (p != head->prev);
-    printf("\n");
-    Listn_del_all(&head);
-
-    // demo with dummy head
-    head = Listn_new(-1); // sentinel value
-    i = 5;
-    while (i--)
-        Listn_append(&head, i);
-    for (p = head->next; p != head; p = p->next)
-        printf("%d,", p->data);
-    printf("\n");
-    Listn_del_all(&head);
-
-    /* Heap demo */
-    size_t j;
-    int b[] = { 3, 5, 2, 3, 8, 0 };
-    size_t n = LENGTH(b) - 1;
-    printf("is %sa heap\n", Max_heap_is_heap(b, n) ? "" : "not ");
-    Max_heap_heapify(b, n);
-    Max_heap_push(b, n++, 7);
-    printf("is %sa heap\n", Max_heap_is_heap(b, n) ? "" : "not ");
-    for (j = 0; j < LENGTH(b); j++)
-        printf("%d%c", Max_heap_pop(b, n--), (j + 1 == LENGTH(b)) ? '\n' : ',');
-
-    int a[] = { 3, 5, 2, 3, 4 };
-    for (j = 0; j < LENGTH(a); j++)
-        printf("%d%c", a[j], (j + 1 == LENGTH(a)) ? '\n' : ',');
-    Max_heap_sort(a, LENGTH(a));
-    for (j = 0; j < LENGTH(a); j++)
-        printf("%d%c", a[j], (j + 1 == LENGTH(a)) ? '\n' : ',');
-
-    /* Using Vector and Heap to make a priority queue */
-    Stack *v = Stack_new(0);
-    i = j = 20;
-    while (i--) // Initial members
-        Stack_push(v, rand() % j);
-    Max_heap_heapify(v->data, v->size);
-    i = 20;
-    while (i--) { // add more members
-        Stack_push(v, 0); // make space
-        Max_heap_push(v->data, v->size - 1, rand() % j); // place the member
-    }
-    while (v->size) {
-        printf("%d,", Max_heap_pop(v->data, v->size)); // get the member
-        Stack_pop(v); // remove it's place
-    }
-    printf("\nempty size:%zu\n", v->size);
-    Stack_del(v);
-
-    return 0;
-}
     Name *prev;                                   \
     Type  data;                                   \
 };                                                \
-void Name##_for_each(Name *l, void (*act)(Type*)) \
-{                                                 \
-    Name *p = l;                                  \
-    if (!l)                                       \
-        return;                                   \
-    do {                                          \
-        act(&p->data);                            \
-        p = p->next;                              \
-    } while (p != l);                             \
-}                                                 \
 Name *Name##_new(Type t)                          \
 {                                                 \
     Name *n = malloc(sizeof(Name));               \
     size_t capacity;                                                 \
     size_t min_capacity;                                             \
 } Name;                                                              \
-void Name##_for_each(Name *v, void (*act)(Type*))                    \
-{                                                                    \
-    size_t i;                                                        \
-    if (!v)                                                          \
-        return;                                                      \
-    for (i = 0; i < v->size; i++)                                    \
-        act(v->data + i);                                            \
-}                                                                    \
 ssize_t Name##_resize(Name *v, size_t capacity)                      \
 {                                                                    \
     Type *t = realloc(v->data, capacity * sizeof(Type));             \
     v->capacity = capacity;                                          \
     return capacity;                                                 \
 }                                                                    \
-Type *Name##_push(Name *v, Type t)                                   \
+void Name##_push(Name *v, Type t)                                    \
 {                                                                    \
     if (v->size == v->capacity)                                      \
         if (Name##_resize(v, size_t_max(v->capacity * 2, 1)) < 0)    \
             return NULL;                                             \
-    v->data[v->size] = t;                                            \
-    return v->data + v->size++;                                      \
+    v->data[v->size++] = t;                                          \
 }                                                                    \
 Type Name##_pop(Name *v)                                             \
 {                                                                    \
         Name##_resize(v, size_t_max(v->size * 2, v->min_capacity));  \
     return t;                                                        \
 }                                                                    \
-Name *Name##_new(size_t min_capacity)                                \
+Name Name##_new(size_t min_capacity)                                 \
 {                                                                    \
-    Name *t = malloc(sizeof(Name));                                  \
-    if (!t)                                                          \
-        return NULL;                                                 \
-    *t = (Name){ NULL, 0, 0, min_capacity };                         \
-    Name##_resize(t, min_capacity);                                  \
+    Name t = (Name){ NULL, 0, 0, min_capacity };                     \
+    Name##_resize(&t, min_capacity);                                 \
     return t;                                                        \
 }                                                                    \
 void Name##_del(Name *v)                                             \
 {                                                                    \
     free(v->data);                                                   \
-    free(v);                                                         \
+    v->data     = NULL;                                              \
+    v->capacity = 0;                                                 \
+    v->size     = 0;                                                 \
 }
 
 #endif
 
 cleanup:
 	if (loop) zloop_destroy(&loop);
-	if (ctx ) zctx_destroy(&ctx);
+	if (ctx ) zctx_destroy (&ctx );
 	return (status);
 }
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <zmq.h>
+
+#define zcheck_err(eval, condition, fmt, args...)                                                                     \
+((void)({                                                                                                             \
+    errno = 0;                                                                                                        \
+    if (!(condition)) {                                                                                               \
+        fprintf(stderr, "%s: " fmt "%s%s\n", prog_name, ##args, errno ? ": " : "", errno ? zmq_strerror(errno) : ""); \
+        exit(eval);                                                                                                   \
+    }                                                                                                                 \
+}))
+
+char *prog_name;
+
+/*
+ * Create ZMQ_ROUTER socket, bind, echo messages.
+ */
+int main(int argc, char **argv)
+{
+	int       con;
+	void     *ctx, *soc;
+	zmq_msg_t msg;
+
+	prog_name = argv[0];
+
+	zcheck_err(EXIT_FAILURE,   2 == argc                       , "Supply endpoint as only argument"     );
+	zcheck_err(EXIT_FAILURE, ctx  = zmq_ctx_new()              , "Error creating context"               );
+	zcheck_err(EXIT_FAILURE, soc  = zmq_socket(ctx, ZMQ_DEALER), "Error creating socket"                );
+	zcheck_err(EXIT_FAILURE,   0 == zmq_bind(soc, argv[1])     , "Error binding to endpoint %s", argv[1]);
+	zcheck_err(EXIT_FAILURE,   0 == zmq_msg_init(&msg)         , "Error initialise mesage"              );
+
+	setbuf(stdout, NULL);
+	for (con = 0;;) {
+		int    more, i;
+		size_t size = sizeof(more);
+		zcheck_err(EXIT_FAILURE, -1 != zmq_recvmsg(soc, &msg, 0)                     , "Error receiving message"       );
+		zcheck_err(EXIT_FAILURE,  0 == zmq_getsockopt(soc, ZMQ_RCVMORE, &more, &size), "Error checking for ZMQ_RCVMORE");
+		//zcheck_err(EXIT_FAILURE, -1 != zmq_sendmsg(soc, &msg, more ? ZMQ_SNDMORE : 0), "Error echoing message"         );
+		printf("received %d bytes: ", zmq_msg_size(&msg));
+		for (i = 0; i < zmq_msg_size(&msg); i++)
+			printf("%c", ((char*)zmq_msg_data(&msg))[i]);
+		printf("\n");
+		if (!more)
+			printf("End of message\n");
+	}
+
+	return 0;
+}
 	td=${TMPDIR:-/tmp}
 	[[ -d $td && -r $td && -w $td && -x $td ]] || return 1
 	set -C
-	until { f=$td/$(tr -dc '[:alnum:]' < /dev/urandom | dd bs=8 count=1); >"$f"; }
+	until f=$td/$(tr -dc '[:alnum:]' < /dev/urandom | dd bs=8 count=1); >"$f";
 	do :; done 2>/dev/null
 	printf %s "$f"
 )
 
-zmq_push() { # USAGE: zmq_push host port
+zmq_push() { # USAGE: zmq_push host port < message_file
 	trap '[[ $fd ]] && exec {fd}>&-; [[ -f $msg ]] && rm "$msg"; trap - RETURN' RETURN
 	local fd msg len pre="\x1\x0\xff\x0\x0\x0\x0"