/* Synchronet "uifc" (user interface) 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. * ****************************************************************************/ #ifndef JAVASCRIPT #define JAVASCRIPT #endif #include "sbbs.h" #include "uifc.h" #include "ciolib.h" #include "js_request.h" struct list_ctx_private { int cur; int bar; int left; int top; int width; }; struct showbuf_ctx_private { int cur; int bar; int left; int top; int width; int height; }; struct getstrxy_ctx_private { int lastkey; }; enum { PROP_CUR , PROP_BAR , PROP_LEFT , PROP_TOP , PROP_WIDTH , PROP_HEIGHT , PROP_LASTKEY }; static JSBool js_list_ctx_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { jsval idval; jsint tiny; struct list_ctx_private* p; if ((p = (struct list_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); switch (tiny) { case PROP_CUR: *vp = INT_TO_JSVAL(p->cur); break; case PROP_BAR: *vp = INT_TO_JSVAL(p->bar); break; case PROP_LEFT: *vp = INT_TO_JSVAL(p->left); break; case PROP_TOP: *vp = INT_TO_JSVAL(p->top); break; case PROP_WIDTH: *vp = INT_TO_JSVAL(p->width); break; } return JS_TRUE; } static JSBool js_list_ctx_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { jsval idval; jsint tiny; int32 i = 0; struct list_ctx_private* p; if ((p = (struct list_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); if (!JS_ValueToInt32(cx, *vp, &i)) return JS_FALSE; switch (tiny) { case PROP_CUR: p->cur = i; break; case PROP_BAR: p->bar = i; break; case PROP_LEFT: p->left = i; break; case PROP_TOP: p->top = i; break; case PROP_WIDTH: p->width = i; break; } return JS_TRUE; } static JSBool js_showbuf_ctx_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { jsval idval; jsint tiny; struct showbuf_ctx_private* p; if ((p = (struct showbuf_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); switch (tiny) { case PROP_CUR: *vp = INT_TO_JSVAL(p->cur); break; case PROP_BAR: *vp = INT_TO_JSVAL(p->bar); break; case PROP_LEFT: *vp = INT_TO_JSVAL(p->left); break; case PROP_TOP: *vp = INT_TO_JSVAL(p->top); break; case PROP_WIDTH: *vp = INT_TO_JSVAL(p->width); break; case PROP_HEIGHT: *vp = INT_TO_JSVAL(p->height); break; } return JS_TRUE; } static JSBool js_showbuf_ctx_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { jsval idval; jsint tiny; int32 i = 0; struct showbuf_ctx_private* p; if ((p = (struct showbuf_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); if (!JS_ValueToInt32(cx, *vp, &i)) return JS_FALSE; switch (tiny) { case PROP_CUR: p->cur = i; break; case PROP_BAR: p->bar = i; break; case PROP_LEFT: p->left = i; break; case PROP_TOP: p->top = i; break; case PROP_WIDTH: p->width = i; break; case PROP_HEIGHT: p->height = i; break; } return JS_TRUE; } static JSBool js_getstrxy_ctx_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { jsval idval; jsint tiny; struct getstrxy_ctx_private* p; if ((p = (struct getstrxy_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); switch (tiny) { case PROP_LASTKEY: *vp = INT_TO_JSVAL(p->lastkey); break; } return JS_TRUE; } static JSBool js_getstrxy_ctx_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { jsval idval; jsint tiny; int32 i = 0; struct getstrxy_ctx_private* p; if ((p = (struct getstrxy_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); if (!JS_ValueToInt32(cx, *vp, &i)) return JS_FALSE; switch (tiny) { case PROP_LASTKEY: p->lastkey = i; break; } return JS_TRUE; } #ifdef BUILD_JSDOCS static const char* uifc_list_ctx_prop_desc[] = { "Currently selected item" , "0-based Line number in the currently displayed set that is highlighted" , "left column" , "top line" , "forced width" , NULL }; static const char* uifc_showbuf_ctx_prop_desc[] = { "Currently selected item" , "0-based Line number in the currently displayed set that is highlighted" , "left column" , "top line" , "forced width" , "forced height" , NULL }; static const char* uifc_getstrxy_ctx_prop_desc[] = { "Last pressed key" , NULL }; #endif /* Destructor */ static void js_list_ctx_finalize(JSContext *cx, JSObject *obj) { struct list_ctx_private* p; if ((p = (struct list_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return; free(p); JS_SetPrivate(cx, obj, NULL); } static void js_showbuf_ctx_finalize(JSContext *cx, JSObject *obj) { struct showbuf_ctx_private* p; if ((p = (struct showbuf_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return; free(p); JS_SetPrivate(cx, obj, NULL); } static void js_getstrxy_ctx_finalize(JSContext *cx, JSObject *obj) { struct getstrxy_ctx_private* p; if ((p = (struct getstrxy_ctx_private*)JS_GetPrivate(cx, obj)) == NULL) return; free(p); JS_SetPrivate(cx, obj, NULL); } static JSClass js_uifc_list_ctx_class = { "CTX" /* name */ , JSCLASS_HAS_PRIVATE /* flags */ , JS_PropertyStub /* addProperty */ , JS_PropertyStub /* delProperty */ , js_list_ctx_get /* getProperty */ , js_list_ctx_set /* setProperty */ , JS_EnumerateStub /* enumerate */ , JS_ResolveStub /* resolve */ , JS_ConvertStub /* convert */ , js_list_ctx_finalize /* finalize */ }; static JSClass js_uifc_showbuf_ctx_class = { "CTX" /* name */ , JSCLASS_HAS_PRIVATE /* flags */ , JS_PropertyStub /* addProperty */ , JS_PropertyStub /* delProperty */ , js_showbuf_ctx_get /* getProperty */ , js_showbuf_ctx_set /* setProperty */ , JS_EnumerateStub /* enumerate */ , JS_ResolveStub /* resolve */ , JS_ConvertStub /* convert */ , js_showbuf_ctx_finalize /* finalize */ }; static JSClass js_uifc_getstrxy_ctx_class = { "CTX" /* name */ , JSCLASS_HAS_PRIVATE /* flags */ , JS_PropertyStub /* addProperty */ , JS_PropertyStub /* delProperty */ , js_getstrxy_ctx_get /* getProperty */ , js_getstrxy_ctx_set /* setProperty */ , JS_EnumerateStub /* enumerate */ , JS_ResolveStub /* resolve */ , JS_ConvertStub /* convert */ , js_getstrxy_ctx_finalize /* finalize */ }; static jsSyncPropertySpec js_uifc_list_class_properties[] = { /* name ,tinyid ,flags, ver */ { "cur", PROP_CUR, JSPROP_ENUMERATE, 317 }, { "bar", PROP_BAR, JSPROP_ENUMERATE, 317 }, { "left", PROP_LEFT, JSPROP_ENUMERATE, 31802 }, { "top", PROP_TOP, JSPROP_ENUMERATE, 31802 }, { "width", PROP_WIDTH, JSPROP_ENUMERATE, 31802 }, {0} }; static jsSyncPropertySpec js_uifc_showbuf_class_properties[] = { /* name ,tinyid ,flags, ver */ { "cur", PROP_CUR, JSPROP_ENUMERATE, 31802 }, { "bar", PROP_BAR, JSPROP_ENUMERATE, 31802 }, { "left", PROP_LEFT, JSPROP_ENUMERATE, 31802 }, { "top", PROP_TOP, JSPROP_ENUMERATE, 31802 }, { "width", PROP_WIDTH, JSPROP_ENUMERATE, 31802 }, { "height", PROP_HEIGHT, JSPROP_ENUMERATE, 31802 }, {0} }; static jsSyncPropertySpec js_uifc_getstrxy_class_properties[] = { /* name ,tinyid ,flags, ver */ { "lastkey", PROP_LASTKEY, JSPROP_ENUMERATE, 31802 }, {0} }; /* Constructor */ static JSBool js_list_ctx_constructor(JSContext *cx, uintN argc, jsval *arglist) { jsval * argv = JS_ARGV(cx, arglist); JSObject * obj = JS_THIS_OBJECT(cx, arglist); struct list_ctx_private* p; obj = JS_NewObject(cx, &js_uifc_list_ctx_class, NULL, NULL); JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj)); if ((p = (struct list_ctx_private *)calloc(1, sizeof(struct list_ctx_private))) == NULL) { JS_ReportError(cx, "calloc failed"); return JS_FALSE; } if (!JS_SetPrivate(cx, obj, p)) { JS_ReportError(cx, "JS_SetPrivate failed"); return JS_FALSE; } p->bar = INT_MAX; if (argc > 0 && JSVAL_IS_NUMBER(argv[0])) p->cur = JSVAL_TO_INT(argv[0]); if (argc > 1 && JSVAL_IS_NUMBER(argv[1])) p->bar = JSVAL_TO_INT(argv[1]); if (argc > 2 && JSVAL_IS_NUMBER(argv[2])) p->left = JSVAL_TO_INT(argv[2]); if (argc > 3 && JSVAL_IS_NUMBER(argv[3])) p->top = JSVAL_TO_INT(argv[3]); if (argc > 4 && JSVAL_IS_NUMBER(argv[4])) p->width = JSVAL_TO_INT(argv[4]); js_SyncResolve(cx, obj, NULL, js_uifc_list_class_properties, NULL, NULL, 0); #ifdef BUILD_JSDOCS js_DescribeSyncObject(cx, obj, "Class used to retain UIFC list menu context", 317); js_DescribeSyncConstructor(cx, obj, "To create a new UIFCListContext object: <tt>var ctx = new UIFCListContext();</tt>"); js_CreateArrayOfStrings(cx, obj, "_property_desc_list", uifc_list_ctx_prop_desc, JSPROP_READONLY); #endif return JS_TRUE; } static JSBool js_showbuf_ctx_constructor(JSContext *cx, uintN argc, jsval *arglist) { jsval * argv = JS_ARGV(cx, arglist); JSObject * obj = JS_THIS_OBJECT(cx, arglist); struct showbuf_ctx_private* p; obj = JS_NewObject(cx, &js_uifc_showbuf_ctx_class, NULL, NULL); JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj)); if ((p = (struct showbuf_ctx_private *)calloc(1, sizeof(struct showbuf_ctx_private))) == NULL) { JS_ReportError(cx, "calloc failed"); return JS_FALSE; } p->height = INT_MAX; p->width = INT_MAX; if (argc > 0 && JSVAL_IS_NUMBER(argv[0])) p->cur = JSVAL_TO_INT(argv[0]); if (argc > 1 && JSVAL_IS_NUMBER(argv[1])) p->bar = JSVAL_TO_INT(argv[1]); if (argc > 2 && JSVAL_IS_NUMBER(argv[2])) p->left = JSVAL_TO_INT(argv[2]); if (argc > 3 && JSVAL_IS_NUMBER(argv[3])) p->top = JSVAL_TO_INT(argv[3]); if (argc > 4 && JSVAL_IS_NUMBER(argv[4])) p->width = JSVAL_TO_INT(argv[4]); if (argc > 5 && JSVAL_IS_NUMBER(argv[5])) p->height = JSVAL_TO_INT(argv[5]); if (!JS_SetPrivate(cx, obj, p)) { JS_ReportError(cx, "JS_SetPrivate failed"); return JS_FALSE; } js_SyncResolve(cx, obj, NULL, js_uifc_showbuf_class_properties, NULL, NULL, 0); #ifdef BUILD_JSDOCS js_DescribeSyncObject(cx, obj, "Class used to retain UIFC showbuf context", 317); js_DescribeSyncConstructor(cx, obj, "To create a new UIFCShowbufContext object: <tt>var ctx = new UIFCShowbufContext();</tt>"); js_CreateArrayOfStrings(cx, obj, "_property_desc_list", uifc_showbuf_ctx_prop_desc, JSPROP_READONLY); #endif return JS_TRUE; } static JSBool js_getstrxy_ctx_constructor(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); struct getstrxy_ctx_private* p; obj = JS_NewObject(cx, &js_uifc_getstrxy_ctx_class, NULL, NULL); JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(obj)); if ((p = (struct getstrxy_ctx_private *)calloc(1, sizeof(struct getstrxy_ctx_private))) == NULL) { JS_ReportError(cx, "calloc failed"); return JS_FALSE; } if (!JS_SetPrivate(cx, obj, p)) { JS_ReportError(cx, "JS_SetPrivate failed"); return JS_FALSE; } js_SyncResolve(cx, obj, NULL, js_uifc_getstrxy_class_properties, NULL, NULL, 0); #ifdef BUILD_JSDOCS js_DescribeSyncObject(cx, obj, "Class used to retain UIFC getstrxy context", 317); js_DescribeSyncConstructor(cx, obj, "To create a new UIFCGetStrXYContext object: <tt>var ctx = new UIFCGetStrXYContext();</tt>"); js_CreateArrayOfStrings(cx, obj, "_property_desc_list", uifc_getstrxy_ctx_prop_desc, JSPROP_READONLY); #endif return JS_TRUE; } /* Properties */ enum { PROP_INITIALIZED /* read-only */ , PROP_MODE , PROP_CHANGES , PROP_SAVNUM , PROP_SCRN_LEN , PROP_SCRN_WIDTH , PROP_ESC_DELAY , PROP_HELPBUF , PROP_HCOLOR , PROP_LCOLOR , PROP_BCOLOR , PROP_CCOLOR , PROP_LBCOLOR , PROP_LIST_HEIGHT }; static JSBool js_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) { jsval idval; jsint tiny; uifcapi_t* uifc; if ((uifc = (uifcapi_t*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); switch (tiny) { case PROP_INITIALIZED: *vp = BOOLEAN_TO_JSVAL(uifc->initialized); break; case PROP_MODE: *vp = UINT_TO_JSVAL(uifc->mode); break; case PROP_CHANGES: *vp = BOOLEAN_TO_JSVAL(uifc->changes); break; case PROP_SAVNUM: *vp = INT_TO_JSVAL(uifc->savnum); break; case PROP_SCRN_LEN: *vp = INT_TO_JSVAL(uifc->scrn_len); break; case PROP_SCRN_WIDTH: *vp = INT_TO_JSVAL(uifc->scrn_width); break; case PROP_ESC_DELAY: *vp = INT_TO_JSVAL(uifc->esc_delay); break; case PROP_HELPBUF: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, uifc->helpbuf)); break; case PROP_HCOLOR: *vp = INT_TO_JSVAL(uifc->hclr); break; case PROP_LCOLOR: *vp = INT_TO_JSVAL(uifc->lclr); break; case PROP_BCOLOR: *vp = INT_TO_JSVAL(uifc->bclr); break; case PROP_CCOLOR: *vp = INT_TO_JSVAL(uifc->cclr); break; case PROP_LBCOLOR: *vp = INT_TO_JSVAL(uifc->lbclr); break; case PROP_LIST_HEIGHT: *vp = INT_TO_JSVAL(uifc->list_height); break; } return(JS_TRUE); } static JSBool js_set(JSContext *cx, JSObject *obj, jsid id, JSBool strict, jsval *vp) { jsval idval; jsint tiny; int32 i = 0; uifcapi_t* uifc; if ((uifc = (uifcapi_t*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); JS_IdToValue(cx, id, &idval); tiny = JSVAL_TO_INT(idval); if (tiny == PROP_CHANGES) return JS_ValueToBoolean(cx, *vp, &uifc->changes); else if (tiny == PROP_HELPBUF) { if (uifc->helpbuf) free(uifc->helpbuf); JSVALUE_TO_MSTRING(cx, *vp, uifc->helpbuf, NULL); HANDLE_PENDING(cx, NULL); return JS_TRUE; } if (!JS_ValueToInt32(cx, *vp, &i)) return JS_FALSE; switch (tiny) { case PROP_MODE: uifc->mode = i; break; case PROP_SAVNUM: if (i == uifc->savnum - 1 && uifc->restore != NULL) uifc->restore(); else uifc->savnum = i; break; case PROP_SCRN_LEN: uifc->scrn_len = i; break; case PROP_SCRN_WIDTH: uifc->scrn_width = i; break; case PROP_ESC_DELAY: uifc->esc_delay = i; break; case PROP_LIST_HEIGHT: uifc->list_height = i; break; case PROP_HCOLOR: uifc->hclr = (char)i; break; case PROP_LCOLOR: uifc->lclr = (char)i; break; case PROP_BCOLOR: uifc->bclr = (char)i; break; case PROP_CCOLOR: uifc->cclr = (char)i; break; case PROP_LBCOLOR: uifc->lbclr = (char)i; break; } return(JS_TRUE); } static jsSyncPropertySpec js_properties[] = { /* name, tinyid, flags, ver */ { "initialized", PROP_INITIALIZED, JSPROP_ENUMERATE | JSPROP_READONLY, 314 }, { "mode", PROP_MODE, JSPROP_ENUMERATE, 314 }, { "changes", PROP_CHANGES, JSPROP_ENUMERATE, 314 }, { "save_num", PROP_SAVNUM, JSPROP_ENUMERATE, 314 }, { "screen_length", PROP_SCRN_LEN, JSPROP_ENUMERATE, 314 }, { "screen_width", PROP_SCRN_WIDTH, JSPROP_ENUMERATE, 314 }, { "list_height", PROP_LIST_HEIGHT, JSPROP_ENUMERATE, 314 }, { "esc_delay", PROP_ESC_DELAY, JSPROP_ENUMERATE, 314 }, { "help_text", PROP_HELPBUF, JSPROP_ENUMERATE, 314 }, { "background_color", PROP_BCOLOR, JSPROP_ENUMERATE, 314 }, { "frame_color", PROP_HCOLOR, JSPROP_ENUMERATE, 314 }, { "text_color", PROP_LCOLOR, JSPROP_ENUMERATE, 314 }, { "inverse_color", PROP_CCOLOR, JSPROP_ENUMERATE, 314 }, { "lightbar_color", PROP_LBCOLOR, JSPROP_ENUMERATE, 314 }, {0} }; #ifdef BUILD_JSDOCS static const char* uifc_prop_desc[] = { "UIFC library has been successfully initialized" , "Current mode flags (see <tt>uifcdefs.js</tt>)" , "A change has occurred in an input call. You are expected to set this to false before calling the input if you care about it." , "Save buffer depth (advanced)" , "Current screen length" , "Current screen width" , "When <tt>WIN_FIXEDHEIGHT</tt> mode flag is set, specifies the height used by a list method" , "Delay before a single ESC char is parsed and assumed to not be an ANSI sequence (advanced)" , "Text that will be displayed when F1 or '?' keys are pressed" , "Background colour" , "Frame colour" , "Text colour" , "Inverse colour" , "Lightbar colour" , NULL }; #endif /* Convenience functions */ static uifcapi_t* get_uifc(JSContext *cx, JSObject *obj) { uifcapi_t* uifc; if ((uifc = (uifcapi_t*)JS_GetPrivate(cx, obj)) == NULL) return(NULL); if (!uifc->initialized) { JS_ReportError(cx, "UIFC not initialized"); return(NULL); } return(uifc); } /* Methods */ static JSBool js_uifc_init(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); int ciolib_mode = CIOLIB_MODE_AUTO; const char* title_def = "Synchronet"; char* title = (char *)title_def; char* mode; uifcapi_t* uifc; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_FALSE); if ((uifc = (uifcapi_t*)JS_GetPrivate(cx, obj)) == NULL) return(JS_FALSE); if (argc) { JSVALUE_TO_MSTRING(cx, argv[0], title, NULL); HANDLE_PENDING(cx, title); if (title == NULL) return(JS_TRUE); } if (argc > 1) { JSVALUE_TO_ASTRING(cx, argv[1], mode, 16, NULL); if (mode != NULL) { if (!stricmp(mode, "STDIO")) ciolib_mode = -1; else if (!stricmp(mode, "AUTO")) ciolib_mode = CIOLIB_MODE_AUTO; else if (!stricmp(mode, "X")) ciolib_mode = CIOLIB_MODE_X; else if (!stricmp(mode, "CURSES")) ciolib_mode = CIOLIB_MODE_CURSES; else if (!stricmp(mode, "CURSES_IBM")) ciolib_mode = CIOLIB_MODE_CURSES_IBM; else if (!stricmp(mode, "CURSES_ASCII")) ciolib_mode = CIOLIB_MODE_CURSES_ASCII; else if (!stricmp(mode, "ANSI")) ciolib_mode = CIOLIB_MODE_ANSI; else if (!stricmp(mode, "CONIO")) ciolib_mode = CIOLIB_MODE_CONIO; else if (!stricmp(mode, "SDL")) ciolib_mode = CIOLIB_MODE_SDL; } } rc = JS_SUSPENDREQUEST(cx); if (ciolib_mode == -1) { if (uifcinix(uifc)) { JS_RESUMEREQUEST(cx, rc); if (title != title_def) free(title); return(JS_TRUE); } } else { if (initciolib(ciolib_mode)) { JS_RESUMEREQUEST(cx, rc); if (title != title_def) free(title); return(JS_TRUE); } if (uifcini32(uifc)) { JS_RESUMEREQUEST(cx, rc); if (title != title_def) free(title); return(JS_TRUE); } } JS_SET_RVAL(cx, arglist, JSVAL_TRUE); uifc->scrn(title); if (title != title_def) free(title); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_uifc_bail(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); uifcapi_t* uifc; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); rc = JS_SUSPENDREQUEST(cx); uifc->bail(); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_uifc_showhelp(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); uifcapi_t* uifc; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); rc = JS_SUSPENDREQUEST(cx); uifc->showhelp(); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_uifc_msg(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); char* str = NULL; uifcapi_t* uifc; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); JSVALUE_TO_MSTRING(cx, argv[0], str, NULL); HANDLE_PENDING(cx, str); if (str == NULL) return(JS_TRUE); rc = JS_SUSPENDREQUEST(cx); uifc->msg(str); free(str); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_uifc_pop(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); char* str = NULL; uifcapi_t* uifc; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); if (argc) { JSVALUE_TO_MSTRING(cx, argv[0], str, NULL); HANDLE_PENDING(cx, str); } rc = JS_SUSPENDREQUEST(cx); uifc->pop(str); if (str) free(str); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_uifc_input(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); char* str; char* org = NULL; char* prompt = NULL; int32 maxlen = 0; int32 left = 0; int32 top = 0; int32 mode = 0; int32 kmode = 0; uifcapi_t* uifc; uintN argn = 0; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); if (argn < argc && JSVAL_IS_NUMBER(argv[argn]) && !JS_ValueToInt32(cx, argv[argn++], &mode)) return(JS_FALSE); if (argn < argc && JSVAL_IS_NUMBER(argv[argn]) && !JS_ValueToInt32(cx, argv[argn++], &left)) return(JS_FALSE); if (argn < argc && JSVAL_IS_NUMBER(argv[argn]) && !JS_ValueToInt32(cx, argv[argn++], &top)) return(JS_FALSE); if (argn < argc && JSVAL_IS_STRING(argv[argn])) { JSVALUE_TO_MSTRING(cx, argv[argn], prompt, NULL); argn++; HANDLE_PENDING(cx, prompt); if (prompt == NULL) return(JS_TRUE); } if (argn < argc && JSVAL_IS_STRING(argv[argn])) { JSVALUE_TO_MSTRING(cx, argv[argn], org, NULL); argn++; if (JS_IsExceptionPending(cx)) { if (prompt) free(prompt); return JS_FALSE; } if (org == NULL) { if (prompt) free(prompt); return(JS_TRUE); } } if (argn < argc && JSVAL_IS_NUMBER(argv[argn]) && !JS_ValueToInt32(cx, argv[argn++], &maxlen)) { if (prompt) free(prompt); if (org) free(org); return(JS_FALSE); } if (argn < argc && JSVAL_IS_NUMBER(argv[argn]) && !JS_ValueToInt32(cx, argv[argn++], &kmode)) { if (prompt) free(prompt); if (org) free(org); return(JS_FALSE); } if (!maxlen) maxlen = 40; if ((str = (char*)malloc(maxlen + 1)) == NULL) { if (prompt) free(prompt); if (org) free(org); return(JS_FALSE); } memset(str, 0, maxlen + 1); if (org) { strncpy(str, org, maxlen); free(org); } rc = JS_SUSPENDREQUEST(cx); if (uifc->input(mode, left, top, prompt, str, maxlen, kmode) < 0) { JS_RESUMEREQUEST(cx, rc); if (prompt) free(prompt); if (str) free(str); return(JS_TRUE); } if (prompt) free(prompt); JS_RESUMEREQUEST(cx, rc); JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str))); if (str) free(str); return(JS_TRUE); } static JSBool js_uifc_list(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); char* title = NULL; int32 left = 0; int32 top = 0; int32 width = 0; int32 dflt = 0; int32 * dptr = &dflt; int32 bar = 0; int32 * bptr = &bar; int32 mode = 0; JSObject* objarg; uifcapi_t* uifc; uintN argn = 0; jsval val; jsuint i; jsuint numopts; str_list_t opts = NULL; char * opt = NULL; size_t opt_sz = 0; jsrefcount rc; struct list_ctx_private *p; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); if (argn < argc && JSVAL_IS_NUMBER(argv[argn]) && !JS_ValueToInt32(cx, argv[argn++], &mode)) return(JS_FALSE); for (; argn < argc; argn++) { if (JSVAL_IS_STRING(argv[argn])) { free(title); JSVALUE_TO_MSTRING(cx, argv[argn], title, NULL); HANDLE_PENDING(cx, title); continue; } if (!JSVAL_IS_OBJECT(argv[argn])) continue; if ((objarg = JSVAL_TO_OBJECT(argv[argn])) == NULL) { free(title); return(JS_FALSE); } if (JS_IsArrayObject(cx, objarg)) { if (!JS_GetArrayLength(cx, objarg, &numopts)) { free(title); return(JS_TRUE); } if (opts == NULL) opts = strListInit(); for (i = 0; i < numopts; i++) { if (!JS_GetElement(cx, objarg, i, &val)) break; JSVALUE_TO_RASTRING(cx, val, opt, &opt_sz, NULL); if (JS_IsExceptionPending(cx)) { if (title) free(title); } strListPush(&opts, opt); } FREE_AND_NULL(opt); } else if (JS_GetClass(cx, objarg) == &js_uifc_list_ctx_class) { p = JS_GetPrivate(cx, objarg); if (p != NULL) { dptr = &(p->cur); bptr = &(p->bar); left = p->left; top = p->top; width = p->width; } } } if (title == NULL || opts == NULL) { JS_SET_RVAL(cx, arglist, JSVAL_FALSE); } else { rc = JS_SUSPENDREQUEST(cx); JS_SET_RVAL(cx, arglist, INT_TO_JSVAL(uifc->list(mode | WIN_BLANKOPTS, left, top, width, (int*)dptr, (int*)bptr, title, opts))); JS_RESUMEREQUEST(cx, rc); } strListFree(&opts); if (title != NULL) free(title); return(JS_TRUE); } static JSBool js_uifc_scrn(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); char* str = NULL; uifcapi_t* uifc; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); JSVALUE_TO_MSTRING(cx, argv[0], str, NULL); HANDLE_PENDING(cx, str); if (str == NULL) return(JS_TRUE); rc = JS_SUSPENDREQUEST(cx); uifc->scrn(str); free(str); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_uifc_timedisplay(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); JSBool force = JS_FALSE; uifcapi_t* uifc; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); if (argc > 0) force = JSVAL_TO_BOOLEAN(argv[0]); rc = JS_SUSPENDREQUEST(cx); uifc->timedisplay(force); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_uifc_bottomline(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); int mode; uifcapi_t* uifc; jsrefcount rc; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); if (argc == 0) { JS_ReportError(cx, "No mode specified"); return(JS_FALSE); } mode = JSVAL_TO_INT(argv[0]); rc = JS_SUSPENDREQUEST(cx); uifc->bottomline(mode); JS_RESUMEREQUEST(cx, rc); return(JS_TRUE); } static JSBool js_uifc_getstrxy(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); char* str; char* org = NULL; int32 left = 0; int32 top = 0; int32 width = 0; int32 maxlen = 0; int32 mode = 0; uifcapi_t* uifc; uintN argn = 0; jsrefcount rc; JSObject* objarg; int * lastkey = NULL; struct getstrxy_ctx_private *p; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); if (argc < 5) { JS_ReportError(cx, "getstrxy requires at least five arguments"); return JS_FALSE; } if (!JS_ValueToInt32(cx, argv[argn++], &left)) return JS_FALSE; if (!JS_ValueToInt32(cx, argv[argn++], &top)) return JS_FALSE; if (!JS_ValueToInt32(cx, argv[argn++], &width)) return JS_FALSE; if (!JS_ValueToInt32(cx, argv[argn++], &maxlen)) return JS_FALSE; if (!JS_ValueToInt32(cx, argv[argn++], &mode)) return JS_FALSE; if (argn < argc && JSVAL_IS_STRING(argv[argn])) { JSVALUE_TO_MSTRING(cx, argv[argn], org, NULL); argn++; if (JS_IsExceptionPending(cx)) { free(org); return JS_FALSE; } if (org == NULL) return(JS_TRUE); } if (argn < argc && JSVAL_IS_OBJECT(argv[argn])) { if ((objarg = JSVAL_TO_OBJECT(argv[argn])) == NULL) { free(org); return(JS_FALSE); } if (JS_GetClass(cx, objarg) == &js_uifc_getstrxy_ctx_class) { p = JS_GetPrivate(cx, objarg); if (p != NULL) { lastkey = &(p->lastkey); } } } if (maxlen < 1) { JS_ReportError(cx, "max length less than one"); free(org); return JS_FALSE; } if ((str = (char*)malloc(maxlen + 1)) == NULL) { free(org); return(JS_FALSE); } memset(str, 0, maxlen + 1); if (org) { strncpy(str, org, maxlen); free(org); } rc = JS_SUSPENDREQUEST(cx); if (uifc->getstrxy(left, top, width, str, maxlen, mode, lastkey) < 0) { JS_RESUMEREQUEST(cx, rc); free(str); JS_SET_RVAL(cx, arglist, JSVAL_NULL); return(JS_TRUE); } JS_RESUMEREQUEST(cx, rc); JS_SET_RVAL(cx, arglist, STRING_TO_JSVAL(JS_NewStringCopyZ(cx, str))); if (str) free(str); return(JS_TRUE); } static JSBool js_uifc_showbuf(JSContext *cx, uintN argc, jsval *arglist) { JSObject * obj = JS_THIS_OBJECT(cx, arglist); jsval * argv = JS_ARGV(cx, arglist); char* str; char* title = NULL; int32 left = 0; int32 top = 0; int32 width = INT_MAX; int32 height = INT_MAX; int32 mode = 0; int * cur = NULL; int * bar = NULL; uifcapi_t* uifc; uintN argn = 0; jsrefcount rc; JSObject* objarg; struct showbuf_ctx_private *p; JS_SET_RVAL(cx, arglist, JSVAL_VOID); if ((uifc = get_uifc(cx, obj)) == NULL) return(JS_FALSE); if (argc < 3) { JS_ReportError(cx, "showbuf requires at least three arguments"); return JS_FALSE; } if (!JS_ValueToInt32(cx, argv[argn++], &mode)) return JS_FALSE; JSVALUE_TO_MSTRING(cx, argv[argn++], title, NULL); if (JS_IsExceptionPending(cx)) { free(title); return JS_FALSE; } if (title == NULL) return(JS_TRUE); JSVALUE_TO_MSTRING(cx, argv[argn++], str, NULL); if (JS_IsExceptionPending(cx)) { free(title); return JS_FALSE; } if (str == NULL) { free(title); return(JS_TRUE); } if (argn < argc && JSVAL_IS_OBJECT(argv[argn])) { if ((objarg = JSVAL_TO_OBJECT(argv[argn])) == NULL) { free(title); free(str); return(JS_FALSE); } if (JS_GetClass(cx, objarg) == &js_uifc_showbuf_ctx_class) { p = JS_GetPrivate(cx, objarg); if (p != NULL) { cur = &(p->cur); bar = &(p->bar); left = p->left; top = p->top; width = p->width; height = p->height; } } } rc = JS_SUSPENDREQUEST(cx); uifc->showbuf(mode, left, top, width, height, title, str, cur, bar); JS_RESUMEREQUEST(cx, rc); free(title); free(str); return(JS_TRUE); } /* Destructor */ static void js_finalize(JSContext *cx, JSObject *obj) { uifcapi_t* p; if ((p = (uifcapi_t*)JS_GetPrivate(cx, obj)) == NULL) return; free(p); JS_SetPrivate(cx, obj, NULL); } static jsSyncMethodSpec js_functions[] = { {"init", js_uifc_init, 1, JSTYPE_BOOLEAN, JSDOCSTR("<i>string</i> title [,<i>string</i> interface_mode]") , JSDOCSTR("Initialize the UIFC library with the specified application/script title (e.g. name and maybe version).<br>" "<tt>interface_mode</tt> is a string representing the desired console mode, one of 'STDIO', 'AUTO', " "'X', 'CURSES', 'ANSI', 'CONIO', or 'SDL' (see <tt>conio.init()</tt> for details).<br>" "Return <tt>true</tt> upon successful UIFC library initialization, <tt>false</tt> upon error." ) , 314}, {"bail", js_uifc_bail, 0, JSTYPE_VOID, JSDOCSTR("") , JSDOCSTR("Uninitialize the UIFC library") , 314}, {"msg", js_uifc_msg, 1, JSTYPE_VOID, JSDOCSTR("<i>string</i> text") , JSDOCSTR("Print a short text message and wait for user acknowledgment") , 314}, {"pop", js_uifc_pop, 1, JSTYPE_VOID, JSDOCSTR("[<i>string</i> text]") , JSDOCSTR("Pop-up (or down) a short text message. Pop-down by passing no <i>text</i> argument.") , 314}, {"input", js_uifc_input, 0, JSTYPE_STRING, JSDOCSTR("[<i>number</i> mode] [,<i>number</i> left] [,<i>number</i> top] [,<i>string</i> prompt] [,<i>string</i> default] [,<i>number</i> maxlen [,<i>number</i> k_mode]]") , JSDOCSTR("Prompt for a string input.<br>" "<tt>mode</tt> is an optional combination of <tt>WIN_</tt> mode flags from <tt>uifcdefs.js</tt>.<br>" "<tt>left</tt> and <tt>top</tt> are optional window offsets to display the input dialog box.<br>" "<tt>prompt</tt> is an optional text string to display as part of the string input dialog box.<br>" "<tt>default</tt> is an optional original text string that the user can edit (requires the <tt>K_EDIT k_mode</tt> flag).<br>" "<tt>maxlen</tt> is an optional maximum input string length (default is 40 characters).<br>" "<tt>k_mode</tt> is an optional combination of <tt>K_</tt> mode flags from either <tt>sbbsdefs.js</tt> or <tt>uifcdefs.js</tt>." "<p>" "Return the new/edited string or <tt>undefined</tt> if editing was aborted (e.g. via ESC key press)." ) , 314}, {"list", js_uifc_list, 0, JSTYPE_NUMBER, JSDOCSTR("[<i>number</i> mode,] <i>string</i> title, <i>array</i> options [,<i>uifc.list.CTX</i> ctx]") , JSDOCSTR("Select from a list of displayed options.<br>" "<tt>title</tt> is the brief description of the list (menu) to be displayed in the list heading.<br>" "<tt>options</tt> is an array of items (typically strings) that comprise the displayed list.<br>" "The <tt>CTX</tt> (context) object can be created using <tt>new uifc.list.CTX</tt> and if the same object is passed in successive calls, allows <tt>WIN_SAV</tt> to work correctly.<br>" "The context object has the following properties (<i>numbers</i>):<br><tt>cur, bar, left, top, width</tt>" "<p>" "Return <tt>-1</tt> if list is aborted (e.g. via ESC key press), <tt>false</tt> upon error (e.g. no option array provided), " "or the 0-based numeric index of the option selected by the user.<br>" "Other negative values may be returned in advanced modes/use-cases (e.g. copy/paste), see <tt>MSK_</tt> and related <tt>WIN_</tt> constants/comments in <tt>uifcdefs.js</tt> for details." ) , 314}, {"showhelp", js_uifc_showhelp, 0, JSTYPE_VOID, JSDOCSTR("") , JSDOCSTR("Show the current help text") , 317}, {"scrn", js_uifc_scrn, 1, JSTYPE_BOOLEAN, JSDOCSTR("<i>string</i> text") , JSDOCSTR("Fill the screen with the appropriate background attribute. string is the title for the application banner.") , 31802}, {"showbuf", js_uifc_showbuf, 7, JSTYPE_VOID, JSDOCSTR("<i>number</i> mode, <i>string</i> title, <i>string</i> helpbuf [,<i>uifc.showbuf.CTX</i> ctx]") , JSDOCSTR("Show a scrollable text buffer - optionally parsing \"help markup codes\"<br>" "The context object can be created using <tt>new uifc.showbuf.CTX</tt> and if the same object is passed, allows <tt>WIN_SAV</tt> to work correctly.<br>" "The context object has the following properties (<i>numbers</i>):<br><tt>cur, bar, left, top, width, height</tt>") , 31802}, {"timedisplay", js_uifc_timedisplay, 0, JSTYPE_VOID, JSDOCSTR("[<i>bool<i/> force = false]") , JSDOCSTR("Update time in upper right corner of screen with current time in ASCII/Unix format") , 31802}, {"bottomline", js_uifc_bottomline, 1, JSTYPE_VOID, JSDOCSTR("<i>number</i> mode") , JSDOCSTR("Display the bottom line using the <tt>WIN_*</tt> mode flags") , 31802}, {"getstrxy", js_uifc_getstrxy, 7, JSTYPE_STRING, JSDOCSTR("<i>number</i> left, <i>number</i> top, <i>number</i> width, <i>number</i> max, <i>number</i> mode [,<i>string</i> original][, <i>uifc.getstrxy.CTX</i> ctx]") , JSDOCSTR("String input/exit box at a specified position" "The context object can be created using <tt>new uifc.showbuf.CTX</tt> and if the same object is passed, allows <tt>WIN_SAV</tt> to work correctly.<br>" "The context object has the following properties: <i>number</i> <tt>lastkey</tt>") , 31802}, {0} }; static JSBool js_uifc_resolve(JSContext *cx, JSObject *obj, jsid id) { char* name = NULL; JSBool ret; jsval objval; JSObject* tobj; if (id != JSID_VOID && id != JSID_EMPTY) { jsval idval; JS_IdToValue(cx, id, &idval); if (JSVAL_IS_STRING(idval)) { JSSTRING_TO_MSTRING(cx, JSVAL_TO_STRING(idval), name, NULL); HANDLE_PENDING(cx, name); } } ret = js_SyncResolve(cx, obj, name, js_properties, js_functions, NULL, 0); if (name == NULL || strcmp(name, "list") == 0) { if (JS_GetProperty(cx, obj, "list", &objval)) { tobj = JSVAL_TO_OBJECT(objval); if (tobj) JS_InitClass(cx, tobj, NULL, &js_uifc_list_ctx_class, js_list_ctx_constructor, 0, NULL, NULL, NULL, NULL); } } if (name == NULL || strcmp(name, "showbuf") == 0) { if (JS_GetProperty(cx, obj, "showbuf", &objval)) { tobj = JSVAL_TO_OBJECT(objval); if (tobj) JS_InitClass(cx, tobj, NULL, &js_uifc_showbuf_ctx_class, js_showbuf_ctx_constructor, 0, NULL, NULL, NULL, NULL); } } if (name == NULL || strcmp(name, "getstrxy") == 0) { if (JS_GetProperty(cx, obj, "getstrxy", &objval)) { tobj = JSVAL_TO_OBJECT(objval); if (tobj) JS_InitClass(cx, tobj, NULL, &js_uifc_getstrxy_ctx_class, js_getstrxy_ctx_constructor, 0, NULL, NULL, NULL, NULL); } } if (name) free(name); return ret; } static JSBool js_uifc_enumerate(JSContext *cx, JSObject *obj) { return(js_uifc_resolve(cx, obj, JSID_VOID)); } static JSClass js_uifc_class = { "UIFC" /* name */ , JSCLASS_HAS_PRIVATE /* flags */ , JS_PropertyStub /* addProperty */ , JS_PropertyStub /* delProperty */ , js_get /* getProperty */ , js_set /* setProperty */ , js_uifc_enumerate /* enumerate */ , js_uifc_resolve /* resolve */ , JS_ConvertStub /* convert */ , js_finalize /* finalize */ }; JSObject* js_CreateUifcObject(JSContext* cx, JSObject* parent) { JSObject* obj; uifcapi_t* api; if ((obj = JS_DefineObject(cx, parent, "uifc", &js_uifc_class, NULL , JSPROP_ENUMERATE | JSPROP_READONLY)) == NULL) return(NULL); if ((api = (uifcapi_t*)malloc(sizeof(uifcapi_t))) == NULL) return(NULL); memset(api, 0, sizeof(uifcapi_t)); api->size = sizeof(uifcapi_t); api->esc_delay = 25; if (!JS_SetPrivate(cx, obj, api)) /* Store a pointer to uifcapi_t */ return(NULL); #ifdef BUILD_JSDOCS js_DescribeSyncObject(cx, obj, "User InterFaCe object - Text User Interface (TUI) menu system for JSexec", 314); js_CreateArrayOfStrings(cx, obj, "_property_desc_list", uifc_prop_desc, JSPROP_READONLY); #endif return(obj); }