Newer
Older
/* Synchronet JavaScript "File" Object */
/****************************************************************************
* @format.tab-size 4 (Plain Text/Source Code File Header) *
* @format.use-tabs true (see http://www.synchro.net/ptsc_hdr.html) *
* *
* Copyright Rob Swindell - http://www.synchro.net/copyright.html *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* See the GNU General Public License for more details: gpl.txt or *
* http://www.fsf.org/copyleft/gpl.html *
* *
* For Synchronet coding style and modification guidelines, see *
* http://www.synchro.net/source.html *
* *
* Note: If this box doesn't appear square, then you need to fix your tabs. *
****************************************************************************/
#include "sbbs.h"
#include "md5.h"
#include "base64.h"
#include "uucode.h"
#include "yenc.h"
#include "ini_file.h"
#if !defined(__unix__)
#include <conio.h> /* for kbhit() */
#include "js_request.h"
FILE* fp;
char name[MAX_PATH + 1];
char mode[7];
uchar etx;
BOOL debug;
BOOL rot13;
BOOL yencoded;
BOOL uuencoded;
BOOL b64encoded;
BOOL network_byte_order;
BOOL pipe; /* Opened with popen() use pclose() to close */
ini_style_t ini_style;
} private_t;
static void dbprintf(BOOL error, private_t* p, char* fmt, ...)
{
va_list argptr;
if (p == NULL || (!p->debug && !error))
va_start(argptr, fmt);
vsnprintf(sbuf, sizeof(sbuf), fmt, argptr);
sbuf[sizeof(sbuf) - 1] = 0;
va_end(argptr);
lprintf(LOG_DEBUG, "%04d File %s%s", p->fp ? fileno(p->fp) : 0, error ? "ERROR: ":"", sbuf);
/* Converts fopen() style 'mode' string into open() style 'flags' integer */
static int fopenflags(char *mode)
{
if (strchr(mode, 'b'))
flags |= O_BINARY;
if (strchr(mode, 'x'))
flags |= O_EXCL;
if (strchr(mode, 'w')) {
flags |= O_CREAT | O_TRUNC;
if (strchr(mode, '+'))
flags |= O_RDWR;
else
}
if (strchr(mode, 'a')) {
flags |= O_CREAT | O_APPEND;
if (strchr(mode, '+'))
flags |= O_RDWR;
else
}
if (strchr(mode, 'r')) {
if (strchr(mode, '+'))
flags |= O_RDWR;
else
}
}
/* File Object Methods */
extern JSClass js_file_class;
js_open(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
BOOL shareable = FALSE;
int file = -1;
uintN i;
jsint bufsize = 2 * 1024;
JSString* str;
private_t* p;
jsrefcount rc;
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
SAFECOPY(p->mode, "w+"); /* default mode */
for (i = 0; i < argc; i++) {
if (JSVAL_IS_STRING(argv[i])) { /* mode */
if ((str = JS_ValueToString(cx, argv[i])) == NULL)
return JS_FALSE;
JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
}
else if (JSVAL_IS_BOOLEAN(argv[i])) /* shareable */
shareable = JSVAL_TO_BOOLEAN(argv[i]);
else if (JSVAL_IS_NUMBER(argv[i])) { /* bufsize */
if (!JS_ValueToInt32(cx, argv[i], &bufsize))
}
rc = JS_SUSPENDREQUEST(cx);
if (shareable)
p->fp = fopen(p->name, p->mode);
else {
if ((file = nopen(p->name, fopenflags(p->mode))) != -1) {
char *fdomode = strdup(p->mode);
char *e = fdomode;
/* Remove deprecated (never-worked, non-standard) 'e'xclusive mode char (and warn): */
for (e = strchr(fdomode, 'e'); e ; e = strchr(e, 'e')) {
JS_ReportWarning(cx, "Deprecated file open mode: 'e'");
memmove(e, e + 1, strlen(e));
}
/* Remove (C11 standard) 'x'clusive mode char to avoid MSVC assertion: */
for (e = strchr(fdomode, 'x'); e ; e = strchr(e, 'x'))
memmove(e, e + 1, strlen(e));
if ((p->fp = fdopen(file, fdomode)) == NULL) {
JS_ReportWarning(cx, "fdopen(%s, %s) ERROR %d: %s", p->name, fdomode, errno, strerror(errno));
}
}
free(fdomode);
}
}
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
dbprintf(FALSE, p, "opened: %s", p->name);
if (!bufsize)
setvbuf(p->fp, NULL, _IONBF, 0); /* no buffering */
else {
#ifdef _WIN32
bufsize = 2;
#endif
setvbuf(p->fp, NULL, _IOFBF, bufsize);
}
close(file);
JS_RESUMEREQUEST(cx, rc);
static JSBool
js_popen(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
uintN i;
jsint bufsize = 2 * 1024;
JSString* str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
SAFECOPY(p->mode, "r+"); /* default mode */
for (i = 0; i < argc; i++) {
if (JSVAL_IS_STRING(argv[i])) { /* mode */
if ((str = JS_ValueToString(cx, argv[i])) == NULL)
return JS_FALSE;
JSSTRING_TO_STRBUF(cx, str, p->mode, sizeof(p->mode), NULL);
else if (JSVAL_IS_NUMBER(argv[i])) { /* bufsize */
if (!JS_ValueToInt32(cx, argv[i], &bufsize))
}
}
rc = JS_SUSPENDREQUEST(cx);
p->fp = popen(p->name, p->mode);
if (p->fp != NULL) {
p->pipe = TRUE;
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
dbprintf(FALSE, p, "popened: %s", p->name);
if (!bufsize)
setvbuf(p->fp, NULL, _IONBF, 0); /* no buffering */
setvbuf(p->fp, NULL, _IOFBF, bufsize);
JS_RESUMEREQUEST(cx, rc);
js_close(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
rc = JS_SUSPENDREQUEST(cx);
#ifdef __unix__
pclose(p->fp);
else
#endif
dbprintf(FALSE, p, "closed: %s", p->name);
JS_RESUMEREQUEST(cx, rc);
static JSBool
js_raw_pollin(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
private_t* p;
jsrefcount rc;
int32 timeout = -1;
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
}
if (argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if (!JS_ValueToInt32(cx, argv[0], &timeout))
}
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(FALSE));
rc = JS_SUSPENDREQUEST(cx);
#ifdef __unix__
/*
* TODO: macOS poll() page has the ominous statement that "The poll() system call currently does not support devices."
* But, since we don't support OS X in Synchronet that's likely OK?
*/
if (socket_readable(fileno(p->fp), timeout))
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
#else
if (isatty(fileno(p->fp))) {
if (kbhit()) {
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
rc = JS_SUSPENDREQUEST(cx);
break;
}
SLEEP(1);
if (timeout > 0)
timeout--;
}
else {
if (!eof(fileno(p->fp))) {
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(TRUE));
rc = JS_SUSPENDREQUEST(cx);
break;
}
SLEEP(1);
if (timeout > 0)
timeout--;
}
}
#endif
JS_RESUMEREQUEST(cx, rc);
return JS_TRUE;
}
static JSBool
js_raw_read(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
char* buf;
int32 len;
JSString* str;
private_t* p;
jsrefcount rc;
int fd;
off_t pos;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
if (argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if (!JS_ValueToInt32(cx, argv[0], &len))
} else
len = 1;
if (len < 0)
len = 1;
if ((buf = malloc(len)) == NULL)
rc = JS_SUSPENDREQUEST(cx);
// https://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_05.html#tag_02_05_01
/* For the first handle, the first applicable condition below applies. After the actions
* required below are taken, if the handle is still open, the application can close it.
* If it is a file descriptor, no action is required.
* If the only further action to be performed on any handle to this open file descriptor
* is to close it, no action need be taken.
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
* If it is a stream which is unbuffered, no action need be taken.
* If it is a stream which is line buffered, and the last byte written to the stream was a
* <newline> (that is, as if a: putc('\n') was the most recent operation on that stream),
* no action need be taken.
* If it is a stream which is open for writing or appending (but not also open for reading),
* the application shall either perform an fflush(), or the stream shall be closed.
* If the stream is open for reading and it is at the end of the file ( feof() is true), no
* action need be taken.
* If the stream is open with a mode that allows reading and the underlying open file
* description refers to a device that is capable of seeking, the application shall
* either perform an fflush(), or the stream shall be closed.
* Otherwise, the result is undefined.
* For the second handle:
* If any previous active handle has been used by a function that explicitly changed the file
* offset, except as required above for the first handle, the application shall perform an
* lseek() or fseek() (as appropriate to the type of handle) to an appropriate location.
*/
/*
* Since we don't want to overcomplicate this, it basically boils down to:
* Call fflush() on the stream, lseek() on the descriptor, diddle the descriptor, then fseek() the
* stream.
*
* The only option bit is the fflush() on the stream, but it never hurts and is sometimes
* required by POSIX.
*/
fflush(p->fp);
len = 0;
else {
fd = fileno(p->fp);
lseek(fd, pos, SEEK_SET);
len = read(fileno(p->fp), buf, len);
fseeko(p->fp, pos + (len >= 0 ? len : 0), SEEK_SET);
dbprintf(FALSE, p, "read %d raw bytes", len);
if (len < 0)
len = 0;
JS_RESUMEREQUEST(cx, rc);
str = JS_NewStringCopyN(cx, buf, len);
free(buf);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
}
js_read(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
char* cp;
char* buf;
char* uubuf;
int32 len;
int32 offset;
int32 uulen;
JSString* str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
if (argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if (!JS_ValueToInt32(cx, argv[0], &len))
} else {
rc = JS_SUSPENDREQUEST(cx);
len = (long)filelength(fileno(p->fp));
offset = (long)ftell(p->fp);
if (offset > 0)
len -= offset;
JS_RESUMEREQUEST(cx, rc);
}
if (len < 0)
len = 512;
if ((buf = malloc(len + 1)) == NULL)
rc = JS_SUSPENDREQUEST(cx);
len = fread(buf, 1, len, p->fp);
dbprintf(FALSE, p, "read %u bytes", len);
if (len < 0)
len = 0;
buf[len] = 0;
if (p->etx) {
cp = strchr(buf, p->etx);
rot13(buf);
if (p->uuencoded || p->b64encoded || p->yencoded) {
uulen = len * 2;
if ((uubuf = malloc(uulen)) == NULL) {
free(buf);
JS_RESUMEREQUEST(cx, rc);
if (p->uuencoded)
uulen = uuencode(uubuf, uulen, buf, len);
else if (p->yencoded)
uulen = yencode(uubuf, uulen, buf, len);
else
uulen = b64_encode(uubuf, uulen, buf, len);
if (uulen >= 0) {
free(buf);
buf = uubuf;
len = uulen;
else
free(uubuf);
JS_RESUMEREQUEST(cx, rc);
str = JS_NewStringCopyN(cx, buf, len);
free(buf);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
js_readln(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
char* cp;
char* buf;
int32 len = 512;
JSString* js_str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
if (argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if (!JS_ValueToInt32(cx, argv[0], &len))
}
if ((buf = malloc(len + 1)) == NULL)
rc = JS_SUSPENDREQUEST(cx);
if (fgets(buf, len + 1, p->fp) != NULL) {
len = strlen(buf);
while (len > 0 && (buf[len - 1] == '\r' || buf[len - 1] == '\n'))
len--;
buf[len] = 0;
if (p->etx) {
cp = strchr(buf, p->etx);
rot13(buf);
JS_RESUMEREQUEST(cx, rc);
if ((js_str = JS_NewStringCopyZ(cx, buf)) != NULL) /* exception here Feb-12-2005 */
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(js_str));
} else {
JS_RESUMEREQUEST(cx, rc);
js_readbin(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
BYTE * b;
WORD * w;
DWORD * l;
uint64_t * q;
int32 size = sizeof(DWORD);
private_t* p;
int32 count = 1;
size_t retlen;
void * buffer = NULL;
size_t i;
JSObject* array;
jsval v;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
if (argc && !JSVAL_NULL_OR_VOID(argv[0])) {
if (!JS_ValueToInt32(cx, argv[0], &size))
if (argc > 1 && !JSVAL_NULL_OR_VOID(argv[1])) {
if (!JS_ValueToInt32(cx, argv[1], &count))
}
rc = JS_SUSPENDREQUEST(cx);
if (size != sizeof(BYTE) && size != sizeof(WORD) && size != sizeof(DWORD) && size != sizeof(uint64_t)) {
/* unknown size */
dbprintf(TRUE, p, "unsupported binary read size: %d", size);
JS_RESUMEREQUEST(cx, rc);
buffer = malloc(size * count);
if (buffer == NULL) {
dbprintf(TRUE, p, "malloc failure of %u bytes", size * count);
JS_RESUMEREQUEST(cx, rc);
b = buffer;
w = buffer;
l = buffer;
q = buffer;
retlen = fread(buffer, size, count, p->fp);
if (count == 1) {
if (retlen == 1) {
switch (size) {
case sizeof(BYTE):
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*b));
break;
case sizeof(WORD):
if (p->network_byte_order)
*w = BE_SHORT(*w);
else
*w = LE_SHORT(*w);
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(*w));
break;
case sizeof(DWORD):
if (p->network_byte_order)
*l = BE_LONG(*l);
else
*l = LE_LONG(*l);
JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(*l));
case sizeof(uint64_t):
if (p->network_byte_order)
*q = BE_INT64(*q);
else
*q = LE_INT64(*q);
JS_SET_RVAL(cx, arglist, DOUBLE_TO_JSVAL((double)*q));
break;
}
}
}
else {
JS_RESUMEREQUEST(cx, rc);
array = JS_NewArrayObject(cx, 0, NULL);
for (i = 0; i < retlen; i++) {
switch (size) {
case sizeof(BYTE):
v = INT_TO_JSVAL(*(b++));
break;
case sizeof(WORD):
if (p->network_byte_order)
*w = BE_SHORT(*w);
else
*w = LE_SHORT(*w);
v = INT_TO_JSVAL(*(w++));
break;
case sizeof(DWORD):
if (p->network_byte_order)
*l = BE_LONG(*l);
else
*l = LE_LONG(*l);
v = UINT_TO_JSVAL(*(l++));
case sizeof(uint64_t):
if (p->network_byte_order)
*q = BE_INT64(*q);
else
*q = LE_INT64(*q);
v = DOUBLE_TO_JSVAL((double)*(q++));
break;
}
if (!JS_SetElement(cx, array, i, &v)) {
rc = JS_SUSPENDREQUEST(cx);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
end:
free(buffer);
JS_RESUMEREQUEST(cx, rc);
js_readall(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsint len = 0;
JSObject* array;
private_t* p;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
array = JS_NewArrayObject(cx, 0, NULL);
while (!feof(p->fp)) {
js_readln(cx, argc, arglist);
if (JS_RVAL(cx, arglist) == JSVAL_NULL)
if (!JS_SetElement(cx, array, len++, &JS_RVAL(cx, arglist)))
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
static jsval get_value(JSContext *cx, char* value, bool blanks)
{
char* p;
BOOL f = FALSE;
jsval val;
if (value == NULL || (*value == 0 && !blanks))
/* integer or float? */
for (p = value; *p; p++) {
if (*p == '.' && !f)
f = TRUE;
else if (!IS_DIGIT(*p))
break;
}
if (p != value && *p == 0) {
if (f)
val = DOUBLE_TO_JSVAL(atof(value));
val = UINT_TO_JSVAL(strtoul(value, NULL, 10));
}
/* hexadecimal number? */
if (!strncmp(value, "0x", 2)) {
for (p = value + 2; *p; p++)
if (!isxdigit((uchar) * p))
break;
if (*p == 0) {
val = UINT_TO_JSVAL(strtoul(value, NULL, 0));
}
}
/* Boolean? */
if (!stricmp(value, "true"))
if (!stricmp(value, "false"))
/* String */
return STRING_TO_JSVAL(JS_NewStringCopyZ(cx, value));
}
static double js_DateGetMsecSinceEpoch(JSContext *cx, JSObject *obj)
{
if (!JS_CallFunctionName(cx, obj, "getTime", 0, NULL, &rval)) {
return ((double)time(NULL)) * 1000;
static JSBool
js_iniGetValue(JSContext *cx, uintN argc, jsval *arglist)
{
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
char* section = ROOT_SECTION;
char* key;
char** list;
char buf[INI_MAX_VALUE_LEN];
int32 i;
jsval val;
jsval dflt = argv[2];
private_t* p;
JSObject* array;
JSObject* dflt_obj;
JSObject* date_obj;
jsrefcount rc;
double dbl;
time_t tt;
char* cstr = NULL;
char* cstr2;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
}
if (argc && argv[0] != JSVAL_VOID && argv[0] != JSVAL_NULL)
JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
if (JS_IsExceptionPending(cx)) {
FREE_AND_NULL(section);
FREE_AND_NULL(key);
/*
* Although section can be NULL (ie: root), a NULL key will cause a
* segfault.
*/
JS_ReportError(cx, "Invalid NULL key specified");
FREE_AND_NULL(section);
str_list_t ini = iniReadFile(p->fp);
if (argc < 3 || dflt == JSVAL_VOID) { /* unspecified default value */
rc = JS_SUSPENDREQUEST(cx);
cstr = iniGetString(ini, section, key, NULL, buf);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, get_value(cx, cstr, /* blanks */ false));
}
if (JSVAL_IS_BOOLEAN(dflt)) {
JS_SET_RVAL(cx, arglist, BOOLEAN_TO_JSVAL(
iniGetBool(ini, section, key, JSVAL_TO_BOOLEAN(dflt))));
else if (JSVAL_IS_OBJECT(dflt)) {
if ((dflt_obj = JSVAL_TO_OBJECT(dflt)) != NULL && (strcmp("Date", JS_GetClass(cx, dflt_obj)->name) == 0)) {
tt = (time_t)(js_DateGetMsecSinceEpoch(cx, dflt_obj) / 1000.0);
rc = JS_SUSPENDREQUEST(cx);
dbl = (double)iniGetDateTime(ini, section, key, tt);
JS_RESUMEREQUEST(cx, rc);
if (date_obj != NULL) {
array = JS_NewArrayObject(cx, 0, NULL);
cstr = NULL;
JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
if (JS_IsExceptionPending(cx)) {
FREE_AND_NULL(cstr);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
rc = JS_SUSPENDREQUEST(cx);
list = iniGetStringList(ini, section, key, ",", cstr);
FREE_AND_NULL(cstr);
JS_RESUMEREQUEST(cx, rc);
for (i = 0; list && list[i]; i++) {
val = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, list[i]));
if (!JS_SetElement(cx, array, i, &val))
break;
}
rc = JS_SUSPENDREQUEST(cx);
iniFreeStringList(list);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(array));
else if (JSVAL_IS_DOUBLE(dflt)) {
rc = JS_SUSPENDREQUEST(cx);
dbl = iniGetFloat(ini, section, key, JSVAL_TO_DOUBLE(dflt));
JS_SET_RVAL(cx, arglist, DOUBLE_TO_JSVAL(dbl));
else if (JSVAL_IS_NUMBER(dflt)) {
if (!JS_ValueToInt32(cx, dflt, &i)) {
FREE_AND_NULL(section);
FREE_AND_NULL(key);
rc = JS_SUSPENDREQUEST(cx);
i = iniGetInteger(ini, section, key, i);
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(i));
JSVALUE_TO_MSTRING(cx, dflt, cstr, NULL);
if (JS_IsExceptionPending(cx)) {
FREE_AND_NULL(cstr);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
rc = JS_SUSPENDREQUEST(cx);
cstr2 = iniGetString(ini, section, key, cstr, buf);
JS_RESUMEREQUEST(cx, rc);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, cstr2)));
}
FREE_AND_NULL(section);
FREE_AND_NULL(key);
}
js_iniSetValue_internal(JSContext *cx, JSObject *obj, uintN argc, jsval* argv, str_list_t* list)
char* section = ROOT_SECTION;
char* key = NULL;
char* result = NULL;
int32 i;
jsval value = argv[2];
private_t* p;
JSObject* value_obj;
jsrefcount rc;
char* cstr;
time_t tt;
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_file_class)) == NULL) {
if (argc && argv[0] != JSVAL_VOID && argv[0] != JSVAL_NULL)
JSVALUE_TO_MSTRING(cx, argv[0], section, NULL);
JSVALUE_TO_MSTRING(cx, argv[1], key, NULL);
if (JS_IsExceptionPending(cx)) {
FREE_AND_NULL(section);
FREE_AND_NULL(key);
if (value == JSVAL_VOID) { /* unspecified value */
rc = JS_SUSPENDREQUEST(cx);
result = iniSetString(list, section, key, "", &p->ini_style);
JS_RESUMEREQUEST(cx, rc);
else if (JSVAL_IS_BOOLEAN(value)) {
result = iniSetBool(list, section, key, JSVAL_TO_BOOLEAN(value), &p->ini_style);
else if (JSVAL_IS_DOUBLE(value)) {
result = iniSetFloat(list, section, key, JSVAL_TO_DOUBLE(value), &p->ini_style);
else if (JSVAL_IS_NUMBER(value)) {
if (!JS_ValueToInt32(cx, value, &i)) {
FREE_AND_NULL(section);
FREE_AND_NULL(key);
rc = JS_SUSPENDREQUEST(cx);
result = iniSetInteger(list, section, key, i, &p->ini_style);
} else if (JSVAL_IS_OBJECT(value)
&& (value_obj = JSVAL_TO_OBJECT(value)) != NULL
&& (strcmp("Date", JS_GetClass(cx, value_obj)->name) == 0)) {
tt = (time_t)(js_DateGetMsecSinceEpoch(cx, value_obj) / 1000.0);
rc = JS_SUSPENDREQUEST(cx);
result = iniSetDateTime(list, section, key, /* include_time */ TRUE, tt, &p->ini_style);
JSVALUE_TO_MSTRING(cx, value, cstr, NULL);
if (JS_IsExceptionPending(cx)) {
FREE_AND_NULL(cstr);
FREE_AND_NULL(section);
FREE_AND_NULL(key);
rc = JS_SUSPENDREQUEST(cx);
result = iniSetString(list, section, key, cstr, &p->ini_style);
FREE_AND_NULL(cstr);