Newer
Older
/* Synchronet JavaScript "COM" 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 "js_request.h"
#ifdef JAVASCRIPT
typedef struct
{
COM_HANDLE com;
BOOL external; /* externally created, don't close */
BOOL is_open;
BOOL network_byte_order;
BOOL debug;
BOOL dtr;
long baud_rate;
int last_error;
char *dev;
} 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, "%s %s%s", p->dev, error ? "ERROR: ":"", sbuf);
}
/* COM Destructor */
static void js_finalize_com(JSContext *cx, JSObject *obj)
{
private_t* p;
if ((p = (private_t*)JS_GetPrivate(cx, obj)) == NULL)
if (p->external == FALSE && p->com != COM_HANDLE_INVALID) {
comClose(p->com);
dbprintf(FALSE, p, "closed");
}
free(p->dev);
free(p);
JS_SetPrivate(cx, obj, NULL);
}
/* COM Object Methods */
extern JSClass js_com_class;
js_close(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_com_class)) == NULL) {
if (p->com == COM_HANDLE_INVALID)
rc = JS_SUSPENDREQUEST(cx);
comClose(p->com);
p->last_error = COM_ERROR_VALUE;
dbprintf(FALSE, p, "closed");
p->com = COM_HANDLE_INVALID;
p->is_open = FALSE;
JS_RESUMEREQUEST(cx, rc);
}
static JSBool
js_open(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_com_class)) == NULL) {
rc = JS_SUSPENDREQUEST(cx);
dbprintf(FALSE, p, "opening port %s", p->dev);
p->com = comOpen(p->dev);
if (p->com == COM_HANDLE_INVALID) {
p->last_error = COM_ERROR_VALUE;
dbprintf(TRUE, p, "connect failed with error %d", p->last_error);
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
JS_RESUMEREQUEST(cx, rc);
}
comSetBaudRate(p->com, p->baud_rate);
p->is_open = TRUE;
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
dbprintf(FALSE, p, "connected to port %s", p->dev);
JS_RESUMEREQUEST(cx, rc);
}
static JSBool
js_send(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
char* cp = NULL;
size_t len = 0;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_com_class)) == NULL) {
if (js_argcIsInsufficient(cx, argc, 1))
return JS_FALSE;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
JSVALUE_TO_MSTRING(cx, argv[0], cp, &len);
HANDLE_PENDING(cx, cp);
rc = JS_SUSPENDREQUEST(cx);
if (cp && comWriteBuf(p->com, (uint8_t *)cp, len) == len) {
dbprintf(FALSE, p, "sent %lu bytes", len);
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
p->last_error = COM_ERROR_VALUE;
dbprintf(TRUE, p, "send of %lu bytes failed", len);
JS_RESUMEREQUEST(cx, rc);
}
static JSBool
js_sendfile(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
off_t len;
int file;
char* fname = NULL;
private_t* p;
jsrefcount rc;
char * buf;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_com_class)) == NULL) {
if (js_argcIsInsufficient(cx, argc, 1))
return JS_FALSE;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
JSVALUE_TO_MSTRING(cx, argv[0], fname, NULL);
HANDLE_PENDING(cx, fname);
if (fname == NULL) {
JS_ReportError(cx, "Failure reading filename");
rc = JS_SUSPENDREQUEST(cx);
if ((file = nopen(fname, O_RDONLY | O_BINARY)) == -1) {
JS_RESUMEREQUEST(cx, rc);
len = filelength(file);
if (len < 1) {
if ((buf = malloc((size_t)len)) == NULL) {
if (read(file, buf, (uint)len) != len) {
free(buf);
close(file);
}
close(file);
if (comWriteBuf(p->com, (uint8_t *)buf, (size_t)len) == len) {
dbprintf(FALSE, p, "sent %ld bytes", len);
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
p->last_error = COM_ERROR_VALUE;
dbprintf(TRUE, p, "send of %ld bytes failed", len);
}
free(buf);
JS_RESUMEREQUEST(cx, rc);
}
static JSBool
js_sendbin(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;
int32 val = 0;
size_t wr = 0;
int32 size = sizeof(DWORD);
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_FALSE);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_com_class)) == NULL) {
if (js_argcIsInsufficient(cx, argc, 1))
return JS_FALSE;
if (!JS_ValueToInt32(cx, argv[0], &val))
return JS_FALSE;
if (!JS_ValueToInt32(cx, argv[1], &size))
return JS_FALSE;
rc = JS_SUSPENDREQUEST(cx);
switch (size) {
case sizeof(BYTE):
b = (BYTE)val;
wr = comWriteBuf(p->com, &b, size);
break;
case sizeof(WORD):
w = (WORD)val;
if (p->network_byte_order)
w = htons(w);
wr = comWriteBuf(p->com, (BYTE*)&w, size);
break;
case sizeof(DWORD):
l = val;
if (p->network_byte_order)
l = htonl(l);
wr = comWriteBuf(p->com, (BYTE*)&l, size);
dbprintf(TRUE, p, "unsupported binary write size: %d", size);
if (wr == size) {
dbprintf(FALSE, p, "sent %u bytes (binary)", size);
JS_SET_RVAL(cx, arglist, JSVAL_TRUE);
p->last_error = COM_ERROR_VALUE;
dbprintf(TRUE, p, "send of %u bytes (binary) failed", size);
JS_RESUMEREQUEST(cx, rc);
}
static JSBool
js_recv(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
char* buf;
int32 len = 512;
JSString* str;
jsrefcount rc;
int32 timeout = 30; /* seconds */
private_t* p;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_com_class)) == NULL) {
if (argc) {
if (!JS_ValueToInt32(cx, argv[0], &len))
return JS_FALSE;
}
if (argc > 1) {
if (!JS_ValueToInt32(cx, argv[1], &timeout))
return JS_FALSE;
}
if ((buf = (char*)malloc(len + 1)) == NULL) {
JS_ReportError(cx, "Error allocating %u bytes", len + 1);
rc = JS_SUSPENDREQUEST(cx);
len = comReadBuf(p->com, buf, len, NULL, timeout);
JS_RESUMEREQUEST(cx, rc);
if (len < 0) {
p->last_error = COM_ERROR_VALUE;
JS_SET_RVAL(cx, arglist, JSVAL_NULL);
str = JS_NewStringCopyN(cx, buf, len);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
rc = JS_SUSPENDREQUEST(cx);
dbprintf(FALSE, p, "received %u bytes", len);
JS_RESUMEREQUEST(cx, rc);
}
static JSBool
js_recvline(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj = JS_THIS_OBJECT(cx, arglist);
jsval * argv = JS_ARGV(cx, arglist);
char* buf;
int i;
int32 len = 512;
int32 timeout = 30; /* seconds */
JSString* str;
private_t* p;
jsrefcount rc;
JS_SET_RVAL(cx, arglist, JSVAL_VOID);
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_com_class)) == NULL) {
if (argc) {
if (!JS_ValueToInt32(cx, argv[0], &len))
return JS_FALSE;
}
if ((buf = (char*)malloc(len + 1)) == NULL) {
JS_ReportError(cx, "Error allocating %u bytes", len + 1);
if (argc > 1) {
if (!JS_ValueToInt32(cx, argv[1], &timeout)) {
return JS_FALSE;
rc = JS_SUSPENDREQUEST(cx);
i = comReadLine(p->com, buf, len + 1, timeout);
if (i > 0 && buf[i - 1] == '\r')
buf[i - 1] = 0;
JS_RESUMEREQUEST(cx, rc);
str = JS_NewStringCopyZ(cx, buf);
JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(str));
rc = JS_SUSPENDREQUEST(cx);
dbprintf(FALSE, p, "received %u bytes (recvline) lasterror=%d"
, i, COM_ERROR_VALUE);
JS_RESUMEREQUEST(cx, rc);
}
static JSBool
js_recvbin(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;
int32 size = sizeof(DWORD);
int rd = 0;
private_t* p;
jsrefcount rc;
int32 timeout = 30; /* seconds */
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(-1));
if ((p = (private_t*)js_GetClassPrivate(cx, obj, &js_com_class)) == NULL) {
if (argc) {
if (!JS_ValueToInt32(cx, argv[0], &size))
return JS_FALSE;
}
if (argc > 1) {
if (!JS_ValueToInt32(cx, argv[1], &timeout))
return JS_FALSE;
}
rc = JS_SUSPENDREQUEST(cx);
switch (size) {
if ((rd = comReadBuf(p->com, (char*)&b, size, NULL, timeout)) == size)
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(b));
break;
case sizeof(WORD):
if ((rd = comReadBuf(p->com, (char*)&w, size, NULL, timeout)) == size) {
if (p->network_byte_order)
w = ntohs(w);
JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(w));
}
break;
case sizeof(DWORD):
if ((rd = comReadBuf(p->com, (char*)&l, size, NULL, timeout)) == size) {
if (p->network_byte_order)
l = ntohl(l);
JS_SET_RVAL(cx, arglist, UINT_TO_JSVAL(l));
}
break;
}
if (rd != size)
p->last_error = COM_ERROR_VALUE;
JS_RESUMEREQUEST(cx, rc);
}
/* COM Object Properites */
enum {
COM_PROP_LAST_ERROR
, COM_PROP_IS_OPEN
, COM_PROP_DEBUG
, COM_PROP_DESCRIPTOR
, COM_PROP_NETWORK_ORDER
, COM_PROP_BAUD_RATE
, COM_PROP_DEVICE
, COM_PROP_DTR
, COM_PROP_CTS
, COM_PROP_DSR
, COM_PROP_RING
, COM_PROP_DCD
};
#ifdef BUILD_JSDOCS
static const char* com_prop_desc[] = {
"Error status for the last COM operation that failed - <small>READ ONLY</small>"
, "<tt>true</tt> if port is in a connected state - <small>READ ONLY</small>"
, "Enable debug logging"
, "COM handle (advanced uses only)"
, "<tt>true</tt> if binary data is to be sent in Network Byte Order (big end first), default is <tt>true</tt>"
, "COM port Baud rate"
, "Device name"
, "Data Terminal Ready"
, "Clear To Send"
, "Data Set Ready"
, "Ring Indicator"
, "Data Carrier Detect"
, NULL
static JSBool js_com_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp)
jsval idval;
jsint tiny;
private_t* p;
jsrefcount rc;
double d;
int32 i;
if ((p = (private_t*)JS_GetPrivate(cx, obj)) == NULL) {
// Prototype access
JS_IdToValue(cx, id, &idval);
tiny = JSVAL_TO_INT(idval);
rc = JS_SUSPENDREQUEST(cx);
dbprintf(FALSE, p, "setting property %d", tiny);
JS_RESUMEREQUEST(cx, rc);
case COM_PROP_DEBUG:
JS_ValueToBoolean(cx, *vp, &(p->debug));
break;
case COM_PROP_DESCRIPTOR:
if (!JS_ValueToInt32(cx, *vp, &i))
return JS_FALSE;
p->com = (COM_HANDLE)i;
p->is_open = TRUE;
break;
case COM_PROP_LAST_ERROR:
if (!JS_ValueToInt32(cx, *vp, &i))
return JS_FALSE;
break;
case COM_PROP_BAUD_RATE:
if (JS_ValueToNumber(cx, *vp, &d)) {
p->baud_rate = (long)d;
rc = JS_SUSPENDREQUEST(cx);
if (p->is_open)
comSetBaudRate(p->com, p->baud_rate);
JS_RESUMEREQUEST(cx, rc);
}
break;
case COM_PROP_NETWORK_ORDER:
JS_ValueToBoolean(cx, *vp, &(p->network_byte_order));
break;
case COM_PROP_DTR:
JS_ValueToBoolean(cx, *vp, &(p->dtr));
if (p->is_open) {
if (p->dtr)
comRaiseDTR(p->com);
else
comLowerDTR(p->com);
}
else
break;
}
static JSBool js_com_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
jsval idval;
jsint tiny;
private_t* p;
JSString* js_str;
jsrefcount rc;
long baud_rate;
int ms;
if ((p = (private_t*)JS_GetPrivate(cx, obj)) == NULL) {
JS_IdToValue(cx, id, &idval);
tiny = JSVAL_TO_INT(idval);
rc = JS_SUSPENDREQUEST(cx);
#if 0 /* just too much */
dbprintf(FALSE, p, "getting property %d", tiny);
case COM_PROP_LAST_ERROR:
*vp = INT_TO_JSVAL(p->last_error);
break;
case COM_PROP_IS_OPEN:
else
*vp = JSVAL_FALSE;
break;
case COM_PROP_DEBUG:
*vp = BOOLEAN_TO_JSVAL(p->debug);
break;
case COM_PROP_DESCRIPTOR:
*vp = INT_TO_JSVAL((int)p->com);
break;
case COM_PROP_NETWORK_ORDER:
*vp = BOOLEAN_TO_JSVAL(p->network_byte_order);
break;
case COM_PROP_BAUD_RATE:
baud_rate = comGetBaudRate(p->com);
*vp = UINT_TO_JSVAL(baud_rate);
break;
case COM_PROP_DEVICE:
JS_RESUMEREQUEST(cx, rc);
if ((js_str = JS_NewStringCopyZ(cx, p->dev)) == NULL)
*vp = STRING_TO_JSVAL(js_str);
rc = JS_SUSPENDREQUEST(cx);
break;
case COM_PROP_DTR:
*vp = BOOLEAN_TO_JSVAL(p->dtr);
break;
case COM_PROP_CTS:
ms = comGetModemStatus(p->com);
*vp = BOOLEAN_TO_JSVAL(ms & COM_CTS);
break;
case COM_PROP_DSR:
ms = comGetModemStatus(p->com);
*vp = BOOLEAN_TO_JSVAL(ms & COM_DSR);
break;
case COM_PROP_RING:
ms = comGetModemStatus(p->com);
*vp = BOOLEAN_TO_JSVAL(ms & COM_RING);
break;
case COM_PROP_DCD:
ms = comGetModemStatus(p->com);
*vp = BOOLEAN_TO_JSVAL(ms & COM_DCD);
break;
}
JS_RESUMEREQUEST(cx, rc);
#define COM_PROP_FLAGS JSPROP_ENUMERATE | JSPROP_READONLY
static jsSyncPropertySpec js_com_properties[] = {
/* name ,tinyid ,flags, ver */
{ "error", COM_PROP_LAST_ERROR, COM_PROP_FLAGS, 315 },
{ "last_error", COM_PROP_LAST_ERROR, JSPROP_READONLY, 315 }, /* alias */
{ "is_open", COM_PROP_IS_OPEN, COM_PROP_FLAGS, 315 },
{ "debug", COM_PROP_DEBUG, JSPROP_ENUMERATE, 315 },
{ "descriptor", COM_PROP_DESCRIPTOR, JSPROP_ENUMERATE, 315 },
{ "network_byte_order", COM_PROP_NETWORK_ORDER, JSPROP_ENUMERATE, 315 },
{ "baud_rate", COM_PROP_BAUD_RATE, JSPROP_ENUMERATE, 315 },
{ "device", COM_PROP_DEVICE, COM_PROP_FLAGS, 315 },
{ "dtr", COM_PROP_DTR, JSPROP_ENUMERATE, 315 },
{ "cts", COM_PROP_CTS, COM_PROP_FLAGS, 315 },
{ "dsr", COM_PROP_DSR, COM_PROP_FLAGS, 315 },
{ "ring", COM_PROP_RING, COM_PROP_FLAGS, 315 },
{ "dcd", COM_PROP_DCD, COM_PROP_FLAGS, 315 },
{0}
};
static jsSyncMethodSpec js_com_functions[] = {
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
{"close", js_close, 0, JSTYPE_VOID, ""
, JSDOCSTR("Close the port immediately")
, 315},
{"open", js_open, 2, JSTYPE_BOOLEAN, JSDOCSTR("")
, JSDOCSTR("Connect to a COM port")
, 315},
{"write", js_send, 1, JSTYPE_ALIAS },
{"send", js_send, 1, JSTYPE_BOOLEAN, JSDOCSTR("data")
, JSDOCSTR("Send a string (AKA write)")
, 315},
{"sendfile", js_sendfile, 1, JSTYPE_BOOLEAN, JSDOCSTR("path/filename")
, JSDOCSTR("Send an entire file over the port")
, 315},
{"writeBin", js_sendbin, 1, JSTYPE_ALIAS },
{"sendBin", js_sendbin, 1, JSTYPE_BOOLEAN, JSDOCSTR("value [,bytes=4]")
, JSDOCSTR("Send a binary integer over the port, default number of bytes is 4 (32-bits)")
, 315},
{"read", js_recv, 1, JSTYPE_ALIAS },
{"recv", js_recv, 1, JSTYPE_STRING, JSDOCSTR("[maxlen=512 [,timeout=30]]")
, JSDOCSTR("Receive a string, default maxlen is 512 characters, default timeout is 30 seconds (AKA read)")
, 315},
{"readline", js_recvline, 0, JSTYPE_ALIAS },
{"readln", js_recvline, 0, JSTYPE_ALIAS },
{"recvline", js_recvline, 0, JSTYPE_STRING, JSDOCSTR("[maxlen=512] [,timeout=30.0]")
, JSDOCSTR("Receive a line-feed terminated string, default maxlen is 512 characters, default timeout is 30 seconds (AKA readline and readln)")
, 315},
{"readBin", js_recvbin, 0, JSTYPE_ALIAS },
{"recvBin", js_recvbin, 0, JSTYPE_NUMBER, JSDOCSTR("[bytes=4 [,timeout=30]")
, JSDOCSTR("Receive a binary integer from the port, default number of bytes is 4 (32-bits), default timeout is 30 seconds")
, 315},
static JSBool js_com_resolve(JSContext *cx, JSObject *obj, jsid id)
char* name = NULL;
JSBool ret;
if (id != JSID_VOID && id != JSID_EMPTY) {
if (JSVAL_IS_STRING(idval)) {
HANDLE_PENDING(cx, name);
ret = js_SyncResolve(cx, obj, name, js_com_properties, js_com_functions, NULL, 0);
if (name)
}
static JSBool js_com_enumerate(JSContext *cx, JSObject *obj)
{
return js_com_resolve(cx, obj, JSID_VOID);
JSClass js_com_class = {
"COM" /* name */
, JSCLASS_HAS_PRIVATE /* flags */
, JS_PropertyStub /* addProperty */
, JS_PropertyStub /* delProperty */
, js_com_get /* getProperty */
, js_com_set /* setProperty */
, js_com_enumerate /* enumerate */
, js_com_resolve /* resolve */
, JS_ConvertStub /* convert */
, js_finalize_com /* finalize */
};
/* COM Constructor (creates COM descriptor) */
static JSBool
js_com_constructor(JSContext *cx, uintN argc, jsval *arglist)
JSObject * obj;
jsval * argv = JS_ARGV(cx, arglist);
obj = JS_NewObject(cx, &js_com_class, NULL, NULL);
JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj));
JSVALUE_TO_MSTRING(cx, argv[0], fname, NULL);
HANDLE_PENDING(cx, fname);
if (argc == 0 || fname == NULL) {
JS_ReportError(cx, "Failure reading port name");
if ((p = (private_t*)malloc(sizeof(private_t))) == NULL) {
JS_ReportError(cx, "malloc failed");
memset(p, 0, sizeof(private_t));
p->network_byte_order = TRUE;
p->baud_rate = 9600;
if (!JS_SetPrivate(cx, obj, p)) {
JS_ReportError(cx, "JS_SetPrivate failed");
}
#ifdef BUILD_JSDOCS
js_DescribeSyncObject(cx, obj, "Class used for serial port communications", 31501);
js_DescribeSyncConstructor(cx, obj, "To create a new COM object: "
"<tt>var c = new COM('<i>device</i>')</tt><br>"
"where <i>device</i> = <tt>COMx</tt> (e.g. COM1) for Win32 or <tt>/dev/ttyXY</tt> for *nix (e.g. /dev/ttyu0)"
);
js_CreateArrayOfStrings(cx, obj, "_property_desc_list", com_prop_desc, JSPROP_READONLY);
#endif
dbprintf(FALSE, p, "object constructed");
JSObject* js_CreateCOMClass(JSContext* cx, JSObject* parent)
comobj = JS_InitClass(cx, parent, NULL
, &js_com_class
, js_com_constructor
, 0 /* number of constructor args */
, NULL /* props, specified in constructor */
, NULL /* funcs, specified in constructor */
, NULL, NULL);
JSObject* js_CreateCOMObject(JSContext* cx, JSObject* parent, const char *name, COM_HANDLE com)
JSObject* obj;
private_t* p;
obj = JS_DefineObject(cx, parent, name, &js_com_class, NULL
, JSPROP_ENUMERATE | JSPROP_READONLY);
if ((p = (private_t*)malloc(sizeof(private_t))) == NULL)
memset(p, 0, sizeof(private_t));
p->com = com;
p->external = TRUE;
p->network_byte_order = TRUE;
if (!JS_SetPrivate(cx, obj, p)) {
dbprintf(TRUE, p, "JS_SetPrivate failed");
}
dbprintf(FALSE, p, "object created");
#endif /* JAVSCRIPT */