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