Mercurial > ~dholland > hg > ag > index.cgi
diff checksum/checksum.c @ 0:13d2b8934445
Import AnaGram (near-)release tree into Mercurial.
author | David A. Holland |
---|---|
date | Sat, 22 Dec 2007 17:52:45 -0500 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/checksum/checksum.c Sat Dec 22 17:52:45 2007 -0500 @@ -0,0 +1,260 @@ +/* + * AnaGram, A System for Syntax Directed Programming + * Copyright 2006 David A. Holland. All Rights Reserved. + * See the file COPYING for license and usage terms. + */ + +/* + * checksum - compute checksums of key files. + * usage: checksum outputprefix symbolic-name filename + * + * Outputs to two files, one with the checksum info and one + * the control file for insertsums. + * + * In each binary searches for a sums patch area, which is a + * region of size TARGETSIZE beginning with the string TARGETLABEL. + * This region is excluded from the sum and reported to insertsums. + * + * XXX the definitions of TARGETSIZE and TARGETLABEL should be shared + * with the ag code. + * + * This module is new code as of June 2006 and should be much more + * portable than the old stuff. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <unistd.h> +#include <fcntl.h> +#include <getopt.h> +#include <errno.h> + +#include "bits.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#define O_TEXT 0 +#endif + +#define TARGETSIZE 512 +#define TARGETLABEL "Checksum data:\n" + +static FILE *datfile, *ctlfile; + +#if 0 +/* The file extensions depend on the platform we're building for. */ +typedef enum { + EXEEXT, + SHLIBEXT, + HLPEXT, +} whichext; + +/* Information about files we checksum. */ +struct fileinfo { + const char *basename; + whichext ext; + int istarget; + const char *tag; +}; + +/* These are the files. */ +static const struct fileinfo files[] = { + { "ag", EXEEXT, 0, "ag" }, + { "agcl", EXEEXT, 0, "agcl" }, + { "ag1", SHLIBEXT, 1, "ag1" }, + { "AnaGram", HLPEXT, 0, "hlp" }, +}; +static const unsigned numfiles = sizeof(files) / sizeof(files[0]); +#endif + +/* The name of this program, from argv[0]. */ +static const char *me; + +//////////////////////////////////////////////////////////// + +static off_t filelength(int fd) { + struct stat statbuf; + fstat(fd, &statbuf); + return statbuf.st_size; +} + +static void setme(const char *av0) { + me = strrchr(av0, '/'); + if (me) { + me++; + } + else { + me = av0; + } +} + +static void die(const char *fmt, ...) { + va_list ap; + fprintf(stderr, "%s: ", me); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + fputc('\n', stderr); + exit(EXIT_FAILURE); +} + +//////////////////////////////////////////////////////////// + +static void openoutput(const char *prefix) { + char buf[128]; + + snprintf(buf, sizeof(buf), "%s.dat", prefix); + datfile = fopen(buf, "at"); + if (!datfile) { + die("%s: fopen failed", buf); + } + + snprintf(buf, sizeof(buf), "%s.ctl", prefix); + ctlfile = fopen(buf, "at"); + if (!ctlfile) { + die("%s: fopen failed", buf); + } +} + +static void closeoutput(void) { + fclose(datfile); + fclose(ctlfile); +} + +//////////////////////////////////////////////////////////// + +/* + * Note: allocates a zero byte after the end of the file + * (the checksum code demands this) + */ +static char *loadfile(const char *path, size_t *len_ret) { + int fd; + char *buf; + off_t length; + ssize_t nread; + + fd = open(path, O_BINARY|O_RDONLY); + if (fd < 0) { + die("%s: %s", path, strerror(errno)); + } + + length = filelength(fd); + if (length > 1000000000L) { + // paranoia is good + die("Unreasonably large file"); + } + + buf = malloc(length+1); + if (!buf) { + die("malloc failed"); + } + + nread = read(fd, buf, length); + if (nread < 0) { + die("%s: read: %s", path, strerror(errno)); + } + if (nread != length) { + die("%s: read: short count", path); + } + + close(fd); + + buf[length] = 0; + + *len_ret = length; + return buf; +} + +static void unloadfile(char *buf) { + free(buf); +} + +//////////////////////////////////////////////////////////// + +static int search(const char *data, size_t len, size_t *pos_ret) { + static const char tag[] = TARGETLABEL; + static unsigned expected = 0; + static size_t start = 0; + + size_t pos = 0; + + for (pos=0; pos<len; pos++) { + int ch = data[pos]; + + if (ch == tag[expected]) { + if (expected==0) { + start = pos; + } + expected++; + if (tag[expected]==0) { + /* found */ + *pos_ret = start; + return 1; + } + } + else { + expected = 0; + } + } + + return 0; +} + +//////////////////////////////////////////////////////////// + +static void sumfile(const char *sym, const char *path) { + char *data; + uint32_t sum; + size_t length, patchpos; + int haspatcharea; + + data = loadfile(path, &length); + haspatcharea = search(data, length, &patchpos); + sum = dosum(data, length, haspatcharea ? patchpos : 0, TARGETSIZE); + unloadfile(data); + + if (haspatcharea && patchpos==0) { + die("%s: patch area is at file offset 0", path); + } + + fprintf(datfile, "%s=%lu,%lu", + sym, (unsigned long) length, (unsigned long) sum); + if (haspatcharea) { + fprintf(datfile, "@%lu", (unsigned long) patchpos); + fprintf(ctlfile, "%s %lu\n", path, (unsigned long) patchpos); + } + else { + fprintf(ctlfile, "# %s no-patch-area\n", path); + } + fprintf(datfile, "\n"); +} + +//////////////////////////////////////////////////////////// + +static void usage(void) { + die("Usage: %s outputprefix symbolic-name pathname", me); +} + +int main(int argc, char *argv[]) { + const char *out, *sym, *path; + + setme(argv[0]); + if (argc != 4) { + usage(); + } + + out = argv[1]; + sym = argv[2]; + path = argv[3]; + + openoutput(out); + sumfile(sym, path); + closeoutput(); + + return EXIT_SUCCESS; +}