Add DATETIME type.

This commit is contained in:
dfs
2007-06-28 03:04:44 +00:00
parent 614ab08099
commit 9501498a7e
3 changed files with 104 additions and 16 deletions

View File

@@ -11,7 +11,7 @@
/***************************************************************/
#include "config.h"
static char const RCSID[] = "$Id: expr.c,v 1.10 2005-09-30 03:29:32 dfs Exp $";
static char const RCSID[] = "$Id: expr.c,v 1.11 2007-06-28 03:04:44 dfs Exp $";
#include <stdio.h>
#include <ctype.h>
@@ -44,7 +44,7 @@ static int Multiply(void), Divide(void), Mod(void), Add(void),
Compare(int);
static int MakeValue (char *s, Value *v, Var *locals);
static int ParseLiteralDate (char **s, int *jul);
static int ParseLiteralDate (char **s, int *jul, int *tim);
/* Binary operators - all left-associative */
@@ -468,10 +468,15 @@ static int MakeValue(char *s, Value *v, Var *locals)
return OK;
} else if (*s == '\'') { /* It's a literal date */
s++;
if ((r=ParseLiteralDate(&s, &h))) return r;
if ((r=ParseLiteralDate(&s, &h, &m))) return r;
if (*s != '\'') return E_BAD_DATE;
v->type = DATE_TYPE;
v->v.val = h;
if (m == NO_TIME) {
v->type = DATE_TYPE;
v->v.val = h;
} else {
v->type = DATETIME_TYPE;
v->v.val = (h * 1440) + m;
}
return OK;
} else if (isdigit(*s)) { /* It's a number - use len to hold it.*/
len = 0;
@@ -529,13 +534,34 @@ static int MakeValue(char *s, Value *v, Var *locals)
/***************************************************************/
int DoCoerce(char type, Value *v)
{
int h, d, m, y, i;
int h, d, m, y, i, k;
char *s;
/* Do nothing if value is already the right type */
if (type == v->type) return OK;
switch(type) {
case DATETIME_TYPE:
switch(v->type) {
case INT_TYPE:
v->type = DATETIME_TYPE;
return OK;
case DATE_TYPE:
v->type = DATETIME_TYPE;
v->v.val *= 1440;
return OK;
case STR_TYPE:
s = v->v.str;
if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = DATETIME_TYPE;
free(v->v.str);
if (m == NO_TIME) m = 0;
v->v.val = i * 1440 + m;
return OK;
default:
return E_CANT_COERCE;
}
case STR_TYPE:
switch(v->type) {
case INT_TYPE: sprintf(CoerceBuf, "%d", v->v.val); break;
@@ -546,6 +572,15 @@ int DoCoerce(char type, Value *v)
sprintf(CoerceBuf, "%04d%c%02d%c%02d",
y, DATESEP, m+1, DATESEP, d);
break;
case DATETIME_TYPE:
i = v->v.val / 1440;
FromJulian(i, &y, &m, &d);
k = v->v.val % 1440;
h = k / 60;
i = k % 60;
sprintf(CoerceBuf, "%04d%c%02d%c%02d %02d%c%02d",
y, DATESEP, m+1, DATESEP, d, h, TIMESEP, i);
break;
default: return E_CANT_COERCE;
}
v->type = STR_TYPE;
@@ -582,6 +617,7 @@ int DoCoerce(char type, Value *v)
case DATE_TYPE:
case TIM_TYPE:
case DATETIME_TYPE:
v->type = INT_TYPE;
return OK;
@@ -598,19 +634,25 @@ int DoCoerce(char type, Value *v)
case STR_TYPE:
s = v->v.str;
if (ParseLiteralDate(&s, &i)) return E_CANT_COERCE;
if (ParseLiteralDate(&s, &i, &m)) return E_CANT_COERCE;
if (*s) return E_CANT_COERCE;
v->type = DATE_TYPE;
free(v->v.str);
v->v.val = i;
return OK;
case DATETIME_TYPE:
v->type = DATE_TYPE;
v->v.val /= 1440;
return OK;
default: return E_CANT_COERCE;
}
case TIM_TYPE:
switch(v->type) {
case INT_TYPE:
case DATETIME_TYPE:
v->type = TIM_TYPE;
v->v.val %= 1440;
if (v->v.val < 0) v->v.val += 1440;
@@ -680,6 +722,16 @@ static int Add(void)
return OK;
}
/* If it's a datetime plus an int, add 'em */
if ((v1.type == DATETIME_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == DATETIME_TYPE)) {
v1.v.val += v2.v.val;
if (v1.v.val < 0) return E_DATE_OVER;
v1.type = DATETIME_TYPE;
PushValStack(v1);
return OK;
}
/* If it's a time plus an int, add 'em mod 1440 */
if ((v1.type == TIM_TYPE && v2.type == INT_TYPE) ||
(v1.type == INT_TYPE && v2.type == TIM_TYPE)) {
@@ -750,6 +802,14 @@ static int Subtract(void)
return OK;
}
/* If it's a datetime minus an int, do subtraction, checking for underflow */
if (v1.type == DATETIME_TYPE && v2.type == INT_TYPE) {
v1.v.val -= v2.v.val;
if (v1.v.val < 0) return E_DATE_OVER;
PushValStack(v1);
return OK;
}
/* If it's a time minus an int, do subtraction mod 1440 */
if (v1.type == TIM_TYPE && v2.type == INT_TYPE) {
v1.v.val = (v1.v.val - v2.v.val) % 1440;
@@ -1059,6 +1119,11 @@ void PrintValue (Value *v, FILE *fp)
FromJulian(v->v.val, &y, &m, &d);
fprintf(fp, "%04d%c%02d%c%02d", y, DATESEP, m+1, DATESEP, d);
}
else if (v->type == DATETIME_TYPE) {
FromJulian(v->v.val / 1440, &y, &m, &d);
fprintf(fp, "%04d%c%02d%c%02d %02d%c%02d", y, DATESEP, m+1, DATESEP, d,
(v->v.val % 1440) / 60, TIMESEP, (v->v.val % 1440) % 60);
}
else fprintf(fp, "ERR");
}
@@ -1086,15 +1151,19 @@ int CopyValue(Value *dest, const Value *src)
/* */
/* ParseLiteralDate */
/* */
/* Parse a literal date. Return result in jul, update s. */
/* Parse a literal date or datetime. Return result in jul */
/* and tim; update s. */
/* */
/***************************************************************/
static int ParseLiteralDate(char **s, int *jul)
static int ParseLiteralDate(char **s, int *jul, int *tim)
{
int y, m, d;
int hour, min;
y=0; m=0; d=0;
hour=0; min=0;
*tim = NO_TIME;
if (!isdigit(**s)) return E_BAD_DATE;
while (isdigit(**s)) {
y *= 10;
@@ -1119,6 +1188,23 @@ static int ParseLiteralDate(char **s, int *jul)
*jul = Julian(y, m, d);
/* Do we have a time part as well? */
if (**s == ' ') {
(*s)++;
while(isdigit(**s)) {
hour *= 10;
hour += *(*s)++ - '0';
}
if (**s != ':' && **s != '.' && **s != TIMESEP) return E_BAD_TIME;
(*s)++;
while(isdigit(**s)) {
min *= 10;
min += *(*s)++ - '0';
}
if (hour > 23 || min > 59) return E_BAD_TIME;
*tim = hour * 60 + min;
}
return OK;
}

View File

@@ -10,14 +10,15 @@
/* */
/***************************************************************/
/* $Id: expr.h,v 1.4 2000-02-18 03:45:53 dfs Exp $ */
/* $Id: expr.h,v 1.5 2007-06-28 03:04:44 dfs Exp $ */
/* Define the types of values */
#define ERR_TYPE 0
#define INT_TYPE 1
#define TIM_TYPE 2
#define DATE_TYPE 3
#define STR_TYPE 4
#define ERR_TYPE 0
#define INT_TYPE 1
#define TIM_TYPE 2
#define DATE_TYPE 3
#define STR_TYPE 4
#define DATETIME_TYPE 5
/* Define stuff for parsing expressions */
#define BEG_OF_EXPR '['

View File

@@ -12,7 +12,7 @@
/***************************************************************/
#include "config.h"
static char const RCSID[] = "$Id: funcs.c,v 1.10 2005-09-30 03:29:32 dfs Exp $";
static char const RCSID[] = "$Id: funcs.c,v 1.11 2007-06-28 03:04:44 dfs Exp $";
#include <stdio.h>
@@ -415,6 +415,7 @@ static int FCoerce(void)
else if (! StrCmpi(s, "date")) return DoCoerce(DATE_TYPE, &RetVal);
else if (! StrCmpi(s, "time")) return DoCoerce(TIM_TYPE, &RetVal);
else if (! StrCmpi(s, "string")) return DoCoerce(STR_TYPE, &RetVal);
else if (! StrCmpi(s, "datetime")) return DoCoerce(DATETIME_TYPE, &RetVal);
else return E_CANT_COERCE;
}