]> git.draconx.ca Git - scripts.git/commitdiff
Import the scripts directory from my website.
authorNick Bowler <nbowler@draconx.ca>
Fri, 7 Dec 2012 00:37:29 +0000 (19:37 -0500)
committerNick Bowler <nbowler@draconx.ca>
Fri, 7 Dec 2012 00:37:29 +0000 (19:37 -0500)
26 files changed:
HEADER.txt [new file with mode: 0644]
WTFPL-2 [new file with mode: 0644]
c-is-not-cxx.c [new file with mode: 0644]
clean-modules.zsh [new file with mode: 0755]
cmdwrap.c [new file with mode: 0644]
dpicalc.c [new file with mode: 0644]
fetchmail-sync.zsh [new file with mode: 0755]
fucked.scheme [new file with mode: 0644]
genlibs.sh [new file with mode: 0755]
get_extension.zsh [new file with mode: 0755]
gitcvs.zsh [new file with mode: 0755]
ircmpc.pl [new file with mode: 0644]
libs.sh [new file with mode: 0755]
maildir-clean.zsh [new file with mode: 0755]
modules.zsh [new file with mode: 0755]
mpdbetter.sed [new file with mode: 0755]
mpdscripts.sh [new file with mode: 0755]
mplus-t-gen.py [new file with mode: 0755]
musicstats.zsh [new file with mode: 0755]
openexec.c [new file with mode: 0644]
polya.tex [new file with mode: 0644]
quine.hs [new file with mode: 0644]
quine.sed [new file with mode: 0755]
replaygain.zsh [new file with mode: 0755]
runcron.zsh [new file with mode: 0755]
spamassassin.zsh [new file with mode: 0755]

diff --git a/HEADER.txt b/HEADER.txt
new file mode 100644 (file)
index 0000000..870ffdf
--- /dev/null
@@ -0,0 +1,4 @@
+Various short programs.  Generally, they are described in comments at the top
+of the source file.  Most of these programs are free to be copied, modified
+and/or distributed under the terms of the Do What The Fuck You Want To Public
+License, version 2.  There is NO WARRANTY, to the extent permitted by law.
diff --git a/WTFPL-2 b/WTFPL-2
new file mode 100644 (file)
index 0000000..cb33446
--- /dev/null
+++ b/WTFPL-2
@@ -0,0 +1,14 @@
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+                    Version 2, December 2004
+
+ Copyright (C) 2004 Sam Hocevar
+  22 rue de Plaisance, 75014 Paris, France
+ Everyone is permitted to copy and distribute verbatim or modified
+ copies of this license document, and changing it is allowed as long
+ as the name is changed.
+
+            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. You just DO WHAT THE FUCK YOU WANT TO.
+
diff --git a/c-is-not-cxx.c b/c-is-not-cxx.c
new file mode 100644 (file)
index 0000000..a942b82
--- /dev/null
@@ -0,0 +1,79 @@
+/* Copyright (C) 2008-2010 Nick Bowler
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ *
+ * This is, to the best of my knowledge, a strictly conforming ANSI C
+ * (C89) program which is not a C++ program.  This proves by counter-
+ * example that C++ is not a superset of C.
+ *
+ * Some of the "techniques" used in this file are stupid legacy features.
+ * Please don't take this as an example of a well-written C program.
+ *
+ * The output of this program should be:
+ *   The old answer was 42, but the new answer is 54.
+ *
+ * There are more than 10 different things wrong with this program if you
+ * consider it as C++.  Can you spot them all?  This is not valid C99 for
+ * a few of these reasons.  For now, it is pointless to update this to
+ * C99 -- there are just too many obvious incompatibilities.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define and 42
+#define or  54
+
+static struct baz {
+       struct foo {
+               enum {
+                       ANSWER1 = and,
+                       ANSWER2 = or,
+                       ANSWER3 = -ANSWER1
+               } val;
+       } foo;
+};
+
+const int foo;
+typedef int baz();
+baz main;
+
+int main(argc, argv)
+       int    argc;
+       char **argv;
+{
+       struct foo foo = { 0 };
+       int *new;
+
+       if (argc >= foo.val) {
+               return main(bar(), argv);
+       }
+
+       goto assign;
+       {
+               int old = 0;
+       assign:
+               old = -argc;
+
+               new = malloc(sizeof 'x');
+               if (!new) {
+                       perror("malloc");
+                       return EXIT_FAILURE;
+               }
+
+               *new = ANSWER2;
+               printf("The old answer was %d, but the new answer is %d.\n",
+                                                                 old, *new);
+               free(new);
+       }
+
+       return 0;
+}
+
+bar()
+{
+       return (enum{X = ANSWER3})-X//**/-1
+               ;
+}
diff --git a/clean-modules.zsh b/clean-modules.zsh
new file mode 100755 (executable)
index 0000000..4ea8251
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env zsh
+# 
+# Copyright © 2012 Nick Bowler
+#
+# Prunes directories in /lib/modules that do not correspond to any kernel
+# version in /boot.  If the -f option is not specified, only print out what
+# will be removed.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+force=no
+verbose=no
+while getopts 'fv' opt $@; do
+       case $opt in
+       f) force=yes ;;
+       v) verbose=yes ;;
+       \?) exit 1 ;;
+       esac
+done
+
+[[ force = yes ]] || verbose=yes
+
+boot=/boot
+kernbase=$boot/vmlinuz-
+kernels=($kernbase*(N))
+
+if ! [[ $#kernels -ge 1 ]]; then
+       printf '%s: no kernels found in %s, aborting\n' "$0" "$boot"
+       exit 1
+fi
+
+typeset -A kernmap
+for v in ${${kernels%.old}#$kernbase}; do
+       kernmap[$v]=false
+done
+
+modbase=/lib/modules
+for d in $modbase/*; do
+       v=${d#$modbase/}
+       if $kernmap[$v] :; then
+               [[ $verbose = yes ]] && printf '%s\n' "$d"
+               [[ $force = yes   ]] && rm -rf "$d"
+       fi
+done
diff --git a/cmdwrap.c b/cmdwrap.c
new file mode 100644 (file)
index 0000000..f146c8b
--- /dev/null
+++ b/cmdwrap.c
@@ -0,0 +1,120 @@
+/* Copyright (C) 2010 Nick Bowler
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ *
+ * Putting . in PATH is generally not a good idea, for a variety of reasons.
+ * However, some programs expect it to be there, and do not function correctly
+ * without it.  This program allows one to invoke specific programs in the
+ * current working directory as though . was in the PATH without it actually
+ * being there.
+ *
+ * To work, place a copy of (or symlink to) this program somewhere that is
+ * actually in the PATH.  The name of the command determines what program
+ * gets invoked.  Basic checks are done to avoid accidental infinite
+ * recursion.
+ *
+ * This is probably not portable to non-GNU/Linux systems.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+/* Common shell return codes */
+#define SHELL_CMD_NOT_FOUND 127
+#define SHELL_CMD_NOT_EXEC  126
+
+/*
+ * A wrapper around readlink which dynamically allocates a buffer large
+ * enough to contain the entire filename.  Also add a null terminator
+ * so that the filename can be used as a C string.
+ */
+char *readlink_alloc(const char *path)
+{
+       ssize_t bufsize = 64, rc;
+       char *buf = NULL, *tmp;
+
+       while (1) {
+               if (bufsize >= SSIZE_MAX/2) {
+                       fprintf(stderr, "cmdwrap: %s: %s\n",
+                                       path, strerror(ENAMETOOLONG));
+                       break;
+               }
+
+               tmp = realloc(buf, bufsize * 2);
+               if (!tmp) {
+                       fprintf(stderr, "cmdwrap: %s\n", strerror(errno));
+                       break;
+               }
+
+               bufsize *= 2;
+               buf = tmp;
+
+               rc = readlink(path, buf, bufsize);
+               if (rc == -1) {
+                       fprintf(stderr, "cmdwrap: %s: %s\n",
+                                       path, strerror(errno));
+                       break;
+               } else if (rc < bufsize) {
+                       buf[rc] = 0;
+                       return buf;
+               }
+       }
+
+       free(buf);
+       return NULL;
+}
+
+int main(int argc, char **argv)
+{
+       char *curexe, *newexe, fdname[64];
+       int fd;
+
+       if (argc < 1) {
+               fprintf(stderr, "cmdwrap: command name must be present in the argument list.\n");
+               return SHELL_CMD_NOT_FOUND;
+       }
+
+       fd = open(argv[0], O_RDONLY);
+       if (fd == -1) {
+               fprintf(stderr, "cmdwrap: %s: %s\n", argv[0], strerror(errno));
+               return SHELL_CMD_NOT_FOUND;
+       }
+
+       /* Try to avoid accidental infinite recursion. */
+       sprintf(fdname, "/proc/self/fd/%d", fd);
+       newexe = readlink_alloc(fdname);
+       if (!newexe)
+               return SHELL_CMD_NOT_FOUND;
+
+       curexe = readlink_alloc("/proc/self/exe");
+       if (!curexe)
+               return SHELL_CMD_NOT_FOUND;
+
+       if (strcmp(newexe, curexe) == 0) {
+               fprintf(stderr, "cmdwrap: infinite recursion detected\n");
+               return SHELL_CMD_NOT_EXEC;
+       }
+
+       /*
+        * Some programs expect argv[0] to point to their actual executable
+        * (potentially after a path lookup).  But if we leave argv[0] as it
+        * is, they'll tend to find this program instead of the right one.
+        *
+        * Fix that up, too.
+        */
+       argv[0] = newexe;
+       free(curexe);
+
+       fexecve(fd, argv, environ);
+       fprintf(stderr, "cmdwrap: %s: %s\n", argv[0], strerror(errno));
+       return SHELL_CMD_NOT_EXEC;
+}
diff --git a/dpicalc.c b/dpicalc.c
new file mode 100644 (file)
index 0000000..42b4d18
--- /dev/null
+++ b/dpicalc.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2011 Nick Bowler
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <math.h>
+
+const char *progname = "dpicalc";
+
+static unsigned long
+simple_strtoul(const char *str, const char *name, int base)
+{
+       unsigned long ret;
+       char *end;
+
+       errno = 0;
+       ret = strtoul(str, &end, base);
+       if (errno != 0) {
+               fprintf(stderr, "%s: %s: invalid %s: %s\n",
+                               progname, str, name, strerror(errno));
+               exit(EXIT_FAILURE);
+       } else if (*end != '\0') {
+               fprintf(stderr, "%s: %s: invalid %s: trailing garbage\n",
+                               progname, str, name);
+               exit(EXIT_FAILURE);
+       }
+
+       return ret;
+}
+
+int main(int argc, char **argv)
+{
+       double diagonal, ratio, phys_width;
+       unsigned long w, h;
+
+       if (argc > 0)
+               progname = argv[0];
+
+       if (argc < 4) {
+               fprintf(stderr, "usage: %s diagonal pixel_w pixel_h\n",
+                               progname);
+               return EXIT_FAILURE;
+       }
+
+       diagonal = strtod(argv[1], NULL);
+       w = simple_strtoul(argv[2], "pixel width", 10);
+       h = simple_strtoul(argv[3], "pixel height", 10);
+
+       ratio = (double) h / w;
+       if (!isnormal(ratio)) {
+               fprintf(stderr, "%s: nonsensical aspect ratio (%.2f)\n",
+                               progname, ratio);
+       }
+
+       phys_width = sqrt(diagonal*diagonal / (1 + ratio*ratio));
+       printf("%.1f\n", w / phys_width);
+
+       return 0;
+}
diff --git a/fetchmail-sync.zsh b/fetchmail-sync.zsh
new file mode 100755 (executable)
index 0000000..45a4e01
--- /dev/null
@@ -0,0 +1,28 @@
+#!/usr/bin/env zsh
+#
+# Copyright (C) 2010 Nick Bowler
+#
+# Simple script which ensures that a running fetchmail daemon is
+# sleeping, by forcing a fetch run and waiting until it finishes.
+# This is useful for log rotation: the fetchmail daemon will not
+# write to the log file while it is sleeping.  It is also useful
+# for manually invoking fetch runs.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+setopt nonotify
+
+pid=`head -n 1 ~/.fetchmail.pid 2>/dev/null`
+
+if ! [[ $pid > 0 && $(ps --no-heading $pid) =~ fetchmail ]]; then
+       echo "$0: fetchmail is not running."
+       exit 1
+fi
+
+coproc sed --unbuffered '/^fetchmail: sleeping/q'
+tail -s 0.1 -n 0 -f ~/.fetchmaillog --pid $! >&p &
+kill -USR1 $pid
+<&p
+wait
diff --git a/fucked.scheme b/fucked.scheme
new file mode 100644 (file)
index 0000000..5f3235b
--- /dev/null
@@ -0,0 +1,2 @@
+(define fucked (lambda (x) (display "fucked\n") (x x)))
+(fucked (call-with-current-continuation (lambda (k) (k k))))
diff --git a/genlibs.sh b/genlibs.sh
new file mode 100755 (executable)
index 0000000..3f28fea
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/zsh
+#
+# Copyright (C) 2009 Nick Bowler
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.  This file is offered as-is,
+# without any warranty.
+#
+# Generate library dependencies for an initramfs.  Finds all dynamically linked
+# binaries listed in an initramfs description (as needed by gen_init_cpio from
+# the Linux source) and passes them to libs.sh in order to actually generate
+# the dependencies.
+
+if [ -z "$1" ]; then
+       echo "usage: genlibs.sh initramfs-desc"
+       exit 1
+fi
+
+files=(`sed -n 's/^ *file \+[^ ]\+ \+\([^ ]\+\).*/\1/p' "$1"`)
+
+dyns=()
+
+for i in $files; do
+       if ! file "$i" | grep dynamic >/dev/null; then continue; fi
+       dyns+="$i"
+done
+
+./libs.sh $dyns
diff --git a/get_extension.zsh b/get_extension.zsh
new file mode 100755 (executable)
index 0000000..090af8e
--- /dev/null
@@ -0,0 +1,46 @@
+#!/usr/bin/env zsh
+#
+# Copyright © 2010-2012 Nick Bowler
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+#
+# A convenient script to download an OpenGL extension specification from the
+# Khronos registry into the current working directory.
+
+IFS=_ extension=(${=1})
+
+case $extension[1] in
+GL|GLX|WGL)
+       ;;
+*)
+       extension=(GL $extension)
+       ;;
+esac
+
+api=$extension[1]
+vendor=$extension[2]
+name=${(j:_:)extension[3,-1]}
+fullname=${(j:_:)extension}
+
+if [[ -z $api || -z $vendor || -z $name ]]; then
+       printf 'usage: %s extension\n' $0 1>&2
+       exit 1
+fi
+
+urls=(
+       http://www.opengl.org/registry/specs/$vendor/$name.txt
+       http://www.opengl.org/registry/specs/$vendor/${api:l}_$name.txt
+)
+
+for url in $urls; do
+       if wget -O $fullname $url; then
+               gzip -f $fullname || exit 1
+               exit 0
+       fi
+
+       rm -f $fullname
+done
+
+exit 1
diff --git a/gitcvs.zsh b/gitcvs.zsh
new file mode 100755 (executable)
index 0000000..9cc13d9
--- /dev/null
@@ -0,0 +1,144 @@
+#!/usr/bin/env zsh
+#
+# Copyright © 2008-2011 Nick Bowler
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+# List all commits that have not yet been committed to CVS.  (run this command
+# from the root of the CVS repository)
+git-cvs-commitlist() {
+       if [[ -z "$1" ]]; then
+               echo "usage: git-cvs-commitlist <git_dir> [origin]" 1>&2
+               return 1
+       fi
+
+       [[ -z "$2" ]] && 2="remotes/CVS/master"
+       [[ -d "$1/.git" ]] && 1="$1/.git"
+
+       GIT_DIR="$1" git cherry -v "$2"
+}
+
+# Commit a specified commit to CVS (run this command from the root of the CVS
+# repository).
+git-cvs-commit() {
+       if [[ -z "$1" || -z "$2" ]]; then
+               echo "usage: git-cvs-commit <git_dir> <commit>" 1>&2
+               return 1
+       fi
+
+       [[ -d "$1/.git" ]] && 1="$1/.git"
+
+       GIT_DIR="$1" git cvsexportcommit -cvp "$2"
+}
+
+# Commit all commits that are not yet in CVS to CVS.
+# (run this command from the root of the CVS repository).
+git-cvs-commit-all() {
+       if [[ -z "$1" ]]; then
+               echo "usage: git-cvs-commit-all <git_dir>" 1>&2
+               return 1
+       fi
+
+       git-cvs-commitlist $1 | while read i; do
+               local commit=$(echo $i | cut -d ' ' -f 2)
+               git-cvs-commit $1 $commit || return $?
+       done
+}
+
+# Import the latest and greatest changes into a git repository (will create
+# a new repository if run outside of any git repo).
+#
+# The details used to fetch from CVS are recorded so that running
+# git-cvs-fetch with no arguments will repeat the same fetch as last time.
+# Currently, some arguments which don't make sense to record are recorded
+# anyway, so you may need to manually edit .git/config afterwards...
+git-cvs-fetch() {
+       local tmp cvsroot cvsmod cvsopts
+
+       cvsroot=${$(git config cvs.root):-$CVSROOT}
+       cvsopts=${$(git config cvs.opts):-'$@'}
+       eval "cvsopts=($cvsopts)"
+
+       # Extract a CVS root from opts, if any.
+       while [[ $((tmp=${cvsopts[(i)-d*]})) -le $#cvsopts ]]; do
+               cvsroot=${cvsopts[$tmp]#-d}
+               cvsopts=($cvsopts[1,$tmp-1] $cvsopts[$tmp+1,-1])
+               if [[ -z $cvsroot ]]; then
+                       cvsroot=${cvsopts[$tmp]}
+                       cvsopts=($cvsopts[1,$tmp-1] $cvsopts[$tmp+1,-1])
+               fi
+       done
+
+       if ! cvsmod=$(git config cvs.module); then
+               cvsmod=$cvsopts[-1]
+               cvsopts=($cvsopts[1,-2])
+       fi
+
+       # By this point, we must have a CVS root and module.
+       if [[ -z $cvsroot ]]; then
+               printf '%s: no CVS root set.\n' $0 1>&2
+               return 1
+       fi
+
+       if [[ -z $cvsmod ]]; then
+               printf '%s: no CVS module set.\n' $0 1>&2
+               return 1
+       fi
+
+       GIT_DIR=`git rev-parse --git-dir 2>/dev/null` git cvsimport \
+               -air CVS -d $cvsroot $cvsopts $cvsmod || return 1
+
+       # Store the settings for this run.
+       git config cvs.root   $cvsroot
+       git config cvs.module $cvsmod
+       [[ $#cvsopts -gt 0 ]] && git config cvs.opts ${(j: :)${(qq)cvsopts}}
+       :
+}
+
+# Generate an excludes file, suitable for writing to .git/info/exclude, based
+# on .cvsignore files found in the repository.  Run this command from the git
+# repository.
+git-cvs-genexclude() {
+       local dir i j cvsdefaults work
+
+       work=`git rev-parse --show-toplevel` || return 1
+       if test -z $work; then
+               printf '%s: must be run from the work tree\n' $0 1>&2
+               return 1
+       fi
+
+       printf '#\n# Automatically generated by %s\n#\n' "$0 $*"
+
+       # CVS ignores a number of patterns by default.
+       cvsdefaults=(
+               'RCS'   'SCCS'  'CVS'   'CVS.adm' 'RCSLOG' 'cvslog.*'
+               'tags'  'TAGS'  '.make.state'     '.nse_depinfo'
+               '*~'    '#*'    '.#*'   ',*'      '_$*'    '*$'
+               '*.old' '*.bak' '*.BAK' '*.orig'  '*.rej'  '.del-*'
+               '*.a'   '*.olb' '*.o'   '*.obj'   '*.so'   '*.exe'
+               '*.Z'   '*.elc' '*.ln'  'core'
+       )
+       printf '%s\n' $cvsdefaults
+
+       find $work -name .cvsignore | while read i; do
+               dir=${$(dirname $i)#$work}
+
+               < $i while read j; do
+                       printf '%s/%s\n' $dir $j
+               done
+       done
+}
+
+# For executable-like invocation...
+
+# It would be nice if we could detect whether we are invoked as an executable
+# and print a usage message if not given any arguments.  I have yet to find
+# a clean way to do this, however.
+
+if [ $# -gt 0 ]; then
+       func="git-cvs-${1#git-cvs-}"
+       shift
+       "$func" $@
+fi
diff --git a/ircmpc.pl b/ircmpc.pl
new file mode 100644 (file)
index 0000000..138a516
--- /dev/null
+++ b/ircmpc.pl
@@ -0,0 +1,134 @@
+# Copyright (C) 2008, 2010 Nick Bowler
+#
+# Irssi script for annoying your friends with MPD status information.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+use strict;
+use vars qw($VERSION %IRSSI);
+
+use utf8;
+use encoding 'utf8';
+use IO::Socket::INET6;
+
+use Irssi qw(
+       command_bind
+       settings_get_bool settings_add_bool
+       settings_get_int  settings_add_int
+       settings_get_str  settings_add_str
+);
+
+$VERSION = '0.1';
+%IRSSI = (
+       authors     => 'Nick Bowler',
+       contact     => 'nbowler@draconx.ca',
+       name        => 'MPC/Irssi',
+       description => 'Irssi client for the Music Player Daemon.',
+       license     => 'WTFPL2',
+);
+
+# MPD Connection Settings
+$ENV{"MPD_HOST"} = "localhost" unless ($ENV{"MPD_HOST"});
+$ENV{"MPD_PORT"} = 6600        unless ($ENV{"MPD_PORT"});
+settings_add_str("mpd", "mpd_host", $ENV{"MPD_HOST"});
+settings_add_int("mpd", "mpd_port", $ENV{"MPD_PORT"});
+
+# Open a connection to MPD.
+sub mpd_open {
+       my $sock = new IO::Socket::INET6(
+               PeerAddr => settings_get_str("mpd_host"),
+               PeerPort => settings_get_int("mpd_port"),
+               Proto    => 'tcp',
+       ) or do {
+               print CLIENTERROR "failed to open MPD socket: $!.";
+               return undef;
+       };
+       binmode($sock, ":utf8");
+
+       # Grab the MPD version.
+       if (!(<$sock> =~ /^OK MPD ([0-9]+)\.([0-9]+)\.([0-9]+)$/)) {
+               print CLIENTERROR "failed MPD handshake: $!.";
+               return undef;
+       }
+
+       return $sock;
+}
+
+sub mpd_currentsong {
+       my ($sock) = @_;
+       my %data;
+
+       # Get MPD status.
+       print $sock "status\n";
+       while (<$sock>) {
+               last if (/^OK/);
+               do { print CLIENTERROR "$_"; return undef } if (/^ACK/);
+
+               if (/^(\w+): (.*)$/) {
+                       $data{$1} = $2;
+               }
+       }
+       return %data if (!defined $data{"songid"});
+
+       # Get song info
+       print $sock "playlistid $data{songid}\n";
+       while (<$sock>) {
+               last if (/^OK/);
+               do { print CLIENTERROR "$_"; return undef } if (/^ACK/);
+
+               if (/^(\w+): (.*)$/) {
+                       $data{$1} = $2;
+               }
+       }
+
+       return %data;
+}
+
+sub mpd_close {
+       my ($sock) = @_;
+       print $sock "close\n";
+       close $sock;
+}
+
+sub fileformat {
+       ($_) = @_;
+
+       return "vorbis" if (/\.ogg$/);
+       return "flac"   if (/\.flac$/);
+       return "mp3"    if (/\.mp3$/);
+}
+
+sub cmd_current {
+       my ($data, $server, $witem) = @_;
+       my ($window, $local) = (Irssi::active_win());
+
+       my $sock = mpd_open() or return;
+       my %info = mpd_currentsong($sock) or return;
+       mpd_close($sock);
+
+       if ($info{'state'} eq "stop") {
+               $window->print("MPD is currently stopped.");
+               return;
+       }
+
+       my $text = "$info{Artist} – $info{Title}, "
+                . "track $info{Track} of “$info{Album}” "
+                . "($info{bitrate}kbps " . fileformat($info{'file'}) . ")";
+
+       # If the active window is not a channel or query, display locally.
+       $local = 1 unless ($witem && ($witem->{type} eq "CHANNEL"
+                                  || $witem->{type} eq "QUERY"));
+       
+       if ($local) {
+               $window->print($text);
+       } elsif ($data) {
+               $data =~ s/\s.*//;
+               $witem->command("SAY $data: /me is listening to $text.");
+       } else {
+               $witem->command("SAY /me is listening to $text.");
+       }
+}
+
+command_bind('mpd', 'cmd_current');
diff --git a/libs.sh b/libs.sh
new file mode 100755 (executable)
index 0000000..228e8ee
--- /dev/null
+++ b/libs.sh
@@ -0,0 +1,63 @@
+#!/bin/zsh
+#
+# Copyright (C) 2009 Nick Bowler
+# Copying and distribution of this file, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved.  This file is offered as-is,
+# without any warranty.
+#
+# Determine library dependencies for dynamically linked binaries and output
+# directives suitable for gen_init_cpio to include all required libraries
+# in an initramfs archive.  Users of this script will probably need to adjust
+# the BASE, LDD and LOADER variables appropriately.
+
+# Directory in which the libraries are located.
+BASE=/usr/x86_64-pc-linux-uclibc
+
+# How to run ldd.  The uClibc dynamic loader explodes wonderfully if
+# LD_LIBRARY_PATH is not set correctly.
+LDD="LD_LIBRARY_PATH=$BASE/lib:$BASE/usr/lib x86_64-pc-linux-uclibc-ldd"
+
+# Where the dynamic loader is located.  Always included in the output.
+LOADER="/lib/ld64-uClibc.so.0"
+
+getlibs() {
+       local file=$1
+
+       if test -u "$1" -o -g "$1"; then
+               file=`mktemp`
+               cp -f "$1" "$file"
+       fi
+
+       eval "$LDD '$file'" | sed -n 's/.*=> \(.*\) (0x[[:xdigit:]]*)/\1/p'
+
+       if [ "$file" != "$1" ]; then
+               rm -f "$file"
+       fi
+}
+
+libs=(`for i in "$@"; do getlibs "$i"; done | sort -u`)
+
+output="file  $LOADER $BASE$LOADER 0755 0 0"
+
+while [ $#libs -gt 0 ]; do
+       i=${libs[1]}
+       libs=(${libs[2,-1]})
+
+       if ! [[ "$i" =~ "^$BASE" ]]; then continue; fi
+
+       dest=${i#$BASE}
+
+       if test -L "$i"; then
+               output="$output\nslink $dest $(readlink "$i") 0644 0 0"
+               next=`readlink "$i"`
+               if [ "$next[0]" != "/" ]; then
+                       next="$(dirname "$i")/$next"
+               fi
+               libs+=$next
+       elif test -f "$i"; then
+               output="$output\nfile  $dest $i 0644 0 0"
+       fi
+done
+
+echo "$output" | sort -u
diff --git a/maildir-clean.zsh b/maildir-clean.zsh
new file mode 100755 (executable)
index 0000000..ee6438b
--- /dev/null
@@ -0,0 +1,60 @@
+#!/usr/bin/env zsh
+#
+# Copyright (C) 2009,2011 Nick Bowler
+#
+# Delete email older than a given date from a maildir.  Assumes that the
+# Date headers in the mails are valid and correct, and is therefore
+# somewhat less useful for cleaning up spam.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+cutoff='last week'
+maildir=
+
+while getopts 'd:' opt $@; do
+       case $opt in
+       d) cutoff=$OPTARG ;;
+       \?) exit 1 ;;
+       esac
+done
+
+shift $((OPTIND-1))
+
+# Determine maildir
+if [[ -n $1 ]]; then
+       maildir=$1
+elif [[ -n $MAIL ]]; then
+       maildir=$MAIL
+fi
+
+# Validate arguments
+date=`date --rfc-3339=date --date=$cutoff` || exit 1
+
+if [[ -z $maildir ]]; then
+       printf '%s: you must specify a maildir.\n' $0
+       exit 1
+fi
+
+if ! [[ -d $maildir/cur && -d $maildir/new && -d $maildir/tmp ]]; then
+       printf '%s: %s is not a valid maildir.\n' $0 $maildir
+       exit 1
+fi
+
+total=`ls $maildir/cur | wc -l`.
+count=0
+
+for i in $maildir/cur/*; do
+       datehdr=`formail -x Date < $i`
+       maildate=`date --rfc-3339=date --date=$datehdr`
+
+       count=$((count+1))
+
+       if [[ $maildate < $date ]]; then
+               printf '(%.0f%%) %s: deleting %s\n' $((100*count/total)) $0 $i
+               rm -f $i
+       else
+               printf '(%.0f%%) %s: keeping %s\n' $((100*count/total)) $0 $i
+       fi
+done
diff --git a/modules.zsh b/modules.zsh
new file mode 100755 (executable)
index 0000000..6115d27
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/env zsh
+#
+# Copyright © 2009 Nick Bowler
+#
+# Generate module listings for an initramfs by searching a subset of the
+# installed modules for a particular kernel version.  Currently, all
+# filesystem and MD drivers, plus all their (recursive) dependencies,
+# are included.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+usage() {
+       echo "usage: modules.zsh kernel-version" 1>&2
+       exit 1
+}
+
+out_mkdir_p() {
+       local i base path
+       base=$1
+       path=(${(s./.)2})
+
+       for i in {1..$#path}; do
+               echo "dir  $base/${(j./.)path[1,i]} 0755 0 0"
+       done
+}
+
+if [ -z "$1" ]; then
+       usage
+fi
+
+kver=$1
+
+moduledir=/lib/modules/$kver
+
+if ! [ -d "$moduledir" ]; then
+       echo "module directory for kernel \`\`$kver'' does not exist." 1>&2
+       usage
+fi
+
+kmods=(`find $moduledir/kernel/fs $moduledir/kernel/drivers/md \
+       -type f -name '*.ko' -exec basename {} .ko \;`)
+
+paths=()
+
+while [ $#kmods -gt 0 ]; do
+       i=${kmods[1]}
+       kmods=(${kmods[2,-1]})
+
+       info=`modinfo -k $kver $i`
+       paths+=`echo $info | sed -n 's/^filename:[[:space:]]*//p'`
+       
+       kmods+=(${(s.,.)$(echo $info | sed -n 's/^depends:[[:space:]]*//p')})
+done
+
+echo "dir  $moduledir 0755 0 0"
+echo "file $moduledir/modules.dep   $moduledir/modules.dep   0644 0 0"
+echo "file $moduledir/modules.alias $moduledir/modules.alias 0644 0 0"
+for i in $paths; do
+       i=${i#$moduledir/}
+       out_mkdir_p $moduledir $(dirname $i)
+       echo "file $moduledir/$i $moduledir/$i 0644 0 0"
+done | sort -u
diff --git a/mpdbetter.sed b/mpdbetter.sed
new file mode 100755 (executable)
index 0000000..a59a4f8
--- /dev/null
@@ -0,0 +1,52 @@
+#!/bin/sed -f
+
+# Nick's mpdbetter `configuration file'.  Input a list of track titles, and
+# substitute each with the title of the best version of that song.
+
+# Handle special cases first
+/ -extra hot mix-/{s///;b}
+/ -Raven fly edit-/{s///;b}
+/ -2006 memorial mix-/{s///;b}
+/ -Practice Track-/{s///;b}
+/ On Air Ver\./{s///;b}
+/-\[instrumental\]/{s///;b}
+/ちいさなヘミソフィア/{s//ヘミソフィア/;b}
+/愛のメロディー/{s/\((.*)\)\?$/(soundtrack ver.)/;b}
+/COLORS -.*/{s//COLORS/;b}
+/ without NATSUMI/{s///;b}
+
+# Some literal replacements
+/松澤由美 - SNOW/c\
+島みやえい子 - SNOW -Album Mix-
+/詩月カオリ - Senecio/c\
+詩月カオリ - Senecio -Album Mix-
+/AKI - Pure Heart〜世界で一番アナタが好き〜/c\
+詩月カオリ - Pure Heart 〜世界で一番アナタが好き〜 -Remix-
+/open〜オルゴールバージョン〜/c\
+詩月カオリ - open
+/euphoric field/c\
+ELISA - euphoric field (Japanese)
+/La Clef 〜迷宮の鍵〜/c\
+KOTOKO - La Clef 〜迷宮の鍵〜
+
+# Sanitization
+s/「\(The Sore Feet Song\)」/\1/
+
+# General rules get most tracks
+/\s*[~〜<〈[(ー–−-]\s\?inst.*/I          {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?tv.*/I            {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?without.*/I       {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?w\/o.*/I          {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?off.*/I           {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?back.*/I          {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?short.*/I         {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?karaoke.*/I       {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?game.*/I          {s///;b}
+/\s*[~〜<〈[(ー–−-]\s\?[^ ]*カラオケ.*/I {s///;b}
+
+# When we lack brackets we match more specific strings
+/ instrumental.*/I {s///;b}
+/ off vocal.*/I    {s///;b}
+/ short.*/I        {s///;b}
+/ tv-\w\+/I        {s///;b}
+/ anime ver\./I    {s///;b}
diff --git a/mpdscripts.sh b/mpdscripts.sh
new file mode 100755 (executable)
index 0000000..ad390f3
--- /dev/null
@@ -0,0 +1,239 @@
+#!/bin/zsh
+#
+# Collection of shell functions for manipulating MPD.  Functions prefixed with
+# __ are intended for use in these scripts, whereas functions prefixed with
+# "mpd" are intended to be called by users.
+#
+# This file may be sourced by your shell startup scripts in order to load all
+# the functions into the environment, or it may be invoked as an executable.
+# The first argument to the script designates the function, with or without
+# the leading "mpd".  Subsequent arguments are passed to the called function.
+#
+# For example, you might run:
+#   `source mpdscripts.sh' followed by `mpdlist mycoolsong'
+# or equivalently:
+#   `./mpdscripts.sh list mycoolsong'.
+# The latter form is useful when not invoking the scripts from a shell.
+#
+# This version specifies the functions:
+#   mpdnext, mpdbetter, mpdlist, mpdalbum, and mpdshow.
+#
+# See the comments above each function for more details.
+#
+# Requires mpc, GNU grep and GNU sed.
+# Works with zsh or bash.
+#
+# Send questions or comments to nbowler@draconx.ca, or find me on IRC as
+# Draconx on irc.freenode.net.
+#
+# Licensed under the terms of the Do What The Fuck You Want To Public License.
+#
+##############################################################################
+
+__mpd_playlist()
+{
+       mpc --format='%position%) %artist% - %title%' playlist
+}
+
+# __mpd_trackid [regexp]
+# With a regular expression as an argument, search the MPD playlist for the
+# track matching the expression and print the index of that track.  Otherwise,
+# print the index of the currently playing track.
+__mpd_trackid()
+{
+       local id
+
+       if [ -z "$1" ]; then
+               id=`mpc | sed -n "2{s/.*#//;s/\/.*//p}"`
+       else
+               id=`__mpd_playlist | sed -n \
+                       "/${1//\//\\\/}/I{s/^[^[:digit:]]//;s/).*//p;q}"`
+       fi
+
+       [ -z "$id" ] && return 1
+
+       echo "$id"
+       return 0
+}
+
+# __mpd_trackname [id]
+# With a track ID as an argument, print the title of that track.  Otherwise,
+# print the title of the currently playing track.
+__mpd_trackname()
+{
+       local title
+
+       if [ -z "$1" ]; then
+               title=`mpc | sed -n "1h;2{g;p;q}"`
+       else
+               title=`__mpd_playlist | sed -n \
+                       "/^[^[:digit:]]*$1)/s/^.[0-9]*) //p"`
+       fi
+
+       [ -z "$title" ] && return 1
+
+       echo "$title"
+       return 0
+}
+
+# mpdnext <regexp> [advance]
+# Searches the playlist for a track matching <regexp>, then moves it to the
+# position following the currently playing track.  If [advance] is a non-empty
+# string, also run `mpc next' to play the moved track immediately.
+mpdnext()
+{
+       local index target name
+
+       if [ -z "$1" ]; then
+               echo "usage: mpdnext <regexp>"
+               return 1
+       fi
+
+       if ! index=`__mpd_trackid`; then
+               echo "mpdnext: MPD is currently stopped."
+               return 1
+       fi
+
+       if ! target=`__mpd_trackid "$1"`; then
+               echo "mpdnext: target not found."
+               return 1
+       fi
+
+       name=`__mpd_trackname $((target))`
+
+       if [ $target -lt $index ]; then
+               mpc move $target $index
+       elif [ $target -gt $index ]; then
+               mpc move $target $((index+1))
+       else
+               echo "mpdnext: selected the playing track"
+               return 1
+       fi
+
+       echo "mpdnext: $name moved."
+
+       # Play track if desired
+       [ -n "$2" ] && mpc next
+
+       return 0
+}
+
+# mpdbetter [sedscript]
+# Processes the title of the currently playing song through the sed program
+# specified by [sedscript] (or ~/.mpdbetter if not specified).  If the
+# resulting title is different, attempt to find it in the playlist and use
+# mpdnext to play it immediately.
+mpdbetter()
+{
+       local title better script="$HOME/.mpdbetter"
+       [ -n "$1" ] && script="$1"
+
+       if ! title=`__mpd_trackname`; then
+               echo "mpdbetter: MPD is currently stopped."
+               return 1
+       fi
+
+       if ! better=`echo "$title" | sed -f "$script"`; then
+               echo "mpdbetter: error in script: \`$script'"
+               return 1
+       fi
+
+       if [ "$better" = "$title" ]; then
+               echo "mpdbetter: nothing to be done."
+               return 1
+       fi
+
+       mpdnext ") $better\$" next
+}
+
+# mpdlist [regexp]
+# Simply search the playlist for tracks matching [regexp], or print the entire
+# playlist if [regexp] is not specified.
+mpdlist()
+{
+       if [ -z "$1" ]; then
+               __mpd_playlist
+       else
+               __mpd_playlist | grep --color=auto -i -- "$1"
+       fi
+}
+
+# mpdshow
+# Display the currently playing track as well as the part of the playlist
+# surrounding that track.
+mpdshow()
+{
+       local index
+
+       if ! index=`__mpd_trackid`; then
+               echo "mpdshow: MPD is currently stopped."
+               return 1
+       fi
+
+       mpc
+       echo
+       __mpd_playlist | grep -C 5 --color=auto "^$index)"
+}
+
+# mpdalbum <regexp>
+# Search the playlist for tracks belonging to an album matching <regexp>.
+# Print those tracks grouped by album and sorted by track number.
+mpdalbum()
+{
+       local current list
+
+       if [ -z "$1" ]; then
+               echo "usage: mpdalbum <regexp>"
+               return 1
+       fi
+
+       # This horrible hack grabs the relevant playlist entries and separates
+       # desired fields with @!@ and !@!.
+       list="`mpc --format $'\n%album%\n%track%\n%artist% - %title%' playlist \
+               | sed -n "
+                       /^.[0-9]*) $/{
+                               h;n
+                               /${1//\//\\\/}/I{
+                                       x;G;s/$/@!@/
+                                       N;s/$/!@!/
+                                       N;s/\n//g
+                                       p
+                               }
+                       }
+               "
+       `"
+
+#      list="`mpc --format '%album%@!@%track%!@!%artist% - %title%' playlist |\
+#              sed -n 'h;s/@!@.*//;'"/${1//\//\\\/}/I{g;p}" | sort -k 2`"
+       
+       if [ -z "$list" ]; then
+               echo "mpdalbum: no matches for \`$1'"
+               return 1
+       fi
+       
+       echo "$list" | while read i; do
+               local album="`echo $i | sed 's/.[0-9]*) \(.*\)@!@.*/\1/'`"
+               local index="`echo $i | sed 's/[# >]\?\([0-9]*\)).*/\1/'`"
+               local title="`echo $i | sed 's/.*!@!//'`"
+
+               if [ "$album" != "$current" ]; then
+                       [ -n "$current" ] && echo
+                       echo "$album"
+                       current="$album"
+               fi
+
+               echo -e " $index)\t$title"
+       done
+}
+
+# For executable-like invocation...
+
+# It would be nice if we could detect whether we are invoked as an executable
+# and print a usage message if not given any arguments.  I have yet to find
+# a clean way to do this, however.
+
+if [ $# -gt 0 ]; then
+       func="mpd${1#mpd}"
+       shift
+       "$func" $@
+fi
diff --git a/mplus-t-gen.py b/mplus-t-gen.py
new file mode 100755 (executable)
index 0000000..d95702a
--- /dev/null
@@ -0,0 +1,38 @@
+#!/usr/bin/env python
+# coding=utf-8
+#
+# Copyright © 2011 Nick Bowler
+#
+# Generates new M+ fonts with the CJK characters enlarged, based on the IPAG
+# versions.  This gives better proportions relative to DejaVu Sans Mono in
+# rxvt-unicode.
+#
+# Run this script in a directory containing the M+ fonts.  The new fonts will
+# be called M+1T+IPAG and M+2T+IPAG.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+import fontforge as ff
+import psMat
+import re
+
+families = [ "M+1M+IPAG", "M+2M+IPAG" ]
+scripts  = [ "hani", "kana" ]
+
+for family in families:
+       font = ff.open(family + ".ttf")
+
+       font.familyname = re.sub(r"(\d)M", r"\1T", font.familyname)
+       font.fontname   = font.familyname + "-Regular"
+       font.fullname   = font.familyname + " Regular"
+
+       for glyph in font.selection.all().byGlyphs:
+               for s in scripts:
+                       if (glyph.script == s):
+                               glyph.transform(psMat.scale(1.35))
+
+       print "Generating " + font.familyname + ".ttf"
+       font.generate(font.familyname + ".ttf")
+       font.close()
diff --git a/musicstats.zsh b/musicstats.zsh
new file mode 100755 (executable)
index 0000000..c5b9a95
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/env zsh
+#
+# Copyright © 2009 Nick Bowler
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+sizes=0
+while getopts 's' opt $@; do
+       case $opt in
+       s) sizes=1 ;;
+       \?) exit 1 ;;
+       esac
+done
+
+shift $((OPTIND-1))
+
+if [[ $# == 0 ]]; then
+       printf 'usage: %s [-s] directory [directory ...]\n' $0
+       exit 1
+fi
+
+alias mfind='find $@ -type f'
+flac=`mfind -name '*.flac' | wc -l`
+vorbis=`mfind -name '*.ogg' | wc -l`
+mp3=`mfind -name '*.mp3' | wc -l`
+total=$((flac+vorbis+mp3))
+
+if [[ $total == 0 ]]; then
+       printf '0 tracks.\n'
+       exit
+fi
+
+printf '%d tracks: %d (%.1f%%) flac, %d (%.1f%%) vorbis, %d (%.1f%%) mp3.\n' \
+       $total \
+       $flac   $((100.0*flac  /total)) \
+       $vorbis $((100.0*vorbis/total)) \
+       $mp3    $((100.0*mp3   /total))
+
+if [[ $sizes == 1 ]]; then
+       alias getsize="du -mc --files0-from=- | sed -n '\$s/\ttotal$//p'"
+       float totalsize=`mfind -print0 | getsize`
+       float flacsize=`mfind -name '*.flac' -print0 | getsize`
+       float vorbissize=`mfind -name '*.ogg' -print0 | getsize`
+       float mp3size=`mfind -name '*.mp3' -print0 | getsize`
+
+       if [[ $totalsize -gt 4000 ]]; then
+               printf 'size: %.1fG total, %.1fG flac, %.1fG vorbis, %.1fG mp3.\n' \
+                       $((totalsize/1024)) \
+                       $((flacsize/1024)) \
+                       $((vorbissize/1024)) \
+                       $((mp3size/1024))
+       else
+               printf 'size: %.1fM total, %.1fM flac, %.1fM vorbis, %.1fM mp3.\n' \
+                       $((totalsize)) \
+                       $((flacsize)) \
+                       $((vorbissize)) \
+                       $((mp3size))
+       fi
+fi
diff --git a/openexec.c b/openexec.c
new file mode 100644 (file)
index 0000000..8cce5f9
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2011 Nick Bowler
+ *
+ * The Mutt email client opens mail attachments with external programs
+ * synchronously: the attachment is decoded and saved to /tmp, the filename
+ * is passed to the program to be run, and when the program exits, the file
+ * is unlinked.  This leads to an obvious problem: if the attachment-viewing
+ * program runs in the foreground, one cannot interact with mutt until you
+ * quit it.  If the program runs in the background, then there is a race
+ * between the program opening the file and mutt unlinking it.
+ *
+ * This tool solves this problem by opening all files and spawning a program
+ * in the background.  It is safe to unlink the files after they are opened,
+ * so the race with mutt is avoided.
+ *
+ * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+ * This is free software: you are free to do what the fuck you want to.
+ * There is NO WARRANTY, to the extent permitted by law.
+ */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <fcntl.h>
+
+static const char *progname = "openexec";
+static const char sopts[] = "-VH";
+static const struct option lopts[] = {
+       { "version", 0, NULL, 'V' },
+       { "help",    0, NULL, 'H' },
+       { 0 }
+};
+
+static void print_version(void)
+{
+       puts("openexec version 1.0");
+       puts("\
+Copyright (C) 2011 Nick Bowler.\n\
+License WTFPL2: Do What The Fuck You Want To Public License, version 2.\n\
+This is free software: you are free to do what the fuck you want to.\n\
+There is NO WARRANTY, to the extent permitted by law.\
+       ");
+}
+
+static void print_usage(FILE *f)
+{
+       fprintf(f, "Usage: %s [options] [file ...] -- program [arguments]\n",
+                  progname);
+}
+
+static void print_help(void)
+{
+       print_usage(stdout);
+       puts("Detailed help coming eventually.");
+}
+
+static char *fake_open(const char *filename)
+{
+       char *buf;
+       int n, fd;
+
+       fd = open(filename, O_RDONLY);
+       if (fd == -1) {
+               fprintf(stderr, "%s: %s: %s\n", progname, filename,
+                                               strerror(errno));
+               return NULL;
+       }
+
+       n = snprintf(NULL, 0, "/proc/self/fd/%d", fd);
+       buf = malloc(n+1);
+       if (!buf) {
+               close(fd);
+               fprintf(stderr, "%s: %s\n", progname, strerror(errno));
+               return NULL;
+       }
+
+       sprintf(buf, "/proc/self/fd/%d", fd);
+       return buf;
+}
+
+int main(int argc, char **argv)
+{
+       int nargs = 0, opt, rc, err, fds[2];
+
+       if (argc > 0)
+               progname = argv[0];
+
+       char *args[argc];
+
+       while ((opt = getopt_long(argc, argv, sopts, lopts, NULL)) != -1) {
+               switch (opt) {
+               case 1:
+                       args[nargs] = fake_open(optarg);
+                       if (!args[nargs])
+                               return EXIT_FAILURE;
+                       nargs++;
+                       break;
+               case 'V':
+                       print_version();
+                       return EXIT_SUCCESS;
+               case 'H':
+                       print_help();
+                       return EXIT_SUCCESS;
+               default:
+                       print_usage(stderr);
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (!argv[optind]) {
+               print_usage(stderr);
+               return EXIT_FAILURE;
+       }
+
+       args[nargs] = NULL;
+       memmove(args + (argc - optind), args, (nargs + 1) * sizeof *args);
+       memcpy(args, argv + optind, (argc - optind) * sizeof *args);
+
+       /*
+        * We use a close-on-exec pipe for the child to signal success/failure
+        * to the parent.  On successful exec, the write end of the pipe will
+        * be closed, causing the read in the parent to return 0.  On failure,
+        * errno will be written to the pipe, allowing the parent to print
+        * an error message.
+        */
+       rc = pipe2(fds, O_CLOEXEC);
+       if (rc == -1) {
+               fprintf(stderr, "%s: pipe2: %s\n", progname, strerror(errno));
+               return EXIT_FAILURE;
+       }
+
+       switch (fork()) {
+       case -1:
+               fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
+               return EXIT_FAILURE;
+       case 0:
+               execvp(args[0], args);
+
+               /* This horrible if statement shuts up GCC... */
+               err = errno;
+               if (write(fds[1], &err, sizeof err))
+                       ;
+               _Exit(EXIT_FAILURE);
+       }
+
+       close(fds[1]);
+       rc = read(fds[0], &err, sizeof err);
+       if (rc == -1) {
+               /* No information about the child's state. */
+               fprintf(stderr, "%s: read: %s\n", progname, strerror(errno));
+               return EXIT_FAILURE;
+       } else if (rc == 0) {
+               /* Exec was successful, so we are too. */
+               return EXIT_SUCCESS;
+       }
+
+       /* Exec in the child failed, print the error we received on the pipe. */
+       fprintf(stderr, "%s: %s: %s\n", progname, args[0], strerror(err));
+       return EXIT_FAILURE;
+}
diff --git a/polya.tex b/polya.tex
new file mode 100644 (file)
index 0000000..4a32eb9
--- /dev/null
+++ b/polya.tex
@@ -0,0 +1,72 @@
+\documentclass{article}
+
+\usepackage{fullpage}
+\usepackage{amssymb}
+\usepackage{tikz}
+
+% Peano Curve of Polya
+\newcounter{polyax}
+\newcounter{polyay}
+\newcounter{polyaz}
+\newcounter{polyap}
+
+\newcommand{\polyafig}[3]{
+  \coordinate (p0) at (#1);
+  \coordinate (p1) at +(0:#2);
+  \coordinate (p2) at (intersection cs:
+    first line={(p0)--+(60:1)},
+    second line={(p1)--($(p1)!1!150:(p0)$)});
+  \draw (p0) -- (p1) -- (p2) --cycle;
+
+  \coordinate (p3) at ($(p0)!(p2)!(p1)$);
+  \draw[densely dotted] (p2) -- (p3);
+
+  \setcounter{polyax}{0}
+  \setcounter{polyay}{2}
+  \setcounter{polyaz}{1}
+  \setcounter{polyap}{3}
+
+  \foreach \d in {#3} {
+    \pgfmathtruncatemacro{\x}{\thepolyax}
+    \pgfmathtruncatemacro{\y}{\thepolyay}
+    \pgfmathtruncatemacro{\z}{\thepolyaz}
+
+    \ifthenelse{\equal{\d}{1}}{
+      \pgfmathtruncatemacro{\xx}{\y}
+      \pgfmathtruncatemacro{\zz}{\z}
+    }{
+      \pgfmathtruncatemacro{\xx}{\x}
+      \pgfmathtruncatemacro{\zz}{\y}
+    }
+    \pgfmathtruncatemacro{\yy}{\y+1}
+
+    \pgfmathtruncatemacro{\v}{\yy+1}
+    \coordinate (p\v) at
+      ($(p\xx)!(p\yy)!(p\zz)$);
+    \draw[densely dotted] (p\yy) -- (p\v);
+
+    \setcounter{polyax}{\xx}
+    \setcounter{polyay}{\yy}
+    \setcounter{polyaz}{\zz}
+    \setcounter{polyap}{\v}
+  }
+}
+
+\title{The Peano Curve of P\'olya}
+\author{}
+\date{}
+
+\begin{document}
+\maketitle
+
+A \emph{Peano Curve} is a curve which hits every point in a two-dimensional
+object.  Recall that a curve is a continuous function
+\[
+f : [0,1] \to \mathbb{R}^2.
+\]
+A famous example of such a curve is due to George P\'olya, which fills a
+right-angled triangle.  For $x \in [0,1)$, let $\{a_n\}^\infty_{n=0}$ be the
+sequence of digits after the decimal point in its binary expansion.  If there
+are multiple binary expansions, either will do (the result is the same).
+
+\end{document}
diff --git a/quine.hs b/quine.hs
new file mode 100644 (file)
index 0000000..e75a8f9
--- /dev/null
+++ b/quine.hs
@@ -0,0 +1,2 @@
+listing = "main = putStr \"listing = \" >> print listing >> putStrLn listing"
+main = putStr "listing = " >> print listing >> putStrLn listing
diff --git a/quine.sed b/quine.sed
new file mode 100755 (executable)
index 0000000..af00345
--- /dev/null
+++ b/quine.sed
@@ -0,0 +1,28 @@
+#!/bin/sed -nf
+# A quine for GNU sed.
+s:.*:   i\\\
+        #!/bin/sed -nf\\\
+        # A quine for GNU sed.\
+        h\
+        s/\\\\/\\\\\\\\/g\
+        s/\&/\\\\\&/g\
+        s/\:/\\\\\:/g\
+        s/\\n/\\\\\\n/g\
+        s/.*/s\:.*\:\&\:/\
+        p\
+        g\
+        s/ \\{2,\\}//g\
+        p:
+i\
+#!/bin/sed -nf\
+# A quine for GNU sed.
+h
+s/\\/\\\\/g
+s/&/\\&/g
+s/:/\\:/g
+s/\n/\\\n/g
+s/.*/s:.*:&:/
+p
+g
+s/ \{2,\}//g
+p
diff --git a/replaygain.zsh b/replaygain.zsh
new file mode 100755 (executable)
index 0000000..89b293f
--- /dev/null
@@ -0,0 +1,64 @@
+#!/usr/bin/env zsh
+#
+# Copyright (C) 2009 Nick Bowler
+#
+# Adds replaygain tags to the flac files in a directory.  Assumes that all
+# the tracks from a CD are located in the same directory.  Unless the -f flag
+# is specified, directories already containing replaygain tags will not be
+# processed.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+alias flactags='metaflac --export-tags-to=-'
+
+is_disc_dir() {
+       local files
+
+       [[ -d $1 ]] || return 1
+
+       files=($1/*.flac(N))
+       [[ $#files > 0 ]] || return 1
+}
+
+has_replay_gain() {
+       local files
+
+       files=($1/*.flac(N))
+       for i in $files; do
+               (flactags $i | grep -q REPLAYGAIN_REFERENCE) || return 1
+       done
+}
+
+force=0
+while getopts 'f' opt $@; do
+       case $opt in
+       f) force=1 ;;
+       \?) exit 1 ;;
+       esac
+done
+
+shift $((OPTIND-1))
+
+if [[ $# == 0 ]]; then
+       printf 'usage: %s [-f] directory [directory ...]\n' $0
+       exit 1
+fi
+
+for dir in $@; do
+       printf '%s: ' $dir
+
+       if ! is_disc_dir $dir; then
+               printf 'not an album directory, skipping.\n'
+               continue
+       fi
+
+       if [[ $force == 0 ]] && has_replay_gain $dir; then
+               printf 'already done, skipping.\n'
+               continue
+       fi
+
+       metaflac --add-replay-gain $dir/*.flac
+       printf 'done.\n'
+done
diff --git a/runcron.zsh b/runcron.zsh
new file mode 100755 (executable)
index 0000000..8248728
--- /dev/null
@@ -0,0 +1,24 @@
+#!/usr/bin/env zsh
+#
+# Copyright © 2011 Nick Bowler
+#
+# Simple script to dispatch jobs in /etc/cron.whatever.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+crondir=/etc/cron.$1
+
+if ! [[ -d $crondir ]]; then
+       printf '%s: argument must be one of:' $0
+       for i in /etc/cron.*; do
+               if ! [[ -d $i ]]; then continue; fi
+               printf ' %s' ${i#/etc/cron.}
+       done
+       echo .
+
+       exit 1
+fi
+
+run-parts --verbose --regex='^[^.][[:alnum:]_.-]+$' $crondir
diff --git a/spamassassin.zsh b/spamassassin.zsh
new file mode 100755 (executable)
index 0000000..becf6b6
--- /dev/null
@@ -0,0 +1,29 @@
+#!/usr/bin/env zsh
+# 
+# Copyright © 2011 Nick Bowler
+#
+# Check mail for spam, automatically spawning spamd as necessary.  This
+# script can therefore be used in a procmail recipe to efficiently handle
+# spam filtering.
+#
+# Runs plain old spamassassin if the daemon cannot be started for any reason.
+#
+# License WTFPL2: Do What The Fuck You Want To Public License, version 2.
+# This is free software: you are free to do what the fuck you want to.
+# There is NO WARRANTY, to the extent permitted by law.
+
+spamd_sock=$HOME/.spamd
+spamd_log=$HOME/.spamdlog
+spamd_pid=$HOME/.spamdpid
+spamd=/usr/sbin/spamd
+
+run_spamd() {
+       flock -n $spamd_pid $spamd --pidfile=$spamd_pid --syslog=$spamd_log \
+                                  --socketpath=$spamd_sock $@
+}
+
+if ! spamc -K -U $spamd_sock &>/dev/null; then
+       run_spamd --daemonize || exec spamassassin
+fi
+
+exec spamc -U $spamd_sock