aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xmaketiles/10kfull192
-rwxr-xr-xmaketiles/10khalf180
-rw-r--r--maketiles/README28
-rwxr-xr-xmaketiles/fixindex26
-rwxr-xr-xmaketiles/packtiles157
-rw-r--r--pnmtilesplit/Makefile19
-rw-r--r--pnmtilesplit/pnmtilesplit.c365
-rw-r--r--tileserver/Makefile31
-rw-r--r--tileserver/base64.c272
-rw-r--r--tileserver/base64.h25
-rw-r--r--tileserver/cdb.c476
-rw-r--r--tileserver/cdb.h61
-rwxr-xr-xtileserver/cdbtestrun149
-rw-r--r--tileserver/netstring.c44
-rw-r--r--tileserver/netstring.h22
-rw-r--r--tileserver/tileserver.c524
-rw-r--r--tileserver/tileset.c208
-rw-r--r--tileserver/tileset.h32
-rw-r--r--tileserver/util.c53
-rw-r--r--tileserver/util.h36
20 files changed, 0 insertions, 2900 deletions
diff --git a/maketiles/10kfull b/maketiles/10kfull
deleted file mode 100755
index 873818092..000000000
--- a/maketiles/10kfull
+++ /dev/null
@@ -1,192 +0,0 @@
-#!/usr/bin/perl -w
-#
-# 10kfull:
-# Turn the 1:10,000 Ordnance Survey map tiles into 254-by-254 pixmaps at full
-# resolution.
-#
-# Copyright (c) 2005 UK Citizens Online Democracy. All rights reserved.
-# Email: chris@mysociety.org; WWW: http://www.mysociety.org/
-#
-
-my $rcsid = ''; $rcsid .= '$Id: 10kfull,v 1.5 2006-09-20 15:01:56 chris Exp $';
-
-use strict;
-
-use Digest::SHA1;
-use Errno;
-use File::stat;
-use Geography::NationalGrid;
-use IO::Dir;
-use IO::File;
-
-use constant TILE_SIZE_PX => 7874;
-use constant TILE_SIZE_M => 5000;
-
-use constant SUBTILE_SIZE_PX => 254;
-use constant SUBTILES_PER_TILE => (TILE_SIZE_PX / SUBTILE_SIZE_PX);
-
-sub debug (@) {
- print STDERR @_;
-}
-
-sub System (@) {
- debug("executing command: ", @_, "\n");
- system(@_);
- die "command failed with status $?" if ($?);
-}
-
-die "arguments are directories containing input tiles in TIFF format and\n"
- . "to which output tiles are to be written, and optional eastings and\n"
- . "northings ranges, in the order west, east, south, north\n"
- if (@ARGV != 2 && @ARGV != 6);
-
-my ($inputdir, $outputdir) = @ARGV;
-$inputdir =~ s#/$##;
-$outputdir =~ s#/$##;
-die "$inputdir: not a directory" if (!-d $inputdir);
-die "$outputdir: not a directory" if (!-d $outputdir);
-
-my $inarea = 0;
-my ($west, $east, $south, $north);
-
-if (@ARGV == 6) {
- $inarea = 1;
- foreach (@ARGV[2 .. 5]) {
- die "'$_' is not a valid number\n" if (!/^[1-9]\d*$/);
- }
- ($west, $east, $south, $north) = @ARGV[2 .. 5];
- die "EAST must be greater than WEST" unless ($east > $west);
- die "NORTH must be greater than SOUTH" unless ($north > $south);
-
- debug("area of interest: west $west, east $east, south $south, north $north\n");
-}
-
-#
-# Within the output directory we create a subdirectory tiles/ containing tile
-# images named for their SHA1 checksums, and a text file mapping tile
-# coordinates to the SHA1 sums.
-#
-
-die "$outputdir/tiles: $!"
- if (!mkdir("$outputdir/tiles", 0755) && !$!{EEXIST});
-
-my $index = new IO::File("$outputdir/index", O_WRONLY | O_CREAT | O_TRUNC, 0644)
- or die "$outputdir/index: $!";
-
-$index->print(<<EOF);
-# This index file connects individual tiles of the 1:10,000 Ordnance Survey
-# maps at their full resolution (0.635m/px). Each such tile is 254 by 254
-# pixels. The tiles are indexed according to their coordinates within the full
-# Ordnance Survey grid, with (0, 0) being the tile at the SW corner of the grid
-# (immediately NE of the origin), (1, 0) being the tile to its east, and (0, 1)
-# the tile immediately to its north. Note that not all tiles are present. For
-# each such tile position this file lists the SHA1 message-digest of the image
-# file which represents the tile.
-EOF
-
-my $d = new IO::Dir($inputdir)
- or die "$inputdir: $!";
-
-my $total_input_size = 0; # KB
-my $total_output_size = 0; # KB
-while (my $name = $d->read()) {
- next unless ($name =~ /\.tiff?$/i);
- debug("have image file $inputdir/$name\n");
-
- my ($gridsq, $offset, $quadrant)
- = map { uc($_) } ($name =~ /^([A-Z]{2})(\d{2})([NS][EW])\./i);
-
- if (!$gridsq) {
- debug(" -> doesn't seem to be a valid 1:10,000 image tile; ignoring\n");
- next;
- }
-
- debug(" -> grid square = $gridsq; offset = $offset; quadrant = $quadrant\n");
- my $p = new Geography::NationalGrid('GB',
- GridReference => "$gridsq $offset");
-
- my ($E, $N) = ($p->easting(), $p->northing());
- debug(" -> SW corner of grid square is at ($E, $N)\n");
-
- $N += TILE_SIZE_M if ($quadrant =~ /^N/);
- $E += TILE_SIZE_M if ($quadrant =~ /E$/);
- debug(" => SW corner of tile is at ($E, $N)\n");
-
- if ($inarea) {
- my $tE = $E + TILE_SIZE_M;
- my $tW = $E;
- my $tN = $N + TILE_SIZE_M;
- my $tS = $N;
-
- if ($tE < $west || $tW > $east
- || $tN < $south || $tS > $north) {
- debug(" tile is outside area of interest; skipping\n");
- next;
- }
- }
-
- my $st = stat("$inputdir/$name");
- my $input_tile_size = $st->size();
- debug(" tile size = $input_tile_size bytes\n");
- $total_input_size += $input_tile_size / 1024.;
-
-
-
- # Figure out the tile offsets.
- my $x = ($E / TILE_SIZE_M) * SUBTILES_PER_TILE;
- my $y = ($N / TILE_SIZE_M) * SUBTILES_PER_TILE;
- debug(" => subtile col/row for SW-most subtile is ($x, $y)\n");
-
- # Now split this tile into subtiles.
- System("tifftopnm $inputdir/$name |"
- . " pnmtilesplit -P -f '$outputdir/%d,%d.png'"
- . " -p 'pnmtopng -compression 9 2>/dev/null' 254 254");
-
- # Consider each of the subtiles.
- debug("finding SHA1 digests of tiles and adding them to index...\n");
- my $nduplicates = 0;
- my $nnew = 0;
- my $size = 0;
- for (my $j = 0; $j < SUBTILES_PER_TILE; ++$j) {
- debug("\r$j/", SUBTILES_PER_TILE);
- my $j2 = SUBTILES_PER_TILE - 1 - $j;
- for (my $i = 0; $i < SUBTILES_PER_TILE; ++$i) {
- my $fn = "$outputdir/$i,$j2.png";
- my $f = new IO::File($fn, O_RDONLY)
- or die "$fn: $!";
- my $sha = new Digest::SHA1();
- $sha->addfile($f);
- $sha = $sha->hexdigest();
- $f->close();
- $index->printf("%d %d %s\n", $x + $i, $y + $j, $sha);
- my ($n1, $n2, $n3) = ($sha =~ /^(.)(.)(.)/);
- mkdir("$outputdir/tiles/$n1");
- mkdir("$outputdir/tiles/$n1/$n2");
- mkdir("$outputdir/tiles/$n1/$n2/$n3");
- my $fn2 = "$outputdir/tiles/$n1/$n2/$n3/$sha.png";
- if (-e $fn2) {
- unlink($fn);
- ++$nduplicates;
- } else {
- rename($fn, $fn2) or die "rename: $!";
- ++$nnew;
- my $st = stat($fn2);
- $size += $st->size();
- }
- }
- }
- debug("\r", SUBTILES_PER_TILE, "/", SUBTILES_PER_TILE, "\n");
- debug("had $nduplicates duplicate tiles + $nnew new, $size bytes\n");
- debug(" output subtiles are ",
- sprintf('%.1f%%', 100 * $size / $input_tile_size),
- " of input tile size for this tile\n");
- $total_output_size += $size / 1024.;
- debug(" so far total input size ",
- sprintf('%.1fKB', $total_input_size), "\n");
- debug(" so far total output size ",
- sprintf('%.1fKB', $total_output_size), "\n");
- debug(" output subtiles are ",
- sprintf('%.1f%%', 100 * $total_output_size / $total_input_size),
- " of input tile size so far overall\n");
- $index->flush();
-}
diff --git a/maketiles/10khalf b/maketiles/10khalf
deleted file mode 100755
index 48d59bc24..000000000
--- a/maketiles/10khalf
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/usr/bin/perl -w
-#
-# 10khalf:
-# Generate half-scale 1:10,000 Ordnance Survey map tiles from the
-# full-resolution ones generated by 10kfull.
-#
-# Copyright (c) 2005 UK Citizens Online Democracy. All rights reserved.
-# Email: chris@mysociety.org; WWW: http://www.mysociety.org/
-#
-
-my $rcsid = ''; $rcsid .= '$Id: 10khalf,v 1.1 2006-09-14 21:43:15 chris Exp $';
-
-use strict;
-
-use Digest::SHA1;
-use File::stat;
-use IO::File;
-
-sub debug (@) {
- print STDERR @_;
-}
-
-sub System (@) {
- #debug("executing command: ", @_, "\n");
- # need bash for <( ) command substitution
- system("/bin/bash", '-c', join(' ', @_));
- die "command failed with status $?" if ($?);
-}
-
-die "arguments are directory containing output files from 10kfull and directory to which the half-resolution tiles are to be written"
- if (2 != @ARGV);
-
-my ($inputdir, $outputdir) = @ARGV;
-$inputdir =~ s#/$##;
-$outputdir =~ s#/$##;
-die "$inputdir: not a directory" if (!-d $inputdir);
-die "$outputdir: not a directory" if (!-d $outputdir);
-
-#
-# Within the output directory we create a subdirectory tiles/ containing tile
-# images named for their SHA1 checksums, and a text file mapping tile
-# coordinates to the SHA1 sums.
-#
-
-die "$outputdir/tiles: $!"
- if (!mkdir("$outputdir/tiles", 0755) && !$!{EEXIST});
-
-my $index = new IO::File("$outputdir/index", O_WRONLY | O_CREAT | O_TRUNC, 0644)
- or die "$outputdir/index: $!";
-
-$index->print(<<EOF);
-# This index file connects individual tiles of the 1:10,000 Ordnance Survey
-# maps at half their original resolution (1.27m/px). Each such tile is 254 by
-# 254 pixels. The tiles are indexed according to their coordinates within the
-# full Ordnance Survey grid, with (0, 0) being the tile at the SW corner of the
-# grid (immediately NE of the origin), (1, 0) being the tile to its east, and
-# (0, 1) the tile immediately to its north. Note that not all tiles are
-# present. For each such tile position this file lists the SHA1 message-digest
-# of the image file which represents the tile.
-EOF
-
-my $in_index = new IO::File("$inputdir/index", O_RDONLY)
- or die "$inputdir/index: $!";
-
-my %fullrestiles = ( );
-my %halfrestiles = ( );
-
-my $line;
-while (defined($line = $in_index->getline()) && $line =~ /^#/) { }
-if (!defined($line)) {
- if ($in_index->error()) {
- die "$inputdir/index: $! (while reading header)";
- } else {
- die "$inputdir/index: premature EOF (while reading header)";
- }
-}
-
-debug("reading $inputdir/index... ");
-my $ntiles = 0;
-my $nhalfrestiles = 0;
-do {
- chomp($line);
- my ($i, $j, $sha1) = split(/\s+/, $line);
- die "$inputdir/index: bad index line '$line'"
- unless (defined($i) && defined($j) && defined($sha1)
- && $i =~ /^(0|[1-9]\d*)$/ && $j =~ /^(0|[1-9]\d*)$/
- && $sha1 =~ /^[0-9a-f]{40}$/);
-
- my $i2 = int($i / 2);
- my $j2 = int($j / 2);
- my $k = pack('II', $i2, $j2);
- if (!exists($halfrestiles{$k})) {
- ++$nhalfrestiles;
- $halfrestiles{$k} = undef;
- }
-
- $fullrestiles{pack('II', $i, $j)} = $sha1;
- ++$ntiles;
-} while (defined($line = $in_index->getline()));
-
-die "$inputdir/index: $!" if ($in_index->error());
-$in_index->close();
-debug("done\n");
-
-debug("read $ntiles from index\n");
-debug("have $nhalfrestiles to generate\n");
-
-System("ppmmake '#ffffff' 254 254 > $outputdir/blank.ppm");
-
-sub imgname ($) {
- my $sha1 = shift;
- if (!defined($sha1)) {
- return "$outputdir/blank.ppm";
- } else {
- $sha1 =~ s#^(.)(.)(.)(.+)$#$1/$2/$3/$1$2$3$4#;
- return "<( pngtopnm $inputdir/tiles/$sha1.png )";
- }
-}
-
-my %compose = ( );
-my $nnew = 0;
-my $nduplicates = 0;
-my $size = 0;
-foreach my $k (keys(%halfrestiles)) {
- my ($i2, $j2) = unpack('II', $k);
- my @t = ( );
- my $n = 0;
- for (my $j = 0; $j <= 1; ++$j) {
- for (my $i = 0; $i <= 1; ++$i) {
- $t[$n] = $fullrestiles{pack('II', 2 * $i2 + $i, 2 * $j2 + $j)};
-# debug("img #$n is ", defined($t[$n]) ? $t[$n] : '(blank)', "\n");
- ++$n;
- }
- }
-
- my $c = join(',', map { defined($_) ? $_ : '*' } @t);
- my $fn = "$outputdir/out.png";
- my $sha;
-
- if (exists($compose{$c})) {
- # we've already made this image
- $sha = $compose{$c};
- } else {
- # make it
- @t = map { imgname($_) } @t;
- System("pnmcat -tb <( pnmcat -lr $t[0] $t[1] ) <( pnmcat -lr $t[2] $t[3] )"
- . " | pnmscale -reduce 2 2>/dev/null"
- . " | pnmtopng -compression 9 2>/dev/null > $fn");
-
- my $f = new IO::File($fn, O_RDONLY)
- or die "$fn: $!";
- $sha = new Digest::SHA1();
- $sha->addfile($f);
- $sha = $sha->hexdigest();
- $f->close();
-
- $compose{$c} = $sha;
- }
-
- $index->printf("%d %d %s\n", $i2, $j2, $sha);
- my ($n1, $n2, $n3) = ($sha =~ /^(.)(.)(.)/);
- mkdir("$outputdir/tiles/$n1");
- mkdir("$outputdir/tiles/$n1/$n2");
- mkdir("$outputdir/tiles/$n1/$n2/$n3");
- my $fn2 = "$outputdir/tiles/$n1/$n2/$n3/$sha.png";
- if (-e $fn2) {
- unlink($fn);
- ++$nduplicates;
- } else {
- rename($fn, $fn2) or die "rename: $!";
- ++$nnew;
- my $st = stat($fn2);
- $size += $st->size();
- }
-
- debug("have $nnew new, $nduplicates duplicates, total size $size bytes\n");
-}
-
-# get rid of the blank PPM.
-unlink("$outputdir/blank.ppm");
diff --git a/maketiles/README b/maketiles/README
deleted file mode 100644
index 64c6bb380..000000000
--- a/maketiles/README
+++ /dev/null
@@ -1,28 +0,0 @@
-File formats and structures
-
-Tiles are generated as PNG files. At the moment these are full-colour PNGs but
-in due course we will probably want to use dithered images with a limited
-palette. Generated tiles are named for their own SHA1 checksums, so that we
-can eliminate duplicate tiles. The first-stage output of these scripts,
-therefore, consists of a set of PNG files named by SHA1 and a text index which
-maps tile locations to SHA1s. These are arranged as:
-
- toplevel/index text index of tiles
- toplevel/tiles/0/0/0 location for images with SHA1s beginning
- 000
- toplevel/tiles/0/0/0/00000000000000000000.png
- first possible image file
-
-This format is not really acceptable for final deployment because many of the
-image files won't be much larger than a filesystem block, so a large amount of
-disk space would be wasted in storing them. Nor is the text index from tile
-location to SHA1 acceptable. So a second program packs the image files into
-catenated files with an index from SHA1 to offset and length in each file.
-Separately, the index from tile location to SHA1 is turned into another index.
-Both indices use Bernstein-style CDB files.
-
- toplevel/index.cdb binary index from tile location to SHA1
- toplevel/tiles/0/0/0/packed catenated file of images with SHA1s
- beginning 000
- toplevel/tiles/0/0/0/index.cdb index of images in packed
-
diff --git a/maketiles/fixindex b/maketiles/fixindex
deleted file mode 100755
index 8bfed69db..000000000
--- a/maketiles/fixindex
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/usr/bin/perl -w
-#
-# fixindex:
-# Fix the indices generated by the buggy version of 10kfull.
-#
-# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
-# Email: chris@mysociety.org; WWW: http://www.mysociety.org/
-#
-
-my $rcsid = ''; $rcsid .= '$Id: fixindex,v 1.2 2006-09-20 15:20:30 chris Exp $';
-
-use strict;
-
-use constant SUBTILES_PER_TILE => 31;
-
-while (defined(my $line = <STDIN>)) {
- chomp($line);
- if ($line =~ /^(0|[1-9]\d*) (0|[1-9]\d*) ([0-9a-f]+)$/) {
- my ($x, $y, $id) = ($1, $2, $3);
- $y = int($y / SUBTILES_PER_TILE) * SUBTILES_PER_TILE
- + SUBTILES_PER_TILE - 1 - ($y % SUBTILES_PER_TILE);
- print "$x $y $id\n";
- } else {
- print "$line\n";
- }
-}
diff --git a/maketiles/packtiles b/maketiles/packtiles
deleted file mode 100755
index dd12ae94f..000000000
--- a/maketiles/packtiles
+++ /dev/null
@@ -1,157 +0,0 @@
-#!/usr/bin/perl -w
-#
-# packtiles:
-# Pack a tree of tiles etc. as generated by 10kfull etc. into the more efficient
-# packed format which is read by the tile server.
-#
-# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
-# Email: chris@mysociety.org; WWW: http://www.mysociety.org/
-#
-
-my $rcsid = ''; $rcsid .= '$Id: packtiles,v 1.3 2006-09-20 14:57:42 chris Exp $';
-
-use strict;
-
-use CDB_File;
-use Errno;
-use File::Slurp;
-use File::stat;
-use IO::Dir;
-use IO::File;
-
-use constant TILEID_LEN => 20;
-use constant BLOCKING => 14;
-
-sub debug (@) {
- print STDERR @_;
-}
-
-sub pack_tile_dir ($$) {
- my ($indir, $outdir) = @_;
-
-}
-
-# new_index_block
-#
-sub new_index_block () {
- # Initially all tiles are null so all bits are set.
- my $bitmaplen = int((BLOCKING * BLOCKING + 8) / 8);
- my $buf = "\xff" x $bitmaplen;
- $buf .= "\00" x (BLOCKING * BLOCKING * TILEID_LEN);
-}
-
-# add_tile_to_index_block BLOCK X Y ID
-#
-sub add_tile_to_index_block ($$$$) {
- my $x = $_[1];
- my $y = $_[2];
- my $id = $_[3];
-
- # clear the nullness bit.
- my $off = $x + $y * BLOCKING;
- my $b = unpack('C', substr($_[0], $off >> 3, 1));
- $b &= ~(1 << ($off & 7));
- substr($_[0], $off >> 3, 1) = pack('C', $b);
-
- # stick the tile itself in.
- my $bitmaplen = int((BLOCKING * BLOCKING + 8) / 8);
- substr($_[0], $bitmaplen + $off * TILEID_LEN, TILEID_LEN) = $id;
-}
-
-die "arguments are input (unpacked) tile directory, and output (packed)\n"
- . "tileset directories\n"
- if (@ARGV != 2);
-
-my ($inputdir, $outputdir) = @ARGV;
-$inputdir =~ s#/$##;
-$outputdir =~ s#/$##;
-die "$inputdir: not a directory" if (!-d $inputdir);
-die "$outputdir: not a directory" if (!-d $outputdir);
-
-# first make the index of tile locations to IDs.
-my %index;
-debug("reading index of tile locations to IDs...\n");
-my $f = new IO::File("$inputdir/index", O_RDONLY);
-my $len = stat($f)->size();
-my $n = 0;
-while (defined(my $line = $f->getline())) {
- debug("\rreading index: ", $f->tell(), "/$len bytes")
- if (0 == ($n % 100));
- ++$n;
-
- next if ($line =~ /^#/);
-
- chomp($line);
- my ($x, $y, $hash) = split(/ /, $line);
- my $id = pack('H*', $hash);
-
- my $x2 = int($x / BLOCKING);
- my $y2 = int($y / BLOCKING);
-
- $index{"$x2,$y2"} ||= new_index_block();
- add_tile_to_index_block(
- $index{"$x2,$y2"},
- $x % BLOCKING, $y % BLOCKING,
- $id);
-}
-debug("\rreading index: $len/$len bytes\n");
-
-die "$inputdir/index: $!" if ($f->error());
-$f->close();
-
-debug("writing index blocks to index.cdb... ");
-my $C = new CDB_File("$outputdir/index.cdb", "$outputdir/index.new");
-$C->insert(blocking => BLOCKING);
-foreach (keys(%index)) {
- $C->insert($_, $index{$_});
-}
-debug("done\n");
-debug("finalising index.cdb... ");
-$C->finish();
-debug("done\n");
-
-debug("packing individual tile directories...\n");
-$n = 0;
-mkdir("$outputdir/tiles");
-for (my $u = 0; $u < 4096; ++$u) {
- my $subpath = sprintf('%x/%x/%x', $u & 0xf, ($u >> 4) & 0xf, $u >> 8);
-
- next unless (-d "$inputdir/tiles/$subpath");
-
- # Ensure the path exists.
- foreach my $p (qw(1 3 5)) {
- my $d = "$outputdir/tiles/" . substr($subpath, 0, $p);
- die "$d: mkdir: $!" if (!mkdir($d) && !$!{EEXIST});
- }
-
- my $in = "$inputdir/tiles/$subpath";
- my $out = "$outputdir/tiles/$subpath";
-
- my $f = new IO::File("$out/tiles", O_WRONLY | O_CREAT | O_TRUNC, 0644)
- or die "$out/tiles: open: $!";
- $C = new CDB_File("$out/tiles.cdb", "$out/tiles.tmp");
- my $d = new IO::Dir($in) or die "$in: $!";
- while (my $name = $d->read()) {
- next unless ($name =~ /^([0-9a-f]+)\.png$/);
- my $id = pack('H*', $1);
- my $buf = read_file("$in/$name") or die "$in/$name: $!";
-
- die "$in/$name: length of file read by File::Slurp did not match stat"
- unless (stat("$in/$name")->size() == length($buf));
-
- my $rec = sprintf('%x:%x', $f->tell(), length($buf));
- $C->insert($id, $rec);
-
- $f->print($buf) or die "$out/tiles: $!";
-
- ++$n;
- }
-
- $f->close();
- $C->finish();
-
- debug("\rpacking tiles: $u/4096");
-}
-
-debug("\rpacking tiles: 4096/4096\n");
-debug("packed $n tiles total\n");
diff --git a/pnmtilesplit/Makefile b/pnmtilesplit/Makefile
deleted file mode 100644
index 65595b2e5..000000000
--- a/pnmtilesplit/Makefile
+++ /dev/null
@@ -1,19 +0,0 @@
-#
-# Makefile:
-# Build pnmtilesplit.
-#
-# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
-# Email: chris@mysociety.org; WWW: http://www.mysociety.org/
-#
-# $Id: Makefile,v 1.2 2006-09-14 17:21:03 chris Exp $
-#
-
-CFLAGS = -Wall -g -O99
-LDFLAGS =
-LDLIBS = -lnetpbm # is this a debianism?
-
-pnmtilesplit: pnmtilesplit.c
- $(CC) $(CFLAGS) pnmtilesplit.c $(LDFLAGS) $(LDLIBS) -o pnmtilesplit
-
-clean:
- rm -f pnmtilesplit *~ core
diff --git a/pnmtilesplit/pnmtilesplit.c b/pnmtilesplit/pnmtilesplit.c
deleted file mode 100644
index ed1ac5dd8..000000000
--- a/pnmtilesplit/pnmtilesplit.c
+++ /dev/null
@@ -1,365 +0,0 @@
-/*
- * pnmtilesplit.c:
- * Split a single large PNM file into numerous smaller tiles.
- *
- * Copyright (c) 2005 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- */
-
-static const char rcsid[] = "$Id: pnmtilesplit.c,v 1.10 2006-09-19 11:27:30 chris Exp $";
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <pam.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <sys/wait.h>
-
-#define err(...) \
- do { \
- fprintf(stderr, "pnmtilesplit: "); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- } while (0)
-
-#define die(...) do { err(__VA_ARGS__); exit(1); } while (0)
-
-static int verbose;
-#define debug(...) if (verbose) fprintf(stderr, __VA_ARGS__)
-
-/* xmalloc LEN
- * Allocate LEN bytes, returning the allocated buffer on success or dying on
- * failure. */
-static void *xmalloc(const size_t s) {
- void *v;
- if (!(v = malloc(s)))
- die("malloc(%u): %s", (unsigned)s, strerror(errno));
- return v;
-}
-
-/* open_output_file FORMAT PIPE I J [PID]
- * Open a new output file, constructing it from FORMAT and the column- and
- * row-index values I and J. If PIPE is non-NULL, open the file via a pipe
- * through the shell. Returns a stdio file handle on success or abort on
- * failure. If PIPE is non-NULL then the process ID of the child process is
- * saved in *PID. */
-static FILE *open_output_file(const char *fmt, const char *pipe_via,
- const int i, const int j, pid_t *child_pid) {
- FILE *fp;
- char *filename;
- filename = xmalloc(strlen(fmt) + 64);
- sprintf(filename, fmt, i, j);
- /* XXX consider creating directories if they don't already exist? */
- if (pipe_via) {
- pid_t p;
- int fd, pp[2];
- if (-1 == (fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644)))
- die("%s: open: %s", filename, strerror(errno));
- else if (-1 == pipe(pp))
- die("pipe: %s", strerror(errno));
- else if (!(fp = fdopen(pp[1], "w")))
- die("fdopen: %s", strerror(errno));
-
- if (-1 == (p = fork()))
- die("fork: %s", strerror(errno));
- else if (0 == p) {
- /* run the pipe command via /bin/sh */
- char *argv[4] = {"/bin/sh", "-c", 0};
- char si[40], sj[40];
- sprintf(si, "TILECOL=%d", i);
- putenv(si);
- sprintf(sj, "TILEROW=%d", j);
- putenv(sj);
- close(0);
- close(1);
- close(pp[1]);
- dup(pp[0]); /* standard input */
- close(pp[0]);
- dup(fd); /* standard output */
- close(fd);
- argv[2] = (char*)pipe_via;
- execv(argv[0], argv);
- err("%s: %s", pipe_via, strerror(errno));
- _exit(1);
- } else if (child_pid)
- *child_pid = p;
-
- close(pp[0]);
- close(fd);
-
- debug("forked child process %d for pipe to \"%s\", write fd = %d\n",
- (int)p, filename, pp[1]);
- } else if (!(fp = fopen(filename, "w"))) {
- die("%s: open: %s", filename, strerror(errno));
- debug("opened file \"%s\"\n", filename);
- }
-
- free(filename);
-
- return fp;
-}
-
-/* usage STREAM
- * Write a usage message to STREAM. */
-void usage(FILE *fp) {
- fprintf(fp,
-"pnmtilesplit - split a PNM file into fixed-size tiles\n"
-"\n"
-"Usage: pnmtilesplit -h | [OPTIONS] WIDTH HEIGHT [INPUT]\n"
-"\n"
-"Split the INPUT image, or, if it is not specified, the image on standard\n"
-"input, into WIDTH-by-HEIGHT pixel tiles. If WIDTH or HEIGHT do not divide\n"
-"the dimensions of the input image exactly, a warning will be printed and\n"
-"the pixels at the extreme right and bottom of the input image will be\n"
-"discarded.\n"
-"\n"
-"Options:\n"
-"\n"
-" -h Display this help message on standard output.\n"
-"\n"
-" -v Output debugging information on standard error.\n"
-"\n"
-" -P Display progress information on standard error (implied by\n"
-" -v).\n"
-"\n"
-" -f FORMAT Use the printf-style FORMAT for the name of the output file,\n"
-" instead of \"%%d,%%d.pnm\".\n"
-"\n"
-" -p COMMAND Don't write files directly, but pipe them via COMMAND. The\n"
-" COMMAND is interpreted by the shell. The variables TILECOL\n"
-" and TILEROW in the environment of the command are set to\n"
-" the column and row indices of the tile being generated.\n"
-"\n"
-" -s Use a slow but more correct implementation, which processes\n"
-" the image files only through netpbm's own API, rather than\n"
-" copying pixel data directly between input and output\n"
-" images.\n"
-"\n"
-"Note that you can specify -f /dev/null and use the pipe command to create\n"
-"the output images, for instance with a command like,\n"
-" pnmtilesplit -p 'pnmtopng > $TILEROW,$TILECOL.png' -f /dev/null 256 256\n"
-"if you want to exchange the column and row indices.\n"
-"\n"
-"Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.\n"
-"Email: chris@mysociety.org; WWW: http://www.mysociety.org/\n"
-"%s\n",
- rcsid);
-}
-
-/* main ARGC ARGV
- * Entry point. */
-int main(int argc, char *argv[]) {
- int tile_w, tile_h, cols, rows;
- char *img_name;
- FILE *img_fp, **tile_fp;
- struct pam img_pam, *tile_pam;
- pid_t *tile_pid;
- char *outfile_format = "%d,%d.pnm", *pipe_via = NULL;
- extern int opterr, optopt, optind;
- static const char optstr[] = "hvPsf:p:";
- int i, j, c, progress = 0, fast_and_ugly = 1;
- tuple *img_row = NULL; /* suppress bogus "might be used uninitialised" */
- unsigned char *buf = NULL;
- size_t img_rowlen = 0, tile_rowlen = 0;
-
- pnm_init(&argc, argv);
- opterr = 0;
-
- while (-1 != (c = getopt(argc, argv, optstr))) {
- switch (c) {
- case 'h':
- usage(stdout);
- return 0;
-
- case 'v':
- verbose = 1;
- /* fall through */
-
- case 'P':
- progress = 1;
- break;
-
- case 'f':
- outfile_format = optarg;
- break;
-
- case 'p':
- pipe_via = optarg;
- break;
-
- case 's':
- fast_and_ugly = 0;
- break;
-
- case '?':
- default:
- if (strchr(optstr, optopt))
- err("option -%c requires an argument", optopt);
- else
- err("unknown option -%c", optopt);
- die("try -h for help");
- }
- }
-
- if (argc - optind < 2 || argc - optind > 3) {
- err("two or three non-option arguments required");
- die("try -h for help");
- }
-
- if (0 == (tile_w = atoi(argv[optind])))
- die("\"%s\" is not a valid tile width", argv[optind]);
- else if (0 == (tile_h = atoi(argv[optind + 1])))
- die("\"%s\" is not a valid tile height", argv[optind + 1]);
-
- if (argv[optind + 2]) {
- img_name = argv[optind + 2];
- if (!(img_fp = fopen(img_name, "rb"))) {
- die("%s: %s", img_name, strerror(errno));
- return 1;
- }
- } else {
- img_name = "(standard input)";
- img_fp = stdin;
- }
-
- /* lamely, this will just abort if something goes wrong */
- pnm_readpaminit(img_fp, &img_pam, sizeof img_pam);
-
- /* couple of checks on the image dimensions */
- if (tile_w > img_pam.width)
- die("image width (%d) is smaller than tile width (%d)",
- img_pam.width, tile_w);
- else if (img_pam.width % tile_w) {
- err("warning: tile width does not divide image width exactly");
- err("warning: last %d columns of image will not be included in any tile",
- img_pam.width % tile_w);
- }
- cols = img_pam.width / tile_w;
-
- if (tile_h > img_pam.height)
- die("image height (%d) is smaller than tile height (%d)",
- img_pam.height, tile_h);
- else if (img_pam.height % tile_h) {
- err("warning: tile height does not divide image height exactly");
- err("warning: last %d rows of image will not be included in any tile",
- img_pam.height % tile_h);
- }
- rows = img_pam.height / tile_h;
-
- debug("input image is %d by %d pixels\n", img_pam.width, img_pam.height);
- debug(" = %d by %d tiles of %d by %d", cols, rows, tile_w, tile_h);
- debug("each pixel contains %d planes, %d bytes per sample",
- img_pam.depth, img_pam.bytes_per_sample);
-
- tile_fp = xmalloc(cols * sizeof *tile_fp);
- tile_pam = xmalloc(cols * sizeof *tile_pam);
- tile_pid = xmalloc(cols * sizeof *tile_pid);
-
- if (fast_and_ugly) {
- img_rowlen = img_pam.width * img_pam.depth * img_pam.bytes_per_sample;
- buf = xmalloc(img_rowlen);
- tile_rowlen = tile_w * img_pam.depth * img_pam.bytes_per_sample;
- } else if (!(img_row = pnm_allocpamrow(&img_pam)))
- die("unable to allocate storage for input row");
-
- for (j = 0; j < rows; ++j) {
- int y;
-
- /* Create output files. */
- debug("creating output files for row %d/%d...\n", j, rows);
- for (i = 0; i < cols; ++i) {
- tile_pam[i] = img_pam;
- tile_pam[i].file = tile_fp[i]
- = open_output_file(outfile_format, pipe_via, i, j,
- tile_pid + i);
- tile_pam[i].width = tile_w;
- tile_pam[i].height = tile_h;
- pnm_writepaminit(tile_pam + i);
- fflush(tile_fp[i]);
- }
-
- /* Copy the image into the various tiles. */
- for (y = 0; y < tile_h; ++y) {
- /* Ugly. libpnm is pretty slow, so for large images it is much
- * quicker to copy bytes from input to output streams using
- * straight stdio calls. If fast_and_ugly is true (the default)
- * then we use such an implementation; but it makes assumptions
- * about the format of the input PNM file which might not be
- * accurate. So we make this optional. */
- if (fast_and_ugly) {
- size_t n;
- if (img_rowlen != (n = fread(buf, 1, img_rowlen, img_fp))) {
- if (feof(img_fp))
- die("%s: premature EOF", img_name);
- else
- die("%s: %s", img_name, strerror(errno));
- }
- for (i = 0; i < cols; ++i) {
- if (tile_rowlen
- != (n = fwrite(buf + i * tile_rowlen,
- 1, tile_rowlen, tile_fp[i]))) {
- die("while writing tile (%d, %d): %s", i, j,
- strerror(errno));
- }
- fflush(tile_fp[i]);
- }
- } else {
- pnm_readpamrow(&img_pam, img_row);
- for (i = 0; i < cols; ++i) {
- pnm_writepamrow(tile_pam + i, img_row + i * tile_w);
- fflush(tile_fp[i]);
- }
- }
- if (progress)
- fprintf(stderr, "\r%d/%d", j * tile_h + y, img_pam.height);
- }
-
- /* Close the output files and check status. */
- debug("\rclosing output files for row %d/%d...\n", j, rows);
- for (i = 0; i < cols; ++i) {
- debug("closing fd %d... ", fileno(tile_fp[i]));
- if (-1 == fclose(tile_fp[i]))
- die("while writing tile (%d, %d): %s", i, j, strerror(errno));
- debug("done\n");
- }
-
- /* XXX I think there is a bug here, since if you close fd i, then
- * wait for child process i, the wait hangs. But I can't see the
- * problem at the moment. Actually calling wait synchronously here
- * is bogus anyway, since we could collect the notification when we
- * receive SIGCHLD, though that would risk spawning a vast number
- * of processes; at the moment we maintain as many child processes
- * as there are columns of tiles in the output. */
- if (pipe_via) {
- debug("waiting for termination of child processes\n");
- for (i = 0; i < cols; ++i) {
- /* Collect exit status of child process. */
- pid_t p;
- int st;
- debug("waiting for termination of process %d... ",
- (int)tile_pid[i]);
- if (-1 == (p = waitpid(tile_pid[i], &st, 0)))
- die("waitpid: %s", strerror(errno));
- else if (st) {
- if (WIFEXITED(st))
- die("child process for tile (%d, %d) failed with "
- "status %d", i, j, WEXITSTATUS(st));
- else
- die("child process for tile (%d, %d) killed by "
- "signal %d", i, j, WTERMSIG(st));
- }
- debug("exited\n");
- }
- }
- }
-
- if (progress)
- fprintf(stderr, "\r%d/%d\n", img_pam.height, img_pam.height);
- return 0;
-}
diff --git a/tileserver/Makefile b/tileserver/Makefile
deleted file mode 100644
index b9ffc302f..000000000
--- a/tileserver/Makefile
+++ /dev/null
@@ -1,31 +0,0 @@
-#
-# Makefile:
-# Build tile server.
-#
-# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
-# Email: chris@mysociety.org; WWW: http://www.mysociety.org/
-#
-# $Id: Makefile,v 1.1 2006-09-20 15:45:51 chris Exp $
-#
-
-CFLAGS = -Wall -g -O99 -I/software/include
-LDFLAGS = -L/software/lib
-LDLIBS = -lfcgi
-
-# for debugging
-#CFLAGS += -DNO_FASTCGI
-
-SRCS = base64.c cdb.c netstring.c tileserver.c tileset.c util.c
-OBJS = $(SRCS:.c=.o)
-HDRS = base64.h cdb.h netstring.h tileset.h util.h
-TXTS =
-
-tileserver: Makefile $(OBJS)
- $(CC) -o tileserver $(OBJS) $(LDFLAGS) $(LDLIBS)
-
-clean:
- rm -f tileserver $(OBJS) *~ core
-
-%.o: %.c Makefile
- $(CC) $(CFLAGS) -c -o $@ $<
-
diff --git a/tileserver/base64.c b/tileserver/base64.c
deleted file mode 100644
index 08723e31c..000000000
--- a/tileserver/base64.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * base64.c:
- * Base64 and "base64ish" encoding and decoding.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- */
-
-static const char rcsid[] = "$Id: base64.c,v 1.1 2006-09-20 10:25:14 chris Exp $";
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <string.h>
-
-static const char b64chars[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "+/=";
-
-static const char b64ishchars[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789"
- "-_=";
-
-/* base64_encode IN INLEN OUT B64ISH NOPAD
- * Encode INLEN bytes at IN into the buffer at OUT. The total number of bytes
- * written is recorded in *OUTLEN. OUT must have space for at least
- * 1 + 4 * (INLEN + 3) / 3 + 1 bytes. Returns a pointer to OUT. This function
- * always succeeds. If B64ISH is true, the alternate "base64ish" alphabet is
- * used instead of the standard one. If NOPAD is true, "=" padding is not added
- * at the end of the transformed buffer. */
-char *base64_encode(const void *in, const size_t inlen, char *out,
- const bool b64ish, const bool nopad) {
- const char *alphabet;
- const uint8_t *b;
- char *p;
- size_t i;
-
- alphabet = b64ish ? b64ishchars : b64chars;
- b = (const uint8_t*)in;
-
- for (i = 0, p = out; i < inlen; i += 3) {
- uint8_t bb[3] = {0};
- unsigned j;
- size_t n, k;
-
- n = inlen - i;
- if (n > 3) n = 3;
- for (k = 0; k < n; ++k) bb[k] = b[i + k];
-
- j = bb[0] >> 2;
- *(p++) = alphabet[j];
-
- j = ((bb[0] & 3) << 4) | (bb[1] >> 4);
- *(p++) = alphabet[j];
-
- if (n == 1) {
- if (!nopad) {
- *(p++) = '=';
- *(p++) = '=';
- }
- break;
- }
-
- j = ((bb[1] & 0xf) << 2) | (bb[2] >> 6);
- *(p++) = alphabet[j];
- if (n == 2) {
- if (!nopad)
- *(p++) = '=';
- break;
- }
-
- j = bb[2] & 0x3f;
- *(p++) = alphabet[j];
- }
-
- *p = 0;
-
- return out;
-}
-
-/* base64_decode IN OUT OUTLEN B64ISH
- * Decode the string at IN into OUT. If B64ISH is true, the alternate
- * "base64ish" alphabet is used instead of the standard one. Returns the number
- * of characters consumed and saves the number of output bytes decoded in
- * *OUTLEN; the number of characters consumed will be smaller than the length
- * of the input string if an invalid character was encountered in IN. OUT must
- * have space for at least 3 * (INLEN / 4) bytes of output. */
-size_t base64_decode(const char *in, void *out, size_t *outlen,
- const bool b64ish) {
- const char *alphabet;
- uint8_t *b;
- size_t inlen = 0, consumed = 0, len = 0, i;
-
- inlen = strlen(in);
- alphabet = b64ish ? b64ishchars : b64chars;
- b = (uint8_t*)out;
-
- for (i = 0; i < inlen; i += 4) {
- char bb[5] = "====";
- size_t n, j;
- const char *p;
-
- n = inlen - i;
- if (n > 4) n = 4;
- memcpy(bb, in + i, n);
-
- if (!(p = strchr(alphabet, bb[0])))
- break;
- j = p - alphabet;
- b[len] = (uint8_t)(j << 2);
- ++consumed;
-
- if (!(p = strchr(alphabet, bb[1])))
- break;
- j = p - alphabet;
- b[len++] |= (uint8_t)(j >> 4);
- b[len] = (uint8_t)(j << 4);
- ++consumed;
-
- if ('=' == bb[2]) {
- ++consumed;
- if ('=' == *p) ++consumed; /* potentially skip last char */
- break;
- } else if (!(p = strchr(alphabet, bb[2])))
- break;
- j = p - alphabet;
- b[len++] |= (uint8_t)(j >> 2);
- b[len] = (uint8_t)(j << 6);
- ++consumed;
-
- if ('=' == bb[3]) {
- ++consumed;
- break;
- } else if (!(p = strchr(alphabet, bb[3])))
- break;
- j = p - alphabet;
- b[len++] |= (uint8_t)j;
- ++consumed;
- }
-
- *outlen = len;
- return consumed;
-}
-
-#ifdef BASE64_TEST_PROGRAM
-
-/*
- * Small test program -- reads base64-encoded or raw data on standard input,
- * and writes on standard output the decoded/encoded version. Driven by
- * base64test.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-
-#define err(...) \
- do { \
- fprintf(stderr, "base64test: "); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- } while (0)
-#define die(...) do { err(__VA_ARGS__); exit(1); } while (0)
-
-struct datum {
- void *buf;
- size_t len;
-};
-
-static struct datum *netstring_read(FILE *fp) {
- unsigned int len = 0;
- int c;
- struct datum *d;
-
-#define FAIL(what) \
- do { \
- if (feof(fp)) \
- die("%s: Premature EOF", what); \
- else \
- die("%s: %s", what, strerror(errno)); \
- } while (0)
-
- while (EOF != (c = getc(fp))) {
- if (isdigit(c))
- len = 10 * len + c - '0';
- else if (c == ':')
- break;
- else
- die("bad character '%c' in netstring length", c);
- }
-
- if (feof(fp) || ferror(fp))
- FAIL("while reading netstring length");
-
- if (!(d = malloc((sizeof *d) + len + 1)))
- die("malloc: %s", strerror(errno));
- d->buf = (char*)d + (sizeof *d);
- d->len = len;
- ((char*)d->buf)[len] = 0; /* ensure NUL-terminated */
-
- if (d->len != fread(d->buf, 1, d->len, fp))
- FAIL("while reading netstring data");
-
- if (EOF == (c = getc(fp))) {
- if (feof(fp))
- die("while reading netstring trailer: Premature EOF");
- else
- die("while reading netstring trailer: %s", strerror(errno));
- }
-
- return d;
-}
-
-void netstring_write(FILE *fp, const struct datum *d) {
- fprintf(fp, "%u:", (unsigned)d->len);
- if (d->len != fwrite(d->buf, 1, d->len, fp))
- die("while writing netstring value: %s", strerror(errno));
- if (1 != fprintf(fp, ","))
- die("while writing netstring trailer: %s", strerror(errno));
-}
-
-/* main ARGC ARGV
- * Entry point. */
-int main(int argc, char *argv[]) {
- while (1) {
- int c;
- struct datum *d, d2;
- size_t l;
-
- if (EOF == (c = getc(stdin)))
- die("premature EOF reading command character");
- else if ('X' == c)
- break;
-
- d = netstring_read(stdin);
-
- switch (c) {
- case 'B': /* base64 */
- case 'b': /* base64ish */
- if (!(d2.buf = malloc(d->len)))
- die("malloc: %s", strerror(errno));
- l = base64_decode(d->buf, d2.buf, &d2.len, c == 'b');
- netstring_write(stdout, &d2);
- free(d2.buf);
- break;
-
- case 'R': /* to base64 */
- case 'r': /* to base64ish */
- if (!(d2.buf = malloc(1 + 4 * (1 + d->len / 3))))
- die("malloc: %s", strerror(errno));
- base64_encode(d->buf, d->len, d2.buf, c == 'r', 0);
- d2.len = strlen((char*)d2.buf);
- netstring_write(stdout, &d2);
- free(d2.buf);
- break;
-
- default:
- die("bad command character '%c'", c);
- }
-
- free(d);
- fflush(stdout);
- }
- return 0;
-}
-
-#endif /* BASE64_TEST_PROGRAM */
diff --git a/tileserver/base64.h b/tileserver/base64.h
deleted file mode 100644
index 3c61cabc3..000000000
--- a/tileserver/base64.h
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * base64.h:
- * Base64 and "base64ish" encoding and decoding.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- * $Id: base64.h,v 1.2 2006-09-20 13:22:58 chris Exp $
- *
- */
-
-#ifndef __BASE64_H_ /* include guard */
-#define __BASE64_H_
-
-#include <sys/types.h>
-
-#include <stdbool.h>
-
-/* base64.c */
-char *base64_encode(const void *in, const size_t inlen, char *out,
- const bool b64ish, const bool nopad);
-size_t base64_decode(const char *in, void *out, size_t *outlen,
- const bool b64ish);
-
-#endif /* __BASE64_H_ */
diff --git a/tileserver/cdb.c b/tileserver/cdb.c
deleted file mode 100644
index 2f9667f2d..000000000
--- a/tileserver/cdb.c
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
- * cdb.c:
- * Read data from Dan-Bernstein-style CDB files.
- *
- * See: http://cr.yp.to/cdb/cdb.txt -- but note also the statement in
- * http://cr.yp.to/cdb/reading.html that, "There may be several records under a
- * single key. You can use cdb_findnext to find the next record under this
- * key." We don't support (or use) this mode, but it should probably be added
- * to the code for completeness.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- */
-
-static const char rcsid[] = "$Id: cdb.c,v 1.6 2006-09-22 12:25:46 francis Exp $";
-
-#include <sys/types.h>
-
-#include <errno.h>
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <sys/stat.h>
-
-#define CDB_IMPL
-#include "cdb.h"
-
-#ifdef VERBOSE_DEBUGGING
-# define debug(...) \
- do { \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- } while (0)
-#else
-# define debug(...) do { } while (0)
-#endif /* VERBOSE_DEBUGGING */
-
-/* struct cdb
- * Internals of CDB object. */
-struct cdb {
- FILE *c_fp;
- struct stat c_st;
- bool c_close_on_destroy;
- struct {
- uint32_t off, len;
- } c_hashlocs[256];
-};
-
-/* Length of the initial portion of the file which gives the hash table
- * locations. */
-#define HASHPTR_LEN (256 * 8)
-
-static size_t do_fread(FILE *fp, void *buf, const size_t len) {
- return fread(buf, 1, len, fp);
-}
-
-/* cdb_hash BUF LEN
- * Return the hash value of the LEN bytes at BUF. */
-cdb_hash_t cdb_hash(const unsigned char *buf, const size_t len) {
- uint32_t h = 5381;
- size_t i;
- for (i = 0; i < len; ++i) {
- h = ((h << 5) + h) ^ buf[i];
- }
- return h;
-}
-
-/* cdb_hash_str STRING
- * Return the hash value of the given STRING. */
-cdb_hash_t cdb_hash_str(const char *s) {
- return cdb_hash((unsigned char*)s, strlen(s));
-}
-
-/* cdb_hash_datum D
- * Return the hash value of the DATUM. */
-cdb_hash_t cdb_hash_datum(const cdb_datum d) {
- return cdb_hash(d->cd_buf, d->cd_len);
-}
-
-/* cdb_open_fp FP
- * Open a CDB file for which a stdio file pointer FP is available. Returns a
- * cdb object on success or NULL on failure, setting cdb_errno. */
-cdb cdb_open_fp(FILE *fp) {
- struct cdb *C = NULL, Cz = {0};
- unsigned char buf[HASHPTR_LEN];
- struct stat st;
- int i;
-
-#define FAIL(e) do { cdb_errno = e; goto fail; } while (0)
-
- if (-1 == fstat(fileno(fp), &st))
- FAIL(errno);
-
- if (st.st_size < HASHPTR_LEN)
- FAIL(CDB_FILE_TOO_SMALL);
-
- if (!(C = malloc(sizeof *C)))
- FAIL(CDB_OUT_OF_MEMORY);
-
- /* wording conditional like this prevents a warning with 32-bit off_t */
- if ((st.st_size >> 31) > 1)
- FAIL(CDB_FILE_TOO_BIG);
-
- *C = Cz;
- C->c_fp = fp;
- C->c_st = st;
-
- if (HASHPTR_LEN != do_fread(fp, buf, HASHPTR_LEN)) {
- if (feof(fp))
- FAIL(CDB_FILE_TRUNCATED);
- else
- FAIL(errno);
- }
-
- for (i = 0; i < 256; ++i) {
- memcpy(&C->c_hashlocs[i].off, buf + 8 * i, 4);
- memcpy(&C->c_hashlocs[i].len, buf + 8 * i + 4, 4);
- /* byte ordering -- CDB is defined as a little-endian format, so
- * this is fine on i386, but not elsewhere. */
- /* NB len is in slots not bytes */
- if (C->c_hashlocs[i].off < HASHPTR_LEN
- || C->c_hashlocs[i].off > C->c_st.st_size
- || C->c_st.st_size - C->c_hashlocs[i].off < C->c_hashlocs[i].len * 8)
- FAIL(CDB_BAD_HASHLOC_PTR);
- }
-
- return C;
-
-fail:
- free(C);
- return NULL;
-
-#undef FAIL
-}
-
-/* yuk */
-#define ALIGNMENT 4 /* __alignof(long double) on i386 */
-typedef uint32_t ptr_int_t; /* XXX needs changing on 64-bit architectures */
-
-/* cdb_datum_alloc LEN
- * Allocate space for a single cdb_datum holding up to LEN bytes. Free with
- * cdb_datum_free. Returns the newly-allocated datum on success or NULL on
- * failure (out of memory). */
-cdb_datum cdb_datum_alloc(const size_t len) {
- cdb_datum d;
- if (!(d = malloc((sizeof *d) + ALIGNMENT + len))) {
- cdb_errno = CDB_OUT_OF_MEMORY;
- return NULL;
- }
- d->cd_buf = (void*)(((ptr_int_t)d + (sizeof *d) + ALIGNMENT) & ~(ALIGNMENT - 1));
- d->cd_len = len;
- return d;
-}
-
-/* cdb_datum_free D
- * Free storage associated with D. */
-void cdb_datum_free(cdb_datum d) {
- if (d) free(d);
-}
-
-/* cdb_open FILE
- * Open the named CDB FILE, returning a cdb object on success or NULL on
- * failure, setting cdb_errno. */
-cdb cdb_open(const char *name) {
- cdb C = NULL;
- FILE *fp;
- if (!(fp = fopen(name, "rb"))) {
- cdb_errno = errno;
- return NULL;
- } else if (!(C = cdb_open_fp(fp)))
- fclose(fp);
- else
- C->c_close_on_destroy = 1;
- return C;
-}
-
-/* cdb_close C
- * Free storage associated with C, and, if it was opened by cdb_open, also
- * close the associated file pointer. */
-void cdb_close(cdb C) {
- if (!C) return;
- if (C->c_close_on_destroy)
- fclose(C->c_fp);
- free(C);
-}
-
-/* get_slot C OFFSET SLOT HASH WHERE
- * Save in *HASH and *WHERE the hash value and offset in the file pointed to by
- * the indexed SLOT in the hash table beginning at OFFSET. Returns 0 on success
- * or an error code on failure. */
-static cdb_result_t get_slot(cdb C, const uint32_t offset, const uint32_t slot,
- cdb_hash_t *hash, uint32_t *where) {
- unsigned char buf[8];
-
- if (-1 == fseek(C->c_fp, offset + 8 * slot, SEEK_SET))
- return errno;
-
- if (8 != do_fread(C->c_fp, buf, 8)) {
- if (feof(C->c_fp))
- return CDB_FILE_TRUNCATED;
- else
- return errno;
- }
-
- memcpy(hash, buf, 4);
- memcpy(where, buf + 4, 4);
-
- return 0;
-}
-
-/* cdb_get C KEY
- * Look up the database entry identified by KEY. Returns the data retrieved on
- * success or NULL on failure, setting cdb_errno. The returned data should be
- * freed with cdb_datum_free. */
-/* XXX add a mode where caller supplies storage */
-cdb_datum cdb_get(cdb C, const cdb_datum key) {
- cdb_hash_t h, h8, sh;
- uint32_t slot0, slot;
- cdb_datum val = NULL;
-
-#define FAIL(e) do { cdb_errno = e; goto fail; } while (0)
-
- if (key->cd_len > C->c_st.st_size)
- FAIL(CDB_NOT_FOUND);
-
- h = cdb_hash_datum(key);
- h8 = h & 0xff;
-
- debug("key len = %u", (unsigned)key->cd_len);
- debug("hash = %08x, hash255 = %02x", (unsigned)h, (unsigned)h8);
-
- if (!C->c_hashlocs[h8].off || !C->c_hashlocs[h8].len)
- FAIL(CDB_NOT_FOUND);
-
- debug("hash table %u starts at offset %u and has %u slots",
- (unsigned)h8,
- (unsigned)C->c_hashlocs[h8].off,
- (unsigned)C->c_hashlocs[h8].len);
-
- slot = slot0 = (h >> 8) % C->c_hashlocs[h8].len;
-
- debug(" %06x %% %u = %u", (unsigned)(h >> 8), C->c_hashlocs[h8].len, (unsigned)slot);
-
- do {
- unsigned char buf[8];
- uint32_t where, keylen, vallen;
- cdb_result_t e;
-
- debug(" looking in slot %u", (unsigned)slot);
-
- if ((e = get_slot(C, C->c_hashlocs[h8].off, slot, &sh, &where)))
- FAIL(e);
-
- debug(" hash = %08x, offset = %u", (unsigned)sh, (unsigned)where);
-
- if (sh == h) {
- if (0 == where)
- FAIL(CDB_NOT_FOUND);
-
- /* Have a potential slot. Grab the key and value length. */
- if (-1 == fseek(C->c_fp, where, SEEK_SET))
- FAIL(errno);
- else if (8 != do_fread(C->c_fp, buf, 8)) {
- if (feof(C->c_fp))
- FAIL(CDB_FILE_TRUNCATED);
- else
- FAIL(errno);
- }
-
- memcpy(&keylen, buf, 4);
- memcpy(&vallen, buf + 4, 4);
-
- debug(" key len = %u, val len = %u",
- (unsigned)keylen, (unsigned)vallen);
-
- if (keylen == key->cd_len) {
- size_t i;
- for (i = 0; i < key->cd_len; ++i) {
- int c;
- if (EOF == (c = getc(C->c_fp))) {
- if (feof(C->c_fp))
- FAIL(CDB_FILE_TRUNCATED);
- else
- FAIL(errno);
- } else if (c != (int)(((unsigned char*)key->cd_buf)[i]))
- break;
- }
-
- if (i == key->cd_len) {
- /* Got it. */
- if (!(val = cdb_datum_alloc(vallen + 1)))
- FAIL(CDB_OUT_OF_MEMORY);
- /* Ensure NUL-terminated. */
- ((char*)val->cd_buf)[vallen] = 0;
- val->cd_len--;
- if (val->cd_len != do_fread(C->c_fp, val->cd_buf,
- val->cd_len)) {
- if (feof(C->c_fp))
- FAIL(CDB_FILE_TRUNCATED);
- else
- FAIL(errno);
- } else
- return val;
- }
- }
- }
-
- slot = (slot + 1) % C->c_hashlocs[h8].len;
- } while (slot != slot0);
-
- cdb_errno = CDB_NOT_FOUND;
-
-fail:
- if (val) cdb_datum_free(val);
- return NULL;
-
-#undef FAIL
-}
-
-/* cdb_get_string C STRING
- * As for cdb_get, but construct the KEY datum from STRING. */
-cdb_datum cdb_get_string(cdb C, const char *s) {
- struct cdb_datum d;
- d.cd_len = strlen(s);
- d.cd_buf = (void*)s;
- return cdb_get(C, &d);
-}
-
-/* cdb_get_buf C BUF LEN
- * As for cdb_get, buf construct the KEY datum from BUF and LEN. */
-cdb_datum cdb_get_buf(cdb C, const void *buf, const size_t len) {
- struct cdb_datum d;
- d.cd_len = len;
- d.cd_buf = (void*)buf;
- return cdb_get(C, &d);
-}
-
-/* cdb_strerror E
- * Return the text of the error message corresponding to E. */
-char *cdb_strerror(const cdb_result_t e) {
- if (e > 0)
- return strerror(e);
- else if (e == 0)
- return "Success";
- else {
- switch (e) {
- case CDB_OUT_OF_MEMORY:
- return "Out of memory";
- case CDB_FILE_TOO_SMALL:
- return "File is too small to be a valid CDB file";
- case CDB_FILE_TOO_BIG:
- return "File is too large to be a valid CDB file";
- case CDB_BAD_HASHLOC_PTR:
- return "Bad hash-table location pointer in CDB file header";
- case CDB_BAD_RECORD_PTR:
- return "Bad record location pointer in CDB hash table";
- case CDB_NOT_FOUND:
- return "Record not found in CDB file";
- default:
- return "Unknown CDB internal error code";
- }
- }
-}
-
-#ifdef CDB_TEST_PROGRAM
-
-/*
- * Little test program -- reads keys as netstrings on standard input, and
- * writes on standard output either "X" for not found, or netstrings giving the
- * values of those keys.
- */
-
-#include <ctype.h>
-
-#define err(...) \
- do { \
- fprintf(stderr, "cdbtest: "); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- } while (0)
-#define die(...) do { err(__VA_ARGS__); exit(1); } while (0)
-
-static cdb_datum netstring_read(FILE *fp) {
- unsigned int len = 0;
- int c;
- cdb_datum d;
-
-#define FAIL(what) \
- do { \
- if (feof(fp)) \
- die("%s: Premature EOF", what); \
- else \
- die("%s: %s", what, strerror(errno)); \
- } while (0)
-
- while (EOF != (c = getc(fp))) {
- if (isdigit(c))
- len = 10 * len + c - '0';
- else if (c == ':')
- break;
- else
- die("bad character '%c' in netstring length", c);
- }
-
- if (feof(fp) || ferror(fp))
- FAIL("while reading netstring length");
-
- if (!(d = cdb_datum_alloc(len)))
- die("while reading netstring: cdb_datum_alloc(%u): %s",
- len, cdb_strerror(cdb_errno));
-
- if (d->cd_len != do_fread(fp, d->cd_buf, d->cd_len))
- FAIL("while reading netstring data");
-
- if (EOF == (c = getc(fp))) {
- if (feof(fp))
- die("while reading netstring trailer: Premature EOF");
- else
- die("while reading netstring trailer: %s", strerror(errno));
- }
-
- return d;
-}
-
-void netstring_write(FILE *fp, const cdb_datum d) {
- fprintf(fp, "%u:", (unsigned)d->cd_len);
- if (d->cd_len != fwrite(d->cd_buf, 1, d->cd_len, fp))
- die("while writing netstring value: %s", strerror(errno));
- if (1 != fprintf(fp, ","))
- die("while writing netstring trailer: %s", strerror(errno));
-}
-
-/* main ARGC ARGV
- * Entry point. */
-int main(int argc, char *argv[]) {
- cdb C;
- if (argc != 2)
- die("single argument should be name of CDB file");
- else if (!(C = cdb_open(argv[1])))
- die("%s: %s", argv[1], cdb_strerror(cdb_errno));
-
- while (1) {
- cdb_datum key, val;
- int c;
-
- c = getc(stdin);
- if ('X' == c)
- break;
- else
- ungetc(c, stdin);
- key = netstring_read(stdin);
-
- if (!(val = cdb_get(C, key))) {
- if (CDB_NOT_FOUND == cdb_errno)
- putc('X', stdout);
- else
- die("cdb_get: %s", cdb_strerror(cdb_errno));
- } else {
- netstring_write(stdout, val);
- cdb_datum_free(val);
- }
- fflush(stdout);
-
- cdb_datum_free(key);
- }
-
- cdb_close(C);
-
- return 0;
-}
-
-#endif /* CDB_TEST_PROGRAM */
diff --git a/tileserver/cdb.h b/tileserver/cdb.h
deleted file mode 100644
index e5959297f..000000000
--- a/tileserver/cdb.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * cdb.h:
- * Interface to Dan-Bernstein-style CDB files.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- * $Id: cdb.h,v 1.4 2006-09-20 14:24:10 chris Exp $
- *
- */
-
-#ifndef __CDB_H_ /* include guard */
-#define __CDB_H_
-
-#include <sys/types.h>
-
-#include <stdint.h>
-#include <stdio.h>
-
-typedef int cdb_result_t;
-typedef uint32_t cdb_hash_t;
-
-typedef struct cdb_datum {
- void *cd_buf;
- size_t cd_len;
-} *cdb_datum;
-
-typedef struct cdb *cdb;
-
-/* error codes */
-#define CDB_OUT_OF_MEMORY -1
-#define CDB_FILE_TOO_SMALL -2
-#define CDB_FILE_TOO_BIG -3
-#define CDB_FILE_TRUNCATED -4
- /* one of the initial 256 pointers pointed outside the file */
-#define CDB_BAD_HASHLOC_PTR -5
- /* a datum pointer pointed outside the file or otherwise somewhere bogus */
-#define CDB_BAD_RECORD_PTR -6
- /* the record wasn't found */
-#define CDB_NOT_FOUND -7
-
-#ifndef CDB_IMPL
-extern
-#endif /* CDB_IMPL */
- cdb_result_t cdb_errno; /* XXX threads */
-
-/* cdb.c */
-cdb_hash_t cdb_hash(const unsigned char *buf, const size_t len);
-cdb_hash_t cdb_hash_str(const char *s);
-cdb_hash_t cdb_hash_datum(const cdb_datum d);
-cdb cdb_open_fp(FILE *fp);
-cdb cdb_open(const char *name);
-void cdb_close(cdb C);
-cdb_datum cdb_datum_alloc(const size_t len);
-void cdb_datum_free(cdb_datum d);
-cdb_datum cdb_get(cdb C, const cdb_datum key);
-cdb_datum cdb_get_string(cdb C, const char *str);
-cdb_datum cdb_get_buf(cdb C, const void *buf, const size_t len);
-char *cdb_strerror(const cdb_result_t e);
-
-#endif /* __CDB_H_ */
diff --git a/tileserver/cdbtestrun b/tileserver/cdbtestrun
deleted file mode 100755
index a83c23e60..000000000
--- a/tileserver/cdbtestrun
+++ /dev/null
@@ -1,149 +0,0 @@
-#!/usr/bin/perl -w
-#
-# cdbtestrun:
-# Run the CDB test program.
-#
-# Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
-# Email: chris@mysociety.org; WWW: http://www.mysociety.org/
-#
-
-my $rcsid = ''; $rcsid .= '$Id: cdbtestrun,v 1.1 2006-09-19 18:26:35 chris Exp $';
-
-use strict;
-
-use CDB_File;
-use IO::Pipe;
-use POSIX qw();
-
-sub random_string ($) {
- my $len = shift;
- my $x = '';
- while (length($x) < $len) {
- $x .= pack('N', int(rand(0xffffffff)));
- }
- return substr($x, 0, $len);
-}
-
-my %h;
-my $C = new CDB_File("test.cdb", "test.tmp")
- or die "test.tmp: $!";
-
-my $nkeys = shift(@ARGV);
-$nkeys ||= 100000;
-die "'$nkeys' is not a valid number of keys" if ($nkeys !~ /^[1-9]\d*$/);
-
-for (my $i = 0; $i < $nkeys; ++$i) {
- my $key;
- do {
- $key = random_string(1 + int(rand(16)));
- } while (exists($h{$key}));
- my $val = random_string(int(rand(100)));
-
- $h{$key} = $val;
- $C->insert($key, $val);
-
- printf STDERR "\rwriting keys: %d/%d", $i, $nkeys
- if (0 == ($i % 100));
-}
-
-print STDERR "\rwriting keys: $nkeys/$nkeys\n";
-print STDERR "finalising database... ";
-$C->finish();
-print STDERR "done\n";
-
-# Make a pipe to the test program and fork it.
-my $p1 = new IO::Pipe(); # parent writes to this
-my $p2 = new IO::Pipe(); # and reads from this.
-
-my $pid = fork();
-if (!defined($pid)) {
- die "fork: $!";
-} elsif (0 == $pid) {
- $p1->reader();
- POSIX::close(0);
- POSIX::dup($p1->fileno());
- $p2->writer();
- POSIX::close(1);
- POSIX::dup($p2->fileno());
-
-# { exec("valgrind", "./cdbtest", "test.cdb"); }
- { exec("./cdbtest", "test.cdb"); }
-
- print STDERR "exec ./cdbtest: $!\n";
- POSIX::_exit(255);
-}
-
-sub netstring_read ($) {
- my $h = shift;
- my $len = 0;
- while (defined(my $c = $h->getc())) {
- if ($c eq 'X' && $len == 0) {
- return undef;
- } elsif ($c eq ':') {
- last;
- } elsif ($c !~ /^\d$/) {
- die "bad character '$c' in netstring length";
- } else {
- $len = $len * 10 + ord($c) - ord('0');
- }
- }
-
- my $buf = '';
- $h->read($buf, $len, 0);
-
- if ($h->getc() ne ',') {
- die "bad character at netstring trailer";
- }
-
- return $buf;
-}
-
-sub netstring_write ($$) {
- my $h = shift;
- $h->printf('%d:', length($_[0]));
- $h->print($_[0]);
- $h->print(',');
- $h->flush();
-}
-
-$p1->writer();
-$p2->reader();
-
-print STDERR "child pid = $pid... press enter to continue\n";
-<STDIN>;
-
-my $n = 0;
-foreach my $key (keys(%h)) {
- if (rand() < 0.05) {
- my $key;
- do {
- $key = random_string(1 + int(rand(16)));
- } while (exists($h{$key}));
- netstring_write($p1, $key);
- my $val = netstring_read($p2);
- if (defined($val)) {
- die "test code said value present when it wasn't";
- }
- }
-
- netstring_write($p1, $key);
- my $val = netstring_read($p2);
- if (!defined($val)) {
- die "test code said val was not present when it was";
- } elsif ($val ne $h{$key}) {
- print "GOT=$val\n";
- print "WANTED=$val\n";
- die "value mismatch";
- }
-
- ++$n;
- printf STDERR "\rtesting %d/%d", $n, $nkeys
- if (0 == ($n % 100));
-}
-print STDERR "\rtesting $n/$nkeys\n";
-
-$p1->write('X');
-$p1->flush();
-wait();
-
-print STDERR "completed with no errors\n";
diff --git a/tileserver/netstring.c b/tileserver/netstring.c
deleted file mode 100644
index f6bbc3b72..000000000
--- a/tileserver/netstring.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * netstring.c:
- * Write netstrings to strings.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- */
-
-static const char rcsid[] = "$Id: netstring.c,v 1.2 2006-09-20 13:24:08 chris Exp $";
-
-#include <sys/types.h>
-#include <stdio.h>
-#include <string.h>
-
-/* netstring_write OUT BUFFER LEN
- * Write the LEN-byte BUFFER to OUT as a netstring, returning the number of
- * bytes. If OUT is NULL, returns the number of bytes required. */
-size_t netstring_write(char *out, const void *buf, const size_t len) {
- size_t l = 0;
- char dummy[32];
- l += sprintf(out ? out : dummy, "%u:", (unsigned)len);
- if (out) memcpy(out + l, buf, len);
- l += len;
- if (out) out[l] = ',';
- ++l;
- return l;
-}
-
-/* netstring_write_string OUT STRING
- * Write the NUL-terminated STRING to OUT as a netstring, returning the number
- * of bytes used. If OUT is NULL, return the number of bytes required. */
-size_t netstring_write_string(char *out, const char *str) {
- return netstring_write(out, str, strlen(str));
-}
-
-/* netstring_write_string OUT I
- * Write I to OUT as a decimal integer formatted as a netstring, returning the
- * number of bytes used. If OUT is NULL, return the number of bytes required. */
-size_t netstring_write_int(char *out, const int i) {
- char str[32];
- sprintf(str, "%d", i);
- return netstring_write_string(out, str);
-}
diff --git a/tileserver/netstring.h b/tileserver/netstring.h
deleted file mode 100644
index 83d5aabfc..000000000
--- a/tileserver/netstring.h
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * netstring.h:
- * Write netstrings into strings.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- * $Id: netstring.h,v 1.1 2006-09-20 10:25:14 chris Exp $
- *
- */
-
-#ifndef __NETSTRING_H_ /* include guard */
-#define __NETSTRING_H_
-
-#include <sys/types.h>
-
-/* netstring.c */
-size_t netstring_write(char *out, const void *buf, const size_t len);
-size_t netstring_write_string(char *out, const char *str);
-size_t netstring_write_int(char *out, const int i);
-
-#endif /* __NETSTRING_H_ */
diff --git a/tileserver/tileserver.c b/tileserver/tileserver.c
deleted file mode 100644
index 672319c11..000000000
--- a/tileserver/tileserver.c
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * tileserver.c:
- * Serve map tiles and information about map tiles.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- */
-
-static const char rcsid[] = "$Id: tileserver.c,v 1.10 2006-09-22 12:25:43 chris Exp $";
-
-/*
- * This is slightly complicated by the fact that we indirect tile references
- * via hashes of the tiles themselves. We support the following queries:
- *
- * http://host/path/tileserver/TILESET/HASH
- * to get an individual tile image in TILESET identified by HASH;
- * http://host/path/tileserver/TILESET/E,N/FORMAT
- * to get the identity of the tile at (E, N) in TILESET in the given
- * FORMAT;
- * http://host/path/tileserver/TILESET/W-E,S-N/FORMAT
- * to get the identities of the tiles in the block with SW corner (W, S)
- * and NE corner (E, N) in the given FORMAT.
- *
- * What FORMATS should we support? RABX and JSON are the obvious ones I guess.
- * Add TEXT for debugging.
- */
-
-#include <sys/types.h>
-
-#include <errno.h>
-#ifndef NO_FASTCGI
-#include <fcgi_stdio.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#include <sys/stat.h>
-
-#include "base64.h"
-#include "netstring.h"
-#include "tileset.h"
-#include "util.h"
-
-/* tiles_basedir
- * The configured path to tilesets. */
-static char *tiles_basedir;
-
-#define HTTP_BAD_REQUEST 400
-#define HTTP_UNAUTHORIZED 401
-#define HTTP_FORBIDDEN 403
-#define HTTP_NOT_FOUND 404
-#define HTTP_INTERNAL_SERVER_ERROR 500
-#define HTTP_NOT_IMPLEMENTED 501
-#define HTTP_SERVICE_UNAVAILABLE 503
-
-/* error STATUS TEXT
- * Send an error to the client with the given HTTP STATUS and TEXT. */
-void error(int status, const char *s) {
- if (status < 100 || status > 999)
- status = 500;
- printf(
- "Status: %03d\r\n"
- "Content-Type: text/plain; charset=us-ascii\r\n"
- "Content-Length: %u\r\n"
- "\r\n"
- "%s\n",
- status,
- strlen(s) + 1,
- s);
-}
-
-/* struct request
- * Definition of a request we handle. */
-struct request {
- char *r_tileset;
- enum {
- FN_GET_TILE = 0,
- FN_GET_TILEIDS
- } r_function;
-
- uint8_t r_tileid[TILEID_LEN];
-
- int r_west, r_east, r_south, r_north;
- enum {
- F_RABX,
- F_JSON,
- F_TEXT,
- F_HTML
- } r_format;
-
- char *r_buf;
-};
-
-void request_free(struct request *R);
-
-/* request_parse PATHINFO
- * Parse a request from PATHINFO. Returns a request on success or NULL on
- * failure. */
-struct request *request_parse(const char *path_info) {
- const char *p, *q;
- struct request *R = NULL, Rz = {0};
-
- /* Some trivial syntax checks. */
- if (!*path_info || *path_info == '/' || !strchr(path_info, '/')) {
- err("PATH_INFO of \"%s\" is not a valid request", path_info);
- return NULL;
- }
-
-
- /*
- * TILESET/HASH
- * TILESET/E,N/FORMAT
- * TILESET/W-E,S-N/FORMAT
- */
-
- /* Tileset name consists of alphanumerics and hyphen. */
- p = path_info + strspn(path_info,
- "0123456789"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "-");
-
- if (*p != '/')
- return NULL;
-
- R = xmalloc(sizeof *R);
- *R = Rz;
- R->r_buf = xmalloc(strlen(path_info) + 1);
- R->r_tileset = R->r_buf;
-
- strncpy(R->r_tileset, path_info, p - path_info);
- R->r_tileset[p - path_info] = 0;
-
- ++p;
-
- /* Mode. */
- if ((q = strchr(p, '/'))) {
- /* Tile IDs request. */
- R->r_function = FN_GET_TILEIDS;
-
- /* Identify format requested. */
- ++q;
- if (!strcmp(q, "RABX"))
- R->r_format = F_RABX;
- else if (!strcmp(q, "JSON"))
- R->r_format = F_JSON;
- else if (!strcmp(q, "text"))
- R->r_format = F_TEXT;
- else if (!strcmp(q, "html"))
- R->r_format = F_HTML;
- else {
- err("request for unknown tile ID result format \"%s\"", q);
- goto fail;
- }
-
- if (4 == sscanf(p, "%d-%d,%d-%d",
- &R->r_west, &R->r_east, &R->r_south, &R->r_north)) {
- if (R->r_west < 0 || R->r_south < 0
- || R->r_east < R->r_west || R->r_north < R->r_south) {
- err("area range query has invalid coordinates or order");
- goto fail;
- } else
- return R;
- } else if (2 == sscanf(p, "%d,%d", &R->r_west, &R->r_south)) {
- R->r_east = R->r_west;
- R->r_north = R->r_south;
- if (R->r_west < 0 || R->r_south < 0) {
- err("tile ID query has negative coordinates");
- goto fail;
- } else
- return R;
- }
- } else {
- size_t l;
-
- /* Tile request. */
- R->r_function = FN_GET_TILE;
- if (strlen(p) != TILEID_LEN_B64)
- goto fail;
-
- /* Decode it. Really this is "base64ish", so that we don't have to
- * deal with '+' or '/' in the URL. */
- base64_decode(p, R->r_tileid, &l, 1);
- if (l != TILEID_LEN)
- goto fail;
-
- return R;
- }
-
-fail:
- request_free(R);
- return NULL;
-}
-
-/* request_free R
- * Free storage allocated for R. */
-void request_free(struct request *R) {
- if (!R) return;
- xfree(R->r_buf);
- xfree(R);
-}
-
-void handle_request(void) {
- char *path_info;
- struct request *R;
- static char *path;
- static size_t pathlen;
- size_t l;
- tileset T;
- time_t now;
- struct tm *tm;
- char date[32];
- const char *last_modified = "Wed, 20 Sep 2006 17:27:40 GMT";
- const unsigned cache_max_age = 365 * 86400;
-
- /* Date: header is required if we give a 304 Not Modified response. */
- time(&now);
- tm = gmtime(&now);
- strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S GMT", tm);
-
- /* All requests are given via PATH_INFO. */
- if (!(path_info = getenv("PATH_INFO"))) {
- error(400, "No request path supplied");
- return;
- }
-
- if ('/' == *path_info)
- ++path_info;
-
- if (!(R = request_parse(path_info))) {
- error(400, "Bad request");
- return;
- }
-
- /* So we have a valid request. */
- l = strlen(R->r_tileset) + strlen(tiles_basedir) + 2;
- if (pathlen < l)
- path = xrealloc(path, pathlen = l);
- sprintf(path, "%s/%s", tiles_basedir, R->r_tileset);
-
- if (!(T = tileset_open(path))) {
- error(404, "Tileset not found");
- /* XXX assumption about the nature of the error */
- request_free(R);
- return;
- }
-
- /* XXX this is poor -- if the client sends If-Modified-Since: we just
- * assume that it hasn't been. We might want to do something more clever at
- * some point. */
- if (getenv("HTTP_IF_MODIFIED_SINCE")) {
- printf(
- "Status: 304 Not Modified\r\n"
- "Date: %s\r\n"
- "\r\n", date);
- tileset_close(T);
- request_free(R);
- return;
- }
-
- if (FN_GET_TILE == R->r_function) {
- /*
- * Send a single tile image to the client.
- */
- void *buf;
- size_t len;
-
- if ((buf = tileset_get_tile(T, R->r_tileid, &len))) {
- printf(
- "Content-Type: image/png\r\n"
- "Content-Length: %u\r\n"
- "Last-Modified: %s\r\n"
- "Date: %s\r\n"
- "Cache-Control: max-age=%u\r\n"
- "\r\n", len, last_modified, date, cache_max_age);
- fwrite(buf, 1, len, stdout);
- xfree(buf);
- } else
- error(404, "Tile not found");
- /* XXX error assumption */
- } else if (FN_GET_TILEIDS == R->r_function) {
- /*
- * Send one or more tile IDs to the client, in some useful format.
- */
- unsigned x, y;
- static char *buf;
- static size_t buflen, n;
- unsigned rows, cols;
- char *p;
-
- rows = R->r_north + 1 - R->r_south;
- cols = R->r_east + 1 - R->r_west;
- n = cols * rows;
- if (buflen < n * TILEID_LEN_B64 + 256)
- buf = xrealloc(buf, buflen = n * TILEID_LEN_B64 + 256);
-
- /* Send start of array in whatever format. */
- p = buf;
- switch (R->r_format) {
- case F_RABX:
- /* Format as array of arrays. */
- *(p++) = 'L';
- p += netstring_write_int(p, (int)rows);
- break;
-
- case F_JSON:
- /* Ditto. */
- *(p++) = '[';
- break;
-
- case F_TEXT:
- /* Space and LF separated matrix so no special leader. */
- break;
-
- case F_HTML:
- strcpy(p,
- "<html><head><title>tileserver test</title></head><body>");
- p += strlen(p);
-
- if (R->r_west > 0)
- p += sprintf(p, "<a href=\"../%u-%u,%u-%u/html\">west</a> ",
- R->r_west - 1, R->r_east - 1,
- R->r_south, R->r_north);
- p += sprintf(p, "<a href=\"../%u-%u,%u-%u/html\">east</a> ",
- R->r_west + 1, R->r_east + 1,
- R->r_south, R->r_north);
-
- p += sprintf(p, "<a href=\"../%u-%u,%u-%u/html\">north</a> ",
- R->r_west, R->r_east,
- R->r_south + 1, R->r_north + 1);
- if (R->r_south > 0)
- p += sprintf(p, "<a href=\"../%u-%u,%u-%u/html\">south</a> ",
- R->r_west, R->r_east,
- R->r_south - 1, R->r_north - 1);
- p += sprintf(p, "<br>");
- break;
- }
-
- /* Iterate over tile IDs. */
- for (y = R->r_north; y >= R->r_south; --y) {
- switch (R->r_format) {
- case F_RABX:
- *(p++) = 'L';
- p += netstring_write_int(p, (int)cols);
- break;
-
- case F_JSON:
- *(p++) = '[';
- break;
-
- case F_TEXT:
- break; /* nothing */
-
- case F_HTML:
- break; /* nothing */
- }
-
- for (x = R->r_west; x <= R->r_east; ++x) {
- uint8_t id[TILEID_LEN];
- char idb64[TILEID_LEN_B64 + 1];
- bool isnull = 0;
-
- if (!(tileset_get_tileid(T, x, y, id)))
- isnull = 1;
- else
- base64_encode(id, TILEID_LEN, idb64, 1, 1);
-
- if (p + 256 > buf + buflen) {
- size_t n;
- n = p - buf;
- buf = xrealloc(buf, buflen *= 2);
- p = buf + n;
- }
-
- switch (R->r_format) {
- case F_RABX:
- if (isnull)
- *(p++) = 'N';
- else {
- *(p++) = 'T';
- p += netstring_write_string(p, idb64);
- }
- break;
-
- case F_JSON:
- if (isnull) {
- strcpy(p, "null");
- p += 4;
- } else {
- *(p++) = '"';
- strcpy(p, idb64);
- p += TILEID_LEN_B64;
- *(p++) = '"';
- }
- if (x < R->r_east)
- *(p++) = ',';
- break;
-
- case F_TEXT:
- if (isnull)
- *(p++) = '-';
- else {
- strcpy(p, idb64);
- p += TILEID_LEN_B64;
- }
- if (x < R->r_east)
- *(p++) = ' ';
- break;
-
- case F_HTML:
- if (isnull)
- ; /* not much we can do without the tile sizes */
- else
- p += sprintf(p,
- "<img title=\"%u,%u\" src=\"../%s\">",
- x, y,
- idb64);
- break;
- }
- }
-
- switch (R->r_format) {
- case F_RABX:
- break; /* no row terminator */
-
- case F_JSON:
- *(p++) = ']';
- if (y < R->r_north)
- *(p++) = ',';
- break;
-
- case F_TEXT:
- *(p++) = '\n';
- break;
-
- case F_HTML:
- p += sprintf(p, "<br>");
- break;
- }
- }
-
- /* Array terminator. */
- switch (R->r_format) {
- case F_RABX:
- break;
-
- case F_JSON:
- *(p++) = ']';
- break;
-
- case F_TEXT:
- break;
-
- case F_HTML:
- p += sprintf(p, "</body></html>");
- }
- /* NB no terminating NUL */
-
- /* Actually send it. */
- printf("Content-Type: ");
- switch (R->r_format) {
- case F_RABX:
- printf("application/octet-stream");
- break;
-
- case F_JSON:
- /* Not really clear what CT to use here but Yahoo use
- * "text/javascript" and presumably they've done more testing
- * than us.... */
- printf("text/javascript");
- break;
-
- case F_TEXT:
- printf("text/plain; charset=us-ascii");
- break;
-
- case F_HTML:
- printf("text/html; charset=us-ascii");
- break;
- }
- printf("\r\n"
- "Content-Length: %u\r\n"
- "Last-Modified: %s\r\n"
- "Date: %s\r\n"
- "Cache-Control: max-age=%u\r\n"
- "\r\n",
- (unsigned)(p - buf), last_modified, date, cache_max_age);
-
- fwrite(buf, 1, p - buf, stdout);
- }
-
- tileset_close(T);
- request_free(R);
-}
-
-int main(int argc, char *argv[]) {
- struct stat st;
- bool initialised = 0;
-
-#ifndef NO_FASTCGI
- while (FCGI_Accept() >= 0)
-#endif
- {
- /* Stupid order since with fcgi_stdio if we haven't called FCGI_Accept
- * we don't get any stderr output.... */
- if (!initialised) {
- if (argc != 2)
- die("single argument is path to tile sets");
- tiles_basedir = argv[1];
- if (-1 == stat(tiles_basedir, &st))
- die("%s: stat: %s", tiles_basedir, strerror(errno));
- else if (!S_ISDIR(st.st_mode))
- die("%s: Not a directory", tiles_basedir);
- initialised = 1;
- }
-
- handle_request();
- }
-
- return 0;
-}
diff --git a/tileserver/tileset.c b/tileserver/tileset.c
deleted file mode 100644
index 866125e30..000000000
--- a/tileserver/tileset.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * tileset.c:
- * Interface to an individual tile set.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- */
-
-static const char rcsid[] = "$Id: tileset.c,v 1.6 2006-09-20 16:44:53 chris Exp $";
-
-/*
- * Tile sets are stored in directory trees which contain indices of tile
- * locations to tile IDs, packed archives of tile images, and indices of where
- * each tile image lives in the corresponding packed file. Tile IDs are SHA1
- * digests of the tile contents, enabling efficient storage in the presence of
- * repeated tiles.
- *
- * Note that this doesn't have attractive properties for locality of reference.
- * That will need fixing if performance under the current scheme is not
- * acceptable.
- */
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "cdb.h"
-#include "tileset.h"
-#include "util.h"
-
-#define TILEID_LEN 20
-
-struct tileset {
- char *t_path, *t_pathbuf;
- cdb t_tileid_idx;
- /* Tile IDs are stored in the tile ID database in N-by-N square blocks,
- * so that the tile ID for (X, Y) is obtained by getting the block for
- * (X / N, Y / N) and looking up (X, Y) within it. The blocking factor is
- * (hopefully!) chosen to be about a disk block in size. It is stored in
- * the tile ID database. Rather than allocating a specific tile ID for a
- * tile which is not present, each information block is preceded by a
- * coverage bitmap. */
- unsigned t_blocking;
- bool t_first;
- unsigned t_x, t_y;
- cdb_datum t_block;
- /* File pointer open on an image file and the name of the file it's open
- * on. */
- char *t_imgfile;
- FILE *t_fpimg;
-};
-
-
-/* tileset_open PATH
- * Open the tileset at PATH, returning a tileset object on success or NULL on
- * failure. */
-tileset tileset_open(const char *path) {
- struct tileset *T, Tz = {0};
- cdb_datum d = NULL;
- char *s;
- int i;
-
- T = xmalloc(sizeof *T);
- *T = Tz;
-
- T->t_first = 1;
- T->t_path = xstrdup(path);
- T->t_pathbuf = xmalloc(strlen(path) + sizeof "/tiles/a/b/c/tiles.cdb");
-
- /* Open the tile ID index. */
- sprintf(T->t_pathbuf, "%s/index.cdb", T->t_path);
- if (!(T->t_tileid_idx = cdb_open(T->t_pathbuf)))
- goto fail;
-
- /* get blocking factor */
- if (!(d = cdb_get_string(T->t_tileid_idx, "blocking")))
- goto fail;
- s = (char*)d->cd_buf;
- if (!(i = atoi(s)) || i < 0)
- goto fail;
- T->t_blocking = (unsigned)i;
-
- cdb_datum_free(d);
-
- return T;
-
-fail:
- tileset_close(T);
- if (d) cdb_datum_free(d);
- return NULL;
-}
-
-/* tileset_close T
- * Free resources associated with T. */
-void tileset_close(tileset T) {
- if (!T) return;
- cdb_close(T->t_tileid_idx);
- xfree(T->t_path);
- xfree(T->t_pathbuf);
- xfree(T);
-}
-
-/* tileset_path T
- * Return the path used to open T. */
-char *tileset_path(tileset T) {
- return T->t_path;
-}
-
-static size_t blockmap_bitmap_len(const unsigned blocking) {
- return (blocking * blocking + 8) / 8;
-}
-
-static size_t blockmap_len(const unsigned blocking) {
- size_t l;
- /* Bitmap of null tiles. */
- l = blockmap_bitmap_len(blocking);
- /* Tile IDs themselves */
- l += blocking * blocking * TILEID_LEN;
- return l;
-}
-
-/* tileset_get_tileid T X Y ID
- * Write into ID the tile ID of the tile at (X, Y) in T, returning true on
- * success or false on failure. */
-bool tileset_get_tileid(tileset T, const unsigned x, const unsigned y,
- uint8_t *id) {
- unsigned x2, y2, off, off0;
- uint8_t *b;
-
- if (T->t_first || T->t_x != x || T->t_y != y) {
- /* Grab block from database. */
- char buf[32];
-
- T->t_first = 0;
- if (T->t_block) cdb_datum_free(T->t_block);
-
- sprintf(buf, "%u,%u", x / T->t_blocking, y / T->t_blocking);
- if (!(T->t_block = cdb_get_string(T->t_tileid_idx, buf)))
- return 0;
- }
-
- if (T->t_block->cd_len != blockmap_len(T->t_blocking))
- return 0;
- /* XXX also report bogus ID block */
-
- b = (uint8_t*)T->t_block->cd_buf;
-
- x2 = x % T->t_blocking;
- y2 = y % T->t_blocking;
- off = (x2 + y2 * T->t_blocking);
-
- /* For a tile not present the corresponding bit in the bitmap is set. */
- if (b[off >> 3] & (1 << (off & 7)))
- return 0;
-
- off0 = blockmap_bitmap_len(T->t_blocking);
- memcpy(id, b + off0 + off * TILEID_LEN, TILEID_LEN);
-
- return 1;
-}
-
-/* tileset_get_tile T ID LEN
- * Retrieve the tile identified by ID, writing its length into *LEN and
- * returning a malloced buffer containing its contents on success, or returning
- * NULL on failure. */
-void *tileset_get_tile(tileset T, const uint8_t *id, size_t *len) {
- cdb idx = NULL;
- cdb_datum d = NULL;
- void *ret = NULL;
- unsigned off;
- FILE *fp = NULL;
-
- sprintf(T->t_pathbuf, "%s/tiles/%x/%x/%x/tiles.cdb",
- T->t_path, (unsigned)(id[0] >> 4),
- (unsigned)(id[0] & 0xf), (unsigned)(id[1] >> 4));
- if (!(idx = cdb_open(T->t_pathbuf)))
- return NULL;
- /* also maybe report bogus index */
-
- if (!(d = cdb_get_buf(idx, id, TILEID_LEN)))
- goto fail;
-
- if (2 != sscanf((char*)d->cd_buf, "%x:%x", &off, len))
- goto fail;
-
- sprintf(T->t_pathbuf, "%s/tiles/%x/%x/%x/tiles",
- T->t_path, (unsigned)(id[0] >> 4),
- (unsigned)(id[0] & 0xf), (unsigned)(id[1] >> 4));
- if (!(fp = fopen(T->t_pathbuf, "rb")))
- goto fail;
- else if (-1 == fseek(fp, off, SEEK_SET))
- goto fail;
-
- ret = xmalloc(*len);
- if (*len != fread(ret, 1, *len, fp)) {
- xfree(ret);
- goto fail;
- }
-
-fail:
- if (idx) cdb_close(idx);
- if (d) cdb_datum_free(d);
- if (fp) fclose(fp);
- return ret;
-}
diff --git a/tileserver/tileset.h b/tileserver/tileset.h
deleted file mode 100644
index 58b22a5e2..000000000
--- a/tileserver/tileset.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * tileset.h:
- * Interface to an individual tile set.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- * $Id: tileset.h,v 1.2 2006-09-20 13:24:58 chris Exp $
- *
- */
-
-#ifndef __TILESET_H_ /* include guard */
-#define __TILESET_H_
-
-#include <sys/types.h>
-
-#include <stdbool.h>
-#include <stdint.h>
-
-#define TILEID_LEN 20
-#define TILEID_LEN_B64 27
-
-typedef struct tileset *tileset;
-
-/* tileset.c */
-tileset tileset_open(const char *path);
-void tileset_close(tileset T);
-bool tileset_get_tileid(tileset T, const unsigned x, const unsigned y,
- uint8_t *id);
-void *tileset_get_tile(tileset T, const uint8_t *id, size_t *len);
-
-#endif /* __TILESET_H_ */
diff --git a/tileserver/util.c b/tileserver/util.c
deleted file mode 100644
index fbc500438..000000000
--- a/tileserver/util.c
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * util.c:
- * Miscellaneous utility functions.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- */
-
-static const char rcsid[] = "$Id: util.c,v 1.1 2006-09-20 15:45:51 chris Exp $";
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "util.h"
-
-/*
- * Wrappers for memory-allocation functions.
- */
-void *xmalloc(const size_t s) {
- void *v;
- if (!(v = malloc(s)))
- die("malloc(%u bytes): %s", (unsigned)s, strerror(errno));
- return v;
-}
-
-void *xcalloc(const size_t a, const size_t b) {
- void *v;
- if (!(v = calloc(a, b)))
- die("calloc(%u * %u bytes): %s",
- (unsigned)a, (unsigned)b, strerror(errno));
- return v;
-}
-
-void *xrealloc(void *b, const size_t s) {
- void *v;
- if (!(v = realloc(b, s)))
- die("realloc(%u bytes): %s", (unsigned)s, strerror(errno));
- return v;
-}
-
-char *xstrdup(const char *s) {
- char *t;
- if (!(t = strdup(s)))
- die("strdup(%u bytes): %s", (unsigned)(strlen(s) + 1), strerror(errno));
- return t;
-}
-
-void xfree(void *v) {
- if (v) free(v);
-}
diff --git a/tileserver/util.h b/tileserver/util.h
deleted file mode 100644
index a2f1f7bc8..000000000
--- a/tileserver/util.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * util.h:
- * Utilities.
- *
- * Copyright (c) 2006 UK Citizens Online Democracy. All rights reserved.
- * Email: chris@mysociety.org; WWW: http://www.mysociety.org/
- *
- * $Id: util.h,v 1.1 2006-09-20 15:45:51 chris Exp $
- *
- */
-
-#ifndef __UTIL_H_ /* include guard */
-#define __UTIL_H_
-
-/* err FORMAT [ARG ...]
- * Write an error message to standard error. */
- /* XXX format this with a timestamp for the error-log? */
-#define err(...) \
- do { \
- fprintf(stderr, "tileserver: "); \
- fprintf(stderr, __VA_ARGS__); \
- fprintf(stderr, "\n"); \
- } while (0)
-
-/* die FORMAT [ARG ...]
- * Write an error message to standard error and exit unsuccessfully. */
-#define die(...) do { err(__VA_ARGS__); exit(1); } while (0)
-
-/* util.c */
-void *xmalloc(const size_t s);
-void *xcalloc(const size_t a, const size_t b);
-void *xrealloc(void *b, const size_t s);
-char *xstrdup(const char *s);
-void xfree(void *v);
-
-#endif /* __UTIL_H_ */