Add initial leaptable-compiler commit

This commit is contained in:
Laurence Withers 2009-01-03 23:05:17 +00:00
parent a71156ef59
commit 67c96e40bb
9 changed files with 430 additions and 2 deletions

5
config
View File

@ -32,3 +32,8 @@
source "scripts/paths" source "scripts/paths"
# Project-specific variables below. # Project-specific variables below.
[ -z "${LIBISO8601_CFLAGS}" ] && LIBISO8601_CFLAGS="$(libiso8601-config --cflags)"
[ -z "${LIBISO8601_LIBS}" ] && LIBISO8601_LIBS="$(libiso8601-config --libs)"
[ -z "${CC}" ] && CC="gcc"
[ -z "${CFLAGS}" ] && CFLAGS="-g -O2 -W -Wall"

View File

@ -0,0 +1 @@
app c leaptable-compiler bin

View File

@ -0,0 +1,349 @@
/* leaptable-compiler/src/leaptable-compiler/000_TopSource.c
*
* (c)2009, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv3. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/* Below are all the includes used throughout the application. */
#include <fcntl.h>
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "iso8601.h"
const char* signature_string = "/O9PdPZI";
struct iso8601_details print_details = {
.date_prec = iso8601_prec_day,
.time_prec = iso8601_prec_none,
.extended = 1,
};
const char* text_fname = 0, * table_fname = 0;
FILE* do_open(const char* fname, const char* mode)
{
FILE* fp;
if(!fname) {
if(mode[0] == 'r') return stdin;
fflush(stdout);
return stdout;
}
fp = fopen(fname, mode);
if(!fp) {
fprintf(stderr, "Unable to open \"%s\": %m.\n", fname);
exit(1);
}
return fp;
}
struct day_list {
int* days;
int num, size;
};
struct day_list* day_list_new(void)
{
struct day_list* l;
l = malloc(sizeof(struct day_list));
l->days = malloc(sizeof(int) * 8);
l->num = 0;
l->size = 8;
return l;
}
void day_list_add(struct day_list* l, int day)
{
if(l->num == l->size) {
l->size <<= 1;
l->days = realloc(l->days, l->size * sizeof(int));
}
l->days[l->num++] = day;
}
int _day_list_sort_cmp(const void* v1, const void* v2)
{
const int* i1, * i2;
i1 = v1;
i2 = v2;
if(*i1 < *i2) return -1;
if(*i1 > *i2) return 1;
return 0;
}
void day_list_sort(struct day_list* dl)
{
qsort(dl->days, dl->num, sizeof(int), _day_list_sort_cmp);
}
void write_i32(char* buf, uint32_t val)
{
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
buf[3] = val;
}
uint32_t read_i32(const char* buf)
{
const uint8_t* b;
b = (const uint8_t*)buf;
return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
}
int do_compile(void)
{
FILE* fin, * fout;
char* line = 0;
size_t line_sz = 0;
int lineno = 0, year, month, day;
struct iso8601_date d;
struct day_list* dl;
char buf[4];
fin = do_open(text_fname, "r");
dl = day_list_new();
while(getline(&line, &line_sz, fin) != -1) {
++lineno;
if(iso8601_parse(line, &d, 0, 0)) {
fprintf(stderr, "%s:%d: unable to parse ISO8601 date.\n",
text_fname ?: "stdin", lineno);
return 1;
}
day_list_add(dl, d.day);
iso8601_to_cal(&year, &month, &day, &d);
if(!(month == 6 && day == 30) && !(month == 12 && day == 31)) {
fprintf(stderr, "%s:%d: warning: date (%04d-%02d-%02d) does not "
"correspond to a usual leap second day.\n",
text_fname ?: "stdin", lineno, year, month, day);
}
}
day_list_sort(dl);
fout = do_open(table_fname, "w");
fwrite(signature_string, 1, 8, fout);
write_i32(buf, dl->num);
fwrite(buf, 1, 4, fout);
for(lineno = 0; lineno < dl->num; ++lineno) {
write_i32(buf, dl->days[lineno]);
fwrite(buf, 1, 4, fout);
}
return 0;
}
int do_dump(void)
{
FILE* fin, * fout;
char buf[32];
int num, i;
struct iso8601_date d = {
.sec = 0,
.nsec = 0,
};
fin = do_open(table_fname, "r");
if(fread(buf, 1, 8, fin) != 8) goto read_err;
if(memcmp(buf, signature_string, 8)) {
fprintf(stderr, "%s: invalid signature.\n",
table_fname ?: "stdin");
return 1;
}
if(fread(buf, 1, 4, fin) != 4) goto read_err;
num = read_i32(buf);
fout = do_open(text_fname, "w");
for(i = 0; i < num; ++i) {
if(fread(buf, 1, 4, fin) != 4) goto read_err;
d.day = read_i32(buf);
fputs(iso8601_print(buf, sizeof(buf), &d, &print_details), fout);
putc('\n', fout);
}
return 0;
read_err:
fprintf(stderr, "%s: error reading from file (truncated or %m).\n",
table_fname ?: "stdin");
return 1;
}
int do_verify(void)
{
FILE* fin;
char buf[8];
int i, num, day;
struct day_list* dl;
char s1[32], s2[32];
struct iso8601_date d1, d2;
if(!table_fname) {
fputs("Verify mode cannot work with stdin.\n", stderr);
return 1;
}
if(iso8601_leap_table_load(table_fname)) {
fprintf(stderr, "%s: unable to load table (%m).\n", table_fname);
return 1;
}
fputs("Table loaded by library.\n", stdout);
fin = do_open(table_fname, "r");
dl = day_list_new();
if(fread(buf, 1, 8, fin) != 8) goto read_err;
if(memcmp(buf, signature_string, 8)) {
fprintf(stderr, "%s: invalid signature.\n", table_fname);
return 1;
}
if(fread(buf, 1, 4, fin) != 4) goto read_err;
num = read_i32(buf);
for(i = 0; i < num; ++i) {
if(fread(buf, 1, 4, fin) != 4) goto read_err;
day = read_i32(buf);
day_list_add(dl, day);
}
printf("Loaded %d entries from disk.\n", num);
d1.sec = 0;
d1.nsec = 0;
d1.day = dl->days[0] - 1;
iso8601_print(s1, sizeof(s1), &d1, &print_details);
d2.sec = 0;
d2.nsec = 0;
d2.day = dl->days[dl->num - 1] + 1;
iso8601_print(s2, sizeof(s2), &d2, &print_details);
num = iso8601_leap_elapsed(&d1, &d2);
printf("Number of leap seconds elapsed between %s and %s: %d (%sexpected).\n",
s1, s2, num, (num == dl->num) ? "" : "un");
if(num != dl->num) return 1;
fputs("Scanning days.\n", stdout);
for(num = 0; d1.day < d2.day; ++d1.day) {
if(iso8601_seconds_leap(&d1) == 86400) continue;
iso8601_print(s1, sizeof(s1), &d1, &print_details);
fputs("Found leap second at ", stdout);
fputs(s1, stdout);
if(num == dl->num) {
fputs("(unexpected -- past end of table)\n", stdout);
return 1;
}
if(dl->days[num] != d1.day) {
fputs("(unexpected -- table's next leap at ", stdout);
d1.day = dl->days[num];
iso8601_print(s1, sizeof(s1), &d1, &print_details);
fputs(s1, stdout);
fputs(")\n", stdout);
return 1;
}
fputs("(expected).\n", stdout);
++num;
}
return 0;
read_err:
fprintf(stderr, "%s: error reading from file (truncated or %m).\n",
table_fname ?: "stdin");
return 1;
}
void usage(void)
{
fputs("Usage:\n\n"
" leaptable-compiler MODE [options]\n\n"
"Modes:\n"
" compile Compile text file to table file.\n"
" dump Dump table file as text.\n"
" verify Verify correct operation of table file.\n"
"\n"
"Options:\n"
" -h, --help Display this screen.\n"
" -V, --version Display version number.\n"
" -x, --text Name of text file.\n"
" -t, --table Name of table file.\n"
"", stdout);
}
struct option options[] = {
{ "help", no_argument, 0, 'h' },
{ "version", no_argument, 0, 'V' },
{ "text", required_argument, 0, 'x' },
{ "table", required_argument, 0, 't' },
{ 0, 0, 0, 0 }
};
const char* optstr = "ht:x:V";
int main(int argc, char* argv[])
{
while(1) {
switch(getopt_long(argc, argv, optstr, options, 0)) {
case -1: goto opts_done;
case '?': return 1;
case 'h': usage(); return 0;
case 'V': fputs("leaptable-compiler " VERSION "\n", stdout); return 0;
case 'x': text_fname = optarg; break;
case 't': table_fname = optarg; break;
}
}
opts_done:
if(optind != (argc - 1)) {
usage();
return 1;
}
if(!strcmp(argv[optind], "compile")) return do_compile();
if(!strcmp(argv[optind], "dump")) return do_dump();
if(!strcmp(argv[optind], "verify")) return do_verify();
fputs("Unknown mode.\n", stderr);
return 1;
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

View File

@ -0,0 +1,41 @@
# These are external variables, and shouldn't clash with anything else
# leaptable_compiler
# leaptable_compiler_BUILT
#
if [ -z ${leaptable_compiler_BUILT} ]
then
leaptable_compiler="obj/leaptable-compiler"
EXTRAS="-std=gnu99 -D_GNU_SOURCE ${LIBISO8601_CFLAGS} ${LIBISO8601_LIBS}"
echo "Building application ${leaptable_compiler}..."
do_cmd source src/leaptable-compiler/build.monolithic || return 1
MODIFIED=0
for test in ${MONOLITHIC_TESTS} ${SRC}
do
if [ ${test} -nt ${leaptable_compiler} ]
then
MODIFIED=1
break
fi
done
if [ ${MODIFIED} -ne 0 ]
then
echo " Compiling..."
do_cmd ${CC} ${CFLAGS} -I obj -o "${leaptable_compiler}" ${SRC} ${EXTRAS} || return 1
print_success "Application built"
else
print_success "Application up to date"
fi
leaptable_compiler_BUILT=1
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -0,0 +1 @@
source src/leaptable-compiler/build.app

View File

@ -0,0 +1 @@
source src/leaptable-compiler/build.install-app

View File

@ -0,0 +1,12 @@
build_target leaptable-compiler
# make paths (this is for Gentoo in particular)
build_dir_tree "${BINDIR}" || return 1
# install binary
echo "Installing binaries into '${BINDIR}'"
install_file "${leaptable_compiler}" "${BINDIR}" 0755 || return 1
print_success "Done"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -0,0 +1,18 @@
# These are external variables, and shouldn't clash with anything else
# leaptable_compiler_MONOLITHIC
#
SRC="obj/leaptable-compiler.c"
MONOLITHIC_TESTS="src/leaptable-compiler/build.app src/leaptable-compiler/build.monolithic"
if [ -z "${leaptable_compiler_MONOLITHIC}" ]
then
MONOLITHIC_SOURCE="$(find src/leaptable-compiler/ -name '*.c' | sort)"
make_monolithic ${SRC} C || return 1
leaptable_compiler_MONOLITHIC=1
MONOLITHIC_DOC="${MONOLITHIC_DOC} ${SRC}"
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: syntax=sh:expandtab:ts=4:sw=4

View File

@ -10,8 +10,8 @@
# VERSION contains the full version number of the library, which is # VERSION contains the full version number of the library, which is
# expected to be in 'major.minor.micro' format. # expected to be in 'major.minor.micro' format.
VERMAJOR=0 VERMAJOR=0
VERMINOR=0 VERMINOR=3
VERMICRO=0 VERMICRO=4
# kate: replace-trailing-space-save true; space-indent true; tab-width 4; # kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4:syntax=sh # vim: expandtab:ts=4:sw=4:syntax=sh