From 2477f210a3950cdbd2fea3112d865d2bbcdbe045 Mon Sep 17 00:00:00 2001 From: "Rob Swindell (on Debian Linux)" <rob@synchro.net> Date: Sat, 18 Jan 2025 16:55:15 -0800 Subject: [PATCH] Throw fewer exceptions when passed null or undefined as parameters Some scripts (e.g. addfiles.js) depend on the previous (undocumented) behavior for some methods, e.g. lfexpand(undefined) would return undefined. So for global functions that are expected to return a modified version of the value passed (usually a string), return null or undefined when passed null or undefined. Backward compatibility is more important than consistency in this case. :-( --- exec/tests/global/except.js | 30 ++++++------ exec/tests/global/rtypes.js | 9 ++++ src/sbbs3/js_global.c | 95 +++++++++++++++++++++---------------- 3 files changed, 78 insertions(+), 56 deletions(-) diff --git a/exec/tests/global/except.js b/exec/tests/global/except.js index ed5ef1bcc8..68a45188f5 100644 --- a/exec/tests/global/except.js +++ b/exec/tests/global/except.js @@ -3,9 +3,9 @@ // Value (e.g. 0, 1) is number of non-null/undefined args required var func_list = { 'ascii': 1, - 'ascii_str': 1, + 'ascii_str': 0, 'alert': 0, - 'backslash': 1, + 'backslash': 0, 'base64_encode': 1, 'base64_decode': 1, 'beep': 1, @@ -28,8 +28,8 @@ var func_list = { 'file_exists': 0, 'file_getcase': 1, 'file_getdosname': 1, - 'file_getext': 1, - 'file_getname': 1, + 'file_getext': 0, + 'file_getname': 0, 'file_isdir': 0, 'file_mode': 1, 'file_mutex': 1, @@ -43,7 +43,7 @@ var func_list = { 'fullpath': 1, 'html_encode': 1, 'html_decode': 1, - 'lfexpand': 1, + 'lfexpand': 0, 'load': 1, 'log': 0, 'md5_calc': 1, @@ -59,8 +59,8 @@ var func_list = { 'resolve_ip': 1, 'rmdir': 1, 'rmfiles': 1, - 'rot13_translate': 1, - 'skipsp': 1, + 'rot13_translate': 0, + 'skipsp': 0, 'sha1_calc': 1, 'socket_strerror': 1, 'str_has_ctrl': 0, @@ -69,17 +69,17 @@ var func_list = { 'str_is_utf8': 0, 'strerror': 1, 'strftime': 1, - 'strip_ansi': 1, - 'strip_ctrl': 1, - 'strip_ctrl_a': 1, - 'strip_exascii': 1, - 'truncsp': 1, + 'strip_ansi': 0, + 'strip_ctrl': 0, + 'strip_ctrl_a': 0, + 'strip_exascii': 0, + 'truncsp': 0, 'truncstr': 2, - 'utf8_decode': 1, - 'utf8_encode': 1, + 'utf8_decode': 0, + 'utf8_encode': 0, 'utf8_get_width': 1, 'wildmatch': 0, - 'word_wrap': 1, + 'word_wrap': 0, 'yield': 1, }; diff --git a/exec/tests/global/rtypes.js b/exec/tests/global/rtypes.js index ddd4f0528d..694d7ffc8c 100644 --- a/exec/tests/global/rtypes.js +++ b/exec/tests/global/rtypes.js @@ -1,4 +1,5 @@ // Test global function return types +// @format.tab-size 4, @format.use-tabs true var type = { 'alert(0)' : 'undefined', @@ -6,7 +7,11 @@ var type = { 'ascii("A")' : 'number', 'ascii_str("A")' : 'string', 'ascii_str(1)' : 'string', + 'ascii_str(null)' : 'object', // null + 'ascii_str(undefined)' : 'undefined', 'backslash("")' : 'string', + 'backslash(null)' : 'object', // null + 'backslaash(undefined)' : 'undefined', 'base64_encode("")' : 'object', // null 'base64_encode("1")' : 'string', 'base64_decode("")' : 'object', // null @@ -35,6 +40,8 @@ var type = { 'flags_str(0)' : 'string', 'fullpath("")' : 'string', 'lfexpand("")' : 'string', + 'lfexpand(null)' : 'object', // null + 'lfexpand(undefined)' : 'undefined', 'log("")' : 'string', 'md5_calc("")' : 'string', 'mswait()' : 'number', @@ -53,6 +60,8 @@ var type = { 'str_is_utf16("")' : 'boolean', 'str_is_utf8("")' : 'boolean', 'strftime("")' : 'string', + 'strip_ctrl(null)' : 'null', + 'strip_ctrl(undefined)' : 'undefined', 'strip_ctrl("")' : 'string', 'strip_ctrl_a("")' : 'string', 'strip_ansi("")' : 'string', diff --git a/src/sbbs3/js_global.c b/src/sbbs3/js_global.c index 111e9dac12..c9f5469d94 100644 --- a/src/sbbs3/js_global.c +++ b/src/sbbs3/js_global.c @@ -1081,9 +1081,10 @@ js_ascii_str(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], buf, NULL) HANDLE_PENDING(cx, buf); if (buf == NULL) @@ -1113,9 +1114,10 @@ js_strip_ctrl(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], buf, NULL); HANDLE_PENDING(cx, buf); if (buf == NULL) @@ -1144,9 +1146,10 @@ js_strip_ctrl_a(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], buf, NULL); HANDLE_PENDING(cx, buf); if (buf == NULL) @@ -1175,9 +1178,10 @@ js_strip_ansi(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], buf, NULL) HANDLE_PENDING(cx, buf); if (buf == NULL) @@ -1206,9 +1210,10 @@ js_strip_exascii(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], buf, NULL) HANDLE_PENDING(cx, buf); if (buf == NULL) @@ -1239,9 +1244,10 @@ js_lfexpand(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], inbuf, NULL); HANDLE_PENDING(cx, inbuf); if (inbuf == NULL) @@ -1287,9 +1293,10 @@ js_word_wrap(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], inbuf, NULL); HANDLE_PENDING(cx, inbuf); if (inbuf == NULL) @@ -2767,9 +2774,10 @@ js_internal_charfunc(JSContext *cx, uintN argc, jsval *arglist, char *(*func)(ch if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JS_SET_RVAL(cx, arglist, JSVAL_VOID); JSVALUE_TO_MSTRING(cx, argv[0], str, &strlen); HANDLE_PENDING(cx, str); @@ -2854,9 +2862,12 @@ js_truncstr(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 2)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0) || js_argvIsNullOrVoid(cx, argv, 1)) + if (js_argvIsNullOrVoid(cx, argv, 1)) return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], str, NULL); HANDLE_PENDING(cx, str); if (str == NULL) @@ -4585,9 +4596,10 @@ js_utf8_encode(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } if (JSVAL_IS_STRING(argv[0])) { if (str_is_utf16(cx, argv[0])) { js_str = JS_ValueToString(cx, argv[0]); @@ -4685,9 +4697,10 @@ js_utf8_decode(JSContext *cx, uintN argc, jsval *arglist) if (js_argcIsInsufficient(cx, argc, 1)) return JS_FALSE; - if (js_argvIsNullOrVoid(cx, argv, 0)) - return JS_FALSE; - + if (JSVAL_NULL_OR_VOID(argv[0])) { + JS_SET_RVAL(cx, arglist, argv[0]); + return JS_TRUE; + } JSVALUE_TO_MSTRING(cx, argv[0], buf, NULL); HANDLE_PENDING(cx, buf); if (buf == NULL) @@ -4932,31 +4945,31 @@ static jsSyncMethodSpec js_global_functions[] = { , JSDOCSTR("Convert single character to numeric ASCII value or vice-versa (returns number OR string)") , 310}, {"ascii_str", js_ascii_str, 1, JSTYPE_STRING, JSDOCSTR("text") - , JSDOCSTR("Convert extended-ASCII (CP437) characters in text string to plain US-ASCII equivalent, returns modified string") + , JSDOCSTR("Convert extended-ASCII (CP437) characters in text string to plain US-ASCII equivalent, returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 310}, {"strip_ctrl", js_strip_ctrl, 1, JSTYPE_STRING, JSDOCSTR("text") - , JSDOCSTR("Strip all control characters and Ctrl-A (attribute) sequences from string, returns modified string") + , JSDOCSTR("Strip all control characters and Ctrl-A (attribute) sequences from string, returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 310}, {"strip_ctrl_a", js_strip_ctrl_a, 1, JSTYPE_STRING, JSDOCSTR("text") - , JSDOCSTR("Strip all Ctrl-A (attribute) sequences from string, returns modified string") + , JSDOCSTR("Strip all Ctrl-A (attribute) sequences from string, returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 320}, {"strip_ansi", js_strip_ansi, 1, JSTYPE_STRING, JSDOCSTR("text") - , JSDOCSTR("Strip all ANSI terminal control sequences from string, returns modified string") + , JSDOCSTR("Strip all ANSI terminal control sequences from string, returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 31802}, {"strip_exascii", js_strip_exascii, 1, JSTYPE_STRING, JSDOCSTR("text") - , JSDOCSTR("Strip all extended-ASCII characters from string, returns modified string") + , JSDOCSTR("Strip all extended-ASCII characters from string, returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 310}, {"skipsp", js_skipsp, 1, JSTYPE_STRING, JSDOCSTR("text") - , JSDOCSTR("Skip (trim) white-space characters off <b>beginning</b> of string, returns modified string") + , JSDOCSTR("Skip (trim) white-space characters off <b>beginning</b> of string, returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 315}, {"truncsp", js_truncsp, 1, JSTYPE_STRING, JSDOCSTR("text") - , JSDOCSTR("Truncate (trim) white-space characters off <b>end</b> of string, returns modified string") + , JSDOCSTR("Truncate (trim) white-space characters off <b>end</b> of string, returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 310}, {"truncstr", js_truncstr, 2, JSTYPE_STRING, JSDOCSTR("text, charset") - , JSDOCSTR("Truncate (trim) string at first char in <i>charset</i>, returns modified string") + , JSDOCSTR("Truncate (trim) string at first char in <i>charset</i>, returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 310}, {"lfexpand", js_lfexpand, 1, JSTYPE_STRING, JSDOCSTR("text") - , JSDOCSTR("Expand sole line-feeds (LF) to carriage-return/line-feed sequences (CRLF), returns modified string") + , JSDOCSTR("Expand sole line-feeds (LF) to carriage-return/line-feed sequences (CRLF), returns modified string or <tt>null</tt> or <tt>undefined</tt> if passed those values") , 310}, {"wildmatch", js_wildmatch, 2, JSTYPE_BOOLEAN, JSDOCSTR("[<i>bool</i> case_sensitive=false,] filename [,pattern='*'] [,path=false]") , JSDOCSTR("Return <tt>true</tt> if the <i>filename</i> matches the wildcard <i>pattern</i> (wildcard characters supported are '*' and '?'), " -- GitLab