diff --git a/azure/docsite/404.html b/azure/docsite/404.html index c3d87087..63c6a7d3 100644 --- a/azure/docsite/404.html +++ b/azure/docsite/404.html @@ -1067,6 +1067,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/api/api-c-con/index.html b/azure/docsite/api/api-c-con/index.html index 2510aaba..f34445cd 100644 --- a/azure/docsite/api/api-c-con/index.html +++ b/azure/docsite/api/api-c-con/index.html @@ -1440,6 +1440,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/api/api-c-d2d/index.html b/azure/docsite/api/api-c-d2d/index.html index b20a9936..cf284d4d 100644 --- a/azure/docsite/api/api-c-d2d/index.html +++ b/azure/docsite/api/api-c-d2d/index.html @@ -1179,6 +1179,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/api/api-c-general/index.html b/azure/docsite/api/api-c-general/index.html index 1d580e0c..e400d189 100644 --- a/azure/docsite/api/api-c-general/index.html +++ b/azure/docsite/api/api-c-general/index.html @@ -1350,6 +1350,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/api/api-c-stdlib/index.html b/azure/docsite/api/api-c-stdlib/index.html index 60e8a9e6..5d5836cf 100644 --- a/azure/docsite/api/api-c-stdlib/index.html +++ b/azure/docsite/api/api-c-stdlib/index.html @@ -1251,6 +1251,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/api/api-libcpp/index.html b/azure/docsite/api/api-libcpp/index.html index 377bd31b..1007baf6 100644 --- a/azure/docsite/api/api-libcpp/index.html +++ b/azure/docsite/api/api-libcpp/index.html @@ -1095,6 +1095,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/api/api-localization/index.html b/azure/docsite/api/api-localization/index.html index f3ea6758..b995e726 100644 --- a/azure/docsite/api/api-localization/index.html +++ b/azure/docsite/api/api-localization/index.html @@ -1239,6 +1239,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/api/api-typescript/index.html b/azure/docsite/api/api-typescript/index.html index ac242b71..2d4bcaf2 100644 --- a/azure/docsite/api/api-typescript/index.html +++ b/azure/docsite/api/api-typescript/index.html @@ -1329,6 +1329,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-balls/index.html b/azure/docsite/examples/examples-balls/index.html index f6566d55..76aca7d0 100644 --- a/azure/docsite/examples/examples-balls/index.html +++ b/azure/docsite/examples/examples-balls/index.html @@ -1134,6 +1134,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-callc/index.html b/azure/docsite/examples/examples-callc/index.html index bfcf01ae..58ebe1c2 100644 --- a/azure/docsite/examples/examples-callc/index.html +++ b/azure/docsite/examples/examples-callc/index.html @@ -1095,6 +1095,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-divcon/index.html b/azure/docsite/examples/examples-divcon/index.html index 806352d4..5484f5b8 100644 --- a/azure/docsite/examples/examples-divcon/index.html +++ b/azure/docsite/examples/examples-divcon/index.html @@ -1152,6 +1152,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-fft/index.html b/azure/docsite/examples/examples-fft/index.html index 75e0750b..a89e6e28 100644 --- a/azure/docsite/examples/examples-fft/index.html +++ b/azure/docsite/examples/examples-fft/index.html @@ -1143,6 +1143,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-helloworld/index.html b/azure/docsite/examples/examples-helloworld/index.html index d93a535a..3e6f5427 100644 --- a/azure/docsite/examples/examples-helloworld/index.html +++ b/azure/docsite/examples/examples-helloworld/index.html @@ -1095,6 +1095,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-libcxx/index.html b/azure/docsite/examples/examples-libcxx/index.html index 7c789299..d0527d00 100644 --- a/azure/docsite/examples/examples-libcxx/index.html +++ b/azure/docsite/examples/examples-libcxx/index.html @@ -1095,6 +1095,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-maze/index.html b/azure/docsite/examples/examples-maze/index.html index 5de3d7eb..3ffb39a4 100644 --- a/azure/docsite/examples/examples-maze/index.html +++ b/azure/docsite/examples/examples-maze/index.html @@ -1095,6 +1095,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-multi-io/index.html b/azure/docsite/examples/examples-multi-io/index.html index 1ed13716..7419a80e 100644 --- a/azure/docsite/examples/examples-multi-io/index.html +++ b/azure/docsite/examples/examples-multi-io/index.html @@ -1143,6 +1143,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-overview/index.html b/azure/docsite/examples/examples-overview/index.html index ba2d7d25..4c56546a 100644 --- a/azure/docsite/examples/examples-overview/index.html +++ b/azure/docsite/examples/examples-overview/index.html @@ -712,18 +712,18 @@
  • - + - Running the examples locally + Running or Building the examples locally
  • - + - Building the Examples + Copying Examples to Start your own Project @@ -1212,6 +1212,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • @@ -1351,18 +1372,18 @@
  • - + - Running the examples locally + Running or Building the examples locally
  • - + - Building the Examples + Copying Examples to Start your own Project @@ -1516,15 +1537,12 @@

    Unit Tests

    -

    Running the examples locally

    -

    To run the examples locally:

    - -

    Building the Examples

    -

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

    +

    Running or Building the examples locally

    +

    Online versions of the examples can be viewed here.

    +

    You can also run the examples locally, or build them..

    +

    Copying Examples to Start your own Project

    +

    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.

    +

    Also see the section on Import Resolution if you installed with git clone.

    diff --git a/azure/docsite/examples/examples-pong/index.html b/azure/docsite/examples/examples-pong/index.html index b165bf3f..f1ec8b38 100644 --- a/azure/docsite/examples/examples-pong/index.html +++ b/azure/docsite/examples/examples-pong/index.html @@ -1134,6 +1134,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/examples/examples-terminal/index.html b/azure/docsite/examples/examples-terminal/index.html index 80c4cf6c..d4d825d7 100644 --- a/azure/docsite/examples/examples-terminal/index.html +++ b/azure/docsite/examples/examples-terminal/index.html @@ -1152,6 +1152,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/gettingstarted/basicsteps/index.html b/azure/docsite/gettingstarted/basicsteps/index.html index dfe740a1..28fc641b 100644 --- a/azure/docsite/gettingstarted/basicsteps/index.html +++ b/azure/docsite/gettingstarted/basicsteps/index.html @@ -1161,6 +1161,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/gettingstarted/charencoding/index.html b/azure/docsite/gettingstarted/charencoding/index.html index 59233f3a..cffb549f 100644 --- a/azure/docsite/gettingstarted/charencoding/index.html +++ b/azure/docsite/gettingstarted/charencoding/index.html @@ -1161,6 +1161,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/gettingstarted/compiler-opts/index.html b/azure/docsite/gettingstarted/compiler-opts/index.html index eb2f7cad..c048b881 100644 --- a/azure/docsite/gettingstarted/compiler-opts/index.html +++ b/azure/docsite/gettingstarted/compiler-opts/index.html @@ -1221,6 +1221,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/gettingstarted/debugging/index.html b/azure/docsite/gettingstarted/debugging/index.html index c6f651ba..aff6a472 100644 --- a/azure/docsite/gettingstarted/debugging/index.html +++ b/azure/docsite/gettingstarted/debugging/index.html @@ -571,6 +571,15 @@ +
  • + +
  • + + + Resolving Imports + + +
  • @@ -1161,6 +1170,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • @@ -1246,6 +1276,15 @@ +
  • + +
  • + + + Resolving Imports + + +
  • @@ -1303,6 +1342,8 @@

    Source Level Debugging WebAssembl
  • you need to ensure that the web server/browser can find the source code
  • also see Example Readme
  • +

    Resolving Imports

    +

    If you are having issues with import resolution, see this section.

    Useful twr-wasm Debug Functions

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

    #include "twr-wasm.h"
    diff --git a/azure/docsite/gettingstarted/helloworld/index.html b/azure/docsite/gettingstarted/helloworld/index.html
    index 312d7913..4e54d68d 100644
    --- a/azure/docsite/gettingstarted/helloworld/index.html
    +++ b/azure/docsite/gettingstarted/helloworld/index.html
    @@ -1221,6 +1221,27 @@
       
       
       
    +    
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • @@ -1476,6 +1497,7 @@

    Step 2: Create the HTML

  • 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.

    +

    For more detail on import resolution see this section.

    Step 3: Compile your C code to create your .wasm file

    cd hello-proj
     clang --target=wasm32 -nostdinc -nostdlib -isystem ./node_modules/twr-wasm/include -c  helloworld.c -o helloworld.o
    @@ -1552,7 +1574,7 @@ 

    See live version

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

    Next steps after hello world

    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.

    +

    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.

    Debugging

    diff --git a/azure/docsite/gettingstarted/installation/index.html b/azure/docsite/gettingstarted/installation/index.html index b2a4e8b5..b332031c 100644 --- a/azure/docsite/gettingstarted/installation/index.html +++ b/azure/docsite/gettingstarted/installation/index.html @@ -448,27 +448,27 @@
  • - + - Note on Examples + clang and wasm-ld
  • - + - clang and wasm-ld + python and more
  • - + - python + Note on Examples @@ -1170,6 +1170,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • @@ -1258,27 +1279,27 @@
  • - + - Note on Examples + clang and wasm-ld
  • - + - clang and wasm-ld + python and more
  • - + - python + Note on Examples @@ -1354,12 +1375,19 @@

    git install

    }

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

    -

    Note on Examples

    -

    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.

    +

    For more details see this section on Import Resolution

    clang and wasm-ld

    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.

    -

    python

    -

    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.

    +

    python and more

    +

    To use the included examples\server.py to execute your project 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 Hello World walk through, you can alternately execute HTML files directly using VS Code and Chrome.

    +

    You will likely want these tools installed to use twr-wasm:

    + +

    Note on Examples

    +

    You can run the examples either locally or with the online versions.

    diff --git a/azure/docsite/gettingstarted/parameters/index.html b/azure/docsite/gettingstarted/parameters/index.html index 20754593..b221146f 100644 --- a/azure/docsite/gettingstarted/parameters/index.html +++ b/azure/docsite/gettingstarted/parameters/index.html @@ -1263,6 +1263,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/gettingstarted/stdio/index.html b/azure/docsite/gettingstarted/stdio/index.html index 34f1a01c..0ab9c9d9 100644 --- a/azure/docsite/gettingstarted/stdio/index.html +++ b/azure/docsite/gettingstarted/stdio/index.html @@ -6,7 +6,7 @@ - + @@ -24,7 +24,7 @@ - Consoles (stdio, stderr, more) with C/C++ WebAssembly - Easier WebAssembly with twr-wasm + Consoles with C/C++ WebAssembly (stdio, stderr, more) - Easier WebAssembly with twr-wasm @@ -102,7 +102,7 @@
    - Consoles (stdio, stderr, more) with C/C++ WebAssembly + Consoles with C/C++ WebAssembly (stdio, stderr, more)
    @@ -1263,6 +1263,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/index.html b/azure/docsite/index.html index 9b350252..62b0b6b4 100644 --- a/azure/docsite/index.html +++ b/azure/docsite/index.html @@ -22,7 +22,7 @@ - Learn WebAssembly with twr-wasm - Documentation and Examples - Easier WebAssembly with twr-wasm + Easier WebAssembly with twr-wasm - Documentation and Examples - Easier WebAssembly with twr-wasm @@ -64,7 +64,7 @@
    - + Skip to content @@ -100,7 +100,7 @@
    - Learn WebAssembly with twr-wasm - Documentation and Examples + Easier WebAssembly with twr-wasm - Documentation and Examples
    @@ -1199,6 +1199,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • @@ -1367,11 +1388,13 @@ -

    Learn WebAssembly with twr-wasm
    Documentation and Examples

    +

    Easier WebAssembly with twr-wasm
    Documentation and Examples

    Easier C/C++ WebAssembly

    Version 2.4.2

    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 terminal, and use 2D drawing apis (that are compatible with JavaScript Canvas APIs) to draw to a <canvas> element.

    +

    twr-wasm includes comprehensive console support for stdio. You can input and print to a <div> tag, or use a <canvas> element as an terminal.

    +

    twr-wasm makes it easy to await on blocking C/C++ functions.

    +

    twr-wasm makes it easy to use C/C++ 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.

    Live WebAssembly Examples and Source

    @@ -1386,32 +1409,27 @@

    Live WebAssembly Examples and Sour Bouncing Balls (C++) -View bouncing balls +View bouncing balls Source for balls -Pong (C++) -View Pong -Source for Pong - - Maze Gen/Solve (Win32 C Port) -View live maze +View live maze Source for maze Input/Output with <div> -View square demo +View square demo Source -Mini-Terminal (hello world using <canvas>) -View demo +I/O to terminal with <canvas> +View demo Source CLI using libc++ and <canvas>) -View console +View console Source diff --git a/azure/docsite/more/building/index.html b/azure/docsite/more/building/index.html index afe24143..2c378194 100644 --- a/azure/docsite/more/building/index.html +++ b/azure/docsite/more/building/index.html @@ -1083,6 +1083,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/more/imports/index.html b/azure/docsite/more/imports/index.html new file mode 100644 index 00000000..5e6c6632 --- /dev/null +++ b/azure/docsite/more/imports/index.html @@ -0,0 +1,1383 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + Resolving Import Statements - Easier WebAssembly with twr-wasm + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + + + + Skip to content + + +
    +
    + +
    + + + + + + +
    + + + + + + + +
    + +
    + + + + +
    +
    + + + +
    +
    +
    + + + + + + + +
    +
    +
    + + + + + + + +
    +
    + + + + + + + +

    twr-wasm Import Resolution

    +

    This section covers path resolution for statements like this: +

    import {twrWasmModule} from "twr-wasm";
    +

    +

    It can be confusing to determine how tools like VS Code, a bundler, or a Web Browser resolve imports like "twr-wasm". This section explains how it works, using the included examples as examples.

    +

    If you have installed twr-wasm using npm, most tools will automatically resolve imports by finding the node_modules folder.

    +

    However, if you installed using git clone, then other steps will need to be taken. The examples are in the git repo tree, and as a result there may be no node_modules for the twr-wasm libraries. This will also be the case for your project, if you installed with git clone.

    +

    Import path resolution by the bundler

    +

    A bundler will find the twr-wasm library using one of these methods:

    +
      +
    1. If twr-wasm has been installed with npm install, the bundler will find the node_modules folder
    2. +
    3. Alternately, If all your scripts are in TypeScript, use paths entry in tsconfig.json (see maze example)
    4. +
    5. Alternately, use alias option in package.json as in the helloworld example +
           "alias": {
      +          "twr-wasm": "../../lib-js/index.js"
      +     },
      +
    6. +
    +

    In the examples, the alias entry in the package.json exists so that the parcel bundler can find twr-wasm.

    +

    If you are using a bundler, you don't need to add a <script type="importmap"> tag.

    +

    Import path resolution by the browser

    +

    This section apples to executing your javascript without first "bundling" it. Whether execution is from the filesystem directly in a browser or using a web server.

    +

    In order for the browser to locate the twr-wasm path when import is used, you can add code like this to your HTML prior to the import. You should make sure the path for twr-wasm is correct for your project (this is correct for the examples). +

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

    +

    Import resolution by VS Code and tsc

    +

    VS Code Intellisense and the typescript compiler need to find modules. If twr-wasm is installed using npm into a node_modules folder, this is probably automatic. But if this is not the case, you can add a line to the tsconfig.json as follows (this example assumes the tsconfig.json is in a examples/example folder). See the maze example. +

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

    + + + + + + + + + + + + + + + + +
    +
    + + + +
    + +
    + + + +
    +
    +
    +
    + + + + + + + + + + \ No newline at end of file diff --git a/azure/docsite/more/production/index.html b/azure/docsite/more/production/index.html index b507d1a0..d4fc00a8 100644 --- a/azure/docsite/more/production/index.html +++ b/azure/docsite/more/production/index.html @@ -13,7 +13,7 @@ - + @@ -1083,6 +1083,27 @@ + + +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + diff --git a/azure/docsite/more/wasm-problem/index.html b/azure/docsite/more/wasm-problem/index.html index f0c4b476..1e4164ee 100644 --- a/azure/docsite/more/wasm-problem/index.html +++ b/azure/docsite/more/wasm-problem/index.html @@ -16,7 +16,7 @@ - + @@ -1095,6 +1095,27 @@ +
  • + + + + + Import Resolution + + + + +
  • + + + + + + + + + +
  • diff --git a/azure/docsite/search/search_index.json b/azure/docsite/search/search_index.json index 01571fdb..10e0533c 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.4.2

    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 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.

    "},{"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":"
    • compile and link C/C++ for use with WebAssembly using clang directly
    • standard C library, libc++. and purpose built APIs available from C/C++
    • TypeScript/JavaScript classes to load Wasm modules and call C/C++ functions
    • localization support, UTF-8, and windows-1252 support
    • in C/C++, print and get characters to/from <div> tags in your HTML page
    • in C/C++, print and get characters to/from a <canvas> based \"terminal\"
    • in C/C++ use 2D drawing API compatible with JavaScript Canvas
    • in C/C++, use the \"blocking loop\" pattern and integrate with Javascript's asynchronous event loop
    "},{"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":"
    • libc++ built for WebAssembly is included
    • most of the standard C library is now implemented
    • instructions for WebAssembly C/C++ source level debugging
    • version of library with debug symbols provided
    • locale, UTF-8, and windows-1252 support
    "},{"location":"#version-2-limitations","title":"Version 2 Limitations","text":"
    • libc++ not built with exceptions enabled
    • some standard C library functions are not 100% implemented
    • Designed to work with a browser. Not tested with or designed to work with node.js
    • Not all of compile-rt is ported (but most bits you need are)
    "},{"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 Character Console API","text":"

    twr-wasm for WebAssembly provides Consoles for interactive user I/O. Character and graphic 2D draw consoles exist. This section covers the streaming and addressable character APIs that can be used with an instance of twrConsoleDebug, twrConsoleTerminal, twrConsoleDiv. This API works with stdin, stdout, stderr and custom named consoles.

    Also see the Consoles section in Getting Started

    "},{"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-a-console","title":"Getting a Console","text":""},{"location":"api/api-c-con/#stdin-stdout-stderr","title":"stdin, stdout, stderr","text":"

    stdin, stdout, stderr are defined in <stdio.h>.

    This section describes how to configure stdio

    In C, consoles are represented by a twr_ioconsole_t.

    stdio.h also defines FILE like this:

    typedef twr_ioconsole_t 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/#twr_get_console","title":"twr_get_console","text":"

    This function will retrieve a console by its name. The standard names are stdio, stderr, and std2d. In addition, any named console that was passed to a module using the io option can be retrieved with this function.

    See io doc.

    See the multi-io example.

    #include \"twr-crt.h\"\n\ntwr_ioconsole_t* twr_get_console(const char* name)\n
    "},{"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\ntwr_ioconsole_t* io_nullcon(void);\n
    "},{"location":"api/api-c-con/#io-console-functions","title":"IO Console Functions","text":""},{"location":"api/api-c-con/#io_cls","title":"io_cls","text":"

    For addressable display consoles only.

    Clears the screen. That is, all character cells in the console 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(twr_ioconsole_t* io);\n
    "},{"location":"api/api-c-con/#io_getc32","title":"io_getc32","text":"

    Waits for the user to press a key and then returns a unicode code point.

    To return characters encoded with the current locale, see io_mbgetc

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

    For addressable display consoles only.

    Gets the current default foreground and background colors. These colors are used by an new text updates.

    The color format is a 24 bit int as RGB.

    #include <twr_io.h>\n\nvoid io_get_colors(twr_ioconsole_t* io, unsigned long *foreground, unsigned long *background);\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 addressable display consoles, the cursor position ranges from [0, width*height-1], inclusive.

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

    Given a string key (name) of a property, returns its integer value. The available properties varies by console type.

    #include <twr_io.h>\n\nint io_get_prop(twr_ioconsole_t* io, const char* key)\n
    All consoles support: \"type\".

    Addressable consoles also support: \"cursorPos\", \"charWidth\", \"charHeight\", \"foreColorAsRGB\", \"backColorAsRGB\", \"widthInChars\", \"heightInChars\", \"fontSize\", \"canvasWidth\", \"canvasHeight\"

    You can do a bitwise & on type with the following C defines to determine a console capabilities:

    • IO_TYPE_CHARREAD
    • IO_TYPE_CHARWRITE
    • IO_TYPE_ADDRESSABLE_DISPLAY
    • IO_TYPE_CANVAS2D

    For example:

    if (io_get_prop(stdin, \"type\")&IO_TYPE_CHARREAD) {\n   printf (\"okay to read from stdin);\n}\n

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

    Returns the width in characters of an addressable console.

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

    Returns the height in characters of an addressable console.

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

    For addressable display 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 console (see twrConsoleTerminal Options), 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(twr_ioconsole_t* io, unsigned long foreground, unsigned long background);\n
    "},{"location":"api/api-c-con/#io_setc","title":"io_setc","text":"

    For addressable display consoles only.

    Sets a console cell to the specified character. Sends a byte to an console and supports the current locale's character encoding. This function will \"stream\" using the current code page. In other words, if you are in the \"C\" locale io_setc it will set ASCII characters. 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(twr_ioconsole_t* io, int location, unsigned char c);\n
    "},{"location":"api/api-c-con/#io_setc32","title":"io_setc32","text":"

    For addressable display consoles only.

    Sets a console 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(twr_ioconsole_t* io, int location, int c);\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(twr_ioconsole_t* io, int loc);\n
    "},{"location":"api/api-c-con/#io_set_cursorxy","title":"io_set_cursorxy","text":"

    Set's the cursor's x,y position in an addressable console.

    #include <twr_io.h>\n\nvoid io_set_cursorxy(twr_ioconsole_t* io, int x, int y);\n
    "},{"location":"api/api-c-con/#io_setfocus","title":"io_setfocus","text":"

    Sets the input focus to the indicated console.

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

    Sets a range of characters in an addressable display.

    #include <twr_io.h>\n\nvoid io_set_range(twr_ioconsole_t* io, int *chars32, int start, int len)\n
    "},{"location":"api/api-c-con/#io_setreset","title":"io_setreset","text":"

    For addressable display 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 terminal example.

    #include <twr_io.h>\n\nbool io_setreset(twr_ioconsole_t* io, int x, int y, bool isset);\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(twr_ioconsole_t* io, char* strout);\n
    "},{"location":"api/api-c-con/#io_mbgets","title":"io_mbgets","text":"

    Gets a string from a Console. 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. If the encoding is UTF-8, then the result will be multibyte.

    This function is commonly used with stdin.

    This function requires that you use twrWasmModuleAsync.

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

    For addressable display consoles only.

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

    #include <twr_io.h>\n\nbool io_point(twr_ioconsole_t* io, int x, int y);\n
    "},{"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(twr_ioconsole_t* 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(twr_ioconsole_t* 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(twr_ioconsole_t *io, const char *format, ...);\n
    "},{"location":"api/api-c-con/#io_begin_draw","title":"io_begin_draw","text":"

    For addressable display 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 terminal example.

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

    For addressable display consoles only.

    See io_begin_draw.

    #include <twr_io.h>\n\nvoid io_end_draw(twr_ioconsole_t* io);\n
    "},{"location":"api/api-c-con/#deprecated-functions","title":"Deprecated Functions","text":""},{"location":"api/api-c-con/#twr_debugcon","title":"twr_debugcon","text":"

    This function has been removed. Use stderr or twr_conlog.

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

    or

    #include <stdio.h>\n\nfprintf(stderr, \"hello over there in browser debug console land\\n\");\n
    "},{"location":"api/api-c-con/#twr_divcon","title":"twr_divcon","text":"

    This function has been removed.

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

    This function has been removed.

    "},{"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.

    "},{"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/#code-example","title":"Code Example","text":"Draw A Rectangle
    #include \"twr-draw2d.h\"\n\nvoid square() {\n   // batch draw commands, with a maximum of 100 commands before render\n   struct d2d_draw_seq* ds=d2d_start_draw_sequence(100);\n   // set color using CSS color string\n   d2d_setfillstyle(ds, \"blue\");\n   // draw a the rect\n   d2d_fillrect(ds, 10, 10, 100, 100);\n   // this will cause the JavaScript thread to render\n   d2d_end_draw_sequence(ds);\n}\n
    "},{"location":"api/api-c-d2d/#overview","title":"Overview","text":"

    The Draw 2D APIs are C APIs and are part of the twr-wasm library that you access with #include \"twr-draw2d.h\". There is also a C++ canvas wrapper class in examples/twr-cpp used by the balls and pong examples.

    To create a canvas surface, that you can draw to using the twr-wasm 2D C drawing APIs, you can use the twrConsoleCanvas class in your JavaScript/HTML (see Consoles Section). Or more simply, if you add a canvas tag to your HTML named twr_d2dcanvas, the needed twrConsoleCanvas will be created automatically.

    <canvas id=\"twr_d2dcanvas\" width=\"600\" height=\"600\"></canvas>\n//Feel free to change the `width=\"600` and/or `height=\"600` attributes.\n

    To draw using the C 2D Draw API:

    • call d2d_start_draw_sequence (or alternately d2d_start_draw_sequence_with_con)
    • call one or more (a sequence) of 2D draw commands, like d2d_fillrect
    • call d2d_end_draw_sequence
    • repeat as desired

    d2d_start_draw_sequence will draw to the default twrConsoleCanvas, as explained at the start of this section. d2d_start_draw_sequence_with_con is optional, and allows you to specify the twrConsoleCanvas to draw to. You would typically get this console in C using the twr_get_console function (which retrieves a named console that you specified in the io module option.)

    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, 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/#possible-pitfalls","title":"Possible Pitfalls","text":"

    Some commands have extra details that you need to be aware of to avoid performance loss or bugs.

    • Getters, like d2d_measuretext, will flush the queue in order to retrieve the requested data. If your program relies on not flushing early (for example, to avoid flashes), then getters should be avoided in your main render loops.
    • putImageData references the provided pointer, so the given image data needs to stay valid on the caller's stack or heap until flush is called.
    • getLineDash takes in a buffer_length, double * array (the buffer), and returns the amount of the buffer filled. If there are more line segments than can fit in the buffer_length, a warning is printed and the excess is voided. If you want to know the size before hand for allocation, the getLineDashLength function is available.
    "},{"location":"api/api-c-d2d/#notes","title":"Notes","text":"

    The functions listed below are based on the JavaScript Canvas 2D API (found here). However, there are some slight differences since these APIS are made for C rather than JavaScript. For example some items keep resources stored on the JavaScript side (such as d2d_createlineargradient) which are referenced by a numeric ID , rather than an actual object reference.

    Additionally, there are alternative functions like d2d_setstrokestylergba, which calls the same underlying function as d2d_setstrokestyle, but takes in a color as a number rather than CSS style string.

    As noted above, putImageData requires that the image data be valid until flush is called.

    Other functions that take a string, like d2d_filltext, don't have this same issue because they make a copy of the string argument. These string copies will be automatically freed.

    d2d_load_image should be called outside of a d2d_start_draw_sequence segment. If you are loading it to an id that you plan on freeing, ensure that the buffer is flushed before doing so as d2d_load_image bypasses it. In addition, d2d_load_image requires you to be using twrWasmAsyncModule as it waits for the image to load (or fail) before returning.

    "},{"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);\nstruct d2d_draw_seq* d2d_start_draw_sequence_with_con(int flush_at_ins_count, twr_ioconsole_t * con);\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, unsigned long c, double x, double y);\nvoid d2d_stroketext(struct d2d_draw_seq* ds, const char* text, 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_setstrokestylergba(struct d2d_draw_seq* ds, unsigned long color);\nvoid d2d_setfillstylergba(struct d2d_draw_seq* ds, unsigned long color);\nvoid d2d_setstrokestyle(struct d2d_draw_seq* ds, const char* css_color);\nvoid d2d_setfillstyle(struct d2d_draw_seq* ds, const char* css_color);\nvoid d2d_setfont(struct d2d_draw_seq* ds, const char* font);\nvoid d2d_setlinecap(struct d2d_draw_seq* ds, const char* line_cap);\nvoid d2d_setlinejoin(struct d2d_draw_seq* ds, const char* line_join);\nvoid d2d_setlinedashoffset(struct d2d_draw_seq* ds, double line_dash_offset);\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_arcto(struct d2d_draw_seq* ds, double x1, double y1, double x2, double y2, double radius);\nvoid d2d_bezierto(struct d2d_draw_seq* ds, double cp1x, double cp1y, double cp2x, double cp2y, double x, double y);\nvoid d2d_roundrect(struct d2d_draw_seq* ds, double x, double y, double width, double height, double radii);\nvoid d2d_ellipse(struct d2d_draw_seq* ds, double x, double y, double radiusX, double radiusY, double rotation, double startAngle, double endAngle, bool counterclockwise);\nvoid d2d_quadraticcurveto(struct d2d_draw_seq* ds, double cpx, double cpy, double x, double y);\nvoid d2d_rect(struct d2d_draw_seq* ds, double x, double y, double width, double height);\nvoid d2d_closepath(struct d2d_draw_seq* ds);\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\nvoid d2d_reset(struct d2d_draw_seq* ds);\nvoid d2d_clearrect(struct d2d_draw_seq* ds, double x, double y, double w, double h);\nvoid d2d_scale(struct d2d_draw_seq* ds, double x, double y);\nvoid d2d_translate(struct d2d_draw_seq* ds, double x, double y);\nvoid d2d_rotate(struct d2d_draw_seq* ds, double angle);\nvoid d2d_gettransform(struct d2d_draw_seq* ds, struct d2d_2d_matrix *transform);\nvoid d2d_settransform(struct d2d_draw_seq* ds, double a, double b, double c, double d, double e, double f);\nvoid d2d_settransformmatrix(struct d2d_draw_seq* ds, const struct d2d_2d_matrix * transform);\nvoid d2d_transform(struct d2d_draw_seq* ds, double a, double b, double c, double d, double e, double f);\nvoid d2d_transformmatrix(struct d2d_draw_seq* ds, const struct d2d_2d_matrix * transform);\nvoid d2d_resettransform(struct d2d_draw_seq* ds);\nvoid d2d_setlinedash(struct d2d_draw_seq* ds, unsigned long len, const double* segments);\nunsigned long d2d_getlinedash(struct d2d_draw_seq* ds, unsigned long length, double* buffer);\nunsigned long d2d_getlinedashlength(struct d2d_draw_seq* ds);\n\nbool d2d_load_image(const char* url, long id);\nbool d2d_load_image_with_con(const char* url, long id, twr_ioconsole_t * con);\nvoid d2d_drawimage(struct d2d_draw_seq* ds, long id, double dx, double dy);\nvoid d2d_getimagedata(struct d2d_draw_seq* ds, double x, double y, double width, double height, void* buffer, unsigned long buffer_len);\nunsigned long d2d_getimagedatasize(double width, double height);\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

    d2d_gettransform() returns this structure:

    struct d2d_2d_matrix {\n   double a, b, c, d, e, f;\n};\n

    d2d_getlinedash() returns this structure:

    struct d2d_line_segments {\n    long len;\n    double *segments;\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 stderr (usually your browser console) from your C code.

    #include \"twr-crt.h\"\n\nvoid twr_conlog(char* format, ...);\n
    This call is identical to fprintf(stderr, ...), except that it adds a newline.

    When stderr is set to twrConsoleDebug each call to twr_conlog() will generate a single call to console.log() in JavaScript to ensure that you see debug prints.

    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.

    "},{"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 with these functions is blocking and you must use twrWasmModuleAsync -- see stdin for details on how to enable blocking character input.

    Also see:

    • io_mbgets - get a multibyte string from a console using the current locale character encoding. Console must support IO_TYPE_CHARREAD.
    • twr_mbgets - the same as io_mbgets with the console set to stdin.
    • io_mbgetc - get a multibyte character from an IoConsole (like stdin) using the current locale character encoding
    • getc (sames as fgetc) - get a single byte from a FILE * (IoConsole) -- returning ASCII or extended ASCII (window-1252 encoding)
    • io_getc32 - gets a 32 bit unicode code point from an IoConsole (which must support IO_TYPE_CHARREAD)
    #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 twr_ioconsole_t*)

    #include <stdio.h>\n\nvoid twr_mem_debug_stats(twr_ioconsole_t* 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 Character Encoding Support with twr-wasm.

    #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 'twr_ioconsole_t *' 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 twr_ioconsole_t 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 it 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-libcpp/","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":"
    • libc++ locale and unicode functions are supported by twr-wasm.
    • libc++ unicode support includes utf-16 and utf-32 strings.
    "},{"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 APILoad and call Wasm, Create i/o Consoles","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.
    • create I/O Consoles for character streaming, a terminal, or 2D Canvas Drawing

    class twrWasmModule and class twrWasmModuleAsync are used to load .wasm modules and call their C functions. Both classes 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.

    The classes twrConsoleDiv, twrConsoleTerminal, twrConsoleDebug, and twrConsoleCanvas create consoles that enable user i/o. Your C/C++ can direct user interactive i/o to these consoles. See Console Introduction for information on enabling character input and output in a module.

    "},{"location":"api/api-typescript/#apis-common-to-twrwasmmodule-and-twrwasmmoduleasync","title":"APIs Common to twrWasmModule and twrWasmModuleAsync","text":""},{"location":"api/api-typescript/#common-constructor-options","title":"Common Constructor Options","text":"

    See module options below.

    "},{"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:

    • the first entry is the name of the C function in the Wasm module to call
    • and the next optional entries are a variable number of arguments to pass to the C function, of type:

      • number - will be converted to a signed or unsigned long, int32_t, int, float or double as needed to match the C function declaration.
      • bigint - will be converted into an int64_t or equivalent
      • string - converted to a char * of malloc'd module memory where string is copied into
      • ArrayBuffer - the array is copied into malloc'd module memory. If you need to pass the length, pass it as a separate argument. Any modifications to the memory made by your C code will be reflected back into the JavaScript ArrayBuffer.
      • URL - the url contents are copied into malloc'd module Memory, and two C arguments are generated - index (pointer) to the memory, and length

    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. 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-twrwasmmodule","title":"class twrWasmModule","text":"

    This class is used when your C function call will not block (that is, they will not take 'a long time' to execute).

    The constructor accepts an optional object (type IModOpts), which is explained further down.

    import {twrWasmModule} from \"twr-wasm\";\n\nconst mod = new twrWasmModule();\n

    "},{"location":"api/api-typescript/#class-twrwasmmoduleasync","title":"class twrWasmModuleAsync","text":"

    This class is used to enable blocking C functions, suchs as sleep or traditional C style blocking input (such as getc);

    The constructor accepts an optional object (type IModOpts), which is explained further down.

    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

    You must use twrWasmModuleAsync in order to:

    • call any blocking C function (meaning it takes \"a long time\") to return
    • use blocking input from a div or canvas ( eg. twr_mbgets )
    • use twr_sleep
    "},{"location":"api/api-typescript/#linking-requirements","title":"Linking Requirements","text":"

    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 wasm-ld Linker Options.

    "},{"location":"api/api-typescript/#javascript-needed-for-char-input","title":"JavaScript Needed for Char Input","text":"

    When a console will handle key input, you need to add a line to your JavaScript to send key events to the console. There are two options for this: You can send the key events directly to the console, or if the key events are always directed to stdio, you cam send the key events to the module. This latter case is primarily for when you are using tag shortcuts.

    To send key events to the console, you add a line like this:

    yourDivOrCanvasElement.addEventListener(\"keydown\",(ev)=>{yourConsoleClassInstance.keyDown(ev)});\n

    To send key events to the module's stdio, you add a line like this:

    yourDivOrCanvasElement.addEventListener(\"keydown\",(ev)=>{yourModuleClassInstance.keyDown(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.):

    yourDivOrCanvasElement.focus();\n

    You will also need to set the tabindex attribute in your tag like this to enable key events:

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

    See this example on character input.

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

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

    twrWasmModuleAsync uses SharedArrayBuffers which require certain CORS HTTP headers to be set. Note that twrWasmModule does not use SharedArrayBuffers. If you limit yourself to twrWasmModule you will not need to worry about configuring the CORS http headers on your web server.

    See this note on enabling CORS HTTP headers for SharedArrayBuffers.

    "},{"location":"api/api-typescript/#module-options","title":"Module Options","text":"

    The twrWasmModule and twrWasmModuleAsync constructor both take optional options.

    For example:

    let amod=new twrWasmModuleAsync();\n\nlet amod=new twrWasmModuleAsync({\n   stdio: new twrConsoleDebug();  // send stdio to debug console\n   });\n

    These are the options: twrWasmModule & twrWasmModuleAsync Options

    export interface IModOpts {\n   stdio?: IConsoleStream&IConsoleBase,\n   d2dcanvas?: IConsoleCanvas&IConsoleBase,\n   io?: {[key:string]: IConsole},\n}\n

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

    Set this to a Console class instance. If you leave it undefined, twrConsoleDebug will be used (or a tag shortcut, if set)

    This option is a shortcut to setting stdio using the io option.

    "},{"location":"api/api-typescript/#d2dcanvas-option","title":"d2dcanvas Option","text":"

    Set this to a twrConsoleCanvas instance to configure a 2D drawing surface. If you leave it undefined, a tag shortcut will be used.

    This option is a shortcut to setting std2d using the io option (note the different names).

    "},{"location":"api/api-typescript/#io-option-multiple-consoles-with-names","title":"io Option: Multiple Consoles with Names","text":"

    This option allows you to assign names to consoles. The C/C++ code can then retrieve a console by name.

    When using the io object to specify named consoles:

    • You can use the attribute stdio to set stdio.
    • You can use the attribute stderr to set stderr
    • You can use the attribute std2d to set the default 2D Drawing Surfaces -- used by twr-wasm 2D APIs.
    • all other attribute names are available for your consoles. Use this to access consoles in C/C++ beyond (or instead of) stdio, etc.

    Alternately, you can specify stdio and std2d directly as module attributes (outside of io) as a shortcut (see above).

    There is a twr-wasm C API to access named consoles: twr_get_console.

    This code snippet shows how to use the io option to pass in an object containing named console attributes:

    const stream1Element=document.getElementById(\"stream1\");\nconst stream2Element=document.getElementById(\"stream2\");\n\nconst debug = new twrConsoleDebug();\nconst stream1 = new twrConsoleDiv(stream1Element);\nconst stream2 = new twrConsoleDiv(stream2Element);\n\nstream1Element.addEventListener(\"keydown\",(ev)=>{stream1.keyDown(ev)});\nstream2Element.addEventListener(\"keydown\",(ev)=>{stream2.keyDown(ev)});\n\n// setting stdio and/or stderr to a debug console isn't necessary since that will be the default if stdio or stderr is not set.\n// but here to show how to set stdio and/or stderr.  They can be set to any console.\nconst amod = new twrWasmModuleAsync( {io:{stdio: debug, stderr: debug, stream1: stream1, stream2: stream2}} );\nconst mod = new twrWasmModule( {io:{stdio: debug, stderr: debug, stream1: stream1, stream2: stream2}} );\n

    In this case, as well as setting stdio and stderr, consoles named \"stream1\" and \"stream2\" are made available to the C/C++ code.

    Using a Named Console
    twr_ioconsole_t * stream1=twr_get_console(\"stream1\");\nfprintf(stream1, \"Hello Stream One!\\n\");\n

    A complete example multi-io is provided.

    "},{"location":"api/api-typescript/#deprecated-options","title":"Deprecated Options","text":"

    The following options are deprecated. Instead of these, use options available to twrConsoleDiv and twrConsoleTerminal constructors.

    deprecated
    export interface IModOpts {\n   windim?:[number, number],\n   forecolor?:string,\n   backcolor?:string,\n   fontsize?:number,\n}\n

    Note:

    • windim - if stdio is set to a twrConsoleTerminal, this will set the width and height, in characters. Instead, use constructor options on twrConsoleTerminal.
    • forecolor and backcolor - if stdio is set to twrConsoleDiv or twrConsoleTerminal, these can be set to a CSS color (like '#FFFFFF' or 'white') to change the default background and foreground colors. However, these are deprecated, and instead, use the twrConsoleDiv or twrConsoleTerminal constructor options.
    • fonsize - Changes the default fontsize if stdio is set to twrConsoleDiv or twrConsoleTerminal. Deprecated, instead use twrConsoleDiv or twrConsoleTerminal constructor options.
    • TStdioVals have been removed (they were a not too useful option in prior versions of twr-wasm)
    • divLog is deprecated. Instead use the putStr member function on most consoles.
    "},{"location":"api/api-typescript/#console-classes","title":"Console Classes","text":""},{"location":"api/api-typescript/#class-twrconsoledebug","title":"class twrConsoleDebug","text":"

    twrConsoleDebug streamings characters to the browser debug console.

    C type: IO_TYPE_CHARWRITE

    There are no constructor parameters.

    "},{"location":"api/api-typescript/#class-twrconsolediv","title":"class twrConsoleDiv","text":"

    twrConsoleDiv streams character input and output to a div tag .

    C type: IO_TYPE_CHARREAD and IO_TYPE_CHARWRITE

    The div tag will expand as you add more text (via printf, etc).

    You pass a <div> element to use to render the Console to to the twrConsoleDiv constructor. For example:

    <div id=\"div1\" tabindex=\"0\"></div>\n\n<script type=\"module\">\n   import {twrWasmModuleAsync, twrConsoleDiv} from \"twr-wasm\";\n\n   const stream1Element=document.getElementById(\"div1\");\n\n   // adding keyDown events is needed if the console will accept key input\n   // don't forget to set \"tabindex\" in your tag, otherwise it won't get key events\n   stream1Element.addEventListener(\"keydown\",(ev)=>{stream1.keyDown(ev)});\n\n   const stream1 = new twrConsoleDiv(stream1Element);\n   const mod = new twrWasmModuleAsync( {stdio: stream1} );\n   // mod.callC would go here...\n</script>\n

    There are constructor options to set the color and font size. You can also set these directly in the HTML for your <div> tag. If you wish to change the default font, set the font in the div tag with the normal HTML tag options.

    twrConsoleDiv constructor options
    constructor(element:HTMLDivElement,  params:IConsoleDivParams)\n\nexport interface IConsoleDivParams {\n   foreColor?: string,\n   backColor?: string,\n   fontSize?: number,\n}\n
    "},{"location":"api/api-typescript/#class-twrconsoleterminal","title":"class twrConsoleTerminal","text":"

    twrConsoleTerminal provides streaming and addressable character input and output. A <canvas> tag is used to render into.

    C types: IO_TYPE_CHARREAD, IO_TYPE_CHARWRITE, IO_TYPE_ADDRESSABLE_DISPLAY

    twrConsoleTerminal is a simple windowed terminal and supports the same streamed output and input features as a does twrConsoleDiv, 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).

    The canvas width and height, in pixels, will be set based on your selected font size and the width and height (in characters) of the terminal. These are passed as constructor options when you instantiate the twrConsoleTerminal.

    You can use the putStr member function on most consoles to print a string to the terminal in JavaScript.

    As you add more text (via printf, etc), the twrConsoleTerminal will scroll if it becomes full (unlike twrConsoleDiv, which expands)

    A list of C functions that operate on twrConsoleTerminal are available.

    Here is an example:

    <body>\n\n   <canvas id=\"canvas1forterm\" tabindex=\"0\"></canvas>\n\n   <script type=\"module\">\n      import {twrWasmModuleAsync, twrConsoleTerminal} from \"twr-wasm\";\n\n      // find the HTML elements that we will use for our console to render into\n      const term1Element=document.getElementById(\"canvas1forterm\");\n\n      // adding keyDown events is needed if the console will accept key input\n      // don't forget to set \"tabindex\" in your tag, otherwise it won't get key events\n      term1Element.addEventListener(\"keydown\",(ev)=>{term1.keyDown(ev)});\n\n      // create the console\n      const term1 = new twrConsoleTerminal(term1Element, {widthInChars: 50, heightInChars: 20});\n\n      const amod = new twrWasmModuleAsync( \n         {io:{\n            stdio: debug, stderr: debug, stream1: stream1, stream2: stream2, term1: term1, term2: term2, draw1: draw1, draw2: draw2\n         }} );\n\n      // set the input focus so user doesn't have to click\n      stream1Element.focus();\n\n      // load the wasm code and call the multi C function\n      await amod.loadWasm(\"./multi-io.wasm\");\n      await amod.callC([\"multi\"]);\n\n      // example of using a console in in JavaScript\n      stream1.putStr(`Hello stream1 of type ${stream1.getProp(\"type\")} from JavaScript!\\n`);\n\n   </script>\n</body>\n

    twrConsoleTerminal constructor options
    constructor (canvasElement:HTMLCanvasElement, params:IConsoleTerminalParams)\n\n// see twrConsoleDiv options elsewhere, which are also supported\nexport interface IConsoleTerminalParams extends IConsoleDivParams {\n   widthInChars?: number,\n   heightInChars?: number,\n}\n
    "},{"location":"api/api-typescript/#class-twrconsolecanvas","title":"class twrConsoleCanvas","text":"

    twrConsoleCanvas creates a 2D drawing surface that the Canvas compatible 2d drawing APIs can be used with.

    C type: IO_TYPE_CANVAS2D.

    constructor(element:HTMLCanvasElement)\n
    twrConsoleCanvas Example
    <body>\n   canvas id=\"canvas1for2d\"></canvas>\n\n   <script type=\"module\">\n      import {twrWasmModule, twrConsoleCanvas} from \"twr-wasm\";\n\n      // find the HTML elements that we will \n      // use for our console to render into\n      const draw1Element=document.getElementById(\"canvas1for2d\");\n\n      // create the console\n      const draw1 = new twrConsoleCanvas(draw1Element);\n\n      const mod = new twrWasmModule( {io: {std2d: draw1}  }} );\n\n      // callC here...\n   </script>\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.

    • View bouncing balls
    • Source for balls

    The bouncing balls example demonstrates

    • C++
    • Using the twr-wasm draw 2D APIs that match Javascript Canvas APIs.
    • Using the twr-wasm canvas.cpp wrapper class.

    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++.

    • View callC example running live
    • View callC example source
    "},{"location":"examples/examples-divcon/","title":"divcon - Printf and Input Using a div Tag","text":"

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

    • view divcon example running live
    • View divcon source code
    "},{"location":"examples/examples-divcon/#screen-grab-of-square-calculator","title":"Screen Grab of Square Calculator","text":""},{"location":"examples/examples-divcon/#c-code","title":"C Code","text":"divcon.c
    #include <stdio.h>\n#include <stdlib.h>\n#include \"twr-crt.h\"\n\nvoid stdio_div() {\n    char inbuf[64];\n    char *r;\n    int i;\n\n    printf(\"Square Calculator\\n\");\n\n    while (1) {\n        printf(\"Enter an integer: \");\n        r=twr_mbgets(inbuf);  // r is NULL if esc entered.  Otherwise r == inbuf\n        if (r) {  \n            i=atoi(inbuf);\n            printf(\"%d squared is %d\\n\\n\",i,i*i);\n        }\n        else {\n            printf(\"\\n\");\n        }\n    }\n}\n
    "},{"location":"examples/examples-divcon/#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
    <body>\n   <div id=\"stdioDiv\" \n        tabindex=\"0\" \n        style=\"color: DarkGreen; background-color: LightGray; font-size: 18px;font-family: Arial, sans-serif;\" >\n        Loading... <br>\n   </div>\n\n   <script type=\"module\">\n      import {twrWasmModuleAsync, twrConsoleDiv} from \"twr-wasm\";\n\n      const con = new twrConsoleDiv(document.getElementById(\"stdioDiv\"));\n      const amod = new twrWasmModuleAsync({stdio: con});\n\n      // remove 'Loading...'\n      document.getElementById(\"stdioDiv\").innerHTML =\"<br>\"; \n      // send key events to twrConsoleDiv\n      document.getElementById(\"stdioDiv\").addEventListener(\"keydown\",(ev)=>{con.keyDown(ev)});\n\n      await amod.loadWasm(\"./divcon.wasm\");\n      await amod.callC([\"stdio_div\"]);\n\n   </script>\n</body>\n
    "},{"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.

    • View example running on the web
    • View example source code
    "},{"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 a 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.

    • View helloworld example running live
    • View helloworld source code
    "},{"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.

    • view tests-libcxx example running live
    • View tests-libcxx source code

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

    • tests-user Live
    • tests-user Source
    "},{"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.

    • View live maze here
    • Source for maze
    "},{"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-multi-io/","title":"Multi-io -Multiple Console Example","text":""},{"location":"examples/examples-multi-io/#what-it-does","title":"What It Does","text":"

    This example demos six simultaneous consoles:

    • Two character streaming consoles directed to a <div> tag
    • Two character terminal consoles directed to a <canvas> tag
    • Two 2D draw surface consoles directed to a <canvas> tag

    The multi-io example also demos:

    • Creating consoles in JavaScript/TypeScript
    • Using consoles in C/C++ and JavaScript/TypeScript
    • Mixing multiple Consoles
    • Using multiple .wasm modules using the same console
    • Inputting, printing, and drawing to consoles
    "},{"location":"examples/examples-multi-io/#running-examples-and-source","title":"Running Examples and Source:","text":"
    • View multi-io
    • Source for multi-io

    Also see Console Introduction

    "},{"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":"
    • Click here to view C/C++ WebAssembly twr-wasm examples running live
    • Click here to view source code and make files
    "},{"location":"examples/examples-overview/#hello-world","title":"Hello World","text":"Name Description Link helloworld A very simple C Wasm example to get you started helloworld"},{"location":"examples/examples-overview/#console-examples","title":"Console Examples","text":"Name Description Link divcon This simple C program demos inputting andprinting characters to a div tag divcon terminal This simple C program demos writing and inputtingfrom a <canvas> tag that twr-wasm configuresas a windowed \"terminal\" terminal multi-io Demo 6 simultaneous consoles: stream i/o, terminal, 2D Drawing multi-io"},{"location":"examples/examples-overview/#draw-2d-examples","title":"Draw 2D Examples","text":"Name Description Link 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"},{"location":"examples/examples-overview/#call-argument-examples","title":"Call Argument Examples","text":"Name Description Link callC A demo of passing and returning values betweenJavaScript and Wasm module callc fft A demo of calling a C library to perform an FFTthat is graphed in TypeScript fft"},{"location":"examples/examples-overview/#unit-tests","title":"Unit Tests","text":"Name Description Link 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/#running-the-examples-locally","title":"Running the examples locally","text":"

    To run the examples locally:

    • clone the twr-wasm repo
    • then from a shell with the repo root as the current directory, execute python examples\\server.py. This small python script is a local http server that also sets the needed cors headers
    • http://localhost:8000/examples/
    "},{"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.

    • View Pong
    • Source for Pong

    The Pong example demonstrates

    • C++
    • Using twr-wasm draw 2D APIs that match Javascript Canvas APIs.
    • Using the twr-wasm canvas.cpp class.
    • Taking in Javascript events as user input

    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-terminal/","title":"Terminal Console Demo","text":"

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

    "},{"location":"examples/examples-terminal/#what-it-does","title":"What it Does","text":"
    • uses class twrConsoleTerminal, a Console
    • moves a string up or down in the terminal window when you press the u or d or arrow keys.
    • shows basic color usage
    • draws a graphic box around the terminal window.
    "},{"location":"examples/examples-terminal/#run-and-view-the-code","title":"Run and View the Code","text":"
    • View terminal example running live
    • View terminal source code
    • For another 'terminal' demo View tests-user
    "},{"location":"examples/examples-terminal/#screen-grab-of-terminal","title":"Screen Grab of Terminal","text":""},{"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:

    • If you're C/C++ code does not have any direct user interface built in, it can do its calculations and return. The FFT is an example of this.
    • If your C/C++ code uses a classic C \"UI\", where it gets keys from stdin and sends the results to stdout, you can direct stdin and stdout to a <div> or <canvas> tag. This is explained in the stdio section.
    • Your C/C++ code could be sent events from JavaScript (such mouse, key, timer, or other). This is done by simply calling a C function with the events as arguments. The C/C++ code could then generate no output, could render to a <div> or <canvas> using stdio type C/C++ functions, or it could render to a <canvas> using 2D drawing APIs that correspond to JavaScript canvas 2D draw operations. (Balls) is an example.
    "},{"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 characters. 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:

    • Configure your text editor to save in Windows-1252/ISO-8859-1 format (instead of UTF-8)
    • use compiler flags like --finput-charset and -fexec-charset

    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 describes 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:

    • llvmPackages_18.clang-unwrapped (clang 18.1.7)
    • llvmPackages_17.clang-unwrapped (clang 17.0.6)
    "},{"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:

    • ../../include is a relative link to include that works if your project is a sub folder in the examples folder.
    • ./node_modules/twr-wasm/include assumes you installed with npm into your project folder. (see the Hello World Walk Through).
    "},{"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(twr_ioconsole_t* 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)
    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.
    7. 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 these CORS notes.
    8. your code can be bundled or unbundled, but
    9. you need to ensure that the web server/browser can find the source code
    10. 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

    Inside JavaScript, you can print to a console using the putStr console member function that is available on all consoles.

    For example:

    const stream1 = new twrConsoleDiv(stream1Element);\nstream1.putStr(`Hello stream1 of type ${stream1.getProp(\"type\")} from JavaScript!\\n`);\n

    "},{"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:

    • Create the helloworld.c file
    • Create the index.html file
    • Compile the helloworld.c code with clang
    • Link the helloworld.o and twr.a files with wasm-ld to create a helloworld.wasm file
    • Set the needed library and include paths to allow the twr-wasm libraries to be discovered
    • Create an optional Makefile
    • Execute the \"hello world\" program using a local web server or directly with VS Code and Chrome

    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":"
    • prerequisites: install clang, wasm-ld, and python or VS Code (or both)
    • Create a folder for your project, such as hello-proj
    • cd into hello-proj
    • npm install twr-wasm
    • your folder structure should now look similar to this:
      hello-proj\\\n\u251c\u2500\u2500package.json\n\u2514\u2500\u2500node_modules\\\n   \u2514\u2500\u2500twr-wasm\\\n      \u251c\u2500\u2500examples\\\n      \u2514\u2500\u2500include\\\n      \u2514\u2500\u2500lib-c\\\n      \u2514\u2500\u2500lib-js\\\n      \u2514\u2500\u2500LICENSE\n      \u2514\u2500\u2500package.json\n      \u2514\u2500\u2500readme.md\n
    "},{"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.

    • Copy the file server.py from the examples folder to your hello-proj folder (where your index.html resides).
    • Execute with the shell command python server.py.
    • Open your web browser and browse to http://localhost:8000/index.html
    • You should see 'Hello World' in the browser window!

    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:

    • select the Run and Debug icon on left
    • Select the green play icon at the top, with \"Launch Chrome Hello, World!\" selected
    • Chrome should launch, and you should see 'Hello World' in the browser window!

    --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:

    • npm install will install everything necessary to build your software: built libraries (lib-js, lib-c) and includes. In addition the examples are installed.
    • git clone will copy the above as well as the source and VS Code settings.

    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:

    • Integer 32 or 64 bit
    • Floating point 32 or 64 bit

    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:

    • Integer 32: JavaScript number type is converted to an Integer 32 and passed to C when the C function prototype specifies a signed or unsigned int, long, int32_t, or a pointer type. All of these are 32 bits in length in wasm32.
    • Integer 64: JavaScript bigint type is converted to an Integer 64 and passed to C when the C function prototype specifies signed or unsigned int64_t (or equivalent). Attempting to pass a JavaScript number to a C int64_t will fail with a JavaScript runtime error.
    • Float 32: JavaScript number type is converted to a Float 32 when the C function prototype specifies a float.
    • Float 64: JavaScript number type is passed as a Float 64 when the C function prototype specifies a double.

    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 pass 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
    • The first entry, int a, will be at offset 0 in memory (from the start of the struct in memory).
    • The second entry, char b, will be at offset 4 in memory. This is expected since the length of an int is 4 bytes.
    • The third entry, int *c, will be at offset 8 in memory, not at offset 5 as you might expect. The compiler adds three bytes of padding to align the pointer to a 4-byte boundary.

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

    • char is 1 byte aligned
    • short is 2 byte aligned
    • pointers are 4 byte aligned
    • int, long, int32_t are 4 byte aligned
    • double (Float 64) is 8-byte aligned

    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:

    • await mod.malloc(structSize) is a shortcut for: await mod.callC([\"malloc\", structSize])
    • mod.malloc returns a C pointer as a number. This pointer is also an index into WebAssembly.Memory -- which is exposed as the byte array (Uint8Array) via mod.mem8 by twr-wasm.
    • When accessing a C struct in JavaScript/TypeScript, you have to do a bit of arithmetic to find the correct structure entry.
    • The entry int *c is a pointer to an int. So a separate malloc to hold the int is needed.
    • In twr-wasm there is no function like setLong to set a byte. Instead you access the byte array view of the WebAssembly memory with mod.mem8. Functions like mod.setLong manipulate this byte array for you.
    • As well as mod.mem8 (Uint8Array), you can also access WebAssembly.Memory directly via mod.mem32 (Uint32Array), and mod.memD (Float64Array).
    • The list of functions available to access WebAssembly.Memory can be found at the end of this page.
    "},{"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:

    • Allocate memory for the string inside the WebAssembly memory. This is typically done by calling the C malloc from JavaScript. malloc returns a pointer, which is an index into the WebAssembly Memory.
    • Copy the JavaScript string to this malloc'd Wasm memory. In the case of twr-wasm, this copying also converts the character encoding as necessary, for example, to UTF-8.
    • Pass the malloc'd memory index to your function as an integer (which is accepted as a pointer by C code).

    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:

    • ArrayBuffers have entries of all the same length, so the index math is straight forward and now struct padding is needed.
    • When an ArrayBuffer is passed to a function, the function receives a pointer to the malloc memory. If the length is not known by the function, the length needs to be passed as a separate argument.
    • Before callC returns, any modifications made to the memory by the C code are reflected back into the ArrayBuffer.
    • the malloced copy of the ArrayBuffer is freed.

    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":"Consoles with C/C++ WebAssemblystdio, stderr, and more","text":"

    This section describes how to use twr-wasm in order to:

    • create input/output consoles for use by C/C++
    • direct stdin/stdout and stderr to a console
    • use addressable display and canvas 2D consoles
    • use multiple consoles at once
    "},{"location":"gettingstarted/stdio/#quick-example","title":"Quick Example","text":"Hello World
    #include <stdio.h>\n\nvoid hello() {\n    printf(\"hello world\\n\");\n}\n
    Using twrConsoleDiv
    <body>\n   <div id=\"console-tag\"></div>\n\n   <script type=\"module\">\n      import {twrConsoleDiv, twrWasmModule} from \"twr-wasm\";\n\n      const tag=document.getElementById(\"console-tag\");\n      const streamConsole=new twrConsoleDiv(tag); \n      const mod = new twrWasmModule({stdio: streamConsole});\n      await mod.loadWasm(\"./helloworld.wasm\");\n      await mod.callC([\"hello\"]);\n\n   </script>\n</body>\n
    Using twr_iodiv Shortcut
    <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\n   </script>\n</body>\n
    "},{"location":"gettingstarted/stdio/#running-examples","title":"Running 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 Multiple Consoles, including Canvas2D View multi-io demo Source"},{"location":"gettingstarted/stdio/#capabilities","title":"Capabilities","text":"

    With a Console you can:

    • read character streams (Use C statements like getc or io_mbgets)
    • write character streams (use C statements like printf or cout)
    • position characters, graphics, colors with an addressable display (Use C statements like io_setc32 or io_set_cursor).
    • draw to a Canvas compatible 2D surface (Use C statements like d2d_fillrect).

    Consoles are primarily designed for use by twr-wasm C/C++ modules, but they can also be used by JavaScript/TypeScript.

    Although it is common to have a single console, an arbitrary number of consoles can be created, and they can be used by an arbitrary number of twr-wasm C/C++ modules.

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

    "},{"location":"gettingstarted/stdio/#tag-shortcuts","title":"Tag Shortcuts","text":"

    If you add a <div id=\"twr_iodiv\">, a <canvas id=\"twr_iocanvas\">, or a <canvas id=\"twr_d2dcanvas\"> tag to your HTML, twr-wasm will create the appropriate class for you when you instantiate the class twrWasmModule or twrWasmModuleAsync. Use these tag shortcuts as an aternative to instantiating the console classes in your JavaScript/TypeScript.

    • <div id=\"twr_iodiv\"> will be used to create a twrConsoleDiv as stdio
    • <canvas id=\"twr_iocanvas\"> will be used to create a twrConsoleTerminal as stdio.
    • <canvas id=\"twr_d2dcanvas\"> will be used to create a twrConsoleCanvas as std2d -- the default 2D drawing surface. See 2D drawing APIs.

    If neither of the above <div> or <canvas> is defined in your HTML, and if you have not set stdio via the io or stdio module options, then stdout is sent to the debug console in your browser. And stdin is not available.

    "},{"location":"gettingstarted/stdio/#console-classes","title":"Console Classes","text":"

    Consoles are implemented in TypeScript and run in the JavaScript main thread. This allows consoles to be shared by multiple wasm modules.

    For simple cases, when you use the tag shortcuts, you won't need to use these console classes directly. For more bespoke cases, they will come in handy. For details on console classes, see the TypeScript/JavaScript API reference

    These conosle classes are available in twr-wasm:

    • twrConsoleDiv streams character input and output to a div tag
    • twrConsoleTerminal provides streaming or addressable character input and output using a canvas tag.
    • twrConsoleDebug streamings characters to the browser debug console.
    • twrConsoleCanvas creates a 2D drawing surface that the Canvas compatible 2d drawing APIs can be used with.
    "},{"location":"gettingstarted/stdio/#multiple-consoles-with-names","title":"Multiple Consoles with Names","text":"

    When you instantiate a class twrWasmModule or twrWasmModuleAsync, you can pass it the module option io -- a javascript object containing name-console attributes. Your C/C++ code can then retrieve a console by name. This is described in more detail the TypeScript/JavaScript API Reference.

    Also see the multi-io example.

    "},{"location":"gettingstarted/stdio/#setting-stdio-and-stderr","title":"Setting stdio and stderr","text":"

    stdio can be defined automatically if you use a Tag Shortcut. stderr streams to the browser's debug console by default. Both can be set to a specific console with the module io option.

    For example, either of these will set stdio to a streaming div console:

    const tag=document.getElementById(\"console-tag\");\nconst streamConsole=new twrConsoleDiv(tag);\n\nconst mod = new twrWasmModule({stdio: streamConsole});\nconst mod = new twrWasmModule({ io: {stdio: streamConsole} });\n

    This option would send stderr and stdio to the same console:

    const mod = new twrWasmModule({ io: \n   {stdio: streamConsole, stderr: streamConsole} \n});\n
    "},{"location":"gettingstarted/stdio/#utf-8-or-windows-1252","title":"UTF-8 or Windows-1252","text":"

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

    "},{"location":"gettingstarted/stdio/#c-access-to-consoles","title":"C Access To Consoles","text":""},{"location":"gettingstarted/stdio/#io_functions","title":"io_functions","text":"

    io_functions are available to operate on all character based Consoles.

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

    d2d_functions are available to operate on Canvas 2D Consoles.

    "},{"location":"gettingstarted/stdio/#reading-from-a-console","title":"Reading from a Console","text":"

    Reading from a console is blocking, and so twrWasmModuleAsync must be used to receive keys. There are some specific requirements to note in the twrWasmModuleAsync API docs.

    You can get characters with any of these functions:

    • io_mbgets - get a multibyte string from a console using the current locale character encoding. Console must support IO_TYPE_CHARREAD.
    • twr_mbgets - the same as io_mbgets with the console set to stdin.
    • io_mbgetc - get a multibyte character from an twr_ioconsole_t * (aka FILE *) like stdin using the current locale character encoding
    • getc (same as fgetc) - get a single byte from a FILE * (aka twr_ioconsole_t *) -- returning ASCII or extended ASCII (window-1252 encoding)
    • io_getc32 - gets a 32 bit unicode code point from an twr_ioconsole_t * (which must support IO_TYPE_CHARREAD)
    "},{"location":"gettingstarted/stdio/#standard-c-library-functions","title":"Standard C Library Functions","text":"

    Many of the common standard C library functions, plus twr-wasm specific functions, are available to stream characters to and from the standard input and output console that supports character streaming (most do).

    In C, a console is represented by twr_ioconsole_t. In addition, FILE is the same as a twr_ioconsole_t (typedef twr_ioconsole_t FILE). stdout, stdin, stderr are all consoles.

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

    FILE is supported for user input and output, and for stderr. FILE as filesystem I/O 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

    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":"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 ():

    • TypeScript (5.4.5)
    • clang tool chain (17.0.6) - for C/C++ code
    • wasm-ld (17.0.6) - to link the .wasm files
    • wat2wasm (1.0.34) - to compile WebAssembly (.wat) files of which I have a few
    • GNU make (4.4.1)
    • git - to clone twr-wasm source, or to clone llvm, if you want to build libc++

    In addition, you might need:

    • VS Code - to use the debug launcher and build tasks
    • NPM - package manager
    • Parcel v2 - to bundle the examples
    • mkdocs, material theme, meta-descriptions plugin - to build the documentation static web site
    • python - mkdocs is built with python, and you need python to run server.py in examples
    • CMake and ninja - to build llvm libc++

    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":"HTTP CORS headers needed to use twrWasmModuleAsync","text":"

    If you are using twr-wasm with web pages served by an http server, you may need to enable certain CORS headers. This applies whether using a remote server or using your local machine for development.

    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. It may be helpful to also see the SharedArrayBuffer documentation online.

    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.

    Here are two provided examples of how to enable the necessary headers:

    • server.py
    • staticwebapp.config.json

    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":"more/production/#using-twrwasmmoduleasync-with-file","title":"Using twrWasmModuleAsync with file:","text":"

    If you are loading html with chrome from files (not using an https server), you will need to set these command line args:

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

    More detail is found in the debugging section.

    "},{"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 terminal emulator, character encoding support, and more.

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

    Version 2.4.2

    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 includes comprehensive console support for stdio. You can input and print to a <div> tag, or use a <canvas> element as an terminal.

    twr-wasm makes it easy to await on blocking C/C++ functions.

    twr-wasm makes it easy to use C/C++ 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.

    "},{"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 Maze Gen/Solve (Win32 C Port) View live maze Source for maze Input/Output with <div> View square demo Source I/O to terminal with <canvas> View demo Source CLI using libc++ and <canvas>) View console Source"},{"location":"#key-features","title":"Key Features","text":"
    • compile and link C/C++ for use with WebAssembly using clang directly
    • standard C library, libc++. and purpose built APIs available from C/C++
    • TypeScript/JavaScript classes to load Wasm modules and call C/C++ functions
    • localization support, UTF-8, and windows-1252 support
    • in C/C++, print and get characters to/from <div> tags in your HTML page
    • in C/C++, print and get characters to/from a <canvas> based \"terminal\"
    • in C/C++ use 2D drawing API compatible with JavaScript Canvas
    • in C/C++, use the \"blocking loop\" pattern and integrate with Javascript's asynchronous event loop
    "},{"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":"
    • libc++ built for WebAssembly is included
    • most of the standard C library is now implemented
    • instructions for WebAssembly C/C++ source level debugging
    • version of library with debug symbols provided
    • locale, UTF-8, and windows-1252 support
    "},{"location":"#version-2-limitations","title":"Version 2 Limitations","text":"
    • libc++ not built with exceptions enabled
    • some standard C library functions are not 100% implemented
    • Designed to work with a browser. Not tested with or designed to work with node.js
    • Not all of compile-rt is ported (but most bits you need are)
    "},{"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 Character Console API","text":"

    twr-wasm for WebAssembly provides Consoles for interactive user I/O. Character and graphic 2D draw consoles exist. This section covers the streaming and addressable character APIs that can be used with an instance of twrConsoleDebug, twrConsoleTerminal, twrConsoleDiv. This API works with stdin, stdout, stderr and custom named consoles.

    Also see the Consoles section in Getting Started

    "},{"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-a-console","title":"Getting a Console","text":""},{"location":"api/api-c-con/#stdin-stdout-stderr","title":"stdin, stdout, stderr","text":"

    stdin, stdout, stderr are defined in <stdio.h>.

    This section describes how to configure stdio

    In C, consoles are represented by a twr_ioconsole_t.

    stdio.h also defines FILE like this:

    typedef twr_ioconsole_t 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/#twr_get_console","title":"twr_get_console","text":"

    This function will retrieve a console by its name. The standard names are stdio, stderr, and std2d. In addition, any named console that was passed to a module using the io option can be retrieved with this function.

    See io doc.

    See the multi-io example.

    #include \"twr-crt.h\"\n\ntwr_ioconsole_t* twr_get_console(const char* name)\n
    "},{"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\ntwr_ioconsole_t* io_nullcon(void);\n
    "},{"location":"api/api-c-con/#io-console-functions","title":"IO Console Functions","text":""},{"location":"api/api-c-con/#io_cls","title":"io_cls","text":"

    For addressable display consoles only.

    Clears the screen. That is, all character cells in the console 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(twr_ioconsole_t* io);\n
    "},{"location":"api/api-c-con/#io_getc32","title":"io_getc32","text":"

    Waits for the user to press a key and then returns a unicode code point.

    To return characters encoded with the current locale, see io_mbgetc

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

    For addressable display consoles only.

    Gets the current default foreground and background colors. These colors are used by an new text updates.

    The color format is a 24 bit int as RGB.

    #include <twr_io.h>\n\nvoid io_get_colors(twr_ioconsole_t* io, unsigned long *foreground, unsigned long *background);\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 addressable display consoles, the cursor position ranges from [0, width*height-1], inclusive.

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

    Given a string key (name) of a property, returns its integer value. The available properties varies by console type.

    #include <twr_io.h>\n\nint io_get_prop(twr_ioconsole_t* io, const char* key)\n
    All consoles support: \"type\".

    Addressable consoles also support: \"cursorPos\", \"charWidth\", \"charHeight\", \"foreColorAsRGB\", \"backColorAsRGB\", \"widthInChars\", \"heightInChars\", \"fontSize\", \"canvasWidth\", \"canvasHeight\"

    You can do a bitwise & on type with the following C defines to determine a console capabilities:

    • IO_TYPE_CHARREAD
    • IO_TYPE_CHARWRITE
    • IO_TYPE_ADDRESSABLE_DISPLAY
    • IO_TYPE_CANVAS2D

    For example:

    if (io_get_prop(stdin, \"type\")&IO_TYPE_CHARREAD) {\n   printf (\"okay to read from stdin);\n}\n

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

    Returns the width in characters of an addressable console.

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

    Returns the height in characters of an addressable console.

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

    For addressable display 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 console (see twrConsoleTerminal Options), 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(twr_ioconsole_t* io, unsigned long foreground, unsigned long background);\n
    "},{"location":"api/api-c-con/#io_setc","title":"io_setc","text":"

    For addressable display consoles only.

    Sets a console cell to the specified character. Sends a byte to an console and supports the current locale's character encoding. This function will \"stream\" using the current code page. In other words, if you are in the \"C\" locale io_setc it will set ASCII characters. 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(twr_ioconsole_t* io, int location, unsigned char c);\n
    "},{"location":"api/api-c-con/#io_setc32","title":"io_setc32","text":"

    For addressable display consoles only.

    Sets a console 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(twr_ioconsole_t* io, int location, int c);\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(twr_ioconsole_t* io, int loc);\n
    "},{"location":"api/api-c-con/#io_set_cursorxy","title":"io_set_cursorxy","text":"

    Set's the cursor's x,y position in an addressable console.

    #include <twr_io.h>\n\nvoid io_set_cursorxy(twr_ioconsole_t* io, int x, int y);\n
    "},{"location":"api/api-c-con/#io_setfocus","title":"io_setfocus","text":"

    Sets the input focus to the indicated console.

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

    Sets a range of characters in an addressable display.

    #include <twr_io.h>\n\nvoid io_set_range(twr_ioconsole_t* io, int *chars32, int start, int len)\n
    "},{"location":"api/api-c-con/#io_setreset","title":"io_setreset","text":"

    For addressable display 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 terminal example.

    #include <twr_io.h>\n\nbool io_setreset(twr_ioconsole_t* io, int x, int y, bool isset);\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(twr_ioconsole_t* io, char* strout);\n
    "},{"location":"api/api-c-con/#io_mbgets","title":"io_mbgets","text":"

    Gets a string from a Console. 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. If the encoding is UTF-8, then the result will be multibyte.

    This function is commonly used with stdin.

    This function requires that you use twrWasmModuleAsync.

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

    For addressable display consoles only.

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

    #include <twr_io.h>\n\nbool io_point(twr_ioconsole_t* io, int x, int y);\n
    "},{"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(twr_ioconsole_t* 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(twr_ioconsole_t* 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(twr_ioconsole_t *io, const char *format, ...);\n
    "},{"location":"api/api-c-con/#io_begin_draw","title":"io_begin_draw","text":"

    For addressable display 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 terminal example.

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

    For addressable display consoles only.

    See io_begin_draw.

    #include <twr_io.h>\n\nvoid io_end_draw(twr_ioconsole_t* io);\n
    "},{"location":"api/api-c-con/#deprecated-functions","title":"Deprecated Functions","text":""},{"location":"api/api-c-con/#twr_debugcon","title":"twr_debugcon","text":"

    This function has been removed. Use stderr or twr_conlog.

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

    or

    #include <stdio.h>\n\nfprintf(stderr, \"hello over there in browser debug console land\\n\");\n
    "},{"location":"api/api-c-con/#twr_divcon","title":"twr_divcon","text":"

    This function has been removed.

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

    This function has been removed.

    "},{"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.

    "},{"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/#code-example","title":"Code Example","text":"Draw A Rectangle
    #include \"twr-draw2d.h\"\n\nvoid square() {\n   // batch draw commands, with a maximum of 100 commands before render\n   struct d2d_draw_seq* ds=d2d_start_draw_sequence(100);\n   // set color using CSS color string\n   d2d_setfillstyle(ds, \"blue\");\n   // draw a the rect\n   d2d_fillrect(ds, 10, 10, 100, 100);\n   // this will cause the JavaScript thread to render\n   d2d_end_draw_sequence(ds);\n}\n
    "},{"location":"api/api-c-d2d/#overview","title":"Overview","text":"

    The Draw 2D APIs are C APIs and are part of the twr-wasm library that you access with #include \"twr-draw2d.h\". There is also a C++ canvas wrapper class in examples/twr-cpp used by the balls and pong examples.

    To create a canvas surface, that you can draw to using the twr-wasm 2D C drawing APIs, you can use the twrConsoleCanvas class in your JavaScript/HTML (see Consoles Section). Or more simply, if you add a canvas tag to your HTML named twr_d2dcanvas, the needed twrConsoleCanvas will be created automatically.

    <canvas id=\"twr_d2dcanvas\" width=\"600\" height=\"600\"></canvas>\n//Feel free to change the `width=\"600` and/or `height=\"600` attributes.\n

    To draw using the C 2D Draw API:

    • call d2d_start_draw_sequence (or alternately d2d_start_draw_sequence_with_con)
    • call one or more (a sequence) of 2D draw commands, like d2d_fillrect
    • call d2d_end_draw_sequence
    • repeat as desired

    d2d_start_draw_sequence will draw to the default twrConsoleCanvas, as explained at the start of this section. d2d_start_draw_sequence_with_con is optional, and allows you to specify the twrConsoleCanvas to draw to. You would typically get this console in C using the twr_get_console function (which retrieves a named console that you specified in the io module option.)

    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, 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/#possible-pitfalls","title":"Possible Pitfalls","text":"

    Some commands have extra details that you need to be aware of to avoid performance loss or bugs.

    • Getters, like d2d_measuretext, will flush the queue in order to retrieve the requested data. If your program relies on not flushing early (for example, to avoid flashes), then getters should be avoided in your main render loops.
    • putImageData references the provided pointer, so the given image data needs to stay valid on the caller's stack or heap until flush is called.
    • getLineDash takes in a buffer_length, double * array (the buffer), and returns the amount of the buffer filled. If there are more line segments than can fit in the buffer_length, a warning is printed and the excess is voided. If you want to know the size before hand for allocation, the getLineDashLength function is available.
    "},{"location":"api/api-c-d2d/#notes","title":"Notes","text":"

    The functions listed below are based on the JavaScript Canvas 2D API (found here). However, there are some slight differences since these APIS are made for C rather than JavaScript. For example some items keep resources stored on the JavaScript side (such as d2d_createlineargradient) which are referenced by a numeric ID , rather than an actual object reference.

    Additionally, there are alternative functions like d2d_setstrokestylergba, which calls the same underlying function as d2d_setstrokestyle, but takes in a color as a number rather than CSS style string.

    As noted above, putImageData requires that the image data be valid until flush is called.

    Other functions that take a string, like d2d_filltext, don't have this same issue because they make a copy of the string argument. These string copies will be automatically freed.

    d2d_load_image should be called outside of a d2d_start_draw_sequence segment. If you are loading it to an id that you plan on freeing, ensure that the buffer is flushed before doing so as d2d_load_image bypasses it. In addition, d2d_load_image requires you to be using twrWasmAsyncModule as it waits for the image to load (or fail) before returning.

    "},{"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);\nstruct d2d_draw_seq* d2d_start_draw_sequence_with_con(int flush_at_ins_count, twr_ioconsole_t * con);\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, unsigned long c, double x, double y);\nvoid d2d_stroketext(struct d2d_draw_seq* ds, const char* text, 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_setstrokestylergba(struct d2d_draw_seq* ds, unsigned long color);\nvoid d2d_setfillstylergba(struct d2d_draw_seq* ds, unsigned long color);\nvoid d2d_setstrokestyle(struct d2d_draw_seq* ds, const char* css_color);\nvoid d2d_setfillstyle(struct d2d_draw_seq* ds, const char* css_color);\nvoid d2d_setfont(struct d2d_draw_seq* ds, const char* font);\nvoid d2d_setlinecap(struct d2d_draw_seq* ds, const char* line_cap);\nvoid d2d_setlinejoin(struct d2d_draw_seq* ds, const char* line_join);\nvoid d2d_setlinedashoffset(struct d2d_draw_seq* ds, double line_dash_offset);\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_arcto(struct d2d_draw_seq* ds, double x1, double y1, double x2, double y2, double radius);\nvoid d2d_bezierto(struct d2d_draw_seq* ds, double cp1x, double cp1y, double cp2x, double cp2y, double x, double y);\nvoid d2d_roundrect(struct d2d_draw_seq* ds, double x, double y, double width, double height, double radii);\nvoid d2d_ellipse(struct d2d_draw_seq* ds, double x, double y, double radiusX, double radiusY, double rotation, double startAngle, double endAngle, bool counterclockwise);\nvoid d2d_quadraticcurveto(struct d2d_draw_seq* ds, double cpx, double cpy, double x, double y);\nvoid d2d_rect(struct d2d_draw_seq* ds, double x, double y, double width, double height);\nvoid d2d_closepath(struct d2d_draw_seq* ds);\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\nvoid d2d_reset(struct d2d_draw_seq* ds);\nvoid d2d_clearrect(struct d2d_draw_seq* ds, double x, double y, double w, double h);\nvoid d2d_scale(struct d2d_draw_seq* ds, double x, double y);\nvoid d2d_translate(struct d2d_draw_seq* ds, double x, double y);\nvoid d2d_rotate(struct d2d_draw_seq* ds, double angle);\nvoid d2d_gettransform(struct d2d_draw_seq* ds, struct d2d_2d_matrix *transform);\nvoid d2d_settransform(struct d2d_draw_seq* ds, double a, double b, double c, double d, double e, double f);\nvoid d2d_settransformmatrix(struct d2d_draw_seq* ds, const struct d2d_2d_matrix * transform);\nvoid d2d_transform(struct d2d_draw_seq* ds, double a, double b, double c, double d, double e, double f);\nvoid d2d_transformmatrix(struct d2d_draw_seq* ds, const struct d2d_2d_matrix * transform);\nvoid d2d_resettransform(struct d2d_draw_seq* ds);\nvoid d2d_setlinedash(struct d2d_draw_seq* ds, unsigned long len, const double* segments);\nunsigned long d2d_getlinedash(struct d2d_draw_seq* ds, unsigned long length, double* buffer);\nunsigned long d2d_getlinedashlength(struct d2d_draw_seq* ds);\n\nbool d2d_load_image(const char* url, long id);\nbool d2d_load_image_with_con(const char* url, long id, twr_ioconsole_t * con);\nvoid d2d_drawimage(struct d2d_draw_seq* ds, long id, double dx, double dy);\nvoid d2d_getimagedata(struct d2d_draw_seq* ds, double x, double y, double width, double height, void* buffer, unsigned long buffer_len);\nunsigned long d2d_getimagedatasize(double width, double height);\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

    d2d_gettransform() returns this structure:

    struct d2d_2d_matrix {\n   double a, b, c, d, e, f;\n};\n

    d2d_getlinedash() returns this structure:

    struct d2d_line_segments {\n    long len;\n    double *segments;\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 stderr (usually your browser console) from your C code.

    #include \"twr-crt.h\"\n\nvoid twr_conlog(char* format, ...);\n
    This call is identical to fprintf(stderr, ...), except that it adds a newline.

    When stderr is set to twrConsoleDebug each call to twr_conlog() will generate a single call to console.log() in JavaScript to ensure that you see debug prints.

    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.

    "},{"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 with these functions is blocking and you must use twrWasmModuleAsync -- see stdin for details on how to enable blocking character input.

    Also see:

    • io_mbgets - get a multibyte string from a console using the current locale character encoding. Console must support IO_TYPE_CHARREAD.
    • twr_mbgets - the same as io_mbgets with the console set to stdin.
    • io_mbgetc - get a multibyte character from an IoConsole (like stdin) using the current locale character encoding
    • getc (sames as fgetc) - get a single byte from a FILE * (IoConsole) -- returning ASCII or extended ASCII (window-1252 encoding)
    • io_getc32 - gets a 32 bit unicode code point from an IoConsole (which must support IO_TYPE_CHARREAD)
    #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 twr_ioconsole_t*)

    #include <stdio.h>\n\nvoid twr_mem_debug_stats(twr_ioconsole_t* 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 Character Encoding Support with twr-wasm.

    #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 'twr_ioconsole_t *' 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 twr_ioconsole_t 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 it 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-libcpp/","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":"
    • libc++ locale and unicode functions are supported by twr-wasm.
    • libc++ unicode support includes utf-16 and utf-32 strings.
    "},{"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 APILoad and call Wasm, Create i/o Consoles","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.
    • create I/O Consoles for character streaming, a terminal, or 2D Canvas Drawing

    class twrWasmModule and class twrWasmModuleAsync are used to load .wasm modules and call their C functions. Both classes 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.

    The classes twrConsoleDiv, twrConsoleTerminal, twrConsoleDebug, and twrConsoleCanvas create consoles that enable user i/o. Your C/C++ can direct user interactive i/o to these consoles. See Console Introduction for information on enabling character input and output in a module.

    "},{"location":"api/api-typescript/#apis-common-to-twrwasmmodule-and-twrwasmmoduleasync","title":"APIs Common to twrWasmModule and twrWasmModuleAsync","text":""},{"location":"api/api-typescript/#common-constructor-options","title":"Common Constructor Options","text":"

    See module options below.

    "},{"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:

    • the first entry is the name of the C function in the Wasm module to call
    • and the next optional entries are a variable number of arguments to pass to the C function, of type:

      • number - will be converted to a signed or unsigned long, int32_t, int, float or double as needed to match the C function declaration.
      • bigint - will be converted into an int64_t or equivalent
      • string - converted to a char * of malloc'd module memory where string is copied into
      • ArrayBuffer - the array is copied into malloc'd module memory. If you need to pass the length, pass it as a separate argument. Any modifications to the memory made by your C code will be reflected back into the JavaScript ArrayBuffer.
      • URL - the url contents are copied into malloc'd module Memory, and two C arguments are generated - index (pointer) to the memory, and length

    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. 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-twrwasmmodule","title":"class twrWasmModule","text":"

    This class is used when your C function call will not block (that is, they will not take 'a long time' to execute).

    The constructor accepts an optional object (type IModOpts), which is explained further down.

    import {twrWasmModule} from \"twr-wasm\";\n\nconst mod = new twrWasmModule();\n

    "},{"location":"api/api-typescript/#class-twrwasmmoduleasync","title":"class twrWasmModuleAsync","text":"

    This class is used to enable blocking C functions, suchs as sleep or traditional C style blocking input (such as getc);

    The constructor accepts an optional object (type IModOpts), which is explained further down.

    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

    You must use twrWasmModuleAsync in order to:

    • call any blocking C function (meaning it takes \"a long time\") to return
    • use blocking input from a div or canvas ( eg. twr_mbgets )
    • use twr_sleep
    "},{"location":"api/api-typescript/#linking-requirements","title":"Linking Requirements","text":"

    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 wasm-ld Linker Options.

    "},{"location":"api/api-typescript/#javascript-needed-for-char-input","title":"JavaScript Needed for Char Input","text":"

    When a console will handle key input, you need to add a line to your JavaScript to send key events to the console. There are two options for this: You can send the key events directly to the console, or if the key events are always directed to stdio, you cam send the key events to the module. This latter case is primarily for when you are using tag shortcuts.

    To send key events to the console, you add a line like this:

    yourDivOrCanvasElement.addEventListener(\"keydown\",(ev)=>{yourConsoleClassInstance.keyDown(ev)});\n

    To send key events to the module's stdio, you add a line like this:

    yourDivOrCanvasElement.addEventListener(\"keydown\",(ev)=>{yourModuleClassInstance.keyDown(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.):

    yourDivOrCanvasElement.focus();\n

    You will also need to set the tabindex attribute in your tag like this to enable key events:

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

    See this example on character input.

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

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

    twrWasmModuleAsync uses SharedArrayBuffers which require certain CORS HTTP headers to be set. Note that twrWasmModule does not use SharedArrayBuffers. If you limit yourself to twrWasmModule you will not need to worry about configuring the CORS http headers on your web server.

    See this note on enabling CORS HTTP headers for SharedArrayBuffers.

    "},{"location":"api/api-typescript/#module-options","title":"Module Options","text":"

    The twrWasmModule and twrWasmModuleAsync constructor both take optional options.

    For example:

    let amod=new twrWasmModuleAsync();\n\nlet amod=new twrWasmModuleAsync({\n   stdio: new twrConsoleDebug();  // send stdio to debug console\n   });\n

    These are the options: twrWasmModule & twrWasmModuleAsync Options

    export interface IModOpts {\n   stdio?: IConsoleStream&IConsoleBase,\n   d2dcanvas?: IConsoleCanvas&IConsoleBase,\n   io?: {[key:string]: IConsole},\n}\n

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

    Set this to a Console class instance. If you leave it undefined, twrConsoleDebug will be used (or a tag shortcut, if set)

    This option is a shortcut to setting stdio using the io option.

    "},{"location":"api/api-typescript/#d2dcanvas-option","title":"d2dcanvas Option","text":"

    Set this to a twrConsoleCanvas instance to configure a 2D drawing surface. If you leave it undefined, a tag shortcut will be used.

    This option is a shortcut to setting std2d using the io option (note the different names).

    "},{"location":"api/api-typescript/#io-option-multiple-consoles-with-names","title":"io Option: Multiple Consoles with Names","text":"

    This option allows you to assign names to consoles. The C/C++ code can then retrieve a console by name.

    When using the io object to specify named consoles:

    • You can use the attribute stdio to set stdio.
    • You can use the attribute stderr to set stderr
    • You can use the attribute std2d to set the default 2D Drawing Surfaces -- used by twr-wasm 2D APIs.
    • all other attribute names are available for your consoles. Use this to access consoles in C/C++ beyond (or instead of) stdio, etc.

    Alternately, you can specify stdio and std2d directly as module attributes (outside of io) as a shortcut (see above).

    There is a twr-wasm C API to access named consoles: twr_get_console.

    This code snippet shows how to use the io option to pass in an object containing named console attributes:

    const stream1Element=document.getElementById(\"stream1\");\nconst stream2Element=document.getElementById(\"stream2\");\n\nconst debug = new twrConsoleDebug();\nconst stream1 = new twrConsoleDiv(stream1Element);\nconst stream2 = new twrConsoleDiv(stream2Element);\n\nstream1Element.addEventListener(\"keydown\",(ev)=>{stream1.keyDown(ev)});\nstream2Element.addEventListener(\"keydown\",(ev)=>{stream2.keyDown(ev)});\n\n// setting stdio and/or stderr to a debug console isn't necessary since that will be the default if stdio or stderr is not set.\n// but here to show how to set stdio and/or stderr.  They can be set to any console.\nconst amod = new twrWasmModuleAsync( {io:{stdio: debug, stderr: debug, stream1: stream1, stream2: stream2}} );\nconst mod = new twrWasmModule( {io:{stdio: debug, stderr: debug, stream1: stream1, stream2: stream2}} );\n

    In this case, as well as setting stdio and stderr, consoles named \"stream1\" and \"stream2\" are made available to the C/C++ code.

    Using a Named Console
    twr_ioconsole_t * stream1=twr_get_console(\"stream1\");\nfprintf(stream1, \"Hello Stream One!\\n\");\n

    A complete example multi-io is provided.

    "},{"location":"api/api-typescript/#deprecated-options","title":"Deprecated Options","text":"

    The following options are deprecated. Instead of these, use options available to twrConsoleDiv and twrConsoleTerminal constructors.

    deprecated
    export interface IModOpts {\n   windim?:[number, number],\n   forecolor?:string,\n   backcolor?:string,\n   fontsize?:number,\n}\n

    Note:

    • windim - if stdio is set to a twrConsoleTerminal, this will set the width and height, in characters. Instead, use constructor options on twrConsoleTerminal.
    • forecolor and backcolor - if stdio is set to twrConsoleDiv or twrConsoleTerminal, these can be set to a CSS color (like '#FFFFFF' or 'white') to change the default background and foreground colors. However, these are deprecated, and instead, use the twrConsoleDiv or twrConsoleTerminal constructor options.
    • fonsize - Changes the default fontsize if stdio is set to twrConsoleDiv or twrConsoleTerminal. Deprecated, instead use twrConsoleDiv or twrConsoleTerminal constructor options.
    • TStdioVals have been removed (they were a not too useful option in prior versions of twr-wasm)
    • divLog is deprecated. Instead use the putStr member function on most consoles.
    "},{"location":"api/api-typescript/#console-classes","title":"Console Classes","text":""},{"location":"api/api-typescript/#class-twrconsoledebug","title":"class twrConsoleDebug","text":"

    twrConsoleDebug streamings characters to the browser debug console.

    C type: IO_TYPE_CHARWRITE

    There are no constructor parameters.

    "},{"location":"api/api-typescript/#class-twrconsolediv","title":"class twrConsoleDiv","text":"

    twrConsoleDiv streams character input and output to a div tag .

    C type: IO_TYPE_CHARREAD and IO_TYPE_CHARWRITE

    The div tag will expand as you add more text (via printf, etc).

    You pass a <div> element to use to render the Console to to the twrConsoleDiv constructor. For example:

    <div id=\"div1\" tabindex=\"0\"></div>\n\n<script type=\"module\">\n   import {twrWasmModuleAsync, twrConsoleDiv} from \"twr-wasm\";\n\n   const stream1Element=document.getElementById(\"div1\");\n\n   // adding keyDown events is needed if the console will accept key input\n   // don't forget to set \"tabindex\" in your tag, otherwise it won't get key events\n   stream1Element.addEventListener(\"keydown\",(ev)=>{stream1.keyDown(ev)});\n\n   const stream1 = new twrConsoleDiv(stream1Element);\n   const mod = new twrWasmModuleAsync( {stdio: stream1} );\n   // mod.callC would go here...\n</script>\n

    There are constructor options to set the color and font size. You can also set these directly in the HTML for your <div> tag. If you wish to change the default font, set the font in the div tag with the normal HTML tag options.

    twrConsoleDiv constructor options
    constructor(element:HTMLDivElement,  params:IConsoleDivParams)\n\nexport interface IConsoleDivParams {\n   foreColor?: string,\n   backColor?: string,\n   fontSize?: number,\n}\n
    "},{"location":"api/api-typescript/#class-twrconsoleterminal","title":"class twrConsoleTerminal","text":"

    twrConsoleTerminal provides streaming and addressable character input and output. A <canvas> tag is used to render into.

    C types: IO_TYPE_CHARREAD, IO_TYPE_CHARWRITE, IO_TYPE_ADDRESSABLE_DISPLAY

    twrConsoleTerminal is a simple windowed terminal and supports the same streamed output and input features as a does twrConsoleDiv, 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).

    The canvas width and height, in pixels, will be set based on your selected font size and the width and height (in characters) of the terminal. These are passed as constructor options when you instantiate the twrConsoleTerminal.

    You can use the putStr member function on most consoles to print a string to the terminal in JavaScript.

    As you add more text (via printf, etc), the twrConsoleTerminal will scroll if it becomes full (unlike twrConsoleDiv, which expands)

    A list of C functions that operate on twrConsoleTerminal are available.

    Here is an example:

    <body>\n\n   <canvas id=\"canvas1forterm\" tabindex=\"0\"></canvas>\n\n   <script type=\"module\">\n      import {twrWasmModuleAsync, twrConsoleTerminal} from \"twr-wasm\";\n\n      // find the HTML elements that we will use for our console to render into\n      const term1Element=document.getElementById(\"canvas1forterm\");\n\n      // adding keyDown events is needed if the console will accept key input\n      // don't forget to set \"tabindex\" in your tag, otherwise it won't get key events\n      term1Element.addEventListener(\"keydown\",(ev)=>{term1.keyDown(ev)});\n\n      // create the console\n      const term1 = new twrConsoleTerminal(term1Element, {widthInChars: 50, heightInChars: 20});\n\n      const amod = new twrWasmModuleAsync( \n         {io:{\n            stdio: debug, stderr: debug, stream1: stream1, stream2: stream2, term1: term1, term2: term2, draw1: draw1, draw2: draw2\n         }} );\n\n      // set the input focus so user doesn't have to click\n      stream1Element.focus();\n\n      // load the wasm code and call the multi C function\n      await amod.loadWasm(\"./multi-io.wasm\");\n      await amod.callC([\"multi\"]);\n\n      // example of using a console in in JavaScript\n      stream1.putStr(`Hello stream1 of type ${stream1.getProp(\"type\")} from JavaScript!\\n`);\n\n   </script>\n</body>\n

    twrConsoleTerminal constructor options
    constructor (canvasElement:HTMLCanvasElement, params:IConsoleTerminalParams)\n\n// see twrConsoleDiv options elsewhere, which are also supported\nexport interface IConsoleTerminalParams extends IConsoleDivParams {\n   widthInChars?: number,\n   heightInChars?: number,\n}\n
    "},{"location":"api/api-typescript/#class-twrconsolecanvas","title":"class twrConsoleCanvas","text":"

    twrConsoleCanvas creates a 2D drawing surface that the Canvas compatible 2d drawing APIs can be used with.

    C type: IO_TYPE_CANVAS2D.

    constructor(element:HTMLCanvasElement)\n
    twrConsoleCanvas Example
    <body>\n   canvas id=\"canvas1for2d\"></canvas>\n\n   <script type=\"module\">\n      import {twrWasmModule, twrConsoleCanvas} from \"twr-wasm\";\n\n      // find the HTML elements that we will \n      // use for our console to render into\n      const draw1Element=document.getElementById(\"canvas1for2d\");\n\n      // create the console\n      const draw1 = new twrConsoleCanvas(draw1Element);\n\n      const mod = new twrWasmModule( {io: {std2d: draw1}  }} );\n\n      // callC here...\n   </script>\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.

    • View bouncing balls
    • Source for balls

    The bouncing balls example demonstrates

    • C++
    • Using the twr-wasm draw 2D APIs that match Javascript Canvas APIs.
    • Using the twr-wasm canvas.cpp wrapper class.

    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++.

    • View callC example running live
    • View callC example source
    "},{"location":"examples/examples-divcon/","title":"divcon - Printf and Input Using a div Tag","text":"

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

    • view divcon example running live
    • View divcon source code
    "},{"location":"examples/examples-divcon/#screen-grab-of-square-calculator","title":"Screen Grab of Square Calculator","text":""},{"location":"examples/examples-divcon/#c-code","title":"C Code","text":"divcon.c
    #include <stdio.h>\n#include <stdlib.h>\n#include \"twr-crt.h\"\n\nvoid stdio_div() {\n    char inbuf[64];\n    char *r;\n    int i;\n\n    printf(\"Square Calculator\\n\");\n\n    while (1) {\n        printf(\"Enter an integer: \");\n        r=twr_mbgets(inbuf);  // r is NULL if esc entered.  Otherwise r == inbuf\n        if (r) {  \n            i=atoi(inbuf);\n            printf(\"%d squared is %d\\n\\n\",i,i*i);\n        }\n        else {\n            printf(\"\\n\");\n        }\n    }\n}\n
    "},{"location":"examples/examples-divcon/#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
    <body>\n   <div id=\"stdioDiv\" \n        tabindex=\"0\" \n        style=\"color: DarkGreen; background-color: LightGray; font-size: 18px;font-family: Arial, sans-serif;\" >\n        Loading... <br>\n   </div>\n\n   <script type=\"module\">\n      import {twrWasmModuleAsync, twrConsoleDiv} from \"twr-wasm\";\n\n      const con = new twrConsoleDiv(document.getElementById(\"stdioDiv\"));\n      const amod = new twrWasmModuleAsync({stdio: con});\n\n      // remove 'Loading...'\n      document.getElementById(\"stdioDiv\").innerHTML =\"<br>\"; \n      // send key events to twrConsoleDiv\n      document.getElementById(\"stdioDiv\").addEventListener(\"keydown\",(ev)=>{con.keyDown(ev)});\n\n      await amod.loadWasm(\"./divcon.wasm\");\n      await amod.callC([\"stdio_div\"]);\n\n   </script>\n</body>\n
    "},{"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.

    • View example running on the web
    • View example source code
    "},{"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 a 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.

    • View helloworld example running live
    • View helloworld source code
    "},{"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.

    • view tests-libcxx example running live
    • View tests-libcxx source code

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

    • tests-user Live
    • tests-user Source
    "},{"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.

    • View live maze here
    • Source for maze
    "},{"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-multi-io/","title":"Multi-io -Multiple Console Example","text":""},{"location":"examples/examples-multi-io/#what-it-does","title":"What It Does","text":"

    This example demos six simultaneous consoles:

    • Two character streaming consoles directed to a <div> tag
    • Two character terminal consoles directed to a <canvas> tag
    • Two 2D draw surface consoles directed to a <canvas> tag

    The multi-io example also demos:

    • Creating consoles in JavaScript/TypeScript
    • Using consoles in C/C++ and JavaScript/TypeScript
    • Mixing multiple Consoles
    • Using multiple .wasm modules using the same console
    • Inputting, printing, and drawing to consoles
    "},{"location":"examples/examples-multi-io/#running-examples-and-source","title":"Running Examples and Source:","text":"
    • View multi-io
    • Source for multi-io

    Also see Console Introduction

    "},{"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":"
    • Click here to view C/C++ WebAssembly twr-wasm examples running live
    • Click here to view source code and make files
    "},{"location":"examples/examples-overview/#hello-world","title":"Hello World","text":"Name Description Link helloworld A very simple C Wasm example to get you started helloworld"},{"location":"examples/examples-overview/#console-examples","title":"Console Examples","text":"Name Description Link divcon This simple C program demos inputting andprinting characters to a div tag divcon terminal This simple C program demos writing and inputtingfrom a <canvas> tag that twr-wasm configuresas a windowed \"terminal\" terminal multi-io Demo 6 simultaneous consoles: stream i/o, terminal, 2D Drawing multi-io"},{"location":"examples/examples-overview/#draw-2d-examples","title":"Draw 2D Examples","text":"Name Description Link 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"},{"location":"examples/examples-overview/#call-argument-examples","title":"Call Argument Examples","text":"Name Description Link callC A demo of passing and returning values betweenJavaScript and Wasm module callc fft A demo of calling a C library to perform an FFTthat is graphed in TypeScript fft"},{"location":"examples/examples-overview/#unit-tests","title":"Unit Tests","text":"Name Description Link 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/#running-or-building-the-examples-locally","title":"Running or Building the examples locally","text":"

    Online versions of the examples can be viewed here.

    You can also run the examples locally, or build them..

    "},{"location":"examples/examples-overview/#copying-examples-to-start-your-own-project","title":"Copying Examples to Start your own Project","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.

    Also see the section on Import Resolution if you installed with git clone.

    "},{"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.

    • View Pong
    • Source for Pong

    The Pong example demonstrates

    • C++
    • Using twr-wasm draw 2D APIs that match Javascript Canvas APIs.
    • Using the twr-wasm canvas.cpp class.
    • Taking in Javascript events as user input

    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-terminal/","title":"Terminal Console Demo","text":"

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

    "},{"location":"examples/examples-terminal/#what-it-does","title":"What it Does","text":"
    • uses class twrConsoleTerminal, a Console
    • moves a string up or down in the terminal window when you press the u or d or arrow keys.
    • shows basic color usage
    • draws a graphic box around the terminal window.
    "},{"location":"examples/examples-terminal/#run-and-view-the-code","title":"Run and View the Code","text":"
    • View terminal example running live
    • View terminal source code
    • For another 'terminal' demo View tests-user
    "},{"location":"examples/examples-terminal/#screen-grab-of-terminal","title":"Screen Grab of Terminal","text":""},{"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:

    • If you're C/C++ code does not have any direct user interface built in, it can do its calculations and return. The FFT is an example of this.
    • If your C/C++ code uses a classic C \"UI\", where it gets keys from stdin and sends the results to stdout, you can direct stdin and stdout to a <div> or <canvas> tag. This is explained in the stdio section.
    • Your C/C++ code could be sent events from JavaScript (such mouse, key, timer, or other). This is done by simply calling a C function with the events as arguments. The C/C++ code could then generate no output, could render to a <div> or <canvas> using stdio type C/C++ functions, or it could render to a <canvas> using 2D drawing APIs that correspond to JavaScript canvas 2D draw operations. (Balls) is an example.
    "},{"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 characters. 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:

    • Configure your text editor to save in Windows-1252/ISO-8859-1 format (instead of UTF-8)
    • use compiler flags like --finput-charset and -fexec-charset

    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 describes 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:

    • llvmPackages_18.clang-unwrapped (clang 18.1.7)
    • llvmPackages_17.clang-unwrapped (clang 17.0.6)
    "},{"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:

    • ../../include is a relative link to include that works if your project is a sub folder in the examples folder.
    • ./node_modules/twr-wasm/include assumes you installed with npm into your project folder. (see the Hello World Walk Through).
    "},{"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(twr_ioconsole_t* 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)
    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.
    7. 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 these CORS notes.
    8. your code can be bundled or unbundled, but
    9. you need to ensure that the web server/browser can find the source code
    10. also see Example Readme
    "},{"location":"gettingstarted/debugging/#resolving-imports","title":"Resolving Imports","text":"

    If you are having issues with import resolution, see this section.

    "},{"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

    Inside JavaScript, you can print to a console using the putStr console member function that is available on all consoles.

    For example:

    const stream1 = new twrConsoleDiv(stream1Element);\nstream1.putStr(`Hello stream1 of type ${stream1.getProp(\"type\")} from JavaScript!\\n`);\n

    "},{"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:

    • Create the helloworld.c file
    • Create the index.html file
    • Compile the helloworld.c code with clang
    • Link the helloworld.o and twr.a files with wasm-ld to create a helloworld.wasm file
    • Set the needed library and include paths to allow the twr-wasm libraries to be discovered
    • Create an optional Makefile
    • Execute the \"hello world\" program using a local web server or directly with VS Code and Chrome

    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":"
    • prerequisites: install clang, wasm-ld, and python or VS Code (or both)
    • Create a folder for your project, such as hello-proj
    • cd into hello-proj
    • npm install twr-wasm
    • your folder structure should now look similar to this:
      hello-proj\\\n\u251c\u2500\u2500package.json\n\u2514\u2500\u2500node_modules\\\n   \u2514\u2500\u2500twr-wasm\\\n      \u251c\u2500\u2500examples\\\n      \u2514\u2500\u2500include\\\n      \u2514\u2500\u2500lib-c\\\n      \u2514\u2500\u2500lib-js\\\n      \u2514\u2500\u2500LICENSE\n      \u2514\u2500\u2500package.json\n      \u2514\u2500\u2500readme.md\n
    "},{"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.

    For more detail on import resolution see this section.

    "},{"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.

    • Copy the file server.py from the examples folder to your hello-proj folder (where your index.html resides).
    • Execute with the shell command python server.py.
    • Open your web browser and browse to http://localhost:8000/index.html
    • You should see 'Hello World' in the browser window!

    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:

    • select the Run and Debug icon on left
    • Select the green play icon at the top, with \"Launch Chrome Hello, World!\" selected
    • Chrome should launch, and you should see 'Hello World' in the browser window!

    --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:

    • npm install will install everything necessary to build your software: built libraries (lib-js, lib-c) and includes. In addition the examples are installed.
    • git clone will copy the above as well as the source and VS Code settings.

    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.

    For more details see this section on Import Resolution

    "},{"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-and-more","title":"python and more","text":"

    To use the included examples\\server.py to execute your project 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 Hello World walk through, you can alternately execute HTML files directly using VS Code and Chrome.

    You will likely want these tools installed to use twr-wasm:

    • gnu make (all the examples use make)
    • VS Code (not required, but the repo includes VS Code launch.json, etc)
    • TypeScript (not required, but the twr-wasm source code is TypeScript)
    "},{"location":"gettingstarted/installation/#note-on-examples","title":"Note on Examples","text":"

    You can run the examples either locally or with the online versions.

    "},{"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:

    • Integer 32 or 64 bit
    • Floating point 32 or 64 bit

    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:

    • Integer 32: JavaScript number type is converted to an Integer 32 and passed to C when the C function prototype specifies a signed or unsigned int, long, int32_t, or a pointer type. All of these are 32 bits in length in wasm32.
    • Integer 64: JavaScript bigint type is converted to an Integer 64 and passed to C when the C function prototype specifies signed or unsigned int64_t (or equivalent). Attempting to pass a JavaScript number to a C int64_t will fail with a JavaScript runtime error.
    • Float 32: JavaScript number type is converted to a Float 32 when the C function prototype specifies a float.
    • Float 64: JavaScript number type is passed as a Float 64 when the C function prototype specifies a double.

    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 pass 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
    • The first entry, int a, will be at offset 0 in memory (from the start of the struct in memory).
    • The second entry, char b, will be at offset 4 in memory. This is expected since the length of an int is 4 bytes.
    • The third entry, int *c, will be at offset 8 in memory, not at offset 5 as you might expect. The compiler adds three bytes of padding to align the pointer to a 4-byte boundary.

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

    • char is 1 byte aligned
    • short is 2 byte aligned
    • pointers are 4 byte aligned
    • int, long, int32_t are 4 byte aligned
    • double (Float 64) is 8-byte aligned

    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:

    • await mod.malloc(structSize) is a shortcut for: await mod.callC([\"malloc\", structSize])
    • mod.malloc returns a C pointer as a number. This pointer is also an index into WebAssembly.Memory -- which is exposed as the byte array (Uint8Array) via mod.mem8 by twr-wasm.
    • When accessing a C struct in JavaScript/TypeScript, you have to do a bit of arithmetic to find the correct structure entry.
    • The entry int *c is a pointer to an int. So a separate malloc to hold the int is needed.
    • In twr-wasm there is no function like setLong to set a byte. Instead you access the byte array view of the WebAssembly memory with mod.mem8. Functions like mod.setLong manipulate this byte array for you.
    • As well as mod.mem8 (Uint8Array), you can also access WebAssembly.Memory directly via mod.mem32 (Uint32Array), and mod.memD (Float64Array).
    • The list of functions available to access WebAssembly.Memory can be found at the end of this page.
    "},{"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:

    • Allocate memory for the string inside the WebAssembly memory. This is typically done by calling the C malloc from JavaScript. malloc returns a pointer, which is an index into the WebAssembly Memory.
    • Copy the JavaScript string to this malloc'd Wasm memory. In the case of twr-wasm, this copying also converts the character encoding as necessary, for example, to UTF-8.
    • Pass the malloc'd memory index to your function as an integer (which is accepted as a pointer by C code).

    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:

    • ArrayBuffers have entries of all the same length, so the index math is straight forward and now struct padding is needed.
    • When an ArrayBuffer is passed to a function, the function receives a pointer to the malloc memory. If the length is not known by the function, the length needs to be passed as a separate argument.
    • Before callC returns, any modifications made to the memory by the C code are reflected back into the ArrayBuffer.
    • the malloced copy of the ArrayBuffer is freed.

    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":"Consoles with C/C++ WebAssemblystdio, stderr, and more","text":"

    This section describes how to use twr-wasm in order to:

    • create input/output consoles for use by C/C++
    • direct stdin/stdout and stderr to a console
    • use addressable display and canvas 2D consoles
    • use multiple consoles at once
    "},{"location":"gettingstarted/stdio/#quick-example","title":"Quick Example","text":"Hello World
    #include <stdio.h>\n\nvoid hello() {\n    printf(\"hello world\\n\");\n}\n
    Using twrConsoleDiv
    <body>\n   <div id=\"console-tag\"></div>\n\n   <script type=\"module\">\n      import {twrConsoleDiv, twrWasmModule} from \"twr-wasm\";\n\n      const tag=document.getElementById(\"console-tag\");\n      const streamConsole=new twrConsoleDiv(tag); \n      const mod = new twrWasmModule({stdio: streamConsole});\n      await mod.loadWasm(\"./helloworld.wasm\");\n      await mod.callC([\"hello\"]);\n\n   </script>\n</body>\n
    Using twr_iodiv Shortcut
    <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\n   </script>\n</body>\n
    "},{"location":"gettingstarted/stdio/#running-examples","title":"Running 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 Multiple Consoles, including Canvas2D View multi-io demo Source"},{"location":"gettingstarted/stdio/#capabilities","title":"Capabilities","text":"

    With a Console you can:

    • read character streams (Use C statements like getc or io_mbgets)
    • write character streams (use C statements like printf or cout)
    • position characters, graphics, colors with an addressable display (Use C statements like io_setc32 or io_set_cursor).
    • draw to a Canvas compatible 2D surface (Use C statements like d2d_fillrect).

    Consoles are primarily designed for use by twr-wasm C/C++ modules, but they can also be used by JavaScript/TypeScript.

    Although it is common to have a single console, an arbitrary number of consoles can be created, and they can be used by an arbitrary number of twr-wasm C/C++ modules.

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

    "},{"location":"gettingstarted/stdio/#tag-shortcuts","title":"Tag Shortcuts","text":"

    If you add a <div id=\"twr_iodiv\">, a <canvas id=\"twr_iocanvas\">, or a <canvas id=\"twr_d2dcanvas\"> tag to your HTML, twr-wasm will create the appropriate class for you when you instantiate the class twrWasmModule or twrWasmModuleAsync. Use these tag shortcuts as an aternative to instantiating the console classes in your JavaScript/TypeScript.

    • <div id=\"twr_iodiv\"> will be used to create a twrConsoleDiv as stdio
    • <canvas id=\"twr_iocanvas\"> will be used to create a twrConsoleTerminal as stdio.
    • <canvas id=\"twr_d2dcanvas\"> will be used to create a twrConsoleCanvas as std2d -- the default 2D drawing surface. See 2D drawing APIs.

    If neither of the above <div> or <canvas> is defined in your HTML, and if you have not set stdio via the io or stdio module options, then stdout is sent to the debug console in your browser. And stdin is not available.

    "},{"location":"gettingstarted/stdio/#console-classes","title":"Console Classes","text":"

    Consoles are implemented in TypeScript and run in the JavaScript main thread. This allows consoles to be shared by multiple wasm modules.

    For simple cases, when you use the tag shortcuts, you won't need to use these console classes directly. For more bespoke cases, they will come in handy. For details on console classes, see the TypeScript/JavaScript API reference

    These conosle classes are available in twr-wasm:

    • twrConsoleDiv streams character input and output to a div tag
    • twrConsoleTerminal provides streaming or addressable character input and output using a canvas tag.
    • twrConsoleDebug streamings characters to the browser debug console.
    • twrConsoleCanvas creates a 2D drawing surface that the Canvas compatible 2d drawing APIs can be used with.
    "},{"location":"gettingstarted/stdio/#multiple-consoles-with-names","title":"Multiple Consoles with Names","text":"

    When you instantiate a class twrWasmModule or twrWasmModuleAsync, you can pass it the module option io -- a javascript object containing name-console attributes. Your C/C++ code can then retrieve a console by name. This is described in more detail the TypeScript/JavaScript API Reference.

    Also see the multi-io example.

    "},{"location":"gettingstarted/stdio/#setting-stdio-and-stderr","title":"Setting stdio and stderr","text":"

    stdio can be defined automatically if you use a Tag Shortcut. stderr streams to the browser's debug console by default. Both can be set to a specific console with the module io option.

    For example, either of these will set stdio to a streaming div console:

    const tag=document.getElementById(\"console-tag\");\nconst streamConsole=new twrConsoleDiv(tag);\n\nconst mod = new twrWasmModule({stdio: streamConsole});\nconst mod = new twrWasmModule({ io: {stdio: streamConsole} });\n

    This option would send stderr and stdio to the same console:

    const mod = new twrWasmModule({ io: \n   {stdio: streamConsole, stderr: streamConsole} \n});\n
    "},{"location":"gettingstarted/stdio/#utf-8-or-windows-1252","title":"UTF-8 or Windows-1252","text":"

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

    "},{"location":"gettingstarted/stdio/#c-access-to-consoles","title":"C Access To Consoles","text":""},{"location":"gettingstarted/stdio/#io_functions","title":"io_functions","text":"

    io_functions are available to operate on all character based Consoles.

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

    d2d_functions are available to operate on Canvas 2D Consoles.

    "},{"location":"gettingstarted/stdio/#reading-from-a-console","title":"Reading from a Console","text":"

    Reading from a console is blocking, and so twrWasmModuleAsync must be used to receive keys. There are some specific requirements to note in the twrWasmModuleAsync API docs.

    You can get characters with any of these functions:

    • io_mbgets - get a multibyte string from a console using the current locale character encoding. Console must support IO_TYPE_CHARREAD.
    • twr_mbgets - the same as io_mbgets with the console set to stdin.
    • io_mbgetc - get a multibyte character from an twr_ioconsole_t * (aka FILE *) like stdin using the current locale character encoding
    • getc (same as fgetc) - get a single byte from a FILE * (aka twr_ioconsole_t *) -- returning ASCII or extended ASCII (window-1252 encoding)
    • io_getc32 - gets a 32 bit unicode code point from an twr_ioconsole_t * (which must support IO_TYPE_CHARREAD)
    "},{"location":"gettingstarted/stdio/#standard-c-library-functions","title":"Standard C Library Functions","text":"

    Many of the common standard C library functions, plus twr-wasm specific functions, are available to stream characters to and from the standard input and output console that supports character streaming (most do).

    In C, a console is represented by twr_ioconsole_t. In addition, FILE is the same as a twr_ioconsole_t (typedef twr_ioconsole_t FILE). stdout, stdin, stderr are all consoles.

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

    FILE is supported for user input and output, and for stderr. FILE as filesystem I/O 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

    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":"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 ():

    • TypeScript (5.4.5)
    • clang tool chain (17.0.6) - for C/C++ code
    • wasm-ld (17.0.6) - to link the .wasm files
    • wat2wasm (1.0.34) - to compile WebAssembly (.wat) files of which I have a few
    • GNU make (4.4.1)
    • git - to clone twr-wasm source, or to clone llvm, if you want to build libc++

    In addition, you might need:

    • VS Code - to use the debug launcher and build tasks
    • NPM - package manager
    • Parcel v2 - to bundle the examples
    • mkdocs, material theme, meta-descriptions plugin - to build the documentation static web site
    • python - mkdocs is built with python, and you need python to run server.py in examples
    • CMake and ninja - to build llvm libc++

    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/imports/","title":"twr-wasm Import Resolution","text":"

    This section covers path resolution for statements like this:

    import {twrWasmModule} from \"twr-wasm\";\n

    It can be confusing to determine how tools like VS Code, a bundler, or a Web Browser resolve imports like \"twr-wasm\". This section explains how it works, using the included examples as examples.

    If you have installed twr-wasm using npm, most tools will automatically resolve imports by finding the node_modules folder.

    However, if you installed using git clone, then other steps will need to be taken. The examples are in the git repo tree, and as a result there may be no node_modules for the twr-wasm libraries. This will also be the case for your project, if you installed with git clone.

    "},{"location":"more/imports/#import-path-resolution-by-the-bundler","title":"Import path resolution by the bundler","text":"

    A bundler will find the twr-wasm library using one of these methods:

    1. If twr-wasm has been installed with npm install, the bundler will find the node_modules folder
    2. Alternately, If all your scripts are in TypeScript, use paths entry in tsconfig.json (see maze example)
    3. Alternately, use alias option in package.json as in the helloworld example
           \"alias\": {\n          \"twr-wasm\": \"../../lib-js/index.js\"\n     },\n

    In the examples, the alias entry in the package.json exists so that the parcel bundler can find twr-wasm.

    If you are using a bundler, you don't need to add a <script type=\"importmap\"> tag.

    "},{"location":"more/imports/#import-path-resolution-by-the-browser","title":"Import path resolution by the browser","text":"

    This section apples to executing your javascript without first \"bundling\" it. Whether execution is from the filesystem directly in a browser or using a web server.

    In order for the browser to locate the twr-wasm path when import is used, you can add code like this to your HTML prior to the import. You should make sure the path for twr-wasm is correct for your project (this is correct for the examples).

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

    "},{"location":"more/imports/#import-resolution-by-vs-code-and-tsc","title":"Import resolution by VS Code and tsc","text":"

    VS Code Intellisense and the typescript compiler need to find modules. If twr-wasm is installed using npm into a node_modules folder, this is probably automatic. But if this is not the case, you can add a line to the tsconfig.json as follows (this example assumes the tsconfig.json is in a examples/example folder). See the maze example.

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

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

    If you are using twr-wasm with web pages served by an http server, you may need to enable certain CORS headers. This applies whether using a remote server or using your local machine for development.

    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. It may be helpful to also see the SharedArrayBuffer documentation online.

    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.

    Here are two provided examples of how to enable the necessary headers:

    • server.py
    • staticwebapp.config.json

    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":"more/production/#using-twrwasmmoduleasync-with-file","title":"Using twrWasmModuleAsync with file:","text":"

    If you are loading html with chrome from files (not using an https server), you will need to set these command line args:

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

    More detail is found in the debugging section.

    "},{"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 terminal emulator, character encoding support, and more.

    "}]} \ No newline at end of file diff --git a/azure/docsite/sitemap.xml b/azure/docsite/sitemap.xml index 589216b8..2b0f61b7 100644 --- a/azure/docsite/sitemap.xml +++ b/azure/docsite/sitemap.xml @@ -140,6 +140,11 @@ 2024-08-11 daily + + https://twiddlingbits.dev/docsite/more/imports/ + 2024-08-11 + daily + https://twiddlingbits.dev/docsite/more/production/ 2024-08-11 diff --git a/azure/docsite/sitemap.xml.gz b/azure/docsite/sitemap.xml.gz index cbee74b3..30d25208 100644 Binary files a/azure/docsite/sitemap.xml.gz and b/azure/docsite/sitemap.xml.gz differ