#pike __REAL_VERSION__ |
#pragma strict_types |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Boolean |
|
|
{ |
constant is_val_boolean = 1; |
|
|
|
string encode_json(); |
} |
|
class True |
|
|
{ |
inherit Boolean; |
|
constant is_val_true = 1; |
|
|
string encode_json() {return "true";} |
|
|
|
protected int __hash() |
{ |
return 34123; |
} |
protected int `== (mixed other) |
{ |
return objectp (other) && [int]([object]other)->is_val_true; |
} |
|
protected mixed cast (string type) |
{ |
switch (type) { |
case "int": return 1; |
case "string": return "1"; |
default: error ("Cannot cast %O to %s.\n", this, type); |
} |
} |
|
protected string _sprintf (int flag) |
{ |
return flag == 'O' && "Val.true"; |
} |
} |
|
class False |
|
|
{ |
inherit Boolean; |
|
constant is_val_false = 1; |
|
|
protected int `!() {return 1;} |
|
string encode_json() {return "false";} |
|
protected int __hash() |
{return 54634;} |
protected int `== (mixed other) |
{return objectp (other) && [int]([object]other)->is_val_false;} |
|
protected mixed cast (string type) |
{ |
switch (type) { |
case "int": return 0; |
case "string": return "0"; |
default: error ("Cannot cast %O to %s.\n", this, type); |
} |
} |
|
protected string _sprintf (int flag) |
{ |
return flag == 'O' && "Val.false"; |
} |
} |
|
Boolean true = True(); |
Boolean false = False(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constant Null = Builtin.Null; |
|
|
|
Null null = Null(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#define NANOSECONDS 1000000000 |
|
|
|
|
|
int local_timezone = lambda() { |
int tprobe = time(1); |
for(;; tprobe -= 4 * 30 * 24 * 3600) { |
mapping(string:int) tm = localtime(tprobe); |
if (!tm->isdst) |
return tm->timezone; |
} |
}(); |
|
|
|
|
|
|
|
|
final string iso_timezone(int timezone) { |
if (timezone) { |
string res; |
if (timezone < 0) |
timezone = -timezone, res = "+"; |
else |
res = "-"; |
res += sprintf("%02d", timezone / 3600); |
if (timezone %= 3600) { |
res += sprintf(":%02d", timezone / 60); |
if (timezone %= 60) |
res += sprintf(":%02d", timezone); |
} |
return res; |
} |
return ""; |
} |
|
|
|
|
|
|
|
|
string iso_time(mapping(string:int) tm) { |
string res = sprintf("%02d:%02d", tm->hour, tm->min); |
int usec = tm->nsec; |
if (tm->sec || usec) { |
res += sprintf(":%02d", tm->sec); |
if (usec) { |
int msec; |
res += (usec /= 1000) * 1000 != tm->nsec |
? sprintf(".%09d", tm->nsec) |
: (msec = usec / 1000) * 1000 != usec |
? sprintf(".%06d", usec) |
: sprintf(".%03d", msec); |
} |
} |
return res; |
} |
|
|
|
|
|
|
|
class Timebase { |
|
|
|
int nsecs; |
|
array(int) _encode() { |
return ({nsecs}); |
} |
|
void _decode(array(int) x) { |
nsecs = x[0]; |
} |
|
|
|
|
|
variant protected void create(void|mapping(string:int) tm) { |
} |
variant protected void create(this_program copy) { |
nsecs = [int]copy->nsecs; |
} |
variant protected void create(int|float sec, void|int nsec) { |
nsecs = (int)(sec * NANOSECONDS + nsec); |
} |
|
|
|
int|float `usecs() { |
return nsecs % 1000 ? nsecs / 1000.0 : nsecs / 1000; |
} |
|
|
|
|
|
int `usecs=(int usec) { |
nsecs = 1000 * usec; |
return usec; |
} |
|
protected mixed `+(mixed that) { |
if (objectp(that) && ([object]that)->is_interval) { |
this_program n; |
if (([object]that)->days || ([object]that)->months) { |
mapping(string:int) t = tm(); |
if (([object]that)->days) |
if (t->mday) |
t->mday += [int]([object]that)->days; |
else |
error("Adding days is not supported\n"); |
if (([object]that)->months) |
if (zero_type(t->mon)) |
error("Adding months is not supported\n"); |
else |
t->mon += [int]([object]that)->months; |
|
|
|
|
int oldtimezone = t->timezone; |
t = (n = this_program(t))->tm(); |
n->nsecs += (t->timezone - oldtimezone) * NANOSECONDS; |
} else |
n = this_program(this); |
n->nsecs += [int]([object]that)->nsecs; |
return n; |
} else if (!intp(that) && !floatp(that)) |
error("Cannot add %O\n", that); |
this_program n = this_program(); |
n->nsecs = (int)(nsecs + [float|int]that * NANOSECONDS); |
return n; |
} |
|
protected mixed `-(mixed that) { |
return this + -that; |
} |
|
protected int(0..1) `<(mixed that) { |
return |
intp(that) ? nsecs < [int]that * NANOSECONDS |
: floatp(that) ? nsecs < [float]that * NANOSECONDS |
: objectp(that) && nsecs < [int]([object]that)->nsecs |
&& !zero_type(([object]that)->nsecs); |
} |
|
protected int(0..1) `==(mixed that) { |
return objectp(that) |
? nsecs == [int]([object]that)->nsecs && !zero_type(([object]that)->nsecs) |
: intp(that) ? nsecs == [int]that * NANOSECONDS |
: floatp(that) && (float)nsecs == [float]that * NANOSECONDS; |
} |
|
public mapping(string:int) tm() { |
return (["nsec": abs(nsecs) % NANOSECONDS ]); |
} |
|
|
|
|
|
protected mixed cast(string to) { |
switch (to) { |
case "string": |
return (nsecs < 0 ? "-" : "") + iso_time(tm()); |
case "float": |
return nsecs / NANOSECONDS.0; |
case "int": |
return nsecs / NANOSECONDS; |
default: |
return UNDEFINED; |
} |
} |
|
protected string _sprintf(int fmt, mapping(string:mixed) params) { |
switch (fmt) { |
case 's': return (string)this; |
default: return sprintf(sprintf("%%*%c", fmt), params, 0); |
} |
} |
} |
|
|
|
|
|
|
|
|
|
|
class Time { |
inherit Timebase; |
constant is_time = 1; |
|
|
|
|
|
|
|
|
|
variant |
protected void create(int hour, int min, void|int sec, void|int nsec) { |
nsecs = ((((hour * 60) + min) * 60 + sec) * NANOSECONDS) + nsec; |
} |
variant protected void create(int sec) { |
nsecs = sec * NANOSECONDS; |
} |
|
|
|
|
|
|
|
|
variant protected void create(mapping(string:int) tm) { |
create(tm->hour, tm->min, tm->sec, tm->nsec); |
} |
|
protected mixed `+(mixed that) { |
if (objectp(that) && ([object]that)->is_date) |
return that + this; |
return ::`+(that); |
} |
|
|
|
|
|
|
public mapping(string:int) tm() { |
int hourleft; |
int secleft = (hourleft = abs(nsecs) / NANOSECONDS) % 60; |
int minleft = (hourleft /= 60) % 60; |
hourleft /= 60; |
return ::tm() + (["hour":hourleft, "min":minleft, "sec":secleft]); |
} |
|
protected string _sprintf(int fmt, mapping(string:mixed) params) { |
if (fmt == 'O') |
return sprintf("Time(%s)", (string)this); |
return ::_sprintf(fmt, params); |
} |
} |
|
|
|
|
|
|
|
class TimeTZ { |
inherit Time; |
|
|
|
|
|
|
|
int timezone; |
|
array(int) _encode() { |
return ({nsecs, timezone}); |
} |
|
void _decode(array(int) x) { |
nsecs = x[0]; |
timezone = x[1]; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variant protected void create(int year, int month, int day, |
int hour, int min, void|int sec, void|int nsec) { |
mapping(string:int) t |
= localtime(mktime((["year":year - 1900, "mon":month - 1, |
"mday":day, "hour":hour, "min":min, "sec":sec]))); |
t->nsec = nsec; |
create(t); |
} |
|
|
|
|
|
|
|
|
variant protected void create(mapping(string:int) tm) { |
timezone = zero_type(tm->timezone) ? local_timezone : tm->timezone; |
::create(tm->hour, tm->min, tm->sec, tm->nsec); |
} |
|
variant |
protected void create(int hour, int min, void|int sec, void|int nsec) { |
timezone = local_timezone; |
::create(hour, min, sec, nsec); |
} |
variant protected void create(this_program copy) { |
timezone = [int]copy->timezone; |
::create(copy); |
} |
|
public mapping(string:int) tm() { |
return ::tm() + (["timezone":timezone]); |
} |
|
protected mixed cast(string to) { |
if (to == "string") |
return ::cast(to) + iso_timezone(timezone); |
return ::cast(to); |
} |
|
protected string _sprintf(int fmt, mapping(string:mixed) params) { |
if (fmt == 'O') |
return sprintf("TimeTZ(%s)", (string)this); |
return ::_sprintf(fmt, params); |
} |
} |
|
|
|
|
|
|
|
|
|
|
|
|
class Interval { |
inherit Time; |
constant is_interval = 1; |
|
|
|
int days; |
|
|
int months; |
|
array(int) _encode() { |
return ({nsecs, days, months}); |
} |
|
void _decode(array(int) x) { |
nsecs = x[0]; |
days = x[1]; |
months = x[2]; |
} |
|
variant protected void create(this_program copy) { |
::create(copy); |
days = copy->days; |
months = copy->months; |
} |
|
protected mixed `*(mixed that) { |
this_program n = this_program(this); |
if (intp(that)) { |
n->nsecs *= that; |
n->days *= that; |
n->months *= that; |
} else if (floatp(that)) { |
n->nsecs = (int)(nsecs * that); |
n->days = (int)(days * that); |
n->months = (int)(months * that); |
if (days && n->days % days || months && n->months % months) |
error("Cannot create fractional days or months\n"); |
} else |
error("Cannot add %O\n", that); |
return n; |
} |
|
protected mixed `/(mixed that) { |
if (!intp(that) && !floatp(that)) |
error("Cannot divide by %O\n", that); |
this_program n = this_program(this); |
n->nsecs = (int)(nsecs / that); |
n->days = (int)(days / that); |
n->months = (int)(months / that); |
if (days && n->days % days || months && n->months % months) |
error("Cannot create fractional days or months\n"); |
return n; |
} |
|
protected mixed `+(mixed that) { |
if (!objectp(that) || !([object]that)->is_interval) |
error("Cannot add %O\n", that); |
this_program n = this_program(this); |
n->nsecs += ([object]that)->nsecs; |
n->days += ([object]that)->days; |
n->months += ([object]that)->months; |
return n; |
} |
|
protected mixed `-(void|mixed that) { |
this_program n = this_program(this); |
if (zero_type(that)) { |
n->nsecs = -n->nsecs; |
n->days = -n->days; |
n->months = -n->months; |
} else if (!objectp(that) || !([object]that)->is_interval) |
error("Cannot substract %O\n", that); |
else { |
n->nsecs -= ([object]that)->nsecs; |
n->days -= ([object]that)->days; |
n->months -= ([object]that)->months; |
} |
return n; |
} |
|
protected int(0..1) `<(mixed that) { |
return objectp(that) && ([object]that)->is_interval |
&& |
( months <= ([object]that)->months && days <= ([object]that)->days |
&& nsecs < ([object]that)->nsecs |
|| months <= ([object]that)->months && days < ([object]that)->days |
&& nsecs <= ([object]that)->nsecs |
|| months < ([object]that)->months && days <= ([object]that)->days |
&& nsecs <= ([object]that)->nsecs); |
} |
|
protected int(0..1) `==(mixed that) { |
return objectp(that) && ([object]that)->is_interval |
&& months == [int]([object]that)->months |
&& days == [int]([object]that)->days |
&& nsecs == [int]([object]that)->nsecs; |
} |
|
|
|
|
|
|
|
public mapping(string:int) tm() { |
return ::tm() + (["mon":months, "mday":days]) |
+ (nsecs < 0 ? (["isnegative":1]) : ([])); |
} |
|
|
|
|
|
protected mixed cast(string to) { |
switch (to) { |
case "string": { |
string res = months ? sprintf("%d MONTH", months) : ""; |
if (days) |
res += (res > "" ? " " : "") + sprintf("%d DAY", days); |
return res + (nsecs ? (res > "" ? " " : "") + ::cast(to) : ""); |
} |
case "float": |
case "int": |
if (months || days) |
error("Interval contains variable units and cannot be casted\n"); |
} |
return ::cast(to); |
} |
|
protected string _sprintf(int fmt, mapping(string:mixed) params) { |
if (fmt == 'O') |
return sprintf("Interval(%s)", (string)this); |
return ::_sprintf(fmt, params); |
} |
} |
|
|
|
|
|
|
|
|
class Timestamp { |
inherit Timebase; |
constant is_timestamp = 1; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variant protected void create(int year, int month, int day, |
void|int hour, void|int min, void|int sec, void|int nsec) { |
create((["year":year - 1900, "mon":month - 1, "mday":day, "hour":hour, |
"min":min, "sec":sec, "nsec":nsec |
])); |
} |
variant protected void create(int unix_time, void|int nsec) { |
::create(unix_time, nsec); |
} |
|
variant protected void create(object copy) { |
|
create([mapping(string:int)]copy->tm() - (<"timezone">)); |
} |
variant protected void create(mapping(string:int) tm) { |
create(mktime(tm), tm->nsec); |
} |
|
protected mixed `-(void|mixed that) { |
if (zero_type(that)) |
error("Cannot negate %O\n", this); |
if (objectp(that)) { |
if (([object]that)->is_date) |
that = this_program([object]that); |
if (([object]that)->is_timestamp) { |
Interval n = Interval(); |
n->nsecs = nsecs - [int]([object]that)->nsecs; |
return n; |
} |
if (!([object]that)->is_interval) |
error("Cannot substract %O\n", that); |
} |
return this + -that; |
} |
|
inline protected int(0..1) `<(mixed that) { |
return intp(that) ? (int)this < that : ::`<(that); |
} |
|
|
|
|
|
|
public mapping(string:int) tm() { |
return localtime((int)this) + (["nsec": nsecs % NANOSECONDS ]); |
} |
|
|
|
protected mixed cast(string to) { |
switch (to) { |
case "string": { |
mapping(string:int) t = tm(); |
string res = sprintf("%04d/%02d/%02d", |
t->year + 1900, t->mon+1, t->mday); |
if (t->hour || t->min || t->sec || t->nsec) |
res += " " + iso_time(t); |
return res + iso_timezone(t->timezone); |
} |
} |
return ::cast(to); |
} |
|
protected string _sprintf(int fmt, mapping(string:mixed) params) { |
if (fmt == 'O') |
return sprintf("Timestamp(%s)", (string)this); |
return ::_sprintf(fmt, params); |
} |
} |
|
|
|
|
|
|
|
class Date { |
constant is_date = 1; |
|
|
int days; |
|
array(int) _encode() { |
return ({days}); |
} |
|
void _decode(array(int) x) { |
days = x[0]; |
} |
|
|
variant protected void create(int year, int month, int day) { |
create((["year":year - 1900, "mon":month - 1, "mday":day])); |
} |
variant protected void create(this_program copy) { |
days = [int]copy->days; |
} |
variant protected void create(Timestamp copy) { |
days = copy->nsecs / (24 * 3600 * NANOSECONDS) - (copy->nsecs < 0); |
} |
variant protected void create(mapping(string:int) tm) { |
create(mktime(tm + (["isdst":0, "timezone":0]))); |
} |
variant protected void create(int unix_time) { |
days = unix_time / (24 * 3600); |
} |
variant protected void create(float unix_time) { |
create((int)unix_time); |
} |
variant protected void create() { |
} |
|
protected mixed `+(mixed that) { |
object n = this_program(this); |
if (objectp(that)) { |
if (([object]that)->is_interval) { |
n->days += ([object]that)->days; |
if(([object]that)->months) { |
mapping(string:int) t = [mapping(string:int)]n->tm(); |
t->mon += ([object]that)->months; |
n = this_program(t); |
} |
if (([object]that)->nsecs) |
(n = Timestamp(n))->nsecs += ([object]that)->nsecs; |
} else if (([object]that)->is_time) { |
mapping(string:int) t = [mapping(string:int)]n->tm() |
+ [mapping(string:int)]([object]that)->tm(); |
n = Timestamp(t); |
} else |
error("Cannot add %O\n", that); |
} else if (intp(that)) |
n->days += that; |
else |
error("Cannot add %O\n", that); |
return n; |
} |
|
protected mixed `-(void|mixed that) { |
if (zero_type(that)) |
error("Cannot negate %O\n", this); |
if (objectp(that)) { |
Interval n = Interval(); |
if (([object]that)->is_date) { |
n->days = days - [int]([object]that)->days; |
return n; |
} |
if (([object]that)->is_timestamp) { |
n->nsecs = Timestamp(this)->nsecs - [int]([object]that)->nsecs; |
return n; |
} |
error("Cannot substract %O\n", that); |
} |
return this + -that; |
} |
|
inline protected int(0..1) `<(mixed that) { |
return |
intp(that) ? (int)this < that |
: floatp(that) ? (float)this < that |
: objectp(that) |
&& (([object]that)->is_date ? days < ([object]that)->days |
: ([object]that)->is_timestamp |
&& days * 24 * 3600 * NANOSECONDS < ([object]that)->nsecs); |
} |
|
inline protected int(0..1) `>(mixed that) { |
return |
intp(that) ? (int)this > that |
: floatp(that) ? (float)this > that |
: objectp(that) |
&& (([object]that)->is_date ? days > ([object]that)->days |
: ([object]that)->is_timestamp |
&& days * 24 * 3600 * NANOSECONDS > ([object]that)->nsecs); |
} |
|
protected int(0..1) `==(mixed that) { |
return |
objectp(that) |
&& (days == [int]([object]that)->days |
&& !zero_type(([object]that)->days) |
|| !zero_type(([object]that)->nsecs) |
&& days * 24 * 3600 * NANOSECONDS == [int]([object]that)->nsecs) |
|| intp(that) && (int)this == [int]that |
|| floatp(that) && (float)this == [float]that; |
} |
|
public mapping(string:int) tm() { |
return gmtime((int)this); |
} |
|
protected mixed cast(string to) { |
switch (to) { |
case "string": { |
mapping(string:int) t = tm(); |
return sprintf("%04d/%02d/%02d", t->year + 1900, t->mon+1, t->mday); |
} |
case "float": |
return (float)(int)this; |
case "int": |
return days * 24 * 3600; |
default: |
return UNDEFINED; |
} |
} |
|
protected string _sprintf(int fmt, mapping(string:mixed) params) { |
switch (fmt) { |
case 'O': return sprintf("Date(%s)", (string)this); |
case 's': return (string)this; |
} |
return sprintf(sprintf("%%*%c", fmt), params, 0); |
} |
} |
|
|