[mw-devel] MW3 r963 - trunk/src
psycodom at sucs.org
psycodom at sucs.org
Mon May 21 10:22:26 BST 2007
Author: psycodom
Date: 2007-05-21 10:22:26 +0100 (Mon, 21 May 2007)
New Revision: 963
Modified:
trunk/src/iconv.c
trunk/src/js.c
trunk/src/js.h
trunk/src/main.c
trunk/src/sqlite.c
trunk/src/sqlite.h
Log:
Fixes a handful of memory leaks.
Sorts the javascript sqlite code to return a useful error if a query fails rather than stopping execution.
Adds a handful of useful features to javascript.
Modified: trunk/src/iconv.c
===================================================================
--- trunk/src/iconv.c 2007-05-11 17:42:08 UTC (rev 962)
+++ trunk/src/iconv.c 2007-05-21 09:22:26 UTC (rev 963)
@@ -263,7 +263,7 @@
{
strcpy(buffcpy, buff);
conversion_result=convert_string_charset(buffcpy, "UTF-8", strlen(buffcpy), buff, "UTF-8", strlen(buff)+1, NULL, NULL, NULL, NULL, NULL);
-
+ free(buffcpy);
}
return conversion_result;
}
Modified: trunk/src/js.c
===================================================================
--- trunk/src/js.c 2007-05-11 17:42:08 UTC (rev 962)
+++ trunk/src/js.c 2007-05-21 09:22:26 UTC (rev 963)
@@ -11,6 +11,7 @@
#include <iconv.h>
#include <sys/types.h>
#include <pwd.h>
+#include <readline/readline.h>
#include "bb.h"
#include "proto.h"
@@ -19,7 +20,17 @@
#include "script.h"
#include "talker_privs.h"
#include "iconv.h"
+#include "alias.h"
+extern Alias alias_list;
+extern Alias bind_list;
+extern Alias rpc_list;
+extern Alias event_list;
+extern Alias onoff_list;
+extern Alias ipc_list;
+extern Alias force_list;
+extern Alias shutdown_list;
+
extern struct person *user;
extern long userposn;
extern unsigned long rights;
@@ -31,6 +42,9 @@
static JSContext *jscx = NULL;
static JSObject *jsroot = NULL;
+enum bindtype { K_BIND=0, K_BIND_EVENT, K_BIND_ONOFF, K_BIND_IPC, K_BIND_FORCE, K_BIND_SHUTDOWN, K_BIND_ALIAS, K_BIND_RPC };
+#define K_BROADCAST 1
+
JSClass globclass = {
"milliways", JSCLASS_HAS_PRIVATE,
JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,JS_PropertyStub,
@@ -52,6 +66,20 @@
JSCLASS_NO_OPTIONAL_MEMBERS
};
+JSClass js_userrecordclass = {
+ "userrecord", JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
+JSClass js_termsizeclass = {
+ "termsize", JSCLASS_HAS_PRIVATE,
+ JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
+ JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub,
+ JSCLASS_NO_OPTIONAL_MEMBERS
+};
+
// turns a jsval into a utf-8 string that mw can handle
// expects the utf8_buffer to have been allocated and be at least buffer_length long
// used to reduce mass code duplication
@@ -77,7 +105,7 @@
/* Function for printing to standard out from javascript (helpful for
- * debugging and demonstrates how to call C from js)
+ * debugging and demonstrates how to call C from js) - also useful for event functions
*/
static JSBool js_print(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval)
{
@@ -135,6 +163,7 @@
return JS_FALSE;
}
+
/* say to the talker */
static JSBool js_say(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval)
{
@@ -163,6 +192,329 @@
return JS_FALSE;
}
+/* send an rpc/rpb */
+static JSBool js_rpc(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval)
+{
+ char msg[MAXTEXTLENGTH]="";
+ char rpc_type[MAXTEXTLENGTH]="";
+ char username[NAMESIZE+1]="";
+ int broadcast=0;
+
+ int conversion_result;
+ if (argc < 3) {
+ printf("Error: javascript rpc() expects 3 arguments\n");
+ return JS_FALSE;
+ }
+ if(JSVAL_IS_INT(argv[0])) {
+ if(JSVAL_TO_INT(argv[0]) == K_BROADCAST) {
+ broadcast=1;
+ }
+ }
+
+ if (JSVAL_IS_STRING(argv[0])) {
+ conversion_result=jsval_to_utf8string(cx, argv[0], username, NAMESIZE+1);
+ if( conversion_result < 0) {
+ printf("Error: javascript rpc(): major argument conversion error\n");
+ return JS_FALSE;
+ }
+ }
+
+ conversion_result=jsval_to_utf8string(cx, argv[1], rpc_type, MAXTEXTLENGTH-100);
+ if( conversion_result < 0) {
+ printf("Error: javascript rpc(): major argument conversion error\n");
+
+ return JS_FALSE;
+ }
+ conversion_result=jsval_to_utf8string(cx, argv[2], msg, MAXTEXTLENGTH-100);
+ if( conversion_result < 0) {
+ printf("Error: javascript rpc(): major argument conversion error\n");
+ return JS_FALSE;
+ }
+ // something is empty
+ if( (broadcast==0 && username[0]=='\0') || rpc_type[0]=='\0') {
+ printf("Error: javascript rpc(): invalid arguments\n");
+ return JS_FALSE;
+ }
+
+ sendrpc(username, rpc_type, msg, broadcast);
+
+ return JS_TRUE;
+}
+
+/* send an ipc/ipb */
+static JSBool js_ipc(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval)
+{
+ char msg[MAXTEXTLENGTH]="";
+ char username[NAMESIZE+1]="";
+ int broadcast=0;
+ int conversion_result;
+ if (argc < 2) {
+ printf("Error: javascript ipc() expects 2 arguments\n");
+ return JS_FALSE;
+ }
+ if(JSVAL_IS_INT(argv[0])) {
+ if(JSVAL_TO_INT(argv[0]) == K_BROADCAST) {
+ broadcast=1;
+ }
+ }
+ if (JSVAL_IS_STRING(argv[0])) {
+ conversion_result=jsval_to_utf8string(cx, argv[0], username, NAMESIZE+1);
+ if( conversion_result < 0) {
+ printf("Error: javascript ipc(): major argument conversion error\n");
+ return JS_FALSE;
+ }
+ }
+
+
+ conversion_result=jsval_to_utf8string(cx, argv[1], msg, MAXTEXTLENGTH-100);
+ if( conversion_result < 0) {
+ printf("Error: javascript ipc(): major argument conversion error\n");
+ return JS_FALSE;
+ }
+ // not broadcast and no username
+ if(broadcast==0 && username[0]=='\0') {
+ printf("Error: javascript ipc(): expects a username or K_BROADCAST\n");
+
+ return JS_FALSE;
+ }
+
+ sendipc(username, msg, broadcast);
+ return JS_TRUE;
+}
+
+/* ask a user for extra input */
+static JSBool js_input(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSString *the_jsstring, *jsstr;
+ size_t ucs2_length, prompt_length, line_length;
+ jschar *ucs2_string;
+ int conv_error;
+
+ char *prompt=NULL, *line;
+
+ if(argc > 0) {
+ if(JSVAL_IS_STRING(argv[0])) {
+ // convert prompt to local
+ the_jsstring = JS_ValueToString(cx, argv[0]);
+ ucs2_length=JS_GetStringLength(the_jsstring);
+ ucs2_string=JS_GetStringChars(the_jsstring);
+ prompt_length=sizeof(char)*((ucs2_length*3)+1); // bit ugly
+ prompt=malloc(prompt_length);
+ if(prompt!=NULL) {
+ conv_error=convert_string_charset((char *)ucs2_string, "UCS-2", ucs2_length*sizeof(jschar), prompt, "LOCAL//TRANSLIT", prompt_length, NULL, NULL, NULL, NULL, NULL);
+ if(conv_error<0) {
+ fprintf(stderr, "js_input: convert_string_charset failed with error: %d\n", conv_error);
+ free(prompt);
+ prompt=NULL;
+ }
+ }
+ } else {
+ printf("Warning: when a parameter is specified to javascript input() command it should be a string to use as the prompt\n");
+ }
+ }
+ if( prompt == NULL )
+ {
+ prompt=strdup("? ");
+ }
+
+ busy++;
+ if ((line=readline(prompt))==NULL) line=strdup("");
+ busy--;
+
+ free(prompt);
+
+ line_length = sizeof(jschar) * (strlen(line) + 1);
+
+ ucs2_string = malloc( line_length );
+ if(ucs2_string!=NULL) {
+
+ conv_error=convert_string_charset(line, "LOCAL", strlen(line),
+ (char *)ucs2_string, "UCS-2//TRANSLIT", line_length,
+ NULL, NULL, NULL, NULL, NULL);
+ if(conv_error>=0) {
+ jsstr = JS_NewUCStringCopyZ(cx, ucs2_string);
+ } else {
+ jsstr = JS_NewStringCopyZ(cx, "(garbled string)");
+ }
+
+ free(ucs2_string);
+ } else {
+ jsstr = JS_NewStringCopyZ(cx, "(garbled string)");
+ }
+ *rval=STRING_TO_JSVAL(jsstr);
+
+ return JS_TRUE;
+}
+
+
+/* beep */
+static JSBool js_beep(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval)
+{
+ int i, beeps=0;
+ if(argc < 1) {
+ beeps=1;
+ }
+ else if(JSVAL_IS_INT(argv[0])) {
+ beeps=JSVAL_TO_INT(argv[0]);
+ if(beeps < 1 || beeps > 5) {
+ beeps=0;
+ printf("Warning: javascript beep will only do between 1 and 5 beeps.\n");
+ }
+ } else {
+ printf("Warning: javascript beep command expects an integer.\n");
+ }
+ for(i=0;i<beeps;i++)
+ {
+ write(1,"\7",1);
+ }
+
+ return JS_TRUE;
+}
+
+/* bind something to a javascript function */
+static JSBool js_bind(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval __attribute__((unused)) *rval)
+{
+ char bind[MAXTEXTLENGTH]="";
+ char function_name[MAXTEXTLENGTH]="";
+ int conversion_result;
+ int bind_type=-1;
+ int i=1;
+ if (argc < 2) {
+ printf("Error in javascript: bind expects 2 arguments\n");
+ return JS_TRUE;
+ }
+
+ if (JSVAL_IS_STRING(argv[0])) {
+ conversion_result=jsval_to_utf8string(cx, argv[0], bind, MAXTEXTLENGTH-100);
+ if( conversion_result != 0) {
+ printf("Error in string conversion binding javascript\n");
+ return JS_TRUE;
+
+ }
+ bind_type=K_BIND;
+ } else if (JSVAL_IS_INT(argv[0])) {
+ bind_type=JSVAL_TO_INT(argv[0]);
+ if(bind_type == K_BIND || bind_type == K_BIND_ALIAS || bind_type == K_BIND_RPC) {
+ i++;
+ conversion_result=jsval_to_utf8string(cx, argv[1], bind, MAXTEXTLENGTH-100);
+ if( conversion_result != 0) {
+ printf("Error in string conversion binding javascript\n");
+ return JS_TRUE;
+ }
+ }
+ } else {
+ printf("Error in javascript: bind expects first argument to be a string or a recognised bind id\n");
+ return JS_TRUE;
+ }
+ if (argc>= i-1 && JSVAL_IS_STRING(argv[i])) {
+ conversion_result=jsval_to_utf8string(cx, argv[i], function_name, MAXTEXTLENGTH-100);
+ if( conversion_result != 0) {
+ printf("Error in string conversion binding javascript\n");
+ return JS_TRUE;
+
+ }
+ } else {
+ printf("Error in javascript: bind expects final argument to be a string.\n");
+ return JS_TRUE;
+ }
+
+ switch(bind_type) {
+ case K_BIND:
+ if(bind[0]=='\0') {
+ printf("Error: Empty bind\n");
+ return JS_TRUE;
+ }
+ if (AddLink(&bind_list, bind, function_name))
+ {
+ printf("Bind %s already exists. Redefined\n", bind);
+ }
+
+ break;
+ case K_BIND_ALIAS:
+ if(bind[0]=='\0') {
+ printf("Error: Empty bind\n");
+ return JS_TRUE;
+ }
+ if (AddLink(&alias_list, bind, function_name))
+ {
+ printf("Alias %s->%s already exists. Redefined\n", bind, function_name);
+ }
+
+ break;
+ case K_BIND_RPC:
+ if(bind[0]=='\0') {
+ printf("Error: Empty bind\n");
+ return JS_TRUE;
+ }
+ if (AddLink(&rpc_list, bind, function_name))
+ {
+ printf("RPC %s Bind %s already exists. Redefined\n", bind, function_name);
+ }
+
+ break;
+ case K_BIND_EVENT:
+ if(AddLink(&event_list, function_name, ""))
+ {
+ printf("Event bind %s already exists.\n", function_name);
+ }
+ break;
+ case K_BIND_ONOFF:
+ if(AddLink(&onoff_list, function_name, ""))
+ {
+ printf("CheckOnOff bind %s already exists.\n", function_name);
+ }
+ break;
+ case K_BIND_IPC:
+ if(AddLink(&ipc_list, function_name, ""))
+ {
+ printf("IPC bind %s already exists.\n", function_name);
+ }
+ break;
+ case K_BIND_FORCE:
+ if(AddLink(&force_list, function_name, ""))
+ {
+ printf("Force bind %s already exists.\n", function_name);
+ }
+ break;
+ case K_BIND_SHUTDOWN:
+ if(AddLink(&shutdown_list, function_name, ""))
+ {
+ printf("Shutdown bind %s already exists.\n", function_name);
+ }
+
+ break;
+ default:
+ printf("Unknown bind type %d\n", bind_type);
+ break;
+ }
+ return JS_TRUE;
+}
+
+// return the users terminal dimensions
+static JSBool js_termsize(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval)
+{
+ JSObject *result_object;
+ jsval jv;
+ int width, height;
+
+ result_object=JS_NewObject(cx, &js_termsizeclass, NULL, NULL);
+ if(result_object==NULL)
+ {
+ return JS_FALSE;
+ }
+ jv=OBJECT_TO_JSVAL(result_object);
+
+ width=screen_w();
+ height=screen_h();
+
+ JS_DefineProperty(cx, result_object, "width", INT_TO_JSVAL(width), NULL, NULL, 0);
+ JS_DefineProperty(cx, result_object, "height", INT_TO_JSVAL(height), NULL, NULL, 0);
+
+
+ *rval=jv;
+ return JS_TRUE;
+}
+
// Provides a javascript function to query the wholist
static JSBool js_wholist(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval) {
struct person u;
@@ -179,44 +531,43 @@
JS_AddRoot(cx, res);
while (read(wfile,&w,sizeof(w))) {
- JSObject *line;
+ JSObject *user_record;
JSString *jsstr;
- jsval jv;
- int rown=0;
+ jsval jv, user_jv;
if (w.posn < 0) continue;
lseek(ufile,w.posn,SEEK_SET);
read(ufile,&u,sizeof(u));
/* make a new row and populate it */
- line = JS_NewArrayObject(cx, 0, NULL);
+ user_record = JS_NewObject(cx, &js_userrecordclass, NULL, NULL);
+ user_jv = OBJECT_TO_JSVAL(user_record);
/* user name */
jsstr = JS_NewStringCopyZ(cx, u.name);
jv = STRING_TO_JSVAL(jsstr);
- JS_SetElement(cx, line, rown++, &jv);
+ JS_DefineProperty(cx, user_record, "username", jv, NULL, NULL, 0);
/* room number */
jv = INT_TO_JSVAL(u.room);
- JS_SetElement(cx, line, rown++, &jv);
+ JS_DefineProperty(cx, user_record, "room", jv, NULL, NULL, 0);
/* idle time */
jv = INT_TO_JSVAL(time(0)-u.idletime);
- JS_SetElement(cx, line, rown++, &jv);
+ JS_DefineProperty(cx, user_record, "idle", jv, NULL, NULL, 0);
/* chat modes */
jsstr = JS_NewStringCopyZ(cx, display_cmflags(u.chatmode));
jv = STRING_TO_JSVAL(jsstr);
- JS_SetElement(cx, line, rown++, &jv);
+ JS_DefineProperty(cx, user_record, "chatmodes", jv, NULL, NULL, 0);
/* protection level */
jv = INT_TO_JSVAL((u.chatmode & CM_PROTMASK) >> CM_PROTSHIFT);
- JS_SetElement(cx, line, rown++, &jv);
+ JS_DefineProperty(cx, user_record, "protection_level", jv, NULL, NULL, 0);
jv = INT_TO_JSVAL((u.chatprivs & CP_PROTMASK) >> CP_PROTSHIFT);
- JS_SetElement(cx, line, rown++, &jv);
+ JS_DefineProperty(cx, user_record, "protection_power", jv, NULL, NULL, 0);
/* chat privs */
jsstr = JS_NewStringCopyZ(cx, display_cpflags(u.chatprivs & user->chatprivs));
jv = STRING_TO_JSVAL(jsstr);
- JS_SetElement(cx, line, rown++, &jv);
+ JS_DefineProperty(cx, user_record, "chatprivs", jv, NULL, NULL, 0);
/* stick line into master array */
- jv = OBJECT_TO_JSVAL(line);
- JS_SetElement(cx, res, n++, &jv);
+ JS_SetElement(cx, res, n++, &user_jv);
}
close(wfile);
close(ufile);
@@ -292,7 +643,7 @@
// printf("dbresult_to_jsarray: node @ %p\n", (void *)node);
jsnode = dbdata_to_jsarray(cx, node, data->cols);
jv = OBJECT_TO_JSVAL(jsnode);
- JS_SetElement(cx, jsarray, i, &jv);
+ JS_SetElement(cx, jsarray, data->rows-1-i, &jv);
node = node->next;
i++;
@@ -302,22 +653,103 @@
return jsarray;
}
+// create a javascript array of column names from a db_result
+JSObject *dbresult_to_jscolnames(JSContext *cx, struct db_result *data) {
+ JSObject *jsarray;
+// JSObject *jsnode;
+ jsval jv;
+// struct db_data *node;
+ jschar *ucsstr;
+ int i, conv_error;
+ size_t data_length;
+ JSString *jsstr;
+ if (data == NULL) return NULL;
+ jsarray = JS_NewArrayObject(cx, 0, NULL);
+ JS_AddRoot(cx, jsarray);
+
+ for(i=0;i<data->cols;i++) {
+ data_length = sizeof(jschar) * (strlen(data->colNames[i]) + 1);
+
+ ucsstr = malloc( data_length );
+ if(ucsstr!=NULL) {
+
+ conv_error=convert_string_charset(data->colNames[i], "UTF-8", strlen(data->colNames[i]),
+ (char *)ucsstr, "UCS-2", data_length,
+ NULL, NULL, NULL, NULL, NULL);
+ if(conv_error>=0) {
+ jsstr = JS_NewUCStringCopyZ(cx, ucsstr);
+ } else {
+ jsstr = JS_NewStringCopyZ(cx, "(garbled string)");
+ }
+ free(ucsstr);
+ } else {
+ jsstr = JS_NewStringCopyZ(cx, "(garbled string)");
+ }
+ jv = STRING_TO_JSVAL(jsstr);
+ JS_SetElement(cx, jsarray, i, &jv);
+
+ }
+
+ JS_RemoveRoot(cx, jsarray);
+
+ return jsarray;
+}
+
+// creates a javascript db object from a struct js_db_result
+// on success it return JS_TRUE and the pointer db_object points to the jsval of the new object
+// on fail returns JS_FALSE
+JSBool dbresult_to_jsdbobject(JSContext *cx, struct js_db_result *data, jsval *db_object)
+{
+ JSObject *result_object;
+ JSObject *jsarray, *jscolumns;
+ jsval jsarray_val, jscolumns_val;
+
+ result_object=JS_NewObject(cx, &js_dbresultclass, NULL, NULL);
+ if(result_object==NULL) {
+ return JS_FALSE;
+ }
+ *db_object=OBJECT_TO_JSVAL(result_object);
+
+ JS_DefineProperty(cx, result_object, "db_error", INT_TO_JSVAL(data->db_error), NULL, NULL, JSPROP_READONLY);
+ JS_DefineProperty(cx, result_object, "query_error", INT_TO_JSVAL(data->query_error), NULL, NULL, JSPROP_READONLY);
+ if(data->error_text!=NULL) {
+
+ JS_DefineProperty(cx, result_object, "error_text", STRING_TO_JSVAL(JS_NewStringCopyZ(cx, data->error_text)), NULL, NULL, JSPROP_READONLY);
+ } else {
+ JS_DefineProperty(cx, result_object, "error_text", STRING_TO_JSVAL(JS_NewStringCopyZ(cx, "No Error")), NULL, NULL, JSPROP_READONLY);
+ }
+ if(data->query_result!=NULL) {
+ jsarray=dbresult_to_jsarray(cx, data->query_result);
+ jsarray_val=OBJECT_TO_JSVAL(jsarray);
+ JS_DefineProperty(cx, result_object, "data", jsarray_val, NULL, NULL, 0);
+ jscolumns=dbresult_to_jscolnames(cx, data->query_result);
+ jscolumns_val=OBJECT_TO_JSVAL(jscolumns);
+ JS_DefineProperty(cx, result_object, "column_names", jscolumns_val, NULL, NULL, 0);
+
+ } else {
+ JS_DefineProperty(cx, result_object, "data", JSVAL_NULL, NULL, NULL, 0);
+ JS_DefineProperty(cx, result_object, "column_names", JSVAL_NULL, NULL, NULL, 0);
+ }
+ return JS_TRUE;
+}
+
// Provides a javascript function to query an sqlite3 database
// This probably wants updating to not return JS_FALSE as that halts js execution
// far better to return an error code in rsval which the javascript can handle
static JSBool js_doquery(JSContext *cx, JSObject __attribute__((unused)) *obj, uintN argc, jsval *argv, jsval *rval) {
- struct db_result *dbres;
+ struct js_db_result *dbres;
char *dbname;
char query[MAXTEXTLENGTH*2]; // for now queries will be at most 4096 bytes or will fail.
// if this becomes a problem dynamic allocation of the utf8 buffer might be needed although getting the right size is a pita
//JSObject *result; // result object were creating
- JSObject *resarray;
+ jsval resobject_jsval;
int myid, conversion_result;
char path[1024];
struct passwd *pw;
-
+ JSBool retval;
+
if ((pw=getpwuid(getuid()))==NULL) {
fprintf(stderr, "Error getting user information\n");
return JS_FALSE;
@@ -353,35 +785,21 @@
myid=geteuid();
seteuid(getuid());
- dbres = db_query(path, query);
+ dbres = js_db_query(path, query);
seteuid(myid);
if (!dbres) {
+ printf("Major error in javascript database query.\n");
return JS_FALSE;
}
- if (0 == dbres->rows) {
- // No results found (not an error)
- return JS_TRUE;
- }
-
- resarray = dbresult_to_jsarray(cx, dbres);
- if (!resarray) {
- return JS_FALSE;
- }
-/* result = JS_NewObject(cx, &js_dbresultclass, NULL, NULL);
- // seems pointless to create an object with a data array and a numrows when the array itself has a .length.
- // also something here was making mw segv so it's being done wrong.
- // so now we just return the array.
+ retval = dbresult_to_jsdbobject(cx, dbres, &resobject_jsval);
- JS_DefineProperty(cx, result, "numrows", INT_TO_JSVAL(dbres->rows), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT);
- JS_DefineProperty(cx, result, "data", OBJECT_TO_JSVAL(resarray), NULL, NULL, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE);
-
- //JS_SetPrivate(cx, result, dbres);
-*/
- db_free(dbres);
- *rval = OBJECT_TO_JSVAL(resarray);
- return JS_TRUE;
+
+ js_db_free(dbres);
+
+ *rval = resobject_jsval;
+ return retval;
}
/* prints the type of a jsval */
@@ -427,7 +845,7 @@
fprintf(stderr, "js_exec: argc %d was NULL!\n",i);
continue;
}
- //ucarg=utf8_to_jsstring(argvc[i], &uclen, &utferror);
+ // convert the arguments from utf8 to ucs2 for the javascript engine.
utferror=convert_string_charset(argvc[i], "UTF-8", strlen(argvc[i]), (char *)unicode_arg, "UCS-2", sizeof(jschar) * MAXTEXTLENGTH, NULL, NULL, NULL, NULL, "?");
if(utferror>=0) {
if(utferror & WOUTPUTTOOSHORT) {
@@ -471,6 +889,7 @@
if (er->linebuf != NULL) {
len = er->tokenptr - er->linebuf + 1;
+ if(len<2) len=2;
pointer = malloc(len); memset(pointer,
'-', len); pointer[len-1]='\0';
pointer[len-2]='^';
@@ -551,6 +970,8 @@
printf("The script '%s' does not appear to be utf-8. Some characters may have been discared. Please ensure this file is saved as UTF-8\n", filename);
}
+ // length is currently the number of bytes iconv used (including the null char it created)
+ // thus the number of actual chars in the string required is:
length=(length/sizeof(jschar))-1;
/* Compile the js file specified */
/* script = JS_CompileScript(jscx, jsroot, body, len, filename, lineno); */
@@ -570,7 +991,10 @@
printf("Failed to execute js script: %s\n", filename);
return 0;
}
-
+
+ // now the script has been run we can destroy it (the context retains the functions/objects it created)
+
+ JS_DestroyScript(jscx, script);
return 1;
}
@@ -593,6 +1017,16 @@
return 0;
}
+// cleans up the javascript environment
+int stop_js(void)
+{
+ JS_DestroyContext(jscx);
+ JS_DestroyRuntime(jsrt);
+ return 0;
+
+}
+
+// starts the javascript engine.
int setup_js(void)
{
JSBool builtins;
@@ -633,19 +1067,38 @@
JS_DefineFunction(jscx, jsroot, "exec", js_mwexec, 1, 0);
JS_DefineFunction(jscx, jsroot, "say", js_say, 1, 0);
JS_DefineFunction(jscx, jsroot, "wholist", js_wholist, 0, 1);
-
+ JS_DefineFunction(jscx, jsroot, "rpc", js_rpc, 3, 0);
+ JS_DefineFunction(jscx, jsroot, "ipc", js_ipc, 2, 0);
+
JS_DefineProperty(jscx, jsroot, "whoami", STRING_TO_JSVAL(JS_NewStringCopyZ(jscx,user->name)), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+ JS_DefineFunction(jscx, jsroot, "beep", js_beep, 1, 0);
+ JS_DefineFunction(jscx, jsroot, "input", js_input, 2, 0);
+ JS_DefineFunction(jscx, jsroot, "termsize", js_termsize, 0, 0);
+
+ JS_DefineFunction(jscx, jsroot, "bind", js_bind, 2, 0);
+
+ // Set the bind type constants
+ JS_DefineProperty(jscx, jsroot, "K_BIND_EVENT", INT_TO_JSVAL(K_BIND_EVENT), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+ JS_DefineProperty(jscx, jsroot, "K_BIND_IPC", INT_TO_JSVAL(K_BIND_IPC), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+ JS_DefineProperty(jscx, jsroot, "K_BIND_ONOFF", INT_TO_JSVAL(K_BIND_ONOFF), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+ JS_DefineProperty(jscx, jsroot, "K_BIND_FORCE", INT_TO_JSVAL(K_BIND_FORCE), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+ JS_DefineProperty(jscx, jsroot, "K_BIND_SHUTDOWN", INT_TO_JSVAL(K_BIND_SHUTDOWN), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+ JS_DefineProperty(jscx, jsroot, "K_BIND_RPC", INT_TO_JSVAL(K_BIND_RPC), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+ JS_DefineProperty(jscx, jsroot, "K_BIND_ALIAS", INT_TO_JSVAL(K_BIND_ALIAS), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+
+ // Broadcast constant (for ipc,rpc)
+ JS_DefineProperty(jscx, jsroot, "K_BROADCAST", INT_TO_JSVAL(K_BROADCAST), NULL, NULL, JSPROP_READONLY|JSPROP_PERMANENT);
+
+
/* not for bbs user */
if (is_local) {
JS_DefineFunction(jscx, jsroot, "dbquery", js_doquery, 2, 1);
}
/* need additional functions :
- * - one to bind functions to events (bind?) - yes, saves needing two files per javascript. code written outside of a function is executed when the script loads
* - one to load another script (include?) - possibly although most scripts are loaded from the .mwrc or using .load
* - get system date/time - no, 'new Date()' will get this information for you in a Date object.
- * - input line of text (does anyone use this) - yes, it's nice to be able to prompt the user for extra information. I specifically use it in my batchdo mwscript that allows me to specify a set of commands to do at once.
*/
return 0;
Modified: trunk/src/js.h
===================================================================
--- trunk/src/js.h 2007-05-11 17:42:08 UTC (rev 962)
+++ trunk/src/js.h 2007-05-21 09:22:26 UTC (rev 963)
@@ -3,4 +3,5 @@
int load_jsfile(FILE *f, char *filename);
int load_js(char *filename);
int is_js(char *name);
+int stop_js(void);
int setup_js(void);
Modified: trunk/src/main.c
===================================================================
--- trunk/src/main.c 2007-05-11 17:42:08 UTC (rev 962)
+++ trunk/src/main.c 2007-05-21 09:22:26 UTC (rev 963)
@@ -965,6 +965,7 @@
RoomDestroy(&myroom);
DestroyDirections();
ClearStack();
+ stop_js();
alarm_cleanup();
/* dont display logoff text if quiet, or if dropped */
@@ -974,7 +975,7 @@
}
mwlog("LOGOUT");
-
+ sleep(1); //dodgy hack for race condition in checkonoff, cunningly we currently get woken by the very message we're waiting for.
who_delete(getpid());
#ifdef RWHO
rwhocli_userlogout(user->name);
Modified: trunk/src/sqlite.c
===================================================================
--- trunk/src/sqlite.c 2007-05-11 17:42:08 UTC (rev 962)
+++ trunk/src/sqlite.c 2007-05-21 09:22:26 UTC (rev 963)
@@ -99,6 +99,55 @@
return new;
}
+struct js_db_result* js_db_query(char *dbname, char *query)
+{
+ struct js_db_result *new;
+
+ sqlite3 *db;
+// printf("sizeof js_db_result:%d\n", (int)sizeof(struct js_db_result));
+ new = malloc(sizeof(struct js_db_result));
+
+ if(new == NULL) {
+ return NULL;
+ }
+
+ new->error_text=NULL;
+ new->query_error=0;
+ new->db_error=0;
+
+
+ if (dbname == NULL) {
+ new->error_text=strdup("Database name was NULL");
+ new->db_error=-1;
+ return new;
+ }
+
+
+ db = db_open(dbname);
+ if (!db) {
+ new->error_text=strdup("Failed to open database");
+ new->db_error=-2;
+ return new;
+ }
+
+ new->query_result = malloc(sizeof(struct db_result));
+ if(new->query_result == NULL) {
+ new->error_text=strdup("malloc error for query result");
+ new->db_error=-3;
+ }
+
+ new->query_result->rows = -1;
+ new->query_result->cols = -1;
+ new->query_result->colNames = NULL;
+ new->query_result->data = NULL;
+
+ new->query_error = sqlite3_exec(db, query, db_callback, new->query_result, &new->error_text);
+
+ db_close(db);
+ return new;
+}
+
+
/* how many rows in that result */
int db_numrows(struct db_result *result)
{
@@ -170,3 +219,13 @@
free(result);
}
+void js_db_free(struct js_db_result *result)
+{
+ if(result->query_result!=NULL) {
+ db_free(result->query_result);
+ }
+ if(result->error_text!=NULL) {
+ sqlite3_free(result->error_text);
+ }
+ free(result);
+}
Modified: trunk/src/sqlite.h
===================================================================
--- trunk/src/sqlite.h 2007-05-11 17:42:08 UTC (rev 962)
+++ trunk/src/sqlite.h 2007-05-21 09:22:26 UTC (rev 963)
@@ -13,6 +13,15 @@
struct db_data *data;
};
+struct js_db_result {
+ struct db_result *query_result;
+ int db_error;
+ int query_error;
+ char *error_text;
+};
+
struct db_result *db_query(char *dbname, char *query);
+struct js_db_result* js_db_query(char *dbname, char *query);
void db_getrow(struct db_result *result, int *row);
void db_free(struct db_result *result);
+void js_db_free(struct js_db_result *result);
More information about the mw-devel
mailing list