Compare commits

...

7 Commits

Author SHA1 Message Date
Laurence Withers 5586bf98f9 Bump version 2006-12-01 19:26:08 +00:00
Laurence Withers 2b14f82040 Always log to syslog, regardless of mode 2006-12-01 19:25:46 +00:00
Laurence Withers d0ec200a27 Unlink any existing socket before binding 2006-12-01 19:22:42 +00:00
Laurence Withers 6195451899 Use libiso8601 to parse the time. 2006-11-21 00:11:57 +00:00
root 7d6be54038 Also enable use of the -D option. 2006-10-13 15:07:47 +01:00
Laurence Withers aa8b911200 Bump version 2006-10-12 23:24:15 +01:00
Laurence Withers 98461b586b Fix bug where the 8-char time wasn't being parsed correctly 2006-10-10 17:05:55 +01:00
7 changed files with 17 additions and 421 deletions

4
README
View File

@ -1,4 +1,4 @@
mini-at mini-at http://www.lwithers.me.uk/projects/mini-at/
======================================================================== ========================================================================
(c)2006, Laurence Withers, <l@lwithers.me.uk>. (c)2006, Laurence Withers, <l@lwithers.me.uk>.
Released under the GNU GPLv2. See file COPYING or Released under the GNU GPLv2. See file COPYING or
@ -7,6 +7,8 @@ http://www.gnu.org/copyleft/gpl.html for details.
Really Quick Instructions Really Quick Instructions
------------------------- -------------------------
Install libiso8601 from http://www.lwithers.me.uk/projects/libiso8601/ .
To build: ./make.sh To build: ./make.sh
To install: ./make.sh install To install: ./make.sh install
(you might want to set PREFIX, by default it's /usr/local) (you might want to set PREFIX, by default it's /usr/local)

View File

@ -16,6 +16,7 @@
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <sys/un.h> #include <sys/un.h>
#include <iso8601.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>

View File

@ -6,7 +6,8 @@
if [ -z ${mini_at_BUILT} ] if [ -z ${mini_at_BUILT} ]
then then
mini_at="obj/mini-at" mini_at="obj/mini-at"
EXTRAS="" # @TODO@ cflags, libs [ -z "${LIBISO8601_FLAGS}" ] && LIBISO8601_FLAGS="$(pkg-config libiso8601 --libs --cflags)"
EXTRAS="${LIBISO8601_FLAGS}"
echo "Building application ${mini_at}..." echo "Building application ${mini_at}..."

View File

@ -7,426 +7,18 @@
int parse_time_digs(const char* str, int numdigs)
{
int i = 0;
char ch;
while(numdigs--) {
switch( (ch = *str++) ) {
case '0' ... '9':
i *= 10;
i += ch - '0';
break;
default:
return -1;
}
}
return i;
}
int parse_time_date_daysinyear(int year)
{
if(!(year % 400)) return 366;
if(!(year % 100)) return 365;
if(!(year % 4)) return 366;
return 365;
}
struct parse_time_date_dayselapsed_t {
int ndays, elapsed;
};
struct parse_time_date_dayselapsed_t parse_time_date_dayselapsed_cal[] = {
{ 31, 0 },
{ 28, 31 },
{ 31, 59 },
{ 30, 90 },
{ 31, 120 },
{ 30, 151 },
{ 31, 181 },
{ 31, 212 },
{ 30, 243 },
{ 31, 273 },
{ 30, 304 },
{ 31, 334 }
};
struct parse_time_date_dayselapsed_t parse_time_date_dayselapsed_leapcal[] = {
{ 31, 0 },
{ 29, 31 },
{ 31, 60 },
{ 30, 91 },
{ 31, 121 },
{ 30, 152 },
{ 31, 182 },
{ 31, 213 },
{ 30, 244 },
{ 31, 274 },
{ 30, 305 },
{ 31, 335 }
};
int parse_time_date_dayselapsed(int year, int mon, int day)
{
struct parse_time_date_dayselapsed_t* t;
--mon;
if(mon < 0 || mon > 11) return -1;
if(parse_time_date_daysinyear(year) == 366) t = parse_time_date_dayselapsed_leapcal;
else t = parse_time_date_dayselapsed_cal;
t += mon;
--day;
if(day < 0 || day > t->ndays) return -1;
return day + t->elapsed;
}
// number of seconds elapsed between 1970 and start of `year'
time_t parse_time_date_mkyear(int year)
{
long nd;
// we have an inverse y2k problem!
// basically, the algorithm needs to operate on a 400-year boundary for leap days
// since this is `at', we don't deal with dates in the past
// time_t can't deal with dates earlier than 1970
// so 2000 seems a logical place to start
year -= 2000;
if(year < 0) return -1;
/* Every 4th year is leap
* unless it's a century (not leap)
* unless it's a 4*century (leap)
*
* So there are 97 leap days in 400 years, giving 365 * 400 + 397 = 146097 days
* For each 100 years, there are 24 leaps, giving 365 * 100 + 24 = 36524 days
* For each 4 years, there is 1 leap, giving 365 * 4 + 1 = 1461 days
*/
nd = 146097l * (year / 400);
year %= 400;
if(year) {
nd += 36524 * (year / 100);
year %= 100;
nd += 1461 * (year / 4);
if(year) {
year %= 4;
nd += (year ? 1 : 0) + 365 * year;
} else {
nd++;
}
}
/* Now add number of days between 1970 and 2000 (7 leap years)
* 30 * 365 + 7 = 10957 */
nd += 10957;
// ignoring leap seconds, as time_t does, there are 86400 seconds in a day
nd *= 86400;
// done!
return (time_t)nd;
}
time_t parse_time_date_mkwk(int year, int wk, int wday)
{
// time_t t;
fprintf(stderr, "ISO8601 week dates not supported yet\n");
return -1;
/*
t = parse_time_date_mkyear(year);
if(t == (time_t)-1) return -1;
*/
}
time_t parse_time_date_mkord(int year, int oday)
{
time_t t;
if(oday < 1 || oday > parse_time_date_daysinyear(year)) return -1;
t = parse_time_date_mkyear(year);
if(t == (time_t)-1) return -1;
t += (oday - 1) * 86400;
return t;
}
time_t parse_time_date_mkcal(int year, int mon, int day)
{
time_t t;
t = parse_time_date_mkyear(year);
if(t == (time_t)-1) return -1;
t += parse_time_date_dayselapsed(year, mon, day) * 86400;
return t;
}
time_t parse_time_date(const char* str, const char* end)
{
int year, mon, day;
const char* pos;
// we don't deal with negative years -- this is at!
if(*str < '0' || *str > '9') return -1;
if( (pos = strchr(str, 'W')) ) {
if(strchr(pos, '-')) {
/* Either of:
* yyyy-Www
* yyyy-Www-d
*/
switch(end - pos) {
case 3:
year = parse_time_digs(str, pos - str - 1);
mon = parse_time_digs(pos + 1, 2);
return parse_time_date_mkwk(year, mon, 1);
case 5:
year = parse_time_digs(str, pos - str - 1);
mon = parse_time_digs(pos + 1, 2);
day = parse_time_digs(pos + 4, 1);
return parse_time_date_mkwk(year, mon, day);
default:
return -1;
}
} else {
/* Either of:
* yyyyWww
* yyyyWwwd
*/
switch(end - pos) {
case 3:
year = parse_time_digs(str, pos - str);
mon = parse_time_digs(pos + 1, 2);
return parse_time_date_mkwk(year, mon, 1);
case 4:
year = parse_time_digs(str, pos - str);
mon = parse_time_digs(pos + 1, 2);
day = parse_time_digs(pos + 3, 2);
return parse_time_date_mkwk(year, mon, day);
default:
return -1;
}
}
} else if( (pos = strchr(str, '-')) ) {
/* Valid extended formats are:
* yyyy-mm (year + len 3)
* yyyy-ooo (year + len 4)
* yyyy-mm-dd (year + len 6)
*/
switch(end - pos) {
case 3:
year = parse_time_digs(str, pos - str);
mon = parse_time_digs(pos + 1, 2);
return parse_time_date_mkcal(year, mon, 1);
case 4:
year = parse_time_digs(str, pos - str);
day = parse_time_digs(pos + 1, 3);
return parse_time_date_mkord(year, day);
case 6:
year = parse_time_digs(str, pos - str);
mon = parse_time_digs(pos + 1, 2);
day = parse_time_digs(pos + 4, 2);
return parse_time_date_mkcal(year, mon, day);
default:
return -1;
}
}
/* Valid basic formats, excluding week formats, are:
* yyyy (len 4)
* yyyymm (len 6)
* yyyyooo (len 7)
* yyyymmdd (len 8)
*/
switch(end - str) {
case 4:
year = parse_time_digs(str, 4);
return parse_time_date_mkord(year, 1);
case 6:
year = parse_time_digs(str, 4);
mon = parse_time_digs(str + 4, 2);
return parse_time_date_mkcal(year, mon, 1);
case 7:
year = parse_time_digs(str, 4);
day = parse_time_digs(str + 4, 3);
return parse_time_date_mkord(year, day);
case 8:
year = parse_time_digs(str, 4);
mon = parse_time_digs(str + 4, 2);
day = parse_time_digs(str + 6, 2);
return parse_time_date_mkcal(year, mon, day);
default:
return -1;
}
}
int parse_time_time(const char* str, const char* end)
{
const char* pos;
double d = 0;
char* endp;
int h = 0, m = 0, s = 0, ret;
pos = strchr(str, '.');
if(pos) {
errno = 0;
endp = 0;
d = strtod(pos, &endp);
if(errno || !endp) return -1;
switch(*endp) {
case 'Z':
case '+':
case '-':
case 0:
break;
default:
return -1;
}
} else {
pos = end;
}
/* Valid formats, excluding fraction, are:
*
* hh (len 2)
* hhmm (len 4)
* hh:mm (len 5)
* hhmmss (len 6)
* hh:mm:ss (len 8)
*/
switch(pos - str) {
case 2:
h = parse_time_digs(str, 2);
ret = ((h + d) * 3600 + 0.5);
break;
case 4:
h = parse_time_digs(str, 2);
m = parse_time_digs(str + 2, 2);
ret = h * 3600 + ((m + d) * 60 + 0.5);
break;
case 5:
h = parse_time_digs(str, 2);
m = parse_time_digs(str + 3, 2);
ret = h * 3600 + ((m + d) * 60 + 0.5);
break;
case 6:
h = parse_time_digs(str, 2);
m = parse_time_digs(str + 2, 2);
s = parse_time_digs(str + 4, 2);
ret = h * 3600 + m * 60 + s + d + 0.5;
break;
case 8:
h = parse_time_digs(str, 2);
m = parse_time_digs(str + 3, 2);
s = parse_time_digs(str + 5, 2);
ret = h * 3600 + m * 60 + s + d + 0.5;
break;
default:
return -1;
}
// special cases
if(h == 24 && m == 0 && s == 0) return ret; // midnight at end of day
if(h == 23 && m == 59 && s == 60) return ret; // leap second
if(h < 0 || h > 23) return -1;
if(m < 0 || m > 59) return -1;
if(s < 0 || s > 59) return -1;
return ret;
}
/* parse_time() /* parse_time()
* *
* Parses an ISO-8601 date/time. We support any of the ISO-8601 formats. * Parses an ISO-8601 date/time. We support any of the ISO-8601 formats. Uses libiso8601. On error,
* returns (time_t)-1.
*/ */
time_t parse_time(const char* str) time_t parse_time(const char* str)
{ {
const char* p, * tz; struct iso8601_date iso;
time_t t; time_t t;
int s;
// parse the date portion
p = strchr(str, 'T');
t = p ? parse_time_date(str, p) : parse_time_date(str, str + strlen(str));
if(t == (time_t)-1) return -1;
// parse the time portion
if(p) {
++p;
tz = strchr(p, 'Z');
if(tz) {
if(tz[1]) return -1;
} else {
tz = strchr(p, '+');
if(!tz) tz = strchr(p, '-');
if(!tz) tz = p + strlen(p);
}
s = parse_time_time(p, tz);
if(s == -1) return -1;
t += s;
p = tz + 1;
switch(*tz) {
case '+':
s = parse_time_time(p, p + strlen(p));
if(s == -1) return -1;
t -= s;
break;
case '-':
s = parse_time_time(p, p + strlen(p));
if(s == -1) return -1;
t += s;
break;
}
}
if(iso8601_parse(str, &iso, 0, 0)) return (time_t)-1;
iso8601_to_time_t(&t, &iso);
return t; return t;
} }

View File

@ -51,7 +51,7 @@ int main(int argc, char* argv[])
// process commandline options // process commandline options
while(1) { while(1) {
switch(getopt_long(argc, argv, "hVs:p:", options, 0)) { switch(getopt_long(argc, argv, "hVDs:p:", options, 0)) {
case -1: case -1:
goto done; goto done;

View File

@ -29,9 +29,8 @@ void do_log(int level, const char* fmt, ...)
va_start(va, fmt); va_start(va, fmt);
if(Daemon) { vsyslog(level, fmt, va);
vsyslog(level, fmt, va); if(!Daemon) {
} else {
FILE* out = stdout; FILE* out = stdout;
switch(level) { switch(level) {
@ -128,6 +127,7 @@ int setup_socket(const char* name, int perms)
addr.sun_family = AF_UNIX; addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, name); // main() ensures it is less than UNIX_PATH_MAX bytes strcpy(addr.sun_path, name); // main() ensures it is less than UNIX_PATH_MAX bytes
unlink(name); // unlink any existing socket, but ignore errors
if(bind(fd, (struct sockaddr*)&addr, sizeof(addr))) { if(bind(fd, (struct sockaddr*)&addr, sizeof(addr))) {
LOG(LOG_CRIT, "Couldn't bind socket (fd %d) to file ``%s'' - %s (%d).", LOG(LOG_CRIT, "Couldn't bind socket (fd %d) to file ``%s'' - %s (%d).",
fd, name, strerror(errno), errno); fd, name, strerror(errno), errno);

View File

@ -11,8 +11,8 @@
# expected to be in 'major.minor.micro' format. It can optionally be # expected to be in 'major.minor.micro' format. It can optionally be
# suffixed with a string. # suffixed with a string.
VERMAJOR=1 VERMAJOR=1
VERMINOR=0 VERMINOR=1
VERMICRO=0 VERMICRO=1
VEREXTRA="" VEREXTRA=""
# kate: replace-trailing-space-save true; space-indent true; tab-width 4; # kate: replace-trailing-space-save true; space-indent true; tab-width 4;