Initial import

This commit is contained in:
Laurence Withers 2006-10-14 20:10:01 +01:00
commit 0214b3b06a
32 changed files with 1683 additions and 0 deletions

1
src/libiso8601/.params Normal file
View file

@ -0,0 +1 @@
c lib libiso8601 iso8601.h

BIN
src/libiso8601/.types.h.swp Normal file

Binary file not shown.

View file

@ -0,0 +1,13 @@
/* libiso8601/src/libiso8601/BottomHeader.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
#endif
/* 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,18 @@
/* libiso8601/src/libiso8601/TopHeader.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
#ifndef HEADER_libiso8601
#define HEADER_libiso8601
// standard includes, or includes needed for type declarations
#include <time.h>
#include <stdint.h>
/* 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,17 @@
/* libiso8601/src/libiso8601/TopSource.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
#include "iso8601.h"
// Below are all the includes used throughout the library.
#include <errno.h>
#include <stdlib.h>
/* 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 @@
source src/libiso8601/build.lib

View file

@ -0,0 +1 @@
source src/libiso8601/build.install-lib

View file

@ -0,0 +1,36 @@
build_target libiso8601
# make paths (this is for Gentoo in particular)
build_dir_tree "${LIBDIR}" || return 1
build_dir_tree "${PKGCONFDIR}" || return 1
build_dir_tree "${INCLUDEDIR}" || return 1
# install library
echo "Installing libraries into '${LIBDIR}'"
install_file ${libiso8601} ${LIBDIR} 0755 || return 1
BASE="${libiso8601_BASE}.so"
MAJOR="${BASE}.${SOMAJOR}"
MINOR="${MAJOR}.${SOMINOR}"
MICRO="${MINOR}.${SOMICRO}"
install_symlink "${MINOR}" "${MICRO}" "${LIBDIR}"
install_symlink "${MAJOR}" "${MINOR}" "${LIBDIR}"
install_symlink "${BASE}" "${MAJOR}" "${LIBDIR}"
# install header
echo "Installing header file '${libiso8601_HEADER}' into ${INCLUDEDIR}"
install_header ${libiso8601_HEADER} ${INCLUDEDIR} 0644 || return 1
# install pkgconfig file
echo "Installing package config file into ${PKGCONFDIR}"
PKGCONFFILE=${PKGCONFDIR}/libiso8601.pc
do_cmd rm -f ${PKGCONFFILE}
do_cmd_redir ${PKGCONFFILE} sed \
-e "s,@VERSION@,${VERSION}," \
-e "s,@LIBDIR@,${FINALLIBDIR}," \
-e "s,@INCLUDEDIR@,${FINALINCLUDEDIR}," \
src/libiso8601/pkgconf.in
do_cmd chmod 0644 ${PKGCONFFILE}
print_success "Done"
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

51
src/libiso8601/build.lib Normal file
View file

@ -0,0 +1,51 @@
# These are external variables, and shouldn't clash with anything else
# libiso8601
# libiso8601_BUILT
# libiso8601_HEADER
# libiso8601_BASE
if [ -z ${libiso8601_BUILT} ]
then
libiso8601_BASE=libiso8601
source src/libiso8601/soversion
libiso8601="obj/${libiso8601_BASE}.so.${SOMAJOR}.${SOMINOR}.${SOMICRO}"
SO_EXTRA="-lrt -lc"
echo "Building library ${libiso8601}..."
do_cmd source src/libiso8601/build.monolithic || return 1
MODIFIED=0
for test in ${MONOLITHIC_TESTS} ${HDR} ${SRC}
do
if [ ${test} -nt ${libiso8601} ]
then
MODIFIED=1
break
fi
done
if [ ${MODIFIED} -ne 0 ]
then
echo " Compiling"
SONAME="${libiso8601_BASE}.so.${SOMAJOR}.${SOMINOR}"
do_cmd ${CC} ${CFLAGS} -Iobj -shared -fpic -o "${libiso8601}" \
-Wl,-soname,${SONAME} \
${SRC} ${SO_EXTRA} || return 1
# make tests work
do_cmd ln -sf $(basename ${libiso8601}) obj/${SONAME} || return 1
print_success "Library built"
else
print_success "Library up to date"
fi
libiso8601_BUILT=1
libiso8601_HEADER=${HDR}
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

View file

@ -0,0 +1,21 @@
# These are external variables, and shouldn't clash with anything else
# libiso8601_MONOLITHIC
SRC="obj/libiso8601.c"
HDR="obj/iso8601.h"
MONOLITHIC_TESTS="src/libiso8601/build.lib src/libiso8601/build.monolithic"
if [ -z "${libiso8601_MONOLITHIC}" ]
then
MONOLITHIC_SOURCE="$(echo src/libiso8601/{TopHeader,types,functions,BottomHeader}.h)"
make_monolithic ${HDR} Ch || return 1
MONOLITHIC_SOURCE="$(echo src/libiso8601/{TopSource,c_library,calc,parser}.c)"
make_monolithic ${SRC} C || return 1
libiso8601_MONOLITHIC=1
MONOLITHIC_DOC="${MONOLITHIC_DOC} ${HDR}"
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

View file

@ -0,0 +1,74 @@
/* libiso8601/src/libiso8601/c_library.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
void iso8601_now(struct iso8601_date* date, struct iso8601_details* details)
{
struct timespec ts;
// populate the `struct iso8601_date' if it was passed
if(date) {
clock_gettime(CLOCK_REALTIME, &ts);
iso8601_from_ts(date, &ts);
}
// populate the `struct iso8601_details' if it was passed
if(details) {
tzset();
details->date_prec = iso8601_prec_day;
details->time_prec = iso8601_prec_secfrac;
details->tz_sec = timezone;
}
}
void iso8601_from_ts(struct iso8601_date* date, const struct timespec* ts)
{
ldiv_t qr;
qr = ldiv(ts->tv_sec, 86400);
date->day = /* XXX days between 0000-001 and 1970-001 */ + qr.quot;
date->sec = qr.rem;
date->nsec = ts->tv_nsec;
}
void iso8601_to_ts(struct timespec* ts, const struct iso8601_date* date)
{
ts->tv_sec = 86400L * date->day + date->sec;
ts->tv_nsec = date->nsec;
}
void iso8601_from_time_t(struct iso8601_date* date, const time_t* t)
{
ldiv_t qr;
qr = ldiv(*t, 86400);
date->day = /* XXX days between 0000-001 and 1970-001 */ + qr.quot;
date->sec = qr.rem;
date->nsec = 0;
}
void iso8601_to_time_t(time_t* t, const struct iso8601_date* date)
{
*t = 86400L * date->day + date->sec;
if(date->nsec >= 500000000) ++*t;
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

174
src/libiso8601/calc.c Normal file
View file

@ -0,0 +1,174 @@
/* libiso8601/src/libiso8601/calc.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/* CALCULATION ROUTINES
*
* This file contains calculation routines used internally in the library. Our date format is the
* number of days elapsed since 0000-001 (so that date would be 0, -0001-365 would be -1, etc.).
* Time is represented as the number of seconds elapsed since midnight at the start of the day
* (so 0 is 00:00:00 and 86400 is 24:00:00, which we take to be infinitesimally before the start
* of the next day).
*/
int iso8601_isleap(int year)
{
if(year % 4) return 0;
if(year % 100) return 1;
if(!(year % 400)) return 1;
return 0;
}
/* struct monthcount, _days_in_month_common[], _days_in_month_leap[]
*
* Tables of the number of days in each month, and the number of days elapsed since the start of
* the year for each month.
*/
struct monthcount {
int elapsed, days;
};
static const struct monthcount _days_in_month_common[] = {
{ 0, 31 },
{ 31, 28 },
{ 59, 31 },
{ 90, 30 },
{ 120, 31 },
{ 151, 30 },
{ 181, 31 },
{ 212, 31 },
{ 243, 30 },
{ 273, 31 },
{ 304, 30 },
{ 334, 31 }
};
static const struct monthcount _days_in_month_leap[] = {
{ 0, 31 },
{ 31, 29 },
{ 60, 31 },
{ 91, 30 },
{ 121, 31 },
{ 152, 30 },
{ 182, 31 },
{ 213, 31 },
{ 244, 30 },
{ 274, 31 },
{ 305, 30 },
{ 335, 31 }
};
void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date* date)
{
div_t qr;
const struct monthcount* mc;
int ndays = date->day;
// Each 400 years have 97 leap days, giving 365*400+97 = 146097 days in 400 years
qr = div(ndays, 146097);
*year = qr.quot * 400;
ndays = qr.rem;
// ensure that we always end up with between 0 and 146096 days remaining
if(ndays < 0) {
ndays += 146097;
*year -= 400;
}
// we insert `fake' leap days for years 101, 201, 301
if(ndays >= 36890) ++ndays;
if(ndays >= 73415) ++ndays;
if(ndays >= 109940) ++ndays;
// each remaining 100 year block has 24 leap days, giving 365*100+24 = 36524 days
qr = div(ndays, 36525);
*year += qr.quot * 100;
ndays = qr.rem;
// each 4-year block has 1 leap day, giving 365*4 + 1 = 1461 days
qr = div(ndays, 1461);
*year += qr.quot * 4;
ndays = qr.rem;
// the first year of a 4-year block has 1 leap day, 366 days
if(ndays >= 366) {
--ndays; // pretend to have dealt with leap day
// 365 days per remaining year
qr = div(ndays, 365);
*year += qr.quot;
ndays = qr.rem;
}
// now we simply have number of days elapsed since day 001 in `year'.
mc = iso8601_isleap(*year) ? _days_in_month_leap : _days_in_month_common;
*month = 1;
while(ndays >= mc->days) {
++*month;
ndays -= mc->days;
++mc;
}
*day = ndays + 1;
}
int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day)
{
div_t qr;
const struct monthcount* mc;
// check for range / domain errors
if(year < -5879609 || year > 5879609) {
errno = ERANGE;
return -1;
}
mc = iso8601_isleap(year) ? _days_in_month_leap : _days_in_month_common;
if(month < 1 || month > 12 || day < 0 || day > mc[month - 1].days) {
errno = EDOM;
return -1;
}
// Each 400 years have 97 leap days, giving 365*400+97 = 146097 days in 400 years
qr = div(year, 400);
date->day = qr.quot * 146097;
year = qr.rem;
// ensure we have between 0 and 399 years
if(year < 0) {
date->day -= 146097;
year += 400;
}
// excluding leap days, there are 365 days per year
date->day += 365 * year;
date->day += (year + 3) / 4; // there is one leap year for every four years
date->day -= (year - 1) / 100; // but one less for every century over 0
// now get number of days elapsed up to start of month
date->day += mc[month - 1].elapsed;
// and add number of days elapsed sinced start of month
date->day += day - 1;
return 0;
}
/* 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,27 @@
/* libiso8601/src/libiso8601/functions.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/* parse.c */
void iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest,
struct iso8601_details* details);
/* c_library.c */
void iso8601_now(struct iso8601_date* date, struct iso8601_details* details);
void iso8601_from_ts(struct iso8601_date* date, const struct timespec* ts);
void iso8601_to_ts(struct timespec* ts, const struct iso8601_date* date);
void iso8601_from_time_t(struct iso8601_date* date, const time_t* t);
void iso8601_to_time_t(time_t* t, const struct iso8601_date* date);
/* calc.c */
int iso8601_isleap(int year);
void iso8601_to_cal(int* year, int* month, int* day, const struct iso8601_date* date);
int iso8601_from_cal(struct iso8601_date* date, int year, int month, int day);
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

21
src/libiso8601/parser.c Normal file
View file

@ -0,0 +1,21 @@
/* libiso8601/src/libiso8601/parser.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
void iso8601_parse(const char* str, struct iso8601_date* earliest, struct iso8601_date* latest,
struct iso8601_details* details)
{
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

21
src/libiso8601/pkgconf.in Normal file
View file

@ -0,0 +1,21 @@
# libiso8601/src/lib/clib/pkgconf.in
#
# Metadata file for pkg-config
# ( http://www.freedesktop.org/software/pkgconfig/ )
#
# (c)2006, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv2. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
#
# Name, description
Name: @TODO@
Description: @TODO@
Version: @VERSION@
# Requirements
Requires:
# Compilation information
Libs: -L@LIBDIR@ -liso8601
Cflags: -I@INCLUDEDIR@

17
src/libiso8601/soversion Normal file
View file

@ -0,0 +1,17 @@
# libiso8601/src/libiso8601/soversion
#
# (c)2006, Laurence Withers, <l@lwithers.me.uk>.
# Released under the GNU GPLv2. See file COPYING or
# http://www.gnu.org/copyleft/gpl.html for details.
#
# SOMAJOR and SOMINOR are included in the library's soname. They need to
# be bumped on a binary-incompatible release. They are both single
# integers.
SOMAJOR=0
SOMINOR=0
# SOMICRO is bumped every time there is a binary-compatible release.
SOMICRO=0

45
src/libiso8601/types.h Normal file
View file

@ -0,0 +1,45 @@
/* libiso8601/src/libiso8601/types.h
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
struct iso8601_date {
uint32_t nsec;
int32_t day;
uint32_t sec;
};
enum iso8601_date_prec {
iso8601_prec_year,
iso8601_prec_month,
iso8601_prec_day,
iso8601_prec_ord,
iso8601_prec_week,
iso8601_prec_wday
}date_prec;
enum iso8601_time_prec {
iso8601_prec_none,
iso8601_prec_hour,
iso8601_prec_min,
iso8601_prec_sec,
iso8601_prec_hourfrac,
iso8601_prec_minfrac,
iso8601_prec_secfrac
}time_prec;
struct iso8601_details {
uint8_t date_prec, time_prec;
int32_t tz_sec;
};
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

1
src/tests/.params Normal file
View file

@ -0,0 +1 @@
c tests tests libiso8601

3
src/tests/build.default Normal file
View file

@ -0,0 +1,3 @@
source src/tests/build.tests
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

43
src/tests/build.tests Normal file
View file

@ -0,0 +1,43 @@
# These are external variables, and shouldn't clash with anything else
# tests_BUILT
#
build_target libiso8601 || return 1
if [ -z ${tests_BUILT} ]
then
LIBS="${libiso8601} "
EXTRAS="" # @TODO@ libs, cflags
echo "Building test programs..."
do_cmd mkdir -p obj/tests || return 1
for SRC in src/tests/*.c
do
TEST="obj/tests/$(basename ${SRC} | sed -e 's,.c$,,')"
MODIFIED=0
for file in ${LIBS} ${SRC} src/tests/build.tests
do
if [ ${file} -nt ${TEST} ]
then
MODIFIED=1
break
fi
done
if [ ${MODIFIED} -ne 0 ]
then
do_cmd ${CC} -Iobj ${CFLAGS} -o ${TEST} ${SRC} ${LIBS} ${EXTRAS} || return 1
print_success "Built ${TEST}"
else
print_success "${TEST} is up to date"
fi
done
print_success "All tests built"
tests_BUILT=1
fi
# kate: replace-trailing-space-save true; space-indent true; tab-width 4;
# vim: expandtab:ts=4:sw=4

151
src/tests/calconv.c Normal file
View file

@ -0,0 +1,151 @@
/* libiso8601/src/tests/calconv.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
#include "iso8601.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
const int _days_in_month_common[] = {
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
};
const int _days_in_month_leap[] = {
31,
29,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
};
int try_year(int year)
{
static int daycount = 0;
const int* mc;
int m, d, y2, m2, d2, ret = 0;
struct iso8601_date dt;
mc = iso8601_isleap(year) ? _days_in_month_leap : _days_in_month_common;
for(m = 0; m < 12; ++m) {
for(d = 0; d < mc[m]; ++d) {
if(iso8601_from_cal(&dt, year, m + 1, d + 1)) {
++ret;
printf("[cal2date ] %04d-%02d-%02d: %s (%d)\n",
year, m + 1, d + 1, strerror(errno), errno);
} else if(dt.day != daycount) {
++ret;
printf("[discontinuity] %04d-%02d-%02d: got day=%d, expected day=%d\n",
year, m + 1, d + 1, dt.day, daycount);
} else if(iso8601_to_cal(&y2, &m2, &d2, &dt), year != y2 || m + 1 != m2 || d + 1 != d2) {
++ret;
printf("[date2cal ] %04d-%02d-%02d ==> %04d-%02d-%02d (%d)\n",
year, m + 1, d + 1, y2, m2, d2, daycount);
}
++daycount;
}
}
return ret;
}
int try_neg_year(int year)
{
static int daycount = 365;
const int* mc;
int m, d, y2, m2, d2, ret = 0;
struct iso8601_date dt;
mc = iso8601_isleap(year) ? _days_in_month_leap : _days_in_month_common;
for(m = 11; m >= 0; --m) {
for(d = mc[m]; d; --d) {
if(iso8601_from_cal(&dt, year, m + 1, d)) {
++ret;
printf("[cal2date ] %04d-%02d-%02d: %s (%d)\n",
year, m + 1, d, strerror(errno), errno);
} else if(dt.day != daycount) {
++ret;
printf("[discontinuity] %04d-%02d-%02d: got day=%d, expected day=%d\n",
year, m + 1, d, dt.day, daycount);
} else if(iso8601_to_cal(&y2, &m2, &d2, &dt), year != y2 || m + 1 != m2 || d != d2) {
++ret;
printf("[date2cal ] %04d-%02d-%02d ==> %04d-%02d-%02d (%d)\n",
year, m + 1, d, y2, m2, d2, daycount);
}
--daycount;
}
}
return ret;
}
// stuff repeats on a 400-year cycle, so we really shouldn't need to worry too much about this
#define MAX_YEAR_COUNT 2400
int main(int argc, char* argv[])
{
int ret = 0, year;
if(argc == 2 && !strcmp(argv[1], "--print-summary")) {
printf("Calendar date / day number conversion test.\n");
return 0;
}
for(year = 0; year <= MAX_YEAR_COUNT; ++year) {
ret += try_year(year);
if(ret > 20) return ret;
}
for(year = 0; year >= -MAX_YEAR_COUNT; --year) {
ret += try_neg_year(year);
if(ret > 20) return ret;
}
return ret;
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/

36
src/tests/template Normal file
View file

@ -0,0 +1,36 @@
/* libiso8601/src/tests/???.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
#include "iso8601.h"
#include <stdio.h>
#include <string.h>
int main(int argc, char* argv[])
{
int ret = 0;
if(argc == 2 && !strcmp(argv[1], "--print-summary")) {
printf("One line summary.\n");
return 0;
}
if(argc == 1) {
// empty argument list
}
// TODO
return ret;
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/