diff --git a/docs/05.PORT-API.md b/docs/05.PORT-API.md index 10eca0a95c..08c3514e0a 100644 --- a/docs/05.PORT-API.md +++ b/docs/05.PORT-API.md @@ -72,15 +72,18 @@ typedef enum void jerry_port_log (jerry_log_level_t level, const char *fmt, ...); ``` -The `jerry_port_print_char` is currently not used by the jerry-core directly. +The `jerry_port_string_print` is currently not used by the jerry-core directly. However, it provides a port specific way for `jerry-ext` components to print information. ```c /** - * Print a character to stdout. + * Print a zero-terminated UTF-8 string with length to standard output. + * + * @param s The zero-terminated UTF-8 string to print + * @param len The length of the UTF-8 string. */ -void jerry_port_print_char (char c); +void jerry_port_string_print (const char *s, size_t len); ``` ### Jerry Module system @@ -278,13 +281,18 @@ jerry_port_log (jerry_log_level_t level, /**< log level */ ```c /** - * Print a character to stdout with putchar. + * Provide implementation of jerry_port_string_print. + * Uses 'printf' to print a zero-terminated UTF-8 string to standard output. + * + * @param s The zero-terminated UTF-8 string to print + * @param len The length of the UTF-8 string. */ void -jerry_port_print_char (char c) +jerry_port_string_print (const char *s, size_t len) { - putchar (c); -} /* jerry_port_print_char */ + (void) len; + printf ("%s", s); +} /* jerry_port_string_print */ ``` ## Date diff --git a/docs/10.EXT-REFERENCE-HANDLER.md b/docs/10.EXT-REFERENCE-HANDLER.md index e1d991fa0a..cf963cc42d 100644 --- a/docs/10.EXT-REFERENCE-HANDLER.md +++ b/docs/10.EXT-REFERENCE-HANDLER.md @@ -513,14 +513,14 @@ jerryx_handler_gc (const jerry_value_t func_obj_val, const jerry_value_t this_p, Provide a `print` implementation for scripts. The routine converts all of its arguments to strings and outputs them char-by-char using -`jerry_port_print_char`. The NULL character is output as "\u0000", +`jerry_port_string_print`. The NULL character is output as "\u0000", other characters are output bytewise. *Note*: This implementation does not use standard C `printf` to print its output. This allows more flexibility but also extends the core JerryScript engine port API. Applications that want to use `jerryx_handler_print` must ensure that their port implementation also provides -`jerry_port_print_char`. +`jerry_port_string_print`. **Prototype** @@ -540,7 +540,7 @@ jerryx_handler_print (const jerry_value_t func_obj_val, const jerry_value_t this **See also** - [jerryx_handler_register_global](#jerryx_handler_register_global) -- [jerry_port_print_char](05.PORT-API.md#jerry_port_print_char) +- [jerry_port_string_print](05.PORT-API.md#jerry_port_string_print) # Handler registration helper diff --git a/docs/16.MIGRATION-GUIDE.md b/docs/16.MIGRATION-GUIDE.md index 9c71d63a1b..73c62d15c0 100644 --- a/docs/16.MIGRATION-GUIDE.md +++ b/docs/16.MIGRATION-GUIDE.md @@ -766,7 +766,7 @@ In this section the new API functions are listed. - [`jerry_port_normalize_path`](05.PORT-API.md#jerry_port_normalize_path) - [`jerry_port_read_source`](05.PORT-API.md#jerry_port_read_source) - [`jerry_port_release_source`](05.PORT-API.md#jerry_port_release_source) -- [`jerry_port_print_char`](05.PORT-API.md#jerry_port_print_char) +- [`jerry_port_string_print`](05.PORT-API.md#jerry_port_string_print) - [`jerry_port_get_current_context`](05.PORT-API.md#jerry_port_get_current_context) - [`jerry_port_fatal`](05.PORT-API.md#jerry_port_fatal) - [`jerry_port_sleep`](05.PORT-API.md#jerry_port_sleep) diff --git a/jerry-core/api/jerryscript.c b/jerry-core/api/jerryscript.c index 6f78dca5c7..3364af558b 100644 --- a/jerry-core/api/jerryscript.c +++ b/jerry-core/api/jerryscript.c @@ -3080,34 +3080,79 @@ jerry_string_iterate (const jerry_value_t value, } /* jerry_string_iterate */ /** - * Print char wrapper that casts the argument to an unsigned type + * Iterate over the input string value, visiting each code point of the string once. If + * the input value is not a string, the function will do nothing. * - * @param byte encoded byte value - * @param user_p user pointer + * @param value the input string value + * @param callback callback function called for each code point of the string. + * @param user_p User pointer passed to the callback function */ -static void -jerry_print_char_wrapper (uint8_t byte, void *user_p) +void +jerry_string_iterate_code_point (const jerry_value_t value, jerry_string_iterate_code_point_cb_t callback, void *user_p) { - JERRY_UNUSED (user_p); - static const char *const null_str_p = "\\u0000"; - - if (JERRY_UNLIKELY (byte == '\0')) + if (!ecma_is_value_string (value)) { - const char *curr_p = null_str_p; + return; + } - while (*curr_p != '\0') + ecma_string_t *str_p = ecma_get_string_from_value (value); + ECMA_STRING_TO_UTF8_STRING (str_p, buffer_p, buffer_size); + + const lit_utf8_byte_t *current_p = buffer_p; + const lit_utf8_byte_t *end_p = buffer_p + buffer_size; + + while (current_p < end_p) + { + if (JERRY_UNLIKELY (*current_p >= LIT_UTF8_2_BYTE_MARKER)) { - jerry_port_print_char (*curr_p++); + lit_code_point_t cp; + lit_utf8_size_t read_size = lit_read_code_point_from_cesu8 (current_p, end_p, &cp); + callback (cp, user_p); + current_p += read_size; + continue; } - return; + callback (*current_p++, user_p); } +} /* jerry_string_iterate_code_point */ - jerry_port_print_char ((char) byte); -} /* jerry_print_char_wrapper */ +/** + * Print unicode code point to console + * + * @param code_point unicode code point + */ +void +jerry_code_point_print (uint32_t code_point) +{ + if (JERRY_UNLIKELY (code_point == 0)) + { + static const char null_str_p[] = "\\u0000"; + jerry_port_string_print (null_str_p, sizeof (null_str_p) - 1); + } + else + { + lit_utf8_byte_t bytes[LIT_UTF8_MAX_BYTES_IN_CODE_POINT + 1]; + lit_utf8_size_t encoded_size = lit_code_point_to_utf8 (code_point, bytes); + bytes[encoded_size] = 0; + jerry_port_string_print ((const char *) bytes, encoded_size); + } +} /* jerry_code_point_print */ + +/** + * Print code point to console wrapper + * + * @param code_point unicode code point + * @param user_p user pointer + */ +static void +jerry_print_codepoint_wrapper (uint32_t code_point, void *user_p) +{ + JERRY_UNUSED (user_p); + jerry_code_point_print (code_point); +} /* jerry_print_codepoint_wrapper */ /** - * Print the argument string in utf8 encoding using jerry_port_print_char. + * Print the argument string in utf8 encoding using jerry_port_string_print. * If the argument is not a string, the function does nothing. * * @param value the input string value @@ -3115,7 +3160,7 @@ jerry_print_char_wrapper (uint8_t byte, void *user_p) void jerry_string_print (const jerry_value_t value) { - jerry_string_iterate (value, JERRY_ENCODING_UTF8, &jerry_print_char_wrapper, NULL); + jerry_string_iterate_code_point (value, &jerry_print_codepoint_wrapper, NULL); } /* jerry_string_print */ /** diff --git a/jerry-core/include/jerryscript-core.h b/jerry-core/include/jerryscript-core.h index 51056d9137..c2cb763cb1 100644 --- a/jerry-core/include/jerryscript-core.h +++ b/jerry-core/include/jerryscript-core.h @@ -458,6 +458,10 @@ void jerry_string_iterate (const jerry_value_t value, jerry_encoding_t encoding, jerry_string_iterate_cb_t callback, void *user_p); +void jerry_string_iterate_code_point (const jerry_value_t value, + jerry_string_iterate_code_point_cb_t callback, + void *user_p); +void jerry_code_point_print (uint32_t code_point); void jerry_string_print (const jerry_value_t value); /** * jerry-api-string-op @} diff --git a/jerry-core/include/jerryscript-port.h b/jerry-core/include/jerryscript-port.h index 91bb3fe398..b5c46a9cdb 100644 --- a/jerry-core/include/jerryscript-port.h +++ b/jerry-core/include/jerryscript-port.h @@ -178,16 +178,17 @@ struct jerry_context_t *jerry_port_get_current_context (void); void jerry_port_sleep (uint32_t sleep_time); /** - * Print a single character. + * Print a zero-terminated UTF-8 string with length to standard output. * * Note: * This port function is here so the jerry-ext components would have * a common way to print out information. * If possible do not use from the jerry-core. * - * @param c the character to print. + * @param s The zero-terminated UTF-8 string to print + * @param len The length of the UTF-8 string. */ -void jerry_port_print_char (char c); +void jerry_port_string_print (const char *s, size_t len); /** * Open a source file and read its contents into a buffer. diff --git a/jerry-core/include/jerryscript-types.h b/jerry-core/include/jerryscript-types.h index 4c12fb437f..2cf4a24d63 100644 --- a/jerry-core/include/jerryscript-types.h +++ b/jerry-core/include/jerryscript-types.h @@ -320,6 +320,11 @@ typedef void (*jerry_throw_cb_t) (const jerry_value_t exception_value, void *use */ typedef void (*jerry_string_iterate_cb_t) (uint8_t byte, void *user_p); +/** + * Function type applied each unicode code point of a string + */ +typedef void (*jerry_string_iterate_code_point_cb_t) (uint32_t code_point, void *user_p); + /** * Function type applied for each data property of an object. */ diff --git a/jerry-ext/handler/handler-print.c b/jerry-ext/handler/handler-print.c index c220ba4deb..41cbd990a8 100644 --- a/jerry-ext/handler/handler-print.c +++ b/jerry-ext/handler/handler-print.c @@ -22,7 +22,7 @@ * Provide a 'print' implementation for scripts. * * The routine converts all of its arguments to strings and outputs them - * char-by-char using jerry_port_print_char. + * by using jerry_code_point_print and jerry_string_print. * * The NUL character is output as "\u0000", other characters are output * bytewise. @@ -32,7 +32,7 @@ * output. This allows more flexibility but also extends the core * JerryScript engine port API. Applications that want to use * `jerryx_handler_print` must ensure that their port implementation also - * provides `jerry_port_print_char`. + * provides `jerry_port_string_print`. * * @return undefined - if all arguments could be converted to strings, * error - otherwise. @@ -68,13 +68,13 @@ jerryx_handler_print (const jerry_call_info_t *call_info_p, /**< call informatio if (arg_index > 0) { - jerry_port_print_char (' '); + jerry_code_point_print (' '); } jerry_string_print (str_val); jerry_value_free (str_val); } - jerry_port_print_char ('\n'); + jerry_code_point_print ('\n'); return ret_val; } /* jerryx_handler_print */ diff --git a/jerry-port/default/default-io.c b/jerry-port/default/default-io.c index 05788d59a4..3059f42e92 100644 --- a/jerry-port/default/default-io.c +++ b/jerry-port/default/default-io.c @@ -21,6 +21,10 @@ #include "jerryscript-port-default.h" #include "jerryscript-port.h" +#ifdef _WIN32 +#include +#endif /* _WIN32 */ + /** * Actual log level */ @@ -80,30 +84,44 @@ jerry_port_log (jerry_log_level_t level, /**< message log level */ } } /* jerry_port_log */ -#if defined(JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) - -#define DEBUG_BUFFER_SIZE (256) -static char debug_buffer[DEBUG_BUFFER_SIZE]; -static int debug_buffer_index = 0; - -#endif /* defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) */ - /** - * Default implementation of jerry_port_print_char. Uses 'putchar' to - * print a single character to standard output. + * Default implementation of jerry_port_string_print. + * On win32 use WriteConsoleW and WriteFile to print UTF-8 string to standard output. + * On non-win32 os use fwrite to print UTF-8 string to standard output. + * + * @param s The zero-terminated UTF-8 string to print + * @param len The length of the UTF-8 string. */ void -jerry_port_print_char (char c) /**< the character to print */ +jerry_port_string_print (const char *s, size_t len) { - putchar (c); - -#if defined(JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) - debug_buffer[debug_buffer_index++] = c; - - if ((debug_buffer_index == DEBUG_BUFFER_SIZE) || (c == '\n')) +#ifdef _WIN32 + HANDLE hOut = GetStdHandle (STD_OUTPUT_HANDLE); + if (hOut != INVALID_HANDLE_VALUE) { - jerry_debugger_send_output ((jerry_char_t *) debug_buffer, (jerry_size_t) debug_buffer_index); - debug_buffer_index = 0; + int hType = GetFileType (hOut); + if (FILE_TYPE_CHAR == hType) + { + DWORD charsWritten = -1; + JERRY_VLA (wchar_t, ws, (len + 1)); + int utf16_count = MultiByteToWideChar (CP_UTF8, 0, s, (int) len, ws, (int) (len + 1)); + ws[utf16_count] = '\0'; + WriteConsoleW (hOut, ws, utf16_count, &charsWritten, 0); + } + else + { + WriteFile (hOut, s, len, NULL, NULL); + } } + else + { + fwrite (s, 1, len, stdout); + } +#else /* !_WIN32 */ + fwrite (s, 1, len, stdout); +#endif /* _WIN32 */ + +#if defined(JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) + jerry_debugger_send_output ((const jerry_char_t *) s, (jerry_size_t) len); #endif /* defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) */ -} /* jerry_port_print_char */ +} /* jerry_port_string_print */ diff --git a/targets/baremetal-sdk/esp-idf/jerry_port.c b/targets/baremetal-sdk/esp-idf/jerry_port.c index 2c0e7b4796..ec77801e78 100644 --- a/targets/baremetal-sdk/esp-idf/jerry_port.c +++ b/targets/baremetal-sdk/esp-idf/jerry_port.c @@ -114,24 +114,24 @@ static int debug_buffer_index = 0; #endif /* defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) */ /** - * Default implementation of jerry_port_print_char. Uses 'putchar' to - * print a single character to standard output. + * Provide implementation of jerry_port_string_print. + * Uses 'putchar' to print each utf8 string characters to standard output one by one. + * + * @param s The zero-terminated UTF-8 string to print + * @param len The length of the UTF-8 string. */ void -jerry_port_print_char (char c) /**< the character to print */ +jerry_port_string_print (const char *s, size_t len) { - putchar(c); - -#if defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) - debug_buffer[debug_buffer_index++] = c; - - if ((debug_buffer_index == DEBUG_BUFFER_SIZE) || (c == '\n')) + for (size_t i = 0; i < len; ++i) { - jerry_debugger_send_output ((jerry_char_t *) debug_buffer, (jerry_size_t) debug_buffer_index); - debug_buffer_index = 0; + putchar (s[i]); } + +#if defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) + jerry_debugger_send_output ((const jerry_char_t *) s, (jerry_size_t) len); #endif /* defined (JERRY_DEBUGGER) && (JERRY_DEBUGGER == 1) */ -} /* jerry_port_print_char */ +} /* jerry_port_string_print */ /** * Default implementation of jerry_port_fatal. Calls 'abort' if exit code is diff --git a/targets/os/nuttx/jerry_port.c b/targets/os/nuttx/jerry_port.c index 6814fbad38..12cee504c6 100644 --- a/targets/os/nuttx/jerry_port.c +++ b/targets/os/nuttx/jerry_port.c @@ -150,14 +150,18 @@ jerry_port_get_current_time (void) } /* jerry_port_get_current_time */ /** - * Provide the implementation of jerry_port_print_char. - * Uses 'printf' to print a single character to standard output. + * Provide implementation of jerry_port_string_print. + * Uses 'printf' to print a zero-terminated UTF-8 string to standard output. + * + * @param s The zero-terminated UTF-8 string to print + * @param len The length of the UTF-8 string. */ void -jerry_port_print_char (char c) /**< the character to print */ +jerry_port_string_print (const char *s, size_t len) { - printf ("%c", c); -} /* jerry_port_print_char */ + (void) len; + printf ("%s", s); +} /* jerry_port_string_print */ /** * Provide implementation of jerry_port_sleep. diff --git a/targets/os/zephyr/src/jerry-port.c b/targets/os/zephyr/src/jerry-port.c index 5677821834..cc1d889185 100644 --- a/targets/os/zephyr/src/jerry-port.c +++ b/targets/os/zephyr/src/jerry-port.c @@ -149,14 +149,18 @@ jerry_port_get_current_time (void) } /* jerry_port_get_current_time */ /** - * Provide the implementation of jerry_port_print_char. - * Uses 'printf' to print a single character to standard output. + * Provide implementation of jerry_port_string_print. + * Uses 'printf' to print a zero-terminated UTF-8 string to standard output. + * + * @param s The zero-terminated UTF-8 string to print + * @param len The length of the UTF-8 string. */ void -jerry_port_print_char (char c) /**< the character to print */ +jerry_port_string_print (const char *s, size_t len) { - printf ("%c", c); -} /* jerry_port_print_char */ + (void) len; + printf ("%s", s); +} /* jerry_port_string_print */ /** * Provide implementation of jerry_port_sleep.