changeset 139:e33f37b14893 default tip

Port to 'no-more-make' https://github.com/GrahamStJack/no-more-make
author David Bryant <bagnose@gmail.com>
date Sun, 30 Sep 2012 15:41:25 +0930
parents a1c2b56cb44d
children
files bob.cfg configure.d configure.sh doodle/main/Bobfile doodle/main/chess.d doodle/main/doodle.d doodle/main/dupes.d doodle/main/util/chess.d doodle/main/util/doodle.d doodle/main/util/dupes.d doodle/tk/Bobfile gtk nobuild/Boboptions nobuild/make-tags.sh
diffstat 14 files changed, 791 insertions(+), 726 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/bob.cfg	Sun Sep 30 15:41:25 2012 +0930
@@ -0,0 +1,155 @@
+###############################################################################
+
+# Example bob configuration file.
+#
+# Used by 'bob-config' to establish a build directory, from which a 'bob'
+# command will build your project.
+#
+# This file should be located at the top level of a repository, below which
+# are source directories.
+#
+# Before running bob-config, you need to:
+# * Check out the project's source repository(s).
+# * Ensure that all the project's external dependencies are available,
+#   either in standard system locations or in local project-specific
+#   locations.
+# Bob does not verify external dependencies.
+#
+# If your project is built for a number of target architectures, use
+# one config file for each architecture, and specify which one on the bob-config
+# command-line.
+#
+###############################################################################
+#
+# Top-level syntax is a series of sections, each starting with a line:
+# [section-name]
+#
+# Comment lines begin with '#'.
+#
+# The syntax for each section is section-specific, and described in each
+# section.
+#
+###############################################################################
+
+
+[defines]
+
+# Define variables.
+#
+# Any relative paths provided in variable definitions are relative to
+# the directory this file is in, which is also the working directory
+# of bob-config.
+#
+# A variable definition is: name = text
+#
+# Variables used by bob are:
+#
+#   PROJECT  - Path to directory containing the project's top-level Bobfile.
+#   REPOS    - Paths to other repos (if any), below which are source
+#              directories that are available to build as part of this project.
+#   SYS_INC  - Non-standard paths searched for system includes.
+#   SYS_LIB  - Non-standard paths searched for system libraries.
+#   SYS_PATH - Non-standard paths searched for system utilities.
+#   SYS_IMP  - Non-standard paths searched for D imports.
+#   C_EXTERN - Top-level C/C++ packages that are external to the project.
+#   D_EXTERN - Top-level D packages that are external to the project.
+#
+# Also required are build commands.
+#
+# Build-command variables are used by bob to create the output files specified
+# in the project's Bobfile(s). They are of the form:
+#     <input-ext> <output-ext>(s) = command
+# Reserved extensions with special meaning are:
+#     .obj  -> object file
+#     .slib -> static library
+#     .dlib -> dynamic library
+#     .exe  -> executable
+# The extensions actually used vary with platform.
+# Libraries and executables are built from object files.
+#
+# The commands that use object files to create libraries and executables are
+# specified with the extension of the source files, not .obj.
+# .c source files may be mixed with other types of source files,
+# but others may not. .h files are assumed to be header files.
+#
+# Reserved variables defined by bob from information in Bobfiles are:
+#
+#   INPUT    - Paths of the input file(s) relative to the build dir.
+#   OUTPUT   - Paths of the resultant built file(s) relative to the build dir.
+#   PROJ_INC - Project include or import paths.
+#   PROJ_LIB - Project library paths.
+#   LIBS     - Required libraries.
+#
+# ${} expands a variable, cross-multiplying it with whatever it is adjacent to.
+# eg, if HEADERS = one two three, then -I${HEADERS} becomes -Ione -Itwo -Ithree.   
+# If the variable is empty, the cross-multiplication is also empty.
+# If there is no adjacent text, the variable's value is used.
+# Variable expansion occurs just before a build command is issued, after
+# all dependencies are known.
+
+# Required
+PROJECT  = doodle
+REPOS    =
+SYS_IMP  =
+SYS_INC  =
+SYS_LIB  =
+SYS_PATH =
+C_EXTERN =
+D_EXTERN = core std glib gdk gtk gtkc cairo
+
+# Compiler switches
+CFLAGS     = -fpic -pedantic -Werror -Wall -Wno-long-long -Wundef -Wredundant-decls -DFILE_PATH=${INPUT}
+C++FLAGS   = ${CFLAGS} -Woverloaded-virtual -Wsign-promo -Wctor-dtor-privacy -Wnon-virtual-dtor
+DFLAGS     = -w -wi -gc -Isrc/gtk
+LINKFLAGS  =
+DLINKFLAGS = -L-L/home/dbryant/source/d/GtkD
+
+# Build commands
+
+# Contrived example of source-code generation.
+.H .h     = cp ${INPUT} ${OUTPUT}
+.CPP .cpp = cp ${INPUT} ${OUTPUT}
+
+# Documentation
+.rst .html = rst2html ${INPUT} ${OUTPUT}
+
+# Object files
+.c   .obj = gcc -c ${INPUT} -isystem${SYS_INC} -iquote${PROJ_INC} ${CFLAGS}   -o ${OUTPUT}
+.cpp .obj = g++ -c ${INPUT} -isystem${SYS_INC} -iquote${PROJ_INC} ${C++FLAGS} -o ${OUTPUT}
+.d   .obj = dmd -c ${INPUT} -I${SYS_IMP}            -I${PROJ_INC} ${DFLAGS}   -of${OUTPUT}
+
+# Static libraries
+.c   .slib = rm -f ${OUTPUT} && ar csr ${OUTPUT} ${INPUT} 
+.cpp .slib = rm -f ${OUTPUT} && ar csr ${OUTPUT} ${INPUT} 
+.d   .slib = rm -f ${OUTPUT} && ar csr ${OUTPUT} ${INPUT} 
+
+# Dynamic libraries
+.c   .dlib = gcc -shared ${INPUT} ${LINKFLAGS} -L${SYS_LIB} -L${PROJ_LIB} -l{LIBS} -o ${OUTPUT}
+.cpp .dlib = g++ -shared ${INPUT} ${LINKFLAGS} -L${SYS_LIB} -L${PROJ_LIB} -l{LIBS} -o ${OUTPUT}
+
+# Executables
+.c   .exe = gcc ${INPUT} ${LINKFLAGS}  -L${SYS_LIB}   -L${PROJ_LIB}   -l${LIBS}   -o ${OUTPUT}
+.cpp .exe = g++ ${INPUT} ${LINKFLAGS}  -L${SYS_LIB}   -L${PROJ_LIB}   -l${LIBS}   -o ${OUTPUT}
+.d   .exe = dmd ${INPUT} ${DLINKFLAGS} -L-L${SYS_LIB} -L-L${PROJ_LIB} -L-l${LIBS} -of${OUTPUT}
+
+[modes]
+
+# For each mode, add to already-defined variables.
+# Format of a mode is: the name of the mode, followed by indented
+# variable additions. eg:
+#
+# debug
+#     CFLAGS += ggdb3
+#
+# Exactly one mode is in use for a given build directory, and is specified
+# on the bob-config command line. eg:  mode=debug
+
+debug
+    CFLAGS   += -O1 -ggdb3
+    C++FLAGS += -O1 -ggdb3
+    DFLAGS   += 
+
+release
+    CFLAGS   += -O2 -NDEBUG
+    C++FLAGS += -O2 -NDEBUG
+    DFLAGS   += -O  -release
--- a/configure.d	Sun Sep 30 15:25:53 2012 +0930
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-//
-// Configure script for the reuse repo
-//
-
-import configure_functions;
-
-import std.process;
-import std.string;
-import std.file;
-
-
-void main(string args[]) {
-    auto data = initialise(args, "doodle");
-
-    //
-    // open
-    //
-
-    /*
-    // libssh2 and dependencies required by net
-    usePackage(data, "libssh2", Constraint.AtLeast, "1.2");
-    useHeader( data, "gcrypt.h");
-    useLibrary(data, "libgcrypt.so");
-    */
-    
-    // TAO is required by corba-tao
-    //useTao(data);
-
-
-    //
-    // reuse
-    //
-
-    /*
-    usePackage(data, "libxml-2.0");
-    usePackage(data, "libpng");
-    usePackage(data, "freetype2");
-    usePackage(data, "gtkmm-2.4", Constraint.AtLeast, "2.18");
-    usePackage(data, "gtkglext-1.0");
-    usePackage(data, "gstreamer-0.10", Constraint.AtLeast, "0.10.22");
-    usePackage(data, "gstreamermm-0.10", Constraint.AtLeast, "0.10.1");
-    usePackage(data, "xv");
-    usePackage(data, "xext");
-    usePackage(data, "xextproto");
-    usePackage(data, "neon", Constraint.AtLeast, "0.28.2");
-    usePackage(data, "libconfig", Constraint.AtLeast, "1.3.1");
-    usePackage(data, "libconfig++", Constraint.AtLeast, "1.3.1");
-
-    useHeader( data, "jpeglib.h");
-    useLibrary(data, "libjpeg.so");
-
-    useExecutable(data, "IMAGE_MAGICK_CONVERT", ["convert"]);
-    useExecutable(data, "ZIP", ["zip"]);
-    */
-
-    /*
-    appendBobVar(data, "CCFLAGS",
-                 ["-DGTKMM_MACRO_SHADOW_ERROR",
-                 "-DGTKMM_DISABLE_DEPRECATED",
-                 "-DGDKMM_DISABLE_DEPRECATED",
-                 "-DGLIBMM_DISABLE_DEPRECATED",
-                 "-DGDK_DISABLE_DEPRECATED",
-                 "-DG_DISABLE_DEPRECATED",
-                 "-DLIBSIGC_DISABLE_DEPRECATED",
-                 "-DGTK_DISABLE_DEPRECATED",
-                 "-DGSEAL_ENABLE"]);
-                 */
-
-    /*
-    if (exists("/opt/acacia/ecw")) {
-        string[][Use] dirs;
-        dirs[Use.Inc] = ["/opt/acacia/ecw/include"];
-        dirs[Use.Lib] = ["/opt/acacia/ecw/lib"];
-        setProjectDirs(data, dirs);
-
-        useHeader( data, "NCSFile.h");
-        useLibrary(data, "libNCSUtil.so");
-        useLibrary(data, "libNCSCnet.so");
-        useLibrary(data, "libNCSEcw.so");
-
-        appendBobVar(data, "CCFLAGS",       ["-DUSE_ECW_CHARTING_RASTER_SOURCE"]);
-        appendBobVar(data, "ECW_LIBRARIES", ["NCSEcw", "NCSUtil", "NCSCnet"]);
-    }
-    */
-
-
-    /*
-   appendRunVar(data, "GST_PLUGIN_PATH", ["${DIST_PATH}/lib/plugins"]);
-   */
-   
-   
-   finalise(data, [/*"open"*/]);
-}
--- a/configure.sh	Sun Sep 30 15:25:53 2012 +0930
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,2 +0,0 @@
-#!/bin/bash
-rdmd -I. -Ibuild-tool configure.d $@
--- a/doodle/main/Bobfile	Sun Sep 30 15:25:53 2012 +0930
+++ b/doodle/main/Bobfile	Sun Sep 30 15:41:25 2012 +0930
@@ -1,7 +1,7 @@
 refer doodle/core doodle/dia doodle/fig doodle/gtk ;
 
-dist-util chess : chess.d ;
+dist-exe chess : chess.d ;
 
-dist-util dupes : dupes.d : ;
+dist-exe dupes : dupes.d : ;
 
-dist-util doodle : doodle.d : dl gtkd ;
+dist-exe doodle : doodle.d : dl gtkd ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doodle/main/chess.d	Sun Sep 30 15:41:25 2012 +0930
@@ -0,0 +1,266 @@
+//
+// Notes:
+//  ply = half move (ie black or white's half of the move)
+
+import std.stdio;
+import std.ascii;
+import std.traits;
+import std.range;
+
+enum Side {
+    White, Black
+}
+
+enum Name {
+    King, Queen, Rook, Bishop, Knight, Pawn
+}
+
+struct Piece {
+    Side side;
+    Name name;
+}
+
+string toString(Piece piece) {
+    return
+        [
+        [ "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659" ],
+        [ "\u265A", "\u265B", "\u265C", "\u265D", "\u265E", "\u265F" ]
+        ]
+        [piece.side][piece.name];
+}
+
+//
+//
+//
+
+enum File {
+    _A, _B, _C, _D, _E, _F, _G, _H
+}
+
+char toChar(File f) {
+    return "abcdefgh"[f];
+}
+
+enum Rank {
+    _1, _2, _3, _4, _5, _6, _7, _8
+}
+
+char toChar(Rank r) {
+    return "12345678"[r];
+}
+
+struct Coord {
+    File file;
+    Rank rank;
+}
+
+string toString(in Coord coord) {
+    return toChar(coord.file) ~ "+" ~ toChar(coord.rank);
+}
+
+//
+//
+//
+
+struct Board {
+    struct Square {
+        this(in Side side, in Name name) {
+            occupied = true;
+            piece = Piece(side, name);
+        }
+
+        bool  occupied = false;
+        Piece piece;        // valid if occupied
+    }
+
+    this(in Square[8][8] squares_) {
+        squares = squares_;
+    }
+
+    Square square(Coord coord) const {
+        return squares[coord.file][coord.rank];
+    }
+
+private:
+    Square * at(Coord coord) {
+        return &squares[coord.file][coord.rank];
+    }
+
+    void add(Piece piece, Coord coord) {
+        auto square = at(coord);
+        if (square.occupied) {
+            // error
+        }
+        else {
+            square.occupied = true;
+            square.piece    = piece;
+        }
+    }
+
+    void remove(Coord coord) {
+        auto square = at(coord);
+        if (square.occupied) {
+            square.occupied = false;
+        }
+        else {
+            // error
+        }
+    }
+
+    void move(Coord source, Coord dest) {
+        auto source_sq = at(source);
+        auto dest_sq = at(dest);
+
+        if (source_sq.occupied && !dest_sq.occupied) {
+            source_sq.occupied = false;
+            dest_sq.occupied = true;
+            dest_sq.piece = source_sq.piece;
+        }
+        else {
+            // error
+        }
+    }
+
+    Square[8][8] squares =
+        [
+        [ Square(Side.White, Name.Rook),   Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Rook)   ],
+        [ Square(Side.White, Name.Knight), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Knight) ],
+        [ Square(Side.White, Name.Bishop), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Bishop) ],
+        [ Square(Side.White, Name.Queen),  Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Queen)  ],
+        [ Square(Side.White, Name.King),   Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.King)   ],
+        [ Square(Side.White, Name.Bishop), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Bishop) ],
+        [ Square(Side.White, Name.Knight), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Knight) ],
+        [ Square(Side.White, Name.Rook),   Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Rook)   ]
+        ];
+}
+
+void dump(in Board board) {
+    bool light_square = true;
+
+    foreach_reverse(r; EnumMembers!Rank) {
+        write(toChar(r));
+        foreach(f; EnumMembers!File) {
+
+            if (light_square) {
+                write("\033[47m");
+            }
+            else {
+                write("\033[40m");
+            }
+
+            Board.Square square = board.square(Coord(f, r));
+            if (square.occupied) {
+                write(toString(square.piece));
+            }
+            else {
+                write(" ");
+            }
+
+            light_square = !light_square;
+        }
+        writeln("\033[0m");
+
+        light_square = !light_square;
+    }
+
+    write(" ");
+    foreach(f; EnumMembers!File) {
+        writef("%s", toChar(f));
+    }
+    writeln("");
+}
+
+//
+//
+//
+
+enum KingState {
+    Safe,
+    Check,
+    CheckMate
+}
+
+class Game {
+    struct SideState {
+        KingState kingState;
+        bool      kingMoved;
+        bool      queenRookMoved;
+        bool      kingRookMoved;
+    }
+
+    struct Ply {
+        this(Coord source_, Coord dest_) {
+            source = source_;
+            dest = dest_;
+        }
+
+        Coord source;
+        Coord dest;
+    }
+
+    @property Board board() { return _board; }
+
+    struct Flags {
+        bool check;
+        bool mate;
+    }
+
+    // Default initial pieces, white to play
+    this () {
+    }
+
+    // Restore a previous game
+    this (Board board, Flags whiteFlags, Flags blackFlags, Side nextPly) {
+        _board   = board;
+        _nextPly = nextPly;
+    }
+
+    enum Acceptance {
+        Normal,
+        Check,
+        Mate,
+        Illegal
+    }
+
+    Acceptance apply(in Ply ply) {
+        auto source = _board.square(ply.source);
+        auto dest   = _board.square(ply.dest);
+
+        /+
+        auto sq1 = square(update.source);
+        auto sq2 = square(update.dest);
+
+        if (sq1.piece == Piece.Pawn && update.dest.file != update.source.file) {
+            // en-passant
+        }
+        else if (sq1.piece == Piece.King && update.dest.file - update.source.file > 1) {
+            // castle
+        }
+        +/
+
+        return Acceptance.Normal;
+    }
+
+    private {
+        struct PieceState {
+            bool  uncaptured;
+            Coord coord;        // valid if uncaptured
+        }
+
+        Board         _board;
+        Side          _nextPly;
+        SideState     _whiteSideState;
+        PieceState[8] _whitePieceState;
+        SideState     _blackSideState;
+        PieceState[8] _blackPieceState;
+    }
+}
+
+void main(string[] args) {
+    Board board;
+    dump(board);
+
+    /+
+    Game game;
+    +/
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doodle/main/doodle.d	Sun Sep 30 15:41:25 2012 +0930
@@ -0,0 +1,114 @@
+module main.prog.doodler;
+
+// XXX bob problem, needs it to be like this...
+import doodle.core.backtrace;
+import doodle.core.logging;
+import doodle.core.backtrace;
+
+import doodle.dia.standard_tools;
+import doodle.dia.page_layer;
+import doodle.dia.grid_layer;
+import doodle.dia.tool_layer;
+
+import doodle.fig.diagram_layer;
+import doodle.fig.select_tool;
+
+import doodle.fig.tools;
+
+import doodle.gtk.palette;
+
+import doodle.gtk.cairo_canvas;
+
+private {
+    /*
+    import doodle.core.backtrace;
+    import doodle.core.logging;
+    import doodle.core.backtrace;
+
+    import doodle.dia.standard_tools;
+    import doodle.dia.page_layer;
+    import doodle.dia.grid_layer;
+    import doodle.dia.tool_layer;
+
+    import doodle.fig.diagram_layer;
+    import doodle.fig.select_tool;
+
+    import doodle.fig.tools;
+
+    import doodle.gtk.palette;
+
+    import doodle.gtk.cairo_canvas;
+    */
+
+    import gtk.Main;
+    import gtk.MainWindow;
+    import gtk.VBox;
+
+    import std.stdio;
+}
+
+final class TopLevel : /*private*/ IToolStackObserver {
+    this(string[] args) {
+        Main.init(args);
+        auto window = new MainWindow("Doodle");
+        auto vbox = new VBox(false, 0);
+
+        auto palette = new Palette!Tool;
+        _palette = palette;
+
+        vbox.packStart(palette, false, false, 0);
+
+        Tool[] tools;
+        tools ~= new PanTool;
+        tools ~= new ZoomTool;
+        tools ~= new SelectTool;
+        auto toolLayer = new ToolLayer(tools, this);
+        _toolStack = toolLayer;
+
+        auto gridLayer = new GridLayer;
+
+        auto diagramLayer = new DiagramLayer;
+        _diagram = diagramLayer;
+
+        Layer[] layers;
+        layers ~= new PageLayer;
+        layers ~= gridLayer;
+        layers ~= diagramLayer;
+        layers ~= toolLayer;
+
+        // assume the screen has PPI of 120.0
+        immutable millimetersPerInch = 25.4;
+        immutable pixelsPerMillimetre = 120.0 / millimetersPerInch;
+        auto canvas = new CairoCanvas(layers, toolLayer, gridLayer, pixelsPerMillimetre);
+
+        vbox.packStart(canvas, true, true, 0);
+
+        Palette!Tool.Item[] items = [
+        { "select.svg",    "Select",    "Select and modify elements", new SelectTool },
+        { "rectangle.svg", "Rectangle", "Create rectangle", new CreateRectangleTool(_diagram) },
+        { "ellipse.svg",   "Ellipse",   "Create ellipse", new CreateRectangleTool(_diagram) },
+        { "polyline.svg",  "Polyline",  "Create polyline", new CreateRectangleTool(_diagram) }
+        ];
+
+        palette.configure(items, &_toolStack.use);
+        window.add(vbox);
+        window.setDefaultSize(640, 580);
+        window.showAll();
+        Main.run();
+    }
+
+    void toolChanged(Tool tool) {
+        message("Tool changed %s", tool.name);
+        _palette.activate(tool);
+    }
+
+    private {
+        IToolStack _toolStack;
+        IPalette!Tool _palette;
+        IDiagram _diagram;
+    }
+}
+
+void main(string[] args) {
+    new TopLevel(args);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/doodle/main/dupes.d	Sun Sep 30 15:41:25 2012 +0930
@@ -0,0 +1,246 @@
+import std.stdio;
+import std.string;
+import std.exception;
+import std.algorithm;
+import std.file;
+import std.md5;
+import std.getopt;
+import std.conv;
+import std.ascii;
+import std.c.stdlib;
+
+ulong string_to_size(string s) {
+    // Convert strings to sizes, eg:
+    //   "50"   -> 50
+    //   "80B"  -> 80
+    //   "10K"  -> 10240
+    //   "1M"   -> 1048576
+    // Throws ConvException
+
+    immutable map = [ 'B':1UL, 'K':1UL<<10, 'M':1UL<<20, 'G':1UL<<30, 'T':1UL<<40 ];
+
+    if (s.length == 0) {
+        throw new ConvException("Empty string");
+    }
+    else {
+        ulong multiplier = 1;
+
+        if (isAlpha(s[$-1])) {
+            immutable ulong * m = (s[$-1] in map);
+
+            if (m) {
+                multiplier = *m;
+            }
+            else {
+                throw new ConvException(format("Bad size unit character: %s", s[$-1]));
+            }
+
+            s = s[0..$-1];
+        }
+
+        return multiplier * to!ulong(s);
+    }
+}
+
+string size_to_string(in ulong size) {
+    /+
+    immutable array = [ 'B', 'K', 'M', 'G', 'T' ];
+    size_t index = 0;
+
+    foreach (i, c; array) {
+        if (size / (1UL << i
+
+        writefln("%s %s", i, c);
+    }
+    +/
+
+    return format("%sK", size / 1024);
+}
+
+void find_duplicates(in string[] dirs,
+                     in ulong    file_size,
+                     in ulong    digest_size,
+                     bool        verbose) {
+    static ubyte[16] compute_md5(in string filename, in ulong max_bytes) {
+        size_t chunk_size = min(max_bytes, 4096 * 1024);
+        ubyte[16] digest;
+
+        auto file = File(filename, "r");
+        scope(exit) file.close();
+
+        MD5_CTX context;
+        context.start();
+        ulong byte_count = 0;
+        foreach (ubyte[] buffer; chunks(file, chunk_size)) {
+            context.update(buffer);
+            byte_count += buffer.length;
+            if (byte_count >= max_bytes) {
+                break;
+            }
+        }
+        context.finish(digest);
+
+        return digest;
+    }
+
+    struct FileInfo {
+        string name;
+        ulong  size;
+    }
+
+    FileInfo[] file_array;
+
+    writefln("Accumulating file list");
+
+    foreach (string dir; dirs) {
+        if (isDir(dir)) {
+            string last_entry;
+            try {
+                foreach (string filename; dirEntries(dir, SpanMode.depth, false)) {
+                    last_entry = filename;
+                    try {
+                        if (!isSymlink(filename) && isFile(filename)) {
+                            ulong size = getSize(filename);
+                            if (size >= file_size) {
+                                file_array ~= FileInfo(filename, size);
+                            }
+                        }
+                    }
+                    catch (Exception ex) {
+                        writefln("Skipping %s", filename);
+                        //writefln("Exception %s", ex);
+                        // TODO accumulate errors and print after traversal
+                    }
+                }
+            }
+            catch (FileException ex) {
+                // ignore
+                writefln("Error, dirEntries bailed out after: %s. Continuing anyway", last_entry);
+            }
+        }
+        else {
+            writefln("Not a dir: %s", dir);
+        }
+    }
+
+    writefln("Processing %s files", file_array.length);
+
+    uint[][ulong] size_to_file_indices;
+    bool[ulong]   duplicate_sizes;
+
+    foreach (uint index, file; file_array) {
+        //writefln("%s %s %s", index, file.name, file.size);
+
+        if (uint[] * indices = (file.size in size_to_file_indices)) {
+            if (indices.length == 1) {
+                // Second time we've seen a file of this size,
+                // record it in the duplicate_sizes array
+                duplicate_sizes[file.size] = true;
+            }
+
+            (*indices) ~= index;
+        }
+        else {
+            size_to_file_indices[file.size] = [ index ];
+        }
+    }
+
+    writefln("Number of files of duplicate size %s", duplicate_sizes.length);
+
+    ulong total_waste = 0;
+
+    foreach_reverse (size; duplicate_sizes.keys.sort) {
+        uint[] indices = size_to_file_indices[size];
+        //writefln("For size %s there are %s files", size, indices.length);
+
+        uint[][ubyte[16]] digest_to_indices;
+
+        foreach (index; indices) {
+            const FileInfo file_info = file_array[index];
+
+            try {
+                ubyte[16] digest = compute_md5(file_info.name, digest_size);
+
+                if (uint[] * duplicate_indices = (digest in digest_to_indices)) {
+                    // A true duplicate
+                    // index and index2 are the same
+
+                    (*duplicate_indices) ~= index;
+                }
+                else {
+                    digest_to_indices[digest] ~= index;
+                }
+            }
+            catch (ErrnoException ex) {
+                //writefln("Skipping: %s", file_info.name);
+            }
+
+            //writefln("\t%s", file_info.name);
+        }
+
+        foreach (indices2; digest_to_indices) {
+            if (indices2.length > 1) {
+                // List the duplicates
+                foreach (i, index; indices) {
+                    FileInfo file_info = file_array[index];
+                    if (i == 0) {
+                        writefln("%s", size_to_string(file_info.size));
+                        total_waste += file_info.size;
+                    }
+                    writefln("    %s", file_info.name);
+                }
+                writefln("");
+            }
+        }
+    }
+
+    writefln("Done, total waste: %s", size_to_string(total_waste));
+}
+
+int main(string[] args) {
+    ulong file_size;
+    ulong digest_size;
+    bool  verbose;
+
+    try {
+        string file_size_string   = "100K";
+        string digest_size_string = "100K";
+
+        void help(in string) {
+            writefln("Usage: dupes [OPTION]... DIR...\n"
+                     "Recursively locate duplicate files in a list of directories\n"
+                     "\n"
+                     "Options\n"
+                     " -d, --digest-size=SIZE     size of digest used for comparison [%s]\n"
+                     " -f, --file-size=SIZE       minimum size of files searched for duplication [%s]\n"
+                     " -v, --verbose              be verbose\n"
+                     "     --help                 display this help and exit\n"
+                     "\n"
+                     "SIZE is an integer, optionally followed by K, M, G, T",
+                     file_size_string,
+                     digest_size_string);
+            exit(1);
+        }
+
+        getopt(args,
+               "file-size|f",   &file_size_string,
+               "digest-size|d", &digest_size_string,
+               "verbose|v",     &verbose,
+               "help",          &help);
+
+        file_size   = string_to_size(file_size_string);
+        digest_size = string_to_size(digest_size_string);
+    }
+    catch (ConvException ex) {
+        writefln("Conversion error: %s", ex);
+        exit(2);
+    }
+
+    if (verbose) {
+        writefln("file-size=%s, digest-size=%s", size_to_string(file_size), size_to_string(digest_size));
+    }
+
+    find_duplicates(args[1..$], file_size, digest_size, verbose);
+
+    return 0;
+}
--- a/doodle/main/util/chess.d	Sun Sep 30 15:25:53 2012 +0930
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,266 +0,0 @@
-//
-// Notes:
-//  ply = half move (ie black or white's half of the move)
-
-import std.stdio;
-import std.ascii;
-import std.traits;
-import std.range;
-
-enum Side {
-    White, Black
-}
-
-enum Name {
-    King, Queen, Rook, Bishop, Knight, Pawn
-}
-
-struct Piece {
-    Side side;
-    Name name;
-}
-
-string toString(Piece piece) {
-    return
-        [
-        [ "\u2654", "\u2655", "\u2656", "\u2657", "\u2658", "\u2659" ],
-        [ "\u265A", "\u265B", "\u265C", "\u265D", "\u265E", "\u265F" ]
-        ]
-        [piece.side][piece.name];
-}
-
-//
-//
-//
-
-enum File {
-    _A, _B, _C, _D, _E, _F, _G, _H
-}
-
-char toChar(File f) {
-    return "abcdefgh"[f];
-}
-
-enum Rank {
-    _1, _2, _3, _4, _5, _6, _7, _8
-}
-
-char toChar(Rank r) {
-    return "12345678"[r];
-}
-
-struct Coord {
-    File file;
-    Rank rank;
-}
-
-string toString(in Coord coord) {
-    return toChar(coord.file) ~ "+" ~ toChar(coord.rank);
-}
-
-//
-//
-//
-
-struct Board {
-    struct Square {
-        this(in Side side, in Name name) {
-            occupied = true;
-            piece = Piece(side, name);
-        }
-
-        bool  occupied = false;
-        Piece piece;        // valid if occupied
-    }
-
-    this(in Square[8][8] squares_) {
-        squares = squares_;
-    }
-
-    Square square(Coord coord) const {
-        return squares[coord.file][coord.rank];
-    }
-
-private:
-    Square * at(Coord coord) {
-        return &squares[coord.file][coord.rank];
-    }
-
-    void add(Piece piece, Coord coord) {
-        auto square = at(coord);
-        if (square.occupied) {
-            // error
-        }
-        else {
-            square.occupied = true;
-            square.piece    = piece;
-        }
-    }
-
-    void remove(Coord coord) {
-        auto square = at(coord);
-        if (square.occupied) {
-            square.occupied = false;
-        }
-        else {
-            // error
-        }
-    }
-
-    void move(Coord source, Coord dest) {
-        auto source_sq = at(source);
-        auto dest_sq = at(dest);
-
-        if (source_sq.occupied && !dest_sq.occupied) {
-            source_sq.occupied = false;
-            dest_sq.occupied = true;
-            dest_sq.piece = source_sq.piece;
-        }
-        else {
-            // error
-        }
-    }
-
-    Square[8][8] squares =
-        [
-        [ Square(Side.White, Name.Rook),   Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Rook)   ],
-        [ Square(Side.White, Name.Knight), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Knight) ],
-        [ Square(Side.White, Name.Bishop), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Bishop) ],
-        [ Square(Side.White, Name.Queen),  Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Queen)  ],
-        [ Square(Side.White, Name.King),   Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.King)   ],
-        [ Square(Side.White, Name.Bishop), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Bishop) ],
-        [ Square(Side.White, Name.Knight), Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Knight) ],
-        [ Square(Side.White, Name.Rook),   Square(Side.White, Name.Pawn), Square(), Square(), Square(), Square(), Square(Side.Black, Name.Pawn), Square(Side.Black, Name.Rook)   ]
-        ];
-}
-
-void dump(in Board board) {
-    bool light_square = true;
-
-    foreach_reverse(r; EnumMembers!Rank) {
-        write(toChar(r));
-        foreach(f; EnumMembers!File) {
-
-            if (light_square) {
-                write("\033[47m");
-            }
-            else {
-                write("\033[40m");
-            }
-
-            Board.Square square = board.square(Coord(f, r));
-            if (square.occupied) {
-                write(toString(square.piece));
-            }
-            else {
-                write(" ");
-            }
-
-            light_square = !light_square;
-        }
-        writeln("\033[0m");
-
-        light_square = !light_square;
-    }
-
-    write(" ");
-    foreach(f; EnumMembers!File) {
-        writef("%s", toChar(f));
-    }
-    writeln("");
-}
-
-//
-//
-//
-
-enum KingState {
-    Safe,
-    Check,
-    CheckMate
-}
-
-class Game {
-    struct SideState {
-        KingState kingState;
-        bool      kingMoved;
-        bool      queenRookMoved;
-        bool      kingRookMoved;
-    }
-
-    struct Ply {
-        this(Coord source_, Coord dest_) {
-            source = source_;
-            dest = dest_;
-        }
-
-        Coord source;
-        Coord dest;
-    }
-
-    @property Board board() { return _board; }
-
-    struct Flags {
-        bool check;
-        bool mate;
-    }
-
-    // Default initial pieces, white to play
-    this () {
-    }
-
-    // Restore a previous game
-    this (Board board, Flags whiteFlags, Flags blackFlags, Side nextPly) {
-        _board   = board;
-        _nextPly = nextPly;
-    }
-
-    enum Acceptance {
-        Normal,
-        Check,
-        Mate,
-        Illegal
-    }
-
-    Acceptance apply(in Ply ply) {
-        auto source = _board.square(ply.source);
-        auto dest   = _board.square(ply.dest);
-
-        /+
-        auto sq1 = square(update.source);
-        auto sq2 = square(update.dest);
-
-        if (sq1.piece == Piece.Pawn && update.dest.file != update.source.file) {
-            // en-passant
-        }
-        else if (sq1.piece == Piece.King && update.dest.file - update.source.file > 1) {
-            // castle
-        }
-        +/
-
-        return Acceptance.Normal;
-    }
-
-    private {
-        struct PieceState {
-            bool  uncaptured;
-            Coord coord;        // valid if uncaptured
-        }
-
-        Board         _board;
-        Side          _nextPly;
-        SideState     _whiteSideState;
-        PieceState[8] _whitePieceState;
-        SideState     _blackSideState;
-        PieceState[8] _blackPieceState;
-    }
-}
-
-void main(string[] args) {
-    Board board;
-    dump(board);
-
-    /+
-    Game game;
-    +/
-}
--- a/doodle/main/util/doodle.d	Sun Sep 30 15:25:53 2012 +0930
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,114 +0,0 @@
-module main.prog.doodler;
-
-// XXX bob problem, needs it to be like this...
-import doodle.core.backtrace;
-import doodle.core.logging;
-import doodle.core.backtrace;
-
-import doodle.dia.standard_tools;
-import doodle.dia.page_layer;
-import doodle.dia.grid_layer;
-import doodle.dia.tool_layer;
-
-import doodle.fig.diagram_layer;
-import doodle.fig.select_tool;
-
-import doodle.fig.tools;
-
-import doodle.gtk.palette;
-
-import doodle.gtk.cairo_canvas;
-
-private {
-    /*
-    import doodle.core.backtrace;
-    import doodle.core.logging;
-    import doodle.core.backtrace;
-
-    import doodle.dia.standard_tools;
-    import doodle.dia.page_layer;
-    import doodle.dia.grid_layer;
-    import doodle.dia.tool_layer;
-
-    import doodle.fig.diagram_layer;
-    import doodle.fig.select_tool;
-
-    import doodle.fig.tools;
-
-    import doodle.gtk.palette;
-
-    import doodle.gtk.cairo_canvas;
-    */
-
-    import gtk.Main;
-    import gtk.MainWindow;
-    import gtk.VBox;
-
-    import std.stdio;
-}
-
-final class TopLevel : /*private*/ IToolStackObserver {
-    this(string[] args) {
-        Main.init(args);
-        auto window = new MainWindow("Doodle");
-        auto vbox = new VBox(false, 0);
-
-        auto palette = new Palette!Tool;
-        _palette = palette;
-
-        vbox.packStart(palette, false, false, 0);
-
-        Tool[] tools;
-        tools ~= new PanTool;
-        tools ~= new ZoomTool;
-        tools ~= new SelectTool;
-        auto toolLayer = new ToolLayer(tools, this);
-        _toolStack = toolLayer;
-
-        auto gridLayer = new GridLayer;
-
-        auto diagramLayer = new DiagramLayer;
-        _diagram = diagramLayer;
-
-        Layer[] layers;
-        layers ~= new PageLayer;
-        layers ~= gridLayer;
-        layers ~= diagramLayer;
-        layers ~= toolLayer;
-
-        // assume the screen has PPI of 120.0
-        immutable millimetersPerInch = 25.4;
-        immutable pixelsPerMillimetre = 120.0 / millimetersPerInch;
-        auto canvas = new CairoCanvas(layers, toolLayer, gridLayer, pixelsPerMillimetre);
-
-        vbox.packStart(canvas, true, true, 0);
-
-        Palette!Tool.Item[] items = [
-        { "select.svg",    "Select",    "Select and modify elements", new SelectTool },
-        { "rectangle.svg", "Rectangle", "Create rectangle", new CreateRectangleTool(_diagram) },
-        { "ellipse.svg",   "Ellipse",   "Create ellipse", new CreateRectangleTool(_diagram) },
-        { "polyline.svg",  "Polyline",  "Create polyline", new CreateRectangleTool(_diagram) }
-        ];
-
-        palette.configure(items, &_toolStack.use);
-        window.add(vbox);
-        window.setDefaultSize(640, 580);
-        window.showAll();
-        Main.run();
-    }
-
-    void toolChanged(Tool tool) {
-        message("Tool changed %s", tool.name);
-        _palette.activate(tool);
-    }
-
-    private {
-        IToolStack _toolStack;
-        IPalette!Tool _palette;
-        IDiagram _diagram;
-    }
-}
-
-void main(string[] args) {
-    new TopLevel(args);
-}
--- a/doodle/main/util/dupes.d	Sun Sep 30 15:25:53 2012 +0930
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,246 +0,0 @@
-import std.stdio;
-import std.string;
-import std.exception;
-import std.algorithm;
-import std.file;
-import std.md5;
-import std.getopt;
-import std.conv;
-import std.ascii;
-import std.c.stdlib;
-
-ulong string_to_size(string s) {
-    // Convert strings to sizes, eg:
-    //   "50"   -> 50
-    //   "80B"  -> 80
-    //   "10K"  -> 10240
-    //   "1M"   -> 1048576
-    // Throws ConvException
-
-    immutable map = [ 'B':1UL, 'K':1UL<<10, 'M':1UL<<20, 'G':1UL<<30, 'T':1UL<<40 ];
-
-    if (s.length == 0) {
-        throw new ConvException("Empty string");
-    }
-    else {
-        ulong multiplier = 1;
-
-        if (isAlpha(s[$-1])) {
-            immutable ulong * m = (s[$-1] in map);
-
-            if (m) {
-                multiplier = *m;
-            }
-            else {
-                throw new ConvException(format("Bad size unit character: %s", s[$-1]));
-            }
-
-            s = s[0..$-1];
-        }
-
-        return multiplier * to!ulong(s);
-    }
-}
-
-string size_to_string(in ulong size) {
-    /+
-    immutable array = [ 'B', 'K', 'M', 'G', 'T' ];
-    size_t index = 0;
-
-    foreach (i, c; array) {
-        if (size / (1UL << i
-
-        writefln("%s %s", i, c);
-    }
-    +/
-
-    return format("%sK", size / 1024);
-}
-
-void find_duplicates(in string[] dirs,
-                     in ulong    file_size,
-                     in ulong    digest_size,
-                     bool        verbose) {
-    static ubyte[16] compute_md5(in string filename, in ulong max_bytes) {
-        size_t chunk_size = min(max_bytes, 4096 * 1024);
-        ubyte[16] digest;
-
-        auto file = File(filename, "r");
-        scope(exit) file.close();
-
-        MD5_CTX context;
-        context.start();
-        ulong byte_count = 0;
-        foreach (ubyte[] buffer; chunks(file, chunk_size)) {
-            context.update(buffer);
-            byte_count += buffer.length;
-            if (byte_count >= max_bytes) {
-                break;
-            }
-        }
-        context.finish(digest);
-
-        return digest;
-    }
-
-    struct FileInfo {
-        string name;
-        ulong  size;
-    }
-
-    FileInfo[] file_array;
-
-    writefln("Accumulating file list");
-
-    foreach (string dir; dirs) {
-        if (isDir(dir)) {
-            string last_entry;
-            try {
-                foreach (string filename; dirEntries(dir, SpanMode.depth, false)) {
-                    last_entry = filename;
-                    try {
-                        if (!isSymlink(filename) && isFile(filename)) {
-                            ulong size = getSize(filename);
-                            if (size >= file_size) {
-                                file_array ~= FileInfo(filename, size);
-                            }
-                        }
-                    }
-                    catch (Exception ex) {
-                        writefln("Skipping %s", filename);
-                        //writefln("Exception %s", ex);
-                        // TODO accumulate errors and print after traversal
-                    }
-                }
-            }
-            catch (FileException ex) {
-                // ignore
-                writefln("Error, dirEntries bailed out after: %s. Continuing anyway", last_entry);
-            }
-        }
-        else {
-            writefln("Not a dir: %s", dir);
-        }
-    }
-
-    writefln("Processing %s files", file_array.length);
-
-    uint[][ulong] size_to_file_indices;
-    bool[ulong]   duplicate_sizes;
-
-    foreach (uint index, file; file_array) {
-        //writefln("%s %s %s", index, file.name, file.size);
-
-        if (uint[] * indices = (file.size in size_to_file_indices)) {
-            if (indices.length == 1) {
-                // Second time we've seen a file of this size,
-                // record it in the duplicate_sizes array
-                duplicate_sizes[file.size] = true;
-            }
-
-            (*indices) ~= index;
-        }
-        else {
-            size_to_file_indices[file.size] = [ index ];
-        }
-    }
-
-    writefln("Number of files of duplicate size %s", duplicate_sizes.length);
-
-    ulong total_waste = 0;
-
-    foreach_reverse (size; duplicate_sizes.keys.sort) {
-        uint[] indices = size_to_file_indices[size];
-        //writefln("For size %s there are %s files", size, indices.length);
-
-        uint[][ubyte[16]] digest_to_indices;
-
-        foreach (index; indices) {
-            const FileInfo file_info = file_array[index];
-
-            try {
-                ubyte[16] digest = compute_md5(file_info.name, digest_size);
-
-                if (uint[] * duplicate_indices = (digest in digest_to_indices)) {
-                    // A true duplicate
-                    // index and index2 are the same
-
-                    (*duplicate_indices) ~= index;
-                }
-                else {
-                    digest_to_indices[digest] ~= index;
-                }
-            }
-            catch (ErrnoException ex) {
-                //writefln("Skipping: %s", file_info.name);
-            }
-
-            //writefln("\t%s", file_info.name);
-        }
-
-        foreach (indices2; digest_to_indices) {
-            if (indices2.length > 1) {
-                // List the duplicates
-                foreach (i, index; indices) {
-                    FileInfo file_info = file_array[index];
-                    if (i == 0) {
-                        writefln("%s", size_to_string(file_info.size));
-                        total_waste += file_info.size;
-                    }
-                    writefln("    %s", file_info.name);
-                }
-                writefln("");
-            }
-        }
-    }
-
-    writefln("Done, total waste: %s", size_to_string(total_waste));
-}
-
-int main(string[] args) {
-    ulong file_size;
-    ulong digest_size;
-    bool  verbose;
-
-    try {
-        string file_size_string   = "100K";
-        string digest_size_string = "100K";
-
-        void help(in string) {
-            writefln("Usage: dupes [OPTION]... DIR...\n"
-                     "Recursively locate duplicate files in a list of directories\n"
-                     "\n"
-                     "Options\n"
-                     " -d, --digest-size=SIZE     size of digest used for comparison [%s]\n"
-                     " -f, --file-size=SIZE       minimum size of files searched for duplication [%s]\n"
-                     " -v, --verbose              be verbose\n"
-                     "     --help                 display this help and exit\n"
-                     "\n"
-                     "SIZE is an integer, optionally followed by K, M, G, T",
-                     file_size_string,
-                     digest_size_string);
-            exit(1);
-        }
-
-        getopt(args,
-               "file-size|f",   &file_size_string,
-               "digest-size|d", &digest_size_string,
-               "verbose|v",     &verbose,
-               "help",          &help);
-
-        file_size   = string_to_size(file_size_string);
-        digest_size = string_to_size(digest_size_string);
-    }
-    catch (ConvException ex) {
-        writefln("Conversion error: %s", ex);
-        exit(2);
-    }
-
-    if (verbose) {
-        writefln("file-size=%s, digest-size=%s", size_to_string(file_size), size_to_string(digest_size));
-    }
-
-    find_duplicates(args[1..$], file_size, digest_size, verbose);
-
-    return 0;
-}
--- a/doodle/tk/Bobfile	Sun Sep 30 15:25:53 2012 +0930
+++ b/doodle/tk/Bobfile	Sun Sep 30 15:41:25 2012 +0930
@@ -1,6 +1,6 @@
 refer doodle/core ;
 
-test-util test1 : test1.d ;
-test-util test2 : test2.d ;
+#test-util test1 : test1.d ;
+#test-util test2 : test2.d ;
 
 static-lib tk : color.d  events.d  geometry.d  palette.d  renderer.d  screen_model.d;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gtk	Sun Sep 30 15:41:25 2012 +0930
@@ -0,0 +1,1 @@
+/home/dbryant/source/d/GtkD/src
\ No newline at end of file
--- a/nobuild/Boboptions	Sun Sep 30 15:25:53 2012 +0930
+++ b/nobuild/Boboptions	Sun Sep 30 15:41:25 2012 +0930
@@ -8,4 +8,5 @@
 #DFLAGS = -w -wi -gc -I~/source/d/gtkD-trunk/src ;
 #DFLAGS = -w -wi -gc -I~/source/d/GtkD/src ;
 DFLAGS = -w -wi -gc -Isrc/gtk ;
+
 DLINKFLAGS = -L-L/home/dbryant/source/d/GtkD ;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nobuild/make-tags.sh	Sun Sep 30 15:41:25 2012 +0930
@@ -0,0 +1,3 @@
+#!/bin/bash
+
+find -L src -name \*.d | ctags -L- --extra=+f -f TAGS ;