From ad6eb23b750569b41a77e1c9bc5b295e725ed74a Mon Sep 17 00:00:00 2001 From: Anthony Date: Mon, 29 Jul 2024 08:13:24 -0500 Subject: [PATCH] add build (code) artifacts to main --- azure/docsite/index.html | 2 +- azure/docsite/search/search_index.json | 2 +- azure/examples/balls/balls-dbg.wasm | Bin 254657 -> 254621 bytes azure/examples/dist/balls/balls-dbg.wasm | Bin 254657 -> 254621 bytes azure/examples/dist/pong/pong.wasm | Bin 31197 -> 31181 bytes azure/examples/pong/pong.wasm | Bin 31197 -> 31181 bytes examples/pong/pong.wasm | Bin 31197 -> 31181 bytes 7 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azure/docsite/index.html b/azure/docsite/index.html index 4542e666..bc9d82a2 100644 --- a/azure/docsite/index.html +++ b/azure/docsite/index.html @@ -1348,7 +1348,7 @@

Learn WebAssembly with twr-wasm
Documentation and Examples

Easier C/C++ WebAssembly

-

Version 2.3.0

+

Version 2.3.1

twr-wasm is a simple, lightweight and easy to use library for building C/C++ WebAssembly code directly with clang. It solves some common use cases with less work than the more feature rich emscripten.

twr-wasm is easy to understand, and has some great features. You can call blocking functions. You can input and print streaming character i/o to a <div> tag, use a <canvas> element as an ANSI terminal, and use 2D drawing apis (that are compatible with JavaScript Canvas APIs) to draw to a <canvas> element.

twr-wasm allows you to run C/C++ code in a web browser. Legacy code, libraries, full applications, or single functions can be integrated with JavaScript and TypeScript.

diff --git a/azure/docsite/search/search_index.json b/azure/docsite/search/search_index.json index 91c283c6..e9122ee7 100644 --- a/azure/docsite/search/search_index.json +++ b/azure/docsite/search/search_index.json @@ -1 +1 @@ -{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Learn WebAssembly with twr-wasmDocumentation and Examples","text":""},{"location":"#easier-cc-webassembly","title":"Easier C/C++ WebAssembly","text":"

Version 2.3.0

twr-wasm is a simple, lightweight and easy to use library for building C/C++ WebAssembly code directly with clang. It solves some common use cases with less work than the more feature rich emscripten.

twr-wasm is easy to understand, and has some great features. You can call blocking functions. You can input and print streaming character i/o to a <div> tag, use a <canvas> element as an ANSI terminal, and use 2D drawing apis (that are compatible with JavaScript Canvas APIs) to draw to a <canvas> element.

twr-wasm allows you to run C/C++ code in a web browser. Legacy code, libraries, full applications, or single functions can be integrated with JavaScript and TypeScript.

twr-wasm is designed to be used with the standard llvm clang compiler and tools.

twr-wasm was previously named tiny-wasm-runtime.

"},{"location":"#live-webassembly-examples-and-source","title":"Live WebAssembly Examples and Source","text":"Name View Live Link Source Link Bouncing Balls (C++) View bouncing balls Source for balls Pong (C++) View Pong Source for Pong Maze Gen/Solve (Win32 C Port) View live maze Source for maze Input/Output with <div> View square demo Source Mini-Terminal (hello world using <canvas>) View demo Source CLI using libc++ and <canvas>) View console Source"},{"location":"#key-features","title":"Key Features","text":""},{"location":"#hello-world","title":"Hello World","text":"

Here is the simplest twr-wasm example.

helloworld.c
#include <stdio.h>\n\nvoid hello() {\n    printf(\"hello, world!\\n\");\n}\n
index.html
<head>\n   <title>Hello World</title>\n</head>\n<body>\n   <div id=\"twr_iodiv\"></div>\n\n   <script type=\"module\">\n      import {twrWasmModule} from \"twr-wasm\";\n\n      const mod = new twrWasmModule();\n      await mod.loadWasm(\"./helloworld.wasm\");\n      await mod.callC([\"hello\"]);\n   </script>\n</body>\n
"},{"location":"#on-github","title":"On Github","text":"

https://github.com/twiddlingbits/twr-wasm

"},{"location":"#why","title":"Why?","text":"

The Wasm Runtime Limitations section explains why a library like twr-wasm is needed to use WebAssembly.

"},{"location":"#version-2-vs-1","title":"Version 2 vs. 1","text":""},{"location":"#version-2-limitations","title":"Version 2 Limitations","text":""},{"location":"#post-feedback","title":"Post Feedback","text":"

Please post feedback (it worked for you, didn't work, requests, questions, etc) at https://github.com/twiddlingbits/twr-wasm/

"},{"location":"api/api-c-con/","title":"WebAssembly Console API","text":"

twr-wasm for WebAssembly provides a console API for abstracting I/O. This console API is used by stdin, stdout, and stderr, as well as the ANSI Terminal. Streaming and Windowed I/O is supported.

This section describes the C character based input/output console API this is abstracted by struct IoConsole.

Consoles can be \"tty\" aka \"streamed\", or they can be \"windowed\" (aka a \"terminal\").

Also see stdio

"},{"location":"api/api-c-con/#examples","title":"Examples","text":"Name View Live Link Source Link \"terminal\" in/out with a <canvas> View mini-term demo Source"},{"location":"api/api-c-con/#getting-stderr-stdin-stdout","title":"Getting stderr, stdin, stdout","text":"

stdio.h defines stdin, stdout, stderr as explained here: stdio

stdio.h also defines FILE like this:

typedef struct IoConsole FILE; \n

from <stdio.h>:

#define stderr (FILE *)(twr_get_stderr_con())\n#define stdin (FILE *)(twr_get_stdio_con())\n#define stdout (FILE *)(twr_get_stdio_con())\n

"},{"location":"api/api-c-con/#getting-a-new-console","title":"Getting a new console","text":"

stdin and stdout are set as explaind here. However, in unusual cases you might want to access the various consoles directly, regardless of how stdin, stdout, or stderr are set. You can do so like this:

"},{"location":"api/api-c-con/#io_nullcon","title":"io_nullcon","text":"

Returns an IoConsole that goes to the bit bucket. io_getc32 will return 0.

#include \"twr-io.h\"\n\nstruct IoConsole* io_nullcon(void);\n
"},{"location":"api/api-c-con/#twr_debugcon","title":"twr_debugcon","text":"

Returns an IoConsole that goes to the browser's debug console.

#include \"twr-crt.h\"\n\nstruct IoConsole* twr_debugcon(void);\n
"},{"location":"api/api-c-con/#twr_divcon","title":"twr_divcon","text":"

Returns an IoConsole that goes to <div id=\"twr_iodiv\">, if it exists.

#include \"twr-crt.h\"\n\nstruct IoConsole* twr_divcon(void);\n
"},{"location":"api/api-c-con/#twr_windowcon","title":"twr_windowcon","text":"

Returns an IoConsole that goes to <canvas id=\"twr_iocanvas\"> , if it exists.

NOTE: Only one call can be made to this function, and it is usually made by the twr-wasm C runtime, so you likely won't call this function.

#include \"twr-crt.h\"\n\nstruct IoConsole* twr_windowcon(void);\n
"},{"location":"api/api-c-con/#io-console-functions","title":"IO Console Functions","text":""},{"location":"api/api-c-con/#io_putc","title":"io_putc","text":"

Sends a byte to an IoConsole and supports the current locale's character encoding. This function will \"stream\" using the current code page. In other words, if you io_putc ASCII, it will work as \"normal\". If the current locale is set to 1252, then you can send windows-1252 encoded characters. If the current locale is UTF-8, then you can stream UTF-8 (that is, call io_putc once for each byte of the multi-byte UTF-8 character).

Note that when characters are sent to the browser console using stderr they will not render to the console until a newline, return, or ASCII 03 (End-of-Text) is sent.

#include \"twr-io.h\"\n\nvoid io_putc(struct IoConsole* io, unsigned char c);\n
"},{"location":"api/api-c-con/#io_putstr","title":"io_putstr","text":"

Calls io_putc for each byte in the passed string.

#include \"twr-io.h\"\n\nvoid io_putstr(struct IoConsole* io, const char* s);\n
"},{"location":"api/api-c-con/#io_printf","title":"io_printf","text":"

Identical to fprintf, however io_printf will call io_begin_draw and io_end_draw around its drawing activities -- resulting in snapper performance.

For example:

#include \"twr-io.h\"\n\nio_printf(twr_debugcon(), \"hello over there in browser debug console land\\n\");\n

or

#include <stdio.h>\n#include <twr_io.h>\n\nio_printf(stdout, \"hello world\\n\");\n
#include <twr_io.h>\n\nvoid io_printf(struct IoConsole *io, const char *format, ...);\n
"},{"location":"api/api-c-con/#io_getc32","title":"io_getc32","text":"

Waits for the user to enter and then returns a unicode code point. Currently only really works with an IoConsole that is stdin.

To return characters encoded with the current locale, see io_mbgetc

#include <twr_io.h>\n\nint io_getc32(struct IoConsole* io);\n
"},{"location":"api/api-c-con/#io_mbgetc","title":"io_mbgetc","text":"

io_mbgetc will get a character from stdin and encode it using the character encoding of the LC_CTYPE category of the current locale. \"C\" will use ASCII. UTF-8 and windows-1252 are also supported.

#include <twr_io.h>\n\nvoid io_mbgetc(struct IoConsole* io, char* strout);\n
"},{"location":"api/api-c-con/#io_mbgets","title":"io_mbgets","text":"

Gets a string from an IoConsole (which needs to be stdin). Returns when the user presses \"Enter\". Displays a cursor character and echos the inputted characters, at the current cursor position. Uses character encoding of LC_TYPE of current locale.

#include <twr_io.h>\n\nchar *io_mbgets(struct IoConsole* io, char *buffer );\n
"},{"location":"api/api-c-con/#io_get_cursor","title":"io_get_cursor","text":"

Returns an integer of the current cursor position. The cursor is where the next io_putc is going to go.

For windowed consoles, the cursor position ranges from [0, width*height-1], inclusive.

#include <twr_io.h>\n\nint io_get_cursor(struct IoConsole* io);\n
"},{"location":"api/api-c-con/#io_set_colors","title":"io_set_colors","text":"

For windowed consoles only.

Sets a 24 bit RGB default color for the foreground and background. The prior default colors are changed (lost). For example, if you set the default colors when you created the window (see stdio), the defaults will no longer be active. Use io_get_colors to save existing colors for later restoration using io_set_colors.

A call to io_set_colors doesn't actually cause any on screen changes. Instead, these new default colors are used in future draw and text calls. A foreground and background color is set for each cell in the console window. The cell's colors are set to these default foreground/background colors when a call to io_setc, io_setreset, etc is made.

#include <twr_io.h>\n\nvoid io_set_colors(struct IoConsole* io, unsigned long foreground, unsigned long background);\n
"},{"location":"api/api-c-con/#io_get_colors","title":"io_get_colors","text":"

For windowed consoles only.

Gets the current default colors.

#include <twr_io.h>\n\nvoid io_get_colors(struct IoConsole* io, unsigned long *foreground, unsigned long *background);\n
"},{"location":"api/api-c-con/#io_cls","title":"io_cls","text":"

For windowed consoles only.

Clears the screen. That is, all character cells in the window are set to a space, their colors are reset to the current default colors (see io_set_colors).

#include <twr_io.h>\n\nvoid io_cls(struct IoConsoleWindow* iow);\n
"},{"location":"api/api-c-con/#io_setc","title":"io_setc","text":"

For windowed consoles only.

Sets a window cell to a character. Sends a byte to an IoConsole and supports the current locale's character encoding. This function will \"stream\" using the current code page. In other words, if you io_setc ASCII, it will work as \"normal\". If the current locale is set to 1252, then you can send windows-1252 encoded characters. If the current locale is UTF-8, then you can stream UTF-8 (that is, call io_setc once for each byte of the multi-byte UTF-8 character).

#include <twr_io.h>\n\nbool io_setc(struct IoConsoleWindow* iow, int location, unsigned char c);\n
"},{"location":"api/api-c-con/#io_setc32","title":"io_setc32","text":"

For windowed consoles only.

Sets a window cell to a unicode code point. The colors are set to the defaults (see io_set_colors).

#include <twr_io.h>\n\nvoid io_setc32(struct IoConsoleWindow* iow, int location, int c);\n
"},{"location":"api/api-c-con/#io_setreset","title":"io_setreset","text":"

For windowed consoles only.

Sets or resets (clears) a chunky graphics \"pixel\". Each character cell can also be a 2x3 grid of graphic \"pixels\". In other words, the terminal window has pixel dimensions of width2 x height3.

The color will be set to the defaults if the impacted cell is not a graphics cell. If it is an existing graphics cell, the colors don't change.

See the stdio-canvas example.

#include <twr_io.h>\n\nbool io_setreset(struct IoConsoleWindow* iow, int x, int y, bool isset);\n
"},{"location":"api/api-c-con/#io_point","title":"io_point","text":"

For windowed consoles only.

Checks if a chunky graphics \"pixel\" is set or clear. See io_setreset.

#include <twr_io.h>\n\nbool io_point(struct IoConsoleWindow* iow, int x, int y);\n
"},{"location":"api/api-c-con/#io_set_cursor","title":"io_set_cursor","text":"

Moves the cursor. See io_get_cursor.

#include <twr_io.h>\n\nvoid io_set_cursor(struct IoConsoleWindow* iow, int loc);\n
"},{"location":"api/api-c-con/#io_begin_draw","title":"io_begin_draw","text":"

For windowed consoles only.

This call (and its matching io_end_draw) are not required. But if you bracket any call sequence that draws to the terminal window with an io_begin_draw and io_end_draw, the updates will be batched into one update. This will increase performance and usually prevents the user from seeing partial updates.

io_begin_draw can be nested.

See the stdio-canvas example.

#include <twr_io.h>\n\nvoid io_begin_draw(struct IoConsole* io);\n
"},{"location":"api/api-c-con/#io_end_draw","title":"io_end_draw","text":"

For windowed consoles only.

See io_begin_draw.

#include <twr_io.h>\n\nvoid io_end_draw(struct IoConsole* io);\n
"},{"location":"api/api-c-d2d/","title":"2D Draw C API for WebAssembly","text":"

This section describes twr-wasm's C D2D API, which allows your WebAssembly module to call many of the JavaScript Canvas APIs. There is also a C++ canvas wrapper class in source/twr-cpp used by the balls and pong examples.

"},{"location":"api/api-c-d2d/#examples","title":"Examples","text":"Name View Live Link Source Link Bouncing Balls (C++) View bouncing balls Source for balls Pong (C++) View Pong Source for Pong Maze (Win32 C Port) View live maze here Source for maze"},{"location":"api/api-c-d2d/#overview","title":"Overview","text":"

To create a canvas surface that you can draw to using the twr-wasm 2D C drawing APIs, add a canvas tag to your HTML named twr_d2dcanvas like this example (you can use any width/height you like):

<canvas id=\"twr_d2dcanvas\" width=\"600\" height=\"600\"></canvas>\n

To draw using the C 2D Draw API:

Commands are queued until flushed -- which will take the batch of queued draw commands, and execute them. The 2D draw APIs will work with either twrWasmModule or twrWasmModuleAsync. With twrWasmModuleAsync, the batch of commands is sent from the worker thread over to the JavaScript main thread for execution. By batching the calls between calls to d2d_start_draw_sequence and d2d_end_draw_sequence, performance is improved.

d2d_flush waits for the commands to finish execution before returning. d2d_flush is called automatically by d2d_end_draw_sequence and so you generally don't need to call it manually.

You pass an argument to d2d_start_draw_sequence specifying how many instructions will trigger an automatic call to d2d_flush. You can make this larger for efficiency, or smaller if you want to see the render progress more frequently. There is no limit on the size of the queue, except memory used in the Wasm module. The d2d_flush function can be called manually call, but this is not normally needed, unless you would like to ensure a sequence renders before your d2d_end_draw_sequence is called, or before the count passed d2d_start_draw_sequence is met.

If you are using twrWasmModuleAsync, or if you are re-rendering the entire frame for each animation update, you should ensure that all of your draws for a complete frame are made without an explicit or implicit call to d2d_flush in the middle of the draw sequence, as this may cause flashing.

"},{"location":"api/api-c-d2d/#functions","title":"Functions","text":"

These are the Canvas APIs currently available in C:

struct d2d_draw_seq* d2d_start_draw_sequence(int flush_at_ins_count);\nvoid d2d_end_draw_sequence(struct d2d_draw_seq* ds);\nvoid d2d_flush(struct d2d_draw_seq* ds);\nint d2d_get_canvas_prop(const char* prop);\n\nvoid d2d_fillrect(struct d2d_draw_seq* ds, double x, double y, double w, double h);\nvoid d2d_strokerect(struct d2d_draw_seq* ds, double x, double y, double w, double h);\nvoid d2d_filltext(struct d2d_draw_seq* ds, const char* str, double x, double y);\nvoid d2d_fillcodepoint(struct d2d_draw_seq* ds, char c, double x, double y);\n\nvoid d2d_measuretext(struct d2d_draw_seq* ds, const char* str, struct d2d_text_metrics *tm);\nvoid d2d_save(struct d2d_draw_seq* ds);\nvoid d2d_restore(struct d2d_draw_seq* ds);\n\nvoid d2d_setlinewidth(struct d2d_draw_seq* ds, double width);\nvoid d2d_setfillstylergba(struct d2d_draw_seq* ds, unsigned long color);\nvoid d2d_setstrokestylergba(struct d2d_draw_seq* ds, unsigned long color);\nvoid d2d_setfillstyle(struct d2d_draw_seq* ds, const char* css_color);\nvoid d2d_setstrokestyle(struct d2d_draw_seq* ds, const char* css_color);\nvoid d2d_setfont(struct d2d_draw_seq* ds, const char* font);\n\nvoid d2d_createlineargradient(struct d2d_draw_seq* ds, long id, double x0, double y0, double x1, double y1);\nvoid d2d_createradialgradient(struct d2d_draw_seq* ds, long id, double x0, double y0, double radius0, double x1, double y1, double radius1);\nvoid d2d_addcolorstop(struct d2d_draw_seq* ds, long gradID, long position, const char* csscolor);\nvoid d2d_setfillstylegradient(struct d2d_draw_seq* ds, long gradID);\nvoid d2d_releaseid(struct d2d_draw_seq* ds, long id);\n\nvoid d2d_beginpath(struct d2d_draw_seq* ds);\nvoid d2d_fill(struct d2d_draw_seq* ds);\nvoid d2d_stroke(struct d2d_draw_seq* ds);\nvoid d2d_moveto(struct d2d_draw_seq* ds, double x, double y);\nvoid d2d_lineto(struct d2d_draw_seq* ds, double x, double y);\nvoid d2d_arc(struct d2d_draw_seq* ds, double x, double y, double radius, double start_angle, double end_angle, bool counterclockwise);\nvoid d2d_bezierto(struct d2d_draw_seq* ds, double cp1x, double cp1y, double cp2x, double cp2y, double x, double y);\n\nvoid d2d_imagedata(struct d2d_draw_seq* ds, long id, void*  mem, unsigned long length, unsigned long width, unsigned long height);\nvoid d2d_putimagedata(struct d2d_draw_seq* ds, long id, unsigned long dx, unsigned long dy);\nvoid d2d_putimagedatadirty(struct d2d_draw_seq* ds, long id, unsigned long dx, unsigned long dy, unsigned long dirtyX, unsigned long dirtyY, unsigned long dirtyWidth, unsigned long dirtyHeight);\n

d2d_measuretext() returns this structure:

struct d2d_text_metrics {\n    double actualBoundingBoxAscent;\n    double actualBoundingBoxDescent;\n    double actualBoundingBoxLeft;\n    double actualBoundingBoxRight;\n    double fontBoundingBoxAscent;\n    double fontBoundingBoxDescent;\n    double width;\n};\n

d2d_get_canvas_prop() returns a value of:

export interface ICanvasProps {\n   charWidth: number,\n   charHeight: number,\n   foreColor: number,\n   backColor: number,\n   widthInChars: number,\n   heightInChars: number,\n   canvasWidth:number,\n   canvasHeight:number\n}\n
"},{"location":"api/api-c-general/","title":"General C API for Wasm","text":""},{"location":"api/api-c-general/#overview","title":"Overview","text":"

This sections describes the \"general\" twr-wasm functions available that don't fit neatly into another category (such as standard C library functions, Draw 2D functions, etc.)

These functions often start with \"twr_\" and are generally found in this include file:

\\twr-wasm\\include\\twr-crt.h

"},{"location":"api/api-c-general/#bzero","title":"bzero","text":"

Set a block of memory to zeros. Calls memset(to, 0, count).

#include <string.h>\n\nvoid bzero (void *to, size_t count);\n
"},{"location":"api/api-c-general/#getc","title":"getc","text":"

This is the standard c library function (see the the standard library docs available on the internet).

Of note this function will return extended ASCII (128-255 inclusive). The extend ASCII are always encoded with Windows-1252 encoding.

See twr_getc32 for a list of related functions.

Note that C character input is blocking and you must use twrWasmModuleAsync -- see stdin for details on how to enable blocking character input.

"},{"location":"api/api-c-general/#twr_atod","title":"twr_atod","text":"

Similar to stdlib atof.

#include \"twr-crt.h\"\n\ndouble twr_atod(const char* str);\n
"},{"location":"api/api-c-general/#twr_atou64","title":"twr_atou64","text":"

Convert a string to a 64 bit unsigned integer, stopping when the first non-valid character is encountered. If len is provided, it will be set to the number of characters read. Radix should be >=2 and <=36 -- for example, 10 is a normal base 10 number and 16 is hexadecimal.

#include \"twr-crt.h\"\n\nint64_t twr_atou64(const char *str, int* len, int radix);\n
"},{"location":"api/api-c-general/#twr_dtoa","title":"twr_dtoa","text":"

The functions to convert double to text are snprintf, fcvt_s,twr_dtoa, twr_toexponential, and twr_tofixed

#include \"twr-crt.h\"\n\nvoid twr_dtoa(char* buffer, int sizeInBytes, double value, int max_precision);\n
"},{"location":"api/api-c-general/#twr_cache_mallocfree","title":"twr_cache_malloc/free","text":"

These functions keep allocated memory in a cache for much faster re-access than the standard malloc/free.

#include \"twr-crt.h\"\n\nvoid *twr_cache_malloc(twr_size_t size);\nvoid twr_cache_free(void* mem);\n
"},{"location":"api/api-c-general/#twr_code_page_to_utf32_streamed","title":"twr_code_page_to_utf32_streamed","text":"

Return a unicode code point (aka utf-32 value) when passed a byte stream that represents an encoded character using the current local's LC_CTYPE code page. A zero is returned if the byte stream has not yet completed a decode.

For example:

int cp\n\nsetlocale(LC_ALL, \"\");  // set to default locale, which will be UTF-8 encoding with local language/region\n\n// turn a UTF-8 Euro into a UTF-32 value\ncp==twr_code_page_to_utf32_streamed(0xE2);\nassert (cp==0);\ncp=twr_code_page_to_utf32_streamed(0x82);\nassert (cp==0);\ncp=twr_code_page_to_utf32_streamed(0xAC);\nassert (cp==0x000020AC);   // Euro Code points\n
#include <locale.h>\n\nint twr_code_page_to_utf32_streamed(unsigned char byte) \n
"},{"location":"api/api-c-general/#twr_conlog","title":"twr_conlog","text":"

twr_conlog prints debug messages to the browser console from your C code.

#include \"twr-crt.h\"\n\nvoid twr_conlog(char* format, ...);\n

Each call to twr_conlog() will generate a single call to console.log() in JavaScript to ensure that you see debug prints. This call is identical to printf, except that it adds a newline.

The current implementation does not wait for the debug string to output to the console before returning from twr_conlog, when using twrWasmModuleAsync. In this case, it can take a small bit of time for the string to make its way across the Worker Thread boundary. This is normally not a problem and results in faster performance. But if your code crashes soon after the debug print, the print might not appear. If you think this is an issue, you can call twr_sleep(1) after your twr_conlog call. This will force a blocking wait for the print to print.

Prior to 1.0, this function was called twr_dbg_printf, and operated slightly differently.

"},{"location":"api/api-c-general/#twr_epoch_timems","title":"twr_epoch_timems","text":"

Returns the number of milliseconds since the start of the epoch.

#include \"twr-wasm.h\"\n\nuint64_t twr_epoch_timems();\n

"},{"location":"api/api-c-general/#twr_getc32","title":"twr_getc32","text":"

Gets a 32 bit unicode code point character from stdin. Unlike the standard C library function getchar, twr_getc32 does not buffer a line (that is, twr_getc32 will return a character before the user presses Enter).

twr_getc32 is implemented as:

int twr_getc32() {\n    return io_getc32(twr_get_stdio_con());\n}\n

Note that stdlib getchar and ungetc are not currently implemented.

Note that C character input is blocking and you must use twrWasmModuleAsync -- see stdin for details on how to enable blocking character input.

Also see:

#include \"twr-crt.h\"\n\nint twr_getc32();\n
"},{"location":"api/api-c-general/#twr_get_navlang","title":"twr_get_navlang","text":"

Returns the BCP 47 language tag as found in javacript navigator.language. If len is not null, it will be filled in with the string length of the language tag.

#include \"twr-crt.h\"\n\nconst char* twr_get_navlang(int *len);\n
"},{"location":"api/api-c-general/#twr_get_current_locale","title":"twr_get_current_locale","text":"
extern inline locale_t twr_get_current_locale(void);\n

twr_get_current_locale will return the locale that has been set by setlocale. It can be used to pass to a function that takes a locale_t.

"},{"location":"api/api-c-general/#twr_localize_numeric_string","title":"twr_localize_numeric_string","text":"

Functions like twr_dtoa do not localize the decimal point. To get a localized decimal point, you can use printf, or alternately twr_localize_numeric_string to post process a string. For example:

char b[10];\nstrcpy(b, \"1.23\");\ntwr_localize_numeric_string(b, twr_get_current_locale());\n// if locale was set to french, then b is now 1,23\n
#include <locale.h>\n\nvoid twr_localize_numeric_string(char* str, locale_t locale);\n
"},{"location":"api/api-c-general/#twr_mem_debug_stats","title":"twr_mem_debug_stats","text":"

Print memory map and malloc stats to stderr or stdout.

(note FILE * is the same as struct IoConsole*)

#include <stdio.h>\n\nvoid twr_mem_debug_stats(struct IoConsole* outcon);\n
"},{"location":"api/api-c-general/#twr_mbgets","title":"twr_mbgets","text":"

Gets a string from stdin. The string will be in the current locale's character encoding -- ASCII for \"C\", and either UTF-8 or windows-1252 for \"\". See localization.

#include \"twr-crt.h\"\n\nchar* twr_mbgets(char* buffer);\n

Internally this function uses the stdio IoConsole -- see the IoConsole section for more advanced input/output.

This function will encode characters as specified by the LC_CTYPE category of the current locale. ASCII is used for \"C\", and UTF-8 and Windows-1252 are also supported (see localization)

Note that C character input is blocking and you must use twrWasmModuleAsync -- see stdin for details on how to enable blocking character input.

"},{"location":"api/api-c-general/#twr_mbslen_l","title":"twr_mbslen_l","text":"

Returns the number of characters in a string using the character encoding of the passed locale (ASCII for \"C\", UTF-8, or windows-1252 for \"\"). You can use twr_get_current_locale to find the current locale.

#include <string.h>\n\nsize_t twr_mbslen_l(const char *str, locale_t locale);\n

"},{"location":"api/api-c-general/#twr_sleep","title":"twr_sleep","text":"

twr_sleep is a traditional blocking sleep function. This function is blocking, and so is only available if you use twrWasmModuleAsync.

#include \"twr-wasm.h\"\n\nvoid twr_sleep(int ms);\n
"},{"location":"api/api-c-general/#twr_tofixed","title":"twr_tofixed","text":"

This function is identical to its JavaScript version.

#include \"twr-wasm.h\"\n\nvoid twr_tofixed(char* buffer, int buffer_size, double value, int dec_digits);\n

The functions to convert double to text are snprintf, fcvt_s,twr_dtoa, twr_toexponential, and twr_tofixed

"},{"location":"api/api-c-general/#twr_toexponential","title":"twr_toexponential","text":"

This function is identical to its JavaScript version.

#include \"twr-wasm.h\"\n\nvoid twr_toexponential(char* buffer, int buffer_size, double value, int dec_digits);\n

The functions to convert double to text are snprintf, fcvt_s,twr_dtoa, twr_toexponential, and twr_tofixed

"},{"location":"api/api-c-general/#twr_strhorizflip","title":"twr_strhorizflip","text":"

Mirror image the passed in string.

#include \"twr-crt.h\"\n\nvoid twr_strhorizflip(char * buffer, int n);\n

"},{"location":"api/api-c-general/#twr_utf8_char_len","title":"twr_utf8_char_len","text":"

Returns the number of bytes in a UTF-8 character (passed as a string pointer). UTF-8 characters can be 1 to 4 bytes in length.

#include <string.h>\n\nint twr_utf8_char_len(const char *str);\n

"},{"location":"api/api-c-general/#twr_utf32_to_code_page","title":"twr_utf32_to_code_page","text":"

Takes a utf32 value (aka unicode code point value), and fills in the passed character array buffer with the character encoding of the utf32 value, using the current locale's LC_CTYPE code page. The buffer is 0 terminated.

Also see c32rtomb and c16rtomb.

For example:

char strbuf[6];             // max size of utf-8 is 4+terminating zero.  Max size of ASCII or windows 1252 is 1 + terminating zero\nsetlocale(LC_ALL, \"\");  // set to default locale, which will be UTF-8 encoding with local language/region\ntwr_utf32_to_code_page(strbuf, 0x000020AC);  // encode a Euro code point \nprintf(\"%s\", strbuf); \nassert ( strcmp(strbuf,\"\\xE2\\x82\\xAC\")==0 );  // utf-8 encoding of euro\nassert ( strcmp(strbuf,\"\u20ac\")==0 );           // clang string literals default to utf-8 encoding\n

include <locale.h>\n\nvoid twr_utf32_to_code_page(char* out, int utf32)\n
"},{"location":"api/api-c-general/#twr_vprintf","title":"twr_vprintf","text":"

Performs a printf by calling the callback with cbdata for each character.

#include \"twr-crt.h\"\n\nvoid twr_vprintf(twr_cbprintf_callback out, void* cbdata, const char *format, va_list* args);\n

"},{"location":"api/api-c-general/#floating-math-helpers","title":"floating math helpers","text":"
int twr_isnan(double v);\nint twr_isinf(double v);\ndouble twr_nanval();\ndouble twr_infval();\n
"},{"location":"api/api-c-stdlib/","title":"Standard C library for WebAssembly","text":"

This section describes twr-wasm's support for the Standard C Library. twr-wasm includes its own implementation of the standard C library optimized for WebAssembly and Wasm running in a web browser. This is a core feature of twr-wasm.

For documentation of these functions, see the many standard C library documentation web sites.

The following subset of the standard C library is available. Also see twr-wasm/include folder for include files.

"},{"location":"api/api-c-stdlib/#stdioh","title":"stdio.h","text":"
* fprintf will only work with these -- stderr, stdin, stdout */\n/* these return 'struct IoConsole *' which is same as 'FILE *' */\n#define stderr (FILE *)(twr_get_stderr_con())\n#define stdin (FILE *)(twr_get_stdio_con())\n#define stdout (FILE *)(twr_get_stdio_con())\n\nint snprintf(char *buffer, size_t bufsz, const char *format, ... );\nint sprintf( char *buffer, const char *format, ... );\nint vsnprintf(char *buffer, size_t bufsz, const char *format, va_list vlist);\nint vasprintf(char **strp, const char* format, va_list vlist );\nint printf(const char* format, ...);\nint vprintf(const char* format, va_list vlist );\nint puts(const char *str);\nint putchar(int c);\n\ntypedef struct IoConsole FILE; \nint vfprintf(FILE *stream, const char *format, va_list vlist);\nint fprintf(FILE *stream, const char* format, ...);\nsize_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);\nint ferror(FILE *stream);\nint feof(FILE *stream);\nint fflush(FILE *stream);\nint is_terminal(FILE *stream);\nint fputc(int ch, FILE* stream);\nint putc(int ch, FILE* stream);\nint fgetc(FILE *stream );\nint getc(FILE *stream);\n
"},{"location":"api/api-c-stdlib/#stdlibh","title":"stdlib.h","text":"
void *malloc(size_t size);\nvoid free(void *mem);\nsize_t avail(void);\nvoid *realloc( void *ptr, size_t new_size );\nvoid* calloc( size_t num, size_t size );\nvoid *aligned_alloc( size_t alignment, size_t size );\n\nint rand(void);\nvoid srand(int seed);\n\n#define __min(a,b) (((a) < (b)) ? (a) : (b))\n#define __max(a,b) (((a) > (b)) ? (a) : (b))\n\nint _fcvt_s(\n   char* buffer,\n   size_t sizeInBytes,\n   double value,\n   int fracpart_numdigits,\n   int *dec,\n   int *sign\n);\ndouble atof(const char* str);\nint atoi(const char *str);\nlong atol( const char *str );\nlong long atoll( const char *str );\nlong strtol(const char *str, char **str_end, int base);\nlong long strtoll(const char *str, char **str_end, int base);\nlong long strtoll_l(const char *str, char **str_end, int base,  locale_t loc);\nunsigned long long strtoull(const char *str, char **str_end,  int base);\nunsigned long long strtoull_l(const char *str, char **str_end,  int base, locale_t loc);\nunsigned long strtoul(const char *str, char ** str_end,  int base);\nfloat strtof(const char *str, char ** str_end);\nfloat strtof_l(const char *str, char ** str_end, locale_t locale);\ndouble strtod(const char *str, char **str_end);\ndouble strtod_l(const char *str, char **str_end, locale_t locale);\nlong double strtold(const char *str, char **str_end);\nlong double strtold_l(const char *str, char **str_end, locale_t locale);\nint _itoa_s(int64_t value, char * buffer, size_t size, int radix);\n\ndiv_t div( int x, int y );\nldiv_t ldiv( long x, long y );\nlldiv_t lldiv( long long x, long long y );\n\n_Noreturn void abort(void);\nint atexit(void (*func)(void));\n

Note that _fcvt_s as currently enabled has these limitations: - fractional digits <=100 - values must be less than 1e+21 - values negative exponents must be smaller than 1e-99

There is a full featured version of _fcvt_s in the source code, but is not currently enabled, since the version enabled is smaller and works in most use cases.

"},{"location":"api/api-c-stdlib/#asserth","title":"assert.h","text":"
void assert(int expression);\n
"},{"location":"api/api-c-stdlib/#mathh","title":"math.h","text":"
int abs(int n);\ndouble acos(double arg);\ndouble asin(double arg);\ndouble atan(double arg);\ndouble ceil(double arg);\ndouble cos(double arg);\ndouble exp(double arg);\ndouble fabs(double arg);\ndouble floor(double arg);\ndouble fmod(double x, double y);\ndouble log(double arg);\ndouble pow(double base, double exp);\ndouble sin(double arg);\ndouble sqrt(double arg);\ndouble tan(double arg);\ndouble trunc(double arg);\n
"},{"location":"api/api-c-stdlib/#stdargh","title":"stdarg.h","text":"
#define va_start(v,l)   __builtin_va_start(v,l)\n#define va_end(v)   __builtin_va_end(v)\n#define va_arg(v,l) __builtin_va_arg(v,l)\n#define va_copy(d,s)    __builtin_va_copy(d,s)\ntypedef __builtin_va_list va_list;\n
"},{"location":"api/api-c-stdlib/#ctypeh","title":"ctype.h","text":"
int isascii(int);\nint toascii(int);\nint isalnum(int c);\nint isalpha(int c);\nint isblank(int);\nint iscntrl(int);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int);\nint isprint(int);\nint ispunct(int);\nint isspace(int c);\nint isupper(int);\nint isxdigit(int);\nint tolower(int c);\nint toupper(int c);\n\nint isalnum_l(int c, locale_t loc);\nint isalpha_l(int c, locale_t loc);\nint isblank_l(int c, locale_t loc);\nint iscntrl_l(int c, locale_t loc);\nint isdigit_l(int c, locale_t loc);\nint isgraph_l(int c, locale_t loc);\nint islower_l(int c, locale_t loc);\nint isprint_l(int c, locale_t loc);\nint ispunct_l(int c, locale_t loc);\nint isspace_l(int c, locale_t loc);\nint isupper_l(int c, locale_t loc);\nint isxdigit_l(int c, locale_t loc);\nint tolower_l(int c, locale_t loc);\nint toupper_l(int c, locale_t loc);\n
"},{"location":"api/api-c-stdlib/#stddefh","title":"stddef.h","text":"
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)\ntypedef __PTRDIFF_TYPE__ ptrdiff_t;\ntypedef double max_align_t;\n
"},{"location":"api/api-c-stdlib/#stringh","title":"string.h","text":"
size_t strlen(const char * str);\nchar *strdup(const char * source);\nchar *strcpy(char *dest, const char *source);\nint strcat_s(char *dest, size_t destsz, const char *src);\nchar* strcat(char *dest, const char *src);\nchar *strncpy(char *dest, const char *source, size_t count);\nint strcmp(const char* string1, const char* string2);\nint strncmp(const char* lhs, const char* rhs, size_t count);\nint stricmp(const char* string1, const char* string2);\nint strnicmp(const char* string1, const char* string2, size_t count);\nint strcoll(const char* lhs, const char* rhs);\nint strcoll_l(const char* lhs, const char* rhs,  locale_t loc);\nchar *strchr(const char *str, int ch);\nvoid *memchr(const void *ptr, int ch, size_t count);\nchar *strstr(const char *haystack, const char *needle);\nchar * strerror(int errnum );\nchar * _strerror(const char *strErrMsg);\nvoid *memmove(void *dest, const void *src, size_t n);\nint memcmp( const void* lhs, const void* rhs, size_t count );\nvoid bzero (void *to, size_t count);\n\n// implemented in memcpy.wat\nvoid *memcpy(void *dest, const void * src, size_t n);\nvoid *memset(void *mem, int c, size_t n);\n
"},{"location":"api/api-c-stdlib/#timeh","title":"time.h","text":"
typedef unsigned long time_t;\nunsigned long time(unsigned long *time);\nsize_t strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr);\nsize_t strftime_l(char *s, size_t maxsize, const char *format, const struct tm *timeptr, locale_t  locale);\nstruct tm *localtime(const time_t *timer);\nint gettimeofday(struct timeval *tv, void* notused);\n#define timerisset(tvp)     ((tvp)->tv_sec || (tvp)->tv_usec)\n#define timercmp(tvp,uvp,cmp)                   \\\n        ((tvp)->tv_sec cmp (uvp)->tv_sec ||     \\\n         ((tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec))\n#define timerclear(tvp)     (tvp)->tv_sec = (tvp)->tv_usec = 0\n
"},{"location":"api/api-c-stdlib/#localeh","title":"locale.h","text":"
#define LC_GLOBAL_LOCALE twr_get_current_locale()\nchar* setlocale(int category, const char* locale);\nstruct lconv *localeconv(void);\nlocale_t newlocale(int category_mask, const char *locale, locale_t base);\nlocale_t    uselocale(locale_t);\nvoid freelocale(locale_t);\nlocale_t duplocale(locale_t);\nextern inline locale_t twr_get_current_locale(void);\n
"},{"location":"api/api-c-stdlib/#ucharh","title":"uchar.h","text":"
typedef uint_least32_t char32_t;\ntypedef uint_least16_t char16_t;\n\nsize_t c32rtomb( char* s, char32_t c32, mbstate_t* ps );\n
"},{"location":"api/api-c-stdlib/#errnoh","title":"errno.h","text":"
typedef int errno_t;\n\nextern int * _errno(void);\n#define errno (*_errno())\n\nerrno_t  _set_errno(int _Value);\nerrno_t  _get_errno(int *_Value);\n
"},{"location":"api/api-c-stdlib/#_stdtypesh","title":"_stdtypes.h","text":"

// don't include directly -- included by various .h files

typedef unsigned long size_t;\n#define MAX_SIZE_T 2147483647  \n\n#ifdef __cplusplus\n#define NULL __null\n#else\n#define NULL ((void*)0)\n#endif\n\ntypedef struct __locale_t_struct * locale_t;\n

"},{"location":"api/api-c-stdlib/#other-include-files-available","title":"Other include files available","text":"
float.h\nlimits.h\nstdbool.h\nstdint.h\n
"},{"location":"api/api-libc%2B%2B/","title":"libc++ for WebAssembly","text":"

This section describes twr-wasm's support for using the standard c++ library libc++ with WebAssembly.

twr-wasm includes libc++ built for WebAssembly in the twr-wasm/lib-c folder.

For C++ the use of libc++ is optional. That is you can build twr-wasm projects in C++ with or without libc++.

See the examples tests-libcx and tests-user for examples of using libc++.

See the balls example for how to create a C++ WebAssembly program without the standard C++ library. The primary advantage to this approach is a bit smaller code size. You don't need to staticly link libc++.

Some of the key options twr-wasm's libc++ for WebAssembly was built with are these:

DLIBCXX_ENABLE_LOCALIZATION=ON \nDLIBCXX_ENABLE_UNICODE=ON \nDLIBCXX_ENABLE_RTTI=ON \nDLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \n\nDCMAKE_BUILD_TYPE=Release       \nDCMAKE_CXX_STANDARD=20 \n\nDLIBCXX_ENABLE_EXCEPTIONS=OFF \nDLIBCXX_ENABLE_THREADS=OFF \nDLIBCXX_ENABLE_SHARED=OFF \nDLIBCXX_ENABLE_WIDE_CHARACTERS=OFF \nDLIBCXX_ENABLE_FILESYSTEM=OFF \nDLIBCXX_ENABLE_TIME_ZONE_DATABASE=OFF \nDLIBCXX_ENABLE_MONOTONIC_CLOCK=OFF \nDLIBCXX_ENABLE_RANDOM_DEVICE=OFF\n
"},{"location":"api/api-localization/","title":"Localization Reference for twr-wasm","text":"

This section details twr-wasm's WebAssembly localization support.

Also see Introduction to Character Encoding Support with twr-wasm

"},{"location":"api/api-localization/#using-c","title":"Using C:","text":"

Standard C locale functions are supported by twr-wasm. ASCII, UTF-8 and windows-1252 encoding is supported by the twr-wasm standard C library locale. twr-wasm also includes C functions for UTF-32 support.

"},{"location":"api/api-localization/#using-c_1","title":"Using C++:","text":""},{"location":"api/api-localization/#character-encodings","title":"Character Encodings","text":"

twr-wasm C locales support ASCII, UTF-8 or windows-1252 encoding. UTF-16/32 are not supported as a std c lib locale setting, but functions are provided to convert utf-32 (unicode code points) to and from ASCII, UTF-8, and windows-1252 \"code pages\" (there are other miscellaneous utf-32 based functions as well.)

"},{"location":"api/api-localization/#locales-standard-c-library","title":"Locales (Standard C Library)","text":""},{"location":"api/api-localization/#c","title":"\"C\"","text":"

\"C\" is the default locale, as usual. When \"C\" is selected, the functions operate as usual. One subtly is that console i/o functions (such as printf) will generally function as expected with UTF-8, since the div and window consoles correctly handle UTF-8 character encoding. This is normal on some OSs, such as linux, but not the default on Windows (which often defaults to windows-1252 for backward compatibility).

isgraph style functions will only recognize ASCII characters, as is normal. Functions such as strcmp operate on the byte sequence, which will typically results in UTF-8 codes being compared lexically. strcoll will use lexical ordering.

"},{"location":"api/api-localization/#posix","title":"\"POSIX\"","text":"

\"POSIX\" is the same as \"C\"

"},{"location":"api/api-localization/#_1","title":"\"\"","text":"

\"\" is the locale to specify the users default setting (this selects the setting used by the browser). This will also enable UTF-8 in functions such as strcoll. For example, if your browser is set to \"en-US\" as its default locale, setlocale(LC_ALL, \"\") will return en-US.UTF-8.

isgraph style functions will still only recognize ASCII characters (since UTF-8 doesn't encode any single bytes greater than 127). strcoll uses locale specific ordering, and printf will use locale specific decimal points. strcmp still compares two strings lexicographically (byte-by-byte) without considering locale-specific rules, per the spec.

"},{"location":"api/api-localization/#utf-8","title":"\".UTF-8\"","text":"

\".UTF-8\" is the same as \"\" with twr-wasm.

"},{"location":"api/api-localization/#1252","title":"\".1252\"","text":"

\".1252\" will select the current default locale, but use windows-1252 character encoding (instead of UTF-8). Windows-1252 is a super set of ISO-8859-1 and is the most commonly used encoding for many european languages when unicode is not used. This mode is primarily for legacy software, backwards compatibly, and windows compatibility.

"},{"location":"api/api-localization/#others","title":"Others","text":"

Setting arbitrary locales, such as \"fr-FR\" when the browser is defaulted to another locale, is not supported.

"},{"location":"api/api-localization/#select-the-default-locale","title":"Select the default locale","text":"

To select the user's browser's default locale using the C language, and enable consistent utf-8 support, use a call like this:

setlocale(LC_ALL, \"\")\n
"},{"location":"api/api-localization/#c-and-libc-functions","title":"C and libc++ functions","text":"

If you are using twr-wasm's build of libc++, libc++ locale and unicode functions work as normal.

The usual standard C library locale support is available, along with some POSIX extensions. In addition, some locale useful twr-wasm specific functions are documented in C API, such as twr_get_current_locale,twr_mbgets, twr_getc32, twr_utf8_char_len, twr_mbslen_l, twr_utf32_to_code_page, twr_code_page_to_utf32_streamed, twr_get_navlang, twr_localize_numeric_string.

Note that io_getc32, getc(stdin), fgetc(stdin) do not look at the current locale. io_getc32 returns a 32 bit unicode code point, and getc/fgetc return extended ASCII.

For a locale aware character input, use io_mbgetc() or twr_mbgets(). Both use the locale category LC_CTYPE. See C API.

Note that when the locale is not set (or whenever the \"C\" locale is set) functions that get character(s) from stdin that are locale aware, like twr_mbgets(), behave different than functions that output characters to stdout (like puts, io_putstr, io_putc, putchar). Characters to stdout in \"C\" locale will handle UTF-8 characters. For stdin, \"C\" locale uses ASCII.

For consistent UTF-8 (or windows-1252) behavior, set the locale as discussed above ( use setlocale )

The primary standard C library locale functions are:

char* setlocale(int category, const char* locale);\nstruct lconv *localeconv(void);\n

As well as the two standard library functions above, appropriate functions take into account the current locale (printf, strcoll, etc).

Note that setlocale returns a string using BCP 47 format (like a web browser). Locale strings look like \"en-US.UTF-8\", instead of \"en_US.UTF-8\". A dash, not an underscore, is used as a separator.

POSIX functions These are the extended POSIX style functions provided that are related to locale:

locale_t newlocale(int category_mask, const char *locale, locale_t base);\nlocale_t uselocale(locale_t);\nvoid freelocale(locale_t);\nlocale_t duplocale(locale_t);\n\nint isalnum_l(int c, locale_t loc);\nint isalpha_l(int c, locale_t loc);\nint isblank_l(int c, locale_t loc);\nint iscntrl_l(int c, locale_t loc);\nint isdigit_l(int c, locale_t loc);\nint isgraph_l(int c, locale_t loc);\nint islower_l(int c, locale_t loc);\nint isprint_l(int c, locale_t loc);\nint ispunct_l(int c, locale_t loc);\nint isspace_l(int c, locale_t loc);\nint isupper_l(int c, locale_t loc);\nint isxdigit_l(int c, locale_t loc);\nint tolower_l(int c, locale_t loc);\nint toupper_l(int c, locale_t loc);\n\nlong long strtoll_l(const char *str, char **str_end, int base,  locale_t loc);\nunsigned long long strtoull_l(const char *str, char **str_end,  int base, locale_t loc);\nfloat strtof_l(const char *str, char ** str_end, locale_t locale);\ndouble strtod_l(const char *str, char **str_end, locale_t locale);\nlong double strtold_l(const char *str, char **str_end, locale_t locale);\n\nint strcoll_l(const char* lhs, const char* rhs,  locale_t loc);\n\nsize_t strftime_l(char *s, size_t maxsize, const char *format, const struct tm *timeptr, locale_t locale);\n
"},{"location":"api/api-typescript/","title":"TypeScript-JavaScript API to load and call Wasm","text":"

This section describes the twr-wasm TypeScript/JavaScript classes that you use to load your Wasm modules, and to call C functions in your Wasm modules.

class twrWasmModule and class twrWasmModuleAsync have similar APIs. The primary difference is that class twrWasmModuleAsync proxies functionality through a Web Worker thread, which allows blocking C functions to be called in your WebAssembly Module. The Async part of twrWasmModuleAsync refers to the ability to await on a blocking callC in your JavaScript main thread, when using twrWasmModuleAsync.

"},{"location":"api/api-typescript/#class-twrwasmmodule","title":"class twrWasmModule","text":"

import {twrWasmModule} from \"twr-wasm\";\n\nconst mod = new twrWasmModule();\n
twrWasmModule provides the two core JavaScript APIs for access to a WebAssembly Module:

"},{"location":"api/api-typescript/#loadwasm","title":"loadWasm","text":"

Use loadWasm to load your compiled C/C++ code (the .wasm file).

await mod.loadWasm(\"./mycode.wasm\")\n

"},{"location":"api/api-typescript/#callc","title":"callC","text":"

After your .wasm module is loaded with loadWasm, you call functions in your C/C++ from TypeScript/JavaScript like this:

let result=await mod.callC([\"function_name\", param1, param2])\n

If you are calling into C++, you need to use extern \"C\" like this in your C++ function:

extern \"C\" int function_name() {}\n

Each C/C++ function that you wish to call from TypeScript/JavaScript needs to be exported in your wasm-ld command line with an option like this:

--export=function_name\n
Or like this in your source file:
__attribute__((export_name(\"function_name\")))\nvoid function_name() {\n   ...\n}\n

Fo more details, see the Compiler Options.

callC takes an array where:

callC returns the value returned by the C function. long, int32_t, int, float or double and the like are returned as a number, int64_t is returned as a bigint, and pointers are returned as a number. The contents of the pointer will need to be extracted using the functions listed below in the section \"Accessing Data in the WebAssembly Memory\". The callC example also illustrates this.

More details can be found in this article: Passing Function Arguments to WebAssembly and in this example. The FFT example demonstrates passing and modifying a Float32Array view of an ArrayBuffer.

"},{"location":"api/api-typescript/#class-twrwasmmoduleasync","title":"class twrWasmModuleAsync","text":"
import {twrWasmModuleAsync} from \"twr-wasm\";\n\nconst amod = new twrWasmModuleAsync();\n

twrWasmModuleAsync implements all of the same functions as twrWasmModule, plus allows blocking inputs, and blocking code generally. This is achieved by proxying all the calls through a Web Worker thread.

For example, with this C function in your Wasm module:

void mysleep() {\n    twr_sleep(5000);  // sleep 5 seconds\n}\n

can be called from your JavaScript main loop like this:

await amod.callC([\"mysleep\"]);\n

This is useful for inputting from stdin, or for traditional blocking loops. The example stdio-div - Printf and Input Using a div Tag demos this.

You must use twrWasmModuleAsync in order to:

See stdio section for information on enabling blocking character input, as well as this Example.

When linking your C/C++ code, twrWasmModule and twrWasmModuleAsync use slightly different wasm-ld options since twrWasmModuleAsync uses shared memory. twrWasmModule will operate with shared memory, so technically you could just use the same share memory options with either module, but you don't need the overhead of shared memory when using twrWasmModule, and so better to not enable it.

See Compiler Options.

twrWasmModuleAsync uses SharedArrayBuffers which require certain HTTP headers to be set. Note that twrWasmModule has an advantage in that it does not use SharedArrayBuffers.

Github pages doesn't support the needed CORS headers for SharedArrayBuffers. But other web serving sites do have options to enable the needed CORS headers. For example, the azure static web site config file staticwebapp.config.json looks like this:

{\n    \"globalHeaders\": {\n      \"Access-Control-Allow-Origin\": \"*\",\n      \"Cross-Origin-Embedder-Policy\": \"require-corp\",\n      \"Cross-Origin-Opener-Policy\": \"same-origin\"\n    }\n}\n

server.py in the examples folder will launch a local server with the correct headers. To use Chrome without a web server, see the Hello World walk through.

"},{"location":"api/api-typescript/#class-options","title":"Class Options","text":"

The twrWasmModule and twrWasmModuleAsync constructor both take optional options.

For example:

let amod=new twrWasmModuleAsync();\n\nlet amod=new twrWasmModuleAsync({\n   windim:[50,20], \n   forecolor:\"beige\", \n   backcolor:\"DarkOliveGreen\", \n   fontsize:18\n   });\n

For a <div id=\"twr_iodiv\"> it is simpler to set the color and font in the div tag per the normal HTML method. But for <div id=\"twr_iocanvas\">, that method won't work and you need to use the constructor options for color and fontsize.

These are the options:

export type TStdioVals=\"div\"|\"canvas\"|\"null\"|\"debug\";\n\nexport interface IModOpts {\n   stdio?:TStdioVals, \n   windim?:[number, number],\n   forecolor?:string,\n   backcolor?:string,\n   fontsize?:number,\n   imports?:{},\n}\n

"},{"location":"api/api-typescript/#stdio","title":"stdio","text":"

You can explicitly set your stdio source (for C/C++ printf, etc) with the stdio option, but typically you don't set it. Instead, it will auto set as described here

"},{"location":"api/api-typescript/#windim","title":"windim","text":"

This options is used with a terminal console ( <canvas id=\"twr_iocanvas\"> ) to set the width and height, in characters.

The canvas width and height, in pixels, will be set based on your fontsize and the width and height (in characters) of the terminal.

"},{"location":"api/api-typescript/#forecolor-and-backcolor","title":"forecolor and backcolor","text":"

These can be set to a CSS color (like '#FFFFFF' or 'white') to change the default background and foreground colors.

"},{"location":"api/api-typescript/#fonsize","title":"fonsize","text":"

Changes the default fontsize for div or canvas based I/O. The size is in pixels.

"},{"location":"api/api-typescript/#divlog","title":"divLog","text":"

If stdio is set to twr_iodiv, you can use the divLog twrWasmModule/Async function like this:

import {twrWasmModule} from \"twr-wasm\";\n\nconst mod = new twrWasmModule();\nawait mod.loadWasm(\"./tests.wasm\");\nawait mod.callC([\"tests\"]);\n\nmod.divLog(\"\\nsin() speed test\");\nlet sumA=0;\nconst start=Date.now();\n\nfor (let i=0; i<2000000;i++)\n   sumA=sumA+Math.sin(i);\n\nconst endA=Date.now();\n\nlet sumB=await mod.callC([\"sin_test\"]);\nconst endB=Date.now();\n\nmod.divLog(\"sum A: \", sumA, \" in ms: \", endA-start);\nmod.divLog(\"sum B: \", sumB,  \" in ms: \", endB-endA);\n

"},{"location":"api/api-typescript/#accessing-data-in-the-webassembly-memory","title":"Accessing Data in the WebAssembly Memory","text":"

callC() will convert your JavaScript arguments into a form suitable for use by your C code. However, if you return or want to access struct values inside TypeScript you will find the following twrWasmModule and twrWasmModuleAsync functions handy. See the callc example and Passing Function Arguments from JavaScript to C/C++ with WebAssembly for an explanation of how these functions work.

async putString(sin:string, codePage=codePageUTF8)  // returns index into WebAssembly.Memory\nasync putU8(u8a:Uint8Array)   // returns index into WebAssembly.Memory\nasync putArrayBuffer(ab:ArrayBuffer)  // returns index into WebAssembly.Memory\nasync fetchAndPutURL(fnin:URL)  // returns index into WebAssembly.Memory\nasync malloc(size:number)           // returns index in WebAssembly.Memory.  \n\nstringToU8(sin:string, codePage=codePageUTF8)\ncopyString(buffer:number, buffer_size:number, sin:string, codePage=codePageUTF8):void\ngetLong(idx:number): number\nsetLong(idx:number, value:number)\ngetDouble(idx:number): number\nsetDouble(idx:number, value:number)\ngetShort(idx:number): number\ngetString(strIndex:number, len?:number, codePage=codePageUTF8): string\ngetU8Arr(idx:number): Uint8Array\ngetU32Arr(idx:number): Uint32Array\n\nmemory?:WebAssembly.Memory;\nmem8:Uint8Array;\nmem32:Uint32Array;\nmemD:Float64Array;\n

"},{"location":"examples/examples-balls/","title":"Bouncing Balls - 2D Draw API Wasm Example","text":"

This example uses twr-wasm's 2D Draw API and a C++ Canvas class with WebAssembly and C++ to bounce balls around your HTML page.

The bouncing balls example demonstrates

This example does not use libc++, which results in smaller code size. For an example that uses libc++ see tests-libcxx.

"},{"location":"examples/examples-balls/#screen-grab-of-balls-example","title":"Screen Grab of Balls Example","text":""},{"location":"examples/examples-callc/","title":"callC - Calling WebAssembly Functions Example","text":"

This example demonstrates how to pass and return values between TypeScript/JavaScript and C/C++ when you are using WebAssembly with twr-wasm.

This article explains the key concepts to pass arguments between JavaScript/TypeScript and Wasm C/C++.

"},{"location":"examples/examples-fft/","title":"FFT - Example of using C FFT with HTML/JavaScript","text":"

This example is a demo of integrating the popular KISS FFT C library with TypeScript/JavaScript/HTML using WebAssembly. The FFT C library is compiled into a Wasm (WebAssembly) module using clang, with the help of twr-wasm. The FFT Wasm module is used by the HTML page to calculate the FFT. The FFT input and output is drawn to the web page using JavaScript canvas functions.

The FFT library exposes APIs to process data, and doesn't use stdio.

The FFT APIs use float32 arrays for complex-number input and output data, and a configuration C struct. In the example I generate the input data by adding a 1K and 5K sine waves, call the kiss FFT API to perform the FFT on the generated sine waves, and then graph the input and output data using a JavaScript Canvas.

"},{"location":"examples/examples-fft/#screen-grab-of-output","title":"Screen Grab of Output","text":""},{"location":"examples/examples-fft/#code","title":"Code","text":"

Here is part of the code. The rest can be found on github.

index.html

<head>\n    <title>Fast Fourier transform (FFT)</title>\n</head>\n<body style=\"background-color:white\">\n\n    <br>\n\n    <div style=\"font:24px arial\">Input Signal</div>\n    <canvas id=\"c-input\" width=\"1024\" height=\"300\" style=\"background-color:lightgray\"></canvas>\n\n    <br><br><br>\n\n    <div style=\"font:24px arial\">FFT Output</div>\n    <canvas id=\"c-output\" width=\"1024\" height=\"300\" style=\"background-color:lightgray\"></canvas>\n\n    <script type=\"module\">\n        import {fftDemo} from \"./fft-script.js\";\n\n        fftDemo();\n\n    </script>\n</body>\n
fft-script.js
import {twrWasmModule} from \"twr-wasm\";\n\nexport async function fftDemo() {\n\n    const mod=new twrWasmModule();\n\n    // load the kiss_fft C code as is, unmodified\n    await mod.loadWasm('kiss_fft.wasm');\n\n    //  kissFFTData stores and graphs the input and output data\n    //  in this example the fft has 1024 bins, and I am using a 48K sampling rate\n    let fft=new kissFFTData(1024, 48000);\n    fft.genSin(1000)\n    fft.addSin(5000)\n    fft.graphIn(\"c-input\");\n\n    // see kiss_fft README, but in summary you: (a) alloc config, (b) compute the FFT, (c) free the config\n    // kiss_fft_alloc() returns a malloced structure.  Pointers are numbers (index into Wasm module memory) in JS land \n    //\n    //kiss_fft_cfg cfg = kiss_fft_alloc( nfft ,is_inverse_fft ,0,0 );\n    let cfg:number = await mod.callC([\"kiss_fft_alloc\", fft.nfft, 0, 0, 0 ]);\n\n    // The FFT input and output data are C arrays of complex numbers.\n    // typedef struct {\n    //    kiss_fft_scalar r;\n    //    kiss_fft_scalar i;\n    // } kiss_fft_cpx;\n    //\n    // /*  default is float */\n    // define kiss_fft_scalar float\n\n    // So if the FFT data has 1024 bins, then 1024 * 2 floats (r & i) * 4 bytes per float are needed.\n    // I use a JS Float32Array view on the ArrayBuffer to access the floats\n\n    // When an arrayBuffer is passed in as an argument to mod.callC,\n    // callC will malloc memory in the Wasm module of a size that matches the array buffer, then\n    // copy the arraybuffer into the malloc'd memory prior to the function call, \n    // then copy the malloc'd memory contents back into the arrayBuffer post call.\n    // The malloc'd memory is free'd post call. \n\n    // void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);\n    await mod.callC([\"kiss_fft\", cfg, fft.inArrayBuf, fft.outArrayBuf]);\n\n    fft.graphOut(\"c-output\");\n\n    await mod.callC([\"free\", cfg]);      // not much point to this since all the module memory is about to disappear\n}\n

"},{"location":"examples/examples-helloworld/","title":"Hello World - WebAssembly C Example","text":"

This example is an very simple twr-wasm program. It uses WebAssembly and C to print \"hello, world!\" to an HTML <div> tag.

Also see: Hello World - Step-by-Step C to Wasm.

"},{"location":"examples/examples-libcxx/","title":"tests-libcxx - WebAssembly libc++ Smoke Test","text":"

This is a simple test of various libc++ functions using WebAssembly with twr-wasm. The C++ program links with libc++. An example makefile is provided.

Also see this WebAssembly program that uses libc++ with twr-wasm to implement a CLI console.

"},{"location":"examples/examples-maze/","title":"Maze Generator/Solver","text":"

This example is a port to Wasm of a 20 year old Win32 C Maze creator, with the help of twr-wasm 2D Draw APIs.

"},{"location":"examples/examples-maze/#screen-grab-of-output","title":"Screen Grab of Output","text":""},{"location":"examples/examples-maze/#overview","title":"Overview","text":"

This Maze generator uses the twr-wasm \"d2d\" (Draw 2D) C APIs. These allow drawing onto an HTML canvas from C/C++. (Also see the balls C++ example).

This C code is interesting in that it is a combination of blocking and non blocking functions. The CalcMaze function is blocking when the \"slow draw\" flag is set. It uses Sleep in this case. For this reason, I use twrWasmModuleAsync. The solve section uses repeated calls to SolveStep, which works well with a JavaScript main loop. I used a javascript interval timer to make repeated calls to the C SolveStep function. If all the C code was structured this way, twrWasmModule could have been used (instead of the Async version)

To port this code to twr-wasm I wrote a (very tiny) Win32 compatible API (in winemu.c/winemu.h). It only implements the features needed to port Maze, but it might be useful to use as a starting point for porting your Win32 code to the web.

index.html
<head>\n    <title>Maze</title>\n</head>\n<body style=\"background-color:powderblue\">\n    <canvas id=\"twr_d2dcanvas\" width=\"600\" height=\"600\"></canvas>\n\n    <script type=\"module\">\n        import {mazeRunner} from \"./maze-script.js\";\n\n        mazeRunner();\n    </script>\n</body>\n
maze-script.js
import {twrWasmModuleAsync} from \"twr-wasm\";\n\nexport async function mazeRunner() {\n\n    const amod=new twrWasmModuleAsync();\n\n    await amod.loadWasm('maze.wasm');\n\n    //void CalcMaze(HWND hWnd, LONG cell_size, LONG is_black_bg, LONG isd - slow draw)\n    await amod.callC([\"CalcMaze\", 0, 7, 0, 1]);\n    await amod.callC([\"SolveBegin\"]);\n\n    let timer = setInterval(async ()=>{\n        let isdone=await amod.callC([\"SolveStep\", 0]);  //SolveStep(hwnd))\n        if (isdone) clearInterval(timer);\n    }, 50);\n}\n
"},{"location":"examples/examples-overview/","title":"WebAssembly C/C++ Examples","text":""},{"location":"examples/examples-overview/#overview","title":"Overview","text":"

These C and C++ examples demonstrate how to create different types of WebAssembly (wasm) programs with the twr-wasm library.

These are good examples to use as starting points for your own Wasm projects.

These examples are a good place to learn how to configure clang and wasm-ld to compile and link C/C++ code for use with WebAssembly (wasm).

"},{"location":"examples/examples-overview/#example-quick-links","title":"Example Quick Links","text":""},{"location":"examples/examples-overview/#examples-overview","title":"Examples Overview","text":"

Each of these examples are designed to illustrate how to use a feature of twr-wasm.

Name Description Link helloworld A very simple C Wasm example to get you started helloworld stdio-div This simple C program demos inputting andprinting characters to a div tag stdio-div stdio-canvas This simple C program demos writing and inputtingfrom a <canvas> tag that twr-wasm configuresas a windowed \"mini-terminal\" stdio-canvas balls These fun Bouncing Balls are written in C++ and demo the2D drawing APIs with a C++ Canvas wrapper class balls pong A simple game of Pong written in C++ to demo 2D drawing APIs with a C++ canvas wrapper class and taking user input from JS pong maze This is an old Win32 program ported to wasmand demos the 2D Draw APIs maze fft A demo of calling a C library to perform an FFTthat is graphed in TypeScript fft callC A demo of passing and returning values betweenJavaScript and Wasm module callc tests twr-wasm unit tests tests tests-user \"cli\" for tests using libc++ and <canvas> tests-user tests-libcxx Smoke test for libc++. Shows how to use libc++. tests-libcxx"},{"location":"examples/examples-overview/#building-the-examples","title":"Building the Examples","text":"

See Example Readme for more information on building and running the examples.

"},{"location":"examples/examples-pong/","title":"Pong - 2D Game Example","text":"

Similar to the balls example, this example uses twr-wasm's 2D Draw API and a C++ canvas class to run a simple game of singleplayer Pong.

The Pong example demonstrates

This example does not use libc++, which results in smaller code size. For an example that uses libc++ see tests-libcxx.

"},{"location":"examples/examples-pong/#screen-grab-of-pong-example","title":"Screen Grab of Pong Example","text":""},{"location":"examples/examples-stdio-canvas/","title":"stdio-canvas - Terminal Using a Canvas Tag","text":"

A simple ANSI WebAssembly C \"terminal\" is created with input and output directed to an HTML <canvas> tag.

This example will move a string up or down in the terminal window when you press the u or d or arrow keys.

This example also draws a graphic box around the terminal window.

"},{"location":"examples/examples-stdio-canvas/#screen-grab-of-terminal","title":"Screen Grab of Terminal","text":""},{"location":"examples/examples-stdio-canvas/#c-code","title":"C Code","text":"stdio-canvas.c
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <locale.h>\n#include \"twr-crt.h\"\n\n/* this twr-wasm C example draws a utf-8 string in the middle of a windowed console, */\n/* and allows the user to move the string up or down with the u, d or arrow keys */\n\n/* see include/twr-io.h for available functions to draw chars to windowed console */\n\nvoid draw_outline(struct IoConsoleWindow* iow);\nvoid show_str_centered(struct IoConsoleWindow* iow, int h, const char* str);\n\nvoid stdio_canvas() {\n    struct IoConsoleWindow* iow=(struct IoConsoleWindow*)twr_get_stdio_con();\n\n    assert(iow->con.header.type&IO_TYPE_WINDOW);\n\n    setlocale(LC_ALL, \"\");  // set user default locale, which is always UTF-8.  This is here to turn on UTF-8.\n\n    int h;\n    const char* str=\"Hello World (press u, d, \u2191, or \u2193)\";  // arrows are UTF-8 multibyte\n    const char* spc=\"                                 \";\n    char inbuf[6];  // UTF-8 should be max 4 bytes plus string ending 0\n\n    h=iow->display.height/2;\n\n   draw_outline(iow);\n\n    while (1) {\n      show_str_centered(iow, h,  str);\n      io_mbgetc(stdin, inbuf); // also see twr_getc32 documentation\n      show_str_centered(iow, h,  spc);   // erase old string\n\n      if (strcmp(inbuf,\"u\")==0 || strcmp(inbuf,\"\u2191\")==0) {   // arrows are multibyte UTF-8.\n         h=h-1;\n         if (h<1) h=1;  // border I drew is in the 0 position\n      }\n      if (strcmp(inbuf,\"d\")==0 || strcmp(inbuf,\"\u2193\")==0) {\n         h=h+1;\n         if (h>=(iow->display.height-1)) h=iow->display.height-2;  // border I drew is in the height-1 position\n      }\n   }\n}\n\nvoid show_str_centered(struct IoConsoleWindow* iow, int h, const char* str) {\n    int len=twr_mbslen_l(str, twr_get_current_locale());\n    int x=(iow->display.width-len)/2;\n    io_set_cursorxy(iow, x, h);\n    io_putstr(&iow->con, str);\n}\n\nvoid draw_outline(struct IoConsoleWindow* iow) {\n   const int w=iow->display.width*2;   // graphic cells are 2x3\n   const int h=iow->display.height*3;\n   unsigned long fgcolor, bgcolor;\n\n   io_begin_draw(&iow->con);\n\n   io_get_colors(&iow->con, &fgcolor, &bgcolor);\n   io_set_colors(&iow->con, 0x000000, bgcolor);  // draw in black\n\n   for (int i=0; i<w; i++) {\n      io_setreset(iow, i, 0, true);\n      io_setreset(iow, i, h-1, true);\n   }\n\n   for (int i=0; i<h; i++) {\n      io_setreset(iow, 0, i, true);\n      io_setreset(iow, w-1, i, true);\n   }\n\n   io_set_colors(&iow->con, fgcolor, bgcolor);  // restore\n\n   io_end_draw(&iow->con);\n\n}\n
"},{"location":"examples/examples-stdio-canvas/#html-code","title":"HTML Code","text":"index.html
<!doctype html>\n<html>\n<head>\n   <title>stdio-canvas example</title>\n</head>\n<body>\n   <canvas id=\"twr_iocanvas\" tabindex=\"0\"></canvas>\n\n   <!-- importmap used when un-bundled -->\n   <script type=\"importmap\">\n      {\n         \"imports\": {\n         \"twr-wasm\": \"../../lib-js/index.js\"\n         }\n      }\n   </script>\n\n   <script type=\"module\">\n      import {twrWasmModuleAsync} from \"twr-wasm\";\n\n      try {\n         const amod = new twrWasmModuleAsync({windim:[50,20], forecolor:\"beige\", backcolor:\"DarkOliveGreen\", fontsize:18});\n\n         document.getElementById(\"twr_iocanvas\").focus();\n         document.getElementById(\"twr_iocanvas\").addEventListener(\"keydown\",(ev)=>{amod.keyDownCanvas(ev)});\n\n         await amod.loadWasm(\"./stdio-canvas.wasm\");\n         const r=await amod.callC([\"stdio_canvas\"]);\n         console.log(\"callC returned: \"+r);\n      }\n      catch(ex) {\n         console.log(\"unexpected exception\");\n         throw ex;\n      }\n\n   </script>\n</body>\n</html>\n
"},{"location":"examples/examples-stdio-div/","title":"stdio-div - Printf and Input Using a div Tag","text":"

This simple WebAssembly C program demos inputting and printing characters with a div tag.

"},{"location":"examples/examples-stdio-div/#screen-grab-of-square-calculator","title":"Screen Grab of Square Calculator","text":""},{"location":"examples/examples-stdio-div/#c-code","title":"C Code","text":"stdio-div.c
#include <stdio.h>\n#include <stdlib.h>\n#include \"twr-crt.h\"\n\nvoid stdio_div() {\n   char inbuf[64];\n   int i;\n\n   printf(\"Square Calculator\\n\");\n\n   while (1) {\n      printf(\"Enter an integer: \");\n      twr_mbgets(inbuf);\n      i=atoi(inbuf);\n      printf(\"%d squared is %d\\n\\n\",i,i*i);\n   }\n}\n
"},{"location":"examples/examples-stdio-div/#html-code","title":"HTML Code","text":"

We are using twrWasmModuleAsync which integrates blocking C code into JavaScript. twrWasmModuleAsync can also be used to receive key input from a <div> or <canvas> tag.

index.html
<head>\n   <title>stdio-div example</title>\n</head>\n<body>\n   <div id=\"twr_iodiv\" style=\"background-color:LightGray;color:DarkGreen\" tabindex=\"0\">Loading... <br></div>\n\n   <script type=\"module\">\n      import {twrWasmModuleAsync} from \"twr-wasm\";\n\n      let amod;\n\n      try {\n         amod = new twrWasmModuleAsync();\n\n         document.getElementById(\"twr_iodiv\").innerHTML =\"<br>\";\n         document.getElementById(\"twr_iodiv\").addEventListener(\"keydown\",(ev)=>{amod.keyDownDiv(ev)});\n\n         await amod.loadWasm(\"./stdio-div.wasm\");\n         await amod.callC([\"stdio_div\"]);\n      }\n      catch(ex) {\n         amod.divLog(\"unexpected exception\");\n         throw ex;\n      }\n\n   </script>\n</body>\n
"},{"location":"gettingstarted/basicsteps/","title":"Basic Steps To Create Your Wasm Project","text":"

This section describes the basic steps to integrate your TypeScript/JavaScript with C/C++ WebAssembly code.

"},{"location":"gettingstarted/basicsteps/#overview-of-webassembly-project","title":"Overview of WebAssembly Project","text":"

Your C/C++ WebAssembly project will consist of HTML (and related JavaScript or TypeScript) and C or C++ source files that are compiled into a \".wasm\" binary file that is loaded as a WebAssembly module by your JavaScript.

"},{"location":"gettingstarted/basicsteps/#javascripttypescript-part-of-wasm-project","title":"JavaScript/TypeScript Part of Wasm Project","text":"

On the JavaScript side of your WebAssembly project you will use the twr-wasm JavaScript/TypeScript class twrWasmModule or twrWasmModuleAsync to load the .wasm module, and then call C functions in it using callC (more details are in the TypeScript/Javascript API section).

"},{"location":"gettingstarted/basicsteps/#cc-part-of-wasm-project","title":"C/C++ Part of Wasm Project","text":"

You will call C functions (or C++ with ' extern \"C\" ' linkage) in the .wasm module from your JavaScript. You can also call JavaScript functions from your C/C++ code, but this is less common.

There is no direct equivalent to a C \"main\". Instead, a Wasm module provides exported C functions that you can call from JavaScript/TypeScript. A Wasm module is more like a runtime loaded dynamic library.

You're C/C++ code can be non-blocking or blocking. Blocking means that it \"takes a long time\" to return. For example, if you want to send mouse events to C code, have the code process them then return, this would be non-blocking. Alternately, if your C code is a big loop that never returns, that would be very blocking. You can use the twr-wasm class twrWasmModuleAsync to execute blocking code from JavaScript. The example maze demonstrates both non-blocking and blocking C calls.

Here are some examples of different types of C/C++ code:

"},{"location":"gettingstarted/basicsteps/#steps-to-integrate-c-code-with-javascript-code","title":"Steps to integrate C code with JavaScript code","text":"

Here are the general steps to integrate your C with your JavaScript:

  1. Compile your C code with clang and link with wasm-ld to create the .wasm file.
  2. On the JavaScript side you:
    1. Access twr-wasm \"ES\" modules in the normal way with import.
    2. Add a <div id=twr_iodiv> or <canvas id=twr_iocanvas> to your HTML (see stdio)
    3. Use new twrWasmModule(), followed by a call to loadWasm(), then one or more callC().
    4. Alternately, use twrWasmModuleAsync() -- which is interchangeable with twrWasmModule, but proxies through a worker thread, and adds blocking support, including blocking char input.
    5. For more details, see the remainder of this documentation, or see the hello world or other exampes.
"},{"location":"gettingstarted/charencoding/","title":"Character Encoding Support with twr-wasm","text":"

This section explains twr-wasm's WebAssembly support for ASCII, UTF-8, windows-1252, and UTF-32 character encoding.

"},{"location":"gettingstarted/charencoding/#getting-started","title":"Getting Started","text":"

When using C with twr-wasm, you will likely want to add this line to the start of your code:

setlocale(LC_ALL, \"\")\n

This will change the C locale language to the one selected in the browser, and will enable consistent UTF-8 character encoding support.

Without this line, the standard C runtime will (mostly) default character encoding to ASCII, as per the standard. The exception is that just as with gcc, twr-wasm consoles support outputting UTF-8.

"},{"location":"gettingstarted/charencoding/#character-encodings","title":"Character Encodings","text":"

twr-wasm supports ASCII, UNICODE, and extended-ASCII (in the form of Windows-1252).

These days UNICODE with UTF-8 encoding is the most popular method of displaying and encoding text. UTF-8 is popular because it has the deep character glyph definitions of UNICODE with an encoding that provides (a) the best backwards compatibility with ASCII, and (b) a compact memory footprint. It does this at the expense of some multibyte complexities.

UTF-8 is variable length, and uses between one to four bytes to represent any unicode code point, with ASCII compatibility in the first 128 bytes. It is also the standard for the web, and the default for clang. But because UTF-8 uses a variable number of bytes per character it can make string manipulation in C a bit harder than ASCII, Windows-1252 or UTF-32.

In this document you will see the term \"locale\". This term originated (at least as its commonly used in programming) in the standard C library, and is also used in the standard C++ library (libc++ in twr-wasm). A locale refers to a region of the world, along with a specific character encoding. The twr-wasm standard c runtime uses a label akin to this to define a locale: en-US.UTF-8. Of note is that libc++ and the standard C runtime have different domains for their locales (ie, they don't directly impact each other). You can learn more about locales by searching the internet.

twr-wasm C locales support ASCII, UTF-8 or windows-1252 character encoding. UTF-16/32 are not supported as a std c lib locale setting, but functions are provided to convert utf-32 (unicode code points) to and from ASCII, UTF-8, and windows-1252 \"code pages\" (there are other miscellaneous utf-32 based functions as well.)

Although twr-wasm's standard c library locale doesn't support utf-32 directly, you can use int arrays (instead of byte arrays) to hold utf-32 strings, and then convert them to/from utf-8 with the help of the provided functions for this purpose. Alternately, you can use libc++, which has classes that directly support utf-16 and utf-32.

"},{"location":"gettingstarted/charencoding/#windows-compatibility-with-windows-1252","title":"Windows Compatibility with Windows-1252","text":"

Windows-1252 is the default character encoding on Windows computers in many countries - particularly the Americas and western Europe -- and particularly when using MSVC. Linux, clang, gcc, and the web commonly default in some way to UTF-8 character encoding. Windows-1252 is an extension of ASCII that uses a single byte per character. This makes it easier than UTF-8 from a programmers perspective, but it doesn't represent as many characters. It is supported by twr-wasm to make it easier to port legacy C code, windows code, as well as a simpler alternative to UTF-8.

twr-wasm supports Windows-1252, and you can enable it like this:

setlocale(LC_ALL, \".1252\")\n

This will set the locale to the default browser language, and character encoding to Windows-1252.

1252 String Literals These days text editors generally default to UTF-8. In order to use windows-1252 source code and/or string literals, such as const char * str=\"\u20ac100\" you may need to:

By default, the Microsoft Visual Studio C compiler (MSVC) does not treat string literals as UTF-8. Instead, it treats them as being encoded in the current code page of the system, which is typically Windows-1252 on western european language Windows systems. twr-wasm is designed to work with clang, which does default to utf-8, so if you are compiling code written for MSVC, and you use extend character sets (non ASCII), you may need to adjust your compiler settings with the flags mentioned above.

"},{"location":"gettingstarted/charencoding/#more","title":"More","text":"

For more details see Localization Reference for twr-wasm

"},{"location":"gettingstarted/compiler-opts/","title":"Compiling, Linking, and Memory Options","text":"

This section described how to use clang to compile C/C++ code for WebAssembly, and how to use wasm-ld to link your files into a .wasm module, when using twr-wasm.

twr-wasm lets you use clang directly, without a wrapper. This section describes the needed clang compile options and the wasm-ld link options. You can also take a look at the example makefiles.

"},{"location":"gettingstarted/compiler-opts/#compiler-notes","title":"Compiler Notes","text":"

twr-wasm has been tested with clang 17.0.6 and wasm-ld 17.0.6.

If you are using nix, the default clang packages are wrapped with flags that break compilation. The following packages don't have this issue:

"},{"location":"gettingstarted/compiler-opts/#c-clang-compiler-options","title":"C clang Compiler Options","text":"

When compiling C code with clang for use with Wasm and twr-wasm, use these clang options:

 --target=wasm32 -nostdinc -nostdlib -isystem  ../../include\n

Here is an example of a compile command:

clang --target=wasm32 -nostdinc -nostdlib -isystem ./node_modules/twr-wasm/include -c  helloworld.c -o helloworld.o\n

-isystem should be adjusted to point to where the folder twr-wasm/include is installed. For example:

"},{"location":"gettingstarted/compiler-opts/#c-clang-compiler-options_1","title":"C++ clang Compiler Options","text":"

When compiling C++ code with clang for use with Wasm and twr-wasm, use these clang options:

 --target=wasm32 -fno-exceptions -nostdlibinc -nostdinc -nostdlib -isystem  ../../include\n

"},{"location":"gettingstarted/compiler-opts/#wasm-ld-linker-options","title":"wasm-ld Linker Options","text":"

Use the wasm-ld linker directly with twr-wasm.

For example:

wasm-ld  helloworld.o ./node_modules/twr-wasm/lib-c/twr.a -o helloworld.wasm  --no-entry --initial-memory=131072 --max-memory=131072 --export=hello \n

For C and C++ link to twr.a to link to the twr-wasm library.

For C++ link to libc++.a if you are using libc++. (see the tests-libcxx example makefile).

Be sure to adjust the path to twr.a and libc++.a as needed to the location where twr-wasm/lib-c/ is installed.

All of the twr-wasm functions are staticly linked from the library lib-c/twr.a. There is also a version ( lib-c/twrd.a ) of twr-wasm library available with debug symbols. One of these two static libraries should be added to the list of files to link (normally this is twr.a). Both versions are built with asserts enabled. twr.a is built with -O3. twrd.a is built with -g -O0.

C functions that you wish to call from JavaScript should either have an -export option passed to wasm-ld, or you can use the __attribute__((export_name(\"function_name\"))) option in your C function definition.

All exported functions to JavaScript should be C linkage (extern \"C\" if using C++).

wasm-ld should be passed the following options:

If Using twrWasmModule:

--no-entry --initial-memory=<size> --max-memory=<size>\n

If Using twrWasmModuleAsync:

--no-entry --shared-memory --no-check-features --initial-memory=<size> --max-memory=<size>\n

"},{"location":"gettingstarted/compiler-opts/#memory-options-memory-size-stack-size-etc","title":"Memory Options (Memory Size, Stack Size, etc)","text":"

WebAssembly.Memory contains all the data used by your code (including the data needs of staticly linked libraries such as twr-wasm or libc++), but it does not store your actual code. It provides a contiguous, mutable array of raw bytes. Code execution and storage in WebAssembly are handled separately using the WebAssembly.Module and WebAssembly.Instance objects. The code (compiled WebAssembly instructions) is stored in the WebAssembly.Module, while WebAssembly.Memoryis used to manage the linear memory accessible to the WebAssembly instance for storing data. Examples of data include your static data (.bss section or the .data section), the heap (used by malloc and free), and the stack (used for function calls and local variables).

The memory size should be a multiple of 64*1024 (64K) chunks. \"initial-memory\" and \"max-memory\" should be set to the same number since there is no support for automatically growing memory in twr-wasm. The memory is an export out of the .wasm into the JavaScript code -- you should not create or set the size of WebAssembly.Memory in JavaScript when using twr-wasm.

You set the memory size for your module (WebAssembly.Memory) using wasm-ld options as follows (this examples sets your Wasm memory to 1MB).

"},{"location":"gettingstarted/compiler-opts/#twrwasmmodule","title":"twrWasmModule","text":"

if using twrWasmModule:

--initial-memory=1048576 --max-memory=1048576\n

"},{"location":"gettingstarted/compiler-opts/#twrwasmmoduleasync","title":"twrWasmModuleAsync","text":"

If you are using twrWasmModuleAsync, shared memory must also be enabled. Like this:

--shared-memory --no-check-features --initial-memory=1048576 --max-memory=1048576\n

See this production note on using shared memory.

"},{"location":"gettingstarted/compiler-opts/#stack-size","title":"Stack Size","text":"

You can change your C/C++ stack size from the default 64K with the following wasm-ld option. This example sets the stack at 128K

 -z stack-size=131072\n

"},{"location":"gettingstarted/compiler-opts/#print-memory-map","title":"Print Memory Map","text":"

You can print your module memory map, heap stats, and stack size using the function from C:

void twr_mem_debug_stats(struct IoConsole* outcon);\n
You can call it from Javascript with the output sent to the debug console (stderr) like this:
twrWasmModule/Async.callC([\"twr_wasm_print_mem_debug_stats\"])\n

"},{"location":"gettingstarted/compiler-opts/#typescriptjavascript-malloc-and-memory-access","title":"TypeScript/JavaScript malloc and Memory Access","text":"

twrWasmModule and twrWasmModuleAsync expose malloc as an async function, as well as the WebAssembly Module memory as:

async malloc(size:number);\n\nmemory?:WebAssembly.Memory;\nmem8:Uint8Array;\nmem32:Uint32Array;\nmemD:Float64Array;\n
to call free from JavaScript (you probably won't need to), you can use:
twrWasmModule/Async.callC([\"twr_free\", index]);  // index to memory to free, as returned by malloc\n

more information on these functions and module public variables can be found in the examples in this section: Passing Function Arguments to WebAssembly.

"},{"location":"gettingstarted/debugging/","title":"Debugging WebAssembly","text":"

This section describes tips for debugging your WebAssembly (Wasm) program. Some of these techniques are WebAssembly generic, some are specific to using twr-wasm.

"},{"location":"gettingstarted/debugging/#debug-and-release-libraries","title":"Debug and Release libraries","text":"

There are release (twr.a) and debug (twrd.a) versions of the twr-wasm C library. The \"debug\" version has debug symbols enabled with -g and is built with optimizations disabled via -O0. The \"release\" version has no debug symbols and optimization is set to -O3. Both have asserts enabled. In general, you should use the \"release\" version unless you wish to step through the twr-wasm source -- in which case use the \"debug\" version.

libc++.a is not built with debug symbols.

"},{"location":"gettingstarted/debugging/#source-level-debugging-webassembly-cc","title":"Source Level Debugging WebAssembly C/C++","text":"

In order to enable C/C++ source debugging with Wasm and clang, do the following:

  1. Use Chrome
  2. Install the Chrome extension: C/C++ DevTools Support (DWARF) ( https://chromewebstore.google.com/detail/pdcpmagijalfljmkmjngeonclgbbannb )
  3. Use the clang compile flag -g to add debug annotation to your object files
  4. You may want to turn off optimization to allow the debugger to have a bit more logical behavior (remove the -O flag or set to -O0)
  5. You may want to use the version of the twr-wasm C library that has debug symbols enabled (twrd.a). Only if you want to step into the twrd.a source.
  6. You need to serve your files with a (likely local) web server. For example, 'python server.py' is provided. 'server.py' can be found in the examples root folder. Note that your local server needs to enable SharedArrayBuffers if you are using twrWasmModuleAsync -- see the server.py example.
  7. your code can be bundled or unbundled, but
  8. you need to ensure that the web server/browser can find the source code
  9. also see Example Readme
"},{"location":"gettingstarted/debugging/#useful-twr-wasm-debug-functions","title":"Useful twr-wasm Debug Functions","text":"

Use twr_conlog to print to the JavaScript console from C (see API ref section).

#include \"twr-wasm.h\"\n\ntwr_conlog(\"hello 99 in hex: %x\",99);\n

Use twrWasmModule.divLog() to print to a div inside JavaScript code (see API ref section).

"},{"location":"gettingstarted/debugging/#testing-webassembly-without-a-web-server","title":"Testing WebAssembly Without a Web Server","text":"

Note: If you use this technique, you will not be able to get the C/C++ DevTool chrome extension to run, and so source level debugging won't work. (If you know how to fix this, please contact me on github.)

You can execute and debug JavaScript with Wasm from local files without an HTTP server. It might be helpful to download the twr-wasm source code from github when you do this (so you can step through the twr-wasm typescript code as needed).

See the examples and Example Readme for more detail on how this works.

In general, you will need to add a clip of code similar to this to your HTML:

<script type=\"importmap\">\n   {\n      \"imports\": {\n      \"twr-wasm\": \"./../../lib-js/index.js\"\n      }\n   }\n</script>\n

Make sure the paths to twr-wasm/lib-js/index.js are correct for where your source is located. The above is correct for the provided examples.

You will need to set the following flags when running chrome from the shell or VS Code (the first is only strictly required if using twrWasmModuleAsync).

--enable-features=SharedArrayBuffer\n--allow-file-access-from-files\n

If you are using VS Code, You can create a launch.json entry similar to this:

launch.json
{\n    \"configurations\": [\n    {\n        \"name\": \"Launch Chrome\",\n        \"request\": \"launch\",\n        \"type\": \"chrome\",\n        \"runtimeArgs\": [\n            \"--allow-file-access-from-files\",\n            \"--autoplay-policy=no-user-gesture-required\",\n            \"--enable-features=SharedArrayBuffer\"\n         ],\n         \"file\": \"${workspaceFolder}/index.html\",\n         \"cwd\": \"${workspaceFolder}/\",\n    }\n    ]\n}\n
"},{"location":"gettingstarted/helloworld/","title":"Create and Run WebAssembly Hello World","text":"

This section shows you, step by step, how to to create a C \"hello world\" program for WebAssembly (Wasm) with twr-wasm, C, HTML, and JavaScript.

You will learn how to:

You can find code for a hello world example in the folder examples\\helloworld. It is similar, but not identical to this walk through. The primary differences are the paths for lib-c, lib-js, and include.

"},{"location":"gettingstarted/helloworld/#step-0-installation","title":"Step 0: Installation","text":""},{"location":"gettingstarted/helloworld/#step-1-create-the-c-code","title":"Step 1: Create the C code","text":"

Create a file helloworld.c in hello-proj helloworld.c

#include <stdio.h>\n\nvoid hello() {\n   printf(\"hello world\\n\");\n}\n

"},{"location":"gettingstarted/helloworld/#step-2-create-the-html","title":"Step 2: Create the HTML","text":"

Create a file index.html in hello-proj index.html

<!doctype html>\n<html>\n<head>\n   <title>Hello World</title>\n\n   <script type=\"importmap\">\n   {\n      \"imports\": {\n      \"twr-wasm\": \"./node_modules/twr-wasm/lib-js/index.js\"\n      }\n   }\n   </script>\n\n</head>\n<body>\n   <div id=\"twr_iodiv\"></div>\n\n   <script type=\"module\">\n      import {twrWasmModule} from \"twr-wasm\";\n\n      const mod = new twrWasmModule();\n      await mod.loadWasm(\"./helloworld.wasm\");\n      await mod.callC([\"hello\"]);\n   </script>\n</body>\n</html>\n

This example uses Import Maps, which are used when not using a bundler like WebPack or Parcel. For smaller projects, this can be simpler with a more clear debugging and development environment. This is the approach we will use for this example (no bundler).

The path in the importmap section of index.html should point to the location where you installed twr-wasm/lib-js. The path above is correct for this project example with the indicated folder structure.

"},{"location":"gettingstarted/helloworld/#step-3-compile-your-c-code-to-create-your-wasm-file","title":"Step 3: Compile your C code to create your .wasm file","text":"
cd hello-proj\nclang --target=wasm32 -nostdinc -nostdlib -isystem ./node_modules/twr-wasm/include -c  helloworld.c -o helloworld.o\nwasm-ld  helloworld.o ./node_modules/twr-wasm/lib-c/twr.a -o helloworld.wasm  --no-entry --initial-memory=131072 --max-memory=131072 --export=hello \n

The path to twr.a and to include should match your installation. The above path is correct for this example.

As an alternate to executing clang and wasm-ld from the shell, here is a Makefile that will work for this example:

Makefile
CC := clang\nTWRCFLAGS := --target=wasm32 -nostdinc -nostdlib -isystem  ./node_modules/twr-wasm/include\nCFLAGS := -c -Wall -O3 $(TWRCFLAGS)\nCFLAGS_DEBUG := -c -Wall -g -O0  $(TWRCFLAGS)\n\n.PHONY: default\n\ndefault: helloworld.wasm\n\nhelloworld.o: helloworld.c\n    $(CC) $(CFLAGS)  $< -o $@\n\nhelloworld.wasm: helloworld.o \n    wasm-ld  helloworld.o ./node_modules/twr-wasm/lib-c/twr.a -o helloworld.wasm \\\n        --no-entry --initial-memory=131072 --max-memory=131072 \\\n        --export=hello \n

Copy the above into a file named Makefile and execute with make (or mingw32-make in windows).

"},{"location":"gettingstarted/helloworld/#step-4-load-and-execute-your-web-page","title":"Step 4: Load and execute your web page","text":"

The two easiest ways to load and execute your index.html web page locally are:

"},{"location":"gettingstarted/helloworld/#option-a-run-a-local-web-server","title":"Option A: Run a local web Server","text":"

You can run a local server to view your helloworld program.

At this pont your folder structure should look like this:

hello-proj\\\n\u2514\u2500\u2500node_modules\\\n\u2514\u2500\u2500helloworld.c\n\u2514\u2500\u2500helloworld.o\n\u2514\u2500\u2500helloworld.wasm\n\u2514\u2500\u2500index.html\n\u2514\u2500\u2500Makefile\n\u2514\u2500\u2500package.json\n\u2514\u2500\u2500server.py\n
"},{"location":"gettingstarted/helloworld/#option-b-vs-code-launchjson","title":"Option B: VS Code launch.json","text":"

Alternately, you can launch chrome without a local web server. Add an entry similar to the following to hello-proj\\.vscode\\launch.json. This assumes your workspaceFolder is hello-proj.

launch.json
{\n    \"configurations\": [\n    {\n        \"name\": \"Launch Chrome Hello, World!\",\n        \"request\": \"launch\",\n        \"type\": \"chrome\",\n        \"runtimeArgs\": [\n            \"--allow-file-access-from-files\",\n            \"--autoplay-policy=no-user-gesture-required\",\n            \"--enable-features=SharedArrayBuffer\"\n         ],\n         \"file\": \"${workspaceFolder}/index.html\",\n         \"cwd\": \"${workspaceFolder}/\",\n    }\n    ]\n}\n

Once you have created this file, you:

--autoplay-policy=no-user-gesture-required and --enable-features=SharedArrayBuffer are not required for this simple \"hello world\" example, but will be needed if you request user input or you are using twrWasModuleAsync.

"},{"location":"gettingstarted/helloworld/#see-live-version","title":"See live version","text":"

You can find a live link to hello world on this page.

"},{"location":"gettingstarted/helloworld/#next-steps-after-hello-world","title":"Next steps after hello world","text":"

A good way to get your own code up and running is to copy one of the examples, get it to build and run, then start modifying it. Note you will need to modify the paths for include, lib-js, lib-c, etc. based on your project structure. The examples are all setup with relative paths assuming the folder structure twr-wasm\\examples\\<example>

The examples include MakeFiles.

\"Hello World\" uses the twr-wasm class twrWasmModule. If you wish to use C blocking functions, such as twr_getc32 or twr_sleep, you should use twrWasmModuleAsync. This square calculator example shows how to do this.

If you wish to build an app that makes non-block calls into C, the balls example shows how to do this. The maze example uses a combination of blocking and non-blocking C functions.

"},{"location":"gettingstarted/helloworld/#debugging","title":"Debugging","text":"

See the debugging section for debugging tips, including setting up Wasm source level debugging.

"},{"location":"gettingstarted/installation/","title":"Installing twr-wasm","text":"

A simple way to install twr-wasm is:

npm install twr-wasm\n

See the \"Hello World walk through\" in the following section for more specifics.

There are actually two methods of installation with different pros and cons:

When using twr-wasm your applications needs to access both JavaScript and C twr-wasm libraries. This is explained in the installation sections below, as well as in the Hello World walk through.

"},{"location":"gettingstarted/installation/#npm-install","title":"npm install","text":"

npm install twr-wasm\n
After installation from npm, you will have a folder structure like this:

node_modules\\\n   twr-wasm\\\n      examples\\\n      include\\\n      lib-c\\\n      lib-js\\\n      LICENSE\n      package.json\n      readme.md\n
The JavaScript and TypeScript exports are in lib-js and should be found by VS Code, TypeScript or your bundler as usual when using a statement like import {twrWasmModule} from \"twr-wasm\".

The C library (twr.a) that you will need to link your C/C++ program to is found in the libs-c folder, and the C/C++ include files that you will need to use in your C/C++ program are found in the include folder. You will need to use paths to to these folders in your makefile. See the Hello World walk through for details.

There is no real downside to this installation method, except possibly: (1) it does not include source code (use git clone for that), and (b) the C libraries are buried inside your node_modules.

"},{"location":"gettingstarted/installation/#git-install","title":"git install","text":"
 git clone https://github.com/twiddlingbits/twr-wasm\n

This method of installation installs the complete code base, including source and built binaries.

The primary downside to this method is that the JavaScript side of twr-wasm will not be placed in a node_modules folder. This will create a little extra work to configure a bundler, TypeScript or VS Code to find the location of imports.

There are a few solutions to this. For example, in the provided Hello World example, a package.json file with an alias entry is used. This syntax is supported by the Parcel bundler:

{\n   \"@parcel/resolver-default\": {\n      \"packageExports\": true\n   },\n   \"alias\": {\n      \"twr-wasm\": \"../../lib-js/index.js\"\n   },\n   \"dependencies\": {\n      \"twr-wasm\": \"^2.0.0\"\n   }\n}\n

The FFT example uses the paths entry in the tsconfig.json file. This is found by TypeScript, VS Code and the Parcel bundler. This is probably the best solution if you are using TypeScript.

\"paths\": {\n   \"twr-wasm\": [\"./../../lib-js/index\"]\n}\n

The paths for alias and paths shown above are correct for the included examples, but will likely need to be adjust for your project.

"},{"location":"gettingstarted/installation/#note-on-examples","title":"Note on Examples","text":"

All of the examples have makefiles that use a relative path for twr.a and includes. These paths will work fine if your code is in an examples sub-folder as a peer to the other examples. But assuming your code is in your own project folder elsewhere, you will need to determine the correct path to twr.a and includes for your project's makefile. Details on how to do this can be found in the following sections: Hello World walk through and the Compiler and Linker Options section.

"},{"location":"gettingstarted/installation/#clang-and-wasm-ld","title":"clang and wasm-ld","text":"

To build C/C++ code for use in your Wasm project, you will need to install clang and the wasm-ld linker. If you are using Windows, more details can be found at the end of the Building Source section.

"},{"location":"gettingstarted/installation/#python","title":"python","text":"

To use the included examples\\server.py you will need to install python. server.py is a simple HTTP server for local testing that sets the correct CORS headers for twrWasmModuleAsync. As explained in the following Hello World walk through, you can alternately execute HTML files directly using VS Code and Chrome.

"},{"location":"gettingstarted/parameters/","title":"Passing Function Arguments to WebAssembly","text":"

This article describes techniques to transfer data between JavaScript/TypeScript and C/C++ when using WebAssembly. It delves a bit \u201cunder the covers\u201d to explain how this works when you use a library like twr-wasm or Emscripten. In this article, I am using twr-wasm for the examples. Emscripten does something similar.

For an example that illustrates the concepts discussed here, see: the callC example.

"},{"location":"gettingstarted/parameters/#webassembly-virtual-machine-intrinsic-capabilities","title":"WebAssembly Virtual Machine Intrinsic Capabilities","text":"

The WebAssembly VM (often referred to as a Wasm \u201cRuntime\u201d) is limited to passing numbers between C functions and the Wasm host (I\u2019ll assume that\u2019s JavaScript for this document). In other words, if you are using the most basic WebAssembly capabilities provided by JavaScript, such as WebAssembly.Module, WebAssembly.Instance, and instance.exports, your function calls and return types can only be:

These correspond to the WebAssembly spec support for: i32, i64, f32, and f64.

Note that a JavaScript number is of type Float 64 (known as a double in C/C++.). If you are storing an integer into a JavaScript number, it is converted to a Float 64, and its maximum \"integer\" precision is significantly less than 64 bits (its about 52 bits, but this is a simplification). As a result, to use a 64-bit integers with JavaScript the bigint type is used.

When using 32-bit WebAssembly (by far the most common default), and you call a C function from JavaScript without using any \u201chelper\u201d libraries (like twr-wasm), the following argument types can be passed:

The same rules apply to the return types.

"},{"location":"gettingstarted/parameters/#c-structs-javascript-c","title":"C Structs: JavaScript <--> C","text":"

This section shows how to create a C struct in JavaScript, then pase it to a C function, and then read the modified C struct in JavaScript.

Although the techniques described here are explained with a struct example, the basic techniques are used with other data types as well (such as strings). For common data types, like a string, libraries like twr-wasm will handle these details for you automatically.

To create and pass a C struct from JavaScript to C, the technique is to call the WebAssembly C malloc from JavaScript to allocate WebAssembly memory and then manipulating the memory in JavaScript. One complexity is that each struct entry\u2019s memory address needs to be calculated. And when calculating the WebAssembly Memory indices for the struct entries, C structure padding must be accounted for.

"},{"location":"gettingstarted/parameters/#struct-entry-padding","title":"struct Entry Padding","text":"

Before we delve into the actual code, lets review C struct entry padding.

In clang, if you declare this structure in your C code:

struct test_struct {\n    int a;\n    char b;\n    int *c;\n};\n

This behavior is dependent on your compiler, cpu, and whether you are using 32 or 64-bit architecture. For wasm32 with clang:

If you are not familiar with structure padding, there are many articles on the web.

Alignment requirements are why twr-wasm malloc (and GCC malloc for that matter) aligns new memory allocations on an 8-byte boundary.

"},{"location":"gettingstarted/parameters/#creating-a-struct-in-javascript","title":"Creating a struct in JavaScript","text":"

We can create and initialize the above struct test_struct like this in JavaScript:

//...\nconst mod = new twrWasmModule();\n//...\nconst structSize=12;\nconst structIndexA=0;\nconst structIndexB=4;\nconst structIndexC=8;   // compiler allocates pointer on 4 byte boundaries\nlet structMem=await mod.malloc(structSize);\nlet intMem=await mod.malloc(4);\nmod.setLong(structMem+structIndexA, 1);\nmod.mem8[structMem+structIndexB]=2;    // you can access the memory directly with the mem8, mem32, and memD (float64 aka double) byte arrays.\nmod.setLong(structMem+structIndexC, intMem);\nmod.setLong(intMem, 200000);\n

note that:

"},{"location":"gettingstarted/parameters/#passing-struct-to-c-from-javascript","title":"Passing struct to C from JavaScript","text":"

Assume we have C code that adds 2 to each entry of the test_struct:

__attribute__((export_name(\"do_struct\")))\nvoid do_struct(struct test_struct *p) {\n    p->a=p->a+2;\n    p->b=p->b+2;\n    (*p->c)++;\n    (*p->c)++;\n}\n

Once the struct has been created in JavaScript, you can call the C function do_struct that adds 2 to each entry like this in twr-wasm:

await mod.callC([\"do_struct\", structMem]);  // will add two to each value\n
"},{"location":"gettingstarted/parameters/#accessing-returned-c-struct-in-javascript","title":"Accessing returned C struct in JavaScript","text":"

You access the returned elements like this using JavaScript:

success=mod.getLong(structMem+structIndexA)==3;\nsuccess=success && mod.mem8[structMem+structIndexB]==4;\nconst intValPtr=mod.getLong(structMem+structIndexC);\nsuccess=success && intValPtr==intMem;\nsuccess=success && mod.getLong(intValPtr)==200002;\n

You can see the additional complexity of de-referencing the int *.

"},{"location":"gettingstarted/parameters/#cleanup","title":"Cleanup","text":"

You can free the malloced memory like this:

await mod.callC([\"free\", intMem]);    // unlike malloc, there is no short cut for free, yet\nawait mod.callC([\"free\", structMem]);\n

The complete code for this example is here.

"},{"location":"gettingstarted/parameters/#passing-strings-from-javascript-to-cc-webassembly","title":"Passing Strings from JavaScript to C/C++ WebAssembly","text":"

Although you can use the technique I am about to describe here directly (by writing your own code), it is generally accomplished by using a third-party library such as twr-wasm or Emscripten. These libraries handle the nitty-gritty for you.

To pass a string from JavaScript/TypeScript to a WebAssembly module, the general approach is to:

In the case of twr-wasm, the above steps are handled automatically for you by the callC function:

mod.callC([\"my_function\", \"this is my string\"]);  // mod is instance of twrWasmModule\n

Under the covers, to pass \"this is my string\" from JavaScript to the C Web Assembly function, callC will execute code like this:

// twrWasmModule member function\nasync putString(sin:string, codePage = codePageUTF8) {\n    const ru8 = this.stringToU8(sin, codePage);  // convert a string to UTF8 encoded characters stored in a Uint8Array\n    const strIndex = await this.malloc(ru8.length + 1);  // shortcut for: await this.callC([\"malloc\", ru8.length + 1]);\n    this.mem8.set(ru8, strIndex);  // mem8 is of type Uint8Array and is the Wasm Module\u2019s Memory\n    this.mem8[strIndex + ru8.length] = 0;\n    return strIndex;\n}\n
this.malloc is the standard C runtime malloc function, provided by twr-wasm, and linked into your .wasm code that is loaded into the WebAssembly Module. Likewise, twr-wasm will call free after the function call is executed.

"},{"location":"gettingstarted/parameters/#returning-a-string-from-cc-webassembly-to-javascript","title":"Returning a String from C/C++ WebAssembly to JavaScript","text":"

Returning a string from C to JavaScript is the reverse of passing in a string from JavaScript to C. When the \u201craw\u201d WebAssembly capabilities are used (WebAssembly.Module, etc.) and your C code looks like this:

return(\"my string\");\n

The WebAssembly VM and JavaScript host will cause your JavaScript to receive an unsigned 32-bit integer. This is the pointer to the string, cast to an unsigned 32-bit integer. This integer is an index into the WebAssembly Memory.

twr-wasm provides a function to pull the string out of WebAssembly Memory and convert the character encoding to a JavaScript string. JavaScript strings are Unicode 16, but twr-wasm supports ASCII, UTF-8, and windows-1252 string encoding. When extracted and converted, a copy of the string is made.

const retStringPtr = await mod.callC([\"ret_string_function\"]);\nconsole.log(mod.getString(retStringPtr));\n

The retStringPtr is an integer 32 (but converted to a JavaScript number, which is Float 64). This integer is an index into the WebAssembly Memory.

"},{"location":"gettingstarted/parameters/#passing-arraybuffers-from-javascript-to-cc-webassembly","title":"Passing ArrayBuffers from JavaScript to C/C++ WebAssembly","text":"

When callC in twr-wasm is used to pass an ArrayBuffer to and from C/C++, some details are handled for you. The technique is similar to that used for a string or as performed manually for a struct above, with the following differences:

Here is an example:

let ba = new Uint8Array(4);\nba[0] = 99; ba[1] = 98; ba[2] = 97; ba[3] = 6;\nconst ret_sum = await mod.callC([\"param_bytearray\", ba.buffer, ba.length]);\n

See this example for the complete example.

"},{"location":"gettingstarted/parameters/#passing-a-javascript-object-to-webassembly","title":"Passing a JavaScript Object to WebAssembly","text":""},{"location":"gettingstarted/parameters/#simple-case-use-c-struct","title":"Simple Case - use C struct","text":"

For a simple object like this:

const a = 'foo';\nconst b = 42;\n\nconst obj = {\n  a: a,\n  b: b\n};\n

It is straightforward to convert to a C struct like this:

struct obj {\n    const char* a;\n    int b;\n};\n
To pass this JavaScript object to WebAssembly, a C struct is created (using the struct techniques described above). Each object entry is then copied into the corresponding C struct entry (using the struct and string techniques described above).

"},{"location":"gettingstarted/parameters/#more-complicated-object","title":"More Complicated Object","text":"

A JavaScript object can contain entries that are of more complexity than simple C data types. For example:

const a = 'foo';\nconst b = 42;\nconst map = new Map();\nmap1.set('a', 1);\nmap1.set('b', 2);\nmap1.set('c', 3);\nconst object2 = { a: a, b: b, c: map };\n

In this case, you are going to have to do more work. An approach is to use the libc++ map class, which is similar to the JavaScript Map. You could also perhaps use the libc++ vector.

To handle this more complicated JavaScript object with a Map entry, an approach is to export functions from WebAssembly to create and add entries to the libc++ map (you need to use extern 'C' to export these C++ access functions as C functions). In otherworld, you might export from your Wasm Module C functions like this:

void* createMap();   // return an unsigned long Map ID\nvoid addIntToMap(void* mapID, int newInt);\n

You would then use these functions in JavaScript to build your C++ map. JavaScript would access this map using the unsigned long identifier (the void * returned by createMap). After creating and adding entries to the map, you would set this MapID to object2.c.

There are alternative approaches. For example, you could convert the JavaScript Map to a C struct, by enumerating every entry in the Map. Your C struct might look like: `

struct entry {\n    char* name;\n    int value;\n};\n\nstruct mapUnroll {\n    int MapLen;\n    struct entry* entries[];\n};\n

This approach is probably even more work, less general purpose, and less efficient.

"},{"location":"gettingstarted/parameters/#summary","title":"Summary","text":"

I hope this has demystified how JavaScript values are passed to and from WebAssembly. In many cases, functions like twr-wasm's mod.callC will handle the work for you. But in more bespoke cases, you will have to handle some of the work yourself.

"},{"location":"gettingstarted/stdio/","title":"Stdio with C/C++ WebAssembly","text":"

This section describes how you can direct C/C++ standard input or output to or from a div or canvas tag in a twr-wasm C/C++ Wasm project.

"},{"location":"gettingstarted/stdio/#use-div-or-canvas-tag","title":"Use div or canvas tag","text":"

Standard input and output can be directed to a <div> or to a <canvas> HTML tag. Using a <div> is a simple way to display the output of a printf, or to get input from getc (using traditional standard library blocking input).

A <canvas> tag can be used by twr-wasm to create a simple ANSI style terminal or console. This windowed terminal supports the same streamed output and input features as a does a div tag, but also supports x,y coordinates, colors, and other features. The window console supports chunky (low res) graphics (each character cell can be used as a 2x3 graphic array).

Another difference between a div stream and a canvas stream, is that a div tag will grow as more text is added. On the other hand, a canvas tag has a fixed width and height, and additional text will cause a scroll as it fills up the window.

Unicode characters are supported by stdout and stdin (see Character Encoding Support with twr-wasm).

"},{"location":"gettingstarted/stdio/#div-or-canvas-tag-discovery-order","title":"div or canvas tag discovery order","text":"

If you wish to use a div or canvas tag for stdio when using twr-wasm, in your HTML file add a <div id=\"twr_iodiv\"> or alternately a <canvas id=\"twr_iocanvas\"> tag.

Note that you can also add a <canvas id=\"twr_d2dcanvas\"> to your HTML to define a canvas to be used by twr-wasm's 2D drawing APIs.

"},{"location":"gettingstarted/stdio/#stderr","title":"stderr","text":"

stderr streams to the browser's debug console.

"},{"location":"gettingstarted/stdio/#examples","title":"Examples","text":"Name View Live Link Source Link stdin and stdout to <div> View square demo Source simple \"terminal\" via <canvas> View hello world demo Source \"cli\" with a <canvas> stdio View CLI demo using libc++ Source"},{"location":"gettingstarted/stdio/#io-console-docs","title":"IO Console Docs","text":"

stdin, stdout, and stderr are abstracted by a twr-wasm IO Consoles.

"},{"location":"gettingstarted/stdio/#utf-8-or-windows-1252","title":"UTF-8 or Windows-1252","text":"

Stdin and stdout can support UTF-8 or Windows-1252 character encodings (see Character Encoding Support with twr-wasm).

"},{"location":"gettingstarted/stdio/#includes","title":"Includes","text":"

#include <stdio.h> to access stdout, stdin, stderr, and FILE.

FILE is supported for user input and output, and for stderr. File i/o (to a filesystem) is not currently supported.

"},{"location":"gettingstarted/stdio/#stdout-and-stderr-functions","title":"stdout and stderr functions","text":"

You can use these functions to output to the standard library defines stderr or stdout:

fputc, putc, vfprintf, fprintf, fwrite\n

You can also use the IO Console functions referenced above to send to stdout and stderr.

These functions go to stdout:

printf, vprintf, puts, putchar\n

Note that when characters are sent to the browser console using stderr they will not render to the console until a newline, return, or ASCII 03 (End-of-Text) is sent.

For example:

#include <stdio.h>\n\nfprintf(stderr, \"hello over there in browser debug console land\\n\");\n

A more common method to send output to the debug console is to use twr_conlog. See General C API Section.

"},{"location":"gettingstarted/stdio/#stdin-functions","title":"stdin functions","text":"

Reading from stdin is blocking, and so twrWasmModuleAsync must be used to receive keys from stdin. See the next section for the needed JavaScript line.

You can get characters from stdin with any of these functions:

"},{"location":"gettingstarted/stdio/#javascript-needed-for-char-input","title":"JavaScript needed for char input","text":"

twrWasmModuleAsync must be used to receive keys from stdin. In addtion, you should add a line like the following to your JavaScript for stdin to work:

If using twr_iodiv

document.getElementById(\"twr_iodiv\").addEventListener(\"keydown\",(ev)=>{amod.keyDownDiv(ev)});\n

If using twr_iocanvas

document.getElementById(\"twr_iocanvas\").addEventListener(\"keydown\",(ev)=>{amod.keyDownCanvas(ev)});\n

You likely want a line like this to automatically set the focus to the div or canvas element (so the user doesn't have to click on the element to manually set focus. Key events are sent to the element with focus.):

document.getElementById(\"twr_iocanvas\").focus();\n

You will also need to set the tabindex attribute in your div tag like this:

<div id=\"twr_iodiv\" tabindex=\"0\"></div>\n

See the stdio-div and stdio-canvas examples.

"},{"location":"gettingstarted/stdio/#sending-asyncronous-events-to-wasm-functions","title":"Sending asyncronous events to Wasm functions","text":"

Note that this section describes blocking input using stdin. As an alternative, you can send events (keyboard, mouse, timer, etc) to a non-blocking C function from JavaScript using callC. See the balls example.

"},{"location":"more/building/","title":"Building the twr-wasm Source","text":""},{"location":"more/building/#source-for-twr-wasm","title":"Source for twr-wasm","text":"

The source can be found at:

https://github.com/twiddlingbits/twr-wasm\n

The main branch contains the latest release. The dev branch is work in progress.

"},{"location":"more/building/#tools-needed-to-build-twr-wasm-source","title":"Tools Needed to Build twr-wasm Source","text":"

You will need these core tools, versions used in release are in ():

In addition, you might need:

There is a deprecated gcc build that I used to use for testing, but now the tests are executed in wasm.

"},{"location":"more/building/#to-build-the-libraries-lib-c-lib-js","title":"To Build the Libraries (lib-c, lib-js)","text":"

cd source\nmake\n
or on windows
cd source\nmingw32-make\n

"},{"location":"more/building/#to-build-the-examples","title":"To Build the Examples","text":"

See examples/readme.md for more information.

To build the examples, but not bundle them.

cd examples\nsh buildall.sh\n

To build bundles:

sh buildbundles.sh\n

"},{"location":"more/building/#to-build-the-docs","title":"To Build the docs","text":"

The docs are created using the material theme for mkdocs.

In twr-wasm root folder:

mkdocs build\n

The destination of the build is found in the mkdocs.yml file (site_dir: azure/docsite/).

Usually the docs are built as part of building the static web site that hosts the docs and examples. This is accomplished using this shell script (found in examples folder):

buildazure.sh\n

"},{"location":"more/building/#to-build-libc-for-wasm-and-twr-wasm","title":"To Build libc++ for Wasm and twr-wasm","text":"

See the instructions in the comments in the shell script source\\libcxx\\buildlibcxx.sh

"},{"location":"more/building/#installing-clang-and-wasm-ld-on-windows","title":"Installing clang and wasm-ld on Windows","text":"

Here is how I installed the tools for windows:

 install  MSYS2 \n   1. https://www.msys2.org/\n   2. After the install completes, run UCRT64 terminal by clicking on the MSYS2 UCRT64 in the Start menu\n   3. pacman -Syuu\n\n install gcc using MSYS2 UCRT64\n   1. Use MSYS2 UCRT64 terminal (per above)\n   1. pacman -S mingw-w64-ucrt-x86_64-toolchain\n\n install clang and wasm-ld using MSYS2 UCRT64\n   2. Use MSYS2 UCRT64  (per above)\n      1. pacman -S mingw-w64-ucrt-x86_64-clang\n      2. pacman -S mingw-w64-x86_64-lld\n\nupdate PATH env variable using the windows control panel (search for path)\n   2. added C:\\msys64\\ucrt64\\bin \n   3. added C:\\msys64\\mingw64\\bin \n   4. added C:\\msys64\\usr\\bin (for sh.exe used by mingw32-make)\n

wabt tools: can be found here https://github.com/WebAssembly/wabt/releases

"},{"location":"more/production/","title":"CORS headers needed to use twrWasmModuleAsync","text":"

Important Production Note

twr-wasm class twrWasmModuleAsync uses SharedArrayBuffers, and there are special CORS headers that need to be configured to use SharedArrayBuffers, that are not widely enabled by default on web servers. The server.py or staticwebapp.config.json examples show which headers to set (also see the SharedArrayBuffer documentation online).

"},{"location":"more/wasm-problem/","title":"Wasm Runtime Limitations","text":"

HTML browsers can load a WebAssembly module, and execute it's bytecode in a virtual machine. To create this bytecode (.wasm file) from C/C++, you compile your code using clang with the target code format being WebAssembly (aka Wasm) byte code. If you are not using a support library like twr-wasm or emscripten, there are a few issues that one immediately encounters trying to execute code that is more complicated than squaring a number.

The Wasm virtual machine simply executes the instructions that are generated by the clang compiler and linked by the linker into the .wasm file. The first issue encountered is that some code that is generated by a compiler assumes a compiler support library will be linked to your code. That is, clang code generation will produce calls to compiler support routines for floating point, memcpy, and the like. In clang, these support routines are in the \"compile-rt\" support library. Typically clang handles this behind to scenes for you. But support for a WebAssembly version of this compiler support library is not (as of this writing) included in a clang distribution.

The next level up the library stack is the standard C runtime library. This library provides functions like malloc and printf. And then built on the standard C runtime library is the standard c++ library - like libc++. WebAssembly versions of these libraries are also not part of a clang distribution.

To get access to WebAssembly versions of these libraries you need to use emscripten or twr-wasm.

The second problem is that all the function calls between your Wasm module and your javascript are limited to parameters and return values that are numbers (integer and float). No strings, arrays, struct pointers, etc. (for more on this see this doc).

The third problem is that legacy C code or games often block, and when written this way they don't naturally integrate with the JavaScript asynchronous programming model.

twr-wasm is a static C library (twr.a) that you can link to your clang C/C++ Wasm code, as well as a set of JavaScript/TypeScript modules that solve these issues.

In addition, twr-wasm provides APIs that you can use in your WebAssembly code - such as Canvas compatible 2D drawing APIs, a simple ANSI terminal emulator, character encoding support, and more.

"}]} \ No newline at end of file +{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Learn WebAssembly with twr-wasmDocumentation and Examples","text":""},{"location":"#easier-cc-webassembly","title":"Easier C/C++ WebAssembly","text":"

Version 2.3.1

twr-wasm is a simple, lightweight and easy to use library for building C/C++ WebAssembly code directly with clang. It solves some common use cases with less work than the more feature rich emscripten.

twr-wasm is easy to understand, and has some great features. You can call blocking functions. You can input and print streaming character i/o to a <div> tag, use a <canvas> element as an ANSI terminal, and use 2D drawing apis (that are compatible with JavaScript Canvas APIs) to draw to a <canvas> element.

twr-wasm allows you to run C/C++ code in a web browser. Legacy code, libraries, full applications, or single functions can be integrated with JavaScript and TypeScript.

twr-wasm is designed to be used with the standard llvm clang compiler and tools.

twr-wasm was previously named tiny-wasm-runtime.

"},{"location":"#live-webassembly-examples-and-source","title":"Live WebAssembly Examples and Source","text":"Name View Live Link Source Link Bouncing Balls (C++) View bouncing balls Source for balls Pong (C++) View Pong Source for Pong Maze Gen/Solve (Win32 C Port) View live maze Source for maze Input/Output with <div> View square demo Source Mini-Terminal (hello world using <canvas>) View demo Source CLI using libc++ and <canvas>) View console Source"},{"location":"#key-features","title":"Key Features","text":""},{"location":"#hello-world","title":"Hello World","text":"

Here is the simplest twr-wasm example.

helloworld.c
#include <stdio.h>\n\nvoid hello() {\n    printf(\"hello, world!\\n\");\n}\n
index.html
<head>\n   <title>Hello World</title>\n</head>\n<body>\n   <div id=\"twr_iodiv\"></div>\n\n   <script type=\"module\">\n      import {twrWasmModule} from \"twr-wasm\";\n\n      const mod = new twrWasmModule();\n      await mod.loadWasm(\"./helloworld.wasm\");\n      await mod.callC([\"hello\"]);\n   </script>\n</body>\n
"},{"location":"#on-github","title":"On Github","text":"

https://github.com/twiddlingbits/twr-wasm

"},{"location":"#why","title":"Why?","text":"

The Wasm Runtime Limitations section explains why a library like twr-wasm is needed to use WebAssembly.

"},{"location":"#version-2-vs-1","title":"Version 2 vs. 1","text":""},{"location":"#version-2-limitations","title":"Version 2 Limitations","text":""},{"location":"#post-feedback","title":"Post Feedback","text":"

Please post feedback (it worked for you, didn't work, requests, questions, etc) at https://github.com/twiddlingbits/twr-wasm/

"},{"location":"api/api-c-con/","title":"WebAssembly Console API","text":"

twr-wasm for WebAssembly provides a console API for abstracting I/O. This console API is used by stdin, stdout, and stderr, as well as the ANSI Terminal. Streaming and Windowed I/O is supported.

This section describes the C character based input/output console API this is abstracted by struct IoConsole.

Consoles can be \"tty\" aka \"streamed\", or they can be \"windowed\" (aka a \"terminal\").

Also see stdio

"},{"location":"api/api-c-con/#examples","title":"Examples","text":"Name View Live Link Source Link \"terminal\" in/out with a <canvas> View mini-term demo Source"},{"location":"api/api-c-con/#getting-stderr-stdin-stdout","title":"Getting stderr, stdin, stdout","text":"

stdio.h defines stdin, stdout, stderr as explained here: stdio

stdio.h also defines FILE like this:

typedef struct IoConsole FILE; \n

from <stdio.h>:

#define stderr (FILE *)(twr_get_stderr_con())\n#define stdin (FILE *)(twr_get_stdio_con())\n#define stdout (FILE *)(twr_get_stdio_con())\n

"},{"location":"api/api-c-con/#getting-a-new-console","title":"Getting a new console","text":"

stdin and stdout are set as explaind here. However, in unusual cases you might want to access the various consoles directly, regardless of how stdin, stdout, or stderr are set. You can do so like this:

"},{"location":"api/api-c-con/#io_nullcon","title":"io_nullcon","text":"

Returns an IoConsole that goes to the bit bucket. io_getc32 will return 0.

#include \"twr-io.h\"\n\nstruct IoConsole* io_nullcon(void);\n
"},{"location":"api/api-c-con/#twr_debugcon","title":"twr_debugcon","text":"

Returns an IoConsole that goes to the browser's debug console.

#include \"twr-crt.h\"\n\nstruct IoConsole* twr_debugcon(void);\n
"},{"location":"api/api-c-con/#twr_divcon","title":"twr_divcon","text":"

Returns an IoConsole that goes to <div id=\"twr_iodiv\">, if it exists.

#include \"twr-crt.h\"\n\nstruct IoConsole* twr_divcon(void);\n
"},{"location":"api/api-c-con/#twr_windowcon","title":"twr_windowcon","text":"

Returns an IoConsole that goes to <canvas id=\"twr_iocanvas\"> , if it exists.

NOTE: Only one call can be made to this function, and it is usually made by the twr-wasm C runtime, so you likely won't call this function.

#include \"twr-crt.h\"\n\nstruct IoConsole* twr_windowcon(void);\n
"},{"location":"api/api-c-con/#io-console-functions","title":"IO Console Functions","text":""},{"location":"api/api-c-con/#io_putc","title":"io_putc","text":"

Sends a byte to an IoConsole and supports the current locale's character encoding. This function will \"stream\" using the current code page. In other words, if you io_putc ASCII, it will work as \"normal\". If the current locale is set to 1252, then you can send windows-1252 encoded characters. If the current locale is UTF-8, then you can stream UTF-8 (that is, call io_putc once for each byte of the multi-byte UTF-8 character).

Note that when characters are sent to the browser console using stderr they will not render to the console until a newline, return, or ASCII 03 (End-of-Text) is sent.

#include \"twr-io.h\"\n\nvoid io_putc(struct IoConsole* io, unsigned char c);\n
"},{"location":"api/api-c-con/#io_putstr","title":"io_putstr","text":"

Calls io_putc for each byte in the passed string.

#include \"twr-io.h\"\n\nvoid io_putstr(struct IoConsole* io, const char* s);\n
"},{"location":"api/api-c-con/#io_printf","title":"io_printf","text":"

Identical to fprintf, however io_printf will call io_begin_draw and io_end_draw around its drawing activities -- resulting in snapper performance.

For example:

#include \"twr-io.h\"\n\nio_printf(twr_debugcon(), \"hello over there in browser debug console land\\n\");\n

or

#include <stdio.h>\n#include <twr_io.h>\n\nio_printf(stdout, \"hello world\\n\");\n
#include <twr_io.h>\n\nvoid io_printf(struct IoConsole *io, const char *format, ...);\n
"},{"location":"api/api-c-con/#io_getc32","title":"io_getc32","text":"

Waits for the user to enter and then returns a unicode code point. Currently only really works with an IoConsole that is stdin.

To return characters encoded with the current locale, see io_mbgetc

#include <twr_io.h>\n\nint io_getc32(struct IoConsole* io);\n
"},{"location":"api/api-c-con/#io_mbgetc","title":"io_mbgetc","text":"

io_mbgetc will get a character from stdin and encode it using the character encoding of the LC_CTYPE category of the current locale. \"C\" will use ASCII. UTF-8 and windows-1252 are also supported.

#include <twr_io.h>\n\nvoid io_mbgetc(struct IoConsole* io, char* strout);\n
"},{"location":"api/api-c-con/#io_mbgets","title":"io_mbgets","text":"

Gets a string from an IoConsole (which needs to be stdin). Returns when the user presses \"Enter\". Displays a cursor character and echos the inputted characters, at the current cursor position. Uses character encoding of LC_TYPE of current locale.

#include <twr_io.h>\n\nchar *io_mbgets(struct IoConsole* io, char *buffer );\n
"},{"location":"api/api-c-con/#io_get_cursor","title":"io_get_cursor","text":"

Returns an integer of the current cursor position. The cursor is where the next io_putc is going to go.

For windowed consoles, the cursor position ranges from [0, width*height-1], inclusive.

#include <twr_io.h>\n\nint io_get_cursor(struct IoConsole* io);\n
"},{"location":"api/api-c-con/#io_set_colors","title":"io_set_colors","text":"

For windowed consoles only.

Sets a 24 bit RGB default color for the foreground and background. The prior default colors are changed (lost). For example, if you set the default colors when you created the window (see stdio), the defaults will no longer be active. Use io_get_colors to save existing colors for later restoration using io_set_colors.

A call to io_set_colors doesn't actually cause any on screen changes. Instead, these new default colors are used in future draw and text calls. A foreground and background color is set for each cell in the console window. The cell's colors are set to these default foreground/background colors when a call to io_setc, io_setreset, etc is made.

#include <twr_io.h>\n\nvoid io_set_colors(struct IoConsole* io, unsigned long foreground, unsigned long background);\n
"},{"location":"api/api-c-con/#io_get_colors","title":"io_get_colors","text":"

For windowed consoles only.

Gets the current default colors.

#include <twr_io.h>\n\nvoid io_get_colors(struct IoConsole* io, unsigned long *foreground, unsigned long *background);\n
"},{"location":"api/api-c-con/#io_cls","title":"io_cls","text":"

For windowed consoles only.

Clears the screen. That is, all character cells in the window are set to a space, their colors are reset to the current default colors (see io_set_colors).

#include <twr_io.h>\n\nvoid io_cls(struct IoConsoleWindow* iow);\n
"},{"location":"api/api-c-con/#io_setc","title":"io_setc","text":"

For windowed consoles only.

Sets a window cell to a character. Sends a byte to an IoConsole and supports the current locale's character encoding. This function will \"stream\" using the current code page. In other words, if you io_setc ASCII, it will work as \"normal\". If the current locale is set to 1252, then you can send windows-1252 encoded characters. If the current locale is UTF-8, then you can stream UTF-8 (that is, call io_setc once for each byte of the multi-byte UTF-8 character).

#include <twr_io.h>\n\nbool io_setc(struct IoConsoleWindow* iow, int location, unsigned char c);\n
"},{"location":"api/api-c-con/#io_setc32","title":"io_setc32","text":"

For windowed consoles only.

Sets a window cell to a unicode code point. The colors are set to the defaults (see io_set_colors).

#include <twr_io.h>\n\nvoid io_setc32(struct IoConsoleWindow* iow, int location, int c);\n
"},{"location":"api/api-c-con/#io_setreset","title":"io_setreset","text":"

For windowed consoles only.

Sets or resets (clears) a chunky graphics \"pixel\". Each character cell can also be a 2x3 grid of graphic \"pixels\". In other words, the terminal window has pixel dimensions of width2 x height3.

The color will be set to the defaults if the impacted cell is not a graphics cell. If it is an existing graphics cell, the colors don't change.

See the stdio-canvas example.

#include <twr_io.h>\n\nbool io_setreset(struct IoConsoleWindow* iow, int x, int y, bool isset);\n
"},{"location":"api/api-c-con/#io_point","title":"io_point","text":"

For windowed consoles only.

Checks if a chunky graphics \"pixel\" is set or clear. See io_setreset.

#include <twr_io.h>\n\nbool io_point(struct IoConsoleWindow* iow, int x, int y);\n
"},{"location":"api/api-c-con/#io_set_cursor","title":"io_set_cursor","text":"

Moves the cursor. See io_get_cursor.

#include <twr_io.h>\n\nvoid io_set_cursor(struct IoConsoleWindow* iow, int loc);\n
"},{"location":"api/api-c-con/#io_begin_draw","title":"io_begin_draw","text":"

For windowed consoles only.

This call (and its matching io_end_draw) are not required. But if you bracket any call sequence that draws to the terminal window with an io_begin_draw and io_end_draw, the updates will be batched into one update. This will increase performance and usually prevents the user from seeing partial updates.

io_begin_draw can be nested.

See the stdio-canvas example.

#include <twr_io.h>\n\nvoid io_begin_draw(struct IoConsole* io);\n
"},{"location":"api/api-c-con/#io_end_draw","title":"io_end_draw","text":"

For windowed consoles only.

See io_begin_draw.

#include <twr_io.h>\n\nvoid io_end_draw(struct IoConsole* io);\n
"},{"location":"api/api-c-d2d/","title":"2D Draw C API for WebAssembly","text":"

This section describes twr-wasm's C D2D API, which allows your WebAssembly module to call many of the JavaScript Canvas APIs. There is also a C++ canvas wrapper class in source/twr-cpp used by the balls and pong examples.

"},{"location":"api/api-c-d2d/#examples","title":"Examples","text":"Name View Live Link Source Link Bouncing Balls (C++) View bouncing balls Source for balls Pong (C++) View Pong Source for Pong Maze (Win32 C Port) View live maze here Source for maze"},{"location":"api/api-c-d2d/#overview","title":"Overview","text":"

To create a canvas surface that you can draw to using the twr-wasm 2D C drawing APIs, add a canvas tag to your HTML named twr_d2dcanvas like this example (you can use any width/height you like):

<canvas id=\"twr_d2dcanvas\" width=\"600\" height=\"600\"></canvas>\n

To draw using the C 2D Draw API:

Commands are queued until flushed -- which will take the batch of queued draw commands, and execute them. The 2D draw APIs will work with either twrWasmModule or twrWasmModuleAsync. With twrWasmModuleAsync, the batch of commands is sent from the worker thread over to the JavaScript main thread for execution. By batching the calls between calls to d2d_start_draw_sequence and d2d_end_draw_sequence, performance is improved.

d2d_flush waits for the commands to finish execution before returning. d2d_flush is called automatically by d2d_end_draw_sequence and so you generally don't need to call it manually.

You pass an argument to d2d_start_draw_sequence specifying how many instructions will trigger an automatic call to d2d_flush. You can make this larger for efficiency, or smaller if you want to see the render progress more frequently. There is no limit on the size of the queue, except memory used in the Wasm module. The d2d_flush function can be called manually call, but this is not normally needed, unless you would like to ensure a sequence renders before your d2d_end_draw_sequence is called, or before the count passed d2d_start_draw_sequence is met.

If you are using twrWasmModuleAsync, or if you are re-rendering the entire frame for each animation update, you should ensure that all of your draws for a complete frame are made without an explicit or implicit call to d2d_flush in the middle of the draw sequence, as this may cause flashing.

"},{"location":"api/api-c-d2d/#functions","title":"Functions","text":"

These are the Canvas APIs currently available in C:

struct d2d_draw_seq* d2d_start_draw_sequence(int flush_at_ins_count);\nvoid d2d_end_draw_sequence(struct d2d_draw_seq* ds);\nvoid d2d_flush(struct d2d_draw_seq* ds);\nint d2d_get_canvas_prop(const char* prop);\n\nvoid d2d_fillrect(struct d2d_draw_seq* ds, double x, double y, double w, double h);\nvoid d2d_strokerect(struct d2d_draw_seq* ds, double x, double y, double w, double h);\nvoid d2d_filltext(struct d2d_draw_seq* ds, const char* str, double x, double y);\nvoid d2d_fillcodepoint(struct d2d_draw_seq* ds, char c, double x, double y);\n\nvoid d2d_measuretext(struct d2d_draw_seq* ds, const char* str, struct d2d_text_metrics *tm);\nvoid d2d_save(struct d2d_draw_seq* ds);\nvoid d2d_restore(struct d2d_draw_seq* ds);\n\nvoid d2d_setlinewidth(struct d2d_draw_seq* ds, double width);\nvoid d2d_setfillstylergba(struct d2d_draw_seq* ds, unsigned long color);\nvoid d2d_setstrokestylergba(struct d2d_draw_seq* ds, unsigned long color);\nvoid d2d_setfillstyle(struct d2d_draw_seq* ds, const char* css_color);\nvoid d2d_setstrokestyle(struct d2d_draw_seq* ds, const char* css_color);\nvoid d2d_setfont(struct d2d_draw_seq* ds, const char* font);\n\nvoid d2d_createlineargradient(struct d2d_draw_seq* ds, long id, double x0, double y0, double x1, double y1);\nvoid d2d_createradialgradient(struct d2d_draw_seq* ds, long id, double x0, double y0, double radius0, double x1, double y1, double radius1);\nvoid d2d_addcolorstop(struct d2d_draw_seq* ds, long gradID, long position, const char* csscolor);\nvoid d2d_setfillstylegradient(struct d2d_draw_seq* ds, long gradID);\nvoid d2d_releaseid(struct d2d_draw_seq* ds, long id);\n\nvoid d2d_beginpath(struct d2d_draw_seq* ds);\nvoid d2d_fill(struct d2d_draw_seq* ds);\nvoid d2d_stroke(struct d2d_draw_seq* ds);\nvoid d2d_moveto(struct d2d_draw_seq* ds, double x, double y);\nvoid d2d_lineto(struct d2d_draw_seq* ds, double x, double y);\nvoid d2d_arc(struct d2d_draw_seq* ds, double x, double y, double radius, double start_angle, double end_angle, bool counterclockwise);\nvoid d2d_bezierto(struct d2d_draw_seq* ds, double cp1x, double cp1y, double cp2x, double cp2y, double x, double y);\n\nvoid d2d_imagedata(struct d2d_draw_seq* ds, long id, void*  mem, unsigned long length, unsigned long width, unsigned long height);\nvoid d2d_putimagedata(struct d2d_draw_seq* ds, long id, unsigned long dx, unsigned long dy);\nvoid d2d_putimagedatadirty(struct d2d_draw_seq* ds, long id, unsigned long dx, unsigned long dy, unsigned long dirtyX, unsigned long dirtyY, unsigned long dirtyWidth, unsigned long dirtyHeight);\n

d2d_measuretext() returns this structure:

struct d2d_text_metrics {\n    double actualBoundingBoxAscent;\n    double actualBoundingBoxDescent;\n    double actualBoundingBoxLeft;\n    double actualBoundingBoxRight;\n    double fontBoundingBoxAscent;\n    double fontBoundingBoxDescent;\n    double width;\n};\n

d2d_get_canvas_prop() returns a value of:

export interface ICanvasProps {\n   charWidth: number,\n   charHeight: number,\n   foreColor: number,\n   backColor: number,\n   widthInChars: number,\n   heightInChars: number,\n   canvasWidth:number,\n   canvasHeight:number\n}\n
"},{"location":"api/api-c-general/","title":"General C API for Wasm","text":""},{"location":"api/api-c-general/#overview","title":"Overview","text":"

This sections describes the \"general\" twr-wasm functions available that don't fit neatly into another category (such as standard C library functions, Draw 2D functions, etc.)

These functions often start with \"twr_\" and are generally found in this include file:

\\twr-wasm\\include\\twr-crt.h

"},{"location":"api/api-c-general/#bzero","title":"bzero","text":"

Set a block of memory to zeros. Calls memset(to, 0, count).

#include <string.h>\n\nvoid bzero (void *to, size_t count);\n
"},{"location":"api/api-c-general/#getc","title":"getc","text":"

This is the standard c library function (see the the standard library docs available on the internet).

Of note this function will return extended ASCII (128-255 inclusive). The extend ASCII are always encoded with Windows-1252 encoding.

See twr_getc32 for a list of related functions.

Note that C character input is blocking and you must use twrWasmModuleAsync -- see stdin for details on how to enable blocking character input.

"},{"location":"api/api-c-general/#twr_atod","title":"twr_atod","text":"

Similar to stdlib atof.

#include \"twr-crt.h\"\n\ndouble twr_atod(const char* str);\n
"},{"location":"api/api-c-general/#twr_atou64","title":"twr_atou64","text":"

Convert a string to a 64 bit unsigned integer, stopping when the first non-valid character is encountered. If len is provided, it will be set to the number of characters read. Radix should be >=2 and <=36 -- for example, 10 is a normal base 10 number and 16 is hexadecimal.

#include \"twr-crt.h\"\n\nint64_t twr_atou64(const char *str, int* len, int radix);\n
"},{"location":"api/api-c-general/#twr_dtoa","title":"twr_dtoa","text":"

The functions to convert double to text are snprintf, fcvt_s,twr_dtoa, twr_toexponential, and twr_tofixed

#include \"twr-crt.h\"\n\nvoid twr_dtoa(char* buffer, int sizeInBytes, double value, int max_precision);\n
"},{"location":"api/api-c-general/#twr_cache_mallocfree","title":"twr_cache_malloc/free","text":"

These functions keep allocated memory in a cache for much faster re-access than the standard malloc/free.

#include \"twr-crt.h\"\n\nvoid *twr_cache_malloc(twr_size_t size);\nvoid twr_cache_free(void* mem);\n
"},{"location":"api/api-c-general/#twr_code_page_to_utf32_streamed","title":"twr_code_page_to_utf32_streamed","text":"

Return a unicode code point (aka utf-32 value) when passed a byte stream that represents an encoded character using the current local's LC_CTYPE code page. A zero is returned if the byte stream has not yet completed a decode.

For example:

int cp\n\nsetlocale(LC_ALL, \"\");  // set to default locale, which will be UTF-8 encoding with local language/region\n\n// turn a UTF-8 Euro into a UTF-32 value\ncp==twr_code_page_to_utf32_streamed(0xE2);\nassert (cp==0);\ncp=twr_code_page_to_utf32_streamed(0x82);\nassert (cp==0);\ncp=twr_code_page_to_utf32_streamed(0xAC);\nassert (cp==0x000020AC);   // Euro Code points\n
#include <locale.h>\n\nint twr_code_page_to_utf32_streamed(unsigned char byte) \n
"},{"location":"api/api-c-general/#twr_conlog","title":"twr_conlog","text":"

twr_conlog prints debug messages to the browser console from your C code.

#include \"twr-crt.h\"\n\nvoid twr_conlog(char* format, ...);\n

Each call to twr_conlog() will generate a single call to console.log() in JavaScript to ensure that you see debug prints. This call is identical to printf, except that it adds a newline.

The current implementation does not wait for the debug string to output to the console before returning from twr_conlog, when using twrWasmModuleAsync. In this case, it can take a small bit of time for the string to make its way across the Worker Thread boundary. This is normally not a problem and results in faster performance. But if your code crashes soon after the debug print, the print might not appear. If you think this is an issue, you can call twr_sleep(1) after your twr_conlog call. This will force a blocking wait for the print to print.

Prior to 1.0, this function was called twr_dbg_printf, and operated slightly differently.

"},{"location":"api/api-c-general/#twr_epoch_timems","title":"twr_epoch_timems","text":"

Returns the number of milliseconds since the start of the epoch.

#include \"twr-wasm.h\"\n\nuint64_t twr_epoch_timems();\n

"},{"location":"api/api-c-general/#twr_getc32","title":"twr_getc32","text":"

Gets a 32 bit unicode code point character from stdin. Unlike the standard C library function getchar, twr_getc32 does not buffer a line (that is, twr_getc32 will return a character before the user presses Enter).

twr_getc32 is implemented as:

int twr_getc32() {\n    return io_getc32(twr_get_stdio_con());\n}\n

Note that stdlib getchar and ungetc are not currently implemented.

Note that C character input is blocking and you must use twrWasmModuleAsync -- see stdin for details on how to enable blocking character input.

Also see:

#include \"twr-crt.h\"\n\nint twr_getc32();\n
"},{"location":"api/api-c-general/#twr_get_navlang","title":"twr_get_navlang","text":"

Returns the BCP 47 language tag as found in javacript navigator.language. If len is not null, it will be filled in with the string length of the language tag.

#include \"twr-crt.h\"\n\nconst char* twr_get_navlang(int *len);\n
"},{"location":"api/api-c-general/#twr_get_current_locale","title":"twr_get_current_locale","text":"
extern inline locale_t twr_get_current_locale(void);\n

twr_get_current_locale will return the locale that has been set by setlocale. It can be used to pass to a function that takes a locale_t.

"},{"location":"api/api-c-general/#twr_localize_numeric_string","title":"twr_localize_numeric_string","text":"

Functions like twr_dtoa do not localize the decimal point. To get a localized decimal point, you can use printf, or alternately twr_localize_numeric_string to post process a string. For example:

char b[10];\nstrcpy(b, \"1.23\");\ntwr_localize_numeric_string(b, twr_get_current_locale());\n// if locale was set to french, then b is now 1,23\n
#include <locale.h>\n\nvoid twr_localize_numeric_string(char* str, locale_t locale);\n
"},{"location":"api/api-c-general/#twr_mem_debug_stats","title":"twr_mem_debug_stats","text":"

Print memory map and malloc stats to stderr or stdout.

(note FILE * is the same as struct IoConsole*)

#include <stdio.h>\n\nvoid twr_mem_debug_stats(struct IoConsole* outcon);\n
"},{"location":"api/api-c-general/#twr_mbgets","title":"twr_mbgets","text":"

Gets a string from stdin. The string will be in the current locale's character encoding -- ASCII for \"C\", and either UTF-8 or windows-1252 for \"\". See localization.

#include \"twr-crt.h\"\n\nchar* twr_mbgets(char* buffer);\n

Internally this function uses the stdio IoConsole -- see the IoConsole section for more advanced input/output.

This function will encode characters as specified by the LC_CTYPE category of the current locale. ASCII is used for \"C\", and UTF-8 and Windows-1252 are also supported (see localization)

Note that C character input is blocking and you must use twrWasmModuleAsync -- see stdin for details on how to enable blocking character input.

"},{"location":"api/api-c-general/#twr_mbslen_l","title":"twr_mbslen_l","text":"

Returns the number of characters in a string using the character encoding of the passed locale (ASCII for \"C\", UTF-8, or windows-1252 for \"\"). You can use twr_get_current_locale to find the current locale.

#include <string.h>\n\nsize_t twr_mbslen_l(const char *str, locale_t locale);\n

"},{"location":"api/api-c-general/#twr_sleep","title":"twr_sleep","text":"

twr_sleep is a traditional blocking sleep function. This function is blocking, and so is only available if you use twrWasmModuleAsync.

#include \"twr-wasm.h\"\n\nvoid twr_sleep(int ms);\n
"},{"location":"api/api-c-general/#twr_tofixed","title":"twr_tofixed","text":"

This function is identical to its JavaScript version.

#include \"twr-wasm.h\"\n\nvoid twr_tofixed(char* buffer, int buffer_size, double value, int dec_digits);\n

The functions to convert double to text are snprintf, fcvt_s,twr_dtoa, twr_toexponential, and twr_tofixed

"},{"location":"api/api-c-general/#twr_toexponential","title":"twr_toexponential","text":"

This function is identical to its JavaScript version.

#include \"twr-wasm.h\"\n\nvoid twr_toexponential(char* buffer, int buffer_size, double value, int dec_digits);\n

The functions to convert double to text are snprintf, fcvt_s,twr_dtoa, twr_toexponential, and twr_tofixed

"},{"location":"api/api-c-general/#twr_strhorizflip","title":"twr_strhorizflip","text":"

Mirror image the passed in string.

#include \"twr-crt.h\"\n\nvoid twr_strhorizflip(char * buffer, int n);\n

"},{"location":"api/api-c-general/#twr_utf8_char_len","title":"twr_utf8_char_len","text":"

Returns the number of bytes in a UTF-8 character (passed as a string pointer). UTF-8 characters can be 1 to 4 bytes in length.

#include <string.h>\n\nint twr_utf8_char_len(const char *str);\n

"},{"location":"api/api-c-general/#twr_utf32_to_code_page","title":"twr_utf32_to_code_page","text":"

Takes a utf32 value (aka unicode code point value), and fills in the passed character array buffer with the character encoding of the utf32 value, using the current locale's LC_CTYPE code page. The buffer is 0 terminated.

Also see c32rtomb and c16rtomb.

For example:

char strbuf[6];             // max size of utf-8 is 4+terminating zero.  Max size of ASCII or windows 1252 is 1 + terminating zero\nsetlocale(LC_ALL, \"\");  // set to default locale, which will be UTF-8 encoding with local language/region\ntwr_utf32_to_code_page(strbuf, 0x000020AC);  // encode a Euro code point \nprintf(\"%s\", strbuf); \nassert ( strcmp(strbuf,\"\\xE2\\x82\\xAC\")==0 );  // utf-8 encoding of euro\nassert ( strcmp(strbuf,\"\u20ac\")==0 );           // clang string literals default to utf-8 encoding\n

include <locale.h>\n\nvoid twr_utf32_to_code_page(char* out, int utf32)\n
"},{"location":"api/api-c-general/#twr_vprintf","title":"twr_vprintf","text":"

Performs a printf by calling the callback with cbdata for each character.

#include \"twr-crt.h\"\n\nvoid twr_vprintf(twr_cbprintf_callback out, void* cbdata, const char *format, va_list* args);\n

"},{"location":"api/api-c-general/#floating-math-helpers","title":"floating math helpers","text":"
int twr_isnan(double v);\nint twr_isinf(double v);\ndouble twr_nanval();\ndouble twr_infval();\n
"},{"location":"api/api-c-stdlib/","title":"Standard C library for WebAssembly","text":"

This section describes twr-wasm's support for the Standard C Library. twr-wasm includes its own implementation of the standard C library optimized for WebAssembly and Wasm running in a web browser. This is a core feature of twr-wasm.

For documentation of these functions, see the many standard C library documentation web sites.

The following subset of the standard C library is available. Also see twr-wasm/include folder for include files.

"},{"location":"api/api-c-stdlib/#stdioh","title":"stdio.h","text":"
* fprintf will only work with these -- stderr, stdin, stdout */\n/* these return 'struct IoConsole *' which is same as 'FILE *' */\n#define stderr (FILE *)(twr_get_stderr_con())\n#define stdin (FILE *)(twr_get_stdio_con())\n#define stdout (FILE *)(twr_get_stdio_con())\n\nint snprintf(char *buffer, size_t bufsz, const char *format, ... );\nint sprintf( char *buffer, const char *format, ... );\nint vsnprintf(char *buffer, size_t bufsz, const char *format, va_list vlist);\nint vasprintf(char **strp, const char* format, va_list vlist );\nint printf(const char* format, ...);\nint vprintf(const char* format, va_list vlist );\nint puts(const char *str);\nint putchar(int c);\n\ntypedef struct IoConsole FILE; \nint vfprintf(FILE *stream, const char *format, va_list vlist);\nint fprintf(FILE *stream, const char* format, ...);\nsize_t fwrite(const void* buffer, size_t size, size_t count, FILE* stream);\nint ferror(FILE *stream);\nint feof(FILE *stream);\nint fflush(FILE *stream);\nint is_terminal(FILE *stream);\nint fputc(int ch, FILE* stream);\nint putc(int ch, FILE* stream);\nint fgetc(FILE *stream );\nint getc(FILE *stream);\n
"},{"location":"api/api-c-stdlib/#stdlibh","title":"stdlib.h","text":"
void *malloc(size_t size);\nvoid free(void *mem);\nsize_t avail(void);\nvoid *realloc( void *ptr, size_t new_size );\nvoid* calloc( size_t num, size_t size );\nvoid *aligned_alloc( size_t alignment, size_t size );\n\nint rand(void);\nvoid srand(int seed);\n\n#define __min(a,b) (((a) < (b)) ? (a) : (b))\n#define __max(a,b) (((a) > (b)) ? (a) : (b))\n\nint _fcvt_s(\n   char* buffer,\n   size_t sizeInBytes,\n   double value,\n   int fracpart_numdigits,\n   int *dec,\n   int *sign\n);\ndouble atof(const char* str);\nint atoi(const char *str);\nlong atol( const char *str );\nlong long atoll( const char *str );\nlong strtol(const char *str, char **str_end, int base);\nlong long strtoll(const char *str, char **str_end, int base);\nlong long strtoll_l(const char *str, char **str_end, int base,  locale_t loc);\nunsigned long long strtoull(const char *str, char **str_end,  int base);\nunsigned long long strtoull_l(const char *str, char **str_end,  int base, locale_t loc);\nunsigned long strtoul(const char *str, char ** str_end,  int base);\nfloat strtof(const char *str, char ** str_end);\nfloat strtof_l(const char *str, char ** str_end, locale_t locale);\ndouble strtod(const char *str, char **str_end);\ndouble strtod_l(const char *str, char **str_end, locale_t locale);\nlong double strtold(const char *str, char **str_end);\nlong double strtold_l(const char *str, char **str_end, locale_t locale);\nint _itoa_s(int64_t value, char * buffer, size_t size, int radix);\n\ndiv_t div( int x, int y );\nldiv_t ldiv( long x, long y );\nlldiv_t lldiv( long long x, long long y );\n\n_Noreturn void abort(void);\nint atexit(void (*func)(void));\n

Note that _fcvt_s as currently enabled has these limitations: - fractional digits <=100 - values must be less than 1e+21 - values negative exponents must be smaller than 1e-99

There is a full featured version of _fcvt_s in the source code, but is not currently enabled, since the version enabled is smaller and works in most use cases.

"},{"location":"api/api-c-stdlib/#asserth","title":"assert.h","text":"
void assert(int expression);\n
"},{"location":"api/api-c-stdlib/#mathh","title":"math.h","text":"
int abs(int n);\ndouble acos(double arg);\ndouble asin(double arg);\ndouble atan(double arg);\ndouble ceil(double arg);\ndouble cos(double arg);\ndouble exp(double arg);\ndouble fabs(double arg);\ndouble floor(double arg);\ndouble fmod(double x, double y);\ndouble log(double arg);\ndouble pow(double base, double exp);\ndouble sin(double arg);\ndouble sqrt(double arg);\ndouble tan(double arg);\ndouble trunc(double arg);\n
"},{"location":"api/api-c-stdlib/#stdargh","title":"stdarg.h","text":"
#define va_start(v,l)   __builtin_va_start(v,l)\n#define va_end(v)   __builtin_va_end(v)\n#define va_arg(v,l) __builtin_va_arg(v,l)\n#define va_copy(d,s)    __builtin_va_copy(d,s)\ntypedef __builtin_va_list va_list;\n
"},{"location":"api/api-c-stdlib/#ctypeh","title":"ctype.h","text":"
int isascii(int);\nint toascii(int);\nint isalnum(int c);\nint isalpha(int c);\nint isblank(int);\nint iscntrl(int);\nint isdigit(int c);\nint isgraph(int c);\nint islower(int);\nint isprint(int);\nint ispunct(int);\nint isspace(int c);\nint isupper(int);\nint isxdigit(int);\nint tolower(int c);\nint toupper(int c);\n\nint isalnum_l(int c, locale_t loc);\nint isalpha_l(int c, locale_t loc);\nint isblank_l(int c, locale_t loc);\nint iscntrl_l(int c, locale_t loc);\nint isdigit_l(int c, locale_t loc);\nint isgraph_l(int c, locale_t loc);\nint islower_l(int c, locale_t loc);\nint isprint_l(int c, locale_t loc);\nint ispunct_l(int c, locale_t loc);\nint isspace_l(int c, locale_t loc);\nint isupper_l(int c, locale_t loc);\nint isxdigit_l(int c, locale_t loc);\nint tolower_l(int c, locale_t loc);\nint toupper_l(int c, locale_t loc);\n
"},{"location":"api/api-c-stdlib/#stddefh","title":"stddef.h","text":"
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)\ntypedef __PTRDIFF_TYPE__ ptrdiff_t;\ntypedef double max_align_t;\n
"},{"location":"api/api-c-stdlib/#stringh","title":"string.h","text":"
size_t strlen(const char * str);\nchar *strdup(const char * source);\nchar *strcpy(char *dest, const char *source);\nint strcat_s(char *dest, size_t destsz, const char *src);\nchar* strcat(char *dest, const char *src);\nchar *strncpy(char *dest, const char *source, size_t count);\nint strcmp(const char* string1, const char* string2);\nint strncmp(const char* lhs, const char* rhs, size_t count);\nint stricmp(const char* string1, const char* string2);\nint strnicmp(const char* string1, const char* string2, size_t count);\nint strcoll(const char* lhs, const char* rhs);\nint strcoll_l(const char* lhs, const char* rhs,  locale_t loc);\nchar *strchr(const char *str, int ch);\nvoid *memchr(const void *ptr, int ch, size_t count);\nchar *strstr(const char *haystack, const char *needle);\nchar * strerror(int errnum );\nchar * _strerror(const char *strErrMsg);\nvoid *memmove(void *dest, const void *src, size_t n);\nint memcmp( const void* lhs, const void* rhs, size_t count );\nvoid bzero (void *to, size_t count);\n\n// implemented in memcpy.wat\nvoid *memcpy(void *dest, const void * src, size_t n);\nvoid *memset(void *mem, int c, size_t n);\n
"},{"location":"api/api-c-stdlib/#timeh","title":"time.h","text":"
typedef unsigned long time_t;\nunsigned long time(unsigned long *time);\nsize_t strftime(char *s, size_t maxsize, const char *format, const struct tm *timeptr);\nsize_t strftime_l(char *s, size_t maxsize, const char *format, const struct tm *timeptr, locale_t  locale);\nstruct tm *localtime(const time_t *timer);\nint gettimeofday(struct timeval *tv, void* notused);\n#define timerisset(tvp)     ((tvp)->tv_sec || (tvp)->tv_usec)\n#define timercmp(tvp,uvp,cmp)                   \\\n        ((tvp)->tv_sec cmp (uvp)->tv_sec ||     \\\n         ((tvp)->tv_sec == (uvp)->tv_sec && (tvp)->tv_usec cmp (uvp)->tv_usec))\n#define timerclear(tvp)     (tvp)->tv_sec = (tvp)->tv_usec = 0\n
"},{"location":"api/api-c-stdlib/#localeh","title":"locale.h","text":"
#define LC_GLOBAL_LOCALE twr_get_current_locale()\nchar* setlocale(int category, const char* locale);\nstruct lconv *localeconv(void);\nlocale_t newlocale(int category_mask, const char *locale, locale_t base);\nlocale_t    uselocale(locale_t);\nvoid freelocale(locale_t);\nlocale_t duplocale(locale_t);\nextern inline locale_t twr_get_current_locale(void);\n
"},{"location":"api/api-c-stdlib/#ucharh","title":"uchar.h","text":"
typedef uint_least32_t char32_t;\ntypedef uint_least16_t char16_t;\n\nsize_t c32rtomb( char* s, char32_t c32, mbstate_t* ps );\n
"},{"location":"api/api-c-stdlib/#errnoh","title":"errno.h","text":"
typedef int errno_t;\n\nextern int * _errno(void);\n#define errno (*_errno())\n\nerrno_t  _set_errno(int _Value);\nerrno_t  _get_errno(int *_Value);\n
"},{"location":"api/api-c-stdlib/#_stdtypesh","title":"_stdtypes.h","text":"

// don't include directly -- included by various .h files

typedef unsigned long size_t;\n#define MAX_SIZE_T 2147483647  \n\n#ifdef __cplusplus\n#define NULL __null\n#else\n#define NULL ((void*)0)\n#endif\n\ntypedef struct __locale_t_struct * locale_t;\n

"},{"location":"api/api-c-stdlib/#other-include-files-available","title":"Other include files available","text":"
float.h\nlimits.h\nstdbool.h\nstdint.h\n
"},{"location":"api/api-libc%2B%2B/","title":"libc++ for WebAssembly","text":"

This section describes twr-wasm's support for using the standard c++ library libc++ with WebAssembly.

twr-wasm includes libc++ built for WebAssembly in the twr-wasm/lib-c folder.

For C++ the use of libc++ is optional. That is you can build twr-wasm projects in C++ with or without libc++.

See the examples tests-libcx and tests-user for examples of using libc++.

See the balls example for how to create a C++ WebAssembly program without the standard C++ library. The primary advantage to this approach is a bit smaller code size. You don't need to staticly link libc++.

Some of the key options twr-wasm's libc++ for WebAssembly was built with are these:

DLIBCXX_ENABLE_LOCALIZATION=ON \nDLIBCXX_ENABLE_UNICODE=ON \nDLIBCXX_ENABLE_RTTI=ON \nDLIBCXX_ENABLE_STATIC_ABI_LIBRARY=ON \n\nDCMAKE_BUILD_TYPE=Release       \nDCMAKE_CXX_STANDARD=20 \n\nDLIBCXX_ENABLE_EXCEPTIONS=OFF \nDLIBCXX_ENABLE_THREADS=OFF \nDLIBCXX_ENABLE_SHARED=OFF \nDLIBCXX_ENABLE_WIDE_CHARACTERS=OFF \nDLIBCXX_ENABLE_FILESYSTEM=OFF \nDLIBCXX_ENABLE_TIME_ZONE_DATABASE=OFF \nDLIBCXX_ENABLE_MONOTONIC_CLOCK=OFF \nDLIBCXX_ENABLE_RANDOM_DEVICE=OFF\n
"},{"location":"api/api-localization/","title":"Localization Reference for twr-wasm","text":"

This section details twr-wasm's WebAssembly localization support.

Also see Introduction to Character Encoding Support with twr-wasm

"},{"location":"api/api-localization/#using-c","title":"Using C:","text":"

Standard C locale functions are supported by twr-wasm. ASCII, UTF-8 and windows-1252 encoding is supported by the twr-wasm standard C library locale. twr-wasm also includes C functions for UTF-32 support.

"},{"location":"api/api-localization/#using-c_1","title":"Using C++:","text":""},{"location":"api/api-localization/#character-encodings","title":"Character Encodings","text":"

twr-wasm C locales support ASCII, UTF-8 or windows-1252 encoding. UTF-16/32 are not supported as a std c lib locale setting, but functions are provided to convert utf-32 (unicode code points) to and from ASCII, UTF-8, and windows-1252 \"code pages\" (there are other miscellaneous utf-32 based functions as well.)

"},{"location":"api/api-localization/#locales-standard-c-library","title":"Locales (Standard C Library)","text":""},{"location":"api/api-localization/#c","title":"\"C\"","text":"

\"C\" is the default locale, as usual. When \"C\" is selected, the functions operate as usual. One subtly is that console i/o functions (such as printf) will generally function as expected with UTF-8, since the div and window consoles correctly handle UTF-8 character encoding. This is normal on some OSs, such as linux, but not the default on Windows (which often defaults to windows-1252 for backward compatibility).

isgraph style functions will only recognize ASCII characters, as is normal. Functions such as strcmp operate on the byte sequence, which will typically results in UTF-8 codes being compared lexically. strcoll will use lexical ordering.

"},{"location":"api/api-localization/#posix","title":"\"POSIX\"","text":"

\"POSIX\" is the same as \"C\"

"},{"location":"api/api-localization/#_1","title":"\"\"","text":"

\"\" is the locale to specify the users default setting (this selects the setting used by the browser). This will also enable UTF-8 in functions such as strcoll. For example, if your browser is set to \"en-US\" as its default locale, setlocale(LC_ALL, \"\") will return en-US.UTF-8.

isgraph style functions will still only recognize ASCII characters (since UTF-8 doesn't encode any single bytes greater than 127). strcoll uses locale specific ordering, and printf will use locale specific decimal points. strcmp still compares two strings lexicographically (byte-by-byte) without considering locale-specific rules, per the spec.

"},{"location":"api/api-localization/#utf-8","title":"\".UTF-8\"","text":"

\".UTF-8\" is the same as \"\" with twr-wasm.

"},{"location":"api/api-localization/#1252","title":"\".1252\"","text":"

\".1252\" will select the current default locale, but use windows-1252 character encoding (instead of UTF-8). Windows-1252 is a super set of ISO-8859-1 and is the most commonly used encoding for many european languages when unicode is not used. This mode is primarily for legacy software, backwards compatibly, and windows compatibility.

"},{"location":"api/api-localization/#others","title":"Others","text":"

Setting arbitrary locales, such as \"fr-FR\" when the browser is defaulted to another locale, is not supported.

"},{"location":"api/api-localization/#select-the-default-locale","title":"Select the default locale","text":"

To select the user's browser's default locale using the C language, and enable consistent utf-8 support, use a call like this:

setlocale(LC_ALL, \"\")\n
"},{"location":"api/api-localization/#c-and-libc-functions","title":"C and libc++ functions","text":"

If you are using twr-wasm's build of libc++, libc++ locale and unicode functions work as normal.

The usual standard C library locale support is available, along with some POSIX extensions. In addition, some locale useful twr-wasm specific functions are documented in C API, such as twr_get_current_locale,twr_mbgets, twr_getc32, twr_utf8_char_len, twr_mbslen_l, twr_utf32_to_code_page, twr_code_page_to_utf32_streamed, twr_get_navlang, twr_localize_numeric_string.

Note that io_getc32, getc(stdin), fgetc(stdin) do not look at the current locale. io_getc32 returns a 32 bit unicode code point, and getc/fgetc return extended ASCII.

For a locale aware character input, use io_mbgetc() or twr_mbgets(). Both use the locale category LC_CTYPE. See C API.

Note that when the locale is not set (or whenever the \"C\" locale is set) functions that get character(s) from stdin that are locale aware, like twr_mbgets(), behave different than functions that output characters to stdout (like puts, io_putstr, io_putc, putchar). Characters to stdout in \"C\" locale will handle UTF-8 characters. For stdin, \"C\" locale uses ASCII.

For consistent UTF-8 (or windows-1252) behavior, set the locale as discussed above ( use setlocale )

The primary standard C library locale functions are:

char* setlocale(int category, const char* locale);\nstruct lconv *localeconv(void);\n

As well as the two standard library functions above, appropriate functions take into account the current locale (printf, strcoll, etc).

Note that setlocale returns a string using BCP 47 format (like a web browser). Locale strings look like \"en-US.UTF-8\", instead of \"en_US.UTF-8\". A dash, not an underscore, is used as a separator.

POSIX functions These are the extended POSIX style functions provided that are related to locale:

locale_t newlocale(int category_mask, const char *locale, locale_t base);\nlocale_t uselocale(locale_t);\nvoid freelocale(locale_t);\nlocale_t duplocale(locale_t);\n\nint isalnum_l(int c, locale_t loc);\nint isalpha_l(int c, locale_t loc);\nint isblank_l(int c, locale_t loc);\nint iscntrl_l(int c, locale_t loc);\nint isdigit_l(int c, locale_t loc);\nint isgraph_l(int c, locale_t loc);\nint islower_l(int c, locale_t loc);\nint isprint_l(int c, locale_t loc);\nint ispunct_l(int c, locale_t loc);\nint isspace_l(int c, locale_t loc);\nint isupper_l(int c, locale_t loc);\nint isxdigit_l(int c, locale_t loc);\nint tolower_l(int c, locale_t loc);\nint toupper_l(int c, locale_t loc);\n\nlong long strtoll_l(const char *str, char **str_end, int base,  locale_t loc);\nunsigned long long strtoull_l(const char *str, char **str_end,  int base, locale_t loc);\nfloat strtof_l(const char *str, char ** str_end, locale_t locale);\ndouble strtod_l(const char *str, char **str_end, locale_t locale);\nlong double strtold_l(const char *str, char **str_end, locale_t locale);\n\nint strcoll_l(const char* lhs, const char* rhs,  locale_t loc);\n\nsize_t strftime_l(char *s, size_t maxsize, const char *format, const struct tm *timeptr, locale_t locale);\n
"},{"location":"api/api-typescript/","title":"TypeScript-JavaScript API to load and call Wasm","text":"

This section describes the twr-wasm TypeScript/JavaScript classes that you use to load your Wasm modules, and to call C functions in your Wasm modules.

class twrWasmModule and class twrWasmModuleAsync have similar APIs. The primary difference is that class twrWasmModuleAsync proxies functionality through a Web Worker thread, which allows blocking C functions to be called in your WebAssembly Module. The Async part of twrWasmModuleAsync refers to the ability to await on a blocking callC in your JavaScript main thread, when using twrWasmModuleAsync.

"},{"location":"api/api-typescript/#class-twrwasmmodule","title":"class twrWasmModule","text":"

import {twrWasmModule} from \"twr-wasm\";\n\nconst mod = new twrWasmModule();\n
twrWasmModule provides the two core JavaScript APIs for access to a WebAssembly Module:

"},{"location":"api/api-typescript/#loadwasm","title":"loadWasm","text":"

Use loadWasm to load your compiled C/C++ code (the .wasm file).

await mod.loadWasm(\"./mycode.wasm\")\n

"},{"location":"api/api-typescript/#callc","title":"callC","text":"

After your .wasm module is loaded with loadWasm, you call functions in your C/C++ from TypeScript/JavaScript like this:

let result=await mod.callC([\"function_name\", param1, param2])\n

If you are calling into C++, you need to use extern \"C\" like this in your C++ function:

extern \"C\" int function_name() {}\n

Each C/C++ function that you wish to call from TypeScript/JavaScript needs to be exported in your wasm-ld command line with an option like this:

--export=function_name\n
Or like this in your source file:
__attribute__((export_name(\"function_name\")))\nvoid function_name() {\n   ...\n}\n

Fo more details, see the Compiler Options.

callC takes an array where:

callC returns the value returned by the C function. long, int32_t, int, float or double and the like are returned as a number, int64_t is returned as a bigint, and pointers are returned as a number. The contents of the pointer will need to be extracted using the functions listed below in the section \"Accessing Data in the WebAssembly Memory\". The callC example also illustrates this.

More details can be found in this article: Passing Function Arguments to WebAssembly and in this example. The FFT example demonstrates passing and modifying a Float32Array view of an ArrayBuffer.

"},{"location":"api/api-typescript/#class-twrwasmmoduleasync","title":"class twrWasmModuleAsync","text":"
import {twrWasmModuleAsync} from \"twr-wasm\";\n\nconst amod = new twrWasmModuleAsync();\n

twrWasmModuleAsync implements all of the same functions as twrWasmModule, plus allows blocking inputs, and blocking code generally. This is achieved by proxying all the calls through a Web Worker thread.

For example, with this C function in your Wasm module:

void mysleep() {\n    twr_sleep(5000);  // sleep 5 seconds\n}\n

can be called from your JavaScript main loop like this:

await amod.callC([\"mysleep\"]);\n

This is useful for inputting from stdin, or for traditional blocking loops. The example stdio-div - Printf and Input Using a div Tag demos this.

You must use twrWasmModuleAsync in order to:

See stdio section for information on enabling blocking character input, as well as this Example.

When linking your C/C++ code, twrWasmModule and twrWasmModuleAsync use slightly different wasm-ld options since twrWasmModuleAsync uses shared memory. twrWasmModule will operate with shared memory, so technically you could just use the same share memory options with either module, but you don't need the overhead of shared memory when using twrWasmModule, and so better to not enable it.

See Compiler Options.

twrWasmModuleAsync uses SharedArrayBuffers which require certain HTTP headers to be set. Note that twrWasmModule has an advantage in that it does not use SharedArrayBuffers.

Github pages doesn't support the needed CORS headers for SharedArrayBuffers. But other web serving sites do have options to enable the needed CORS headers. For example, the azure static web site config file staticwebapp.config.json looks like this:

{\n    \"globalHeaders\": {\n      \"Access-Control-Allow-Origin\": \"*\",\n      \"Cross-Origin-Embedder-Policy\": \"require-corp\",\n      \"Cross-Origin-Opener-Policy\": \"same-origin\"\n    }\n}\n

server.py in the examples folder will launch a local server with the correct headers. To use Chrome without a web server, see the Hello World walk through.

"},{"location":"api/api-typescript/#class-options","title":"Class Options","text":"

The twrWasmModule and twrWasmModuleAsync constructor both take optional options.

For example:

let amod=new twrWasmModuleAsync();\n\nlet amod=new twrWasmModuleAsync({\n   windim:[50,20], \n   forecolor:\"beige\", \n   backcolor:\"DarkOliveGreen\", \n   fontsize:18\n   });\n

For a <div id=\"twr_iodiv\"> it is simpler to set the color and font in the div tag per the normal HTML method. But for <div id=\"twr_iocanvas\">, that method won't work and you need to use the constructor options for color and fontsize.

These are the options:

export type TStdioVals=\"div\"|\"canvas\"|\"null\"|\"debug\";\n\nexport interface IModOpts {\n   stdio?:TStdioVals, \n   windim?:[number, number],\n   forecolor?:string,\n   backcolor?:string,\n   fontsize?:number,\n   imports?:{},\n}\n

"},{"location":"api/api-typescript/#stdio","title":"stdio","text":"

You can explicitly set your stdio source (for C/C++ printf, etc) with the stdio option, but typically you don't set it. Instead, it will auto set as described here

"},{"location":"api/api-typescript/#windim","title":"windim","text":"

This options is used with a terminal console ( <canvas id=\"twr_iocanvas\"> ) to set the width and height, in characters.

The canvas width and height, in pixels, will be set based on your fontsize and the width and height (in characters) of the terminal.

"},{"location":"api/api-typescript/#forecolor-and-backcolor","title":"forecolor and backcolor","text":"

These can be set to a CSS color (like '#FFFFFF' or 'white') to change the default background and foreground colors.

"},{"location":"api/api-typescript/#fonsize","title":"fonsize","text":"

Changes the default fontsize for div or canvas based I/O. The size is in pixels.

"},{"location":"api/api-typescript/#divlog","title":"divLog","text":"

If stdio is set to twr_iodiv, you can use the divLog twrWasmModule/Async function like this:

import {twrWasmModule} from \"twr-wasm\";\n\nconst mod = new twrWasmModule();\nawait mod.loadWasm(\"./tests.wasm\");\nawait mod.callC([\"tests\"]);\n\nmod.divLog(\"\\nsin() speed test\");\nlet sumA=0;\nconst start=Date.now();\n\nfor (let i=0; i<2000000;i++)\n   sumA=sumA+Math.sin(i);\n\nconst endA=Date.now();\n\nlet sumB=await mod.callC([\"sin_test\"]);\nconst endB=Date.now();\n\nmod.divLog(\"sum A: \", sumA, \" in ms: \", endA-start);\nmod.divLog(\"sum B: \", sumB,  \" in ms: \", endB-endA);\n

"},{"location":"api/api-typescript/#accessing-data-in-the-webassembly-memory","title":"Accessing Data in the WebAssembly Memory","text":"

callC() will convert your JavaScript arguments into a form suitable for use by your C code. However, if you return or want to access struct values inside TypeScript you will find the following twrWasmModule and twrWasmModuleAsync functions handy. See the callc example and Passing Function Arguments from JavaScript to C/C++ with WebAssembly for an explanation of how these functions work.

async putString(sin:string, codePage=codePageUTF8)  // returns index into WebAssembly.Memory\nasync putU8(u8a:Uint8Array)   // returns index into WebAssembly.Memory\nasync putArrayBuffer(ab:ArrayBuffer)  // returns index into WebAssembly.Memory\nasync fetchAndPutURL(fnin:URL)  // returns index into WebAssembly.Memory\nasync malloc(size:number)           // returns index in WebAssembly.Memory.  \n\nstringToU8(sin:string, codePage=codePageUTF8)\ncopyString(buffer:number, buffer_size:number, sin:string, codePage=codePageUTF8):void\ngetLong(idx:number): number\nsetLong(idx:number, value:number)\ngetDouble(idx:number): number\nsetDouble(idx:number, value:number)\ngetShort(idx:number): number\ngetString(strIndex:number, len?:number, codePage=codePageUTF8): string\ngetU8Arr(idx:number): Uint8Array\ngetU32Arr(idx:number): Uint32Array\n\nmemory?:WebAssembly.Memory;\nmem8:Uint8Array;\nmem32:Uint32Array;\nmemD:Float64Array;\n

"},{"location":"examples/examples-balls/","title":"Bouncing Balls - 2D Draw API Wasm Example","text":"

This example uses twr-wasm's 2D Draw API and a C++ Canvas class with WebAssembly and C++ to bounce balls around your HTML page.

The bouncing balls example demonstrates

This example does not use libc++, which results in smaller code size. For an example that uses libc++ see tests-libcxx.

"},{"location":"examples/examples-balls/#screen-grab-of-balls-example","title":"Screen Grab of Balls Example","text":""},{"location":"examples/examples-callc/","title":"callC - Calling WebAssembly Functions Example","text":"

This example demonstrates how to pass and return values between TypeScript/JavaScript and C/C++ when you are using WebAssembly with twr-wasm.

This article explains the key concepts to pass arguments between JavaScript/TypeScript and Wasm C/C++.

"},{"location":"examples/examples-fft/","title":"FFT - Example of using C FFT with HTML/JavaScript","text":"

This example is a demo of integrating the popular KISS FFT C library with TypeScript/JavaScript/HTML using WebAssembly. The FFT C library is compiled into a Wasm (WebAssembly) module using clang, with the help of twr-wasm. The FFT Wasm module is used by the HTML page to calculate the FFT. The FFT input and output is drawn to the web page using JavaScript canvas functions.

The FFT library exposes APIs to process data, and doesn't use stdio.

The FFT APIs use float32 arrays for complex-number input and output data, and a configuration C struct. In the example I generate the input data by adding a 1K and 5K sine waves, call the kiss FFT API to perform the FFT on the generated sine waves, and then graph the input and output data using a JavaScript Canvas.

"},{"location":"examples/examples-fft/#screen-grab-of-output","title":"Screen Grab of Output","text":""},{"location":"examples/examples-fft/#code","title":"Code","text":"

Here is part of the code. The rest can be found on github.

index.html

<head>\n    <title>Fast Fourier transform (FFT)</title>\n</head>\n<body style=\"background-color:white\">\n\n    <br>\n\n    <div style=\"font:24px arial\">Input Signal</div>\n    <canvas id=\"c-input\" width=\"1024\" height=\"300\" style=\"background-color:lightgray\"></canvas>\n\n    <br><br><br>\n\n    <div style=\"font:24px arial\">FFT Output</div>\n    <canvas id=\"c-output\" width=\"1024\" height=\"300\" style=\"background-color:lightgray\"></canvas>\n\n    <script type=\"module\">\n        import {fftDemo} from \"./fft-script.js\";\n\n        fftDemo();\n\n    </script>\n</body>\n
fft-script.js
import {twrWasmModule} from \"twr-wasm\";\n\nexport async function fftDemo() {\n\n    const mod=new twrWasmModule();\n\n    // load the kiss_fft C code as is, unmodified\n    await mod.loadWasm('kiss_fft.wasm');\n\n    //  kissFFTData stores and graphs the input and output data\n    //  in this example the fft has 1024 bins, and I am using a 48K sampling rate\n    let fft=new kissFFTData(1024, 48000);\n    fft.genSin(1000)\n    fft.addSin(5000)\n    fft.graphIn(\"c-input\");\n\n    // see kiss_fft README, but in summary you: (a) alloc config, (b) compute the FFT, (c) free the config\n    // kiss_fft_alloc() returns a malloced structure.  Pointers are numbers (index into Wasm module memory) in JS land \n    //\n    //kiss_fft_cfg cfg = kiss_fft_alloc( nfft ,is_inverse_fft ,0,0 );\n    let cfg:number = await mod.callC([\"kiss_fft_alloc\", fft.nfft, 0, 0, 0 ]);\n\n    // The FFT input and output data are C arrays of complex numbers.\n    // typedef struct {\n    //    kiss_fft_scalar r;\n    //    kiss_fft_scalar i;\n    // } kiss_fft_cpx;\n    //\n    // /*  default is float */\n    // define kiss_fft_scalar float\n\n    // So if the FFT data has 1024 bins, then 1024 * 2 floats (r & i) * 4 bytes per float are needed.\n    // I use a JS Float32Array view on the ArrayBuffer to access the floats\n\n    // When an arrayBuffer is passed in as an argument to mod.callC,\n    // callC will malloc memory in the Wasm module of a size that matches the array buffer, then\n    // copy the arraybuffer into the malloc'd memory prior to the function call, \n    // then copy the malloc'd memory contents back into the arrayBuffer post call.\n    // The malloc'd memory is free'd post call. \n\n    // void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout);\n    await mod.callC([\"kiss_fft\", cfg, fft.inArrayBuf, fft.outArrayBuf]);\n\n    fft.graphOut(\"c-output\");\n\n    await mod.callC([\"free\", cfg]);      // not much point to this since all the module memory is about to disappear\n}\n

"},{"location":"examples/examples-helloworld/","title":"Hello World - WebAssembly C Example","text":"

This example is an very simple twr-wasm program. It uses WebAssembly and C to print \"hello, world!\" to an HTML <div> tag.

Also see: Hello World - Step-by-Step C to Wasm.

"},{"location":"examples/examples-libcxx/","title":"tests-libcxx - WebAssembly libc++ Smoke Test","text":"

This is a simple test of various libc++ functions using WebAssembly with twr-wasm. The C++ program links with libc++. An example makefile is provided.

Also see this WebAssembly program that uses libc++ with twr-wasm to implement a CLI console.

"},{"location":"examples/examples-maze/","title":"Maze Generator/Solver","text":"

This example is a port to Wasm of a 20 year old Win32 C Maze creator, with the help of twr-wasm 2D Draw APIs.

"},{"location":"examples/examples-maze/#screen-grab-of-output","title":"Screen Grab of Output","text":""},{"location":"examples/examples-maze/#overview","title":"Overview","text":"

This Maze generator uses the twr-wasm \"d2d\" (Draw 2D) C APIs. These allow drawing onto an HTML canvas from C/C++. (Also see the balls C++ example).

This C code is interesting in that it is a combination of blocking and non blocking functions. The CalcMaze function is blocking when the \"slow draw\" flag is set. It uses Sleep in this case. For this reason, I use twrWasmModuleAsync. The solve section uses repeated calls to SolveStep, which works well with a JavaScript main loop. I used a javascript interval timer to make repeated calls to the C SolveStep function. If all the C code was structured this way, twrWasmModule could have been used (instead of the Async version)

To port this code to twr-wasm I wrote a (very tiny) Win32 compatible API (in winemu.c/winemu.h). It only implements the features needed to port Maze, but it might be useful to use as a starting point for porting your Win32 code to the web.

index.html
<head>\n    <title>Maze</title>\n</head>\n<body style=\"background-color:powderblue\">\n    <canvas id=\"twr_d2dcanvas\" width=\"600\" height=\"600\"></canvas>\n\n    <script type=\"module\">\n        import {mazeRunner} from \"./maze-script.js\";\n\n        mazeRunner();\n    </script>\n</body>\n
maze-script.js
import {twrWasmModuleAsync} from \"twr-wasm\";\n\nexport async function mazeRunner() {\n\n    const amod=new twrWasmModuleAsync();\n\n    await amod.loadWasm('maze.wasm');\n\n    //void CalcMaze(HWND hWnd, LONG cell_size, LONG is_black_bg, LONG isd - slow draw)\n    await amod.callC([\"CalcMaze\", 0, 7, 0, 1]);\n    await amod.callC([\"SolveBegin\"]);\n\n    let timer = setInterval(async ()=>{\n        let isdone=await amod.callC([\"SolveStep\", 0]);  //SolveStep(hwnd))\n        if (isdone) clearInterval(timer);\n    }, 50);\n}\n
"},{"location":"examples/examples-overview/","title":"WebAssembly C/C++ Examples","text":""},{"location":"examples/examples-overview/#overview","title":"Overview","text":"

These C and C++ examples demonstrate how to create different types of WebAssembly (wasm) programs with the twr-wasm library.

These are good examples to use as starting points for your own Wasm projects.

These examples are a good place to learn how to configure clang and wasm-ld to compile and link C/C++ code for use with WebAssembly (wasm).

"},{"location":"examples/examples-overview/#example-quick-links","title":"Example Quick Links","text":""},{"location":"examples/examples-overview/#examples-overview","title":"Examples Overview","text":"

Each of these examples are designed to illustrate how to use a feature of twr-wasm.

Name Description Link helloworld A very simple C Wasm example to get you started helloworld stdio-div This simple C program demos inputting andprinting characters to a div tag stdio-div stdio-canvas This simple C program demos writing and inputtingfrom a <canvas> tag that twr-wasm configuresas a windowed \"mini-terminal\" stdio-canvas balls These fun Bouncing Balls are written in C++ and demo the2D drawing APIs with a C++ Canvas wrapper class balls pong A simple game of Pong written in C++ to demo 2D drawing APIs with a C++ canvas wrapper class and taking user input from JS pong maze This is an old Win32 program ported to wasmand demos the 2D Draw APIs maze fft A demo of calling a C library to perform an FFTthat is graphed in TypeScript fft callC A demo of passing and returning values betweenJavaScript and Wasm module callc tests twr-wasm unit tests tests tests-user \"cli\" for tests using libc++ and <canvas> tests-user tests-libcxx Smoke test for libc++. Shows how to use libc++. tests-libcxx"},{"location":"examples/examples-overview/#building-the-examples","title":"Building the Examples","text":"

See Example Readme for more information on building and running the examples.

"},{"location":"examples/examples-pong/","title":"Pong - 2D Game Example","text":"

Similar to the balls example, this example uses twr-wasm's 2D Draw API and a C++ canvas class to run a simple game of singleplayer Pong.

The Pong example demonstrates

This example does not use libc++, which results in smaller code size. For an example that uses libc++ see tests-libcxx.

"},{"location":"examples/examples-pong/#screen-grab-of-pong-example","title":"Screen Grab of Pong Example","text":""},{"location":"examples/examples-stdio-canvas/","title":"stdio-canvas - Terminal Using a Canvas Tag","text":"

A simple ANSI WebAssembly C \"terminal\" is created with input and output directed to an HTML <canvas> tag.

This example will move a string up or down in the terminal window when you press the u or d or arrow keys.

This example also draws a graphic box around the terminal window.

"},{"location":"examples/examples-stdio-canvas/#screen-grab-of-terminal","title":"Screen Grab of Terminal","text":""},{"location":"examples/examples-stdio-canvas/#c-code","title":"C Code","text":"stdio-canvas.c
#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n#include <locale.h>\n#include \"twr-crt.h\"\n\n/* this twr-wasm C example draws a utf-8 string in the middle of a windowed console, */\n/* and allows the user to move the string up or down with the u, d or arrow keys */\n\n/* see include/twr-io.h for available functions to draw chars to windowed console */\n\nvoid draw_outline(struct IoConsoleWindow* iow);\nvoid show_str_centered(struct IoConsoleWindow* iow, int h, const char* str);\n\nvoid stdio_canvas() {\n    struct IoConsoleWindow* iow=(struct IoConsoleWindow*)twr_get_stdio_con();\n\n    assert(iow->con.header.type&IO_TYPE_WINDOW);\n\n    setlocale(LC_ALL, \"\");  // set user default locale, which is always UTF-8.  This is here to turn on UTF-8.\n\n    int h;\n    const char* str=\"Hello World (press u, d, \u2191, or \u2193)\";  // arrows are UTF-8 multibyte\n    const char* spc=\"                                 \";\n    char inbuf[6];  // UTF-8 should be max 4 bytes plus string ending 0\n\n    h=iow->display.height/2;\n\n   draw_outline(iow);\n\n    while (1) {\n      show_str_centered(iow, h,  str);\n      io_mbgetc(stdin, inbuf); // also see twr_getc32 documentation\n      show_str_centered(iow, h,  spc);   // erase old string\n\n      if (strcmp(inbuf,\"u\")==0 || strcmp(inbuf,\"\u2191\")==0) {   // arrows are multibyte UTF-8.\n         h=h-1;\n         if (h<1) h=1;  // border I drew is in the 0 position\n      }\n      if (strcmp(inbuf,\"d\")==0 || strcmp(inbuf,\"\u2193\")==0) {\n         h=h+1;\n         if (h>=(iow->display.height-1)) h=iow->display.height-2;  // border I drew is in the height-1 position\n      }\n   }\n}\n\nvoid show_str_centered(struct IoConsoleWindow* iow, int h, const char* str) {\n    int len=twr_mbslen_l(str, twr_get_current_locale());\n    int x=(iow->display.width-len)/2;\n    io_set_cursorxy(iow, x, h);\n    io_putstr(&iow->con, str);\n}\n\nvoid draw_outline(struct IoConsoleWindow* iow) {\n   const int w=iow->display.width*2;   // graphic cells are 2x3\n   const int h=iow->display.height*3;\n   unsigned long fgcolor, bgcolor;\n\n   io_begin_draw(&iow->con);\n\n   io_get_colors(&iow->con, &fgcolor, &bgcolor);\n   io_set_colors(&iow->con, 0x000000, bgcolor);  // draw in black\n\n   for (int i=0; i<w; i++) {\n      io_setreset(iow, i, 0, true);\n      io_setreset(iow, i, h-1, true);\n   }\n\n   for (int i=0; i<h; i++) {\n      io_setreset(iow, 0, i, true);\n      io_setreset(iow, w-1, i, true);\n   }\n\n   io_set_colors(&iow->con, fgcolor, bgcolor);  // restore\n\n   io_end_draw(&iow->con);\n\n}\n
"},{"location":"examples/examples-stdio-canvas/#html-code","title":"HTML Code","text":"index.html
<!doctype html>\n<html>\n<head>\n   <title>stdio-canvas example</title>\n</head>\n<body>\n   <canvas id=\"twr_iocanvas\" tabindex=\"0\"></canvas>\n\n   <!-- importmap used when un-bundled -->\n   <script type=\"importmap\">\n      {\n         \"imports\": {\n         \"twr-wasm\": \"../../lib-js/index.js\"\n         }\n      }\n   </script>\n\n   <script type=\"module\">\n      import {twrWasmModuleAsync} from \"twr-wasm\";\n\n      try {\n         const amod = new twrWasmModuleAsync({windim:[50,20], forecolor:\"beige\", backcolor:\"DarkOliveGreen\", fontsize:18});\n\n         document.getElementById(\"twr_iocanvas\").focus();\n         document.getElementById(\"twr_iocanvas\").addEventListener(\"keydown\",(ev)=>{amod.keyDownCanvas(ev)});\n\n         await amod.loadWasm(\"./stdio-canvas.wasm\");\n         const r=await amod.callC([\"stdio_canvas\"]);\n         console.log(\"callC returned: \"+r);\n      }\n      catch(ex) {\n         console.log(\"unexpected exception\");\n         throw ex;\n      }\n\n   </script>\n</body>\n</html>\n
"},{"location":"examples/examples-stdio-div/","title":"stdio-div - Printf and Input Using a div Tag","text":"

This simple WebAssembly C program demos inputting and printing characters with a div tag.

"},{"location":"examples/examples-stdio-div/#screen-grab-of-square-calculator","title":"Screen Grab of Square Calculator","text":""},{"location":"examples/examples-stdio-div/#c-code","title":"C Code","text":"stdio-div.c
#include <stdio.h>\n#include <stdlib.h>\n#include \"twr-crt.h\"\n\nvoid stdio_div() {\n   char inbuf[64];\n   int i;\n\n   printf(\"Square Calculator\\n\");\n\n   while (1) {\n      printf(\"Enter an integer: \");\n      twr_mbgets(inbuf);\n      i=atoi(inbuf);\n      printf(\"%d squared is %d\\n\\n\",i,i*i);\n   }\n}\n
"},{"location":"examples/examples-stdio-div/#html-code","title":"HTML Code","text":"

We are using twrWasmModuleAsync which integrates blocking C code into JavaScript. twrWasmModuleAsync can also be used to receive key input from a <div> or <canvas> tag.

index.html
<head>\n   <title>stdio-div example</title>\n</head>\n<body>\n   <div id=\"twr_iodiv\" style=\"background-color:LightGray;color:DarkGreen\" tabindex=\"0\">Loading... <br></div>\n\n   <script type=\"module\">\n      import {twrWasmModuleAsync} from \"twr-wasm\";\n\n      let amod;\n\n      try {\n         amod = new twrWasmModuleAsync();\n\n         document.getElementById(\"twr_iodiv\").innerHTML =\"<br>\";\n         document.getElementById(\"twr_iodiv\").addEventListener(\"keydown\",(ev)=>{amod.keyDownDiv(ev)});\n\n         await amod.loadWasm(\"./stdio-div.wasm\");\n         await amod.callC([\"stdio_div\"]);\n      }\n      catch(ex) {\n         amod.divLog(\"unexpected exception\");\n         throw ex;\n      }\n\n   </script>\n</body>\n
"},{"location":"gettingstarted/basicsteps/","title":"Basic Steps To Create Your Wasm Project","text":"

This section describes the basic steps to integrate your TypeScript/JavaScript with C/C++ WebAssembly code.

"},{"location":"gettingstarted/basicsteps/#overview-of-webassembly-project","title":"Overview of WebAssembly Project","text":"

Your C/C++ WebAssembly project will consist of HTML (and related JavaScript or TypeScript) and C or C++ source files that are compiled into a \".wasm\" binary file that is loaded as a WebAssembly module by your JavaScript.

"},{"location":"gettingstarted/basicsteps/#javascripttypescript-part-of-wasm-project","title":"JavaScript/TypeScript Part of Wasm Project","text":"

On the JavaScript side of your WebAssembly project you will use the twr-wasm JavaScript/TypeScript class twrWasmModule or twrWasmModuleAsync to load the .wasm module, and then call C functions in it using callC (more details are in the TypeScript/Javascript API section).

"},{"location":"gettingstarted/basicsteps/#cc-part-of-wasm-project","title":"C/C++ Part of Wasm Project","text":"

You will call C functions (or C++ with ' extern \"C\" ' linkage) in the .wasm module from your JavaScript. You can also call JavaScript functions from your C/C++ code, but this is less common.

There is no direct equivalent to a C \"main\". Instead, a Wasm module provides exported C functions that you can call from JavaScript/TypeScript. A Wasm module is more like a runtime loaded dynamic library.

You're C/C++ code can be non-blocking or blocking. Blocking means that it \"takes a long time\" to return. For example, if you want to send mouse events to C code, have the code process them then return, this would be non-blocking. Alternately, if your C code is a big loop that never returns, that would be very blocking. You can use the twr-wasm class twrWasmModuleAsync to execute blocking code from JavaScript. The example maze demonstrates both non-blocking and blocking C calls.

Here are some examples of different types of C/C++ code:

"},{"location":"gettingstarted/basicsteps/#steps-to-integrate-c-code-with-javascript-code","title":"Steps to integrate C code with JavaScript code","text":"

Here are the general steps to integrate your C with your JavaScript:

  1. Compile your C code with clang and link with wasm-ld to create the .wasm file.
  2. On the JavaScript side you:
    1. Access twr-wasm \"ES\" modules in the normal way with import.
    2. Add a <div id=twr_iodiv> or <canvas id=twr_iocanvas> to your HTML (see stdio)
    3. Use new twrWasmModule(), followed by a call to loadWasm(), then one or more callC().
    4. Alternately, use twrWasmModuleAsync() -- which is interchangeable with twrWasmModule, but proxies through a worker thread, and adds blocking support, including blocking char input.
    5. For more details, see the remainder of this documentation, or see the hello world or other exampes.
"},{"location":"gettingstarted/charencoding/","title":"Character Encoding Support with twr-wasm","text":"

This section explains twr-wasm's WebAssembly support for ASCII, UTF-8, windows-1252, and UTF-32 character encoding.

"},{"location":"gettingstarted/charencoding/#getting-started","title":"Getting Started","text":"

When using C with twr-wasm, you will likely want to add this line to the start of your code:

setlocale(LC_ALL, \"\")\n

This will change the C locale language to the one selected in the browser, and will enable consistent UTF-8 character encoding support.

Without this line, the standard C runtime will (mostly) default character encoding to ASCII, as per the standard. The exception is that just as with gcc, twr-wasm consoles support outputting UTF-8.

"},{"location":"gettingstarted/charencoding/#character-encodings","title":"Character Encodings","text":"

twr-wasm supports ASCII, UNICODE, and extended-ASCII (in the form of Windows-1252).

These days UNICODE with UTF-8 encoding is the most popular method of displaying and encoding text. UTF-8 is popular because it has the deep character glyph definitions of UNICODE with an encoding that provides (a) the best backwards compatibility with ASCII, and (b) a compact memory footprint. It does this at the expense of some multibyte complexities.

UTF-8 is variable length, and uses between one to four bytes to represent any unicode code point, with ASCII compatibility in the first 128 bytes. It is also the standard for the web, and the default for clang. But because UTF-8 uses a variable number of bytes per character it can make string manipulation in C a bit harder than ASCII, Windows-1252 or UTF-32.

In this document you will see the term \"locale\". This term originated (at least as its commonly used in programming) in the standard C library, and is also used in the standard C++ library (libc++ in twr-wasm). A locale refers to a region of the world, along with a specific character encoding. The twr-wasm standard c runtime uses a label akin to this to define a locale: en-US.UTF-8. Of note is that libc++ and the standard C runtime have different domains for their locales (ie, they don't directly impact each other). You can learn more about locales by searching the internet.

twr-wasm C locales support ASCII, UTF-8 or windows-1252 character encoding. UTF-16/32 are not supported as a std c lib locale setting, but functions are provided to convert utf-32 (unicode code points) to and from ASCII, UTF-8, and windows-1252 \"code pages\" (there are other miscellaneous utf-32 based functions as well.)

Although twr-wasm's standard c library locale doesn't support utf-32 directly, you can use int arrays (instead of byte arrays) to hold utf-32 strings, and then convert them to/from utf-8 with the help of the provided functions for this purpose. Alternately, you can use libc++, which has classes that directly support utf-16 and utf-32.

"},{"location":"gettingstarted/charencoding/#windows-compatibility-with-windows-1252","title":"Windows Compatibility with Windows-1252","text":"

Windows-1252 is the default character encoding on Windows computers in many countries - particularly the Americas and western Europe -- and particularly when using MSVC. Linux, clang, gcc, and the web commonly default in some way to UTF-8 character encoding. Windows-1252 is an extension of ASCII that uses a single byte per character. This makes it easier than UTF-8 from a programmers perspective, but it doesn't represent as many characters. It is supported by twr-wasm to make it easier to port legacy C code, windows code, as well as a simpler alternative to UTF-8.

twr-wasm supports Windows-1252, and you can enable it like this:

setlocale(LC_ALL, \".1252\")\n

This will set the locale to the default browser language, and character encoding to Windows-1252.

1252 String Literals These days text editors generally default to UTF-8. In order to use windows-1252 source code and/or string literals, such as const char * str=\"\u20ac100\" you may need to:

By default, the Microsoft Visual Studio C compiler (MSVC) does not treat string literals as UTF-8. Instead, it treats them as being encoded in the current code page of the system, which is typically Windows-1252 on western european language Windows systems. twr-wasm is designed to work with clang, which does default to utf-8, so if you are compiling code written for MSVC, and you use extend character sets (non ASCII), you may need to adjust your compiler settings with the flags mentioned above.

"},{"location":"gettingstarted/charencoding/#more","title":"More","text":"

For more details see Localization Reference for twr-wasm

"},{"location":"gettingstarted/compiler-opts/","title":"Compiling, Linking, and Memory Options","text":"

This section described how to use clang to compile C/C++ code for WebAssembly, and how to use wasm-ld to link your files into a .wasm module, when using twr-wasm.

twr-wasm lets you use clang directly, without a wrapper. This section describes the needed clang compile options and the wasm-ld link options. You can also take a look at the example makefiles.

"},{"location":"gettingstarted/compiler-opts/#compiler-notes","title":"Compiler Notes","text":"

twr-wasm has been tested with clang 17.0.6 and wasm-ld 17.0.6.

If you are using nix, the default clang packages are wrapped with flags that break compilation. The following packages don't have this issue:

"},{"location":"gettingstarted/compiler-opts/#c-clang-compiler-options","title":"C clang Compiler Options","text":"

When compiling C code with clang for use with Wasm and twr-wasm, use these clang options:

 --target=wasm32 -nostdinc -nostdlib -isystem  ../../include\n

Here is an example of a compile command:

clang --target=wasm32 -nostdinc -nostdlib -isystem ./node_modules/twr-wasm/include -c  helloworld.c -o helloworld.o\n

-isystem should be adjusted to point to where the folder twr-wasm/include is installed. For example:

"},{"location":"gettingstarted/compiler-opts/#c-clang-compiler-options_1","title":"C++ clang Compiler Options","text":"

When compiling C++ code with clang for use with Wasm and twr-wasm, use these clang options:

 --target=wasm32 -fno-exceptions -nostdlibinc -nostdinc -nostdlib -isystem  ../../include\n

"},{"location":"gettingstarted/compiler-opts/#wasm-ld-linker-options","title":"wasm-ld Linker Options","text":"

Use the wasm-ld linker directly with twr-wasm.

For example:

wasm-ld  helloworld.o ./node_modules/twr-wasm/lib-c/twr.a -o helloworld.wasm  --no-entry --initial-memory=131072 --max-memory=131072 --export=hello \n

For C and C++ link to twr.a to link to the twr-wasm library.

For C++ link to libc++.a if you are using libc++. (see the tests-libcxx example makefile).

Be sure to adjust the path to twr.a and libc++.a as needed to the location where twr-wasm/lib-c/ is installed.

All of the twr-wasm functions are staticly linked from the library lib-c/twr.a. There is also a version ( lib-c/twrd.a ) of twr-wasm library available with debug symbols. One of these two static libraries should be added to the list of files to link (normally this is twr.a). Both versions are built with asserts enabled. twr.a is built with -O3. twrd.a is built with -g -O0.

C functions that you wish to call from JavaScript should either have an -export option passed to wasm-ld, or you can use the __attribute__((export_name(\"function_name\"))) option in your C function definition.

All exported functions to JavaScript should be C linkage (extern \"C\" if using C++).

wasm-ld should be passed the following options:

If Using twrWasmModule:

--no-entry --initial-memory=<size> --max-memory=<size>\n

If Using twrWasmModuleAsync:

--no-entry --shared-memory --no-check-features --initial-memory=<size> --max-memory=<size>\n

"},{"location":"gettingstarted/compiler-opts/#memory-options-memory-size-stack-size-etc","title":"Memory Options (Memory Size, Stack Size, etc)","text":"

WebAssembly.Memory contains all the data used by your code (including the data needs of staticly linked libraries such as twr-wasm or libc++), but it does not store your actual code. It provides a contiguous, mutable array of raw bytes. Code execution and storage in WebAssembly are handled separately using the WebAssembly.Module and WebAssembly.Instance objects. The code (compiled WebAssembly instructions) is stored in the WebAssembly.Module, while WebAssembly.Memoryis used to manage the linear memory accessible to the WebAssembly instance for storing data. Examples of data include your static data (.bss section or the .data section), the heap (used by malloc and free), and the stack (used for function calls and local variables).

The memory size should be a multiple of 64*1024 (64K) chunks. \"initial-memory\" and \"max-memory\" should be set to the same number since there is no support for automatically growing memory in twr-wasm. The memory is an export out of the .wasm into the JavaScript code -- you should not create or set the size of WebAssembly.Memory in JavaScript when using twr-wasm.

You set the memory size for your module (WebAssembly.Memory) using wasm-ld options as follows (this examples sets your Wasm memory to 1MB).

"},{"location":"gettingstarted/compiler-opts/#twrwasmmodule","title":"twrWasmModule","text":"

if using twrWasmModule:

--initial-memory=1048576 --max-memory=1048576\n

"},{"location":"gettingstarted/compiler-opts/#twrwasmmoduleasync","title":"twrWasmModuleAsync","text":"

If you are using twrWasmModuleAsync, shared memory must also be enabled. Like this:

--shared-memory --no-check-features --initial-memory=1048576 --max-memory=1048576\n

See this production note on using shared memory.

"},{"location":"gettingstarted/compiler-opts/#stack-size","title":"Stack Size","text":"

You can change your C/C++ stack size from the default 64K with the following wasm-ld option. This example sets the stack at 128K

 -z stack-size=131072\n

"},{"location":"gettingstarted/compiler-opts/#print-memory-map","title":"Print Memory Map","text":"

You can print your module memory map, heap stats, and stack size using the function from C:

void twr_mem_debug_stats(struct IoConsole* outcon);\n
You can call it from Javascript with the output sent to the debug console (stderr) like this:
twrWasmModule/Async.callC([\"twr_wasm_print_mem_debug_stats\"])\n

"},{"location":"gettingstarted/compiler-opts/#typescriptjavascript-malloc-and-memory-access","title":"TypeScript/JavaScript malloc and Memory Access","text":"

twrWasmModule and twrWasmModuleAsync expose malloc as an async function, as well as the WebAssembly Module memory as:

async malloc(size:number);\n\nmemory?:WebAssembly.Memory;\nmem8:Uint8Array;\nmem32:Uint32Array;\nmemD:Float64Array;\n
to call free from JavaScript (you probably won't need to), you can use:
twrWasmModule/Async.callC([\"twr_free\", index]);  // index to memory to free, as returned by malloc\n

more information on these functions and module public variables can be found in the examples in this section: Passing Function Arguments to WebAssembly.

"},{"location":"gettingstarted/debugging/","title":"Debugging WebAssembly","text":"

This section describes tips for debugging your WebAssembly (Wasm) program. Some of these techniques are WebAssembly generic, some are specific to using twr-wasm.

"},{"location":"gettingstarted/debugging/#debug-and-release-libraries","title":"Debug and Release libraries","text":"

There are release (twr.a) and debug (twrd.a) versions of the twr-wasm C library. The \"debug\" version has debug symbols enabled with -g and is built with optimizations disabled via -O0. The \"release\" version has no debug symbols and optimization is set to -O3. Both have asserts enabled. In general, you should use the \"release\" version unless you wish to step through the twr-wasm source -- in which case use the \"debug\" version.

libc++.a is not built with debug symbols.

"},{"location":"gettingstarted/debugging/#source-level-debugging-webassembly-cc","title":"Source Level Debugging WebAssembly C/C++","text":"

In order to enable C/C++ source debugging with Wasm and clang, do the following:

  1. Use Chrome
  2. Install the Chrome extension: C/C++ DevTools Support (DWARF) ( https://chromewebstore.google.com/detail/pdcpmagijalfljmkmjngeonclgbbannb )
  3. Use the clang compile flag -g to add debug annotation to your object files
  4. You may want to turn off optimization to allow the debugger to have a bit more logical behavior (remove the -O flag or set to -O0)
  5. You may want to use the version of the twr-wasm C library that has debug symbols enabled (twrd.a). Only if you want to step into the twrd.a source.
  6. You need to serve your files with a (likely local) web server. For example, 'python server.py' is provided. 'server.py' can be found in the examples root folder. Note that your local server needs to enable SharedArrayBuffers if you are using twrWasmModuleAsync -- see the server.py example.
  7. your code can be bundled or unbundled, but
  8. you need to ensure that the web server/browser can find the source code
  9. also see Example Readme
"},{"location":"gettingstarted/debugging/#useful-twr-wasm-debug-functions","title":"Useful twr-wasm Debug Functions","text":"

Use twr_conlog to print to the JavaScript console from C (see API ref section).

#include \"twr-wasm.h\"\n\ntwr_conlog(\"hello 99 in hex: %x\",99);\n

Use twrWasmModule.divLog() to print to a div inside JavaScript code (see API ref section).

"},{"location":"gettingstarted/debugging/#testing-webassembly-without-a-web-server","title":"Testing WebAssembly Without a Web Server","text":"

Note: If you use this technique, you will not be able to get the C/C++ DevTool chrome extension to run, and so source level debugging won't work. (If you know how to fix this, please contact me on github.)

You can execute and debug JavaScript with Wasm from local files without an HTTP server. It might be helpful to download the twr-wasm source code from github when you do this (so you can step through the twr-wasm typescript code as needed).

See the examples and Example Readme for more detail on how this works.

In general, you will need to add a clip of code similar to this to your HTML:

<script type=\"importmap\">\n   {\n      \"imports\": {\n      \"twr-wasm\": \"./../../lib-js/index.js\"\n      }\n   }\n</script>\n

Make sure the paths to twr-wasm/lib-js/index.js are correct for where your source is located. The above is correct for the provided examples.

You will need to set the following flags when running chrome from the shell or VS Code (the first is only strictly required if using twrWasmModuleAsync).

--enable-features=SharedArrayBuffer\n--allow-file-access-from-files\n

If you are using VS Code, You can create a launch.json entry similar to this:

launch.json
{\n    \"configurations\": [\n    {\n        \"name\": \"Launch Chrome\",\n        \"request\": \"launch\",\n        \"type\": \"chrome\",\n        \"runtimeArgs\": [\n            \"--allow-file-access-from-files\",\n            \"--autoplay-policy=no-user-gesture-required\",\n            \"--enable-features=SharedArrayBuffer\"\n         ],\n         \"file\": \"${workspaceFolder}/index.html\",\n         \"cwd\": \"${workspaceFolder}/\",\n    }\n    ]\n}\n
"},{"location":"gettingstarted/helloworld/","title":"Create and Run WebAssembly Hello World","text":"

This section shows you, step by step, how to to create a C \"hello world\" program for WebAssembly (Wasm) with twr-wasm, C, HTML, and JavaScript.

You will learn how to:

You can find code for a hello world example in the folder examples\\helloworld. It is similar, but not identical to this walk through. The primary differences are the paths for lib-c, lib-js, and include.

"},{"location":"gettingstarted/helloworld/#step-0-installation","title":"Step 0: Installation","text":""},{"location":"gettingstarted/helloworld/#step-1-create-the-c-code","title":"Step 1: Create the C code","text":"

Create a file helloworld.c in hello-proj helloworld.c

#include <stdio.h>\n\nvoid hello() {\n   printf(\"hello world\\n\");\n}\n

"},{"location":"gettingstarted/helloworld/#step-2-create-the-html","title":"Step 2: Create the HTML","text":"

Create a file index.html in hello-proj index.html

<!doctype html>\n<html>\n<head>\n   <title>Hello World</title>\n\n   <script type=\"importmap\">\n   {\n      \"imports\": {\n      \"twr-wasm\": \"./node_modules/twr-wasm/lib-js/index.js\"\n      }\n   }\n   </script>\n\n</head>\n<body>\n   <div id=\"twr_iodiv\"></div>\n\n   <script type=\"module\">\n      import {twrWasmModule} from \"twr-wasm\";\n\n      const mod = new twrWasmModule();\n      await mod.loadWasm(\"./helloworld.wasm\");\n      await mod.callC([\"hello\"]);\n   </script>\n</body>\n</html>\n

This example uses Import Maps, which are used when not using a bundler like WebPack or Parcel. For smaller projects, this can be simpler with a more clear debugging and development environment. This is the approach we will use for this example (no bundler).

The path in the importmap section of index.html should point to the location where you installed twr-wasm/lib-js. The path above is correct for this project example with the indicated folder structure.

"},{"location":"gettingstarted/helloworld/#step-3-compile-your-c-code-to-create-your-wasm-file","title":"Step 3: Compile your C code to create your .wasm file","text":"
cd hello-proj\nclang --target=wasm32 -nostdinc -nostdlib -isystem ./node_modules/twr-wasm/include -c  helloworld.c -o helloworld.o\nwasm-ld  helloworld.o ./node_modules/twr-wasm/lib-c/twr.a -o helloworld.wasm  --no-entry --initial-memory=131072 --max-memory=131072 --export=hello \n

The path to twr.a and to include should match your installation. The above path is correct for this example.

As an alternate to executing clang and wasm-ld from the shell, here is a Makefile that will work for this example:

Makefile
CC := clang\nTWRCFLAGS := --target=wasm32 -nostdinc -nostdlib -isystem  ./node_modules/twr-wasm/include\nCFLAGS := -c -Wall -O3 $(TWRCFLAGS)\nCFLAGS_DEBUG := -c -Wall -g -O0  $(TWRCFLAGS)\n\n.PHONY: default\n\ndefault: helloworld.wasm\n\nhelloworld.o: helloworld.c\n    $(CC) $(CFLAGS)  $< -o $@\n\nhelloworld.wasm: helloworld.o \n    wasm-ld  helloworld.o ./node_modules/twr-wasm/lib-c/twr.a -o helloworld.wasm \\\n        --no-entry --initial-memory=131072 --max-memory=131072 \\\n        --export=hello \n

Copy the above into a file named Makefile and execute with make (or mingw32-make in windows).

"},{"location":"gettingstarted/helloworld/#step-4-load-and-execute-your-web-page","title":"Step 4: Load and execute your web page","text":"

The two easiest ways to load and execute your index.html web page locally are:

"},{"location":"gettingstarted/helloworld/#option-a-run-a-local-web-server","title":"Option A: Run a local web Server","text":"

You can run a local server to view your helloworld program.

At this pont your folder structure should look like this:

hello-proj\\\n\u2514\u2500\u2500node_modules\\\n\u2514\u2500\u2500helloworld.c\n\u2514\u2500\u2500helloworld.o\n\u2514\u2500\u2500helloworld.wasm\n\u2514\u2500\u2500index.html\n\u2514\u2500\u2500Makefile\n\u2514\u2500\u2500package.json\n\u2514\u2500\u2500server.py\n
"},{"location":"gettingstarted/helloworld/#option-b-vs-code-launchjson","title":"Option B: VS Code launch.json","text":"

Alternately, you can launch chrome without a local web server. Add an entry similar to the following to hello-proj\\.vscode\\launch.json. This assumes your workspaceFolder is hello-proj.

launch.json
{\n    \"configurations\": [\n    {\n        \"name\": \"Launch Chrome Hello, World!\",\n        \"request\": \"launch\",\n        \"type\": \"chrome\",\n        \"runtimeArgs\": [\n            \"--allow-file-access-from-files\",\n            \"--autoplay-policy=no-user-gesture-required\",\n            \"--enable-features=SharedArrayBuffer\"\n         ],\n         \"file\": \"${workspaceFolder}/index.html\",\n         \"cwd\": \"${workspaceFolder}/\",\n    }\n    ]\n}\n

Once you have created this file, you:

--autoplay-policy=no-user-gesture-required and --enable-features=SharedArrayBuffer are not required for this simple \"hello world\" example, but will be needed if you request user input or you are using twrWasModuleAsync.

"},{"location":"gettingstarted/helloworld/#see-live-version","title":"See live version","text":"

You can find a live link to hello world on this page.

"},{"location":"gettingstarted/helloworld/#next-steps-after-hello-world","title":"Next steps after hello world","text":"

A good way to get your own code up and running is to copy one of the examples, get it to build and run, then start modifying it. Note you will need to modify the paths for include, lib-js, lib-c, etc. based on your project structure. The examples are all setup with relative paths assuming the folder structure twr-wasm\\examples\\<example>

The examples include MakeFiles.

\"Hello World\" uses the twr-wasm class twrWasmModule. If you wish to use C blocking functions, such as twr_getc32 or twr_sleep, you should use twrWasmModuleAsync. This square calculator example shows how to do this.

If you wish to build an app that makes non-block calls into C, the balls example shows how to do this. The maze example uses a combination of blocking and non-blocking C functions.

"},{"location":"gettingstarted/helloworld/#debugging","title":"Debugging","text":"

See the debugging section for debugging tips, including setting up Wasm source level debugging.

"},{"location":"gettingstarted/installation/","title":"Installing twr-wasm","text":"

A simple way to install twr-wasm is:

npm install twr-wasm\n

See the \"Hello World walk through\" in the following section for more specifics.

There are actually two methods of installation with different pros and cons:

When using twr-wasm your applications needs to access both JavaScript and C twr-wasm libraries. This is explained in the installation sections below, as well as in the Hello World walk through.

"},{"location":"gettingstarted/installation/#npm-install","title":"npm install","text":"

npm install twr-wasm\n
After installation from npm, you will have a folder structure like this:

node_modules\\\n   twr-wasm\\\n      examples\\\n      include\\\n      lib-c\\\n      lib-js\\\n      LICENSE\n      package.json\n      readme.md\n
The JavaScript and TypeScript exports are in lib-js and should be found by VS Code, TypeScript or your bundler as usual when using a statement like import {twrWasmModule} from \"twr-wasm\".

The C library (twr.a) that you will need to link your C/C++ program to is found in the libs-c folder, and the C/C++ include files that you will need to use in your C/C++ program are found in the include folder. You will need to use paths to to these folders in your makefile. See the Hello World walk through for details.

There is no real downside to this installation method, except possibly: (1) it does not include source code (use git clone for that), and (b) the C libraries are buried inside your node_modules.

"},{"location":"gettingstarted/installation/#git-install","title":"git install","text":"
 git clone https://github.com/twiddlingbits/twr-wasm\n

This method of installation installs the complete code base, including source and built binaries.

The primary downside to this method is that the JavaScript side of twr-wasm will not be placed in a node_modules folder. This will create a little extra work to configure a bundler, TypeScript or VS Code to find the location of imports.

There are a few solutions to this. For example, in the provided Hello World example, a package.json file with an alias entry is used. This syntax is supported by the Parcel bundler:

{\n   \"@parcel/resolver-default\": {\n      \"packageExports\": true\n   },\n   \"alias\": {\n      \"twr-wasm\": \"../../lib-js/index.js\"\n   },\n   \"dependencies\": {\n      \"twr-wasm\": \"^2.0.0\"\n   }\n}\n

The FFT example uses the paths entry in the tsconfig.json file. This is found by TypeScript, VS Code and the Parcel bundler. This is probably the best solution if you are using TypeScript.

\"paths\": {\n   \"twr-wasm\": [\"./../../lib-js/index\"]\n}\n

The paths for alias and paths shown above are correct for the included examples, but will likely need to be adjust for your project.

"},{"location":"gettingstarted/installation/#note-on-examples","title":"Note on Examples","text":"

All of the examples have makefiles that use a relative path for twr.a and includes. These paths will work fine if your code is in an examples sub-folder as a peer to the other examples. But assuming your code is in your own project folder elsewhere, you will need to determine the correct path to twr.a and includes for your project's makefile. Details on how to do this can be found in the following sections: Hello World walk through and the Compiler and Linker Options section.

"},{"location":"gettingstarted/installation/#clang-and-wasm-ld","title":"clang and wasm-ld","text":"

To build C/C++ code for use in your Wasm project, you will need to install clang and the wasm-ld linker. If you are using Windows, more details can be found at the end of the Building Source section.

"},{"location":"gettingstarted/installation/#python","title":"python","text":"

To use the included examples\\server.py you will need to install python. server.py is a simple HTTP server for local testing that sets the correct CORS headers for twrWasmModuleAsync. As explained in the following Hello World walk through, you can alternately execute HTML files directly using VS Code and Chrome.

"},{"location":"gettingstarted/parameters/","title":"Passing Function Arguments to WebAssembly","text":"

This article describes techniques to transfer data between JavaScript/TypeScript and C/C++ when using WebAssembly. It delves a bit \u201cunder the covers\u201d to explain how this works when you use a library like twr-wasm or Emscripten. In this article, I am using twr-wasm for the examples. Emscripten does something similar.

For an example that illustrates the concepts discussed here, see: the callC example.

"},{"location":"gettingstarted/parameters/#webassembly-virtual-machine-intrinsic-capabilities","title":"WebAssembly Virtual Machine Intrinsic Capabilities","text":"

The WebAssembly VM (often referred to as a Wasm \u201cRuntime\u201d) is limited to passing numbers between C functions and the Wasm host (I\u2019ll assume that\u2019s JavaScript for this document). In other words, if you are using the most basic WebAssembly capabilities provided by JavaScript, such as WebAssembly.Module, WebAssembly.Instance, and instance.exports, your function calls and return types can only be:

These correspond to the WebAssembly spec support for: i32, i64, f32, and f64.

Note that a JavaScript number is of type Float 64 (known as a double in C/C++.). If you are storing an integer into a JavaScript number, it is converted to a Float 64, and its maximum \"integer\" precision is significantly less than 64 bits (its about 52 bits, but this is a simplification). As a result, to use a 64-bit integers with JavaScript the bigint type is used.

When using 32-bit WebAssembly (by far the most common default), and you call a C function from JavaScript without using any \u201chelper\u201d libraries (like twr-wasm), the following argument types can be passed:

The same rules apply to the return types.

"},{"location":"gettingstarted/parameters/#c-structs-javascript-c","title":"C Structs: JavaScript <--> C","text":"

This section shows how to create a C struct in JavaScript, then pase it to a C function, and then read the modified C struct in JavaScript.

Although the techniques described here are explained with a struct example, the basic techniques are used with other data types as well (such as strings). For common data types, like a string, libraries like twr-wasm will handle these details for you automatically.

To create and pass a C struct from JavaScript to C, the technique is to call the WebAssembly C malloc from JavaScript to allocate WebAssembly memory and then manipulating the memory in JavaScript. One complexity is that each struct entry\u2019s memory address needs to be calculated. And when calculating the WebAssembly Memory indices for the struct entries, C structure padding must be accounted for.

"},{"location":"gettingstarted/parameters/#struct-entry-padding","title":"struct Entry Padding","text":"

Before we delve into the actual code, lets review C struct entry padding.

In clang, if you declare this structure in your C code:

struct test_struct {\n    int a;\n    char b;\n    int *c;\n};\n

This behavior is dependent on your compiler, cpu, and whether you are using 32 or 64-bit architecture. For wasm32 with clang:

If you are not familiar with structure padding, there are many articles on the web.

Alignment requirements are why twr-wasm malloc (and GCC malloc for that matter) aligns new memory allocations on an 8-byte boundary.

"},{"location":"gettingstarted/parameters/#creating-a-struct-in-javascript","title":"Creating a struct in JavaScript","text":"

We can create and initialize the above struct test_struct like this in JavaScript:

//...\nconst mod = new twrWasmModule();\n//...\nconst structSize=12;\nconst structIndexA=0;\nconst structIndexB=4;\nconst structIndexC=8;   // compiler allocates pointer on 4 byte boundaries\nlet structMem=await mod.malloc(structSize);\nlet intMem=await mod.malloc(4);\nmod.setLong(structMem+structIndexA, 1);\nmod.mem8[structMem+structIndexB]=2;    // you can access the memory directly with the mem8, mem32, and memD (float64 aka double) byte arrays.\nmod.setLong(structMem+structIndexC, intMem);\nmod.setLong(intMem, 200000);\n

note that:

"},{"location":"gettingstarted/parameters/#passing-struct-to-c-from-javascript","title":"Passing struct to C from JavaScript","text":"

Assume we have C code that adds 2 to each entry of the test_struct:

__attribute__((export_name(\"do_struct\")))\nvoid do_struct(struct test_struct *p) {\n    p->a=p->a+2;\n    p->b=p->b+2;\n    (*p->c)++;\n    (*p->c)++;\n}\n

Once the struct has been created in JavaScript, you can call the C function do_struct that adds 2 to each entry like this in twr-wasm:

await mod.callC([\"do_struct\", structMem]);  // will add two to each value\n
"},{"location":"gettingstarted/parameters/#accessing-returned-c-struct-in-javascript","title":"Accessing returned C struct in JavaScript","text":"

You access the returned elements like this using JavaScript:

success=mod.getLong(structMem+structIndexA)==3;\nsuccess=success && mod.mem8[structMem+structIndexB]==4;\nconst intValPtr=mod.getLong(structMem+structIndexC);\nsuccess=success && intValPtr==intMem;\nsuccess=success && mod.getLong(intValPtr)==200002;\n

You can see the additional complexity of de-referencing the int *.

"},{"location":"gettingstarted/parameters/#cleanup","title":"Cleanup","text":"

You can free the malloced memory like this:

await mod.callC([\"free\", intMem]);    // unlike malloc, there is no short cut for free, yet\nawait mod.callC([\"free\", structMem]);\n

The complete code for this example is here.

"},{"location":"gettingstarted/parameters/#passing-strings-from-javascript-to-cc-webassembly","title":"Passing Strings from JavaScript to C/C++ WebAssembly","text":"

Although you can use the technique I am about to describe here directly (by writing your own code), it is generally accomplished by using a third-party library such as twr-wasm or Emscripten. These libraries handle the nitty-gritty for you.

To pass a string from JavaScript/TypeScript to a WebAssembly module, the general approach is to:

In the case of twr-wasm, the above steps are handled automatically for you by the callC function:

mod.callC([\"my_function\", \"this is my string\"]);  // mod is instance of twrWasmModule\n

Under the covers, to pass \"this is my string\" from JavaScript to the C Web Assembly function, callC will execute code like this:

// twrWasmModule member function\nasync putString(sin:string, codePage = codePageUTF8) {\n    const ru8 = this.stringToU8(sin, codePage);  // convert a string to UTF8 encoded characters stored in a Uint8Array\n    const strIndex = await this.malloc(ru8.length + 1);  // shortcut for: await this.callC([\"malloc\", ru8.length + 1]);\n    this.mem8.set(ru8, strIndex);  // mem8 is of type Uint8Array and is the Wasm Module\u2019s Memory\n    this.mem8[strIndex + ru8.length] = 0;\n    return strIndex;\n}\n
this.malloc is the standard C runtime malloc function, provided by twr-wasm, and linked into your .wasm code that is loaded into the WebAssembly Module. Likewise, twr-wasm will call free after the function call is executed.

"},{"location":"gettingstarted/parameters/#returning-a-string-from-cc-webassembly-to-javascript","title":"Returning a String from C/C++ WebAssembly to JavaScript","text":"

Returning a string from C to JavaScript is the reverse of passing in a string from JavaScript to C. When the \u201craw\u201d WebAssembly capabilities are used (WebAssembly.Module, etc.) and your C code looks like this:

return(\"my string\");\n

The WebAssembly VM and JavaScript host will cause your JavaScript to receive an unsigned 32-bit integer. This is the pointer to the string, cast to an unsigned 32-bit integer. This integer is an index into the WebAssembly Memory.

twr-wasm provides a function to pull the string out of WebAssembly Memory and convert the character encoding to a JavaScript string. JavaScript strings are Unicode 16, but twr-wasm supports ASCII, UTF-8, and windows-1252 string encoding. When extracted and converted, a copy of the string is made.

const retStringPtr = await mod.callC([\"ret_string_function\"]);\nconsole.log(mod.getString(retStringPtr));\n

The retStringPtr is an integer 32 (but converted to a JavaScript number, which is Float 64). This integer is an index into the WebAssembly Memory.

"},{"location":"gettingstarted/parameters/#passing-arraybuffers-from-javascript-to-cc-webassembly","title":"Passing ArrayBuffers from JavaScript to C/C++ WebAssembly","text":"

When callC in twr-wasm is used to pass an ArrayBuffer to and from C/C++, some details are handled for you. The technique is similar to that used for a string or as performed manually for a struct above, with the following differences:

Here is an example:

let ba = new Uint8Array(4);\nba[0] = 99; ba[1] = 98; ba[2] = 97; ba[3] = 6;\nconst ret_sum = await mod.callC([\"param_bytearray\", ba.buffer, ba.length]);\n

See this example for the complete example.

"},{"location":"gettingstarted/parameters/#passing-a-javascript-object-to-webassembly","title":"Passing a JavaScript Object to WebAssembly","text":""},{"location":"gettingstarted/parameters/#simple-case-use-c-struct","title":"Simple Case - use C struct","text":"

For a simple object like this:

const a = 'foo';\nconst b = 42;\n\nconst obj = {\n  a: a,\n  b: b\n};\n

It is straightforward to convert to a C struct like this:

struct obj {\n    const char* a;\n    int b;\n};\n
To pass this JavaScript object to WebAssembly, a C struct is created (using the struct techniques described above). Each object entry is then copied into the corresponding C struct entry (using the struct and string techniques described above).

"},{"location":"gettingstarted/parameters/#more-complicated-object","title":"More Complicated Object","text":"

A JavaScript object can contain entries that are of more complexity than simple C data types. For example:

const a = 'foo';\nconst b = 42;\nconst map = new Map();\nmap1.set('a', 1);\nmap1.set('b', 2);\nmap1.set('c', 3);\nconst object2 = { a: a, b: b, c: map };\n

In this case, you are going to have to do more work. An approach is to use the libc++ map class, which is similar to the JavaScript Map. You could also perhaps use the libc++ vector.

To handle this more complicated JavaScript object with a Map entry, an approach is to export functions from WebAssembly to create and add entries to the libc++ map (you need to use extern 'C' to export these C++ access functions as C functions). In otherworld, you might export from your Wasm Module C functions like this:

void* createMap();   // return an unsigned long Map ID\nvoid addIntToMap(void* mapID, int newInt);\n

You would then use these functions in JavaScript to build your C++ map. JavaScript would access this map using the unsigned long identifier (the void * returned by createMap). After creating and adding entries to the map, you would set this MapID to object2.c.

There are alternative approaches. For example, you could convert the JavaScript Map to a C struct, by enumerating every entry in the Map. Your C struct might look like: `

struct entry {\n    char* name;\n    int value;\n};\n\nstruct mapUnroll {\n    int MapLen;\n    struct entry* entries[];\n};\n

This approach is probably even more work, less general purpose, and less efficient.

"},{"location":"gettingstarted/parameters/#summary","title":"Summary","text":"

I hope this has demystified how JavaScript values are passed to and from WebAssembly. In many cases, functions like twr-wasm's mod.callC will handle the work for you. But in more bespoke cases, you will have to handle some of the work yourself.

"},{"location":"gettingstarted/stdio/","title":"Stdio with C/C++ WebAssembly","text":"

This section describes how you can direct C/C++ standard input or output to or from a div or canvas tag in a twr-wasm C/C++ Wasm project.

"},{"location":"gettingstarted/stdio/#use-div-or-canvas-tag","title":"Use div or canvas tag","text":"

Standard input and output can be directed to a <div> or to a <canvas> HTML tag. Using a <div> is a simple way to display the output of a printf, or to get input from getc (using traditional standard library blocking input).

A <canvas> tag can be used by twr-wasm to create a simple ANSI style terminal or console. This windowed terminal supports the same streamed output and input features as a does a div tag, but also supports x,y coordinates, colors, and other features. The window console supports chunky (low res) graphics (each character cell can be used as a 2x3 graphic array).

Another difference between a div stream and a canvas stream, is that a div tag will grow as more text is added. On the other hand, a canvas tag has a fixed width and height, and additional text will cause a scroll as it fills up the window.

Unicode characters are supported by stdout and stdin (see Character Encoding Support with twr-wasm).

"},{"location":"gettingstarted/stdio/#div-or-canvas-tag-discovery-order","title":"div or canvas tag discovery order","text":"

If you wish to use a div or canvas tag for stdio when using twr-wasm, in your HTML file add a <div id=\"twr_iodiv\"> or alternately a <canvas id=\"twr_iocanvas\"> tag.

Note that you can also add a <canvas id=\"twr_d2dcanvas\"> to your HTML to define a canvas to be used by twr-wasm's 2D drawing APIs.

"},{"location":"gettingstarted/stdio/#stderr","title":"stderr","text":"

stderr streams to the browser's debug console.

"},{"location":"gettingstarted/stdio/#examples","title":"Examples","text":"Name View Live Link Source Link stdin and stdout to <div> View square demo Source simple \"terminal\" via <canvas> View hello world demo Source \"cli\" with a <canvas> stdio View CLI demo using libc++ Source"},{"location":"gettingstarted/stdio/#io-console-docs","title":"IO Console Docs","text":"

stdin, stdout, and stderr are abstracted by a twr-wasm IO Consoles.

"},{"location":"gettingstarted/stdio/#utf-8-or-windows-1252","title":"UTF-8 or Windows-1252","text":"

Stdin and stdout can support UTF-8 or Windows-1252 character encodings (see Character Encoding Support with twr-wasm).

"},{"location":"gettingstarted/stdio/#includes","title":"Includes","text":"

#include <stdio.h> to access stdout, stdin, stderr, and FILE.

FILE is supported for user input and output, and for stderr. File i/o (to a filesystem) is not currently supported.

"},{"location":"gettingstarted/stdio/#stdout-and-stderr-functions","title":"stdout and stderr functions","text":"

You can use these functions to output to the standard library defines stderr or stdout:

fputc, putc, vfprintf, fprintf, fwrite\n

You can also use the IO Console functions referenced above to send to stdout and stderr.

These functions go to stdout:

printf, vprintf, puts, putchar\n

Note that when characters are sent to the browser console using stderr they will not render to the console until a newline, return, or ASCII 03 (End-of-Text) is sent.

For example:

#include <stdio.h>\n\nfprintf(stderr, \"hello over there in browser debug console land\\n\");\n

A more common method to send output to the debug console is to use twr_conlog. See General C API Section.

"},{"location":"gettingstarted/stdio/#stdin-functions","title":"stdin functions","text":"

Reading from stdin is blocking, and so twrWasmModuleAsync must be used to receive keys from stdin. See the next section for the needed JavaScript line.

You can get characters from stdin with any of these functions:

"},{"location":"gettingstarted/stdio/#javascript-needed-for-char-input","title":"JavaScript needed for char input","text":"

twrWasmModuleAsync must be used to receive keys from stdin. In addtion, you should add a line like the following to your JavaScript for stdin to work:

If using twr_iodiv

document.getElementById(\"twr_iodiv\").addEventListener(\"keydown\",(ev)=>{amod.keyDownDiv(ev)});\n

If using twr_iocanvas

document.getElementById(\"twr_iocanvas\").addEventListener(\"keydown\",(ev)=>{amod.keyDownCanvas(ev)});\n

You likely want a line like this to automatically set the focus to the div or canvas element (so the user doesn't have to click on the element to manually set focus. Key events are sent to the element with focus.):

document.getElementById(\"twr_iocanvas\").focus();\n

You will also need to set the tabindex attribute in your div tag like this:

<div id=\"twr_iodiv\" tabindex=\"0\"></div>\n

See the stdio-div and stdio-canvas examples.

"},{"location":"gettingstarted/stdio/#sending-asyncronous-events-to-wasm-functions","title":"Sending asyncronous events to Wasm functions","text":"

Note that this section describes blocking input using stdin. As an alternative, you can send events (keyboard, mouse, timer, etc) to a non-blocking C function from JavaScript using callC. See the balls example.

"},{"location":"more/building/","title":"Building the twr-wasm Source","text":""},{"location":"more/building/#source-for-twr-wasm","title":"Source for twr-wasm","text":"

The source can be found at:

https://github.com/twiddlingbits/twr-wasm\n

The main branch contains the latest release. The dev branch is work in progress.

"},{"location":"more/building/#tools-needed-to-build-twr-wasm-source","title":"Tools Needed to Build twr-wasm Source","text":"

You will need these core tools, versions used in release are in ():

In addition, you might need:

There is a deprecated gcc build that I used to use for testing, but now the tests are executed in wasm.

"},{"location":"more/building/#to-build-the-libraries-lib-c-lib-js","title":"To Build the Libraries (lib-c, lib-js)","text":"

cd source\nmake\n
or on windows
cd source\nmingw32-make\n

"},{"location":"more/building/#to-build-the-examples","title":"To Build the Examples","text":"

See examples/readme.md for more information.

To build the examples, but not bundle them.

cd examples\nsh buildall.sh\n

To build bundles:

sh buildbundles.sh\n

"},{"location":"more/building/#to-build-the-docs","title":"To Build the docs","text":"

The docs are created using the material theme for mkdocs.

In twr-wasm root folder:

mkdocs build\n

The destination of the build is found in the mkdocs.yml file (site_dir: azure/docsite/).

Usually the docs are built as part of building the static web site that hosts the docs and examples. This is accomplished using this shell script (found in examples folder):

buildazure.sh\n

"},{"location":"more/building/#to-build-libc-for-wasm-and-twr-wasm","title":"To Build libc++ for Wasm and twr-wasm","text":"

See the instructions in the comments in the shell script source\\libcxx\\buildlibcxx.sh

"},{"location":"more/building/#installing-clang-and-wasm-ld-on-windows","title":"Installing clang and wasm-ld on Windows","text":"

Here is how I installed the tools for windows:

 install  MSYS2 \n   1. https://www.msys2.org/\n   2. After the install completes, run UCRT64 terminal by clicking on the MSYS2 UCRT64 in the Start menu\n   3. pacman -Syuu\n\n install gcc using MSYS2 UCRT64\n   1. Use MSYS2 UCRT64 terminal (per above)\n   1. pacman -S mingw-w64-ucrt-x86_64-toolchain\n\n install clang and wasm-ld using MSYS2 UCRT64\n   2. Use MSYS2 UCRT64  (per above)\n      1. pacman -S mingw-w64-ucrt-x86_64-clang\n      2. pacman -S mingw-w64-x86_64-lld\n\nupdate PATH env variable using the windows control panel (search for path)\n   2. added C:\\msys64\\ucrt64\\bin \n   3. added C:\\msys64\\mingw64\\bin \n   4. added C:\\msys64\\usr\\bin (for sh.exe used by mingw32-make)\n

wabt tools: can be found here https://github.com/WebAssembly/wabt/releases

"},{"location":"more/production/","title":"CORS headers needed to use twrWasmModuleAsync","text":"

Important Production Note

twr-wasm class twrWasmModuleAsync uses SharedArrayBuffers, and there are special CORS headers that need to be configured to use SharedArrayBuffers, that are not widely enabled by default on web servers. The server.py or staticwebapp.config.json examples show which headers to set (also see the SharedArrayBuffer documentation online).

"},{"location":"more/wasm-problem/","title":"Wasm Runtime Limitations","text":"

HTML browsers can load a WebAssembly module, and execute it's bytecode in a virtual machine. To create this bytecode (.wasm file) from C/C++, you compile your code using clang with the target code format being WebAssembly (aka Wasm) byte code. If you are not using a support library like twr-wasm or emscripten, there are a few issues that one immediately encounters trying to execute code that is more complicated than squaring a number.

The Wasm virtual machine simply executes the instructions that are generated by the clang compiler and linked by the linker into the .wasm file. The first issue encountered is that some code that is generated by a compiler assumes a compiler support library will be linked to your code. That is, clang code generation will produce calls to compiler support routines for floating point, memcpy, and the like. In clang, these support routines are in the \"compile-rt\" support library. Typically clang handles this behind to scenes for you. But support for a WebAssembly version of this compiler support library is not (as of this writing) included in a clang distribution.

The next level up the library stack is the standard C runtime library. This library provides functions like malloc and printf. And then built on the standard C runtime library is the standard c++ library - like libc++. WebAssembly versions of these libraries are also not part of a clang distribution.

To get access to WebAssembly versions of these libraries you need to use emscripten or twr-wasm.

The second problem is that all the function calls between your Wasm module and your javascript are limited to parameters and return values that are numbers (integer and float). No strings, arrays, struct pointers, etc. (for more on this see this doc).

The third problem is that legacy C code or games often block, and when written this way they don't naturally integrate with the JavaScript asynchronous programming model.

twr-wasm is a static C library (twr.a) that you can link to your clang C/C++ Wasm code, as well as a set of JavaScript/TypeScript modules that solve these issues.

In addition, twr-wasm provides APIs that you can use in your WebAssembly code - such as Canvas compatible 2D drawing APIs, a simple ANSI terminal emulator, character encoding support, and more.

"}]} \ No newline at end of file diff --git a/azure/examples/balls/balls-dbg.wasm b/azure/examples/balls/balls-dbg.wasm index e6684e84fb021b200737ecb9fe818e63e1cc554d..b497f25bf4bf443e999b1e1632fb9106cef1726e 100644 GIT binary patch delta 36710 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 F`wiLriOm22 delta 36744 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 diff --git a/azure/examples/dist/balls/balls-dbg.wasm b/azure/examples/dist/balls/balls-dbg.wasm index e6684e84fb021b200737ecb9fe818e63e1cc554d..b497f25bf4bf443e999b1e1632fb9106cef1726e 100644 GIT binary patch delta 36710 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 F`wiLriOm22 delta 36744 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 diff --git a/azure/examples/dist/pong/pong.wasm b/azure/examples/dist/pong/pong.wasm index 3fd0e8da4a744cb83a6ca0194a7e74101ba4839a..a4b46ac64db01fc86a97dbb9a450bb8fa2f78fcd 100644 GIT binary patch delta 4190 zcma)9dr*|u6~Fg>$U@e2H>k+lZ#PC5G)k&jf_4g*AT%2@Vv=f|u^C!t+6H5a9maOj zB)e4FAR$ORnEFaeC{&$6Bz!P16RlfgThcL>Oq`5%@_?D>*hVLq@P~G^={fg)`|U36 znC=YhdHl|~=W*}3cR%`)zxyR02njxJJtFe?{7Ws72s63#)%#9FkjycK9E0bLo&0@^ zr-XT6kO013(xIw#mxe!B@B6(iItksge&C$}gSn|c0>vfavK6Z}LSW*c$N zWFw^MAWiohsN?P=kz>~77ieXQGVKM|78RH!+Nz)f#ug7{jr>0HMFfvPZTkEywJO?D z9@C^VS$z;Gcs{)*e2oOTL7_q=%qn)3L|!uBHbZh7LP?uCTgqKw*Cd%MkIG!c<><+g z+ZCgN$#5**DyBXY<=p|5L<*Q_?xRu9BR%%QQz`J*?tQdcD>byi?v?W<<4$N^yfoxBFCz5YMHAC96DO zT|T?ty8K}|Jmp>#9yl6Bk17Pzp&$AjAlVJtV2&)>L$awPS!55%R8J|<(S9`WtDK{X z#L$bxm?E)IMdGX?4I;-CnSwbEGL$<4uMv-GvZF8%vnJ(q@`v` zPz>0l5fptkiA_CXle|p#fzCu(Y};XZJi0#Asnz@{G|bKlt36p2@3Bf~W{>%udrazB zkCpwMdyLhg4XjRQ8kSt;3trF4qF9gF*Yp^+dh+?_)-F#K7yoL3zs>mtepze1F9|*Z z7w)ccP1A^xdth-!!-98SR`g5s|04GtrHZ@dC>+c9ZrVf}NpH7;XYRk#K2}DzTdleC z)^YweY?&VlA8b{|3Ua1K6S# zlHp0^GRhu7YuFuMV3oEe?+WG@VVW$st=nu*LK-`QqQmBJtl+%pbabgZ0=TLQ3|A1+ zMGL&PC%(XG7GFWZ{G6r+P0!;HhrR8V=8qRwRUivwCZ!Riwc zs(?XJi-_HaG-5m%Vb{%ewl#o92}@z(R}~s{zNU?$4F0;n6IRs;m28>{4m_k z`p#?>yg!xPbik9@FYq?_D7)X)^*i)}`+iSO7jK0Xxgp*JFXTRi+S9rB-gOplVBAbT z1YFNu&O5-Lml+e9@(&>MmM*d}6|(=B4k(IMJE_hL76+}F9D!HziZPlKd8Pb1Oy_-{ z?}H8bHTeJa{3l#r;Q^x%ZsspV$>IW(ThA11v+iUrgYuVd4G#Nqo*X;xYP{S6ho$r1B+)=wP~E@teT#;?3bfofKr@e$1m{OC=AuAZ1XSljmM|Z;dvZo#TOxZezj+EzsXLS<{uPRNH zS)SEjh(rOH-#V1QAA~2%a})S833LvW$R^0GD9G>zMGBsNs&p(4TCYT&NP>S-*#zyC zB{O8hNqmW%2mR$P7=P$Ug8U%lta-0^e6Tsfq-#4}8@pBI2Gq4w7`rwU07u+7%&-1A z2WYR(;g{fObpd}5#;Oa#duhm;I4zt}#^jknRnQVN>!%5dYG*VtsXWqL;_}Eot##&- zW9vihd783l8yi4K>Ts2RoKmJ zYIiu8iP|`3&iYRhg!UGmXTxXduv#H2P0v%IKG;0*xvDZGi{TIn6f?dQk@1ygVL+^B1m@F9`U!+En7Og z7oF=m;(OWFU!-%Rg#k3{BQcc+pFcK)irJ&yA-Y0+b}`jVB)Ffc-(R}yC+SThHS*a1 zKw?FiG`7)e?Su}2o{OV)G&FjN4B)*Xw$Zy}zy{&2le`hnV$>E0(?D)WbMmc&XrBqjYKq`2Imfmx^|$GatTYBPubjTi&l zH_e5%%@3zf72<;+lI9+Uk2jlE+V>_i;Pao9@=+*kSR@)3!1{(vsB1{M_eLgTp&5Vw LC9~QZ)~EjmPf9<9 delta 4182 zcma)93viUx6~6cWA)Bx)y9V-p@b8L{37Eu!8v|{V8^cCd92TWeW*CP`A2x^vo6?R& zcd2P1O^A`3RstbJ3@td2*N+9;?PQ^$L`Q6Vj1#7yOUpRaKF~_1Fa_Il?*0FNcWDRR znPku7JLjIqz31LN{Ruty2^|VD8aM7^#WefUwn&8NlzSRI(Fl+QI^%DNr?hA2IfJH! zsV|BE&wkW_s;gDO?`rh?+!UP>`=&hXz5ym?q<@p1GM-HT8x39=L=T+^cW!5lhS_FT z%SkDV41>r=U4#>z_!aARqV9Imj=Ci&Dt<)_XUqy;83N68jS@zjoXpccLf*@!X$ejz zM^V#)k2nFD}(lF>s**M@CVQr60}o!`k{)T#)bsQ^&RGI&O@w_d7} zYaez3$4MQj(jvp+^wfoqOj=GnM-f@Ss~bPB*6gd+CX@Nj-OpIa4xg4WkUyJL~!TqaI7Dd5#`r1*nu+HQ%rPx0ON%i=V=p? zgwRXbq$HtGrR=OEH6-JbOhfX5B&YCk^zC^b;vfZ9&Oob_zbtyX=&Gf{1AJG(sKmn^2&MANi9kKB^=i53e!HTz+D^OmC8YN^cs z<}HO{;C_{dQKbhRb-NapS{)^y(NVG9RZOoMt*&~?T3W^Lr~d%HjHT{2MvsfhTN)gn z;y~d&Vop|5?%UfX-G=|qP|rauu#=w<-hG)neN^tx@ud@-HC^EcY<{{HzNhP;ttSlgD^^vkw}w6J>BNDUXr+ z;9Tu_HnG4WWsTk?%*(CkWM(l_~FRT&tpz_KRCG5m2hygHi7uWdz6nwOm(NR?E*SK{ME^G?gjq$-?-V4uA`L z6+lk`n47_DtzC}B^?v37qu2VB5!{$EPbN2+^y*7nB39p#cfa9eX!3*sB9R+=~ODrf1(l+sQ;oYD;QFz))vC(b!OB(``1B1_+p#FvPE{oN$~auOX7Cw!yH zyz$1ZSDE9N@~p;miCZS8j`O*(<9`&=zer@r_`LcZ5*r4MC!L zy_~{V@|j|w#vvx|K9D5eEee*rSr#8@i4gACh%eA?S-D@eK{fbX>)Mb27;$lt9r!-o zBRT>F^pZFjD4~B4AY=$Moj*r14q3WfUthnwj% z=%P;E`yBY=gJNy4T{Pc&Q&gn(U7h`;KDaIm^aP4V;PzNsfz-mBrz`SY*%J2=@~H z5pEZgqqtQ$3BoQKmU%}zaODo`aRX|&B~jfgFMp+e)>7+KCy#m=tHslI0awKR_?CPC zC}<}@McJyHa3}69IM15LP+{*xfyH_?$o9udaYZG8*Jqb9;#-yGveICte^n%hAAdLl z4w*n%NIyGZvXCii`$r;Sxj4LPJN6#fa%jS~96EQ(?*4?KTN2o`fdzC%=n4w=Q2GZEolB7beEvY)~?30KI& z{|5;bC0yHpueH}z2$zq9C)Rz#xW49(S>nv&U!vn8w`n$O$rZc_ YPFYjhZ7i3N6*;MY|06RtH!aWnFQp_xaR2}S diff --git a/azure/examples/pong/pong.wasm b/azure/examples/pong/pong.wasm index 3fd0e8da4a744cb83a6ca0194a7e74101ba4839a..a4b46ac64db01fc86a97dbb9a450bb8fa2f78fcd 100644 GIT binary patch delta 4190 zcma)9dr*|u6~Fg>$U@e2H>k+lZ#PC5G)k&jf_4g*AT%2@Vv=f|u^C!t+6H5a9maOj zB)e4FAR$ORnEFaeC{&$6Bz!P16RlfgThcL>Oq`5%@_?D>*hVLq@P~G^={fg)`|U36 znC=YhdHl|~=W*}3cR%`)zxyR02njxJJtFe?{7Ws72s63#)%#9FkjycK9E0bLo&0@^ zr-XT6kO013(xIw#mxe!B@B6(iItksge&C$}gSn|c0>vfavK6Z}LSW*c$N zWFw^MAWiohsN?P=kz>~77ieXQGVKM|78RH!+Nz)f#ug7{jr>0HMFfvPZTkEywJO?D z9@C^VS$z;Gcs{)*e2oOTL7_q=%qn)3L|!uBHbZh7LP?uCTgqKw*Cd%MkIG!c<><+g z+ZCgN$#5**DyBXY<=p|5L<*Q_?xRu9BR%%QQz`J*?tQdcD>byi?v?W<<4$N^yfoxBFCz5YMHAC96DO zT|T?ty8K}|Jmp>#9yl6Bk17Pzp&$AjAlVJtV2&)>L$awPS!55%R8J|<(S9`WtDK{X z#L$bxm?E)IMdGX?4I;-CnSwbEGL$<4uMv-GvZF8%vnJ(q@`v` zPz>0l5fptkiA_CXle|p#fzCu(Y};XZJi0#Asnz@{G|bKlt36p2@3Bf~W{>%udrazB zkCpwMdyLhg4XjRQ8kSt;3trF4qF9gF*Yp^+dh+?_)-F#K7yoL3zs>mtepze1F9|*Z z7w)ccP1A^xdth-!!-98SR`g5s|04GtrHZ@dC>+c9ZrVf}NpH7;XYRk#K2}DzTdleC z)^YweY?&VlA8b{|3Ua1K6S# zlHp0^GRhu7YuFuMV3oEe?+WG@VVW$st=nu*LK-`QqQmBJtl+%pbabgZ0=TLQ3|A1+ zMGL&PC%(XG7GFWZ{G6r+P0!;HhrR8V=8qRwRUivwCZ!Riwc zs(?XJi-_HaG-5m%Vb{%ewl#o92}@z(R}~s{zNU?$4F0;n6IRs;m28>{4m_k z`p#?>yg!xPbik9@FYq?_D7)X)^*i)}`+iSO7jK0Xxgp*JFXTRi+S9rB-gOplVBAbT z1YFNu&O5-Lml+e9@(&>MmM*d}6|(=B4k(IMJE_hL76+}F9D!HziZPlKd8Pb1Oy_-{ z?}H8bHTeJa{3l#r;Q^x%ZsspV$>IW(ThA11v+iUrgYuVd4G#Nqo*X;xYP{S6ho$r1B+)=wP~E@teT#;?3bfofKr@e$1m{OC=AuAZ1XSljmM|Z;dvZo#TOxZezj+EzsXLS<{uPRNH zS)SEjh(rOH-#V1QAA~2%a})S833LvW$R^0GD9G>zMGBsNs&p(4TCYT&NP>S-*#zyC zB{O8hNqmW%2mR$P7=P$Ug8U%lta-0^e6Tsfq-#4}8@pBI2Gq4w7`rwU07u+7%&-1A z2WYR(;g{fObpd}5#;Oa#duhm;I4zt}#^jknRnQVN>!%5dYG*VtsXWqL;_}Eot##&- zW9vihd783l8yi4K>Ts2RoKmJ zYIiu8iP|`3&iYRhg!UGmXTxXduv#H2P0v%IKG;0*xvDZGi{TIn6f?dQk@1ygVL+^B1m@F9`U!+En7Og z7oF=m;(OWFU!-%Rg#k3{BQcc+pFcK)irJ&yA-Y0+b}`jVB)Ffc-(R}yC+SThHS*a1 zKw?FiG`7)e?Su}2o{OV)G&FjN4B)*Xw$Zy}zy{&2le`hnV$>E0(?D)WbMmc&XrBqjYKq`2Imfmx^|$GatTYBPubjTi&l zH_e5%%@3zf72<;+lI9+Uk2jlE+V>_i;Pao9@=+*kSR@)3!1{(vsB1{M_eLgTp&5Vw LC9~QZ)~EjmPf9<9 delta 4182 zcma)93viUx6~6cWA)Bx)y9V-p@b8L{37Eu!8v|{V8^cCd92TWeW*CP`A2x^vo6?R& zcd2P1O^A`3RstbJ3@td2*N+9;?PQ^$L`Q6Vj1#7yOUpRaKF~_1Fa_Il?*0FNcWDRR znPku7JLjIqz31LN{Ruty2^|VD8aM7^#WefUwn&8NlzSRI(Fl+QI^%DNr?hA2IfJH! zsV|BE&wkW_s;gDO?`rh?+!UP>`=&hXz5ym?q<@p1GM-HT8x39=L=T+^cW!5lhS_FT z%SkDV41>r=U4#>z_!aARqV9Imj=Ci&Dt<)_XUqy;83N68jS@zjoXpccLf*@!X$ejz zM^V#)k2nFD}(lF>s**M@CVQr60}o!`k{)T#)bsQ^&RGI&O@w_d7} zYaez3$4MQj(jvp+^wfoqOj=GnM-f@Ss~bPB*6gd+CX@Nj-OpIa4xg4WkUyJL~!TqaI7Dd5#`r1*nu+HQ%rPx0ON%i=V=p? zgwRXbq$HtGrR=OEH6-JbOhfX5B&YCk^zC^b;vfZ9&Oob_zbtyX=&Gf{1AJG(sKmn^2&MANi9kKB^=i53e!HTz+D^OmC8YN^cs z<}HO{;C_{dQKbhRb-NapS{)^y(NVG9RZOoMt*&~?T3W^Lr~d%HjHT{2MvsfhTN)gn z;y~d&Vop|5?%UfX-G=|qP|rauu#=w<-hG)neN^tx@ud@-HC^EcY<{{HzNhP;ttSlgD^^vkw}w6J>BNDUXr+ z;9Tu_HnG4WWsTk?%*(CkWM(l_~FRT&tpz_KRCG5m2hygHi7uWdz6nwOm(NR?E*SK{ME^G?gjq$-?-V4uA`L z6+lk`n47_DtzC}B^?v37qu2VB5!{$EPbN2+^y*7nB39p#cfa9eX!3*sB9R+=~ODrf1(l+sQ;oYD;QFz))vC(b!OB(``1B1_+p#FvPE{oN$~auOX7Cw!yH zyz$1ZSDE9N@~p;miCZS8j`O*(<9`&=zer@r_`LcZ5*r4MC!L zy_~{V@|j|w#vvx|K9D5eEee*rSr#8@i4gACh%eA?S-D@eK{fbX>)Mb27;$lt9r!-o zBRT>F^pZFjD4~B4AY=$Moj*r14q3WfUthnwj% z=%P;E`yBY=gJNy4T{Pc&Q&gn(U7h`;KDaIm^aP4V;PzNsfz-mBrz`SY*%J2=@~H z5pEZgqqtQ$3BoQKmU%}zaODo`aRX|&B~jfgFMp+e)>7+KCy#m=tHslI0awKR_?CPC zC}<}@McJyHa3}69IM15LP+{*xfyH_?$o9udaYZG8*Jqb9;#-yGveICte^n%hAAdLl z4w*n%NIyGZvXCii`$r;Sxj4LPJN6#fa%jS~96EQ(?*4?KTN2o`fdzC%=n4w=Q2GZEolB7beEvY)~?30KI& z{|5;bC0yHpueH}z2$zq9C)Rz#xW49(S>nv&U!vn8w`n$O$rZc_ YPFYjhZ7i3N6*;MY|06RtH!aWnFQp_xaR2}S diff --git a/examples/pong/pong.wasm b/examples/pong/pong.wasm index 3fd0e8da4a744cb83a6ca0194a7e74101ba4839a..a4b46ac64db01fc86a97dbb9a450bb8fa2f78fcd 100644 GIT binary patch delta 4190 zcma)9dr*|u6~Fg>$U@e2H>k+lZ#PC5G)k&jf_4g*AT%2@Vv=f|u^C!t+6H5a9maOj zB)e4FAR$ORnEFaeC{&$6Bz!P16RlfgThcL>Oq`5%@_?D>*hVLq@P~G^={fg)`|U36 znC=YhdHl|~=W*}3cR%`)zxyR02njxJJtFe?{7Ws72s63#)%#9FkjycK9E0bLo&0@^ zr-XT6kO013(xIw#mxe!B@B6(iItksge&C$}gSn|c0>vfavK6Z}LSW*c$N zWFw^MAWiohsN?P=kz>~77ieXQGVKM|78RH!+Nz)f#ug7{jr>0HMFfvPZTkEywJO?D z9@C^VS$z;Gcs{)*e2oOTL7_q=%qn)3L|!uBHbZh7LP?uCTgqKw*Cd%MkIG!c<><+g z+ZCgN$#5**DyBXY<=p|5L<*Q_?xRu9BR%%QQz`J*?tQdcD>byi?v?W<<4$N^yfoxBFCz5YMHAC96DO zT|T?ty8K}|Jmp>#9yl6Bk17Pzp&$AjAlVJtV2&)>L$awPS!55%R8J|<(S9`WtDK{X z#L$bxm?E)IMdGX?4I;-CnSwbEGL$<4uMv-GvZF8%vnJ(q@`v` zPz>0l5fptkiA_CXle|p#fzCu(Y};XZJi0#Asnz@{G|bKlt36p2@3Bf~W{>%udrazB zkCpwMdyLhg4XjRQ8kSt;3trF4qF9gF*Yp^+dh+?_)-F#K7yoL3zs>mtepze1F9|*Z z7w)ccP1A^xdth-!!-98SR`g5s|04GtrHZ@dC>+c9ZrVf}NpH7;XYRk#K2}DzTdleC z)^YweY?&VlA8b{|3Ua1K6S# zlHp0^GRhu7YuFuMV3oEe?+WG@VVW$st=nu*LK-`QqQmBJtl+%pbabgZ0=TLQ3|A1+ zMGL&PC%(XG7GFWZ{G6r+P0!;HhrR8V=8qRwRUivwCZ!Riwc zs(?XJi-_HaG-5m%Vb{%ewl#o92}@z(R}~s{zNU?$4F0;n6IRs;m28>{4m_k z`p#?>yg!xPbik9@FYq?_D7)X)^*i)}`+iSO7jK0Xxgp*JFXTRi+S9rB-gOplVBAbT z1YFNu&O5-Lml+e9@(&>MmM*d}6|(=B4k(IMJE_hL76+}F9D!HziZPlKd8Pb1Oy_-{ z?}H8bHTeJa{3l#r;Q^x%ZsspV$>IW(ThA11v+iUrgYuVd4G#Nqo*X;xYP{S6ho$r1B+)=wP~E@teT#;?3bfofKr@e$1m{OC=AuAZ1XSljmM|Z;dvZo#TOxZezj+EzsXLS<{uPRNH zS)SEjh(rOH-#V1QAA~2%a})S833LvW$R^0GD9G>zMGBsNs&p(4TCYT&NP>S-*#zyC zB{O8hNqmW%2mR$P7=P$Ug8U%lta-0^e6Tsfq-#4}8@pBI2Gq4w7`rwU07u+7%&-1A z2WYR(;g{fObpd}5#;Oa#duhm;I4zt}#^jknRnQVN>!%5dYG*VtsXWqL;_}Eot##&- zW9vihd783l8yi4K>Ts2RoKmJ zYIiu8iP|`3&iYRhg!UGmXTxXduv#H2P0v%IKG;0*xvDZGi{TIn6f?dQk@1ygVL+^B1m@F9`U!+En7Og z7oF=m;(OWFU!-%Rg#k3{BQcc+pFcK)irJ&yA-Y0+b}`jVB)Ffc-(R}yC+SThHS*a1 zKw?FiG`7)e?Su}2o{OV)G&FjN4B)*Xw$Zy}zy{&2le`hnV$>E0(?D)WbMmc&XrBqjYKq`2Imfmx^|$GatTYBPubjTi&l zH_e5%%@3zf72<;+lI9+Uk2jlE+V>_i;Pao9@=+*kSR@)3!1{(vsB1{M_eLgTp&5Vw LC9~QZ)~EjmPf9<9 delta 4182 zcma)93viUx6~6cWA)Bx)y9V-p@b8L{37Eu!8v|{V8^cCd92TWeW*CP`A2x^vo6?R& zcd2P1O^A`3RstbJ3@td2*N+9;?PQ^$L`Q6Vj1#7yOUpRaKF~_1Fa_Il?*0FNcWDRR znPku7JLjIqz31LN{Ruty2^|VD8aM7^#WefUwn&8NlzSRI(Fl+QI^%DNr?hA2IfJH! zsV|BE&wkW_s;gDO?`rh?+!UP>`=&hXz5ym?q<@p1GM-HT8x39=L=T+^cW!5lhS_FT z%SkDV41>r=U4#>z_!aARqV9Imj=Ci&Dt<)_XUqy;83N68jS@zjoXpccLf*@!X$ejz zM^V#)k2nFD}(lF>s**M@CVQr60}o!`k{)T#)bsQ^&RGI&O@w_d7} zYaez3$4MQj(jvp+^wfoqOj=GnM-f@Ss~bPB*6gd+CX@Nj-OpIa4xg4WkUyJL~!TqaI7Dd5#`r1*nu+HQ%rPx0ON%i=V=p? zgwRXbq$HtGrR=OEH6-JbOhfX5B&YCk^zC^b;vfZ9&Oob_zbtyX=&Gf{1AJG(sKmn^2&MANi9kKB^=i53e!HTz+D^OmC8YN^cs z<}HO{;C_{dQKbhRb-NapS{)^y(NVG9RZOoMt*&~?T3W^Lr~d%HjHT{2MvsfhTN)gn z;y~d&Vop|5?%UfX-G=|qP|rauu#=w<-hG)neN^tx@ud@-HC^EcY<{{HzNhP;ttSlgD^^vkw}w6J>BNDUXr+ z;9Tu_HnG4WWsTk?%*(CkWM(l_~FRT&tpz_KRCG5m2hygHi7uWdz6nwOm(NR?E*SK{ME^G?gjq$-?-V4uA`L z6+lk`n47_DtzC}B^?v37qu2VB5!{$EPbN2+^y*7nB39p#cfa9eX!3*sB9R+=~ODrf1(l+sQ;oYD;QFz))vC(b!OB(``1B1_+p#FvPE{oN$~auOX7Cw!yH zyz$1ZSDE9N@~p;miCZS8j`O*(<9`&=zer@r_`LcZ5*r4MC!L zy_~{V@|j|w#vvx|K9D5eEee*rSr#8@i4gACh%eA?S-D@eK{fbX>)Mb27;$lt9r!-o zBRT>F^pZFjD4~B4AY=$Moj*r14q3WfUthnwj% z=%P;E`yBY=gJNy4T{Pc&Q&gn(U7h`;KDaIm^aP4V;PzNsfz-mBrz`SY*%J2=@~H z5pEZgqqtQ$3BoQKmU%}zaODo`aRX|&B~jfgFMp+e)>7+KCy#m=tHslI0awKR_?CPC zC}<}@McJyHa3}69IM15LP+{*xfyH_?$o9udaYZG8*Jqb9;#-yGveICte^n%hAAdLl z4w*n%NIyGZvXCii`$r;Sxj4LPJN6#fa%jS~96EQ(?*4?KTN2o`fdzC%=n4w=Q2GZEolB7beEvY)~?30KI& z{|5;bC0yHpueH}z2$zq9C)Rz#xW49(S>nv&U!vn8w`n$O$rZc_ YPFYjhZ7i3N6*;MY|06RtH!aWnFQp_xaR2}S