/* * The builtin Date object. * Copyright (c) 1998 New Generation Software (NGS) Oy * * Author: Markku Rossi */ /* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA */ /* * $Source: /tmp/cvsroot-15-2-2007/clamav-devel/libclamav/js/b_date.c,v $ * $Id: b_date.c,v 1.2 2006/10/28 11:27:44 njh Exp $ */ #if HAVE_CONFIG_H #include "clamav-config.h" #endif #ifdef CL_EXPERIMENTAL #include "jsint.h" #include "rentrant.h" /* XXX TODO 15.13.3 -> */ /* * Types and definitions. */ #define GMT_DATE_FORMAT "%a, %d %b %Y %H:%M:%S GMT" #define MS_PER_SECOND 1000 #define MS_PER_MINUTE (60 * MS_PER_SECOND) #define MS_PER_HOUR (60 * MS_PER_MINUTE) #define MS_PER_DAY (24 * MS_PER_HOUR) /* Class context. */ struct date_ctx_st { /* Static methods. */ JSSymbol s_parse; /* Methods. */ JSSymbol s_format; JSSymbol s_formatGMT; JSSymbol s_getDate; JSSymbol s_getDay; JSSymbol s_getHours; JSSymbol s_getMinutes; JSSymbol s_getMonth; JSSymbol s_getSeconds; JSSymbol s_getTime; JSSymbol s_getTimezoneOffset; JSSymbol s_getYear; JSSymbol s_setDate; JSSymbol s_setHours; JSSymbol s_setMinutes; JSSymbol s_setMonth; JSSymbol s_setSeconds; JSSymbol s_setTime; JSSymbol s_setYear; JSSymbol s_toGMTString; JSSymbol s_toLocaleString; JSSymbol s_UTC; }; typedef struct date_ctx_st DateCtx; /* Date instance context. */ struct date_instance_ctx_st { time_t secs; struct tm localtime; }; typedef struct date_instance_ctx_st DateInstanceCtx; /* * Static functions. */ /* Global methods. */ void MakeTime_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { if (args->u.vinteger != 4) { sprintf (vm->error, "MakeTime: illegal amount of argument"); js_vm_error (vm); } if (!JS_IS_NUMBER (&args[1]) || !JS_IS_NUMBER (&args[2]) || !JS_IS_NUMBER (&args[3]) || !JS_IS_NUMBER (&args[4])) { sprintf (vm->error, "MakeTime: illegal argument"); js_vm_error (vm); } if (!JS_IS_FINITE (&args[1]) || !JS_IS_FINITE (&args[2]) || !JS_IS_FINITE (&args[3]) || !JS_IS_FINITE (&args[4])) { result_return->type = JS_NAN; } else { JSInt32 hour, min, sec, ms; hour = js_vm_to_int32 (vm, &args[1]); min = js_vm_to_int32 (vm, &args[2]); sec = js_vm_to_int32 (vm, &args[3]); ms = js_vm_to_int32 (vm, &args[4]); result_return->type = JS_FLOAT; result_return->u.vfloat = (hour * MS_PER_HOUR + min * MS_PER_MINUTE + sec * MS_PER_SECOND + ms); } } void MakeDay_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { if (args->u.vinteger != 3) { sprintf (vm->error, "MakeDay: illegal amount of argument"); js_vm_error (vm); } if (!JS_IS_NUMBER (&args[1]) || !JS_IS_NUMBER (&args[2]) || !JS_IS_NUMBER (&args[3])) { sprintf (vm->error, "MakeDay: illegal argument"); js_vm_error (vm); } if (!JS_IS_FINITE (&args[1]) || !JS_IS_FINITE (&args[2]) || !JS_IS_FINITE (&args[3])) { result_return->type = JS_NAN; } else { JSInt32 year, month, day; year = js_vm_to_int32 (vm, &args[1]); month = js_vm_to_int32 (vm, &args[2]); day = js_vm_to_int32 (vm, &args[3]); sprintf (vm->error, "MakeDay: not implemented yet"); js_vm_error (vm); } } void MakeDate_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { if (args->u.vinteger != 2) { sprintf (vm->error, "MakeDate: illegal amount of argument"); js_vm_error (vm); } if (!JS_IS_NUMBER (&args[1]) || !JS_IS_NUMBER (&args[2])) { sprintf (vm->error, "MakeDate: illegal argument"); js_vm_error (vm); } if (!JS_IS_FINITE (&args[1]) || !JS_IS_FINITE (&args[2])) { result_return->type = JS_NAN; } else { JSInt32 day; JSInt32 time; day = js_vm_to_int32 (vm, &args[1]); time = js_vm_to_int32 (vm, &args[2]); result_return->type = JS_FLOAT; result_return->u.vfloat = (day * MS_PER_DAY + time); } } void TimeClip_global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { if (args->u.vinteger != 1) { sprintf (vm->error, "TimeClip: illegal amount of argument"); js_vm_error (vm); } if (!JS_IS_NUMBER (&args[1])) { sprintf (vm->error, "TimeClip: illegal argument"); js_vm_error (vm); } if (!JS_IS_FINITE (&args[1])) { result_return->type = JS_NAN; } else { result_return->type = JS_FLOAT; if (args[1].type == JS_INTEGER) result_return->u.vfloat = (double) args[1].u.vinteger; else result_return->u.vfloat = args[1].u.vfloat; if (result_return->u.vfloat > 8.64e15 || result_return->u.vfloat < -8.64e15) result_return->type = JS_NAN; } } /* Method proc. */ static int method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSSymbol method, JSNode *result_return, JSNode *args) { DateCtx *ctx = builtin_info->obj_context; DateInstanceCtx *ictx = instance_context; /* The default return type is integer. */ result_return->type = JS_INTEGER; /* Static methods. */ if (method == ctx->s_parse) { goto not_implemented_yet; } /* ********************************************************************** */ else if (method == vm->syms.s_toString) { if (args->u.vinteger != 0) goto argument_error; if (ictx) goto date_to_string; else js_vm_make_static_string (vm, result_return, "Date", 4); } /* ********************************************************************** */ else if (ictx) { /* Methods. */ if (method == ctx->s_format || method == ctx->s_formatGMT) { struct tm tm_st; struct tm *tm = &ictx->localtime; char *fmt; char *buf; unsigned int buflen; if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_STRING) goto argument_type_error; fmt = js_string_to_c_string (vm, &args[1]); buflen = args[1].u.vstring->len * 2 + 1; buf = js_malloc (vm, buflen); if (method == ctx->s_formatGMT) { js_gmtime (&ictx->secs, &tm_st); tm = &tm_st; } if (args[1].u.vstring->len == 0) buf[0] = '\0'; else { while (strftime (buf, buflen, fmt, tm) == 0) { /* Expand the buffer. */ buflen *= 2; buf = js_realloc (vm, buf, buflen); } } js_vm_make_string (vm, result_return, buf, strlen (buf)); js_free (fmt); js_free (buf); } /* ***************************************************************** */ else if (method == ctx->s_getDate) { if (args->u.vinteger != 0) goto argument_error; result_return->u.vinteger = ictx->localtime.tm_mday; } /* ***************************************************************** */ else if (method == ctx->s_getDay) { if (args->u.vinteger != 0) goto argument_error; result_return->u.vinteger = ictx->localtime.tm_wday; } /* ***************************************************************** */ else if (method == ctx->s_getHours) { if (args->u.vinteger != 0) goto argument_error; result_return->u.vinteger = ictx->localtime.tm_hour; } /* ***************************************************************** */ else if (method == ctx->s_getMinutes) { if (args->u.vinteger != 0) goto argument_error; result_return->u.vinteger = ictx->localtime.tm_min; } /* ***************************************************************** */ else if (method == ctx->s_getMonth) { if (args->u.vinteger != 0) goto argument_error; result_return->u.vinteger = ictx->localtime.tm_mon; } /* ***************************************************************** */ else if (method == ctx->s_getSeconds) { if (args->u.vinteger != 0) goto argument_error; result_return->u.vinteger = ictx->localtime.tm_sec; } /* ***************************************************************** */ else if (method == ctx->s_getTime) { if (args->u.vinteger != 0) goto argument_error; result_return->type = JS_FLOAT; result_return->u.vfloat = (double) ictx->secs * 1000; } /* ***************************************************************** */ else if (method == ctx->s_getTimezoneOffset) goto not_implemented_yet; /* ***************************************************************** */ else if (method == ctx->s_getYear) { if (args->u.vinteger != 0) goto argument_error; result_return->u.vinteger = ictx->localtime.tm_year; if (ictx->localtime.tm_year >= 100 || ictx->localtime.tm_year < 0) result_return->u.vinteger += 1900; } /* ***************************************************************** */ else if (method == ctx->s_setDate) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_INTEGER) goto argument_type_error; if (1 <= args[1].u.vinteger && args[1].u.vinteger <= 31) { ictx->localtime.tm_mday = args[1].u.vinteger; ictx->secs = mktime (&ictx->localtime); } else goto argument_range_error; } /* ***************************************************************** */ else if (method == ctx->s_setHours) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_INTEGER) goto argument_type_error; if (0 <= args[1].u.vinteger && args[1].u.vinteger <= 23) { ictx->localtime.tm_hour = args[1].u.vinteger; ictx->secs = mktime (&ictx->localtime); } else goto argument_range_error; } /* ***************************************************************** */ else if (method == ctx->s_setMinutes) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_INTEGER) goto argument_type_error; if (0 <= args[1].u.vinteger && args[1].u.vinteger <= 59) { ictx->localtime.tm_min = args[1].u.vinteger; ictx->secs = mktime (&ictx->localtime); } else goto argument_range_error; } /* ***************************************************************** */ else if (method == ctx->s_setMonth) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_INTEGER) goto argument_type_error; if (0 <= args[1].u.vinteger && args[1].u.vinteger <= 11) { ictx->localtime.tm_mon = args[1].u.vinteger; ictx->secs = mktime (&ictx->localtime); } else goto argument_range_error; } /* ***************************************************************** */ else if (method == ctx->s_setSeconds) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_INTEGER) goto argument_type_error; if (0 <= args[1].u.vinteger && args[1].u.vinteger <= 59) { ictx->localtime.tm_sec = args[1].u.vinteger; ictx->secs = mktime (&ictx->localtime); } else goto argument_range_error; } /* ***************************************************************** */ else if (method == ctx->s_setTime) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type == JS_INTEGER) ictx->secs = args[1].u.vinteger / 1000; else if (args[1].type == JS_FLOAT) ictx->secs = (long) (args[1].u.vfloat / 1000); else goto argument_type_error; js_localtime (&ictx->secs, &ictx->localtime); } /* ***************************************************************** */ else if (method == ctx->s_setYear) { if (args->u.vinteger != 1) goto argument_error; if (args[1].type != JS_INTEGER) goto argument_type_error; ictx->localtime.tm_year = args[1].u.vinteger; if (args[1].u.vinteger < 0 || args[1].u.vinteger >= 100) ictx->localtime.tm_year -= 1900; ictx->secs = mktime (&ictx->localtime); } /* ***************************************************************** */ else if (method == ctx->s_toGMTString) { struct tm tm_st; char buf[1024]; /* This is enought. */ if (args->u.vinteger != 0) goto argument_error; js_gmtime (&ictx->secs, &tm_st); strftime (buf, sizeof (buf), GMT_DATE_FORMAT, &tm_st); js_vm_make_string (vm, result_return, buf, strlen (buf)); } /* ***************************************************************** */ else if (method == ctx->s_toLocaleString) { char *cp; char buf[1024]; /* This is enought */ if (args->u.vinteger != 0) goto argument_error; date_to_string: js_asctime (&ictx->localtime, buf, sizeof (buf)); cp = strchr (buf, '\n'); if (cp) *cp = '\0'; js_vm_make_string (vm, result_return, buf, strlen (buf)); } /* ***************************************************************** */ else if (method == ctx->s_UTC) goto not_implemented_yet; /* ***************************************************************** */ else return JS_PROPERTY_UNKNOWN; } /* ********************************************************************** */ else return JS_PROPERTY_UNKNOWN; return JS_PROPERTY_FOUND; /* * Error handling. */ not_implemented_yet: sprintf (vm->error, "Date.%s(): not implemented yet", js_vm_symname (vm, method)); js_vm_error (vm); argument_error: sprintf (vm->error, "Date.%s(): illegal amount of arguments", js_vm_symname (vm, method)); js_vm_error (vm); argument_type_error: sprintf (vm->error, "Date.%s(): illegal argument", js_vm_symname (vm, method)); js_vm_error (vm); argument_range_error: sprintf (vm->error, "Date.%s(): argument out of range", js_vm_symname (vm, method)); js_vm_error (vm); /* NOTREACHED. */ return 0; } /* Global method proc. */ static void global_method (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSNode *result_return, JSNode *args) { time_t secs; struct tm localtime; char buf[512]; char *cp; if (args->u.vinteger > 7) { sprintf (vm->error, "Date(): illegal amount of arguments"); js_vm_error (vm); } /* * We ignore our arguments and return the result of: * `new Date ().toString ()'. */ secs = time (NULL); js_localtime (&secs, &localtime); js_asctime (&localtime, buf, sizeof (buf)); cp = strchr (buf, '\n'); if (cp) *cp = '\0'; js_vm_make_string (vm, result_return, buf, strlen (buf)); } /* Property proc. */ static int property (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, void *instance_context, JSSymbol property, int set, JSNode *node) { if (!set) node->type = JS_UNDEFINED; return JS_PROPERTY_UNKNOWN; } /* New proc. */ static void new_proc (JSVirtualMachine *vm, JSBuiltinInfo *builtin_info, JSNode *args, JSNode *result_return) { DateInstanceCtx *instance; time_t seconds = 0; /* Initialized to keep compiler quiet. */ instance = js_calloc (vm, 1, sizeof (*instance)); if (args->u.vinteger == 0) { instance->secs = time (NULL); js_localtime (&instance->secs, &instance->localtime); } else if (args->u.vinteger == 1) goto not_implemented_yet; else if (args->u.vinteger == 3 || args->u.vinteger == 6) { int i; for (i = 0; i < args->u.vinteger; i++) if (args[i + 1].type != JS_INTEGER) goto argument_type_error; /* Year. */ instance->localtime.tm_year = args[1].u.vinteger; if (args[1].u.vinteger < 0 || args[1].u.vinteger >= 100) instance->localtime.tm_year -= 1900; /* Month. */ if (0 <= args[2].u.vinteger && args[2].u.vinteger <= 11) instance->localtime.tm_mon = args[2].u.vinteger; else goto argument_range_error; /* Day. */ if (1 <= args[3].u.vinteger && args[3].u.vinteger <= 31) instance->localtime.tm_mday = args[3].u.vinteger; else goto argument_range_error; if (args->u.vinteger == 6) { /* Sync the localtime according to year, month and day. */ mktime (&instance->localtime); /* Hours. */ if (0 <= args[4].u.vinteger && args[4].u.vinteger <= 23) instance->localtime.tm_hour = args[4].u.vinteger; else goto argument_range_error; /* Minutes. */ if (0 <= args[5].u.vinteger && args[5].u.vinteger <= 59) instance->localtime.tm_min = args[5].u.vinteger; else goto argument_range_error; /* Seconds. */ if (0 <= args[6].u.vinteger && args[6].u.vinteger <= 59) instance->localtime.tm_sec = args[6].u.vinteger; else goto argument_range_error; } instance->secs = mktime (&instance->localtime); } else { js_free (instance); sprintf (vm->error, "new Date(): illegal amount of arguments"); js_vm_error (vm); } js_vm_builtin_create (vm, result_return, builtin_info, instance); return; /* * Error handling. */ not_implemented_yet: sprintf (vm->error, "new Date(%ld args): not implemented yet", args->u.vinteger); js_vm_error (vm); argument_type_error: sprintf (vm->error, "new Date(): illegal argument"); js_vm_error (vm); argument_range_error: sprintf (vm->error, "new Date(): argument out of range"); js_vm_error (vm); } /* Delete proc. */ static void delete_proc (JSBuiltinInfo *builtin_info, void *instance_context) { DateInstanceCtx *ictx = instance_context; if (ictx) js_free (ictx); } /* * Global functions. */ static struct { char *name; JSBuiltinGlobalMethod method; } global_methods[] = { {"MakeTime", MakeTime_global_method}, {"MakeDay", MakeDay_global_method}, {"MakeDate", MakeDate_global_method}, {"TimeClip", TimeClip_global_method}, {NULL, NULL}, }; void js_builtin_Date (JSVirtualMachine *vm) { JSBuiltinInfo *info; DateCtx *ctx; JSNode *n; int i; ctx = js_calloc (vm, 1, sizeof (*ctx)); ctx->s_format = js_vm_intern (vm, "format"); ctx->s_formatGMT = js_vm_intern (vm, "formatGMT"); ctx->s_getDate = js_vm_intern (vm, "getDate"); ctx->s_getDay = js_vm_intern (vm, "getDay"); ctx->s_getHours = js_vm_intern (vm, "getHours"); ctx->s_getMinutes = js_vm_intern (vm, "getMinutes"); ctx->s_getMonth = js_vm_intern (vm, "getMonth"); ctx->s_getSeconds = js_vm_intern (vm, "getSeconds"); ctx->s_getTime = js_vm_intern (vm, "getTime"); ctx->s_getTimezoneOffset = js_vm_intern (vm, "getTimezoneOffset"); ctx->s_getYear = js_vm_intern (vm, "getYear"); ctx->s_parse = js_vm_intern (vm, "parse"); ctx->s_setDate = js_vm_intern (vm, "setDate"); ctx->s_setHours = js_vm_intern (vm, "setHours"); ctx->s_setMinutes = js_vm_intern (vm, "setMinutes"); ctx->s_setMonth = js_vm_intern (vm, "setMonth"); ctx->s_setSeconds = js_vm_intern (vm, "setSeconds"); ctx->s_setTime = js_vm_intern (vm, "setTime"); ctx->s_setYear = js_vm_intern (vm, "setYear"); ctx->s_toGMTString = js_vm_intern (vm, "toGMTString"); ctx->s_toLocaleString = js_vm_intern (vm, "toLocaleString"); ctx->s_UTC = js_vm_intern (vm, "UTC"); /* Object information. */ info = js_vm_builtin_info_create (vm); info->method_proc = method; info->global_method_proc = global_method; info->property_proc = property; info->new_proc = new_proc; info->delete_proc = delete_proc; info->obj_context = ctx; info->obj_context_delete = js_free; /* Define it. */ n = &vm->globals[js_vm_intern (vm, "Date")]; js_vm_builtin_create (vm, n, info, NULL); /* Global methods. */ for (i = 0; global_methods[i].name; i++) { info = js_vm_builtin_info_create (vm); info->global_method_proc = global_methods[i].method; n = &vm->globals[js_vm_intern (vm, global_methods[i].name)]; js_vm_builtin_create (vm, n, info, NULL); } } #endif /*CL_EXPERIMENTAL*/