├── support ├── cross │ ├── __WASM__.py │ ├── aio │ │ ├── atexit.py │ │ ├── recycle.py │ │ ├── prepro.py │ │ ├── clock.py │ │ ├── toplevel.py │ │ ├── trace.py │ │ ├── filelike.py │ │ ├── cross.py │ │ ├── gthread.py │ │ └── simulator.py │ └── __EMSCRIPTEN__.py ├── sim.links │ └── put_modules_simlinks_here ├── __EMSCRIPTEN__.overlay │ ├── pymunk.py │ └── pygame │ │ ├── freesansbold.ttf │ │ ├── _sdl2 │ │ └── __init__.py │ │ └── wasm_patches.py ├── __EMSCRIPTEN__.tests │ ├── xxlimited.cpython-311-wasm32-emscripten.so │ ├── _ctypes_test.cpython-311-wasm32-emscripten.so │ ├── xxlimited_35.cpython-311-wasm32-emscripten.so │ ├── _testmultiphase.cpython-311-wasm32-emscripten.so │ └── _testimportmultiple.cpython-311-wasm32-emscripten.so ├── __EMSCRIPTEN__.py ├── xterm ├── __EMSCRIPTEN__.deps │ ├── ncurses-6.1_emscripten.patch │ ├── ncurses-6.1_emscripten_make.patch │ └── ncurses-6.1_emscripten_makew.patch ├── server.py ├── __EMSCRIPTEN__.patches │ ├── 3.10-host.diff │ ├── 3.11 │ │ ├── asyncio │ │ │ └── __init__.py │ │ └── hashlib.py │ └── 3.10 │ │ └── asyncio │ │ └── __init__.py ├── __EMSCRIPTEN__.yml ├── __EMSCRIPTEN__.embed │ ├── cpython.diff │ └── sysmodule.c ├── __EMSCRIPTEN__-pymain.c └── __EMSCRIPTEN__.sh ├── .github ├── FUNDING.yml └── workflows │ └── ci.yml ├── demos ├── 0-pong │ ├── font.ttf │ ├── favicon.ico │ ├── README.md │ ├── package.toml │ └── 1001fonts-morris-roman-eula.txt ├── org.python3.11.0 │ ├── static │ │ ├── org.python3.11.0.html │ │ └── index.html │ └── cpython.six └── 1-touchpong │ └── package.toml ├── templates ├── no-worker │ ├── main │ ├── org.python.html │ ├── favicon.ico │ ├── pythons.html │ ├── pygame.html │ └── python311.html └── libs │ └── xterm │ ├── styles.css │ ├── xtermjsixel │ ├── style.css │ └── xterm.css │ └── vtx.js ├── scripts ├── cpython-build-host-deps.sh ├── cpython-build-emsdk-prebuilt.sh ├── re-pack-apk.sh ├── pygame-all.sh ├── cpython-fetch.sh ├── make_coldstartfs.sh ├── cpython-build-host.sh ├── cpython-build-host-prebuilt.sh ├── emsdk-fetch.sh ├── cpython-build-emsdk-deps.sh └── cpython-build-emsdk.sh ├── .gitignore ├── LICENSE ├── python-wasm-plus.sh ├── python-wasm-sim.sh ├── config ├── README.md └── tests ├── assets └── cpython.six └── code ├── testjoy.py └── touchpong.py /support/cross/__WASM__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /support/sim.links/put_modules_simlinks_here: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | open_collective: pythonseverywhere 2 | 3 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.overlay/pymunk.py: -------------------------------------------------------------------------------- 1 | from pymunk4 import * 2 | -------------------------------------------------------------------------------- /demos/0-pong/font.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/demos/0-pong/font.ttf -------------------------------------------------------------------------------- /templates/no-worker/main: -------------------------------------------------------------------------------- 1 | templates/libs/emsdk 2 | templates/libs/xterm 3 | templates/libs/browserfs 4 | -------------------------------------------------------------------------------- /demos/0-pong/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/demos/0-pong/favicon.ico -------------------------------------------------------------------------------- /templates/no-worker/org.python.html: -------------------------------------------------------------------------------- 1 | 2 | TODO: History of CPython on asm.js/wasm 3 |
4 | 5 | 6 | -------------------------------------------------------------------------------- /templates/no-worker/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/templates/no-worker/favicon.ico -------------------------------------------------------------------------------- /demos/0-pong/README.md: -------------------------------------------------------------------------------- 1 | # Pong 2 | A pong game made with pygame. 3 | 4 | ## Todo 5 | * Add multiplayer 6 | * Add highscore using mysql 7 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.overlay/pygame/freesansbold.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/support/__EMSCRIPTEN__.overlay/pygame/freesansbold.ttf -------------------------------------------------------------------------------- /demos/org.python3.11.0/static/org.python3.11.0.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |         Github: Not a git repo
4 |         
5 | 6 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.tests/xxlimited.cpython-311-wasm32-emscripten.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/support/__EMSCRIPTEN__.tests/xxlimited.cpython-311-wasm32-emscripten.so -------------------------------------------------------------------------------- /scripts/cpython-build-host-deps.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ${CONFIG:-config} 4 | 5 | echo " 6 | * cpython-build-host-prebuilt pip==$PIP * 7 | " 1>&2 8 | 9 | 10 | # use system packages. 11 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.tests/_ctypes_test.cpython-311-wasm32-emscripten.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/support/__EMSCRIPTEN__.tests/_ctypes_test.cpython-311-wasm32-emscripten.so -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.tests/xxlimited_35.cpython-311-wasm32-emscripten.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/support/__EMSCRIPTEN__.tests/xxlimited_35.cpython-311-wasm32-emscripten.so -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.tests/_testmultiphase.cpython-311-wasm32-emscripten.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/support/__EMSCRIPTEN__.tests/_testmultiphase.cpython-311-wasm32-emscripten.so -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.tests/_testimportmultiple.cpython-311-wasm32-emscripten.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pmp-p/python-wasm-plus/HEAD/support/__EMSCRIPTEN__.tests/_testimportmultiple.cpython-311-wasm32-emscripten.so -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /keystore 2 | /devices 3 | /src 4 | /build 5 | /emsdk/ 6 | /wasm32-tot-emscripten-shell.sh 7 | /python-wasm-plus.epj 8 | /.eric6project 9 | /demos 10 | /tests/code 11 | /support/sim.links 12 | /scratchbook/ 13 | ATTIC 14 | -------------------------------------------------------------------------------- /demos/0-pong/package.toml: -------------------------------------------------------------------------------- 1 | # https://toml.io/en/ 2 | 3 | 4 | # a section for Mys 5 | [package] 6 | name = "Pong" 7 | version = "0.1" 8 | authors = ["CAPTAIN"] 9 | description = "a Pong game" 10 | 11 | 12 | # packing instruction for vfs 13 | [fs] 14 | memfs = [ "main.py", "font.ttf", ] 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demos/1-touchpong/package.toml: -------------------------------------------------------------------------------- 1 | # https://toml.io/en/ 2 | 3 | 4 | # a section for Mys 5 | [package] 6 | name = "touchpong" 7 | version = "0.1" 8 | authors = ["blubberquark"] 9 | description = "Pong game with Multitouch" 10 | 11 | 12 | # packing instruction for vfs 13 | [fs] 14 | memfs = [ "main.py", ] 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.overlay/pygame/_sdl2/__init__.py: -------------------------------------------------------------------------------- 1 | import sys 2 | 3 | if not sys.platform in ("wasi", "emscripten"): 4 | from .sdl2 import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] 5 | from .audio import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] 6 | from .video import * # pylint: disable=wildcard-import; lgtm[py/polluting-import] 7 | -------------------------------------------------------------------------------- /templates/libs/xterm/styles.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | max-width: 800px; 4 | margin: 0 auto 5 | } 6 | 7 | #code { 8 | width: 100%; 9 | height: 180px; 10 | } 11 | 12 | .button-container { 13 | display: flex; 14 | justify-content: end; 15 | height: 50px; 16 | align-items: center; 17 | gap: 10px; 18 | } 19 | 20 | button { 21 | padding: 6px 18px; 22 | 23 | } 24 | -------------------------------------------------------------------------------- /support/cross/aio/atexit.py: -------------------------------------------------------------------------------- 1 | plan = [] 2 | 3 | def register(func, *args, **kwargs): 4 | global plan 5 | plan.append( (func,arg,kwargs,) ) 6 | 7 | def unregister(func): 8 | global plan 9 | todel = [] 10 | for i,elem in enumerate(plan) 11 | if elem[0] is func: 12 | todel.append(i) 13 | 14 | while len(todel): 15 | plan.pop( todel.pop() ) 16 | 17 | 18 | def exiting(): 19 | while len(plan): 20 | 21 | 22 | # replace stock one 23 | import sys 24 | sys.modules['atexit'] = sys.modules['aio.atexit'] 25 | -------------------------------------------------------------------------------- /demos/org.python3.11.0/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | Run CPython 3.11 test suite on browser (runtime at least 20 Minutes) 3 |
 4 | do not switch tab for testsuite, keep it in a exposed window or it will pause
 5 | 
 6 | Meanwhile enjoy casual gaming in another window with :
7 | 8 |
9 | Pygame demos 10 | 11 | Please report issues here:
12 | https://github.com/pmp-p/python-wasm-plus/issues 13 | 14 | -------------------------------------------------------------------------------- /scripts/cpython-build-emsdk-prebuilt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ${CONFIG:-config} 4 | 5 | PIP="$(realpath python3-wasm) -m pip" 6 | 7 | echo " 8 | * cpython-build-emsdk-prebuilt pip==$PIP * 9 | " 1>&2 10 | 11 | 12 | for pkg in installer 13 | do 14 | if [ -d prebuilt/emsdk/${PYBUILD}/site-packages/$pkg ] 15 | then 16 | echo " 17 | $pkg already set to prebuilt 18 | " 19 | else 20 | $PIP install $pkg 21 | mv $PREFIX/lib/python${PYBUILD}/site-packages/${pkg} prebuilt/emsdk/${PYBUILD}/site-packages/ 22 | mv $PREFIX/lib/python${PYBUILD}/site-packages/${pkg}-* prebuilt/emsdk/${PYBUILD}/site-packages/ 23 | fi 24 | done 25 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.py: -------------------------------------------------------------------------------- 1 | # python startup for python3-wasm 2 | import sys,os 3 | 4 | # for emcc to build wasm shared lib 5 | os.environ['EMCC_CFLAGS']='-s SIDE_MODULE=1' 6 | 7 | ARCH=os.popen('arch').read().strip() 8 | 9 | # the egg system may pollute the sys.path with non compatible .so 10 | # clean it up 11 | for i,path in enumerate(sys.path): 12 | if path.find('/emsdk/')>0: 13 | sys.path[i] = sys.path[i].replace('/emsdk/',f'/{ARCH}/') 14 | sys.path[i] = sys.path[i].replace('py3.11-wasm32-tot-emscripten',f'py3.11-linux-{ARCH}') 15 | sys.path[i] = sys.path[i].replace('py3.10-wasm32-tot-emscripten',f'py3.10-linux-{ARCH}') 16 | 17 | import _cffi_backend 18 | import cffi 19 | from cffi import FFI 20 | -------------------------------------------------------------------------------- /support/xterm: -------------------------------------------------------------------------------- 1 | xterm|xterm-new|xterm terminal emulator (XFree86):\ 2 | :am:km:mi:ms:xn:\ 3 | :co#80:it#8:li#24:colors#256:\ 4 | :AL=\E[%dL:DC=\E[%dP:DL=\E[%dM:DO=\E[%dB:IC=\E[%d@:\ 5 | :LE=\E[%dD:\ 6 | :RI=\E[%dC:UP=\E[%dA:ae=^O:al=\E[L:as=^N:bl=^G:bt=\E[Z:\ 7 | :cd=\E[J:ce=\E[K:cl=\E[H\E[2J:cm=\E[%i%d;%dH:cr=^M:\ 8 | :cs=\E[%i%d;%dr:ct=\E[3g:dc=\E[P:dl=\E[M:do=^J:ec=\E[%dX:\ 9 | :ei=\E[4l:ho=\E[H:im=\E[4h:is=\E[!p\E[?3;4l\E[4l\E>:\ 10 | :kD=\177:\ 11 | :kb=^H:ke=\E[?1l\E>:\ 12 | :ks=\E[?1h\E=:le=^H:mb=\E[5m:md=\E[1m:\ 13 | :me=\E[m\017:mr=\E[7m:nd=\E[C:rc=\E8:sc=\E7:se=\E[27m:\ 14 | :sf=^J:so=\E[7m:sr=\EM:st=\EH:ta=^I:te=\E[?1047l\E[?1048l:\ 15 | :ti=\E[?1048h\E[?1047h:ue=\E[24m:up=\E[A:us=\E[4m:\ 16 | :vb=\E[?5h\E[?5l:ve=\E[?25h:vi=\E[?25l:vs=\E[?25h: 17 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.deps/ncurses-6.1_emscripten.patch: -------------------------------------------------------------------------------- 1 | diff -Naur ncurses-6.1/ncurses/curses.priv.h ncurses-6.1_emscripten/ncurses/curses.priv.h 2 | --- ncurses-6.1/ncurses/curses.priv.h 2018-01-20 23:13:41.000000000 -0300 3 | +++ ncurses-6.1_emscripten/ncurses/curses.priv.h 2019-08-08 21:50:05.174897464 -0300 4 | @@ -64,6 +64,23 @@ 5 | #include /* for offsetof */ 6 | #include 7 | #include 8 | + 9 | +#ifdef __EMSCRIPTEN__ 10 | +#ifdef getenv 11 | +#undef getenv 12 | +#endif 13 | + 14 | +#define getenv(name)(char*)\ 15 | +({\ 16 | + char* data = getenv(name);\ 17 | + int length = strlen(data);\ 18 | + char* dest = (char*)malloc(length+1);\ 19 | + strncpy(dest, data, length);\ 20 | + dest[length+1] = '\0';\ 21 | + dest;\ 22 | +}) 23 | +#endif 24 | + 25 | #include 26 | #include 27 | 28 | -------------------------------------------------------------------------------- /support/cross/aio/recycle.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import aio 3 | import platform 4 | 5 | MODULES = list(sys.modules.keys()) 6 | MAIN = list(vars(__import__("__main__")).keys()) 7 | BUILTINS = list(vars(__import__("builtins")).keys()) 8 | 9 | 10 | def cleanup(): 11 | import sys, random 12 | 13 | for mod in list(sys.modules.keys()): 14 | if not mod in MODULES: 15 | sys.modules.pop(mod, None) 16 | 17 | md = vars(__import__("__main__")) 18 | for name in list(md.keys()): 19 | if not name in MAIN: 20 | md.pop(name, None) 21 | 22 | md = vars(__import__("builtins")) 23 | for var in list(md.keys()): 24 | if not name in BUILTINS: 25 | md.pop(name, None) 26 | 27 | del mod, name, md 28 | __import__("importlib").invalidate_caches() 29 | __import__("gc").collect() 30 | 31 | random.seed(1) 32 | 33 | aio.exit = False 34 | aio.paused = False 35 | print(" - cycling done -") 36 | try: 37 | platform.set_window_title('idle') 38 | platform.prompt() 39 | except: 40 | pass 41 | -------------------------------------------------------------------------------- /support/cross/aio/prepro.py: -------------------------------------------------------------------------------- 1 | import builtins 2 | 3 | DEBUG = False 4 | 5 | defines = {} 6 | 7 | 8 | def defined(plat): 9 | try: 10 | return eval(plat) or True 11 | except: 12 | return False 13 | 14 | 15 | def define(tag, value): 16 | global defines, DEBUG 17 | if DEBUG: 18 | import inspect 19 | 20 | lf = inspect.currentframe().f_back 21 | fn = inspect.getframeinfo(lf).filename.rsplit("/assets/", 1)[-1] 22 | ln = lf.f_lineno 23 | info = f"{fn}:{ln}" 24 | defines.setdefault(tag, info) 25 | else: 26 | info = "?:?" 27 | 28 | redef = defined(tag) 29 | if redef: 30 | if redef is value: 31 | pdb(f"INFO: {tag} redefined from {defines.get(tag)} at {info}") 32 | else: 33 | pdb( 34 | f"""\ 35 | WARNING: {tag} was already defined 36 | previous {defines.get(tag)} value {redef} 37 | new {info} value {value} 38 | 39 | """ 40 | ) 41 | 42 | setattr(builtins, tag, value) 43 | 44 | 45 | builtins.define = define 46 | builtins.defined = defined 47 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Paul m. p. P. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /support/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import sys 3 | 4 | import mimetypes 5 | 6 | mimetypes.init() 7 | if ".wasm" not in mimetypes.types_map: 8 | print( 9 | "WARNING: wasm mimetype unsupported on that system, trying to correct", 10 | file=sys.stderr, 11 | ) 12 | mimetypes.types_map[".wasm"] = "application/wasm" 13 | 14 | import argparse 15 | from http import server 16 | 17 | 18 | parser = argparse.ArgumentParser( 19 | description="Start a local webserver with a Python terminal." 20 | ) 21 | parser.add_argument( 22 | "--port", type=int, default=8000, help="port for the http server to listen on" 23 | ) 24 | args = parser.parse_args() 25 | 26 | 27 | class MyHTTPRequestHandler(server.SimpleHTTPRequestHandler): 28 | def end_headers(self): 29 | self.send_my_headers() 30 | 31 | super().end_headers() 32 | 33 | def send_my_headers(self): 34 | self.send_header("Cross-Origin-Opener-Policy", "same-origin") 35 | self.send_header("Cross-Origin-Embedder-Policy", "require-corp") 36 | 37 | 38 | server.test(HandlerClass=MyHTTPRequestHandler, protocol="HTTP/1.1", port=args.port) 39 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, workflow_dispatch] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-22.04 8 | steps: 9 | - uses: actions/checkout@v1 10 | - name: pygame-wasm-builder prepare 11 | run: | 12 | WD=$(pwd) 13 | python3 -V 14 | echo $WD 15 | clang --version | head -n 1 16 | echo 17 | gcc --version | head -n 1 18 | echo 19 | env|grep GITHUB 20 | echo 21 | env|grep ANDROID 22 | sudo apt-get update 23 | sudo apt-get install -y bash wget 24 | 25 | - name: build 26 | run: | 27 | echo " === Building ====" 28 | cd $GITHUB_WORKSPACE 29 | time bash ./python-wasm-plus.sh 30 | du -hs $(find prebuild/emsdk/) 31 | 32 | 33 | - name: pack 34 | run: | 35 | echo " === Packaging ===" 36 | time bash ./buildapp.sh 37 | cd $GITHUB_WORKSPACE 38 | mv build/demo $GITHUB_WORKSPACE/ 39 | du -hs demo/* 40 | 41 | - name : "Upload to GitHub pages" 42 | uses: JamesIves/github-pages-deploy-action@4.1.7 43 | with: 44 | branch: gh-pages 45 | folder: demo 46 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.patches/3.10-host.diff: -------------------------------------------------------------------------------- 1 | --- Python-3.10.5/Modules/readline.c 2022-06-06 13:53:30.000000000 +0200 2 | +++ Python-3.10.5-pydk/Modules/readline.c 2022-06-13 04:07:55.357320826 +0200 3 | @@ -1324,7 +1324,9 @@ 4 | int has_input = 0, err = 0; 5 | 6 | while (!has_input) 7 | - { struct timeval timeout = {0, 100000}; /* 0.1 seconds */ 8 | + { 9 | + 10 | + struct timeval timeout = {0, 10000}; /* 0.01 seconds */ 11 | 12 | /* [Bug #1552726] Only limit the pause if an input hook has been 13 | defined. */ 14 | --- Python-3.10.5/Parser/pegen.c 2022-06-06 13:53:30.000000000 +0200 15 | +++ Python-3.10.5-pydk/Parser/pegen.c 2022-06-13 04:10:09.549166880 +0200 16 | @@ -432,7 +432,7 @@ 17 | * (multi-line) statement are stored in p->tok->interactive_src_start. 18 | * If not, we're parsing from a string, which means that the whole source 19 | * is stored in p->tok->str. */ 20 | - assert((p->tok->fp == NULL && p->tok->str != NULL) || p->tok->fp == stdin); 21 | + assert((p->tok->fp == NULL && p->tok->str != NULL) || p->tok->fp != NULL); 22 | 23 | char *cur_line = p->tok->fp_interactive ? p->tok->interactive_src_start : p->tok->str; 24 | if (cur_line == NULL) { 25 | -------------------------------------------------------------------------------- /support/cross/aio/clock.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import time 3 | import asyncio 4 | 5 | 6 | class tui: 7 | # use direct access, it is absolute addressing on raw terminal. 8 | out = sys.__stdout__.write 9 | 10 | # save cursor 11 | def __enter__(self): 12 | self.out("\x1b7\x1b[?25l") 13 | return self 14 | 15 | # restore cursor 16 | def __exit__(self, *tb): 17 | self.out("\x1b8\x1b[?25h") 18 | 19 | def __call__(self, *a, **kw): 20 | self.out("\x1b[{};{}H{}".format(kw.get("z", 12), kw.get("x", 40), " ".join(a))) 21 | 22 | 23 | def step(x=70, y=0, z=2): 24 | import time 25 | 26 | def box(t, x, y, z): 27 | lines = t.split("\n") 28 | fill = "─" * len(t) 29 | if z > 1: 30 | print("┌%s┐" % fill, x=x, z=z - 1) 31 | for t in lines: 32 | print("│%s│" % t, x=x, z=z) 33 | z += 1 34 | print("└%s┘" % fill, x=x, z=z) 35 | 36 | with tui() as print: 37 | # draw a clock 38 | t = "%02d:%02d:%02d ☢ 99%% " % time.localtime()[3:6] 39 | box(t, x=x, y=y, z=z) 40 | 41 | 42 | async def clock(x=70, y=0, z=2): 43 | # run as a daemon 44 | while True: # not asyncio.exit: 45 | step(x, y, z) 46 | await asyncio.sleep(1) 47 | sys.stdout.flush() 48 | 49 | 50 | def start(x=70, y=0, z=2): 51 | asyncio.create_task(clock(x, y, z)) 52 | -------------------------------------------------------------------------------- /python-wasm-plus.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | reset 3 | export SDKROOT=${SDKROOT:-$(pwd)} 4 | export PYBUILD=${PYBUILD:-3.11} 5 | 6 | chmod +x scripts/*.sh ./support/*.sh 7 | 8 | mkdir -p build/pycache 9 | export PYTHONDONTWRITEBYTECODE=1 10 | 11 | # make install cpython will force bytecode generation 12 | export PYTHONPYCACHEPREFIX="$(realpath build/pycache)" 13 | 14 | ./scripts/cpython-fetch.sh 15 | ./support/__EMSCRIPTEN__.sh 16 | 17 | ./scripts/cpython-build-host-deps.sh >/dev/null 18 | ./scripts/cpython-build-host.sh >/dev/null 19 | ./scripts/cpython-build-host-prebuilt.sh >/dev/null 20 | 21 | # use ./ or emsdk will pollute env 22 | ./scripts/emsdk-fetch.sh 23 | 24 | echo " ------------------- building cpython wasm deps -------------------" 25 | ./scripts/cpython-build-emsdk-deps.sh > /dev/null 26 | 27 | 28 | echo " ------------------- building cpython wasm -----------------------" 29 | if ./scripts/cpython-build-emsdk.sh > /dev/null 30 | then 31 | echo " ------------------- building cpython wasm packages ----------" 32 | ./scripts/cpython-build-emsdk-deps.sh 33 | 34 | echo " ------------------- building cpython pygame -------------------" 35 | ./scripts/pygame-all.sh > /dev/null 36 | 37 | # pygame won't build if python or sdl failed 38 | [ -f prebuilt/emsdk/libpygame${PYBUILD}.a ] || exit 34 39 | 40 | else 41 | echo " cpython-build-emsdk failed" 42 | exit 38 43 | fi 44 | 45 | echo done 46 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.yml: -------------------------------------------------------------------------------- 1 | name: emsdk_build 2 | on: [workflow_dispatch] 3 | 4 | jobs: 5 | # Build job. Builds app for web with emsdk 6 | build-emsdk: 7 | name: Build for Emscripten 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: Checkout 13 | run: | 14 | WD=$(pwd) 15 | python3 -V 16 | echo $WD 17 | clang --version | head -n 1 18 | echo 19 | grep "^Pkg.Revision =" ${ANDROID_HOME}/ndk-bundle/source.properties 20 | cd $GITHUB_WORKSPACE/.. 21 | export PROJECT=$(basename $(find $GITHUB_WORKSPACE/static|grep py$) .py) 22 | git clone https://github.com/pmp-p/python-wasm-plus.git 23 | ln -s $GITHUB_WORKSPACE python-wasm-plus/demos/$PROJECT 24 | cd python-wasm-plus 25 | bash ./python-wasm-plus.sh 26 | bash ./buildapp.sh templates/no-worker demos/$PROJECT demo 27 | cd $GITHUB_WORKSPACE/../python-wasm-plus/demos/$PROJECT 28 | echo "===================" 29 | pwd 30 | echo "===================" 31 | cd $GITHUB_WORKSPACE/../python-wasm-plus/build 32 | mv demo $GITHUB_WORKSPACE/ 33 | cd $GITHUB_WORKSPACE/ 34 | pwd 35 | ls -al demo 36 | du -hs demo/* 37 | 38 | 39 | - name : "Upload to GitHub pages" 40 | uses: JamesIves/github-pages-deploy-action@4.1.7 41 | with: 42 | branch: gh-pages 43 | folder: demo 44 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.patches/3.11/asyncio/__init__.py: -------------------------------------------------------------------------------- 1 | """The asyncio package, tracking PEP 3156.""" 2 | 3 | # flake8: noqa 4 | 5 | import sys 6 | 7 | # This relies on each of the submodules having an __all__ variable. 8 | from .base_events import * 9 | from .coroutines import * 10 | from .events import * 11 | from .exceptions import * 12 | from .futures import * 13 | from .locks import * 14 | from .protocols import * 15 | from .runners import * 16 | from .queues import * 17 | from .streams import * 18 | from .subprocess import * 19 | from .tasks import * 20 | from .taskgroups import * 21 | from .timeouts import * 22 | from .threads import * 23 | from .transports import * 24 | 25 | __all__ = (base_events.__all__ + 26 | coroutines.__all__ + 27 | events.__all__ + 28 | exceptions.__all__ + 29 | futures.__all__ + 30 | locks.__all__ + 31 | protocols.__all__ + 32 | runners.__all__ + 33 | queues.__all__ + 34 | streams.__all__ + 35 | subprocess.__all__ + 36 | tasks.__all__ + 37 | threads.__all__ + 38 | timeouts.__all__ + 39 | transports.__all__) 40 | 41 | if sys.platform == 'win32': # pragma: no cover 42 | from .windows_events import * 43 | __all__ += windows_events.__all__ 44 | elif sys.platform in ['emscripten','wasi']: 45 | from .wasm_events import * 46 | __all__ += wasm_events.__all__ 47 | else: 48 | from .unix_events import * # pragma: no cover 49 | __all__ += unix_events.__all__ 50 | 51 | 52 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.patches/3.10/asyncio/__init__.py: -------------------------------------------------------------------------------- 1 | """The asyncio package, tracking PEP 3156.""" 2 | 3 | # flake8: noqa 4 | 5 | import sys 6 | 7 | # This relies on each of the submodules having an __all__ variable. 8 | from .base_events import * 9 | from .coroutines import * 10 | from .events import * 11 | from .exceptions import * 12 | from .futures import * 13 | from .locks import * 14 | from .protocols import * 15 | from .runners import * 16 | from .queues import * 17 | from .streams import * 18 | from .subprocess import * 19 | from .tasks import * 20 | #from .taskgroups import * 21 | #from .timeouts import * 22 | from .threads import * 23 | from .transports import * 24 | 25 | __all__ = (base_events.__all__ + 26 | coroutines.__all__ + 27 | events.__all__ + 28 | exceptions.__all__ + 29 | futures.__all__ + 30 | locks.__all__ + 31 | protocols.__all__ + 32 | runners.__all__ + 33 | queues.__all__ + 34 | streams.__all__ + 35 | subprocess.__all__ + 36 | tasks.__all__ + 37 | threads.__all__ + 38 | # timeouts.__all__ + 39 | transports.__all__) 40 | 41 | if sys.platform == 'win32': # pragma: no cover 42 | from .windows_events import * 43 | __all__ += windows_events.__all__ 44 | elif sys.platform in ['emscripten','wasi']: 45 | from .wasm_events import * 46 | __all__ += wasm_events.__all__ 47 | else: 48 | from .unix_events import * # pragma: no cover 49 | __all__ += unix_events.__all__ 50 | 51 | 52 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.embed/cpython.diff: -------------------------------------------------------------------------------- 1 | --- Python-3.11.0b1/Modules/readline.c 2022-05-07 00:56:26.000000000 +0200 2 | +++ Python-3.11.0b1-plus/Modules/readline.c 2022-05-21 22:57:01.680634385 +0200 3 | @@ -1326,7 +1326,9 @@ 4 | int has_input = 0, err = 0; 5 | 6 | while (!has_input) 7 | - { struct timeval timeout = {0, 100000}; /* 0.1 seconds */ 8 | + { 9 | + 10 | + struct timeval timeout = {0, 5000}; /* 0.005 seconds */ 11 | 12 | /* [Bug #1552726] Only limit the pause if an input hook has been 13 | defined. */ 14 | --- Python-3.11.0b1/Python/sysmodule.c 2022-05-07 00:56:26.000000000 +0200 15 | +++ Python-3.11.0b1-plus/Python/sysmodule.c 2022-05-21 22:58:12.873024434 +0200 16 | @@ -48,7 +48,7 @@ 17 | extern const char *PyWin_DLLVersionString; 18 | #endif 19 | 20 | -#ifdef __EMSCRIPTEN__ 21 | +#if 0 22 | #include 23 | #endif 24 | 25 | @@ -2692,7 +2692,7 @@ 26 | return NULL; 27 | } 28 | 29 | -#ifdef __EMSCRIPTEN__ 30 | +#if 0 31 | 32 | PyDoc_STRVAR(emscripten_info__doc__, 33 | "sys._emscripten_info\n\ 34 | @@ -2928,7 +2928,7 @@ 35 | } 36 | } 37 | 38 | -#ifdef __EMSCRIPTEN__ 39 | +#if 0 40 | if (EmscriptenInfoType == NULL) { 41 | EmscriptenInfoType = PyStructSequence_NewType(&emscripten_info_desc); 42 | if (EmscriptenInfoType == NULL) { 43 | @@ -3183,7 +3183,7 @@ 44 | #endif 45 | _PyStructSequence_FiniType(&Hash_InfoType); 46 | _PyStructSequence_FiniType(&AsyncGenHooksType); 47 | -#ifdef __EMSCRIPTEN__ 48 | +#if 0 49 | Py_CLEAR(EmscriptenInfoType); 50 | #endif 51 | } 52 | -------------------------------------------------------------------------------- /support/cross/aio/toplevel.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import aio 3 | 4 | # import textwrap 5 | 6 | # https://bugs.python.org/issue34616 7 | # https://github.com/ipython/ipython/blob/320d21bf56804541b27deb488871e488eb96929f/IPython/core/interactiveshell.py#L121-L150 8 | 9 | async_skeleton = """ 10 | #========================================== 11 | async def retry_async_wrap(): 12 | __snapshot = list( locals().keys() ) 13 | {} 14 | maybe_new = list( locals().keys() ) 15 | while len(__snapshot): 16 | try:maybe_new.remove( __snapshot.pop() ) 17 | except:pass 18 | maybe_new.remove('__snapshot') 19 | while len(maybe_new): 20 | new_one = maybe_new.pop(0) 21 | print(new_one , ':=', locals()[new_one]) 22 | setattr(__import__('__main__'), new_one , locals()[new_one] ) 23 | #========================================== 24 | """ 25 | 26 | 27 | async def retry(code, sysinfo ): 28 | global may_have_value 29 | may_have_value = code.startswith('await ') # will display value 30 | try: 31 | code = 'builtins._ = {}'.format(code) 32 | code = async_skeleton.format(" " * 4 + code) 33 | bytecode = compile(code, "", "exec") 34 | #sys.stdout.write(f':async: asyncify "[code stack rewritten]"\n') 35 | 36 | exec(bytecode, vars(__import__('__main__')), globals()) 37 | await retry_async_wrap() 38 | 39 | # success ? clear all previous failures 40 | if may_have_value: 41 | if builtins._ is not None: 42 | sys.stdout.write('%r\n' % builtins._) 43 | 44 | 45 | 46 | except Exception as e: 47 | # FIXME: raise old exception 48 | sys.__excepthook__(*sysinfo) 49 | sys.stdout.write(f":async: can't use code : {e}\n~~> ") 50 | sys.print_exception(e) 51 | finally: 52 | #sys.ps1 = __ps1__ 53 | aio.prompt_request() 54 | -------------------------------------------------------------------------------- /python-wasm-sim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | reset 3 | unset PYTHONSTARTUP 4 | ROOT=$(dirname $(realpath $0)) 5 | 6 | export PYBUILD=${PYBUILD:-3.11} 7 | export PYMAJOR=$(echo -n $PYBUILD|cut -d. -f1) 8 | export PYMINOR=$(echo -n $PYBUILD|cut -d. -f2) 9 | 10 | export PLATFORM=$ROOT/support/sim.links 11 | 12 | mkdir -p $PLATFORM 13 | echo " 14 | 15 | 16 | Put platform (host) modules or symlink to platform independant ones there : 17 | $PLATFORM 18 | 19 | " 20 | 21 | export PYTHONRC=$ROOT/support/pythonrc.py 22 | 23 | export __FILE__="$1" 24 | #export PATH=$ROOT/devices/$(arch)/usr/bin:$PATH 25 | cat $ROOT/support/cross/aio/simulator.py | envsubst > $ROOT/build/pycache/.pythonrc.py 26 | 27 | unset PYTHONHOME 28 | unset _PYTHON_SYSCONFIGDATA_NAME 29 | 30 | export PYTHONPATH=$(pwd):$ROOT/support/cross:$ROOT/support/sim.links:$PYTHONPATH 31 | 32 | export _PYTHON_SYSCONFIGDATA_NAME=$($ROOT/devices/$(arch)/usr/bin/python3 -c 'import sys;print(f"""_sysconfigdata_{sys.abiflags}_{sys.platform}_{getattr(sys.implementation, "_multiarch", "")}""")') 33 | echo "_PYTHON_SYSCONFIGDATA_NAME=$_PYTHON_SYSCONFIGDATA_NAME" 34 | 35 | export PYTHONSTARTUP=$ROOT/build/pycache/.pythonrc.py 36 | 37 | 38 | PYTHONPATH=$ROOT/prebuilt/emsdk/common/site-packages:$PYTHONPATH 39 | 40 | if false 41 | then 42 | PYTHONPATH=$ROOT/devices/emsdk/usr/lib/python${PYBUILD}:$PYTHONPATH 43 | PYTHONPATH=$ROOT/devices/$(arch)/usr/lib/python${PYBUILD}/site-packages:$PYTHONPATH 44 | export PYTHONPATH 45 | echo "======== SYSTEM PYTHON =============" 46 | export LD_LIBRARY_PATH=$ROOT/devices/$(arch)/usr/lib 47 | /usr/local/bin/python${PYBUILD} 48 | python${PYBUILD} -i -u -B 49 | 50 | else 51 | 52 | export LD_LIBRARY_PATH=$ROOT/devices/$(arch)/usr/lib 53 | export PYTHONPATH=$ROOT/devices/$(arch)/usr/lib/python${PYBUILD}/lib-dynload:$PYTHONPATH 54 | $ROOT/devices/$(arch)/usr/bin/python${PYBUILD} -i -u -B 55 | fi 56 | stty sane 57 | -------------------------------------------------------------------------------- /templates/libs/xterm/xtermjsixel/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: helvetica, sans-serif, arial; 3 | font-size: 1em; 4 | color: #111; 5 | } 6 | 7 | h1 { 8 | text-align: center; 9 | } 10 | 11 | #terminal-container { 12 | width: 800px; 13 | height: 450px; 14 | margin: 0 auto; 15 | padding: 2px; 16 | } 17 | 18 | p { 19 | font-size: 0.9em; 20 | font-style: italic 21 | } 22 | 23 | #option-container { 24 | display: flex; 25 | justify-content: center; 26 | } 27 | 28 | .option-group { 29 | display: inline-block; 30 | padding-left: 20px; 31 | vertical-align: top; 32 | } 33 | 34 | pre { 35 | display: block; 36 | padding: 9.5px; 37 | font-size: 13px; 38 | color: #c7254e; 39 | background-color: #f9f2f4; 40 | word-break: break-all; 41 | word-wrap: break-word; 42 | white-space: pre-wrap; 43 | } 44 | 45 | 46 | #container { 47 | display: flex; 48 | height: 75vh; 49 | } 50 | #grid { 51 | flex: 1; 52 | /* max-height: 80vh; 53 | overflow-y: auto; */ 54 | width: 100%; 55 | } 56 | .tab { 57 | overflow: hidden; 58 | border: 1px solid #ccc; 59 | background-color: #f1f1f1; 60 | } 61 | 62 | /* Style the buttons inside the tab */ 63 | .tab button { 64 | background-color: inherit; 65 | float: left; 66 | border: none; 67 | outline: none; 68 | cursor: pointer; 69 | padding: 14px 16px; 70 | transition: 0.3s; 71 | font-size: 17px; 72 | } 73 | 74 | /* Change background color of buttons on hover */ 75 | .tab button:hover { 76 | background-color: #ddd; 77 | } 78 | 79 | /* Create an active/current tablink class */ 80 | .tab button.active { 81 | background-color: #ccc; 82 | } 83 | 84 | /* Style the tab content */ 85 | .tabContent { 86 | display: none; 87 | padding: 6px 12px; 88 | border: 1px solid #ccc; 89 | border-top: none; 90 | max-height: 100vh; 91 | overflow-y: auto; 92 | } 93 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__-pymain.c: -------------------------------------------------------------------------------- 1 | /* Minimal main program -- everything is loaded from the library */ 2 | 3 | #include "Python.h" 4 | 5 | #if __PYDK__ 6 | #include "pycore_call.h" // _PyObject_CallNoArgs() 7 | #include "pycore_initconfig.h" // _PyArgv 8 | #include "pycore_interp.h" // _PyInterpreterState.sysdict 9 | #include "pycore_pathconfig.h" // _PyPathConfig_ComputeSysPath0() 10 | #include "pycore_pylifecycle.h" // _Py_PreInitializeFromPyArgv() 11 | #include "pycore_pystate.h" // _PyInterpreterState_GET() 12 | 13 | static PyStatus 14 | pymain_init(const _PyArgv *args) 15 | { 16 | PyStatus status; 17 | 18 | status = _PyRuntime_Initialize(); 19 | if (_PyStatus_EXCEPTION(status)) { 20 | return status; 21 | } 22 | 23 | PyPreConfig preconfig; 24 | PyPreConfig_InitPythonConfig(&preconfig); 25 | 26 | status = _Py_PreInitializeFromPyArgv(&preconfig, args); 27 | if (_PyStatus_EXCEPTION(status)) { 28 | return status; 29 | } 30 | 31 | PyConfig config; 32 | PyConfig_InitPythonConfig(&config); 33 | 34 | if (args->use_bytes_argv) { 35 | status = PyConfig_SetBytesArgv(&config, args->argc, args->bytes_argv); 36 | } 37 | else { 38 | status = PyConfig_SetArgv(&config, args->argc, args->wchar_argv); 39 | } 40 | if (_PyStatus_EXCEPTION(status)) { 41 | goto done; 42 | } 43 | 44 | status = Py_InitializeFromConfig(&config); 45 | if (_PyStatus_EXCEPTION(status)) { 46 | goto done; 47 | } 48 | status = _PyStatus_OK(); 49 | 50 | done: 51 | PyConfig_Clear(&config); 52 | return status; 53 | } 54 | 55 | static void 56 | pymain_free(void) 57 | { 58 | _PyImport_Fini2(); 59 | _PyPathConfig_ClearGlobal(); 60 | _Py_ClearStandardStreamEncoding(); 61 | _Py_ClearArgcArgv(); 62 | _PyRuntime_Finalize(); 63 | } 64 | 65 | #include "__EMSCRIPTEN__.c" 66 | #else 67 | int 68 | main(int argc, char **argv) 69 | { 70 | 71 | return Py_BytesMain(argc, argv); 72 | } 73 | #endif //#if __PYDK__ 74 | -------------------------------------------------------------------------------- /demos/0-pong/1001fonts-morris-roman-eula.txt: -------------------------------------------------------------------------------- 1 | 1001Fonts Free For Commercial Use License (FFC) 2 | 3 | Preamble 4 | In this license, 'Morris Roman' refers to the given .zip file, which may contain one or numerous fonts. These fonts can be of any type (.ttf, .otf, ...) and together they form a 'font family' or in short a 'typeface'. 5 | 6 | 1. Copyright 7 | Morris Roman is the intellectual property of its respective author, provided it is original, and is protected by copyright laws in many parts of the world. 8 | 9 | 2. Usage 10 | Morris Roman may be downloaded and used free of charge for both personal and commercial use, as long as the usage is not racist or illegal. Personal use refers to all usage that does not generate financial income in a business manner, for instance: 11 | 12 | - personal scrapbooking for yourself 13 | - recreational websites and blogs for friends and family 14 | - prints such as flyers, posters, t-shirts for churches, charities, and non-profit organizations 15 | 16 | Commercial use refers to usage in a business environment, including: 17 | 18 | - business cards, logos, advertising, websites for companies 19 | - t-shirts, books, apparel that will be sold for money 20 | - flyers, posters for events that charge admission 21 | - freelance graphic design work 22 | - anything that will generate direct or indirect income 23 | 24 | 3. Modification 25 | Morris Roman may not be modified, altered, adapted or built upon without written permission by its respective author. This pertains all files within the downloadable font zip-file. 26 | 27 | 4. Distribution 28 | While Morris Roman may freely be copied and passed along to other individuals for private use as its original downloadable zip-file, it may not be sold or published without written permission by its respective author. 29 | 30 | 5. Disclaimer 31 | Morris Roman is offered 'as is' without any warranty. 1001fonts.com and the respective author of Morris Roman shall not be liable for any damage derived from using this typeface. By using Morris Roman you agree to the terms of this license. -------------------------------------------------------------------------------- /support/cross/aio/trace.py: -------------------------------------------------------------------------------- 1 | STEP_INTO = False 2 | 3 | def on(): 4 | global STEP_INTO 5 | STEP_INTO = True 6 | 7 | def off(): 8 | global STEP_INTO 9 | STEP_INTO = False 10 | 11 | def lines(frame, event, arg): 12 | if event != 'line': 13 | return 14 | co = frame.f_code 15 | func_name = co.co_name 16 | line_no = frame.f_lineno 17 | filename = co.co_filename 18 | print(f" {func_name} line {line_no}") 19 | 20 | 21 | def calls(frame, event, arg): 22 | global STEP_INTO 23 | 24 | if event != "call": 25 | return 26 | 27 | co = frame.f_code 28 | func_name = co.co_name 29 | if func_name in ("write"): 30 | return 31 | func_line_no = frame.f_lineno 32 | func_filename = co.co_filename 33 | 34 | if func_filename.startswith("/usr/lib/python3."): 35 | return 36 | 37 | if func_filename.find("/aio/") > 0: 38 | return 39 | 40 | caller = frame.f_back 41 | if caller: 42 | caller_line_no = caller.f_lineno 43 | caller_filename = caller.f_code.co_filename 44 | if caller_filename != func_filename: 45 | print( 46 | "%s() on line %s of %s from line %s of %s" 47 | % ( 48 | func_name, 49 | func_line_no, 50 | func_filename, 51 | caller_line_no, 52 | caller_filename, 53 | ) 54 | ) 55 | else: 56 | print(f"{func_name} {func_filename}:{caller_line_no}->{func_line_no}") 57 | 58 | if STEP_INTO: 59 | return lines 60 | return 61 | 62 | """ 63 | 64 | def trace_calls_and_returns(frame, event, arg): 65 | co = frame.f_code 66 | func_name = co.co_name 67 | if func_name == 'write': 68 | # Ignore write() calls from print statements 69 | return 70 | line_no = frame.f_lineno 71 | filename = co.co_filename 72 | if event == 'call': 73 | print 'Call to %s on line %s of %s' % (func_name, line_no, filename) 74 | return trace_calls_and_returns 75 | elif event == 'return': 76 | print '%s => %s' % (func_name, arg) 77 | return 78 | 79 | 80 | """ 81 | -------------------------------------------------------------------------------- /config: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | export LC_ALL=C 3 | export ROOT=${ROOT:-$(pwd)} 4 | export SDKROOT=${SDKROOT:-$ROOT} 5 | 6 | export PYTHONDONTWRITEBYTECODE=1 7 | export REBUILD=${REBUILD:-false} 8 | export CI=${CI:-false} 9 | 10 | export PYBUILD=${PYBUILD:-3.11} 11 | export PYMAJOR=$(echo -n $PYBUILD|cut -d. -f1) 12 | export PYMINOR=$(echo -n $PYBUILD|cut -d. -f2) 13 | 14 | export HOST_PREFIX=${HOST_PREFIX:-${SDKROOT}/devices/$(arch)/usr} 15 | export PREFIX=${PREFIX:-${SDKROOT}/devices/emsdk/usr} 16 | 17 | mkdir -p ${SDKROOT}/build/pycache 18 | export PYTHONPYCACHEPREFIX=${PYTHONPYCACHEPREFIX:-$(realpath ${SDKROOT}/build/pycache)} 19 | 20 | export HOME=${SDKROOT} 21 | 22 | export HPY=${HOST_PREFIX}/bin/python${PYBUILD} 23 | export PIP=${HOST_PREFIX}/bin/pip${PYBUILD} 24 | 25 | # cpython build opts 26 | export CPOPTS="-Os -g0 -fPIC" 27 | 28 | 29 | if [ -f ${ROOT}/dev ] 30 | then 31 | export COPTS="-O1 -g3 -fPIC" 32 | export QUIET="" 33 | else 34 | export COPTS="-Os -g0 -fPIC" 35 | if ${VERBOSE:-false} 36 | then 37 | export QUIET="" 38 | else 39 | export QUIET="2>&1 > $PYTHONPYCACHEPREFIX/.log" 40 | fi 41 | fi 42 | 43 | 44 | #stable 45 | # EMFLAVOUR=latest 46 | # EMFLAVOUR=${EMFLAVOUR:-latest} 47 | 48 | export EMFLAVOUR=${EMFLAVOUR:-tot} 49 | 50 | #temp fix for oom on CI (Error: Process completed with exit code 143.) 51 | export EMSDK_NUM_CORES=1 52 | 53 | 54 | export PYDK_PYTHON_HOST_PLATFORM=wasm32-$EMFLAVOUR-emscripten 55 | 56 | if echo $LD_LIBRARY_PATH |grep -q ${HOST_PREFIX}/lib 57 | then 58 | # config already set 59 | echo -n 60 | else 61 | OLDPATH=${PATH} 62 | PATH=/usr/local/bin:/usr/bin:/opt/bin:/bin 63 | # this is python used for emsdk : ${SYS_PYTHON} -> ${EMSDK_PYTHON} 64 | for py in 10 9 8 7 65 | do 66 | if command -v python${PYMAJOR}.${py} >/dev/null 67 | then 68 | export SYS_PYTHON=$(command -v python${PYMAJOR}.${py}) 69 | break 70 | else 71 | # sane default 72 | export SYS_PYTHON=$(command -v python${PYMAJOR}) 73 | fi 74 | done 75 | 76 | export LD_LIBRARY_PATH="${HOST_PREFIX}/lib:$LD_LIBRARY_PATH" 77 | export PATH="${HOST_PREFIX}/bin:$OLDPATH" 78 | fi 79 | -------------------------------------------------------------------------------- /scripts/re-pack-apk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -d .git ] 4 | then 5 | CREDITS_GH=$(git remote -v|head -n1 | cut -d' ' -f1|cut -c8-) 6 | else 7 | CREDITS_GH="Not a git repo" 8 | fi 9 | 10 | 11 | 12 | WEB=${1:-demo} 13 | 14 | CN=$(basename $(pwd)) 15 | 16 | APK=$CN.apk 17 | echo " 18 | APK=$APK 19 | 20 | Web Service Folder : $WEB 21 | 22 | assets folder: $(pwd) 23 | 24 | CREDITS: 25 | GH $CREDITS_GH 26 | 27 | " 28 | 29 | export TEMP=some_name_no_one_would_choose 30 | 31 | 32 | if [ -d static ] 33 | then 34 | rm ../../build/$WEB/$APK $APK 35 | 36 | mkdir $TEMP 37 | 38 | mv static ../$APK-static 39 | mv * ./$TEMP/ 2>/dev/null 40 | 41 | mv ./$TEMP/META-INF ./ 42 | mv ./$TEMP/package.toml ./ 43 | 44 | mv $TEMP assets 45 | 46 | zip -r9 ${APK} . --exclude .git/\* -x .gitignore | wc -l 47 | sync 48 | if du -hs ${APK} 49 | then 50 | 51 | mv ../$APK-static static 52 | 53 | 54 | mv assets ./$TEMP/ 55 | mv ./$TEMP/* ./ 56 | rmdir ./$TEMP 57 | 58 | cat > static/$CN.html < 60 |
 61 |         Github: $CREDITS_GH
 62 | END
 63 | 
 64 | 
 65 |         if [ -d .git ]
 66 |         then
 67 |             git status 2>&1 |grep -v \(use |grep -v ^$|grep -v :$|\
 68 |                 grep -v ^Your |grep -v ^On | grep -v apk$ |grep -v static/ >> static/$CN.html
 69 |         else
 70 |             cat package.toml >> static/$CN.html
 71 |         fi
 72 | 
 73 |         cat >> static/$CN.html <
 75 |         
 76 | END
 77 | 
 78 |         if [ -f inline.html ]
 79 |         then
 80 |             cat inline.html >> static/$CN.html
 81 |         fi
 82 | 
 83 | 
 84 |         mv $APK ../../build/$WEB/
 85 |         ln static/* ../../build/$WEB/
 86 |         sync
 87 |     else
 88 |         echo "
 89 | 
 90 | 
 91 |         *****************************************************************************
 92 | 
 93 | 
 94 | 
 95 | 
 96 |                 ZIP failure at $(pwd) for ${APK}
 97 | 
 98 | 
 99 | 
100 | 
101 |         *****************************************************************************
102 | "
103 |     fi
104 | else
105 |     echo "no folder 'static' found, Are you in app folder ?"
106 | fi
107 | 
108 | 
109 | 


--------------------------------------------------------------------------------
/support/cross/aio/filelike.py:
--------------------------------------------------------------------------------
 1 | import sys
 2 | import io
 3 | import socket
 4 | socket.setdefaulttimeout(0.0)
 5 | 
 6 | import aio
 7 | 
 8 | 
 9 | 
10 | async def aio_sock_open(sock,host,port):
11 |     while True:
12 |         try:
13 |             sock.connect( (host,port,) )
14 |         except BlockingIOError:
15 |             await aio.sleep(0)
16 |         except OSError as e:
17 |             # 30 emsdk, 106 linux
18 |             if e.errno in (30,106):
19 |                 return sock
20 |             sys.print_exception(e)
21 | 
22 | 
23 | 
24 | class open:
25 | 
26 |     def __init__(self,url, mode, tmout):
27 |         self.host, port = url.rsplit(':',1)
28 |         self.port = int(port)
29 |         if __WASM__ and __import__('platform').is_browser:
30 |             if not url.startswith('ws'):
31 |                 pdb(f"switching to {self.port}+20000 as websocket")
32 |                 self.port += 20000
33 | 
34 |         self.sock = socket.socket()
35 |         #self.sock.setblocking(0)
36 | 
37 | # overload socket ?
38 | 
39 |     def fileno(self):
40 |         return self.sock.fileno()
41 | 
42 |     def send(self,*argv,**kw):
43 |         self.sock.send(*argv,**kw)
44 | 
45 |     def recv(self, *argv):
46 |         return self.sock.recv(*argv)
47 | 
48 | # ============== specific ===========================
49 | 
50 |     async def __aenter__(self):
51 |         # use async
52 |         await aio_sock_open(self.sock, self.host, self.port)
53 |         return self
54 | 
55 |     async def __aexit__(self, exc_type, exc, tb):
56 |         aio.protect.append(self)
57 |         aio.defer(self.sock.close, (),{} )
58 |         del self.port, self.host, self.sock
59 | 
60 |     def read(self, size=-1):
61 |         return self.recv(0)
62 | 
63 | 
64 |     def write(self, data):
65 |         if isinstance(data, str):
66 |             return self.sock.send(data.encode())
67 |         return self.sock.send(data)
68 | 
69 |     def print(self,*argv,**kw):
70 |         # use EOL
71 |         #kw.setdefault("end","\r\n")
72 |         kw['file']=io.StringIO(newline="\r\n")
73 |         print(*argv,**kw)
74 |         self.write( kw['file'].getvalue() )
75 | 
76 |     def  __enter__(url, mode, tmout):
77 |         # use softrt (wapy)
78 |         return aio.await_for( self.__aenter__())
79 | 
80 |     def __exit__(self, exc_type, exc, tb):
81 |         #self.sock.close()
82 |         pass
83 | 


--------------------------------------------------------------------------------
/templates/no-worker/pythons.html:
--------------------------------------------------------------------------------
  1 | 
115 | 
116 | 
117 | 
118 | 
119 | 
120 | 
121 | 
122 | 
123 | 
124 | 
125 | 


--------------------------------------------------------------------------------
/scripts/pygame-all.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | 
  4 | . ${CONFIG:-config}
  5 | 
  6 | if [ -f /pp ]
  7 | then
  8 |     if $HPY -c "import pygame"
  9 |     then
 10 |         echo "
 11 |     * not re-building host pygame
 12 |         " 1>&2
 13 |     else
 14 |         echo "
 15 |     * building host pygame for desktop simulator
 16 |         " 1>&2
 17 |         rm -rf src/pygame-wasm/Setup src/pygame-wasm/build
 18 |         pushd src/pygame-wasm
 19 |         $HPY setup.py -config -auto -sdl2
 20 |         $HPY setup.py install
 21 |         popd
 22 |     fi
 23 | else
 24 |     echo "
 25 |         * not building host pygame
 26 |     " 1>&2
 27 | fi
 28 | 
 29 | mkdir -p prebuilt
 30 | 
 31 | if [ -d src/pygame-wasm/.git ]
 32 | then
 33 |     echo "
 34 |         * pygame already fetched
 35 |     " 1>&2
 36 | else
 37 |     pushd src
 38 |     # if running from main repo use the upstreaming pygame-wasm
 39 |     if echo $GITHUB_WORKSPACE|grep -q /python-wasm-plus/
 40 |     then
 41 |         # pygame-wasm testing
 42 |         git clone --no-tags --depth 1 --single-branch -b pygame-wasm https://github.com/pmp-p/pygame-wasm pygame-wasm
 43 |     else
 44 |         # git pygame for pygame-web
 45 |         git clone --no-tags --depth 1 --single-branch -b main https://github.com/pygame/pygame pygame-wasm
 46 |     fi
 47 |     popd
 48 | fi
 49 | 
 50 | 
 51 | echo "
 52 | 
 53 | 
 54 |     *******************************************************************************
 55 |     *******************************************************************************
 56 | 
 57 | "
 58 | 
 59 | 
 60 | # remove old lib
 61 | [ -f ${ROOT}/prebuilt/emsdk/libpygame${PYBUILD}.a ] && rm ${ROOT}/prebuilt/emsdk/libpygame${PYBUILD}.a
 62 | 
 63 | 
 64 | 
 65 | # remove anything that could be native
 66 | if [ -d src/pygame-wasm/build ]
 67 | then
 68 |     echo "
 69 |         * cleaning up pygame build
 70 |     " 1>&2
 71 |     rm -rf src/pygame-wasm/Setup src/pygame-wasm/build
 72 | fi
 73 | 
 74 | pushd src/pygame-wasm
 75 | 
 76 | # regen cython files
 77 | if [ -f dev ]
 78 | then
 79 |     #TODO: $HPY setup.py cython config
 80 |     python3 setup.py cython_only
 81 | fi
 82 | 
 83 | 
 84 | # for libSDL2_ttf.a
 85 | # LDFLAGS="$LDFLAGS -L$ROOT/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/pic"
 86 | 
 87 | # emsdk is activated via python3-wasm
 88 | 
 89 | if false
 90 | then
 91 |     SDL_IMAGE="-s USE_SDL_IMAGE=2 -sUSE_LIBPNG -sUSE_LIBJPEG"
 92 | else
 93 |     SDL_IMAGE="-I$PREFIX/include/SDL2 -s USE_SDL=2 -sUSE_SDL_TTF=2 -sUSE_LIBPNG -sUSE_LIBJPEG"
 94 | fi
 95 | 
 96 | #  -lwebp
 97 | 
 98 | rm -rf build/temp.wasm32-* 2>/dev/null
 99 | 
100 | if python3-wasm setup.py -config -auto -sdl2
101 | then
102 |     if CC=emcc CFLAGS="-DHAVE_STDARG_PROTOTYPES -DBUILD_STATIC -DSDL_NO_COMPAT -ferror-limit=1 -Wno-unused-command-line-argument -Wno-unreachable-code-fallthrough -fPIC"\
103 |  EMCC_CFLAGS="$SDL_IMAGE"\
104 |  python3-wasm setup.py build -j3
105 |     then
106 |         OBJS=$(find build/temp.wasm32-*/|grep o$)
107 |         $ROOT/emsdk/upstream/emscripten/emar rcs ${ROOT}/prebuilt/emsdk/libpygame${PYBUILD}.a $OBJS
108 |         for obj in $OBJS
109 |         do
110 |             echo $obj
111 |         done
112 |         du -hs ${ROOT}/prebuilt/emsdk/libpygame${PYBUILD}.a
113 |     else
114 |         exit 82
115 |     fi
116 | else
117 |     exit 85
118 | fi
119 | popd
120 | 
121 | 
122 | 


--------------------------------------------------------------------------------
/scripts/cpython-fetch.sh:
--------------------------------------------------------------------------------
  1 | ##!/bin/bash
  2 | 
  3 | . ${CONFIG:-config}
  4 | 
  5 | echo "
  6 |     *   cpython-fetch $PYBUILD  *
  7 | "
  8 | 
  9 | mkdir -p src
 10 | 
 11 | pushd src 2>&1 >/dev/null
 12 | 
 13 | NOPATCH=false
 14 | PYPATCH=true
 15 | 
 16 | [ -L cpython${PYBUILD} ] && rm cpython${PYBUILD}
 17 | 
 18 | [ -f $HPY ] || REBUILD=true
 19 | 
 20 | 
 21 | if echo $PYBUILD |grep -q 12$
 22 | then
 23 |     if [ -d cpython${PYBUILD} ]
 24 |     then
 25 |         pushd cpython${PYBUILD} 2>&1 >/dev/null
 26 |         # put the tree back to original state so we can pull
 27 |         # Programs/python.c Modules/readline.c
 28 |         git restore .
 29 | 
 30 |         if git pull|grep -q 'Already up to date'
 31 |         then
 32 |             export REBUILD=${REBUILD:-false}
 33 |         else
 34 |             export REBUILD=true
 35 |         fi
 36 |         #not here or pip won't install properly anymore its wheels
 37 |         #cat $ROOT/support/compilenone.py > ./Lib/compileall.py
 38 |         popd
 39 |     else
 40 |         git clone --no-tags --depth 1 --single-branch --branch main https://github.com/python/cpython.git cpython${PYBUILD}
 41 |         export REBUILD=true
 42 |     fi
 43 | fi
 44 | 
 45 | if echo $PYBUILD | grep -q 11$
 46 | then
 47 |     if false
 48 |     then
 49 |         wget -q -c https://www.python.org/ftp/python/3.11.0/Python-3.11.0b4.tar.xz
 50 |         tar xf Python-3.11.0b4.tar.xz
 51 |         ln -s Python-3.11.0b4 cpython${PYBUILD}
 52 |     else
 53 |         if [ -d cpython${PYBUILD} ]
 54 |         then
 55 |             pushd cpython${PYBUILD} 2>&1 >/dev/null
 56 |             git restore .
 57 | 
 58 |             if git pull|grep -q 'Already up to date'
 59 |             then
 60 |                 export REBUILD=${REBUILD:-false}
 61 |             else
 62 |                 export REBUILD=true
 63 |             fi
 64 |             #not here or pip won't install properly anymore its wheels
 65 |             #cat $ROOT/support/compilenone.py > ./Lib/compileall.py
 66 |             popd
 67 |         else
 68 |             git clone --no-tags --depth 1 --single-branch --branch ${PYBUILD} https://github.com/python/cpython.git cpython${PYBUILD}
 69 |             export REBUILD=true
 70 |         fi
 71 |     fi
 72 |     export REBUILD=true
 73 | fi
 74 | 
 75 | if echo $PYBUILD | grep -q 10$
 76 | then
 77 |     wget -q -c https://www.python.org/ftp/python/3.10.6/Python-3.10.6.tar.xz
 78 |     tar xf Python-3.10.6.tar.xz
 79 | 
 80 |     ln -s Python-3.10.6 cpython${PYBUILD}
 81 | 
 82 |     NOPATCH=true
 83 |     export REBUILD=true
 84 | fi
 85 | 
 86 | popd
 87 | 
 88 | 
 89 | 
 90 | # 3.10 is not wasm stable
 91 | if [ -f support/__EMSCRIPTEN__.patches/${PYBUILD}-host.diff ]
 92 | then
 93 |     pushd src/cpython${PYBUILD} 2>&1 >/dev/null
 94 |     patch -p1 < ../../support/__EMSCRIPTEN__.patches/${PYBUILD}-host.diff
 95 |     popd 2>&1 >/dev/null
 96 | fi
 97 | 
 98 | 
 99 | # the sys._emscripten_info is actually not compatible with shared build
100 | # just move its stuff to main
101 | 
102 | if $NOPATCH
103 | then
104 |     echo -n
105 | else
106 |     # do some patching for 3.11+ to allow more shared libs
107 |     pushd src/cpython${PYBUILD} 2>&1 >/dev/null
108 |     patch -p1 < ../../support/__EMSCRIPTEN__.embed/cpython.diff
109 |     popd 2>&1 >/dev/null
110 | fi
111 | 
112 | echo "
113 |     * fetched cpython source, status is :
114 |         REBUILD=${REBUILD}
115 | "
116 | 
117 | [ -d build/cpython-host ] && rm -rf build/cpython-host
118 | [ -d build/cpython-wasm ] && rm -rf build/cpython-wasm
119 | 


--------------------------------------------------------------------------------
/support/__EMSCRIPTEN__.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | . ${CONFIG:-config}
  4 | 
  5 | echo "
  6 |     *__EMSCRIPTEN__*
  7 | "
  8 | 
  9 | 
 10 | if grep -q PYDK src/cpython${PYBUILD}/Programs/python.c
 11 | then
 12 |     echo "
 13 |         * __EMSCRIPTEN__ support already added
 14 |     " 1>&2
 15 | else
 16 |     pushd src/cpython${PYBUILD}
 17 |     if echo $PYBUILD |grep -q 3.12$
 18 |     then
 19 |         echo 3.12 does not need patching for interactive FD
 20 |     else
 21 |         [ -f "Parser/pegen_errors.c" ] && patch -p1 <tok->interactive_src_start.
 28 |       * If not, we're parsing from a string, which means that the whole source
 29 |       * is stored in p->tok->str. */
 30 | -    assert((p->tok->fp == NULL && p->tok->str != NULL) || p->tok->fp == stdin);
 31 | +    assert((p->tok->fp == NULL && p->tok->str != NULL) || p->tok->fp != NULL);
 32 | 
 33 |      char *cur_line = p->tok->fp_interactive ? p->tok->interactive_src_start : p->tok->str;
 34 |      if (cur_line == NULL) {
 35 | END
 36 |     fi
 37 | 
 38 |     # fix the main startup to it gets a minimal kernel for wasm
 39 |     cat > Programs/python.c <use_bytes_argv) {
 74 |         status = PyConfig_SetBytesArgv(&config, args->argc, args->bytes_argv);
 75 |     }
 76 |     else {
 77 |         status = PyConfig_SetArgv(&config, args->argc, args->wchar_argv);
 78 |     }
 79 |     if (_PyStatus_EXCEPTION(status)) {
 80 |         goto done;
 81 |     }
 82 | 
 83 |     status = Py_InitializeFromConfig(&config);
 84 |     if (_PyStatus_EXCEPTION(status)) {
 85 |         goto done;
 86 |     }
 87 |     status = _PyStatus_OK();
 88 | 
 89 | done:
 90 |     PyConfig_Clear(&config);
 91 |     return status;
 92 | }
 93 | 
 94 | static void
 95 | pymain_free(void)
 96 | {
 97 |     _PyImport_Fini2();
 98 |     _PyPathConfig_ClearGlobal();
 99 |     _Py_ClearStandardStreamEncoding();
100 |     _Py_ClearArgcArgv();
101 |     _PyRuntime_Finalize();
102 | }
103 | 
104 | #include "${ROOT}/support/__EMSCRIPTEN__.c"
105 | #else
106 | int
107 | main(int argc, char **argv)
108 | {
109 | 
110 |     return Py_BytesMain(argc, argv);
111 | }
112 | #endif //#if __PYDK__
113 | END
114 | 
115 |     popd
116 | fi
117 | 


--------------------------------------------------------------------------------
/support/__EMSCRIPTEN__.embed/sysmodule.c:
--------------------------------------------------------------------------------
  1 | /* Updating the sys namespace, returning NULL pointer on error */
  2 | #define SET_SYS(key, value)                                \
  3 |     do {                                                   \
  4 |         PyObject *v = (value);                             \
  5 |         if (v == NULL) {                                   \
  6 |             goto err_occurred;                             \
  7 |         }                                                  \
  8 |         res = PyDict_SetItemString(sysdict, key, v);   \
  9 |         Py_DECREF(v);                                      \
 10 |         if (res < 0) {                                     \
 11 |             goto err_occurred;                             \
 12 |         }                                                  \
 13 |     } while (0)
 14 | 
 15 | #define SET_SYS_FROM_STRING(key, value) \
 16 |         SET_SYS(key, PyUnicode_FromString(value))
 17 | 
 18 | 
 19 | #if 2695
 20 | 
 21 | PyDoc_STRVAR(emscripten_info__doc__,
 22 | "sys._emscripten_info\n\
 23 | \n\
 24 | WebAssembly Emscripten platform information.");
 25 | 
 26 | static PyTypeObject *EmscriptenInfoType;
 27 | 
 28 | static PyStructSequence_Field emscripten_info_fields[] = {
 29 |     {"emscripten_version", "Emscripten version (major, minor, micro)"},
 30 |     {"runtime", "Runtime (Node.JS version, browser user agent)"},
 31 |     {"pthreads", "pthread support"},
 32 |     {"shared_memory", "shared memory support"},
 33 |     {0}
 34 | };
 35 | 
 36 | static PyStructSequence_Desc emscripten_info_desc = {
 37 |     "sys._emscripten_info",     /* name */
 38 |     emscripten_info__doc__ ,    /* doc */
 39 |     emscripten_info_fields,     /* fields */
 40 |     4
 41 | };
 42 | 
 43 | EM_JS(char *, _Py_emscripten_runtime, (void), {
 44 |     var info;
 45 |     if (typeof navigator == 'object') {
 46 |         info = navigator.userAgent;
 47 |     } else if (typeof process == 'object') {
 48 |         info = "Node.js ".concat(process.version)
 49 |     } else {
 50 |         info = "UNKNOWN"
 51 |     }
 52 |     var len = lengthBytesUTF8(info) + 1;
 53 |     var res = _malloc(len);
 54 |     stringToUTF8(info, res, len);
 55 |     return res;
 56 | });
 57 | 
 58 | static PyObject *
 59 | make_emscripten_info(void)
 60 | {
 61 |     PyObject *emscripten_info = NULL;
 62 |     PyObject *version = NULL;
 63 |     char *ua;
 64 |     int pos = 0;
 65 | 
 66 |     emscripten_info = PyStructSequence_New(EmscriptenInfoType);
 67 |     if (emscripten_info == NULL) {
 68 |         return NULL;
 69 |     }
 70 | 
 71 |     version = Py_BuildValue("(iii)",
 72 |         __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
 73 |     if (version == NULL) {
 74 |         goto error;
 75 |     }
 76 |     PyStructSequence_SET_ITEM(emscripten_info, pos++, version);
 77 | 
 78 |     ua = _Py_emscripten_runtime();
 79 |     if (ua != NULL) {
 80 |         PyObject *oua = PyUnicode_DecodeUTF8(ua, strlen(ua), "strict");
 81 |         free(ua);
 82 |         if (oua == NULL) {
 83 |             goto error;
 84 |         }
 85 |         PyStructSequence_SET_ITEM(emscripten_info, pos++, oua);
 86 |     } else {
 87 |         Py_INCREF(Py_None);
 88 |         PyStructSequence_SET_ITEM(emscripten_info, pos++, Py_None);
 89 |     }
 90 | 
 91 | #define SetBoolItem(flag) \
 92 |     PyStructSequence_SET_ITEM(emscripten_info, pos++, PyBool_FromLong(flag))
 93 | 
 94 | #ifdef __EMSCRIPTEN_PTHREADS__
 95 |     SetBoolItem(1);
 96 | #else
 97 |     SetBoolItem(0);
 98 | #endif
 99 | 
100 | #ifdef __EMSCRIPTEN_SHARED_MEMORY__
101 |     SetBoolItem(1);
102 | #else
103 |     SetBoolItem(0);
104 | #endif
105 | 
106 | #undef SetBoolItem
107 | 
108 |     if (PyErr_Occurred()) {
109 |         goto error;
110 |     }
111 |     return emscripten_info;
112 | 
113 |   error:
114 |     Py_CLEAR(emscripten_info);
115 |     return NULL;
116 | }
117 | 
118 | #endif // __EMSCRIPTEN__
119 | //2794
120 | 
121 | 
122 | 


--------------------------------------------------------------------------------
/scripts/make_coldstartfs.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | . ${CONFIG:-config}
  4 | 
  5 | FS=$PYTHONPYCACHEPREFIX/fs
  6 | 
  7 | echo "
  8 | 
  9 | 
 10 | 
 11 |     * packing minimal stdlib for
 12 |         PYTHON=$HPY
 13 |         FS=$FS
 14 | 
 15 | 
 16 | ==================================================================================
 17 | " 1>&2
 18 | 
 19 | 
 20 | # TODO check if opt.pyc are really interesting.
 21 | # unset PYTHONDONTWRITEBYTECODE
 22 | 
 23 | $HPY -O -v <&1 | tee $FS.log  |grep py$ > $FS
 24 | from __future__ import annotations
 25 | import sys
 26 | 
 27 | M1='os, json, builtins, shutil, zipimport, time, trace, traceback, '
 28 | M2='asyncio, inspect, _thread, importlib, ctypes, tomllib'
 29 | for mod in (M1+M2).split(', '):
 30 |     try:
 31 |         __import__(mod)
 32 |     except:
 33 |         pass
 34 | try:
 35 |     b'xx'.decode('cp437')
 36 |     b'xx'.decode('cp850')
 37 |     b'xx'.decode('latin1')
 38 |     sys.stdout.reconfigure(encoding='utf-16')
 39 |     sys.stdout.reconfigure(encoding='utf-8')
 40 | except:
 41 |     pass
 42 | 
 43 | # intaller "cp437"
 44 | import compileall, csv, configparser, zlib
 45 | # micropip
 46 | import importlib.metadata
 47 | 
 48 | # for dom event subscriptions and js interface
 49 | import webbrowser
 50 | import platform
 51 | 
 52 | # for wget to overload urlretrieve
 53 | import urllib.request
 54 | 
 55 | # nodezator
 56 | from logging.handlers import RotatingFileHandler
 57 | from colorsys  import rgb_to_hls, hls_to_rgb
 58 | import xml.dom.minidom
 59 | from xml.dom import expatbuilder
 60 | import pydoc
 61 | 
 62 | # rich
 63 | import zlib
 64 | 
 65 | # pygame_gui
 66 | import html.parser
 67 | import importlib.readers
 68 | 
 69 | #pymunk tests
 70 | import unittest, locale
 71 | 
 72 | #pymunk4
 73 | import imp, platform
 74 | 
 75 | #pymunk6
 76 | import numbers, random
 77 | 
 78 | #pgzero
 79 | import hashlib, queue, pkgutil
 80 | 
 81 | #numpy
 82 | import pathlib
 83 | 
 84 | # cffi
 85 | import copy
 86 | 
 87 | #curses
 88 | import curses
 89 | 
 90 | #pytmx
 91 | import gzip
 92 | import zlib
 93 | from xml.etree import ElementTree
 94 | import distutils.spawn
 95 | 
 96 | #pygame_gui
 97 | import importlib.resources
 98 | 
 99 | if 0:
100 |     import cffi
101 |     from cffi import FFI
102 |     ffi = FFI()
103 | END
104 | 
105 | grep -v ^# $FS.log | grep -v ^import 1>&2
106 | 
107 | 
108 | echo "
109 | ==================================================================================
110 | 
111 | 
112 | " 1>&2
113 | 
114 | $HPY -u -B <0:
129 |             #    continue
130 | 
131 | 
132 |             if name.endswith(sysconf):
133 |                 name = name.replace(sysconf,"_sysconfigdata__emscripten_wasm32-emscripten.py")
134 | 
135 |             name = name.replace('asyncio/selector_','asyncio/wasm_')
136 |             print(name, file=tarlist )
137 |         else:
138 |             stdlp = stdlp.replace('$(arch)','emsdk')
139 |             print(stdlp)
140 |             tarcmd=f"tar --directory=/{stdlp}usr/lib --files-from=$PYTHONPYCACHEPREFIX/stdl.list -cf $PYTHONPYCACHEPREFIX/stdl.tar"
141 |             print(tarcmd)
142 | os.system(tarcmd)
143 | END
144 | 
145 | 
146 | mkdir -p $PYTHONPYCACHEPREFIX/stdlib-coldstart
147 | #cp -vf devices/emsdk/usr/lib/python3.*/_sysconfigdata* $PYTHONPYCACHEPREFIX/stdlib-coldstart/python3.*/
148 | pushd $PYTHONPYCACHEPREFIX/stdlib-coldstart
149 | tar xvf $PYTHONPYCACHEPREFIX/stdl.tar | wc -l
150 | rm $PYTHONPYCACHEPREFIX/stdl.tar
151 | du -hs $PYTHONPYCACHEPREFIX/stdlib-coldstart/python3.${PYMINOR}
152 | popd
153 | 
154 | 


--------------------------------------------------------------------------------
/support/cross/aio/cross.py:
--------------------------------------------------------------------------------
  1 | import sys
  2 | 
  3 | DEBUG = False
  4 | 
  5 | import aio.prepro
  6 | 
  7 | aio.prepro.DEBUG = DEBUG
  8 | 
  9 | # that sym cannot be overloaded in a simulator
 10 | 
 11 | if not defined("__WASM__"):
 12 |     if __import__("os").uname().machine.startswith("wasm"):
 13 |         import __WASM__
 14 |     else:
 15 |         __WASM__ = False
 16 | 
 17 |     define("__WASM__", __WASM__)
 18 | 
 19 | 
 20 | # those can
 21 | 
 22 | 
 23 | if not defined("__wasi__"):
 24 |     if __import__("sys").platform in ["wasi"]:
 25 |         import __wasi__
 26 |     else:
 27 |         __wasi__ = False
 28 | 
 29 |     define("__wasi__", __wasi__)
 30 | 
 31 |     # setup exception display with same syntax as upy
 32 |     import traceback
 33 | 
 34 |     def print_exception(e, out=sys.stderr, **kw):
 35 |         kw["file"] = out
 36 |         traceback.print_exc(**kw)
 37 | 
 38 |     sys.print_exception = print_exception
 39 |     del print_exception
 40 | 
 41 | 
 42 | # this *is* the cpython way
 43 | if hasattr(sys, "getandroidapilevel"):
 44 |     platform = defined("__ANDROID__")
 45 |     if not platform:
 46 |         print("importing platform __ANDROID__")
 47 |         try:
 48 |             import __ANDROID__ as platform
 49 |         except Exception as e:
 50 |             if hasattr(sys, "print_exception"):
 51 |                 sys.print_exception(e)
 52 |             else:
 53 |                 __import__("traceback").print_exc()
 54 | 
 55 |             pdb("__ANDROID__ failed to load, assuming simulator instead of error :")
 56 |             del platform
 57 | 
 58 |             # fake it
 59 |             platform == __import__("__main__")
 60 |         define("__ANDROID__", platform)
 61 |     try:
 62 |         __ANDROID_API__
 63 |     except:
 64 |         defined("__ANDROID_API__", sys.getandroidapilevel())
 65 | 
 66 | 
 67 | if sys.platform == "emscripten":
 68 |     platform = defined("__EMSCRIPTEN__")
 69 |     if not platform:
 70 |         print("importing platform __EMSCRIPTEN__")
 71 |         try:
 72 |             import __EMSCRIPTEN__ as platform
 73 |         except Exception as e:
 74 |             if hasattr(sys, "print_exception"):
 75 |                 sys.print_exception(e)
 76 |             else:
 77 |                 __import__("traceback").print_exc()
 78 | 
 79 |             pdb("__EMSCRIPTEN__ failed to load, assuming simulator instead of error :")
 80 |             del platform
 81 | 
 82 |             # fake it
 83 |             platform == __import__("__main__")
 84 |         define("__EMSCRIPTEN__", platform)
 85 | 
 86 | 
 87 | driver = defined("embed")
 88 | try:
 89 |     if not driver:
 90 |         import embed as driver
 91 | 
 92 |         print("platform embedding module driver :", driver)
 93 | except:
 94 |     # use the simulator defined platform value as the embed.
 95 |     driver = platform
 96 | 
 97 | # just in case it was not a module
 98 | sys.modules.setdefault("embed", driver)
 99 | 
100 | try:
101 |     # check it the embedding module was finished for that platform.
102 |     # the least shoulbe syslog ( js console / adb logcat )
103 |     driver.log
104 | except:
105 |     pdb(
106 |         """\
107 | WARNING: embed softrt/syslog functions not found
108 | WARNING: also not in __main__ or simulator provided platform module
109 | """
110 |     )
111 |     driver.enable_irq = print
112 |     driver.disable_irq = print
113 |     driver.log = print
114 | 
115 | define("embed", driver)
116 | 
117 | platform.init_platform(driver)
118 | sys.modules["platform"] = platform
119 | 
120 | 
121 | 
122 | # ================== leverage known python implementations ====================
123 | 
124 | # always come down to upy choices because cpython syntax can more easily be adapted
125 | 
126 | 
127 | if not defined("__UPY__"):
128 |     define("__UPY__", hasattr(sys.implementation, "mpy"))
129 | 
130 | 
131 | if not __UPY__:
132 |     # setup exception display with same syntax as upy
133 |     import traceback
134 | 
135 |     def print_exception(e, out=sys.stderr, **kw):
136 |         kw["file"] = out
137 |         traceback.print_exc(**kw)
138 | 
139 |     sys.print_exception = print_exception
140 |     del print_exception
141 | 
142 | 
143 | scheduler = None
144 | simulator = None
145 | 


--------------------------------------------------------------------------------
/scripts/cpython-build-host.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | . ${CONFIG:-config}
  4 | 
  5 | export PYTHON_FOR_BUILD=${PYTHON_FOR_BUILD:-${HPY}}
  6 | 
  7 | mkdir -p build/cpython-host
  8 | 
  9 | if $REBUILD
 10 | then
 11 |     echo "
 12 |         * building CPython $PYBUILD for $CIVER
 13 |     " 1>&2
 14 | else
 15 |     if [ -f ${PYTHON_FOR_BUILD} ]
 16 |     then
 17 |         REBUILD=false
 18 |         echo "
 19 |             * will *RE-USE* PYTHON_FOR_BUILD found at ${PYTHON_FOR_BUILD}
 20 |         " 1>&2
 21 |     else
 22 |         REBUILD=true
 23 |     fi
 24 | fi
 25 | 
 26 | # in this special case build testsuite
 27 | # main repo https://github.com/pmp-p/python-wasm-plus
 28 | 
 29 | # pygame-web won't build test modules
 30 | 
 31 | if echo $GITHUB_WORKSPACE|grep -q /python-wasm-plus/
 32 | then
 33 |     TESTSUITE="--enable-test-modules"
 34 |     #TESTSUITE=""
 35 | else
 36 |     TESTSUITE=""
 37 | fi
 38 | 
 39 | echo "
 40 | 
 41 | 
 42 | 
 43 | 
 44 |     ********** TESTSUITE test-modules == $TESTSUITE *******************
 45 | 
 46 | 
 47 | 
 48 | 
 49 | " 1>&2
 50 | 
 51 | 
 52 | if $REBUILD
 53 | then
 54 |     pushd build/cpython-host
 55 | 
 56 |     # those are for wasm
 57 |     unset CPPFLAGS
 58 |     unset LDFLAGS
 59 | 
 60 | 
 61 | #export OPT="$CPOPTS -DNDEBUG -fwrapv"
 62 |     cat > $ROOT/src/cpython${PYBUILD}/Tools/wasm/config.host-wasm32-emscripten <> pyconfig.h <&2
105 |             sleep 6
106 |         fi
107 |     fi
108 | 
109 | # OPT="$OPT"
110 | # CFLAGS="-DHAVE_FFI_PREP_CIF_VAR=1 -DHAVE_FFI_PREP_CLOSURE_LOC=1 -DHAVE_FFI_CLOSURE_ALLOC=1"
111 |     if \
112 |     CC=clang CXX=clang++ CFLAGS="-fPIC" CPPFLAGS="-fPIC" \
113 |     ${ROOT}/src/cpython${PYBUILD}/configure \
114 |      --prefix=$HOST_PREFIX $PYOPTS
115 |     then
116 |         make -j$(nproc) install
117 |         rm -rf $(find $ROOT/devices/ -type d|grep __pycache__$)
118 | 
119 |         rm $HOST_PREFIX/bin/*3 $HOST_PREFIX/bin/python3-config
120 | 
121 |         patchelf --remove-needed libintl.so.8  $HOST_PREFIX/bin/python${PYBUILD}
122 |         sed -i 's|-lintl ||g' ${SDKROOT}/devices/x86_64/usr/bin/python${PYBUILD}-config
123 | 
124 |         cp -Rfv $ROOT/support/__EMSCRIPTEN__.patches/${PYBUILD}/. $HOST_PREFIX/lib/python${PYBUILD}/
125 |     else
126 |         echo "
127 | ==========================================================================
128 |     ERROR: could not configure cpython
129 | 
130 |     reminder: you need clang libffi-dev and usual cpython requirements.
131 | ==========================================================================
132 |     " 1>&2
133 |         exit 1
134 |     fi
135 | 
136 |     popd
137 | else
138 |     echo "
139 |         *   cpython host already built :
140 |                 PYTHON_FOR_BUILD=${PYTHON_FOR_BUILD}
141 |     " 1>&2
142 | fi
143 | 
144 | 
145 | unset PYTHON_FOR_BUILD
146 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | # python-wasm-plus
  2 | 
  3 | Thanks to all that participated, the cpython ticket https://github.com/python/cpython/issues/84461 is being solved
  4 | 
  5 | Here's a glimpse of the future :
  6 | A sandbox for making cpython app on webassembly with integrated pygame built with
  7 | emscripten portable sdk.
  8 | 
  9 | How does it work ?
 10 | 
 11 | See the excellent slides of Christian Heimes at PyCon DE
 12 | 
 13 |   https://www.youtube.com/watch?v=oa2LllRZUlU
 14 | 
 15 |   https://speakerdeck.com/tiran/python-3-dot-11-in-the-web-browser-a-journey-pycon-de-2022-keynote
 16 | 
 17 | 
 18 | or notes of PyCon US 2022
 19 |  https://speakerdeck.com/tiran/language-summit-2022-webassembly-python-in-the-browser-and-beyond
 20 | 
 21 | 
 22 | if you don't need pygame linked to cpython then prefer for final size reasons :
 23 | 
 24 |  just cpython on wasm see python-wasm https://github.com/ethanhs/python-wasm/
 25 | 
 26 | or the classics :
 27 | 
 28 | for scientific python see pyodide https://pyodide.org
 29 | 
 30 | for cpython+panda3d see https://rdb.name/panda3d-webgl.md.html or/and PyDK
 31 | 
 32 | 
 33 | Discussions very welcomed here French/English:
 34 |   https://gitter.im/Wasm-Python/community
 35 | 
 36 | English only:
 37 | WebAssembly/python on https://discord.gg/MCTM4xFDMK
 38 | 
 39 | 
 40 | NOTE: ~~as time of cpython pre-3.11a7, released cython does not handle it - only git version - so pygame-wasm is not upstreamed yet
 41 | this is only temporary.~~ pygame-wasm has been upstreamed
 42 | 
 43 | WIP:
 44 | https://github.com/pmp-p/pygame-wasm/tree/pygame-wasm-static
 45 | 
 46 | ready to use:
 47 | 
 48 | https://github.com/pmp-p/pygame-wasm/tree/pygame-wasm-upstream
 49 | 
 50 | 
 51 | devlog:
 52 | https://github.com/pygame/pygame/issues/718
 53 | 
 54 | 
 55 | 
 56 | ***REQUIRED:***
 57 | 
 58 |     1 GNU/Linux system with clang, git, libffi-dev, libssl dev (1.1.1), zlib1g-dev, patch, bash and make
 59 |        for the simulator add sdl2-dev + sdl_* dev.
 60 | 
 61 |     everything else will be downloaded.
 62 |     includes emsdk , cpython , cython, pygame, various imaging lib ...
 63 | 
 64 | 
 65 | ***TESTING:***
 66 | 
 67 |     # need a browser with wasm + WebGL, see https://developer.mozilla.org/en-US/docs/WebAssembly#browser_compatibility
 68 |     # ( on android kitkat please use Bromite release 81.0.4044.83 or chrome/firefox, the webview will NOT work )
 69 |     chromium engine based browsers are faster and also impose some limitations so they are the common denominator for Wasm.
 70 |     most of testing was made on current Brave browser on 64bits GNU/Linux.
 71 | 
 72 | 
 73 | 
 74 |     # (facultative you can use prebuilt) run :
 75 | 
 76 |     ./python-wasm-plus.sh
 77 | 
 78 |     # then run :
 79 | 
 80 |     ./buildapp.sh
 81 | 
 82 |     # navigate to http://localhost:8000 manually or :
 83 | 
 84 |     xdg-open http://localhost:8000
 85 | 
 86 |     #type in the terminal followed  by enter at the python prompt:
 87 | 
 88 |     execfile("touchpong.py")
 89 | 
 90 |     #enjoy a classic
 91 | 
 92 |     #mouse click first out of terminal, then onto canvas.
 93 |     # then move up/down with f,v keys.
 94 | 
 95 | 
 96 | ***USING GITHUB ACTIONS TO PUBLISH SOFTWARE:***
 97 | 
 98 | add `support/__EMSCRIPTEN__.yml` to your `.github/workflows/` folder
 99 | create a folder name `static` at base of your repo
100 | 
101 | in that folder add `static/index.html`
102 | containing eg :
103 | 
104 | `My App`
105 | 
106 | and the main.py but as as the fully qualified domain name eg `static/org.python.myapp.py`
107 | 
108 | everything in the "static" folder will be accessible as single files for the webserver, everything else will go
109 | inside folder "assets" in the apk zip file named after fqdn eg here `org.python.myapp.apk` .
110 | 
111 | After CI completed  ( expect a bit more than 30 minutes ) go to  `https://.github.io//`
112 | 
113 | use ctrl+shift+i to see the wasm/js console while running your app.
114 | 
115 | 
116 | ***CREDITS:***
117 | 
118 |     touchpong.py could be shareware so if you like it, send an expensive thank you
119 |     to @blubberquark on Pygame Community discord ;)
120 | 
121 |     emscripten interface use code from Panda3D project written by https://github.com/rdb  and  regularly modified to accomodate emsdk tip-of-tree.
122 | 
123 | 
124 | ***MORE?:***
125 | 
126 |     multithreaded version with online file access and dynamic code is still brewing
127 |     feel free to contact me if you have interest in more than single threaded demos.
128 | 


--------------------------------------------------------------------------------
/scripts/cpython-build-host-prebuilt.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | . ${CONFIG:-config}
  4 | 
  5 | echo "
  6 |     *   cpython-build-host-prebuilt pip==$PIP   *
  7 | " 1>&2
  8 | 
  9 | 
 10 | # https://stackoverflow.com/questions/6301003/stopping-setup-py-from-installing-as-egg
 11 | # python3 setup.py install --single-version-externally-managed --root=/
 12 | SPY="$HPY setup.py install --single-version-externally-managed --root=/"
 13 | 
 14 | 
 15 | # just in case
 16 | $PIP install pip --upgrade
 17 | 
 18 | 
 19 | # to remove ctypes deps
 20 | $PIP install setuptools --upgrade
 21 | 
 22 | 
 23 | HPFX=./devices/x86_64/usr/lib/python${PYBUILD}
 24 | 
 25 | rm -rf $HPFX/ensurepip/_bundled/*-py3-none-any.whl
 26 | 
 27 | if [ -f $HPFX/site-packages/distutils-precedence.pth ]
 28 | then
 29 |     mv $HPFX/site-packages/distutils-precedence.pth $HPFX/
 30 | fi
 31 | 
 32 | for moveit in setuptools _distutils _distutils_hack pkg_resources
 33 | do
 34 |     if [ -d $HPFX/site-packages/${moveit} ]
 35 |     then
 36 |         echo "
 37 |         * migrating ${moveit}
 38 |         "  1>&2
 39 |         rm -rf $HPFX/${moveit}
 40 |         rm -rf $HPFX/${moveit}-*
 41 |         mv $HPFX/site-packages/${moveit}  $HPFX/
 42 |         mv $HPFX/site-packages/${moveit}-* $HPFX/
 43 |     fi
 44 | done
 45 | 
 46 | 
 47 | 
 48 | 
 49 | export CC=clang
 50 | 
 51 | rm -fr $ROOT/build/pycache/*
 52 | 
 53 | 
 54 | git_update () {
 55 |     SRC=$(basename $1)
 56 |     echo "
 57 |         * updating $SRC
 58 |     " 1>&2
 59 |     if [ -d $SRC ]
 60 |     then
 61 |         pushd $SRC
 62 |         if git pull||grep -q 'Already up to date'
 63 |         then
 64 |             export REBUILD=${REBUILD:-false}
 65 |         else
 66 |             export REBUILD=true
 67 |         fi
 68 |         popd
 69 |     else
 70 |         git clone $1
 71 |     fi
 72 | }
 73 | 
 74 | #===================================================================
 75 | 
 76 | mkdir -p src
 77 | pushd src
 78 | 
 79 | if false
 80 | then
 81 |     # pcpp   https://pypi.org/project/pcpp/
 82 |     # A C99 preprocessor written in pure Python
 83 |     $PIP install pcpp --user
 84 | fi
 85 | 
 86 | 
 87 | if $HPY -c "import pymunk4"
 88 | then
 89 |     echo "
 90 |         * token-utils, pycparser, cffi, pymunk already installed
 91 |     " 1>&2
 92 | else
 93 | 
 94 |     # https://github.com/aroberge/ideas, for code transformation
 95 |     $PIP install token-utils
 96 | 
 97 |     for req in pycparser
 98 |     do
 99 |         pip3 download --dest $(pwd) --no-binary :all: $req
100 |         archive=$(echo -n $req-*z)
101 |         echo $archive  1>&2
102 |         tar xfz $archive && rm $archive
103 |         pushd $req-*
104 |         $PIP install .
105 |         popd
106 |     done
107 | 
108 | 
109 |     rm cffi-branch-default.zip
110 |     wget -q https://foss.heptapod.net/pypy/cffi/-/archive/branch/default/cffi-branch-default.zip
111 |     unzip -o -q cffi-branch-default.zip
112 | 
113 |     pushd cffi-branch-default
114 |         $PIP install .
115 |     popd
116 | 
117 | 
118 |     if [ -d pymunk-4.0.0 ]
119 |     then
120 |         pushd pymunk-4.0.0
121 | 
122 |         [ -d $HOST_PREFIX/lib/python${PYBUILD}/site-packages/pymunk4 ] && rm -rf $HOST_PREFIX/lib/python${PYBUILD}/site-packages/pymunk4
123 | 
124 |         rm -f  pymunk/libchipmunk*.so build/lib/pymunk/* chipmunk_src/*.so chipmunk_src/*/*.o
125 | 
126 |         $HPY setup.py build_chipmunk
127 | 
128 |         $SPY
129 | 
130 |         mv $HOST_PREFIX/lib/python${PYBUILD}/site-packages/pymunk/libchipmunk.so \
131 |             $HOST_PREFIX/lib/python${PYBUILD}/site-packages/pymunk/libchipmunk64.so
132 |         mv $HOST_PREFIX/lib/python${PYBUILD}/site-packages/pymunk \
133 |             $HOST_PREFIX/lib/python${PYBUILD}/site-packages/pymunk4
134 |         popd
135 |     fi
136 | 
137 | fi
138 | 
139 | 
140 | ## cython 3 ( not out yet )
141 | #if $HPY -m cython -V 2>&1|grep -q 'version 3.0.'
142 | #then
143 | #    echo  found cython 3+
144 | #else
145 | #    git_update https://github.com/cython/cython
146 | #    pushd cython
147 | #    $PIP install .
148 | #    popd
149 | #fi
150 | 
151 | 
152 | # ${ROOT}/bin/python3-${ABI_NAME} -m pip $MODE --use-feature=2020-resolver --no-use-pep517 --no-binary :all: $@
153 | #for req in $(find "${ORIGIN}/projects" -maxdepth 2 -type f |grep /requirements.txt$)
154 | 
155 | # TODO: build/patch from sources pip packages here.
156 | # ${ROOT}/bin/pip3 download --dest ${CROSSDIR} --no-binary :all: setuptools pip
157 | 
158 | popd
159 | 
160 | 
161 | 
162 | 
163 | 
164 | 
165 | 
166 | 
167 | 
168 | 
169 | unset CC
170 | 
171 | 
172 | 
173 | 
174 | 
175 | 
176 | 
177 | 
178 | 
179 | 
180 | 
181 | 
182 | 
183 | 
184 | 
185 | 
186 | 
187 | 
188 | 
189 | 
190 | 
191 | 
192 | 
193 | 
194 | 
195 | #
196 | 


--------------------------------------------------------------------------------
/tests/assets/cpython.six:
--------------------------------------------------------------------------------
1 | Pq"1;1;70;91#0;2;97;97;97#1;2;82;82;82#2;2;88;88;88#3;2;41;41;41#4;2;78;78;78#5;2;72;72;72#6;2;56;56;56#7;2;53;53;53#8;2;91;91;91#9;2;66;66;66#10;2;44;44;44#11;2;75;75;75#12;2;47;47;47#13;2;63;63;63#14;2;94;94;97#15;2;78;85;88#16;2;75;78;85#17;2;69;75;82#18;2;56;66;75#19;2;50;60;72#20;2;38;56;72#21;2;66;72;75#22;2;94;97;97#23;2;88;91;94#24;2;53;63;75#25;2;31;50;69#26;2;22;44;63#27;2;25;44;60#28;2;35;50;63#29;2;85;88;91#30;2;82;85;88#31;2;19;41;60#32;2;38;53;66#33;2;91;94;94#34;2;25;47;66#35;2;60;69;78#36;2;25;44;63#37;2;97;97;94#38;2;97;97;91#39;2;97;88;66#40;2;97;82;28#41;2;97;82;41#42;2;97;91;72#43;2;35;53;72#44;2;97;78;25#45;2;97;88;63#46;2;97;94;82#47;2;56;69;78#48;2;97;85;47#49;2;97;91;78#50;2;63;69;75#51;2;97;82;31#52;2;97;78;22#53;2;97;82;38#54;2;78;82;85#55;2;75;82;88#56;2;97;97;88#57;2;56;63;69#58;2;28;41;53#59;2;88;88;91#60;2;41;50;60#61;2;72;75;78#62;2;47;53;63#63;2;50;56;66#64;2;66;69;75#65;2;53;60;69#66;2;35;47;56#67;2;63;66;72#68;2;72;75;82#69;2;25;41;50#70;2;31;41;53#71;2;63;69;72#72;2;50;60;66#73;2;75;78;82#0!34~NFF!33~$#2!34?o?G$#1!35?G#4o$#3!35?o-#0!7~NF!4fFN^~FFF!4~FFF~f??ff~???FffFFN~~NNFfffFN^~NN!4fFFN!6~$#10!7?_O#9O???_!4?G!6?G??G??G!4?_?OGG!9?W!4?_??G??G$#11!7?O#2G??O???_???G!6?o!5?O?~!6?G!9?G!7?O??G$#13!8?_#5G??O?O#8??G!8?G#4?O??O!4?N?GO!8?O???O!4?G??O_?_$#1!10?O!6?o?o!4?G#7!4?ee!5?OO!8?O??G!6?O???G$#6!10?G?G#3O_???o!6?o!9?~!5?O#1O!6?O!5?O??O#6G$#7!11?G#4?G#11!10?o!7?G#8!4?g??_!4?O?_!5?_!9?O$#10!29?GG!10?_!9?O_!8?OO$#12!29?OO#13!14?_!5?_!5?O$#5!29?@#6@!9?O?_!4?OG#3!7?_!5?_$#12!46?_#5G-#0!7~??!4~???~???!4~???~~??~~~???!4~??~_??^~~~C?_~??!4~???!6~$#10!7?~!6?_#11P!8?^#7!4?^^#4!5?~!7?C?M!6?O!9?~$#6!8?_!4?_?C???_!9?_#12_#6!10?@!9?_?C$#13!8?^!6?I#9!8?_#13!16?}!4?O!6?A$#2!13?M???_!8?~!7?~!9?@??_???G!9?~$#1!13?@???^?N#10!22?~??O#7!6?_#9G?~$#4!13?O!5?O#1!24?I!6?P#11?@$#3!14?^???~!6?~!9?~!9?N_!5?^???~!5?~$#8!15?_!28?O!6?A$#5!45?_@-#0!7~??!5{}~~~}{[[[K?_{~~}{{{~{{{!4~{{~~~}!4{}}~~{{!4~}{{!6~$#10!7?~!5?@!9?_@#8?A!7?A?A#13!4?@#10@#9???@!8?@#3@!5?@$!8?@#2A???A!5?A_??A??@???A?@?@!6?A#1!5?A??A#8?@#2??A!5?@?A$#13!8?}#12@#4A???@!7?AOEO!6?A??A@!5?A!6?@!6?A!5?A@$#9!10?@A#11A!7?A???_!6?A#12!15?@#5@A#6@@$#5!11?@!6?@??b#9@?G!6?@#11!16?A$#7!12?@!7?@??@?G#1???@$#3!19?@!4?OF!4?@!4?@$#6!22?_-#0!7~}}!11~!4}~^NN!14FN^!26~$#1!7?@#4@#2!11?@#11@#1@#8@#29?_#25_?O#15G#16G!8?G#27O?_#24_$#23!26?O#26__!11o__#17O$#24!27?O#14G#17??G#18G!4?G#21G#15?G#22G$#19!33?G??G#28!4?O$#20!34?GG-#0!24~B???EEC#27!12?@{#0B!24~$#33!24?{#25A?@?O?A#31!11?}#17@#14C$#34!25?{??O#22GA#32!13?A#23w$#19!25?@#26~o__ox!11~$#32!27?G???C$#17!27?A@?G$#16!27?C#23G#30@#18@-#0!15~NFBBB!4@#26!11w{!7~#31~#27~#23~#0!5@BBFN!15~$#33!15?O!5?!13A#23A#36@#37!10?A???A#41C#42C#45G#46O$#47!15?_#34_owww{{{!11CA#39!10?{#44!6wo#48_$#43!16?OG#17C#20C#22A#35!4?!10@#40!12?!4C$#23!16?G#14C!6?@#38!22?AAA$#25!20?C-#0!14~#15A#34}!8~#26~~~!13^NNN#8O#51_?C#52!7?{#38@#0!14~$#17!14?C#25@!11?_#18_#16!11_#27OO??@#39G!9?C$#19!14?G#54!25?_#23_#37_??C#48A!8?G$#20!14?O#24!27?O#31F#14G#40O!9?_$#33!14?@#32!28?G#28A#44_w!7~B#49A$#43!14?_#42!28?_#46O#0A#45@#53!8?O$#50!44?C#33@-#0!14~#35G!8?_??@#46???!11@#44}}!11~o#38_#0}!13~$#19!14?C#34!8~FA@#51w{{!9}AAA#42@#48@#52!11?N#40B#37@$#20!14?A#24!8?O#38_!4?@#40!8?{{{#42!14?O$#33!14?_#25!8?G#14G??@#48!27?G$#43!14?@#0!9?O#37CA?@#53!26?C$#55!14?O#26!9?@#41_??A$#47!24?C#42G?A$#16!25?A#45C$#48!25?O-#0!15~{woo!5_#38~#53~#51!9~NNN!5G#37??_!5?O?G#48@$#15!15?A#35C!6?F#46!11?!16O???A$#19!15?@#34BFF!4N#33O#49!11?!10_#0?!6_oo{!15~$#17!17?G!5?G#40!14?FFF#44FF!8NFFB$#43!18?G#23O#30OOO#40!28?G#45GC-#0!24~o#42_#51!12~d?AAC$#38!24?N#48O#40!12?AB@???N$#53!25?N#41!12?W???_?O$#0!39?OWW???o!24~$#39!39?c!4?_$#37!39?G#38_!4?N$#56!40?C#44@B~$#46!41?_#42W$#49!41?C-#0!26~}{!4w!6o!4w{}!18~NN!6~$#45!26?@#51@@BBB!6F?@B@#42A#57!19?O#30o$#49!27?A#48A??C!6?C!4?@#58!18?_$#37!28?C!8?G???C#44@$#46!29?C#39C!8?C#46C#41A$#38!32?GG??G#40?BA$#56!34?GG-#0!7~FBrrbBN~NFbrrFF^bBN~NBBN~FB~FFRRBF^~FFrrr^FBRRFN~NFbrrb??!6~$#66!7?o!4?O#65??_???G!9?G#14O?G!6?C#63O!4?G!7?G_#66??_G#64GG#8C#69G#30F$#16!7?Go?C#14O#63G#21???G#23S??_???CO???C!7?__#60G???OG!4?OG??O!7?G$!8?G!4?_???G??GO#33?C#62G!8?G??G#68??_#59G!6?K#58?_!7?O!4?v$#22!8?C???C#70???O#64?G!4?G!9?O!4?GO!4?O#16?C???O!7?OC#33?O$#30!9?C?C???O???C??_O???O!5?C???CC!9?_??CC#61?O#68??G$#57!9?G??_#72???_#54?C#71?O#58_??O#68_#61?_#70Oo!5?_!4?_#22_#29?G?C???G#54_!9?C??w$#61!10?G??O#59!7?G#66??_???G#16?_#67?_??OOG!8?G#14???C#23__???O?C$#62!11?G#21!16?_!7?_#66!6?_#73_#21!6?G!4?_$#8!28?C#54???O_#33?G#57!16?G_-#0!7~??fnf_o}o_fnf`ow~{_`o}w_`o~}o_emeeu~__~~~w__!4e~w_bnffoo!6~$#66!7?~!8?C!8?C#69G!4?G#68C!7?G#22G!7?O??G!7?G#68O#58F#54F$#57!8?O!7?AO!8?O#61C#23@???G#8?@#63?@??O#14?@!8?A!7?C$#65!8?GO#60O!4?@G#33??GA#16?@!6?A!6?O???O!7?@!5?G?C!4?G$!8?f#59G#62?OCC?A??O!6?@?B!9?O#57?@#65???O#73N#23???C??G!5?O!5?G$#68!11?G!8?O#71???@#28?C#65??@H?A#64???C#59??G#66???N#58!5?E#60GOO!4?I!4?G$#54!12?O!9?A???A???OA???GAG!6?O???A#69@#57@??P??@?O?O$#58!12?G!8?B???A!9?B#71!13?G#30C??GO#62??@?O$#64!12?A!4?G???G#14!7?C#60?C@??C??O#64!11?O#67@@???A?G$#21!12?@#70B!7?C!8?E!5?G#50!17?@#70??C$#30!13?G!6?C???AO?G$#22!14?@#14G#67@!8?G!5?O!5?@@?@$#61!15?C#8O!5?C$#63!19?OG-#0!7~ww!61~$#66!7?B#16B$#71!7?C#54C-#0!70@\


--------------------------------------------------------------------------------
/demos/org.python3.11.0/cpython.six:
--------------------------------------------------------------------------------
1 | Pq"1;1;70;91#0;2;97;97;97#1;2;82;82;82#2;2;88;88;88#3;2;41;41;41#4;2;78;78;78#5;2;72;72;72#6;2;56;56;56#7;2;53;53;53#8;2;91;91;91#9;2;66;66;66#10;2;44;44;44#11;2;75;75;75#12;2;47;47;47#13;2;63;63;63#14;2;94;94;97#15;2;78;85;88#16;2;75;78;85#17;2;69;75;82#18;2;56;66;75#19;2;50;60;72#20;2;38;56;72#21;2;66;72;75#22;2;94;97;97#23;2;88;91;94#24;2;53;63;75#25;2;31;50;69#26;2;22;44;63#27;2;25;44;60#28;2;35;50;63#29;2;85;88;91#30;2;82;85;88#31;2;19;41;60#32;2;38;53;66#33;2;91;94;94#34;2;25;47;66#35;2;60;69;78#36;2;25;44;63#37;2;97;97;94#38;2;97;97;91#39;2;97;88;66#40;2;97;82;28#41;2;97;82;41#42;2;97;91;72#43;2;35;53;72#44;2;97;78;25#45;2;97;88;63#46;2;97;94;82#47;2;56;69;78#48;2;97;85;47#49;2;97;91;78#50;2;63;69;75#51;2;97;82;31#52;2;97;78;22#53;2;97;82;38#54;2;78;82;85#55;2;75;82;88#56;2;97;97;88#57;2;56;63;69#58;2;28;41;53#59;2;88;88;91#60;2;41;50;60#61;2;72;75;78#62;2;47;53;63#63;2;50;56;66#64;2;66;69;75#65;2;53;60;69#66;2;35;47;56#67;2;63;66;72#68;2;72;75;82#69;2;25;41;50#70;2;31;41;53#71;2;63;69;72#72;2;50;60;66#73;2;75;78;82#0!34~NFF!33~$#2!34?o?G$#1!35?G#4o$#3!35?o-#0!7~NF!4fFN^~FFF!4~FFF~f??ff~???FffFFN~~NNFfffFN^~NN!4fFFN!6~$#10!7?_O#9O???_!4?G!6?G??G??G!4?_?OGG!9?W!4?_??G??G$#11!7?O#2G??O???_???G!6?o!5?O?~!6?G!9?G!7?O??G$#13!8?_#5G??O?O#8??G!8?G#4?O??O!4?N?GO!8?O???O!4?G??O_?_$#1!10?O!6?o?o!4?G#7!4?ee!5?OO!8?O??G!6?O???G$#6!10?G?G#3O_???o!6?o!9?~!5?O#1O!6?O!5?O??O#6G$#7!11?G#4?G#11!10?o!7?G#8!4?g??_!4?O?_!5?_!9?O$#10!29?GG!10?_!9?O_!8?OO$#12!29?OO#13!14?_!5?_!5?O$#5!29?@#6@!9?O?_!4?OG#3!7?_!5?_$#12!46?_#5G-#0!7~??!4~???~???!4~???~~??~~~???!4~??~_??^~~~C?_~??!4~???!6~$#10!7?~!6?_#11P!8?^#7!4?^^#4!5?~!7?C?M!6?O!9?~$#6!8?_!4?_?C???_!9?_#12_#6!10?@!9?_?C$#13!8?^!6?I#9!8?_#13!16?}!4?O!6?A$#2!13?M???_!8?~!7?~!9?@??_???G!9?~$#1!13?@???^?N#10!22?~??O#7!6?_#9G?~$#4!13?O!5?O#1!24?I!6?P#11?@$#3!14?^???~!6?~!9?~!9?N_!5?^???~!5?~$#8!15?_!28?O!6?A$#5!45?_@-#0!7~??!5{}~~~}{[[[K?_{~~}{{{~{{{!4~{{~~~}!4{}}~~{{!4~}{{!6~$#10!7?~!5?@!9?_@#8?A!7?A?A#13!4?@#10@#9???@!8?@#3@!5?@$!8?@#2A???A!5?A_??A??@???A?@?@!6?A#1!5?A??A#8?@#2??A!5?@?A$#13!8?}#12@#4A???@!7?AOEO!6?A??A@!5?A!6?@!6?A!5?A@$#9!10?@A#11A!7?A???_!6?A#12!15?@#5@A#6@@$#5!11?@!6?@??b#9@?G!6?@#11!16?A$#7!12?@!7?@??@?G#1???@$#3!19?@!4?OF!4?@!4?@$#6!22?_-#0!7~}}!11~!4}~^NN!14FN^!26~$#1!7?@#4@#2!11?@#11@#1@#8@#29?_#25_?O#15G#16G!8?G#27O?_#24_$#23!26?O#26__!11o__#17O$#24!27?O#14G#17??G#18G!4?G#21G#15?G#22G$#19!33?G??G#28!4?O$#20!34?GG-#0!24~B???EEC#27!12?@{#0B!24~$#33!24?{#25A?@?O?A#31!11?}#17@#14C$#34!25?{??O#22GA#32!13?A#23w$#19!25?@#26~o__ox!11~$#32!27?G???C$#17!27?A@?G$#16!27?C#23G#30@#18@-#0!15~NFBBB!4@#26!11w{!7~#31~#27~#23~#0!5@BBFN!15~$#33!15?O!5?!13A#23A#36@#37!10?A???A#41C#42C#45G#46O$#47!15?_#34_owww{{{!11CA#39!10?{#44!6wo#48_$#43!16?OG#17C#20C#22A#35!4?!10@#40!12?!4C$#23!16?G#14C!6?@#38!22?AAA$#25!20?C-#0!14~#15A#34}!8~#26~~~!13^NNN#8O#51_?C#52!7?{#38@#0!14~$#17!14?C#25@!11?_#18_#16!11_#27OO??@#39G!9?C$#19!14?G#54!25?_#23_#37_??C#48A!8?G$#20!14?O#24!27?O#31F#14G#40O!9?_$#33!14?@#32!28?G#28A#44_w!7~B#49A$#43!14?_#42!28?_#46O#0A#45@#53!8?O$#50!44?C#33@-#0!14~#35G!8?_??@#46???!11@#44}}!11~o#38_#0}!13~$#19!14?C#34!8~FA@#51w{{!9}AAA#42@#48@#52!11?N#40B#37@$#20!14?A#24!8?O#38_!4?@#40!8?{{{#42!14?O$#33!14?_#25!8?G#14G??@#48!27?G$#43!14?@#0!9?O#37CA?@#53!26?C$#55!14?O#26!9?@#41_??A$#47!24?C#42G?A$#16!25?A#45C$#48!25?O-#0!15~{woo!5_#38~#53~#51!9~NNN!5G#37??_!5?O?G#48@$#15!15?A#35C!6?F#46!11?!16O???A$#19!15?@#34BFF!4N#33O#49!11?!10_#0?!6_oo{!15~$#17!17?G!5?G#40!14?FFF#44FF!8NFFB$#43!18?G#23O#30OOO#40!28?G#45GC-#0!24~o#42_#51!12~d?AAC$#38!24?N#48O#40!12?AB@???N$#53!25?N#41!12?W???_?O$#0!39?OWW???o!24~$#39!39?c!4?_$#37!39?G#38_!4?N$#56!40?C#44@B~$#46!41?_#42W$#49!41?C-#0!26~}{!4w!6o!4w{}!18~NN!6~$#45!26?@#51@@BBB!6F?@B@#42A#57!19?O#30o$#49!27?A#48A??C!6?C!4?@#58!18?_$#37!28?C!8?G???C#44@$#46!29?C#39C!8?C#46C#41A$#38!32?GG??G#40?BA$#56!34?GG-#0!7~FBrrbBN~NFbrrFF^bBN~NBBN~FB~FFRRBF^~FFrrr^FBRRFN~NFbrrb??!6~$#66!7?o!4?O#65??_???G!9?G#14O?G!6?C#63O!4?G!7?G_#66??_G#64GG#8C#69G#30F$#16!7?Go?C#14O#63G#21???G#23S??_???CO???C!7?__#60G???OG!4?OG??O!7?G$!8?G!4?_???G??GO#33?C#62G!8?G??G#68??_#59G!6?K#58?_!7?O!4?v$#22!8?C???C#70???O#64?G!4?G!9?O!4?GO!4?O#16?C???O!7?OC#33?O$#30!9?C?C???O???C??_O???O!5?C???CC!9?_??CC#61?O#68??G$#57!9?G??_#72???_#54?C#71?O#58_??O#68_#61?_#70Oo!5?_!4?_#22_#29?G?C???G#54_!9?C??w$#61!10?G??O#59!7?G#66??_???G#16?_#67?_??OOG!8?G#14???C#23__???O?C$#62!11?G#21!16?_!7?_#66!6?_#73_#21!6?G!4?_$#8!28?C#54???O_#33?G#57!16?G_-#0!7~??fnf_o}o_fnf`ow~{_`o}w_`o~}o_emeeu~__~~~w__!4e~w_bnffoo!6~$#66!7?~!8?C!8?C#69G!4?G#68C!7?G#22G!7?O??G!7?G#68O#58F#54F$#57!8?O!7?AO!8?O#61C#23@???G#8?@#63?@??O#14?@!8?A!7?C$#65!8?GO#60O!4?@G#33??GA#16?@!6?A!6?O???O!7?@!5?G?C!4?G$!8?f#59G#62?OCC?A??O!6?@?B!9?O#57?@#65???O#73N#23???C??G!5?O!5?G$#68!11?G!8?O#71???@#28?C#65??@H?A#64???C#59??G#66???N#58!5?E#60GOO!4?I!4?G$#54!12?O!9?A???A???OA???GAG!6?O???A#69@#57@??P??@?O?O$#58!12?G!8?B???A!9?B#71!13?G#30C??GO#62??@?O$#64!12?A!4?G???G#14!7?C#60?C@??C??O#64!11?O#67@@???A?G$#21!12?@#70B!7?C!8?E!5?G#50!17?@#70??C$#30!13?G!6?C???AO?G$#22!14?@#14G#67@!8?G!5?O!5?@@?@$#61!15?C#8O!5?C$#63!19?OG-#0!7~ww!61~$#66!7?B#16B$#71!7?C#54C-#0!70@\


--------------------------------------------------------------------------------
/templates/libs/xterm/xtermjsixel/xterm.css:
--------------------------------------------------------------------------------
  1 | /**
  2 |  * Copyright (c) 2014 The xterm.js authors. All rights reserved.
  3 |  * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
  4 |  * https://github.com/chjj/term.js
  5 |  * @license MIT
  6 |  *
  7 |  * Permission is hereby granted, free of charge, to any person obtaining a copy
  8 |  * of this software and associated documentation files (the "Software"), to deal
  9 |  * in the Software without restriction, including without limitation the rights
 10 |  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 11 |  * copies of the Software, and to permit persons to whom the Software is
 12 |  * furnished to do so, subject to the following conditions:
 13 |  *
 14 |  * The above copyright notice and this permission notice shall be included in
 15 |  * all copies or substantial portions of the Software.
 16 |  *
 17 |  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 18 |  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 19 |  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 20 |  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 21 |  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 22 |  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 23 |  * THE SOFTWARE.
 24 |  *
 25 |  * Originally forked from (with the author's permission):
 26 |  *   Fabrice Bellard's javascript vt100 for jslinux:
 27 |  *   http://bellard.org/jslinux/
 28 |  *   Copyright (c) 2011 Fabrice Bellard
 29 |  *   The original design remains. The terminal itself
 30 |  *   has been extended to include xterm CSI codes, among
 31 |  *   other features.
 32 |  */
 33 | 
 34 | /**
 35 |  *  Default styles for xterm.js
 36 |  */
 37 | 
 38 | .xterm {
 39 |     position: relative;
 40 |     user-select: none;
 41 |     -ms-user-select: none;
 42 |     -webkit-user-select: none;
 43 | }
 44 | 
 45 | .xterm.focus,
 46 | .xterm:focus {
 47 |     outline: none;
 48 | }
 49 | 
 50 | .xterm .xterm-helpers {
 51 |     position: absolute;
 52 |     top: 0;
 53 |     /**
 54 |      * The z-index of the helpers must be higher than the canvases in order for
 55 |      * IMEs to appear on top.
 56 |      */
 57 |     z-index: 5;
 58 | }
 59 | 
 60 | .xterm .xterm-helper-textarea {
 61 |     padding: 0;
 62 |     border: 0;
 63 |     margin: 0;
 64 |     /* Move textarea out of the screen to the far left, so that the cursor is not visible */
 65 |     position: absolute;
 66 |     opacity: 0;
 67 |     left: -9999em;
 68 |     top: 0;
 69 |     width: 0;
 70 |     height: 0;
 71 |     z-index: -5;
 72 |     /** Prevent wrapping so the IME appears against the textarea at the correct position */
 73 |     white-space: nowrap;
 74 |     overflow: hidden;
 75 |     resize: none;
 76 | }
 77 | 
 78 | .xterm .composition-view {
 79 |     /* TODO: Composition position got messed up somewhere */
 80 |     background: #000;
 81 |     color: #FFF;
 82 |     display: none;
 83 |     position: absolute;
 84 |     white-space: nowrap;
 85 |     z-index: 1;
 86 | }
 87 | 
 88 | .xterm .composition-view.active {
 89 |     display: block;
 90 | }
 91 | 
 92 | .xterm .xterm-viewport {
 93 |     /* On OS X this is required in order for the scroll bar to appear fully opaque */
 94 |     background-color: #000;
 95 |     overflow-y: scroll;
 96 |     cursor: default;
 97 |     position: absolute;
 98 |     right: 0;
 99 |     left: 0;
100 |     top: 0;
101 |     bottom: 0;
102 | }
103 | 
104 | .xterm .xterm-screen {
105 |     position: relative;
106 | }
107 | 
108 | .xterm .xterm-screen canvas {
109 |     position: absolute;
110 |     left: 0;
111 |     top: 0;
112 | }
113 | 
114 | .xterm .xterm-scroll-area {
115 |     visibility: hidden;
116 | }
117 | 
118 | .xterm-char-measure-element {
119 |     display: inline-block;
120 |     visibility: hidden;
121 |     position: absolute;
122 |     top: 0;
123 |     left: -9999em;
124 |     line-height: normal;
125 | }
126 | 
127 | .xterm {
128 |     cursor: text;
129 | }
130 | 
131 | .xterm.enable-mouse-events {
132 |     /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
133 |     cursor: default;
134 | }
135 | 
136 | .xterm.xterm-cursor-pointer,
137 | .xterm .xterm-cursor-pointer {
138 |     cursor: pointer;
139 | }
140 | 
141 | .xterm.column-select.focus {
142 |     /* Column selection mode */
143 |     cursor: crosshair;
144 | }
145 | 
146 | .xterm .xterm-accessibility,
147 | .xterm .xterm-message {
148 |     position: absolute;
149 |     left: 0;
150 |     top: 0;
151 |     bottom: 0;
152 |     right: 0;
153 |     z-index: 10;
154 |     color: transparent;
155 | }
156 | 
157 | .xterm .live-region {
158 |     position: absolute;
159 |     left: -9999px;
160 |     width: 1px;
161 |     height: 1px;
162 |     overflow: hidden;
163 | }
164 | 
165 | .xterm-dim {
166 |     opacity: 0.5;
167 | }
168 | 
169 | .xterm-underline {
170 |     text-decoration: underline;
171 | }
172 | 
173 | .xterm-strikethrough {
174 |     text-decoration: line-through;
175 | }
176 | 


--------------------------------------------------------------------------------
/tests/code/testjoy.py:
--------------------------------------------------------------------------------
  1 | #!/bin/env python3.11
  2 | 
  3 | import pygame as pg
  4 | 
  5 | try:
  6 |     __EMSCRIPTEN__
  7 | except:
  8 |     __EMSCRIPTEN__ = False
  9 | 
 10 | # Define some colors.
 11 | BLACK = pg.Color('black')
 12 | WHITE = pg.Color('white')
 13 | 
 14 | 
 15 | # This is a simple class that will help us print to the screen.
 16 | # It has nothing to do with the joysticks, just outputting the
 17 | # information.
 18 | class Texblit(object):
 19 |     def __init__(self):
 20 |         self.reset()
 21 |         self.font = pg.font.Font(None, 20)
 22 | 
 23 |     def blit(self, screen, textString):
 24 |         textBitmap = self.font.render(textString, True, BLACK)
 25 |         screen.blit(textBitmap, (self.x, self.y))
 26 |         self.y += self.line_height
 27 | 
 28 |     def reset(self):
 29 |         self.x = 10
 30 |         self.y = 10
 31 |         self.line_height = 15
 32 | 
 33 |     def indent(self):
 34 |         self.x += 10
 35 | 
 36 |     def unindent(self):
 37 |         self.x -= 10
 38 | 
 39 | 
 40 | pg.init()
 41 | 
 42 | # Set the width and height of the screen (width, height).
 43 | screen = pg.display.set_mode((500, 700))
 44 | 
 45 | pg.display.set_caption("My Game")
 46 | 
 47 | # Loop until the user clicks the close button.
 48 | done = False
 49 | 
 50 | # Used to manage how fast the screen updates.
 51 | clock = pg.time.Clock()
 52 | 
 53 | # Initialize the joysticks.
 54 | pg.joystick.init()
 55 | 
 56 | # Get ready to print.
 57 | textPrint = Texblit()
 58 | 
 59 | # -------- Main Program Loop -----------
 60 | def loop():
 61 |     global screen, done, clock, textPrint, BLACK, WHITE
 62 | 
 63 |     while not done:
 64 |         #
 65 |         # EVENT PROCESSING STEP
 66 |         #
 67 |         # Possible joystick actions: JOYAXISMOTION, JOYBALLMOTION, JOYBUTTONDOWN,
 68 |         # JOYBUTTONUP, JOYHATMOTION
 69 |         for event in pg.event.get(): # User did something.
 70 |             if event.type == pg.QUIT: # If user clicked close.
 71 |                 done = True # Flag that we are done so we exit this loop.
 72 |             elif event.type == pg.JOYBUTTONDOWN:
 73 |                 print("Joystick button pressed.")
 74 |             elif event.type == pg.JOYBUTTONUP:
 75 |                 print("Joystick button released.")
 76 | 
 77 |         #
 78 |         # DRAWING STEP
 79 |         #
 80 |         # First, clear the screen to white. Don't put other drawing commands
 81 |         # above this, or they will be erased with this command.
 82 |         screen.fill(WHITE)
 83 |         textPrint.reset()
 84 | 
 85 |         # Get count of joysticks.
 86 |         joystick_count = pg.joystick.get_count()
 87 | 
 88 |         textPrint.blit(screen, "Number of joysticks: {}".format(joystick_count))
 89 |         textPrint.indent()
 90 | 
 91 |         # For each joystick:
 92 |         for i in range(joystick_count):
 93 |             joystick = pg.joystick.Joystick(i)
 94 |             joystick.init()
 95 | 
 96 |             textPrint.blit(screen, "Joystick {}".format(i))
 97 |             textPrint.indent()
 98 | 
 99 |             # Get the name from the OS for the controller/joystick.
100 |             name = joystick.get_name()
101 |             textPrint.blit(screen, "Joystick name: {}".format(name))
102 | 
103 |             # Usually axis run in pairs, up/down for one, and left/right for
104 |             # the other.
105 |             axes = joystick.get_numaxes()
106 |             textPrint.blit(screen, "Number of axes: {}".format(axes))
107 |             textPrint.indent()
108 | 
109 |             for i in range(axes):
110 |                 axis = joystick.get_axis(i)
111 |                 textPrint.blit(screen, "Axis {} value: {:>6.3f}".format(i, axis))
112 |             textPrint.unindent()
113 | 
114 |             buttons = joystick.get_numbuttons()
115 |             textPrint.blit(screen, "Number of buttons: {}".format(buttons))
116 |             textPrint.indent()
117 | 
118 |             for i in range(buttons):
119 |                 button = joystick.get_button(i)
120 |                 textPrint.blit(screen,
121 |                                  "Button {:>2} value: {}".format(i, button))
122 |             textPrint.unindent()
123 | 
124 |             hats = joystick.get_numhats()
125 |             textPrint.blit(screen, "Number of hats: {}".format(hats))
126 |             textPrint.indent()
127 | 
128 |             # Hat position. All or nothing for direction, not a float like
129 |             # get_axis(). Position is a tuple of int values (x, y).
130 |             for i in range(hats):
131 |                 hat = joystick.get_hat(i)
132 |                 textPrint.blit(screen, "Hat {} value: {}".format(i, str(hat)))
133 |             textPrint.unindent()
134 | 
135 |             textPrint.unindent()
136 | 
137 |         #
138 |         # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT
139 |         #
140 | 
141 |         # Go ahead and update the screen with what we've drawn.
142 |         pg.display.flip()
143 | 
144 |         if __EMSCRIPTEN__:
145 |             break
146 |         # Limit to 20 frames per second.
147 |         clock.tick(20)
148 | 
149 | 
150 | # Close the window and quit.
151 | # If you forget this line, the program will 'hang'
152 | # on exit if running from IDLE.
153 | if __EMSCRIPTEN__:
154 |     aio.steps.append(loop)
155 |     aio.steps.append(pg.display.update)
156 | else:
157 |     loop()
158 |     pg.quit()
159 | 
160 | 


--------------------------------------------------------------------------------
/scripts/emsdk-fetch.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | if [[ -z ${EMSDK+z} ]]
  4 | then
  5 | 
  6 |     . ${CONFIG:-config}
  7 | 
  8 |     if [ -d emsdk ]
  9 |     then
 10 |         echo "
 11 |         * using emsdk from $(realpath emsdk)
 12 |             with sys python $SYS_PYTHON
 13 | " 1>&2
 14 |     else
 15 |         # emsdk could have been deleted for full rebuild
 16 |         rm embuild.done
 17 | 
 18 |         if git clone --no-tags --depth 1 --single-branch --branch main https://github.com/emscripten-core/emsdk.git
 19 |         then
 20 |             pushd emsdk
 21 |             ./emsdk install ${EMFLAVOUR:-latest}
 22 |             ./emsdk activate ${EMFLAVOUR:-latest}
 23 |             popd
 24 |         fi
 25 |     fi
 26 | 
 27 |     export EMSDK_PYTHON=$SYS_PYTHON
 28 | 
 29 |     if [ -f ${SDKROOT}/emsdk/emsdk_env.sh ]
 30 |     then
 31 |         echo "
 32 |         * activating emsdk via emsdk_env.sh with EMSDK_PYTHON=$EMSDK_PYTHON
 33 | " 1>&2
 34 |         . ${SDKROOT}/emsdk/emsdk_env.sh
 35 |         # EMSDK_PYTHON may be cleared, restore it
 36 | 
 37 |     else
 38 |         echo "
 39 |         ERROR cannot find emsdk/emsdk_env.sh in $(pwd)
 40 | " 1>&2
 41 |         exit 41
 42 |     fi
 43 | 
 44 |     export EMSDK_PYTHON=$SYS_PYTHON
 45 | 
 46 |     if [ -f embuild.done ]
 47 |     then
 48 |         echo "
 49 |         * emsdk prereq ok
 50 |     "  1>&2
 51 |     else
 52 |         # sdl2_image is too old
 53 |         ALL="libembind libgl libal libhtml5 libstubs libnoexit libsockets"
 54 |         ALL="$ALL libc libdlmalloc libcompiler_rt libc++-noexcept libc++abi-noexcept"
 55 |         ALL="$ALL struct_info libfetch zlib bzip2"
 56 |         ALL="$ALL libpng libjpeg freetype harfbuzz"
 57 |         ALL="$ALL sdl2 sdl2_mixer sdl2_gfx sdl2_ttf"
 58 |         ALL="$ALL sqlite3"
 59 | 
 60 |         echo "
 61 |         * building third parties libraries for emsdk ( can take time ... )
 62 |     "  1>&2
 63 | 
 64 |         for one in $ALL
 65 |         do
 66 |             echo "
 67 |             + $done
 68 |     "  1>&2
 69 |             embuilder --pic build $one
 70 |             embuilder build $one
 71 |         done
 72 | 
 73 |         cat > emsdk/upstream/emscripten/emcc < emsdk/upstream/emscripten/em++
139 | 
140 |         cat > emsdk/upstream/emscripten/emar < emsdk/upstream/emscripten/emcmake
151 | 
152 |         cat > emsdk/upstream/emscripten/emconfigure <&1 >/dev/null; then
201 |         export EM_COMPILER_WRAPPER=ccache
202 |         export _EMCC_CCACHE=1
203 |     fi
204 | 
205 |     export EMCC_SKIP_SANITY_CHECK=1
206 |     export EM_IGNORE_SANITY=1
207 | 
208 | else
209 |     echo "emsdk: config already set !" 1>&2
210 | fi
211 | 
212 | 
213 | 


--------------------------------------------------------------------------------
/support/__EMSCRIPTEN__.overlay/pygame/wasm_patches.py:
--------------------------------------------------------------------------------
  1 | import sys
  2 | import asyncio
  3 | import json
  4 | 
  5 | from pathlib import Path
  6 | 
  7 | #=================================================
  8 | # do no change import order for *thread*
  9 | # patching threading.Thread
 10 | import aio.gthread
 11 | # patched module
 12 | from threading import Thread
 13 | #=================================================
 14 | 
 15 | import platform
 16 | 
 17 | 
 18 | pygame = sys.modules[__package__]
 19 | 
 20 | # ====================================================================
 21 | # replace non working native function.
 22 | 
 23 | print(
 24 |     """\
 25 | https://github.com/pygame-web/pygbag/issues/16
 26 |     applying: use aio green thread for pygame.time.set_timer
 27 | """
 28 | )
 29 | 
 30 | # build the event and send it directly in the queue
 31 | # caveats :
 32 | #   - could be possibly very late
 33 | #   - delay cannot be less than frametime at device refresh rate.
 34 | 
 35 | def patch_set_timer(cust_event_no, millis, loops=0):
 36 |     dlay = float(millis) / 1000
 37 |     cevent = pygame.event.Event(cust_event_no)
 38 | 
 39 |     async def fire_event():
 40 |         while true:
 41 |             await asyncio.sleep(dlay)
 42 |             if aio.exit:
 43 |                 break
 44 |             pygame.event.post(cevent)
 45 | 
 46 |     Thread(target=fire_event).start()
 47 | 
 48 | 
 49 | pygame.time.set_timer = patch_set_timer
 50 | 
 51 | # ====================================================================
 52 | # pygame.quit is too hard on gc, and re-importing pygame is problematic
 53 | # if interpreter is not fully renewed.
 54 | # so just clear screen cut music and hope for the best.
 55 | 
 56 | 
 57 | def patch_pygame_quit():
 58 |     pygame.mixer.music.stop()
 59 |     pygame.mixer.music.unload()
 60 |     pygame.display.update()
 61 | 
 62 | 
 63 | pygame.quit = patch_pygame_quit
 64 | 
 65 | 
 66 | # =====================================================================
 67 | # we want fullscreen-windowed template for games as a default
 68 | # so call javascript to resize canvas viewport to fill the current
 69 | # window each time mode is changed, also remove the "scaled" option
 70 | 
 71 | __pygame_display_set_mode__ = pygame.display.set_mode
 72 | 
 73 | 
 74 | def patch_pygame_display_set_mode(size=(0,0), flags=0, depth=0):
 75 |     import platform
 76 | 
 77 |     # apparently no need to remove scaled.
 78 |     if size != (0,0):
 79 |         if (sys.platform == "emscripten") and platform.is_browser:
 80 |             try:
 81 |                 platform.window.window_resize()
 82 |             except:
 83 |                 print("ERROR: browser host does not provide window_resize() function",file=sys.__stderr__)
 84 | 
 85 |     return __pygame_display_set_mode__(size, flags, depth)
 86 | 
 87 | 
 88 | pygame.display.set_mode = patch_pygame_display_set_mode
 89 | 
 90 | 
 91 | #=======================================================================
 92 | # replace sdl thread music playing by browser native player
 93 | #
 94 | 
 95 | tracks = { "current": 0 }
 96 | 
 97 | 
 98 | def patch_pygame_mixer_music_stop_pause_unload():
 99 |     last = tracks["current"]
100 |     if last:
101 |         platform.window.MM.stop(last)
102 |         tracks["current"] = 0
103 | 
104 | pygame.mixer.music.unload = patch_pygame_mixer_music_stop_pause_unload
105 | 
106 | def patch_pygame_mixer_music_load(fileobj, namehint=""):
107 | 
108 |     global tracks
109 | 
110 |     patch_pygame_mixer_music_stop_pause_unload()
111 | 
112 |     tid = tracks.get( fileobj, None)
113 | 
114 |     # stop previously loaded track
115 |     if tid is not None:
116 |         platform.window.MM.stop(tid)
117 |     else:
118 |         # track was never loaded before
119 |         track = patch_pygame_mixer_sound(fileobj, auto=True)
120 |         tid = track.trackid
121 | 
122 |     # set new current track
123 |     tracks["current"] = tid
124 | 
125 | pygame.mixer.music.load = patch_pygame_mixer_music_load
126 | 
127 | # TODO various buffer input
128 | # FIXME tracks hash key
129 | def patch_pygame_mixer_sound(data, auto=False):
130 |     global tracks
131 |     if isinstance(data, (Path,str) ):
132 |         data = str(data)
133 |         trackid = tracks.get(data,None)
134 |         if trackid is not None:
135 |             return tracks[trackid]
136 |     else:
137 |         pdb(__file__, "137 TODO buffer types !")
138 | 
139 |     if Path(data).is_file():
140 |         transport = "fs"
141 |     else:
142 |         transport = "url"
143 | 
144 |     cfg= {
145 |         "url"  : data,
146 |         "type" : "audio",
147 |         "auto" : auto,
148 |         "io" : transport
149 |     }
150 | 
151 |     track = platform.window.MM.prepare(data, json.dumps(cfg))
152 | 
153 |     if track.error:
154 |         pdb("ERROR: on track",cfg)
155 |         # TODO stub track
156 |         return "stub track"
157 | 
158 |     tracks[data] = track.trackid
159 |     tracks[track.trackid] = track
160 |     platform.window.MM.load(track.trackid)
161 |     return track
162 | 
163 | def patch_pygame_mixer_SoundPatch():
164 |     print("pygame mixer SFX patch is already active you can remove this call")
165 | 
166 | pygame.mixer.SoundPatch = patch_pygame_mixer_SoundPatch
167 | 
168 | # 0.1.6 force soundpatch
169 | pygame.mixer.Sound = patch_pygame_mixer_sound
170 | 
171 | 
172 | def patch_pygame_mixer_music_play(loops=0, start=0.0, fade_ms=0):
173 |     trackid = tracks["current"]
174 |     if trackid:
175 |         platform.window.MM.stop(trackid)
176 |         platform.window.MM.play(trackid, loops )
177 |     else:
178 |         pdb(__file__, "ERROR 156: no track is loaded")
179 | 
180 | pygame.mixer.music.play = patch_pygame_mixer_music_play
181 | 
182 | 
183 | 
184 | 
185 | 
186 | 
187 | 
188 | 
189 | 
190 | 
191 | 
192 | 
193 | 
194 | 
195 | 
196 | 
197 | 
198 | 
199 | 
200 | 
201 | 
202 | 
203 | 
204 | 
205 | 
206 | 
207 | 
208 | 
209 | 
210 | # ====================================================================
211 | print("\n\n")
212 | print(open("/data/data/org.python/assets/pygame.six").read())
213 | 


--------------------------------------------------------------------------------
/scripts/cpython-build-emsdk-deps.sh:
--------------------------------------------------------------------------------
  1 | #!/bin/bash
  2 | 
  3 | . ${CONFIG:-config}
  4 | 
  5 | # =============== ncurses ===========================
  6 | # --disable-database --enable-termcap
  7 | NCOPTS="--enable-ext-colors --enable-ext-mouse --prefix=$PREFIX --disable-echo --without-pthread \
  8 |  --without-tests --without-tack --without-progs --without-manpages \
  9 |  --disable-db-install --without-cxx --without-cxx-binding --enable-pc-files \
 10 |  --with-pkg-config-libdir=$PREFIX/lib/pkgconfig \
 11 |  --with-termlib --enable-termcap --disable-database"
 12 | 
 13 | cd $ROOT/src
 14 | 
 15 | if true
 16 | then
 17 | 
 18 |     wget -q -c https://ftp.gnu.org/pub/gnu/ncurses/ncurses-6.1.tar.gz && tar xfz ncurses-6.1.tar.gz
 19 | 
 20 |     pushd ncurses-6.1
 21 |     [ -f patch.done ] || patch -p1 < $ROOT/support/__EMSCRIPTEN__.deps/ncurses-6.1_emscripten.patch
 22 |     touch patch.done
 23 |     popd
 24 | 
 25 |     cd $ROOT
 26 | 
 27 |     if [ -f devices/emsdk/usr/lib/libncursesw.a ]
 28 |     then
 29 |         echo "
 30 |             * ncursesw already built
 31 |         "  1>&2
 32 |     else
 33 |         mkdir -p build/ncurses/
 34 | 
 35 |         # build wide char
 36 |         rm -rf build/ncurses/*
 37 | 
 38 |         pushd build/ncurses
 39 |         make clean
 40 |         CC=clang CFLAGS="-fpic -Wno-unused-command-line-argument" $ROOT/src/ncurses-6.1/configure \
 41 |          $NCOPTS --enable-widec && make && make install
 42 | 
 43 |         popd
 44 |     fi
 45 | 
 46 | fi
 47 | 
 48 | cd $ROOT
 49 | 
 50 | . ./scripts/emsdk-fetch.sh
 51 | 
 52 | # https://download.osgeo.org/libtiff/tiff-4.3.0.tar.gz
 53 | # http://code.google.com/intl/en-US/speed/webp/index.html
 54 | 
 55 | ALL="-fPIC -s USE_SDL=2 -sUSE_LIBPNG -sUSE_LIBJPEG $CPPFLAGS"
 56 | CNF="emconfigure ./configure --prefix=$PREFIX --with-pic --disable-shared --host $(clang -dumpmachine)"
 57 | 
 58 | # ncurses ncursesw
 59 | 
 60 | # SDL_image
 61 | 
 62 | cd $ROOT/src
 63 | 
 64 | TIFF_VER="4.3.0"
 65 | WEBP_VER="1.2.2"
 66 | 
 67 | # ================== tiff ===================
 68 | 
 69 | if false
 70 | then
 71 |     if [ -f ../devices/emsdk/usr/lib/libtiff.a ]
 72 |     then
 73 |         echo "
 74 |         * tiff $TIFF_VER already built
 75 |     "
 76 |     else
 77 |         wget -c https://download.osgeo.org/libtiff/tiff-$TIFF_VER.tar.gz && tar xfz tiff-$TIFF_VER.tar.gz
 78 |         pushd tiff-$TIFF_VER
 79 |         EMCC_CFLAGS="$ALL" $CNF
 80 |         EMCC_CFLAGS="$ALL" emmake make 2>&1>/dev/null
 81 |         emmake make install 2>&1>/dev/null
 82 |         popd
 83 |     fi
 84 | fi
 85 | 
 86 | # ============ webp =========================
 87 | 
 88 | if [ -f ../devices/emsdk/usr/lib/libwebp.a ]
 89 | then
 90 |     echo "
 91 |     * libwep $WEBP_VER already built
 92 | "
 93 | else
 94 |     wget -q -c https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-$WEBP_VER.tar.gz \
 95 |         && tar xfz libwebp-$WEBP_VER.tar.gz
 96 |     pushd libwebp-$WEBP_VER
 97 |     EMCC_CFLAGS="$ALL" CC=emcc $CNF \
 98 |      --disable-threading --disable-neon --disable-sse2 --enable-libwebpdecoder 2>&1>/dev/null
 99 |     EMCC_CFLAGS="$ALL" emmake make 2>&1>/dev/null
100 |     emmake make install 2>&1>/dev/null
101 |     popd
102 | fi
103 | 
104 | # ================== SDL2_image ====================
105 | 
106 | if [ -f ../devices/emsdk/usr/lib/libSDL2_image.a ]
107 | then
108 |     echo "
109 |     * SDL2_image already built
110 | "
111 | else
112 |     #[ -d SDL_image ] || git clone https://github.com/libsdl-org/SDL_image
113 |     if [ -d SDL2_image-2.6.1 ]
114 |     then
115 |         echo "
116 |             * build SDL2_image pre release
117 |         "  1>&2
118 |     else
119 |         #bad png+grayscale https://github.com/libsdl-org/SDL_image/releases/download/candidate-2.5.1/SDL2_image-2.5.1.tar.gz
120 |         wget -c -q https://github.com/libsdl-org/SDL_image/releases/download/release-2.6.1/SDL2_image-2.6.1.tar.gz
121 | 
122 |         tar xfz SDL2_image-2.6.1.tar.gz
123 |     fi
124 | 
125 |     pushd SDL2_image-2.6.1
126 |     CFLAGS=$CPOPTS EMCC_CFLAGS="$ALL" CC=emcc  $CNF \
127 |      --disable-sdltest --disable-jpg-shared --disable-png-shared
128 |     #--disable-tif-shared
129 |     EMCC_CFLAGS="$ALL" emmake make
130 |     emmake make install
131 |     popd
132 |     [ -f $PREFIX/include/SDL2/SDL_image.h ] || exit 1
133 | fi
134 | 
135 | 
136 | if true
137 | then
138 | 
139 |     if  true #[ -f ../devices/emsdk/usr/lib/libncurses.a ]
140 |     then
141 |         echo "
142 |             * skiping [ncurses] or already built
143 |         " 1>&2
144 |     else
145 |         rm -rf ../build/ncurses/*
146 |         pushd ../build/ncurses
147 | 
148 |         CC=clang CFLAGS="-fpic -Wno-unused-command-line-argument" $ROOT/src/ncurses-6.1/configure \
149 |          $NCOPTS && make && make install
150 | 
151 |         CFLAGS="-fpic -Wno-unused-command-line-argument" emconfigure \
152 |          $ROOT/src/ncurses-6.1/configure \
153 |          $NCOPTS
154 | 
155 |         if patch -p1 < $ROOT/support/__EMSCRIPTEN__.deps/ncurses-6.1_emscripten_make.patch
156 |         then
157 |             emmake make clean
158 |             if emmake make
159 |             then
160 |                 emmake make install
161 |             fi
162 |         fi
163 |         popd
164 |     fi
165 | 
166 |     if [ -f ../devices/emsdk/usr/lib/libncursesw.a ]
167 |     then
168 |         echo "
169 |             * ncursesw already built
170 |         "  1>&2
171 |     else
172 |         # build wide char
173 |         pushd ../build/ncurses
174 | 
175 |         CFLAGS="-fpic -Wno-unused-command-line-argument" emconfigure \
176 |          $ROOT/src/ncurses-6.1/configure $NCOPTS --enable-widec
177 | 
178 |         if patch -p1 < $SDKROOT/support/__EMSCRIPTEN__.deps/ncurses-6.1_emscripten_makew.patch
179 |         then
180 |             emmake make clean
181 |             if emmake make
182 |             then
183 |                 emmake make install
184 |             fi
185 |         fi
186 |         popd
187 |     fi
188 | fi
189 | 
190 | # TODO https://github.com/onelivesleft/PrettyErrors
191 | 
192 | 
193 | 
194 | 
195 | 
196 | cd $ROOT
197 | 
198 | 


--------------------------------------------------------------------------------
/support/cross/aio/gthread.py:
--------------------------------------------------------------------------------
  1 | import aio
  2 | import inspect
  3 | import threading as __threading__
  4 | 
  5 | # mark not started but no error
  6 | aio.error = None
  7 | 
  8 | aio.paused = False
  9 | aio.fd = {}
 10 | aio.pstab = {}
 11 | 
 12 | 
 13 | def _shutdown():
 14 |     print(__file__, "_shutdown")
 15 | 
 16 | 
 17 | # https://docs.python.org/3/library/threading.html#threading.excepthook
 18 | 
 19 | # a green thread
 20 | # FIXME: fix wapy BUG 882 so target can be None too in preempt mode
 21 | 
 22 | # TODO: default granularity with https://docs.python.org/3/library/sys.html#sys.setswitchinterval
 23 | 
 24 | def excepthook(*argv, **kw):
 25 |     print("24 threading.excepthook",__file__,argv,kw)
 26 | 
 27 | class _dangling:
 28 |     @classmethod
 29 |     def copy(cls):
 30 |         # __threading__._MainThread()
 31 |         return set([])
 32 | 
 33 |     @classmethod
 34 |     def clear(cls):
 35 |         pass
 36 | 
 37 |     @classmethod
 38 |     def update(cls, saved):
 39 |         pass
 40 | 
 41 | class Local:
 42 |     pass
 43 | 
 44 | def local():
 45 |     return Local
 46 | 
 47 | class Lock:
 48 |     count = 0
 49 | 
 50 |     def __enter__(self):
 51 |         self.acquire()
 52 | 
 53 |     def __exit__(self, *tb):
 54 |         self.release()
 55 | 
 56 |     def acquire(self, blocking=True, timeout=- 1):
 57 |         self.count += 1
 58 |         return True
 59 | 
 60 |     def release(self):
 61 |         self.count -= 1
 62 | 
 63 |     def locked(self):
 64 |         return self.count>0
 65 | 
 66 | class Condition:
 67 |     def __init__(self, lock=None):
 68 |         self.lock = lock or Lock()
 69 | 
 70 |     def acquire(self, *args):
 71 |         return self.lock.acquire()
 72 | 
 73 |     def release(self):
 74 |         self.lock.release()
 75 | 
 76 |     def wait(self, timeout=None):
 77 |         raise RuntimeError("notify not supported")
 78 | 
 79 |     def wait_for(self, predicate, timeout=None):
 80 |         raise RuntimeError("wait not supported")
 81 | 
 82 | 
 83 | class Thread:
 84 |     def __init__(
 85 |         self, group=None, target=None, name=None, args=(), kwargs={}, *, daemon=None
 86 |     ):
 87 |         # def __init__(self, group=None, target=None, name=None, args=(), kwargs={}):
 88 |         self.args = args
 89 |         self.kwargs = kwargs
 90 |         self.name = name
 91 |         self.slice = 0
 92 |         self.last = aio.rtclock()
 93 | 
 94 |         if target:
 95 |             if hasattr(target, "run"):
 96 |                 if name is None:
 97 |                     self.name = name or target.__class__.__name__
 98 |                 self.run = target.run
 99 |             else:
100 |                 self.run = target
101 | 
102 |             if name is None:
103 |                 try:
104 |                     self.name = "%s-%s" % (self.run.__name__, id(self))
105 |                 except:
106 |                     pass
107 |         else:
108 |             target = self
109 | 
110 |         if self.name is None:
111 |             self.name = "%s-%s" % (self.__class__.__name__, id(self))
112 |         self.status = None
113 | 
114 |     async def wrap(self):
115 |         for idle in self.run(*self.args, **self.kwargs):
116 |             await aio.sleep(0)
117 | 
118 |     async def runner(self, coro):
119 |         self.status = True
120 |         try:
121 |             # TODO: pass thread local context here
122 |             async with aio.ctx(self.slice).call(coro):
123 |                 self.status = False
124 |         except Exception as e:
125 |             self.status = repr(e)
126 |             sys.print_exception(e, sys.stderr)
127 | 
128 |     if __UPY__:
129 | 
130 |         def __iter__(self):
131 |             if self.status is True:
132 |                 rtc = aio.rtclock()
133 |                 self.delta = (rtc - self.last) - self.slice
134 |                 if self.delta < 0:
135 |                     self.delta = 0
136 |                 yield from aio.sleep_ms(self.slice - int(self.delta / 2))
137 |                 self.last = rtc
138 | 
139 |         __await__ = __iter__
140 |     else:
141 | 
142 |         def __await__(self):
143 |             if self.status is True:
144 |                 rtc = aio.rtclock()
145 |                 self.delta = (rtc - self.last) - self.slice
146 |                 if self.delta < 0:
147 |                     self.delta = 0
148 |                 # no sleep_ms on cpy
149 |                 yield from aio.sleep_ms(
150 |                     float(self.slice - int(self.delta / 2)) / 1_000
151 |                 ).__await__()
152 |                 # return aio.sleep( float(self.slice - int(self.delta / 2)) / 1_000 )
153 |                 self.last = rtc
154 | 
155 |     def rt(self, slice):
156 |         self.slice = int(float(slice) * 1_000)
157 |         return self
158 | 
159 |     def start(self):
160 |         aio.pstab.setdefault(self.name, [])
161 |         if self.run:
162 |             if not inspect.iscoroutinefunction(self.run):
163 |                 self.status = True
164 |                 aio.create_task(self.wrap())
165 |             else:
166 |                 coro = self.run(*self.args, **self.kwargs)
167 |                 pdb("168:", self.name, "starting", coro)
168 |                 aio.create_task(self.runner(coro))
169 |             aio.pstab[self.name].append(self)
170 | 
171 |         return self
172 | 
173 |     def join(self):
174 |         embed.enable_irq()
175 |         while self.is_alive():
176 |             aio_suspend()
177 |         embed.disable_irq()
178 | 
179 |     def __bool__(self):
180 |         return self.is_alive() and not aio.exit
181 | 
182 |     def is_alive(self):
183 |         return self.status is True
184 | 
185 | 
186 | def service(srv, *argv, **kw):
187 |     embed.log(f"starting green thread : {srv}")
188 |     thr = aio.Thread(group=None, target=srv, args=argv, kwargs=kw).start()
189 |     srv.__await__ = thr.__await__
190 |     return aio.pstab.setdefault(srv, thr)
191 | 
192 | 
193 | aio.task = service
194 | 
195 | 
196 | def proc(srv):
197 |     return aio.pstab.get(srv)
198 | 
199 | 
200 | class Runnable:
201 |     def __await__(self):
202 |         yield from aio.pstab.get(self).__await__()
203 | 
204 | 
205 | # replace with green threading
206 | import sys
207 | 
208 | sys.modules["threading"] = sys.modules["aio.gthread"]
209 | 


--------------------------------------------------------------------------------
/support/cross/aio/simulator.py:
--------------------------------------------------------------------------------
  1 | print("= ${__FILE__} in websim  for  ${PLATFORM} =")
  2 | 
  3 | 
  4 | # ===============================================
  5 | import sys, os, builtins
  6 | try:
  7 |     import pymunk4 as pymunk
  8 |     sys.modules['pymunk'] = pymunk
  9 | except:
 10 |     print("pymunk4 was not build for simulator")
 11 | 
 12 | 
 13 | # need them earlier than aio
 14 | 
 15 | 
 16 | def pdb(*argv):
 17 |     print(*argv, file=sys.__stderr__)
 18 | 
 19 | 
 20 | builtins.pdb = pdb
 21 | 
 22 | 
 23 | def print_exception(e, out=sys.stderr, **kw):
 24 |     kw["file"] = out
 25 |     traceback.print_exc(**kw)
 26 | 
 27 | 
 28 | sys.print_exception = print_exception
 29 | 
 30 | 
 31 | # aioprompt ======== have asyncio loop runs interleaved with repl ============
 32 | # from https://github.com/pmp-p/aioprompt
 33 | 
 34 | scheduled = []
 35 | scheduler = None
 36 | wrapper_ref = None
 37 | loop = None
 38 | 
 39 | next_tick = 0
 40 | 
 41 | unsupported = ("bionic", "wasm", "emscripten", "wasi", "android")
 42 | 
 43 | # TODO: all readline replacement with accurate timeframes
 44 | # TODO: droid integrate application lifecycle
 45 | 
 46 | if sys.platform not in unsupported:
 47 |     import sys
 48 |     import builtins
 49 |     import ctypes
 50 |     import time
 51 | 
 52 |     if not sys.flags.inspect:
 53 |         print(
 54 |             "Error: interpreter must be run with -i or PYTHONINSPECT must be set for using",
 55 |             __name__,
 56 |         )
 57 |         raise SystemExit
 58 | 
 59 |     def sched_init():
 60 |         global scheduled, scheduler, wrapper_ref
 61 |         #! KEEP IT WOULD BE GC OTHERWISE!
 62 |         # wrapper_ref
 63 | 
 64 |         #scheduled = []
 65 |         import ctypes
 66 | 
 67 |         try:
 68 |             ctypes = ctypes.this
 69 |         except:
 70 |             pass
 71 | 
 72 |         c_char_p = ctypes.c_char_p
 73 |         c_void_p = ctypes.c_void_p
 74 | 
 75 |         HOOKFUNC = ctypes.CFUNCTYPE(c_char_p)
 76 |         PyOS_InputHookFunctionPointer = c_void_p.in_dll(
 77 |             ctypes.pythonapi, "PyOS_InputHook"
 78 |         )
 79 | 
 80 |         def scheduler():
 81 |             global scheduled
 82 |             # prevent reenter
 83 |             lq = len(scheduled)
 84 |             while lq:
 85 |                 fn, a = scheduled.pop(0)
 86 |                 fn(a)
 87 |                 lq -= 1
 88 | 
 89 |         wrapper_ref = HOOKFUNC(scheduler)
 90 |         scheduler_c = ctypes.cast(wrapper_ref, c_void_p)
 91 |         PyOS_InputHookFunctionPointer.value = scheduler_c.value
 92 | 
 93 | #        # replace with faster function
 94 | #        def schedule(fn, a):
 95 | #            scheduled.append((fn, a))
 96 | #
 97 |         sys.modules[__name__].schedule = schedule
 98 | 
 99 |         # now the init code is useless
100 |         del sys.modules[__name__].sched_init
101 | 
102 |     def schedule(fn, a):
103 |         global scheduled, next_tick
104 |         if next_tick==0:
105 |             sched_init()
106 |         next_tick = time.time() + .016
107 |         # cpu cool down
108 |         cooldown = next_tick - time.time()
109 |         if cooldown>0:
110 |             time.sleep(cooldown)
111 |         scheduled.append((fn, a))
112 | 
113 | else:
114 |     pdb("aiorepl no possible on", sys.platform, "expect main to block")
115 |     schedule = None
116 | 
117 | # =====================================================
118 | 
119 | sys.path.append("${PLATFORM}")
120 | 
121 | 
122 | # cannot fake a cpu __WASM__ will be False
123 | 
124 | # but fake the platform AND the module
125 | sys.platform = "emscripten"
126 | 
127 | 
128 | class __EMSCRIPTEN__(object):
129 |     def __init__(self):
130 |         import platform
131 |         self.platform = platform
132 | 
133 |     def __getattribute__(self, name):
134 |         try:
135 |             return object.__getattribute__(self, name)
136 |         except:
137 |             return object.__getattribute__(self.platform, name)
138 | 
139 |     @classmethod
140 |     def PyConfig_InitPythonConfig(*argv):
141 |         pass
142 | 
143 |     @classmethod
144 |     def init_platform(*argv):
145 |         pass
146 | 
147 |     @classmethod
148 |     def flush(cls):
149 |         sys.stdout.flush()
150 |         sys.stderr.flush()
151 | 
152 |     @classmethod
153 |     def trap(cls, *argv, **kw):
154 |         pass
155 | 
156 |     @classmethod
157 |     def system(cls):
158 |         return 'Linux'
159 | 
160 |     is_browser = False
161 | 
162 |     js = pdb
163 |     run_script = pdb
164 | 
165 | __EMSCRIPTEN__ = __EMSCRIPTEN__()
166 | 
167 | sys.modules["__EMSCRIPTEN__"] = __EMSCRIPTEN__
168 | sys.modules["embed"] = __EMSCRIPTEN__
169 | 
170 | 
171 | import aio
172 | import aio.prepro
173 | import aio.cross
174 | 
175 | aio.cross.simulator = True
176 | 
177 | 
178 | exec(open("${PYTHONRC}").read(), globals(), globals())
179 | 
180 | 
181 | # ===============================================================================
182 | 
183 | import aio.clock
184 | 
185 | 
186 | # ===============================================================================
187 | import inspect
188 | import asyncio
189 | 
190 | DEBUG = 1
191 | 
192 | if __name__ == "__main__":
193 |     aio.DEBUG = DEBUG
194 | 
195 |     print("main may block depending on your platform readline implementation")
196 | 
197 |     if schedule:
198 |         aio.cross.scheduler = schedule
199 | 
200 |     # asyncio.create_task( aio.clock.loop() )
201 |     aio.clock.start(x=80)
202 | 
203 |     __main__ = execfile("${__FILE__}")
204 |     # on not arduino style, expect user to run main with asyncio.run( main() )
205 |     # should be already called at this point.
206 | 
207 |     setup = vars(__main__).get("setup", None)
208 |     loop = vars(__main__).get("loop", None)
209 | 
210 |     # arduino naming is just wrong anyway
211 |     if loop is None:
212 |         loop = vars(__main__).get("step", None)
213 | 
214 |     if loop and setup:
215 |         print("found setup, loop")
216 |         if setup:
217 |             setup()
218 |     if loop:
219 |         if not inspect.iscoroutinefunction(loop):
220 |             if loop and setup:
221 |                 print("loop is not a coroutine, running arduino style")
222 |                 aio.steps.append(loop)
223 |             # TODO : use a wrapper for non readline systems.
224 | 
225 |             async def coro():
226 |                 loop()
227 | 
228 |         else:
229 |             coro = loop
230 | 
231 |         if not aio.started:
232 |             aio.started = True
233 |             if DEBUG:
234 |                 pdb("200: starting aio scheduler")
235 |             aio.cross.scheduler(aio.step, 1)
236 | 
237 |     print(" -> asyncio.run passed")
238 |     sys.stdout.flush()
239 |     sys.stderr.flush()
240 | 
241 | 
242 | #
243 | 


--------------------------------------------------------------------------------
/tests/code/touchpong.py:
--------------------------------------------------------------------------------
  1 | try:
  2 |     import android
  3 | 
  4 |     __ANDROID__ = True
  5 | except:
  6 |     __ANDROID__ = False
  7 |     android = None
  8 | 
  9 | try:
 10 |     __EMSCRIPTEN__
 11 | except:
 12 |     __EMSCRIPTEN__ = False
 13 | 
 14 | import pygame as pg
 15 | 
 16 | pg.init()
 17 | if __ANDROID__ :
 18 |     screen = pg.display.set_mode((640, 360), pg.SCALED | pg.FULLSCREEN)
 19 | elif __EMSCRIPTEN__:
 20 |     screen = pg.display.set_mode((640, 360), pg.SCALED)
 21 | else:
 22 |     screen = pg.display.set_mode((640, 360), 0 )
 23 | 
 24 | clock = pg.time.Clock()
 25 | score_font = pg.font.SysFont("monospace", 64)
 26 | 
 27 | left_paddle = pg.Rect(45, 5, 15, 60)
 28 | right_paddle = pg.Rect(580, 5, 15, 60)
 29 | ball = pg.Rect(320, 240, 20, 20)
 30 | ball_speed = [-2, 1]
 31 | 
 32 | fingers = {}
 33 | 
 34 | p1fingers = []
 35 | p2fingers = []
 36 | 
 37 | p1score = 0
 38 | p2score = 0
 39 | last_scorer = 0
 40 | 
 41 | big_ball_time = 0
 42 | big_left_time = 0
 43 | big_right_time = 0
 44 | score_time = 0
 45 | 
 46 | audio = True
 47 | running = True
 48 | 
 49 | 
 50 | def step():
 51 |     global running, score_time, ball, ball_speed, big_left_time, big_right_time
 52 |     global big_ball_time, p1score, p2score, last_scorer, clock, screen
 53 |     global audio
 54 | 
 55 |     if not running:
 56 |         return
 57 | 
 58 |     if audio:
 59 |         pg.mixer.init()
 60 |         pg.music.set_volume(0.5)
 61 |         pg.music.load("Eisenfunk - Pong.ogg")
 62 |         pg.music.play()
 63 |         audio = False
 64 | 
 65 |     pg.event.pump()
 66 | 
 67 |     for event in pg.event.get(pg.FINGERDOWN, pump=False):
 68 |         fingers[event.finger_id] = (event.x, event.y)
 69 |         if event.x < 0.5:
 70 |             p1fingers.append(event.finger_id)
 71 |         else:
 72 |             p2fingers.append(event.finger_id)
 73 | 
 74 |     for event in pg.event.get(pg.FINGERMOTION, pump=False):
 75 |         fingers[event.finger_id] = (event.x, event.y)
 76 | 
 77 |     for event in pg.event.get(pg.FINGERUP, pump=False):
 78 |         del fingers[event.finger_id]
 79 | 
 80 |         if event.finger_id in p1fingers:
 81 |             p1fingers.remove(event.finger_id)
 82 |         if event.finger_id in p2fingers:
 83 |             p2fingers.remove(event.finger_id)
 84 | 
 85 |     for event in pg.event.get(pg.QUIT, pump=False):
 86 |         running = False
 87 | 
 88 |     for event in pg.event.get():
 89 |         st = repr(event)
 90 |         if st.find('-MouseMotion')>0:
 91 |             # works fine actually
 92 |             pass
 93 |         elif st.find('-MouseButton')>0:
 94 |             # works fine actually
 95 |             pass
 96 |         elif st.find('-KeyDown')>0:
 97 |             # works fine actually
 98 |             pass
 99 |         elif st.find('-KeyUp')>0:
100 |             # works fine actually
101 |             pass
102 |         elif st.find('-TextInput')>0:
103 |             # works fine actually
104 |             pass
105 |         else:
106 |             print(st)
107 | 
108 | 
109 |     keys = pg.key.get_pressed()
110 | 
111 |     if score_time > 0:
112 |         score_time -= 1
113 |         if score_time == 0:
114 |             ball = pg.Rect(320, 240, 20, 20)
115 |             if last_scorer == 1:
116 |                 ball_speed = [-2, 1]
117 |             else:
118 |                 ball_speed = [2, -1]
119 |     else:
120 |         if p1fingers:
121 |             fx, fy = fingers[p1fingers[0]]
122 |             y = int(fy * 360)
123 |             if y - left_paddle.centery > 10:
124 |                 left_paddle.centery += 10
125 |             elif y - left_paddle.centery < -10:
126 |                 left_paddle.centery -= 10
127 |             else:
128 |                 left_paddle.centery = y
129 | 
130 |         if p2fingers:
131 |             fx, fy = fingers[p2fingers[0]]
132 |             y = int(fy * 360)
133 |             if y - right_paddle.centery > 10:
134 |                 right_paddle.centery += 10
135 |             elif y - right_paddle.centery < -10:
136 |                 right_paddle.centery -= 10
137 |             else:
138 |                 right_paddle.centery = y
139 | 
140 |         if keys[pg.K_f]:
141 |             left_paddle.centery -= 3
142 |         if keys[pg.K_v]:
143 |             left_paddle.centery += 3
144 | 
145 |         if keys[pg.K_UP]:
146 |             right_paddle.centery -= 3
147 |         if keys[pg.K_DOWN]:
148 |             right_paddle.centery += 3
149 | 
150 | 
151 |         if left_paddle.bottom > 360:
152 |             left_paddle.bottom = 360
153 |         if left_paddle.top < 0:
154 |             left_paddle.top = 0
155 | 
156 |         if right_paddle.bottom > 360:
157 |             right_paddle.bottom = 360
158 |         if right_paddle.top < 0:
159 |             right_paddle.top = 0
160 | 
161 |         ball.centerx += ball_speed[0]
162 |         if ball_speed[0] < 0 and ball.colliderect(left_paddle):
163 |             ball_speed[0] = -ball_speed[0]
164 |             big_ball_time += 5
165 |             big_left_time += 15
166 | 
167 |         if ball_speed[0] > 0 and ball.colliderect(right_paddle):
168 |             ball_speed[0] = -ball_speed[0]
169 |             big_ball_time += 5
170 |             big_right_time += 15
171 | 
172 |         if ball_speed[0] < 0 and ball.left < 0:
173 |             score_time = 50
174 |             p2score += 1
175 |             last_scorer = 2
176 |         if ball_speed[0] > 0 and ball.right > 640:
177 |             score_time = 50
178 |             p1score += 1
179 |             last_scorer = 1
180 | 
181 |         ball.centery += ball_speed[1]
182 |         if ball_speed[1] > 0 and ball.bottom >= 360:
183 |             ball_speed[1] = -ball_speed[1]
184 |             big_ball_time += 5
185 |         if ball_speed[1] < 0 and ball.top <= 0:
186 |             ball_speed[1] = -ball_speed[1]
187 |             big_ball_time += 5
188 | 
189 |     if score_time > 0:
190 |         fg = (255, 255, 255)
191 |         bg = (50, 20, 20)
192 |     else:
193 |         fg = (255, 255, 255)
194 |         bg = (0, 0, 0)
195 | 
196 |     screen.fill(bg)
197 |     if big_left_time > 0:
198 |         pg.draw.rect(screen, fg, left_paddle, 5)
199 |         big_left_time -= 1
200 |     else:
201 |         pg.draw.rect(screen, fg, left_paddle)
202 | 
203 |     if big_right_time > 0:
204 |         pg.draw.rect(screen, fg, right_paddle, 5)
205 |         big_right_time -= 1
206 |     else:
207 |         pg.draw.rect(screen, fg, right_paddle)
208 | 
209 |     if big_ball_time > 0:
210 |         pg.draw.rect(screen, fg, ball, 5)
211 |         big_ball_time -= 1
212 |     else:
213 |         pg.draw.rect(screen, fg, ball)
214 | 
215 |     pg.draw.line(screen, fg, (320 - 1, 0), (320 - 1, 360), 2)
216 |     score_surf = score_font.render(f"{p1score:02}:{p2score:02}", 1, fg)
217 |     screen.blit(score_surf, (320 - score_surf.get_width() // 2, 5))
218 | 
219 |     clock.tick(30)
220 | 
221 |     pg.display.flip()
222 | 
223 | 
224 | if __EMSCRIPTEN__:
225 |     aio.steps.append(step)
226 | else:
227 |     while running:
228 |         step()
229 | 


--------------------------------------------------------------------------------
/support/__EMSCRIPTEN__.deps/ncurses-6.1_emscripten_make.patch:
--------------------------------------------------------------------------------
  1 | --- ncurses/Makefile	2022-04-26 00:07:51.617172493 +0200
  2 | +++ ncurses-wasm/Makefile	2022-04-26 00:12:57.704905779 +0200
  3 | @@ -115,7 +115,7 @@
  4 |  	cd panel && ${MAKE} ${TOP_MFLAGS} $@
  5 |  	cd menu && ${MAKE} ${TOP_MFLAGS} $@
  6 |  	cd form && ${MAKE} ${TOP_MFLAGS} $@
  7 | -	cd misc && ${MAKE} ${TOP_MFLAGS} $@
  8 | +#	cd misc && ${MAKE} ${TOP_MFLAGS} $@
  9 |  
 10 |  libs \
 11 |  install.libs \
 12 | --- ncurses/ncurses/Makefile	2022-04-26 00:07:51.624172419 +0200
 13 | +++ ncurses-wasm/ncurses/Makefile	2022-04-26 00:13:43.524417020 +0200
 14 | @@ -49,14 +49,14 @@
 15 |  VPATH		= /data/git/python-wasm-plus/src/ncurses-6.1/ncurses
 16 |  THIS		= Makefile
 17 |  
 18 | -CF_MFLAGS 	= 
 19 | +CF_MFLAGS 	=
 20 |  
 21 |  
 22 | -x		= 
 23 | +x		=
 24 |  o		= .o
 25 |  
 26 |  MODEL		= normal
 27 | -DESTDIR		= 
 28 | +DESTDIR		=
 29 |  top_srcdir	= /data/git/python-wasm-plus/src/ncurses-6.1
 30 |  srcdir		= /data/git/python-wasm-plus/src/ncurses-6.1/ncurses
 31 |  prefix		= /data/git/python-wasm-plus/devices/emsdk/usr
 32 | @@ -72,14 +72,14 @@
 33 |  
 34 |  PACKAGE		= ncurses
 35 |  
 36 | -LIBTOOL		= 
 37 | -LIBTOOL_OPTS	=  
 38 | -LIBTOOL_CLEAN	= 
 39 | -LIBTOOL_COMPILE	= 
 40 | +LIBTOOL		=
 41 | +LIBTOOL_OPTS	=
 42 | +LIBTOOL_CLEAN	=
 43 | +LIBTOOL_COMPILE	=
 44 |  LIBTOOL_LINK	= ${CC}
 45 | -LIBTOOL_INSTALL	= 
 46 | -LIBTOOL_UNINSTALL = 
 47 | -LT_UNDEF	= 
 48 | +LIBTOOL_INSTALL	=
 49 | +LIBTOOL_UNINSTALL =
 50 | +LT_UNDEF	=
 51 |  
 52 |  INSTALL		= /usr/bin/install -c
 53 |  INSTALL_LIB	= /usr/bin/install -c -m 644
 54 | @@ -94,7 +94,7 @@
 55 |  NM		= /data/git/python-wasm-plus/emsdk/upstream/bin/llvm-nm
 56 |  
 57 |  CTAGS		= ctags
 58 | -ETAGS		= 
 59 | +ETAGS		=
 60 |  
 61 |  CC		= /data/git/python-wasm-plus/emsdk/upstream/emscripten/emcc
 62 |  CPP		= /data/git/python-wasm-plus/emsdk/upstream/emscripten/emcc -E
 63 | @@ -105,7 +105,7 @@
 64 |  
 65 |  CCFLAGS		= $(CPPFLAGS) $(CFLAGS)
 66 |  
 67 | -BUILD_CPPFLAGS	= -DHAVE_CONFIG_H -DUSE_BUILD_CC -I../ncurses -I$(srcdir) -I../include -I$(INCDIR) ${CPPFLAGS} 
 68 | +BUILD_CPPFLAGS	= -DHAVE_CONFIG_H -DUSE_BUILD_CC -I../ncurses -I$(srcdir) -I../include -I$(INCDIR) ${CPPFLAGS}
 69 |  BUILD_CC	= ${CC}
 70 |  BUILD_CCFLAGS	= ${CFLAGS}
 71 |  BUILD_LDFLAGS	= ${LDFLAGS}
 72 | @@ -115,7 +115,7 @@
 73 |  # is compiled into the build, or are test-programs that are not installed.
 74 |  
 75 |  BUILD_EXEEXT	= $x
 76 | -x		= 
 77 | +x		=
 78 |  
 79 |  CFLAGS_LIBTOOL	= $(CCFLAGS)
 80 |  CFLAGS_NORMAL	= $(CCFLAGS)
 81 | @@ -126,16 +126,16 @@
 82 |  CFLAGS_DEFAULT	= $(CFLAGS_NORMAL)
 83 |  
 84 |  LINK		= $(LIBTOOL)
 85 | -LDFLAGS		= -L/data/git/python-wasm-plus/devices/emsdk/usr/lib  
 86 | +LDFLAGS		= -L/data/git/python-wasm-plus/devices/emsdk/usr/lib
 87 |  
 88 |  SHLIB_DIRS	= -L../lib
 89 | -SHLIB_LIST	= $(SHLIB_DIRS) 
 90 | -TINFO_LIST	= $(SHLIB_DIRS) 
 91 | -TICS_LIST	= $(SHLIB_DIRS) 
 92 | +SHLIB_LIST	= $(SHLIB_DIRS)
 93 | +TINFO_LIST	= $(SHLIB_DIRS)
 94 | +TICS_LIST	= $(SHLIB_DIRS)
 95 |  
 96 |  RPATH_LIST	= ${libdir}
 97 | -RESULTING_SYMS	= 
 98 | -VERSIONED_SYMS	= 
 99 | +RESULTING_SYMS	=
100 | +VERSIONED_SYMS	=
101 |  MK_SHARED_LIB	= ${CC} ${LDFLAGS} ${CFLAGS} -shared -Wl,-soname,`basename $@ .${REL_VERSION}`.${ABI_VERSION},-stats,-lc -o $@
102 |  
103 |  NCURSES_MAJOR	= 6
104 | @@ -147,11 +147,11 @@
105 |  
106 |  LIBRARIES	=  ../lib/libncurses.a ../lib/libncurses_g.a
107 |  
108 | -LINT		= 
109 | -LINT_OPTS	= 
110 | -LINT_LIBS	= -lncurses 
111 | +LINT		=
112 | +LINT_OPTS	=
113 | +LINT_LIBS	= -lncurses
114 |  
115 | -FALLBACK_LIST	= 
116 | +FALLBACK_LIST	=
117 |  
118 |  USE_BIG_STRINGS	= 1
119 |  TERMINFO_CAPS	= $(top_srcdir)/include/Caps
120 | @@ -186,7 +186,7 @@
121 |  	$(INCDIR)/nc_mingw.h
122 |  
123 |  TEST_DEPS	= ../lib/libncurses.a
124 | -TEST_ARGS	= -static -L../lib -lform -lmenu -lpanel -lncurses  -dynamic 
125 | +TEST_ARGS	= -static -L../lib -lform -lmenu -lpanel -lncurses  -dynamic
126 |  TEST_LDFLAGS	=  $(TEST_ARGS)   -L/data/git/python-wasm-plus/devices/emsdk/usr/lib
127 |  
128 |  TEST_PROGS = \
129 | @@ -208,7 +208,7 @@
130 |  ################################################################################
131 |  all libs ::	$(AUTO_SRC) ../lib $(LIBRARIES)
132 |  
133 | -all libs ::	report_offsets$(BUILD_EXEEXT) 
134 | +all libs ::	report_offsets$(BUILD_EXEEXT)
135 |  
136 |  sources:	$(AUTO_SRC)
137 |  
138 | @@ -230,20 +230,20 @@
139 |  keys.list :	$(tinfo)/MKkeys_list.sh
140 |  	AWK=$(AWK) $(SHELL) $(tinfo)/MKkeys_list.sh $(TERMINFO_CAPS) | LC_ALL=C sort >$@
141 |  
142 | -make_keys$(BUILD_EXEEXT) : \
143 | -		$(tinfo)/make_keys.c \
144 | -		names.c
145 | -	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(tinfo)/make_keys.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
146 | -
147 | -make_hash$(BUILD_EXEEXT) : \
148 | -		$(tinfo)/make_hash.c \
149 | -		../include/hashsize.h
150 | -	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(tinfo)/make_hash.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
151 | -
152 | -report_offsets$(BUILD_EXEEXT) : \
153 | -		$(srcdir)/report_offsets.c
154 | -	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(srcdir)/report_offsets.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
155 | -	./report_offsets$(BUILD_EXEEXT)
156 | +#make_keys$(BUILD_EXEEXT) : \
157 | +#		$(tinfo)/make_keys.c \
158 | +#		names.c
159 | +#	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(tinfo)/make_keys.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
160 | +
161 | +#make_hash$(BUILD_EXEEXT) : \
162 | +#		$(tinfo)/make_hash.c \
163 | +#		../include/hashsize.h
164 | +#	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(tinfo)/make_hash.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
165 | +
166 | +#report_offsets$(BUILD_EXEEXT) : \
167 | +#		$(srcdir)/report_offsets.c
168 | +#	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(srcdir)/report_offsets.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
169 | +#	./report_offsets$(BUILD_EXEEXT)
170 |  
171 |  ./expanded.c : $(srcdir)/curses.priv.h $(serial)/MKexpanded.sh
172 |  	$(SHELL) -e $(serial)/MKexpanded.sh "$(CPP)" $(CPPFLAGS) > $@
173 | @@ -280,9 +280,9 @@
174 |  
175 |  clean :: mostlyclean
176 |  	-rm -f $(AUTO_SRC)
177 | -	-rm -f make_keys$(BUILD_EXEEXT)
178 | -	-rm -f make_hash$(BUILD_EXEEXT)
179 | -	-rm -f report_offsets$(BUILD_EXEEXT)
180 | +#	-rm -f make_keys$(BUILD_EXEEXT)
181 | +#	-rm -f make_hash$(BUILD_EXEEXT)
182 | +#	-rm -f report_offsets$(BUILD_EXEEXT)
183 |  	-rm -rf .libs *.dSYM *.map
184 |  
185 |  distclean :: clean
186 | @@ -327,7 +327,7 @@
187 |  ###############################################################################
188 |  
189 |  # Generated by CF_LIB_RULES
190 | -resulting.map: 
191 | +resulting.map:
192 |  	gawk 'BEGIN { skip = 1; last=""; } /deprecated in ABI6/ { next; }{ sub("NCURSES([WT]+)?", "&6"); } { if ( last != "" && ( skip == 0 || $$0 !~ /}/ ) ) { print last; } skip = 0; last = $$0; } END { print last; }' <  >$@
193 |  
194 |  distclean::
195 | @@ -336,8 +336,8 @@
196 |  # generated by mk-0th.awk
197 |  #   libname:    ncurses
198 |  #   subsets:    ticlib+termlib+ext_tinfo+base+ext_funcs
199 | -#   ticlib:     
200 | -#   termlib:    
201 | +#   ticlib:
202 | +#   termlib:
203 |  
204 |  .SUFFIXES: .c .cc .h .i .ii
205 |  .c.i :
206 | @@ -885,7 +885,7 @@
207 |  #   echo:       no
208 |  #   subset:     ticlib+termlib+ext_tinfo+base+ext_funcs
209 |  #   crenames:   yes
210 | -#   cxxrenames: 
211 | +#   cxxrenames:
212 |  #   traces:     DEBUG
213 |  #   srcdir:     /data/git/python-wasm-plus/src/ncurses-6.1
214 |  
215 | @@ -1902,7 +1902,7 @@
216 |  #   echo:       no
217 |  #   subset:     ticlib+termlib+ext_tinfo+base+ext_funcs
218 |  #   crenames:   yes
219 | -#   cxxrenames: 
220 | +#   cxxrenames:
221 |  #   traces:     DEBUG
222 |  #   srcdir:     /data/git/python-wasm-plus/src/ncurses-6.1
223 |  
224 | 


--------------------------------------------------------------------------------
/support/__EMSCRIPTEN__.deps/ncurses-6.1_emscripten_makew.patch:
--------------------------------------------------------------------------------
  1 | --- ncurses/Makefile	2022-04-26 01:52:09.047768242 +0200
  2 | +++ ncurses-wasm/Makefile	2022-04-26 01:52:56.637283894 +0200
  3 | @@ -115,7 +115,7 @@
  4 |  	cd panel && ${MAKE} ${TOP_MFLAGS} $@
  5 |  	cd menu && ${MAKE} ${TOP_MFLAGS} $@
  6 |  	cd form && ${MAKE} ${TOP_MFLAGS} $@
  7 | -	cd misc && ${MAKE} ${TOP_MFLAGS} $@
  8 | +#	cd misc && ${MAKE} ${TOP_MFLAGS} $@
  9 |  
 10 |  libs \
 11 |  install.libs \
 12 | --- ncurses/ncurses/Makefile	2022-04-26 01:52:09.054768171 +0200
 13 | +++ ncurses-wasm/ncurses/Makefile	2022-04-26 01:53:20.566040262 +0200
 14 | @@ -49,14 +49,14 @@
 15 |  VPATH		= /data/git/python-wasm-plus/src/ncurses-6.1/ncurses
 16 |  THIS		= Makefile
 17 |  
 18 | -CF_MFLAGS 	= 
 19 | +CF_MFLAGS 	=
 20 |  
 21 |  
 22 | -x		= 
 23 | +x		=
 24 |  o		= .o
 25 |  
 26 |  MODEL		= normal
 27 | -DESTDIR		= 
 28 | +DESTDIR		=
 29 |  top_srcdir	= /data/git/python-wasm-plus/src/ncurses-6.1
 30 |  srcdir		= /data/git/python-wasm-plus/src/ncurses-6.1/ncurses
 31 |  prefix		= /data/git/python-wasm-plus/devices/emsdk/usr
 32 | @@ -72,14 +72,14 @@
 33 |  
 34 |  PACKAGE		= ncursesw
 35 |  
 36 | -LIBTOOL		= 
 37 | -LIBTOOL_OPTS	=  
 38 | -LIBTOOL_CLEAN	= 
 39 | -LIBTOOL_COMPILE	= 
 40 | +LIBTOOL		=
 41 | +LIBTOOL_OPTS	=
 42 | +LIBTOOL_CLEAN	=
 43 | +LIBTOOL_COMPILE	=
 44 |  LIBTOOL_LINK	= ${CC}
 45 | -LIBTOOL_INSTALL	= 
 46 | -LIBTOOL_UNINSTALL = 
 47 | -LT_UNDEF	= 
 48 | +LIBTOOL_INSTALL	=
 49 | +LIBTOOL_UNINSTALL =
 50 | +LT_UNDEF	=
 51 |  
 52 |  INSTALL		= /usr/bin/install -c
 53 |  INSTALL_LIB	= /usr/bin/install -c -m 644
 54 | @@ -94,7 +94,7 @@
 55 |  NM		= /data/git/python-wasm-plus/emsdk/upstream/bin/llvm-nm
 56 |  
 57 |  CTAGS		= ctags
 58 | -ETAGS		= 
 59 | +ETAGS		=
 60 |  
 61 |  CC		= /data/git/python-wasm-plus/emsdk/upstream/emscripten/emcc
 62 |  CPP		= /data/git/python-wasm-plus/emsdk/upstream/emscripten/emcc -E
 63 | @@ -105,7 +105,7 @@
 64 |  
 65 |  CCFLAGS		= $(CPPFLAGS) $(CFLAGS)
 66 |  
 67 | -BUILD_CPPFLAGS	= -DHAVE_CONFIG_H -DUSE_BUILD_CC -I../ncurses -I$(srcdir) -I../include -I$(INCDIR) ${CPPFLAGS} 
 68 | +BUILD_CPPFLAGS	= -DHAVE_CONFIG_H -DUSE_BUILD_CC -I../ncurses -I$(srcdir) -I../include -I$(INCDIR) ${CPPFLAGS}
 69 |  BUILD_CC	= ${CC}
 70 |  BUILD_CCFLAGS	= ${CFLAGS}
 71 |  BUILD_LDFLAGS	= ${LDFLAGS}
 72 | @@ -115,7 +115,7 @@
 73 |  # is compiled into the build, or are test-programs that are not installed.
 74 |  
 75 |  BUILD_EXEEXT	= $x
 76 | -x		= 
 77 | +x		=
 78 |  
 79 |  CFLAGS_LIBTOOL	= $(CCFLAGS)
 80 |  CFLAGS_NORMAL	= $(CCFLAGS)
 81 | @@ -126,16 +126,16 @@
 82 |  CFLAGS_DEFAULT	= $(CFLAGS_NORMAL)
 83 |  
 84 |  LINK		= $(LIBTOOL)
 85 | -LDFLAGS		= -L/data/git/python-wasm-plus/devices/emsdk/usr/lib  
 86 | +LDFLAGS		= -L/data/git/python-wasm-plus/devices/emsdk/usr/lib
 87 |  
 88 |  SHLIB_DIRS	= -L../lib
 89 | -SHLIB_LIST	= $(SHLIB_DIRS) 
 90 | -TINFO_LIST	= $(SHLIB_DIRS) 
 91 | -TICS_LIST	= $(SHLIB_DIRS) 
 92 | +SHLIB_LIST	= $(SHLIB_DIRS)
 93 | +TINFO_LIST	= $(SHLIB_DIRS)
 94 | +TICS_LIST	= $(SHLIB_DIRS)
 95 |  
 96 |  RPATH_LIST	= ${libdir}
 97 | -RESULTING_SYMS	= 
 98 | -VERSIONED_SYMS	= 
 99 | +RESULTING_SYMS	=
100 | +VERSIONED_SYMS	=
101 |  MK_SHARED_LIB	= ${CC} ${LDFLAGS} ${CFLAGS} -shared -Wl,-soname,`basename $@ .${REL_VERSION}`.${ABI_VERSION},-stats,-lc -o $@
102 |  
103 |  NCURSES_MAJOR	= 6
104 | @@ -147,11 +147,11 @@
105 |  
106 |  LIBRARIES	=  ../lib/libncursesw.a ../lib/libncursesw_g.a
107 |  
108 | -LINT		= 
109 | -LINT_OPTS	= 
110 | -LINT_LIBS	= -lncurses 
111 | +LINT		=
112 | +LINT_OPTS	=
113 | +LINT_LIBS	= -lncurses
114 |  
115 | -FALLBACK_LIST	= 
116 | +FALLBACK_LIST	=
117 |  
118 |  USE_BIG_STRINGS	= 1
119 |  TERMINFO_CAPS	= $(top_srcdir)/include/Caps
120 | @@ -186,7 +186,7 @@
121 |  	$(INCDIR)/nc_mingw.h
122 |  
123 |  TEST_DEPS	= ../lib/libncursesw.a
124 | -TEST_ARGS	= -static -L../lib -lformw -lmenuw -lpanelw -lncursesw  -dynamic 
125 | +TEST_ARGS	= -static -L../lib -lformw -lmenuw -lpanelw -lncursesw  -dynamic
126 |  TEST_LDFLAGS	=  $(TEST_ARGS)   -L/data/git/python-wasm-plus/devices/emsdk/usr/lib
127 |  
128 |  TEST_PROGS = \
129 | @@ -208,7 +208,7 @@
130 |  ################################################################################
131 |  all libs ::	$(AUTO_SRC) ../lib $(LIBRARIES)
132 |  
133 | -all libs ::	report_offsets$(BUILD_EXEEXT) 
134 | +all libs ::	report_offsets$(BUILD_EXEEXT)
135 |  
136 |  sources:	$(AUTO_SRC)
137 |  
138 | @@ -230,20 +230,20 @@
139 |  keys.list :	$(tinfo)/MKkeys_list.sh
140 |  	AWK=$(AWK) $(SHELL) $(tinfo)/MKkeys_list.sh $(TERMINFO_CAPS) | LC_ALL=C sort >$@
141 |  
142 | -make_keys$(BUILD_EXEEXT) : \
143 | -		$(tinfo)/make_keys.c \
144 | -		names.c
145 | -	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(tinfo)/make_keys.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
146 | -
147 | -make_hash$(BUILD_EXEEXT) : \
148 | -		$(tinfo)/make_hash.c \
149 | -		../include/hashsize.h
150 | -	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(tinfo)/make_hash.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
151 | -
152 | -report_offsets$(BUILD_EXEEXT) : \
153 | -		$(srcdir)/report_offsets.c
154 | -	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(srcdir)/report_offsets.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
155 | -	./report_offsets$(BUILD_EXEEXT)
156 | +#make_keys$(BUILD_EXEEXT) : \
157 | +#		$(tinfo)/make_keys.c \
158 | +#		names.c
159 | +#	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(tinfo)/make_keys.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
160 | +
161 | +#make_hash$(BUILD_EXEEXT) : \
162 | +#		$(tinfo)/make_hash.c \
163 | +#		../include/hashsize.h
164 | +#	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(tinfo)/make_hash.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
165 | +
166 | +#report_offsets$(BUILD_EXEEXT) : \
167 | +#		$(srcdir)/report_offsets.c
168 | +#	$(BUILD_CC) -o $@ $(BUILD_CPPFLAGS) $(BUILD_CCFLAGS) $(srcdir)/report_offsets.c $(BUILD_LDFLAGS) $(BUILD_LIBS)
169 | +#	./report_offsets$(BUILD_EXEEXT)
170 |  
171 |  ./expanded.c : $(srcdir)/curses.priv.h $(serial)/MKexpanded.sh
172 |  	$(SHELL) -e $(serial)/MKexpanded.sh "$(CPP)" $(CPPFLAGS) > $@
173 | @@ -280,9 +280,9 @@
174 |  
175 |  clean :: mostlyclean
176 |  	-rm -f $(AUTO_SRC)
177 | -	-rm -f make_keys$(BUILD_EXEEXT)
178 | -	-rm -f make_hash$(BUILD_EXEEXT)
179 | -	-rm -f report_offsets$(BUILD_EXEEXT)
180 | +#	-rm -f make_keys$(BUILD_EXEEXT)
181 | +#	-rm -f make_hash$(BUILD_EXEEXT)
182 | +#	-rm -f report_offsets$(BUILD_EXEEXT)
183 |  	-rm -rf .libs *.dSYM *.map
184 |  
185 |  distclean :: clean
186 | @@ -327,7 +327,7 @@
187 |  ###############################################################################
188 |  
189 |  # Generated by CF_LIB_RULES
190 | -resulting.map: 
191 | +resulting.map:
192 |  	gawk 'BEGIN { skip = 1; last=""; } /deprecated in ABI6/ { next; }{ sub("NCURSES([WT]+)?", "&6"); } { if ( last != "" && ( skip == 0 || $$0 !~ /}/ ) ) { print last; } skip = 0; last = $$0; } END { print last; }' <  >$@
193 |  
194 |  distclean::
195 | @@ -336,8 +336,8 @@
196 |  # generated by mk-0th.awk
197 |  #   libname:    ncursesw
198 |  #   subsets:    ticlib+termlib+ext_tinfo+base+widechar+ext_funcs
199 | -#   ticlib:     
200 | -#   termlib:    
201 | +#   ticlib:
202 | +#   termlib:
203 |  
204 |  .SUFFIXES: .c .cc .h .i .ii
205 |  .c.i :
206 | @@ -945,7 +945,7 @@
207 |  #   echo:       no
208 |  #   subset:     ticlib+termlib+ext_tinfo+base+widechar+ext_funcs
209 |  #   crenames:   yes
210 | -#   cxxrenames: 
211 | +#   cxxrenames:
212 |  #   traces:     DEBUG
213 |  #   srcdir:     /data/git/python-wasm-plus/src/ncurses-6.1
214 |  
215 | @@ -2083,7 +2083,7 @@
216 |  #   echo:       no
217 |  #   subset:     ticlib+termlib+ext_tinfo+base+widechar+ext_funcs
218 |  #   crenames:   yes
219 | -#   cxxrenames: 
220 | +#   cxxrenames:
221 |  #   traces:     DEBUG
222 |  #   srcdir:     /data/git/python-wasm-plus/src/ncurses-6.1
223 |  
224 | 


--------------------------------------------------------------------------------
/templates/libs/xterm/vtx.js:
--------------------------------------------------------------------------------
  1 | "use strict";
  2 | 
  3 | var readline = { last_cx : -1 , index : 0, history : ["help()"] }
  4 | 
  5 | readline.complete = function (line) {
  6 |     if ( readline.history[ readline.history.length -1 ] != line )
  7 |         readline.history.push(line);
  8 |     readline.index = 0;
  9 |     python.PyRun_SimpleString(line + "\n")
 10 | 
 11 | }
 12 | 
 13 | 
 14 | if (!window.Terminal) {
 15 |     var xterm_cdn
 16 |     if (window.Module.config && window.Module.config.cdn) {
 17 |         xterm_cdn = window.Module.config.cdn+"xtermjsixel/"
 18 |         console.log("Terminal+ImageAddon importing from CDN :", xterm_cdn)
 19 |     } else {
 20 |         xterm_cdn ??= "https://pygame-web.github.io/archives/0.2.0/xtermjsixel/"
 21 |         console.warn("Terminal+ImageAddon importing from fallback ", xterm_cdn)
 22 |     }
 23 | 
 24 |     for (const css of ["xterm.css","style.css"]) {
 25 |             const cssref = document.createElement('link')
 26 |             cssref.setAttribute("rel", "stylesheet")
 27 |             cssref.setAttribute("type", "text/css")
 28 |             cssref.setAttribute("href", xterm_cdn + css)
 29 |             document.getElementsByTagName("head")[0].appendChild(cssref)
 30 |     }
 31 | 
 32 |     await import(xterm_cdn + "xterm.js")
 33 |     await import(xterm_cdn + "xterm-addon-image.js")
 34 | 
 35 | 
 36 | } else {
 37 |     console.warn("Terminal+ImageAddon were inlined")
 38 | }
 39 | 
 40 | 
 41 | 
 42 | export class WasmTerminal {
 43 |     constructor(hostid, cols, rows, addons_list) {
 44 |         this.input = ''
 45 |         this.resolveInput = null
 46 |         this.activeInput = true
 47 |         this.inputStartCursor = null
 48 | 
 49 |         this.nodup = 1
 50 | 
 51 |         this.xterm = new Terminal(
 52 |             {
 53 | //                allowTransparency: true,
 54 |                 scrollback: 10000,
 55 |                 fontSize: 14,
 56 |                 theme: { background: '#1a1c1f' },
 57 |                 cols: (cols || 100), rows: (rows || 25)
 58 |             }
 59 |         );
 60 | 
 61 |         if (typeof(Worker) !== "undefined") {
 62 | 
 63 |             for (const addon of (addons_list||[]) ) {
 64 |                 console.warn(hostid,cols,rows, addon)
 65 |                 const imageAddon = new ImageAddon.ImageAddon(addon.url , addon);
 66 |                 this.xterm.loadAddon(imageAddon);
 67 |                 this.sixel = function write(data) {
 68 |                     this.xterm.write(data)
 69 |                 }
 70 |             }
 71 | 
 72 | 
 73 |         } else {
 74 |             console.warn("No worker support, not loading xterm addons")
 75 |             this.sixel = function ni() {
 76 |                 console.warn("SIXEL N/I")
 77 |             }
 78 |         }
 79 | 
 80 | 
 81 | 
 82 |         this.xterm.open(document.getElementById(hostid))
 83 | 
 84 |         this.xterm.onKey((keyEvent) => {
 85 |             // Fix for iOS Keyboard Jumping on space
 86 |             if (keyEvent.key === " ") {
 87 |                 keyEvent.domEvent.preventDefault();
 88 |             }
 89 | 
 90 |         });
 91 | 
 92 |         this.xterm.onData(this.handleTermData)
 93 |     }
 94 | 
 95 |     open(container) {
 96 |         this.xterm.open(container);
 97 |     }
 98 | 
 99 |     ESC() {
100 |         for (var i=0; i < arguments.length; i++)
101 |             this.xterm.write("\x1b"+arguments[i])
102 |     }
103 | 
104 |     handleTermData = (data) => {
105 | 
106 |         const ord = data.charCodeAt(0);
107 |         let ofs;
108 | 
109 |         const cx = this.xterm.buffer.active.cursorX
110 | 
111 |         // TODO: Handle ANSI escape sequences
112 |         if (ord === 0x1b) {
113 | 
114 |             // Handle special characters
115 |             switch ( data.charCodeAt(1) ) {
116 |                 case 0x5b:
117 | 
118 |                     const cursor = readline.history.length  + readline.index
119 |                     var histo = ">>> "
120 | 
121 |                     switch ( data.charCodeAt(2) ) {
122 | 
123 |                         case 65:
124 |                             //console.log("VT UP")
125 |                             // memo cursor pos before entering histo
126 |                             if (!readline.index) {
127 |                                 if (readline.last_cx < 0 ) {
128 |                                     readline.last_cx = cx
129 |                                     readline.buffer = this.input
130 |                                 }
131 |                                 // TODO: get current line content from XTERM
132 |                             }
133 | 
134 |                             if ( cursor >0 ) {
135 |                                 readline.index--
136 |                                 histo = ">>> " +readline.history[cursor-1]
137 |                                 //console.log(__FILE__," histo-up  :", readline.index, cursor, histo)
138 | 
139 |                                 this.ESC("[132D","[2K")
140 |                                 this.xterm.write(histo)
141 |                                 this.input = histo.substr(4)
142 |                             }
143 |                             break;
144 | 
145 |                         case 66:
146 |                             //console.log("VT DOWN")
147 |                             if ( readline.index < 0  ) {
148 |                                 readline.index++
149 |                                 histo = histo + readline.history[cursor]
150 |                                 this.ESC("[132D","[2K")
151 |                                 this.xterm.write(histo)
152 |                                 this.input = histo.substr(4)
153 |                             } else {
154 |                                 // we are back
155 |                                 if (readline.last_cx >= 0) {
156 |                                     histo = histo + readline.buffer
157 |                                     readline.buffer = ""
158 |                                     this.ESC("[2K")
159 |                                     this.ESC("[132D")
160 |                                     this.xterm.write(histo)
161 |                                     this.input = histo.substr(4)
162 |                                     this.ESC("[132D")
163 |                                     this.ESC("["+readline.last_cx+"C")
164 |                                     //console.log(__FILE__," histo-back", readline.index, cursor, histo)
165 |                                     readline.last_cx = -1
166 |                                 }
167 |                             }
168 |                             break;
169 | 
170 |                         case 67:
171 |                             //console.log("VT RIGHT")
172 |                             break;
173 | 
174 |                         case 68:
175 |                             //console.log("VT LEFT")
176 |                             break;
177 | 
178 |                         default:
179 |                             console.log(__FILE__,"VT arrow ? "+data.charCodeAt(2))
180 |                     }
181 |                     break
182 |                 default:
183 | 
184 |                     console.log(__FILE__,"VT ESC "+data.charCodeAt(1))
185 |             }
186 | 
187 |         } else if (ord < 32 || ord === 0x7f) {
188 |             switch (data) {
189 |                 case "\r": // ENTER
190 |                 case "\x0a": // CTRL+J
191 |                 case "\x0d": // CTRL+M
192 |                     this.xterm.write('\r\n');
193 |                     readline.complete(this.input)
194 |                     this.input = '';
195 |                     break;
196 |                 case "\x7F": // BACKSPACE
197 |                 case "\x08": // CTRL+H
198 |                 case "\x04": // CTRL+D
199 |                     this.handleCursorErase(true);
200 |                     break;
201 | 
202 |                 case "\0x03": // CTRL+C
203 | 
204 |                     break
205 | 
206 |                 // ^L for clearing VT but keep X pos.
207 |                 case "\x0c":
208 |                     const cy = this.xterm.buffer.active.cursorY
209 | 
210 |                     if (cy < this.xterm.rows )
211 |                         this.ESC("[B","[J","[A")
212 | 
213 |                     this.ESC("[A","[K","[1J")
214 | 
215 |                     for (var i=1;i0 )
222 |                         this.ESC("["+cx+"C")
223 |                     break;
224 | 
225 |             default:
226 |                 switch (ord) {
227 |                     case 3:
228 |                         readline.complete("raise KeyboardInterrupt")
229 |                         break
230 |                 default :
231 |                     console.log("vt:" + ord )
232 |                 }
233 |             }
234 |         } else {
235 |             this.input += data;
236 |             this.xterm.write(data)
237 |         }
238 |     }
239 | 
240 |     handleCursorErase() {
241 |         // Don't delete past the start of input
242 |         if (this.xterm.buffer.active.cursorX <= this.inputStartCursor) {
243 |             return
244 |         }
245 |         this.input = this.input.slice(0, -1)
246 |         this.xterm.write('\x1B[D')
247 |         this.xterm.write('\x1B[P')
248 |     }
249 | 
250 | 
251 |     clear() {
252 |         this.xterm.clear()
253 |     }
254 | 
255 |     // direct write
256 |     sixel(data) {
257 |         this.xterm.write(data)
258 |     }
259 | 
260 |     print(message) {
261 |         const normInput = message.replace(/[\r\n]+/g, "\n").replace(/\n/g, "\r\n")
262 |         this.xterm.write(normInput)
263 |     }
264 | 
265 | }
266 | 
267 | 
268 | window.WasmTerminal = WasmTerminal
269 | window.readline = readline
270 | 
271 | 
272 | 
273 | 
274 | 
275 | 


--------------------------------------------------------------------------------
/templates/no-worker/pygame.html:
--------------------------------------------------------------------------------
  1 | 
  2 | 
  3 | 
  4 |     CPython
  5 |     
  6 |     
  7 |     
  8 | 
  9 |     
 10 | 
 11 |     
 12 | 
 13 |     
 14 |     
 15 |     
 64 | 
 65 |     
 66 |     
 67 |     
 68 | 
 69 |     
 70 | 
 71 | 
 72 | 
 73 | 
 74 | 
 75 |     
76 |
Downloading...
77 |
78 | 79 |
80 | 81 | 82 |
83 | 87 | 88 |
89 | 800x600=>470x320 90 | 91 | 92 | 93 | 94 |   95 |
96 | 97 |
98 | 99 |

100 |
101 |  VT340 102 | 103 |
104 |
105 | 106 | 119 | 120 | 121 | 122 | 123 | 339 | 340 | 341 | -------------------------------------------------------------------------------- /support/cross/__EMSCRIPTEN__.py: -------------------------------------------------------------------------------- 1 | # builtins.__EMSCRIPTEN__ 2 | # builtins.__WASI__ 3 | # builtins.__ANDROID__ also defines __ANDROID_API__ 4 | # builtins.__UPY__ too can point to this module 5 | 6 | import sys, os, builtins 7 | import json 8 | 9 | builtins.builtins = builtins 10 | 11 | builtins.true = True 12 | builtins.false = False 13 | 14 | def breakpointhook(*argv, **kw): 15 | aio.paused = True 16 | 17 | def shed_yield(): 18 | #TODO: coroutine id as pid 19 | print("86", time_time() - aio.enter, aio.spent ) 20 | return True 21 | 22 | sys.breakpointhook = breakpointhook 23 | 24 | this = __import__(__name__) 25 | 26 | # those __dunder__ are usually the same used in C conventions. 27 | 28 | try: 29 | __UPY__ 30 | except: 31 | if hasattr(sys.implementation, "mpy"): 32 | builtins.__UPY__ = this 33 | else: 34 | builtins.__UPY__ = None 35 | 36 | try: 37 | is_browser = not sys._emscripten_info.runtime.startswith('Node.js') 38 | if sys.platform in ("emscripten", "asm.js", "wasm"): 39 | builtins.__EMSCRIPTEN__ = this 40 | else: 41 | builtins.__EMSCRIPTEN__ = None 42 | 43 | except: 44 | is_browser = False 45 | 46 | try: 47 | from embed import * 48 | 49 | if not __UPY__: 50 | from platform import * 51 | from embed_emscripten import * 52 | from embed_browser import window, document, navigator, Object 53 | from embed_browser import fetch, console, prompt, alert, confirm 54 | Object_type = type( Object() ) 55 | except: 56 | pdb(__file__,":107 no browser/emscripten modules yet") 57 | 58 | 59 | # force use a fixed, tested version of uasyncio to avoid non-determinism 60 | if __UPY__: 61 | sys.modules["sys"] = sys 62 | sys.modules["builtins"] = builtins 63 | try: 64 | from . import uasyncio as uasyncio 65 | 66 | print("Warning : using WAPY uasyncio") 67 | except Exception as e: 68 | sys.print_exception(e) 69 | 70 | else: 71 | try: 72 | from . import uasyncio_cpy as uasyncio 73 | except: 74 | pdb("INFO: no uasyncio implementation found") 75 | uasyncio = aio 76 | 77 | sys.modules["uasyncio"] = uasyncio 78 | 79 | 80 | def init_platform(embed): 81 | # simulator won't run javascript for now 82 | if not hasattr(embed, "run_script"): 83 | pdb("186: no js engine") 84 | return False 85 | 86 | import json 87 | 88 | def js(code, delay=0): 89 | # keep a ref till next loop 90 | aio.protect.append(code) 91 | if not delay: 92 | result = embed.run_script(f"JSON.stringify({code})") 93 | if result is not None: 94 | return json.loads(result) 95 | elif delay < 0: 96 | embed.run_script(code) 97 | else: 98 | embed.run_script(code, int(delay)) 99 | 100 | embed.js = js 101 | 102 | 103 | if __WASM__: 104 | import _thread 105 | 106 | try: 107 | _thread.start_new_thread(lambda: None, ()) 108 | except RuntimeError: 109 | pdb("WARNING: that wasm build does not support threads") 110 | 111 | 112 | 113 | 114 | # ========================================== DOM EVENTS =============== 115 | 116 | if is_browser: 117 | # dom events 118 | class EventTarget: 119 | clients = {} 120 | events = [] 121 | def addEventListener(self, host, type, listener, options=None, useCapture=None ): 122 | cli = self.clients.setdefault(type,[]) 123 | cli.append( listener ) 124 | 125 | def build(self, evt_name, jsondata ): 126 | #print( evt_name, jsondata ) 127 | self.events.append( [evt_name, json.loads(jsondata) ] ) 128 | 129 | #def dispatchEvent 130 | 131 | async def process(self): 132 | import inspect 133 | from types import SimpleNamespace 134 | while not aio.exit: 135 | if len(self.events): 136 | evtype , evdata = self.events.pop(0) 137 | discarded = True 138 | for client in self.clients.get(evtype,[]): 139 | is_coro = inspect.iscoroutinefunction(client) 140 | print(" -> ", is_coro, client) 141 | discarded = False 142 | if is_coro: 143 | await client(SimpleNamespace(**evdata)) 144 | else: 145 | client(SimpleNamespace(**evdata)) 146 | if discarded: 147 | console.log(f"221 DISCARD : {evtype} {evdata}") 148 | 149 | await aio.sleep(0) 150 | 151 | EventTarget = EventTarget() 152 | 153 | 154 | #============================= PRELOADING ============================== 155 | 156 | 157 | ROOTDIR = f"/data/data/{sys.argv[0]}/assets" 158 | 159 | 160 | def explore(root): 161 | global prelist, preloadedWasm, preloadedImages, preloadedAudios, counter 162 | 163 | if counter<0: 164 | counter = 0 165 | 166 | import shutil 167 | preloads = f"{preloadedImages} {preloadedAudios} {preloadedWasm}".split(" ") 168 | print(f"194: preloads {preloads}") 169 | 170 | for current, dirnames, filenames in os.walk(root): 171 | for filename in filenames: 172 | if filename.find('.')>1: 173 | ext = filename.rsplit(".", 1)[-1].lower() 174 | if ext in preloads: 175 | counter += 1 176 | src = f"{current}/{filename}" 177 | dst = "/tmp/pre" + str(counter).zfill(4) + "." + ext 178 | print(src,"->",dst) 179 | shutil.copyfile(src, dst) 180 | prelist[src] = dst 181 | embed.preload(dst) 182 | 183 | 184 | def fix_preload_table(): 185 | global prelist, preloadedWasm, preloadedImages, preloadedAudios 186 | 187 | if embed.counter() < 0: 188 | pdb("233: asset manager not ready 0>", embed.counter()) 189 | aio.defer(fix_preload_table, (), {}, delay=60) 190 | # else: 191 | # pdb("236: all assets were ready at", embed.counter()) 192 | 193 | for ( 194 | src, 195 | dst, 196 | ) in prelist.items(): 197 | ext = dst.rsplit(".", 1)[-1] 198 | if ext in preloadedImages: 199 | ptype = "preloadedImages" 200 | elif ext in preloadedAudios: 201 | ptype = "preloadedAudios" 202 | elif ext == "so": 203 | ptype = "preloadedWasm" 204 | 205 | src = f"{ptype}[{repr(src)}]" 206 | dst = f"{ptype}[{repr(dst)}]" 207 | swap = f"({src}={dst}) && delete {dst}" 208 | embed.js(swap, -1) 209 | # print(swap) 210 | 211 | 212 | def run_main(PyConfig, loaderhome=None, loadermain="main.py"): 213 | global ROOTDIR 214 | global preloadedWasm, preloadedImages, preloadedAudios 215 | 216 | if loaderhome: 217 | pdb(f"218: appdir mapped to {loaderhome} by loader") 218 | ROOTDIR = str(loaderhome) 219 | 220 | # simulator won't run javascript for now 221 | if not hasattr(embed, "run_script"): 222 | pdb("209: no js engine") 223 | return False 224 | 225 | # do not do stuff if not called properly from our js loader. 226 | if PyConfig.get("executable", None) is None: 227 | # running in sim 228 | pdb("223: running in simulator") 229 | return False 230 | 231 | sys.executable = PyConfig["executable"] 232 | 233 | preloadedWasm = "so" 234 | preloadedImages = "png jpeg jpg gif" 235 | preloadedAudios = "wav ogg mp4" 236 | 237 | 238 | def preload_apk(p=None): 239 | global counter, prelist, ROOTDIR 240 | global explore, preloadedWasm, preloadedImages, preloadedAudios 241 | ROOTDIR = p or ROOTDIR 242 | if os.path.isdir(ROOTDIR): 243 | os.chdir(ROOTDIR) 244 | else: 245 | pdb(f"cannot chdir to {ROOTDIR=}") 246 | return 247 | 248 | ROOTDIR = os.getcwd() 249 | LSRC = len(ROOTDIR) + 1 250 | counter = -1 251 | prelist = {} 252 | 253 | sys.path.insert(0, ROOTDIR) 254 | 255 | explore(ROOTDIR) 256 | 257 | if counter<0: 258 | pdb(f"{ROOTDIR=}") 259 | pdb(f"{os.getcwd()=}") 260 | 261 | print(f"assets found :", counter) 262 | if not counter: 263 | embed.run() 264 | 265 | return True 266 | 267 | import aio 268 | 269 | if PyConfig.get("interactive", False): 270 | import aio.clock 271 | aio.clock.start(x=80) 272 | 273 | # org.python REPL no preload ! 274 | preload = (sys.argv[0] != 'org.python') 275 | else: 276 | # org.python script 277 | preload = True 278 | 279 | pdb(f"274: preload status {preload}") 280 | 281 | if preload and preload_apk(): 282 | 283 | def fix_preload_table_apk(): 284 | global fix_preload_table, ROOTDIR 285 | fix_preload_table() 286 | os.chdir(ROOTDIR) 287 | sys.path.insert(0, ROOTDIR) 288 | if loadermain: 289 | if os.path.isfile("main.py"): 290 | print(f"283: running {ROOTDIR}/{loadermain} for {sys.argv[0]} (deferred)") 291 | aio.defer(execfile, [f"{ROOTDIR}/{loadermain}"], {}) 292 | else: 293 | pdb(f"no {loadermain} found for {sys.argv[0]} in {ROOTDIR}") 294 | aio.defer(embed.prompt, (), {}, delay=2000) 295 | # else: 296 | # pdb(f"297: no loadermain request for {ROOTDIR=}") 297 | 298 | # C should unlock aio loop when preload count reach 0. 299 | 300 | else: 301 | def fix_preload_table_apk(): 302 | global fix_preload_table_apk, ROOTDIR 303 | pdb("no assets preloaded") 304 | os.chdir(ROOTDIR) 305 | aio.defer(embed.prompt, (),{}) 306 | 307 | # unlock embed looper because no preloading 308 | embed.run() 309 | 310 | aio.defer(fix_preload_table_apk, (), {}, delay=1000) 311 | 312 | if not aio.started: 313 | aio.started = True 314 | aio.create_task(EventTarget.process()) 315 | else: 316 | print("308: EventTarget delayed by loader") 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | # 344 | -------------------------------------------------------------------------------- /templates/no-worker/python311.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CPython 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 22 | 23 | 24 | 25 | 26 | 27 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 |
81 |
Downloading...
82 |
83 | 84 |
85 | 86 | 87 |

88 | 96 | 97 |
98 | 99 |
100 |
101 |
min
102 |
avg
103 |
max
104 | 105 |
106 |
107 | 108 |
109 | 113 | 114 |
115 | Canvas2D/3D (SDL2) 116 | 117 | 118 | 119 |   120 |
121 | 122 |
123 | 124 |
125 | 126 | 140 | 141 | 142 | 143 | 144 | 379 | 380 | 381 | -------------------------------------------------------------------------------- /support/__EMSCRIPTEN__.patches/3.11/hashlib.py: -------------------------------------------------------------------------------- 1 | #. Copyright (C) 2005-2010 Gregory P. Smith (greg@krypto.org) 2 | # Licensed to PSF under a Contributor Agreement. 3 | # 4 | 5 | __doc__ = """hashlib module - A common interface to many hash functions. 6 | 7 | new(name, data=b'', **kwargs) - returns a new hash object implementing the 8 | given hash function; initializing the hash 9 | using the given binary data. 10 | 11 | Named constructor functions are also available, these are faster 12 | than using new(name): 13 | 14 | md5(), sha1(), sha224(), sha256(), sha384(), sha512(), blake2b(), blake2s(), 15 | sha3_224, sha3_256, sha3_384, sha3_512, shake_128, and shake_256. 16 | 17 | More algorithms may be available on your platform but the above are guaranteed 18 | to exist. See the algorithms_guaranteed and algorithms_available attributes 19 | to find out what algorithm names can be passed to new(). 20 | 21 | NOTE: If you want the adler32 or crc32 hash functions they are available in 22 | the zlib module. 23 | 24 | Choose your hash function wisely. Some have known collision weaknesses. 25 | sha384 and sha512 will be slow on 32 bit platforms. 26 | 27 | Hash objects have these methods: 28 | - update(data): Update the hash object with the bytes in data. Repeated calls 29 | are equivalent to a single call with the concatenation of all 30 | the arguments. 31 | - digest(): Return the digest of the bytes passed to the update() method 32 | so far as a bytes object. 33 | - hexdigest(): Like digest() except the digest is returned as a string 34 | of double length, containing only hexadecimal digits. 35 | - copy(): Return a copy (clone) of the hash object. This can be used to 36 | efficiently compute the digests of datas that share a common 37 | initial substring. 38 | 39 | For example, to obtain the digest of the byte string 'Nobody inspects the 40 | spammish repetition': 41 | 42 | >>> import hashlib 43 | >>> m = hashlib.md5() 44 | >>> m.update(b"Nobody inspects") 45 | >>> m.update(b" the spammish repetition") 46 | >>> m.digest() 47 | b'\\xbbd\\x9c\\x83\\xdd\\x1e\\xa5\\xc9\\xd9\\xde\\xc9\\xa1\\x8d\\xf0\\xff\\xe9' 48 | 49 | More condensed: 50 | 51 | >>> hashlib.sha224(b"Nobody inspects the spammish repetition").hexdigest() 52 | 'a4337bc45a8fc544c03f52dc550cd6e1e87021bc896588bd79e901e2' 53 | 54 | """ 55 | 56 | # This tuple and __get_builtin_constructor() must be modified if a new 57 | # always available algorithm is added. 58 | __always_supported = ('md5', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512') 59 | 60 | 61 | # 'blake2b', 'blake2s', 62 | # 'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512', 63 | # 'shake_128', 'shake_256') 64 | 65 | 66 | algorithms_guaranteed = set(__always_supported) 67 | algorithms_available = set(__always_supported) 68 | 69 | __all__ = __always_supported + ('new', 'algorithms_guaranteed', 70 | 'algorithms_available', 'pbkdf2_hmac', 'file_digest') 71 | 72 | 73 | __builtin_constructor_cache = {} 74 | 75 | # Prefer our blake2 implementation 76 | # OpenSSL 1.1.0 comes with a limited implementation of blake2b/s. The OpenSSL 77 | # implementations neither support keyed blake2 (blake2 MAC) nor advanced 78 | # features like salt, personalization, or tree hashing. OpenSSL hash-only 79 | # variants are available as 'blake2b512' and 'blake2s256', though. 80 | __block_openssl_constructor = { 81 | 'blake2b', 'blake2s', 82 | } 83 | 84 | def __get_builtin_constructor(name): 85 | cache = __builtin_constructor_cache 86 | constructor = cache.get(name) 87 | if constructor is not None: 88 | return constructor 89 | try: 90 | if name in {'SHA1', 'sha1'}: 91 | import _sha1 92 | cache['SHA1'] = cache['sha1'] = _sha1.sha1 93 | elif name in {'MD5', 'md5'}: 94 | import _md5 95 | cache['MD5'] = cache['md5'] = _md5.md5 96 | elif name in {'SHA256', 'sha256', 'SHA224', 'sha224'}: 97 | import _sha256 98 | cache['SHA224'] = cache['sha224'] = _sha256.sha224 99 | cache['SHA256'] = cache['sha256'] = _sha256.sha256 100 | elif name in {'SHA512', 'sha512', 'SHA384', 'sha384'}: 101 | import _sha512 102 | cache['SHA384'] = cache['sha384'] = _sha512.sha384 103 | cache['SHA512'] = cache['sha512'] = _sha512.sha512 104 | elif name in {'blake2b', 'blake2s'}: 105 | import _blake2 106 | cache['blake2b'] = _blake2.blake2b 107 | cache['blake2s'] = _blake2.blake2s 108 | elif name in {'sha3_224', 'sha3_256', 'sha3_384', 'sha3_512'}: 109 | import _sha3 110 | cache['sha3_224'] = _sha3.sha3_224 111 | cache['sha3_256'] = _sha3.sha3_256 112 | cache['sha3_384'] = _sha3.sha3_384 113 | cache['sha3_512'] = _sha3.sha3_512 114 | elif name in {'shake_128', 'shake_256'}: 115 | import _sha3 116 | cache['shake_128'] = _sha3.shake_128 117 | cache['shake_256'] = _sha3.shake_256 118 | except (ImportError, ModuleNotFoundError): 119 | pass # no extension module, this hash is unsupported. 120 | 121 | constructor = cache.get(name) 122 | if constructor is not None: 123 | return constructor 124 | 125 | raise ValueError('unsupported hash type ' + name) 126 | 127 | 128 | def __get_openssl_constructor(name): 129 | if name in __block_openssl_constructor: 130 | # Prefer our builtin blake2 implementation. 131 | return __get_builtin_constructor(name) 132 | try: 133 | # MD5, SHA1, and SHA2 are in all supported OpenSSL versions 134 | # SHA3/shake are available in OpenSSL 1.1.1+ 135 | f = getattr(_hashlib, 'openssl_' + name) 136 | # Allow the C module to raise ValueError. The function will be 137 | # defined but the hash not actually available. Don't fall back to 138 | # builtin if the current security policy blocks a digest, bpo#40695. 139 | f(usedforsecurity=False) 140 | # Use the C function directly (very fast) 141 | return f 142 | except (AttributeError, ValueError): 143 | return __get_builtin_constructor(name) 144 | 145 | 146 | def __py_new(name, data=b'', **kwargs): 147 | """new(name, data=b'', **kwargs) - Return a new hashing object using the 148 | named algorithm; optionally initialized with data (which must be 149 | a bytes-like object). 150 | """ 151 | return __get_builtin_constructor(name)(data, **kwargs) 152 | 153 | 154 | def __hash_new(name, data=b'', **kwargs): 155 | """new(name, data=b'') - Return a new hashing object using the named algorithm; 156 | optionally initialized with data (which must be a bytes-like object). 157 | """ 158 | if name in __block_openssl_constructor: 159 | # Prefer our builtin blake2 implementation. 160 | return __get_builtin_constructor(name)(data, **kwargs) 161 | try: 162 | return _hashlib.new(name, data, **kwargs) 163 | except ValueError: 164 | # If the _hashlib module (OpenSSL) doesn't support the named 165 | # hash, try using our builtin implementations. 166 | # This allows for SHA224/256 and SHA384/512 support even though 167 | # the OpenSSL library prior to 0.9.8 doesn't provide them. 168 | return __get_builtin_constructor(name)(data) 169 | 170 | 171 | try: 172 | import _hashlib 173 | new = __hash_new 174 | __get_hash = __get_openssl_constructor 175 | algorithms_available = algorithms_available.union( 176 | _hashlib.openssl_md_meth_names) 177 | except ImportError: 178 | _hashlib = None 179 | new = __py_new 180 | __get_hash = __get_builtin_constructor 181 | 182 | try: 183 | # OpenSSL's PKCS5_PBKDF2_HMAC requires OpenSSL 1.0+ with HMAC and SHA 184 | from _hashlib import pbkdf2_hmac 185 | except ImportError: 186 | from warnings import warn as _warn 187 | _trans_5C = bytes((x ^ 0x5C) for x in range(256)) 188 | _trans_36 = bytes((x ^ 0x36) for x in range(256)) 189 | 190 | def pbkdf2_hmac(hash_name, password, salt, iterations, dklen=None): 191 | """Password based key derivation function 2 (PKCS #5 v2.0) 192 | 193 | This Python implementations based on the hmac module about as fast 194 | as OpenSSL's PKCS5_PBKDF2_HMAC for short passwords and much faster 195 | for long passwords. 196 | """ 197 | _warn( 198 | "Python implementation of pbkdf2_hmac() is deprecated.", 199 | category=DeprecationWarning, 200 | stacklevel=2 201 | ) 202 | if not isinstance(hash_name, str): 203 | raise TypeError(hash_name) 204 | 205 | if not isinstance(password, (bytes, bytearray)): 206 | password = bytes(memoryview(password)) 207 | if not isinstance(salt, (bytes, bytearray)): 208 | salt = bytes(memoryview(salt)) 209 | 210 | # Fast inline HMAC implementation 211 | inner = new(hash_name) 212 | outer = new(hash_name) 213 | blocksize = getattr(inner, 'block_size', 64) 214 | if len(password) > blocksize: 215 | password = new(hash_name, password).digest() 216 | password = password + b'\x00' * (blocksize - len(password)) 217 | inner.update(password.translate(_trans_36)) 218 | outer.update(password.translate(_trans_5C)) 219 | 220 | def prf(msg, inner=inner, outer=outer): 221 | # PBKDF2_HMAC uses the password as key. We can re-use the same 222 | # digest objects and just update copies to skip initialization. 223 | icpy = inner.copy() 224 | ocpy = outer.copy() 225 | icpy.update(msg) 226 | ocpy.update(icpy.digest()) 227 | return ocpy.digest() 228 | 229 | if iterations < 1: 230 | raise ValueError(iterations) 231 | if dklen is None: 232 | dklen = outer.digest_size 233 | if dklen < 1: 234 | raise ValueError(dklen) 235 | 236 | dkey = b'' 237 | loop = 1 238 | from_bytes = int.from_bytes 239 | while len(dkey) < dklen: 240 | prev = prf(salt + loop.to_bytes(4)) 241 | # endianness doesn't matter here as long to / from use the same 242 | rkey = from_bytes(prev) 243 | for i in range(iterations - 1): 244 | prev = prf(prev) 245 | # rkey = rkey ^ prev 246 | rkey ^= from_bytes(prev) 247 | loop += 1 248 | dkey += rkey.to_bytes(inner.digest_size) 249 | 250 | return dkey[:dklen] 251 | 252 | try: 253 | # OpenSSL's scrypt requires OpenSSL 1.1+ 254 | from _hashlib import scrypt 255 | except ImportError: 256 | pass 257 | 258 | 259 | def file_digest(fileobj, digest, /, *, _bufsize=2**18): 260 | """Hash the contents of a file-like object. Returns a digest object. 261 | 262 | *fileobj* must be a file-like object opened for reading in binary mode. 263 | It accepts file objects from open(), io.BytesIO(), and SocketIO objects. 264 | The function may bypass Python's I/O and use the file descriptor *fileno* 265 | directly. 266 | 267 | *digest* must either be a hash algorithm name as a *str*, a hash 268 | constructor, or a callable that returns a hash object. 269 | """ 270 | # On Linux we could use AF_ALG sockets and sendfile() to archive zero-copy 271 | # hashing with hardware acceleration. 272 | if isinstance(digest, str): 273 | digestobj = new(digest) 274 | else: 275 | digestobj = digest() 276 | 277 | if hasattr(fileobj, "getbuffer"): 278 | # io.BytesIO object, use zero-copy buffer 279 | digestobj.update(fileobj.getbuffer()) 280 | return digestobj 281 | 282 | # Only binary files implement readinto(). 283 | if not ( 284 | hasattr(fileobj, "readinto") 285 | and hasattr(fileobj, "readable") 286 | and fileobj.readable() 287 | ): 288 | raise ValueError( 289 | f"'{fileobj!r}' is not a file-like object in binary reading mode." 290 | ) 291 | 292 | # binary file, socket.SocketIO object 293 | # Note: socket I/O uses different syscalls than file I/O. 294 | buf = bytearray(_bufsize) # Reusable buffer to reduce allocations. 295 | view = memoryview(buf) 296 | while True: 297 | size = fileobj.readinto(buf) 298 | if size == 0: 299 | break # EOF 300 | digestobj.update(view[:size]) 301 | 302 | return digestobj 303 | 304 | 305 | for __func_name in __always_supported: 306 | # try them all, some may not work due to the OpenSSL 307 | # version not supporting that algorithm. 308 | try: 309 | globals()[__func_name] = __get_hash(__func_name) 310 | except ValueError: 311 | import logging 312 | logging.exception('code for hash %s was not found.', __func_name) 313 | 314 | 315 | # Cleanup locals() 316 | del __always_supported, __func_name, __get_hash 317 | del __py_new, __hash_new, __get_openssl_constructor 318 | -------------------------------------------------------------------------------- /scripts/cpython-build-emsdk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | . ${CONFIG:-config} 4 | 5 | # TODO: 6 | # fix /pip/_internal/operations/install/wheel.py 7 | # for allowing to avoid pyc creation 8 | 9 | echo " 10 | * building cpython-wasm EMSDK_PYTHON=$SYS_PYTHON 11 | " 1>&2 12 | 13 | 14 | export PYTHON_FOR_BUILD=${PYTHON_FOR_BUILD:-${HPY}} 15 | 16 | # remove old compiler wrapper to avoid conflicts 17 | [ -f $HOST_PREFIX/bin/cc ] && rm $HOST_PREFIX/bin/cc 18 | 19 | . ./scripts/emsdk-fetch.sh 20 | 21 | REBUILD_WASM=${REBUILD_WASMPY:-false} 22 | 23 | if $REBUILD || $REBUILD_WASMPY 24 | then 25 | rm -rf build/cpython-wasm/ build/pycache/config.cache 26 | rm build/cpython-wasm/libpython${PYBUILD}.a 2>/dev/null 27 | rm prebuilt/emsdk/libpython${PYBUILD}.a prebuilt/emsdk/${PYBUILD}/*.so 28 | REBUILD=true 29 | fi 30 | 31 | # 3.10 is not wasm stable 32 | if [ -f support/__EMSCRIPTEN__.patches/${PYBUILD}.diff ] 33 | then 34 | pushd src/cpython${PYBUILD} 2>&1 >/dev/null 35 | patch -p1 < ../../support/__EMSCRIPTEN__.patches/${PYBUILD}.diff 36 | popd 2>&1 >/dev/null 37 | fi 38 | 39 | 40 | if [ -f $EMSDK/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/pic/libffi.a ] 41 | then 42 | echo " 43 | * ffi already built 44 | " 1>&2 45 | else 46 | echo " 47 | * building libffi javascript port 48 | " 1>&2 49 | 50 | if [ -d src/libffi ] 51 | then 52 | echo -n 53 | else 54 | pushd src 2>&1 >/dev/null 55 | git clone https://github.com/pmp-p/libffi-emscripten.git libffi 56 | popd 57 | fi 58 | 59 | mkdir -p build/libffi $PREFIX 60 | pushd build/libffi 61 | 62 | #TODO: check if export PATH=${HOST_PREFIX}/bin:$PATH is really set to avoid system python with different bytecode 63 | #and no loder lib-dynload in the way. 64 | 65 | export EMCC_CFLAGS="-O0 -g0 -fPIC" 66 | 67 | CFLAGS="-O0 -g0 -fPIC" \ 68 | emconfigure $ROOT/src/libffi/configure --host=wasm32-tot-linux\ 69 | --prefix=$PREFIX --enable-static --disable-shared --disable-dependency-tracking\ 70 | --disable-builddir --disable-multi-os-directory --disable-raw-api --disable-docs 71 | 72 | emmake make install 73 | 74 | unset EMCC_CFLAGS 75 | popd 76 | 77 | cp -fv ${PREFIX}/lib/libffi.a $EMSDK/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/pic/ 78 | cp -vf ${PREFIX}/include/ffi*.h ${EMSDK}/upstream/emscripten/cache/sysroot/include/ 79 | 80 | ffipc=${SDKROOT}/emsdk/upstream/emscripten/system/lib/pkgconfig/libffi.pc 81 | cat > $ffipc <&2 128 | 129 | 130 | 131 | if [ -f build/cpython-wasm/libpython${PYBUILD}.a ] 132 | then 133 | echo " 134 | * not rebuilding cpython-wasm for [$PYDK_PYTHON_HOST_PLATFORM] 135 | " 1>&2 136 | else 137 | echo " 138 | * rebuilding build/cpython-wasm for [$PYDK_PYTHON_HOST_PLATFORM] 139 | PYTHON_FOR_BUILD=${PYTHON_FOR_BUILD} 140 | " 1>&2 141 | 142 | 143 | mkdir -p build/cpython-wasm $PREFIX 144 | pushd build/cpython-wasm 145 | 146 | # --with-tzpath="/usr/share/zoneinfo" \ 147 | 148 | export EMCC_CFLAGS="$CPOPTS -D_XOPEN_SOURCE_EXTENDED=1 -I$PREFIX/include/ncursesw -sUSE_ZLIB -sUSE_BZIP2" 149 | 150 | CPPFLAGS="$CPPFLAGS -I$PREFIX/include/ncursesw" 151 | CFLAGS="$CPPFLAGS -I$PREFIX/include/ncursesw" 152 | 153 | # CFLAGS="-DHAVE_FFI_PREP_CIF_VAR=1 -DHAVE_FFI_PREP_CLOSURE_LOC=1 -DHAVE_FFI_CLOSURE_ALLOC=1" 154 | 155 | cat $ROOT/src/cpython${PYBUILD}/Tools/wasm/config.site-wasm32-emscripten \ 156 | > $ROOT/src/cpython${PYBUILD}/Tools/wasm/config.site-wasm32-pydk 157 | 158 | cat >> $ROOT/src/cpython${PYBUILD}/Tools/wasm/config.site-wasm32-pydk << END 159 | 160 | 161 | have_libffi=yes 162 | ac_cv_func_dlopen=yes 163 | ac_cv_lib_ffi_ffi_call=yes 164 | py_cv_module__ctypes=yes 165 | py_cv_module__ctypes_test=yes 166 | END 167 | 168 | 169 | 170 | # OPT="$CPOPTS -DNDEBUG -fwrapv" \ 171 | # --with-c-locale-coercion --without-pydebug --without-pymalloc --disable-ipv6 \ 172 | 173 | # --with-libs='-lz -lffi' \ 174 | 175 | 176 | CONFIG_SITE=$ROOT/src/cpython${PYBUILD}/Tools/wasm/config.site-wasm32-pydk \ 177 | emconfigure $ROOT/src/cpython${PYBUILD}/configure -C --with-emscripten-target=browser \ 178 | --cache-file=${PYTHONPYCACHEPREFIX}/config.cache \ 179 | --enable-wasm-dynamic-linking $TESTSUITE\ 180 | --host=$PYDK_PYTHON_HOST_PLATFORM \ 181 | --build=$($ROOT/src/cpython${PYBUILD}/config.guess) \ 182 | --prefix=$PREFIX \ 183 | --with-build-python=${PYTHON_FOR_BUILD} 184 | 185 | mkdir -p ${PYTHONPYCACHEPREFIX}/empty 186 | touch ${PYTHONPYCACHEPREFIX}/empty/$($HPY -V|cut -f2 -d' ') 187 | 188 | #echo "#define HAVE_NCURSES_H" >> pyconfig.h 189 | if echo $PYBUILD|grep -q 3.10 190 | then 191 | cat > Modules/Setup.local < Modules/Setup.local <&2 226 | 227 | exit 1 228 | fi 229 | 230 | rm -rf $(find $ROOT/devices/ -type d|grep /__pycache__$) 231 | 232 | popd 233 | 234 | mkdir -p ${SDKROOT}/prebuilt/emsdk/${PYBUILD}/site-packages 235 | mkdir -p ${SDKROOT}/prebuilt/emsdk/${PYBUILD}/lib-dynload 236 | 237 | if [ -d $PREFIX/lib/python${PYBUILD}/lib-dynload ] 238 | then 239 | # move them to MEMFS 240 | mv $PREFIX/lib/python${PYBUILD}/lib-dynload/* ${SDKROOT}/prebuilt/emsdk/${PYBUILD}/lib-dynload/ 241 | 242 | # specific platform support 243 | cp -Rfv $ROOT/support/__EMSCRIPTEN__.patches/${PYBUILD}/. $PREFIX/lib/python${PYBUILD}/ 244 | 245 | cp -vf build/cpython-wasm/libpython${PYBUILD}.a prebuilt/emsdk/ 246 | for lib in $(find build/cpython-wasm/|grep lib.*.a$) 247 | do 248 | name=$(basename $lib .a) 249 | cp $lib prebuilt/emsdk/${name}${PYBUILD}.a 250 | done 251 | rmdir $PREFIX/lib/python${PYBUILD}/lib-dynload 252 | fi 253 | fi 254 | 255 | mkdir -p $PYTHONPYCACHEPREFIX/sysconfig 256 | 257 | 258 | # FIXME: seems CI cannot locate that one with python3-wasm 259 | cp $PREFIX/lib/python${PYBUILD}/_sysconfigdata__emscripten_wasm32-emscripten.py \ 260 | ${SDKROOT}/prebuilt/emsdk/${PYBUILD}/_sysconfigdata__emscripten_debug.py 261 | 262 | sed -i 's|-Os|-O0|g' ${SDKROOT}/prebuilt/emsdk/${PYBUILD}/_sysconfigdata__emscripten_debug.py 263 | sed -i 's|-g0|-g3|g' ${SDKROOT}/prebuilt/emsdk/${PYBUILD}/_sysconfigdata__emscripten_debug.py 264 | 265 | 266 | # python setup.py install --single-version-externally-managed --root=/ 267 | # pip3 install . 268 | 269 | cat > $HOST_PREFIX/bin/cc < ${PYTHONPYCACHEPREFIX}/.nanorc <${PYTHONPYCACHEPREFIX}/.numpy-site.cfg < $ROOT/${PYDK_PYTHON_HOST_PLATFORM}-shell.sh < \${HOME}/.pythonrc.py 373 | 374 | export PS1="[PyDK:wasm] \w $ " 375 | 376 | export _PYTHON_SYSCONFIGDATA_NAME=_sysconfigdata__emscripten_ 377 | 378 | END 379 | 380 | cat > $HOST_PREFIX/bin/python3-wasm <&2 412 | ln -sf $HOST_PREFIX/bin/python${PYBUILD} $HOST_PREFIX/bin/python3 413 | 414 | cp -f $HOST_PREFIX/bin/python3-wasm ${ROOT}/ 415 | 416 | 417 | HPFX=./devices/$(arch)/usr/lib/python${PYBUILD} 418 | TPFX=./devices/emsdk/usr/lib/python${PYBUILD} 419 | 420 | rm $TPFX/ensurepip/_bundled/setuptools-*.whl 421 | 422 | for moveit in setuptools distutils _distutils _distutils_hack pkg_resources 423 | do 424 | echo " 425 | * migrating ${moveit} 426 | " 1>&2 427 | cp -rf $HPFX/${moveit} $TPFX/ 428 | cp -rf $HPFX/${moveit}-* $TPFX/ 429 | done 430 | 431 | 432 | unset PYTHON_FOR_BUILD 433 | unset EMCC_CFLAGS 434 | --------------------------------------------------------------------------------