Add initial leaptable-compiler commit
This commit is contained in:
parent
a71156ef59
commit
67c96e40bb
5
config
5
config
|
@ -32,3 +32,8 @@
|
|||
source "scripts/paths"
|
||||
|
||||
# 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"
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
app c leaptable-compiler bin
|
|
@ -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
|
||||
*/
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
source src/leaptable-compiler/build.app
|
|
@ -0,0 +1 @@
|
|||
source src/leaptable-compiler/build.install-app
|
|
@ -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
|
|
@ -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
|
4
version
4
version
|
@ -10,8 +10,8 @@
|
|||
# VERSION contains the full version number of the library, which is
|
||||
# expected to be in 'major.minor.micro' format.
|
||||
VERMAJOR=0
|
||||
VERMINOR=0
|
||||
VERMICRO=0
|
||||
VERMINOR=3
|
||||
VERMICRO=4
|
||||
|
||||
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
|
||||
# vim: expandtab:ts=4:sw=4:syntax=sh
|
||||
|
|
Loading…
Reference in New Issue