Fossil SCM
Merge in pikchrshow-wasm branch: reimplement /pikchrshow using a client-side WASM build of pikchr.c, plus related feature-adjacent tweaks in mimetype handling.
Commit
7fcb462680ce63ae8a9be120c00f46147370b0d006338bfcf58458e80270bff1
Parent
f98a4f5c94a844d…
24 files changed
+11
+36
+108
+42
+1
-2
+4
-5
+57
-11
+14
-6
+7
-1
+9
-1
+24
+10
-8
+10
+147
-9
+2
-2
+64
+65
+14
-1
+6
-1
+12
-2
+123
-3
+4
-1
+4
-1
~
Makefile.in
~
auto.def
~
extsrc/pikchr-worker.js
~
extsrc/pikchr.js
~
extsrc/pikchr.wasm
~
skins/darkmode/css.txt
~
src/builtin.c
~
src/cgi.c
~
src/default.css
~
src/doc.c
~
src/fossil.page.pikchrshow.js
~
src/fossil.page.pikchrshowasm.js
~
src/json.c
~
src/main.mk
~
src/pikchrshow.c
~
src/style.c
~
src/style.pikchrshow.css
~
tools/emcc.sh.in
~
tools/makemake.tcl
~
win/Makefile.mingw
~
win/Makefile.msc
~
www/build.wiki
~
www/changes.wiki
~
www/changes.wiki
+11
| --- Makefile.in | ||
| +++ Makefile.in | ||
| @@ -72,10 +72,21 @@ | ||
| 72 | 72 | USE_SEE = @USE_SEE@ |
| 73 | 73 | APPNAME = fossil |
| 74 | 74 | # |
| 75 | 75 | # APPNAME = fossil-fuzz |
| 76 | 76 | # may be more appropriate for fuzzing. |
| 77 | + | |
| 78 | +#### Emscripten stuff for optionally doing in-tree builds | |
| 79 | +# of any WASM components. We store precompiled WASM in the the SCM, so | |
| 80 | +# this is only useful for people who actively work on WASM | |
| 81 | +# components. EMSDK_ENV refers to the "environment" script which comes | |
| 82 | +# with the Emscripten SDK package: | |
| 83 | +# https://emscripten.org/docs/getting_started/downloads.html | |
| 84 | +EMSDK_HOME = @EMSDK_HOME@ | |
| 85 | +EMSDK_ENV = @EMSDK_ENV@ | |
| 86 | +EMCC_OPT = @EMCC_OPT@ | |
| 87 | +EMCC_WRAPPER = $(SRCDIR_tools)/emcc.sh | |
| 77 | 88 | |
| 78 | 89 | .PHONY: all tags |
| 79 | 90 | |
| 80 | 91 | include $(SRCDIR)/main.mk |
| 81 | 92 | |
| 82 | 93 |
| --- Makefile.in | |
| +++ Makefile.in | |
| @@ -72,10 +72,21 @@ | |
| 72 | USE_SEE = @USE_SEE@ |
| 73 | APPNAME = fossil |
| 74 | # |
| 75 | # APPNAME = fossil-fuzz |
| 76 | # may be more appropriate for fuzzing. |
| 77 | |
| 78 | .PHONY: all tags |
| 79 | |
| 80 | include $(SRCDIR)/main.mk |
| 81 | |
| 82 |
| --- Makefile.in | |
| +++ Makefile.in | |
| @@ -72,10 +72,21 @@ | |
| 72 | USE_SEE = @USE_SEE@ |
| 73 | APPNAME = fossil |
| 74 | # |
| 75 | # APPNAME = fossil-fuzz |
| 76 | # may be more appropriate for fuzzing. |
| 77 | |
| 78 | #### Emscripten stuff for optionally doing in-tree builds |
| 79 | # of any WASM components. We store precompiled WASM in the the SCM, so |
| 80 | # this is only useful for people who actively work on WASM |
| 81 | # components. EMSDK_ENV refers to the "environment" script which comes |
| 82 | # with the Emscripten SDK package: |
| 83 | # https://emscripten.org/docs/getting_started/downloads.html |
| 84 | EMSDK_HOME = @EMSDK_HOME@ |
| 85 | EMSDK_ENV = @EMSDK_ENV@ |
| 86 | EMCC_OPT = @EMCC_OPT@ |
| 87 | EMCC_WRAPPER = $(SRCDIR_tools)/emcc.sh |
| 88 | |
| 89 | .PHONY: all tags |
| 90 | |
| 91 | include $(SRCDIR)/main.mk |
| 92 | |
| 93 |
M
auto.def
+36
| --- auto.def | ||
| +++ auto.def | ||
| @@ -28,10 +28,11 @@ | ||
| 28 | 28 | static=0 => {Link a static executable} |
| 29 | 29 | fusefs=1 => {Disable the Fuse Filesystem} |
| 30 | 30 | fossil-debug=0 => {Build with fossil debugging enabled} |
| 31 | 31 | no-opt=0 => {Build without optimization} |
| 32 | 32 | json=0 => {Build with fossil JSON API enabled} |
| 33 | + with-emsdk:path => {Directory containing the Emscripten SDK} | |
| 33 | 34 | } |
| 34 | 35 | |
| 35 | 36 | # Update the minimum required SQLite version number here, and also |
| 36 | 37 | # in src/main.c near the sqlite3_libversion_number() call. Take care |
| 37 | 38 | # that both places agree! |
| @@ -632,10 +633,37 @@ | ||
| 632 | 633 | set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \ |
| 633 | 634 | $tclconfig(TCL_LD_FLAGS)] |
| 634 | 635 | define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS) |
| 635 | 636 | define FOSSIL_ENABLE_TCL |
| 636 | 637 | } |
| 638 | + | |
| 639 | +# Emscripten is a purely optional component used only for doing | |
| 640 | +# in-tree builds of WASM stuff, as opposed to WASM binaries we import | |
| 641 | +# from other places. This is only set up for Unix-style OSes and is | |
| 642 | +# untested anywhere but Linux. | |
| 643 | +set emsdkHome [opt-val with-emsdk] | |
| 644 | +define EMSDK_HOME "" | |
| 645 | +define EMSDK_ENV "" | |
| 646 | +define EMCC_OPT "-Oz" | |
| 647 | +if {$emsdkHome eq "" && [info exists ::env(EMSDK)]} { | |
| 648 | + # Fall back to checking the environment. $EMSDK gets set | |
| 649 | + # by sourcing emsdk_env.sh. | |
| 650 | + set emsdkHome $::env(EMSDK) | |
| 651 | +} | |
| 652 | +if {$emsdkHome ne ""} { | |
| 653 | + define EMSDK_HOME $emsdkHome | |
| 654 | + set emsdkEnv "$emsdkHome/emsdk_env.sh" | |
| 655 | + if {[file exists $emsdkEnv]} { | |
| 656 | + puts "Using Emscripten SDK environment from $emsdkEnv." | |
| 657 | + define EMSDK_ENV $emsdkEnv | |
| 658 | + if {[info exists ::env(EMCC_OPT)]} { | |
| 659 | + define EMCC_OPT $::env(EMCC_OPT) | |
| 660 | + } | |
| 661 | + } else { | |
| 662 | + puts "emsdk_env.sh not found. Assuming emcc is in the PATH." | |
| 663 | + } | |
| 664 | +} | |
| 637 | 665 | |
| 638 | 666 | # Network functions require libraries on some systems |
| 639 | 667 | cc-check-function-in-lib gethostbyname nsl |
| 640 | 668 | if {![cc-check-function-in-lib socket {socket network}]} { |
| 641 | 669 | # Last resort, may be Windows |
| @@ -726,8 +754,16 @@ | ||
| 726 | 754 | # Linux can only infer the dependency on pthread from OpenSSL when |
| 727 | 755 | # doing dynamic linkage. |
| 728 | 756 | define-append LIBS -lpthread |
| 729 | 757 | } |
| 730 | 758 | |
| 759 | +if {[get-define EMSDK_HOME] ne ""} { | |
| 760 | + define EMCC_WRAPPER $::autosetup(dir)/../tools/emcc.sh | |
| 761 | + make-template tools/emcc.sh.in | |
| 762 | + catch {exec chmod u+x tools/emcc.sh} | |
| 763 | +} else { | |
| 764 | + define EMCC_WRAPPER "" | |
| 765 | + catch {exec rm -f tools/emcc.sh} | |
| 766 | +} | |
| 731 | 767 | |
| 732 | 768 | make-template Makefile.in |
| 733 | 769 | make-config-header autoconfig.h -auto {USE_* FOSSIL_*} |
| 734 | 770 | |
| 735 | 771 | ADDED extsrc/pikchr-worker.js |
| 736 | 772 | ADDED extsrc/pikchr.js |
| 737 | 773 | ADDED extsrc/pikchr.wasm |
| --- auto.def | |
| +++ auto.def | |
| @@ -28,10 +28,11 @@ | |
| 28 | static=0 => {Link a static executable} |
| 29 | fusefs=1 => {Disable the Fuse Filesystem} |
| 30 | fossil-debug=0 => {Build with fossil debugging enabled} |
| 31 | no-opt=0 => {Build without optimization} |
| 32 | json=0 => {Build with fossil JSON API enabled} |
| 33 | } |
| 34 | |
| 35 | # Update the minimum required SQLite version number here, and also |
| 36 | # in src/main.c near the sqlite3_libversion_number() call. Take care |
| 37 | # that both places agree! |
| @@ -632,10 +633,37 @@ | |
| 632 | set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \ |
| 633 | $tclconfig(TCL_LD_FLAGS)] |
| 634 | define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS) |
| 635 | define FOSSIL_ENABLE_TCL |
| 636 | } |
| 637 | |
| 638 | # Network functions require libraries on some systems |
| 639 | cc-check-function-in-lib gethostbyname nsl |
| 640 | if {![cc-check-function-in-lib socket {socket network}]} { |
| 641 | # Last resort, may be Windows |
| @@ -726,8 +754,16 @@ | |
| 726 | # Linux can only infer the dependency on pthread from OpenSSL when |
| 727 | # doing dynamic linkage. |
| 728 | define-append LIBS -lpthread |
| 729 | } |
| 730 | |
| 731 | |
| 732 | make-template Makefile.in |
| 733 | make-config-header autoconfig.h -auto {USE_* FOSSIL_*} |
| 734 | |
| 735 | DDED extsrc/pikchr-worker.js |
| 736 | DDED extsrc/pikchr.js |
| 737 | DDED extsrc/pikchr.wasm |
| --- auto.def | |
| +++ auto.def | |
| @@ -28,10 +28,11 @@ | |
| 28 | static=0 => {Link a static executable} |
| 29 | fusefs=1 => {Disable the Fuse Filesystem} |
| 30 | fossil-debug=0 => {Build with fossil debugging enabled} |
| 31 | no-opt=0 => {Build without optimization} |
| 32 | json=0 => {Build with fossil JSON API enabled} |
| 33 | with-emsdk:path => {Directory containing the Emscripten SDK} |
| 34 | } |
| 35 | |
| 36 | # Update the minimum required SQLite version number here, and also |
| 37 | # in src/main.c near the sqlite3_libversion_number() call. Take care |
| 38 | # that both places agree! |
| @@ -632,10 +633,37 @@ | |
| 633 | set tclconfig(TCL_LD_FLAGS) [string map [list -ldl ""] \ |
| 634 | $tclconfig(TCL_LD_FLAGS)] |
| 635 | define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS) |
| 636 | define FOSSIL_ENABLE_TCL |
| 637 | } |
| 638 | |
| 639 | # Emscripten is a purely optional component used only for doing |
| 640 | # in-tree builds of WASM stuff, as opposed to WASM binaries we import |
| 641 | # from other places. This is only set up for Unix-style OSes and is |
| 642 | # untested anywhere but Linux. |
| 643 | set emsdkHome [opt-val with-emsdk] |
| 644 | define EMSDK_HOME "" |
| 645 | define EMSDK_ENV "" |
| 646 | define EMCC_OPT "-Oz" |
| 647 | if {$emsdkHome eq "" && [info exists ::env(EMSDK)]} { |
| 648 | # Fall back to checking the environment. $EMSDK gets set |
| 649 | # by sourcing emsdk_env.sh. |
| 650 | set emsdkHome $::env(EMSDK) |
| 651 | } |
| 652 | if {$emsdkHome ne ""} { |
| 653 | define EMSDK_HOME $emsdkHome |
| 654 | set emsdkEnv "$emsdkHome/emsdk_env.sh" |
| 655 | if {[file exists $emsdkEnv]} { |
| 656 | puts "Using Emscripten SDK environment from $emsdkEnv." |
| 657 | define EMSDK_ENV $emsdkEnv |
| 658 | if {[info exists ::env(EMCC_OPT)]} { |
| 659 | define EMCC_OPT $::env(EMCC_OPT) |
| 660 | } |
| 661 | } else { |
| 662 | puts "emsdk_env.sh not found. Assuming emcc is in the PATH." |
| 663 | } |
| 664 | } |
| 665 | |
| 666 | # Network functions require libraries on some systems |
| 667 | cc-check-function-in-lib gethostbyname nsl |
| 668 | if {![cc-check-function-in-lib socket {socket network}]} { |
| 669 | # Last resort, may be Windows |
| @@ -726,8 +754,16 @@ | |
| 754 | # Linux can only infer the dependency on pthread from OpenSSL when |
| 755 | # doing dynamic linkage. |
| 756 | define-append LIBS -lpthread |
| 757 | } |
| 758 | |
| 759 | if {[get-define EMSDK_HOME] ne ""} { |
| 760 | define EMCC_WRAPPER $::autosetup(dir)/../tools/emcc.sh |
| 761 | make-template tools/emcc.sh.in |
| 762 | catch {exec chmod u+x tools/emcc.sh} |
| 763 | } else { |
| 764 | define EMCC_WRAPPER "" |
| 765 | catch {exec rm -f tools/emcc.sh} |
| 766 | } |
| 767 | |
| 768 | make-template Makefile.in |
| 769 | make-config-header autoconfig.h -auto {USE_* FOSSIL_*} |
| 770 | |
| 771 | DDED extsrc/pikchr-worker.js |
| 772 | DDED extsrc/pikchr.js |
| 773 | DDED extsrc/pikchr.wasm |
+108
| --- a/extsrc/pikchr-worker.js | ||
| +++ b/extsrc/pikchr-worker.js | ||
| @@ -0,0 +1,108 @@ | ||
| 1 | +/* | |
| 2 | + 2022-05-20 | |
| 3 | + | |
| 4 | + The author disresult like with DOM elements, | |
| 5 | + we have to define a lower-level message API. Messages abstractly | |
| 6 | + look like: | |
| 7 | + | |
| 8 | + { type: string, data: type-specific value } | |
| 9 | + | |
| 10 | + Where 'type' is used for dispatching and 'data' is a | |
| 11 | + 'type'-dependent value. | |
| 12 | + | |
| 13 | + The 'type' values expected by each side of the main/worker | |
| 14 | + connection vary. The types are described below but subject to | |
| 15 | + change at any time as this experiment evolves. | |
| 16 | + | |
| 17 | + Main-to-Worker message types: | |
| 18 | + | |
| 19 | + - pikchr: data=pikchr-format text to render or an object: | |
| 20 | + | |
| 21 | + { | |
| 22 | + pikchr: source code for the pikchr, | |
| 23 | + darkMode: boolean true to adjust colors for a dark color scheme, | |
| 24 | + cssClass: CSS class name to add to the typeshe author disclaims copyright to this source code. In place of a | |
| 25 | + legal notice, here is a blessing: | |
| 26 | + | |
| 27 | + * May you do good and not evil. | |
| 28 | + * May you find forgiveness for yourself and forgive others. | |
| 29 | + * May you share freely, never taking more than you give. | |
| 30 | + | |
| 31 | + *********************************************************************** | |
| 32 | + | |
| 33 | + This is a JS Worker file for use with the pikchr wasm build. It | |
| 34 | + loads the pikchr wasm module and offers access to it via the Worker | |
| 35 | + message-passing interface. | |
| 36 | + | |
| 37 | + Because we can have only a single message handler, as opposed to an | |
| 38 | + arbitrary n/* messages come in the form | |
| 39 | + | |
| 40 | + {type:'module', data:{ | |
| 41 | + type:'status', | |
| 42 | + data: {text:string|null, step:1-based-integer} | |
| 43 | + } | |
| 44 | + | |
| 45 | + with an incrementing step value for each subsequent message. When | |
| 46 | + the module loading is complete, a message with a text value of | |
| 47 | + n ull is posted. | |
| 48 | + | |
| 49 | + - pikchr: | |
| 50 | + | |
| 51 | + {type: 'pikchr', | |
| 52 | + data:{ | |
| 53 | + pikchr: input text, | |
| 54 | + result: rendered result (SVG on success, HTML on error), | |
| 55 | + isError: bool, true if .pikchr holds an error report, | |
| 56 | + flags: integer: flags used to configure the pikchr rendering, | |
| 57 | + width: if !isError, width (integer pixels) of the SVG, | |
| 58 | + height: if !isError, height (integer pixels) of the SVG | |
| 59 | + } | |
| 60 | + } | |
| 61 | + | |
| 62 | +*/ | |
| 63 | + | |
| 64 | +"use strict"; | |
| 65 | +(function(){ | |
| 66 | + /** | |
| 67 | + Posts a message in the form {type,data} unless passed more than | |
| 68 | + 2 args, in which case it posts {type, data:[arg1...argN]}. | |
| 69 | + */ | |
| 70 | + const wMsg = function(type,data){ | |
| 71 | + postMessage({ | |
| 72 | + type, | |
| 73 | + data: arguments.length<3 | |
| 74 | + ? data | |
| 75 | + : Array.prototype.slice.call(arguments,1) | |
| 76 | + }); | |
| 77 | + }; | |
| 78 | + | |
| 79 | + const stderr = function(){wMsg('stderr', Array.prototype.slice.call(arguments));}; | |
| 80 | + | |
| 81 | + self.onerror = function(/*message, source, lineno, colno, error*/) { | |
| 82 | + const err = arguments[4]; | |
| 83 | + if(err && 'ExitStatus'==err.name){ | |
| 84 | + /* This "cannot happen" for this wasm binding, but just in | |
| 85 | + case... */ | |
| 86 | + pikchrModule.isDead = true; | |
| 87 | + stderr("FATAL ERROR:", err.message); | |
| 88 | + stderr("Restarting the app requires reloading the page."); | |
| 89 | + wMsg('error', err); | |
| 90 | + } | |
| 91 | + pikchrModule.setStatus('Exception thrown, see JavaScript console: '+err); | |
| 92 | + }; | |
| 93 | + | |
| 94 | + self.onmessage = function f(ev){ | |
| 95 | + ev = ev.data; | |
| 96 | + switch(ev.type){ | |
| 97 | + /** | |
| 98 | + Runs the given text through pikchr and emits a 'pikchr' | |
| 99 | + message result (output format documented above). | |
| 100 | + | |
| 101 | + Fires a working/start event before it starts and | |
| 102 | + working/end event when it finishes. | |
| 103 | + */ | |
| 104 | + case 'pikchr': | |
| 105 | + if(pikchrModule.isDead){ | |
| 106 | + stderr( show-ready'); | |
| 107 | + }); | |
| 108 | +})(); |
| --- a/extsrc/pikchr-worker.js | |
| +++ b/extsrc/pikchr-worker.js | |
| @@ -0,0 +1,108 @@ | |
| --- a/extsrc/pikchr-worker.js | |
| +++ b/extsrc/pikchr-worker.js | |
| @@ -0,0 +1,108 @@ | |
| 1 | /* |
| 2 | 2022-05-20 |
| 3 | |
| 4 | The author disresult like with DOM elements, |
| 5 | we have to define a lower-level message API. Messages abstractly |
| 6 | look like: |
| 7 | |
| 8 | { type: string, data: type-specific value } |
| 9 | |
| 10 | Where 'type' is used for dispatching and 'data' is a |
| 11 | 'type'-dependent value. |
| 12 | |
| 13 | The 'type' values expected by each side of the main/worker |
| 14 | connection vary. The types are described below but subject to |
| 15 | change at any time as this experiment evolves. |
| 16 | |
| 17 | Main-to-Worker message types: |
| 18 | |
| 19 | - pikchr: data=pikchr-format text to render or an object: |
| 20 | |
| 21 | { |
| 22 | pikchr: source code for the pikchr, |
| 23 | darkMode: boolean true to adjust colors for a dark color scheme, |
| 24 | cssClass: CSS class name to add to the typeshe author disclaims copyright to this source code. In place of a |
| 25 | legal notice, here is a blessing: |
| 26 | |
| 27 | * May you do good and not evil. |
| 28 | * May you find forgiveness for yourself and forgive others. |
| 29 | * May you share freely, never taking more than you give. |
| 30 | |
| 31 | *********************************************************************** |
| 32 | |
| 33 | This is a JS Worker file for use with the pikchr wasm build. It |
| 34 | loads the pikchr wasm module and offers access to it via the Worker |
| 35 | message-passing interface. |
| 36 | |
| 37 | Because we can have only a single message handler, as opposed to an |
| 38 | arbitrary n/* messages come in the form |
| 39 | |
| 40 | {type:'module', data:{ |
| 41 | type:'status', |
| 42 | data: {text:string|null, step:1-based-integer} |
| 43 | } |
| 44 | |
| 45 | with an incrementing step value for each subsequent message. When |
| 46 | the module loading is complete, a message with a text value of |
| 47 | n ull is posted. |
| 48 | |
| 49 | - pikchr: |
| 50 | |
| 51 | {type: 'pikchr', |
| 52 | data:{ |
| 53 | pikchr: input text, |
| 54 | result: rendered result (SVG on success, HTML on error), |
| 55 | isError: bool, true if .pikchr holds an error report, |
| 56 | flags: integer: flags used to configure the pikchr rendering, |
| 57 | width: if !isError, width (integer pixels) of the SVG, |
| 58 | height: if !isError, height (integer pixels) of the SVG |
| 59 | } |
| 60 | } |
| 61 | |
| 62 | */ |
| 63 | |
| 64 | "use strict"; |
| 65 | (function(){ |
| 66 | /** |
| 67 | Posts a message in the form {type,data} unless passed more than |
| 68 | 2 args, in which case it posts {type, data:[arg1...argN]}. |
| 69 | */ |
| 70 | const wMsg = function(type,data){ |
| 71 | postMessage({ |
| 72 | type, |
| 73 | data: arguments.length<3 |
| 74 | ? data |
| 75 | : Array.prototype.slice.call(arguments,1) |
| 76 | }); |
| 77 | }; |
| 78 | |
| 79 | const stderr = function(){wMsg('stderr', Array.prototype.slice.call(arguments));}; |
| 80 | |
| 81 | self.onerror = function(/*message, source, lineno, colno, error*/) { |
| 82 | const err = arguments[4]; |
| 83 | if(err && 'ExitStatus'==err.name){ |
| 84 | /* This "cannot happen" for this wasm binding, but just in |
| 85 | case... */ |
| 86 | pikchrModule.isDead = true; |
| 87 | stderr("FATAL ERROR:", err.message); |
| 88 | stderr("Restarting the app requires reloading the page."); |
| 89 | wMsg('error', err); |
| 90 | } |
| 91 | pikchrModule.setStatus('Exception thrown, see JavaScript console: '+err); |
| 92 | }; |
| 93 | |
| 94 | self.onmessage = function f(ev){ |
| 95 | ev = ev.data; |
| 96 | switch(ev.type){ |
| 97 | /** |
| 98 | Runs the given text through pikchr and emits a 'pikchr' |
| 99 | message result (output format documented above). |
| 100 | |
| 101 | Fires a working/start event before it starts and |
| 102 | working/end event when it finishes. |
| 103 | */ |
| 104 | case 'pikchr': |
| 105 | if(pikchrModule.isDead){ |
| 106 | stderr( show-ready'); |
| 107 | }); |
| 108 | })(); |
+42
| --- a/extsrc/pikchr.js | ||
| +++ b/extsrc/pikchr.js | ||
| @@ -0,0 +1,42 @@ | ||
| 1 | +) { | |
| 2 | + r initPikchrModuDi | |
| 3 | +var initPikchrMod || {};e["ready"] = new Promise(fhis by | |
| 4 | +// setting the ENVIRONMENT// setting the ENVIRONMENT settingow) => { | |
| 5 | + throw toT(resolve, reject) =>e present at the end iffunction(resolve, reject) end if `scriptDirectory` is lice""; | |
| 6 | + | |
| 7 | +function locateFile(path) { | |
| 8 | + if (Module["locaeFile"]) { | |
| 9 | + retut they can | |
| 10 | +// refer to Module (if they choose; th// Sometimes an exivartory` is lice""; | |
| 11 | + | |
| 12 | +fnse = awaitirectory + path; | |
| 13 | +} | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | +/aitirectory + path; | |
| 18 | +} | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | +// Ho);nt runtime environments.} | |
| 23 | +var initPikchrModule = (() => { | |
| 24 | + vchrModule var initPikchrModule =, setWindowTitle; | |
| 25 | +ed in the code, and you | |
| 26 | +//d in the code, and yORKER) { | |
| 27 | +iseResvar readomiseResolve = resolveft()); | |
| 28 | + } | |
| 29 | + } | |
| 30 | + // = reject; | |
| 31 | +}); | |
| 32 | + | |
| 33 | +// Determine nvironment we are in} | |
| 34 | + if (_scriptDir) { | |
| 35 | +iseResvar readyPromi_scriptDir; | |
| 36 | + } | |
| 37 | +Throw) => { | |
| 38 | + throw tindexOf("blob:") !== 0) { | |
| 39 | +iseResvar readyPromiscriptDirectory.substr(0, ) => { | |
| 40 | + thrvar runtimeKeepavar buffer,aliveCounter = 0 || runtimeKeepaliveCounter > 0binaryFilevar initPikchrModuDir = typGlobalBufferAn ENVIRONME.src : undefined; | |
| 41 | + nresponse =>b() =>var function(str)function(arr)function(type) { | |
| 42 | + r |
| --- a/extsrc/pikchr.js | |
| +++ b/extsrc/pikchr.js | |
| @@ -0,0 +1,42 @@ | |
| --- a/extsrc/pikchr.js | |
| +++ b/extsrc/pikchr.js | |
| @@ -0,0 +1,42 @@ | |
| 1 | ) { |
| 2 | r initPikchrModuDi |
| 3 | var initPikchrMod || {};e["ready"] = new Promise(fhis by |
| 4 | // setting the ENVIRONMENT// setting the ENVIRONMENT settingow) => { |
| 5 | throw toT(resolve, reject) =>e present at the end iffunction(resolve, reject) end if `scriptDirectory` is lice""; |
| 6 | |
| 7 | function locateFile(path) { |
| 8 | if (Module["locaeFile"]) { |
| 9 | retut they can |
| 10 | // refer to Module (if they choose; th// Sometimes an exivartory` is lice""; |
| 11 | |
| 12 | fnse = awaitirectory + path; |
| 13 | } |
| 14 | |
| 15 | |
| 16 | |
| 17 | /aitirectory + path; |
| 18 | } |
| 19 | |
| 20 | |
| 21 | |
| 22 | // Ho);nt runtime environments.} |
| 23 | var initPikchrModule = (() => { |
| 24 | vchrModule var initPikchrModule =, setWindowTitle; |
| 25 | ed in the code, and you |
| 26 | //d in the code, and yORKER) { |
| 27 | iseResvar readomiseResolve = resolveft()); |
| 28 | } |
| 29 | } |
| 30 | // = reject; |
| 31 | }); |
| 32 | |
| 33 | // Determine nvironment we are in} |
| 34 | if (_scriptDir) { |
| 35 | iseResvar readyPromi_scriptDir; |
| 36 | } |
| 37 | Throw) => { |
| 38 | throw tindexOf("blob:") !== 0) { |
| 39 | iseResvar readyPromiscriptDirectory.substr(0, ) => { |
| 40 | thrvar runtimeKeepavar buffer,aliveCounter = 0 || runtimeKeepaliveCounter > 0binaryFilevar initPikchrModuDir = typGlobalBufferAn ENVIRONME.src : undefined; |
| 41 | nresponse =>b() =>var function(str)function(arr)function(type) { |
| 42 | r |
Binary file
+1
-2
| --- skins/darkmode/css.txt | ||
| +++ skins/darkmode/css.txt | ||
| @@ -131,13 +131,12 @@ | ||
| 131 | 131 | .button:focus, |
| 132 | 132 | button:focus, |
| 133 | 133 | input[type=button]:focus, |
| 134 | 134 | input[type=reset]:focus, |
| 135 | 135 | input[type=submit]:focus { |
| 136 | - color: #333; | |
| 136 | + outline: 2px outset #333; | |
| 137 | 137 | border-color: #888; |
| 138 | - outline: 0 | |
| 139 | 138 | } |
| 140 | 139 | |
| 141 | 140 | /* All page content from the bottom of the menu or submenu down to |
| 142 | 141 | ** the footer */ |
| 143 | 142 | div.content { |
| 144 | 143 |
| --- skins/darkmode/css.txt | |
| +++ skins/darkmode/css.txt | |
| @@ -131,13 +131,12 @@ | |
| 131 | .button:focus, |
| 132 | button:focus, |
| 133 | input[type=button]:focus, |
| 134 | input[type=reset]:focus, |
| 135 | input[type=submit]:focus { |
| 136 | color: #333; |
| 137 | border-color: #888; |
| 138 | outline: 0 |
| 139 | } |
| 140 | |
| 141 | /* All page content from the bottom of the menu or submenu down to |
| 142 | ** the footer */ |
| 143 | div.content { |
| 144 |
| --- skins/darkmode/css.txt | |
| +++ skins/darkmode/css.txt | |
| @@ -131,13 +131,12 @@ | |
| 131 | .button:focus, |
| 132 | button:focus, |
| 133 | input[type=button]:focus, |
| 134 | input[type=reset]:focus, |
| 135 | input[type=submit]:focus { |
| 136 | outline: 2px outset #333; |
| 137 | border-color: #888; |
| 138 | } |
| 139 | |
| 140 | /* All page content from the bottom of the menu or submenu down to |
| 141 | ** the footer */ |
| 142 | div.content { |
| 143 |
+4
-5
| --- src/builtin.c | ||
| +++ src/builtin.c | ||
| @@ -130,20 +130,19 @@ | ||
| 130 | 130 | blob_reset(&x); |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | /* |
| 134 | 134 | ** Input zList is a list of numeric identifiers for files in |
| 135 | -** aBuiltinFiles[]. Return the concatenation of all of those | |
| 136 | -** files using mimetype zType, or as application/javascript if | |
| 137 | -** zType is 0. | |
| 135 | +** aBuiltinFiles[]. Return the concatenation of all of those files | |
| 136 | +** using mimetype zType, or as text/javascript if zType is 0. | |
| 138 | 137 | */ |
| 139 | 138 | static void builtin_deliver_multiple_js_files( |
| 140 | 139 | const char *zList, /* List of numeric identifiers */ |
| 141 | 140 | const char *zType /* Override mimetype */ |
| 142 | 141 | ){ |
| 143 | 142 | Blob *pOut; |
| 144 | - if( zType==0 ) zType = "application/javascript"; | |
| 143 | + if( zType==0 ) zType = "text/javascript"; | |
| 145 | 144 | cgi_set_content_type(zType); |
| 146 | 145 | pOut = cgi_output_blob(); |
| 147 | 146 | while( zList[0] ){ |
| 148 | 147 | int i = atoi(zList); |
| 149 | 148 | if( i>0 && i<=count(aBuiltinFiles) ){ |
| @@ -203,11 +202,11 @@ | ||
| 203 | 202 | @ File "%h(zName)" not found |
| 204 | 203 | return; |
| 205 | 204 | } |
| 206 | 205 | if( zType==0 ){ |
| 207 | 206 | if( sqlite3_strglob("*.js", zName)==0 ){ |
| 208 | - zType = "application/javascript"; | |
| 207 | + zType = "text/javascript"; | |
| 209 | 208 | }else{ |
| 210 | 209 | zType = mimetype_from_name(zName); |
| 211 | 210 | } |
| 212 | 211 | } |
| 213 | 212 | cgi_set_content_type(zType); |
| 214 | 213 |
| --- src/builtin.c | |
| +++ src/builtin.c | |
| @@ -130,20 +130,19 @@ | |
| 130 | blob_reset(&x); |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | ** Input zList is a list of numeric identifiers for files in |
| 135 | ** aBuiltinFiles[]. Return the concatenation of all of those |
| 136 | ** files using mimetype zType, or as application/javascript if |
| 137 | ** zType is 0. |
| 138 | */ |
| 139 | static void builtin_deliver_multiple_js_files( |
| 140 | const char *zList, /* List of numeric identifiers */ |
| 141 | const char *zType /* Override mimetype */ |
| 142 | ){ |
| 143 | Blob *pOut; |
| 144 | if( zType==0 ) zType = "application/javascript"; |
| 145 | cgi_set_content_type(zType); |
| 146 | pOut = cgi_output_blob(); |
| 147 | while( zList[0] ){ |
| 148 | int i = atoi(zList); |
| 149 | if( i>0 && i<=count(aBuiltinFiles) ){ |
| @@ -203,11 +202,11 @@ | |
| 203 | @ File "%h(zName)" not found |
| 204 | return; |
| 205 | } |
| 206 | if( zType==0 ){ |
| 207 | if( sqlite3_strglob("*.js", zName)==0 ){ |
| 208 | zType = "application/javascript"; |
| 209 | }else{ |
| 210 | zType = mimetype_from_name(zName); |
| 211 | } |
| 212 | } |
| 213 | cgi_set_content_type(zType); |
| 214 |
| --- src/builtin.c | |
| +++ src/builtin.c | |
| @@ -130,20 +130,19 @@ | |
| 130 | blob_reset(&x); |
| 131 | } |
| 132 | |
| 133 | /* |
| 134 | ** Input zList is a list of numeric identifiers for files in |
| 135 | ** aBuiltinFiles[]. Return the concatenation of all of those files |
| 136 | ** using mimetype zType, or as text/javascript if zType is 0. |
| 137 | */ |
| 138 | static void builtin_deliver_multiple_js_files( |
| 139 | const char *zList, /* List of numeric identifiers */ |
| 140 | const char *zType /* Override mimetype */ |
| 141 | ){ |
| 142 | Blob *pOut; |
| 143 | if( zType==0 ) zType = "text/javascript"; |
| 144 | cgi_set_content_type(zType); |
| 145 | pOut = cgi_output_blob(); |
| 146 | while( zList[0] ){ |
| 147 | int i = atoi(zList); |
| 148 | if( i>0 && i<=count(aBuiltinFiles) ){ |
| @@ -203,11 +202,11 @@ | |
| 202 | @ File "%h(zName)" not found |
| 203 | return; |
| 204 | } |
| 205 | if( zType==0 ){ |
| 206 | if( sqlite3_strglob("*.js", zName)==0 ){ |
| 207 | zType = "text/javascript"; |
| 208 | }else{ |
| 209 | zType = mimetype_from_name(zName); |
| 210 | } |
| 211 | } |
| 212 | cgi_set_content_type(zType); |
| 213 |
+57
-11
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -307,11 +307,11 @@ | ||
| 307 | 307 | if(!g.isHTTP) return /* e.g. JSON CLI mode, where g.zTop is not set */; |
| 308 | 308 | else if( zPath==0 ){ |
| 309 | 309 | zPath = g.zTop; |
| 310 | 310 | if( zPath[0]==0 ) zPath = "/"; |
| 311 | 311 | } |
| 312 | - if( g.zBaseURL!=0 && strncmp(g.zBaseURL, "https:", 6)==0 ){ | |
| 312 | + if( g.zBaseURL!=0 && fossil_strncmp(g.zBaseURL, "https:", 6)==0 ){ | |
| 313 | 313 | zSecure = " secure;"; |
| 314 | 314 | } |
| 315 | 315 | if( lifetime!=0 ){ |
| 316 | 316 | blob_appendf(&extraHeader, |
| 317 | 317 | "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; " |
| @@ -330,13 +330,37 @@ | ||
| 330 | 330 | ** Return true if the response should be sent with Content-Encoding: gzip. |
| 331 | 331 | */ |
| 332 | 332 | static int is_gzippable(void){ |
| 333 | 333 | if( g.fNoHttpCompress ) return 0; |
| 334 | 334 | if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0; |
| 335 | - return strncmp(zContentType, "text/", 5)==0 | |
| 336 | - || sqlite3_strglob("application/*xml", zContentType)==0 | |
| 337 | - || sqlite3_strglob("application/*javascript", zContentType)==0; | |
| 335 | + /* Maintenance note: this oddball structure is intended to make | |
| 336 | + ** adding new mimetypes to this list less of a performance hit than | |
| 337 | + ** doing a strcmp/glob over a growing set of compressible types. */ | |
| 338 | + switch(zContentType ? *zContentType : 0){ | |
| 339 | + case (int)'a': | |
| 340 | + if(0==fossil_strncmp("application/",zContentType,12)){ | |
| 341 | + const char * z = &zContentType[12]; | |
| 342 | + switch(*z){ | |
| 343 | + case (int)'j': | |
| 344 | + return fossil_strcmp("javascript", z)==0 | |
| 345 | + || fossil_strcmp("json", z)==0; | |
| 346 | + case (int)'w': return fossil_strcmp("wasm", z)==0; | |
| 347 | + case (int)'x': | |
| 348 | + return fossil_strcmp("x-tcl", z)==0 | |
| 349 | + || fossil_strcmp("x-tar", z)==0; | |
| 350 | + default: | |
| 351 | + return sqlite3_strglob("*xml", z)==0; | |
| 352 | + } | |
| 353 | + } | |
| 354 | + break; | |
| 355 | + case (int)'i': | |
| 356 | + return fossil_strcmp(zContentType, "image/svg+xml")==0 | |
| 357 | + || fossil_strcmp(zContentType, "image/vnd.microsoft.icon")==0; | |
| 358 | + case (int)'t': | |
| 359 | + return fossil_strncmp(zContentType, "text/", 5)==0; | |
| 360 | + } | |
| 361 | + return 0; | |
| 338 | 362 | } |
| 339 | 363 | |
| 340 | 364 | |
| 341 | 365 | /* |
| 342 | 366 | ** The following routines read or write content from/to the wire for |
| @@ -419,10 +443,29 @@ | ||
| 419 | 443 | if( !g.httpUseSSL ){ |
| 420 | 444 | fflush(g.httpOut); |
| 421 | 445 | } |
| 422 | 446 | } |
| 423 | 447 | |
| 448 | +/* | |
| 449 | +** Given a Content-Type value, returns a string suitable for appending | |
| 450 | +** to the Content-Type header for adding (or not) the "; charset=..." | |
| 451 | +** part. It returns an empty string for most types or if zContentType | |
| 452 | +** is NULL. | |
| 453 | +** | |
| 454 | +** See forum post f60dece061c364d1 for the discussions which lead to | |
| 455 | +** this. Previously we always appended the charset, but WASM loaders | |
| 456 | +** are pedantic and refuse to load any responses which have a | |
| 457 | +** charset. Also, adding a charset is not strictly appropriate for | |
| 458 | +** most types (and not required for many others which may ostensibly | |
| 459 | +** benefit from one, as detailed in that forum post). | |
| 460 | +*/ | |
| 461 | +static const char * content_type_charset(const char *zContentType){ | |
| 462 | + if(0==fossil_strncmp(zContentType,"text/",5)){ | |
| 463 | + return "; charset=utf-8"; | |
| 464 | + } | |
| 465 | + return ""; | |
| 466 | +} | |
| 424 | 467 | |
| 425 | 468 | /* |
| 426 | 469 | ** Generate the reply to a web request. The output might be an |
| 427 | 470 | ** full HTTP response, or a CGI response, depending on how things have |
| 428 | 471 | ** be set up. |
| @@ -493,11 +536,12 @@ | ||
| 493 | 536 | |
| 494 | 537 | /* Content intended for logged in users should only be cached in |
| 495 | 538 | ** the browser, not some shared location. |
| 496 | 539 | */ |
| 497 | 540 | if( iReplyStatus!=304 ) { |
| 498 | - blob_appendf(&hdr, "Content-Type: %s; charset=utf-8\r\n", zContentType); | |
| 541 | + blob_appendf(&hdr, "Content-Type: %s%s\r\n", zContentType, | |
| 542 | + content_type_charset(zContentType)); | |
| 499 | 543 | if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){ |
| 500 | 544 | cgi_combine_header_and_body(); |
| 501 | 545 | blob_compress(&cgiContent[0], &cgiContent[0]); |
| 502 | 546 | } |
| 503 | 547 | |
| @@ -569,11 +613,12 @@ | ||
| 569 | 613 | int iStat, |
| 570 | 614 | const char *zStat |
| 571 | 615 | ){ |
| 572 | 616 | char *zLocation; |
| 573 | 617 | CGIDEBUG(("redirect to %s\n", zURL)); |
| 574 | - if( strncmp(zURL,"http:",5)==0 || strncmp(zURL,"https:",6)==0 ){ | |
| 618 | + if( fossil_strncmp(zURL,"http:",5)==0 | |
| 619 | + || fossil_strncmp(zURL,"https:",6)==0 ){ | |
| 575 | 620 | zLocation = mprintf("Location: %s\r\n", zURL); |
| 576 | 621 | }else if( *zURL=='/' ){ |
| 577 | 622 | int n1 = (int)strlen(g.zBaseURL); |
| 578 | 623 | int n2 = (int)strlen(g.zTop); |
| 579 | 624 | if( g.zBaseURL[n1-1]=='/' ) zURL++; |
| @@ -653,11 +698,11 @@ | ||
| 653 | 698 | const char *zMethod = P("REQUEST_METHOD"); |
| 654 | 699 | if( zMethod==0 ) return 0; |
| 655 | 700 | if( strcmp(zMethod,"POST")!=0 ) return 0; |
| 656 | 701 | } |
| 657 | 702 | nBase = (int)strlen(g.zBaseURL); |
| 658 | - if( strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0; | |
| 703 | + if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0; | |
| 659 | 704 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 660 | 705 | return 1; |
| 661 | 706 | } |
| 662 | 707 | |
| 663 | 708 | /* |
| @@ -920,11 +965,12 @@ | ||
| 920 | 965 | int len = *pLen; |
| 921 | 966 | int i; |
| 922 | 967 | int nBoundary = strlen(zBoundary); |
| 923 | 968 | *pnContent = len; |
| 924 | 969 | for(i=0; i<len; i++){ |
| 925 | - if( z[i]=='\n' && strncmp(zBoundary, &z[i+1], nBoundary)==0 ){ | |
| 970 | + if( z[i]=='\n' && fossil_strncmp(zBoundary, &z[i+1], | |
| 971 | + nBoundary)==0 ){ | |
| 926 | 972 | if( i>0 && z[i-1]=='\r' ) i--; |
| 927 | 973 | z[i] = 0; |
| 928 | 974 | *pnContent = i; |
| 929 | 975 | i += nBoundary; |
| 930 | 976 | break; |
| @@ -1348,11 +1394,11 @@ | ||
| 1348 | 1394 | */ |
| 1349 | 1395 | void cgi_decode_post_parameters(void){ |
| 1350 | 1396 | int len = blob_size(&g.cgiIn); |
| 1351 | 1397 | if( len==0 ) return; |
| 1352 | 1398 | if( fossil_strcmp(g.zContentType,"application/x-www-form-urlencoded")==0 |
| 1353 | - || strncmp(g.zContentType,"multipart/form-data",19)==0 | |
| 1399 | + || fossil_strncmp(g.zContentType,"multipart/form-data",19)==0 | |
| 1354 | 1400 | ){ |
| 1355 | 1401 | char *z = blob_str(&g.cgiIn); |
| 1356 | 1402 | cgi_trace(z); |
| 1357 | 1403 | if( g.zContentType[0]=='a' ){ |
| 1358 | 1404 | add_param_list(z, '&'); |
| @@ -2326,11 +2372,11 @@ | ||
| 2326 | 2372 | if( zBrowser ){ |
| 2327 | 2373 | assert( strstr(zBrowser,"%d")!=0 ); |
| 2328 | 2374 | zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort); |
| 2329 | 2375 | #if defined(__CYGWIN__) |
| 2330 | 2376 | /* On Cygwin, we can do better than "echo" */ |
| 2331 | - if( strncmp(zBrowser, "echo ", 5)==0 ){ | |
| 2377 | + if( fossil_strncmp(zBrowser, "echo ", 5)==0 ){ | |
| 2332 | 2378 | wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5); |
| 2333 | 2379 | wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */ |
| 2334 | 2380 | if( (size_t)ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){ |
| 2335 | 2381 | fossil_warning("cannot start browser\n"); |
| 2336 | 2382 | } |
| @@ -2486,11 +2532,11 @@ | ||
| 2486 | 2532 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; |
| 2487 | 2533 | if( 7==sscanf(zDate, "%3[A-Za-z], %d %3[A-Za-z] %d %d:%d:%d", zIgnore, |
| 2488 | 2534 | &mday, zMonth, &year, &hour, &min, &sec)){ |
| 2489 | 2535 | if( year > 1900 ) year -= 1900; |
| 2490 | 2536 | for(mon=0; azMonths[mon]; mon++){ |
| 2491 | - if( !strncmp( azMonths[mon], zMonth, 3 )){ | |
| 2537 | + if( !fossil_strncmp( azMonths[mon], zMonth, 3 )){ | |
| 2492 | 2538 | int nDay; |
| 2493 | 2539 | int isLeapYr; |
| 2494 | 2540 | static int priorDays[] = |
| 2495 | 2541 | { 0, 31, 59, 90,120,151,181,212,243,273,304,334 }; |
| 2496 | 2542 | if( mon<0 ){ |
| 2497 | 2543 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -307,11 +307,11 @@ | |
| 307 | if(!g.isHTTP) return /* e.g. JSON CLI mode, where g.zTop is not set */; |
| 308 | else if( zPath==0 ){ |
| 309 | zPath = g.zTop; |
| 310 | if( zPath[0]==0 ) zPath = "/"; |
| 311 | } |
| 312 | if( g.zBaseURL!=0 && strncmp(g.zBaseURL, "https:", 6)==0 ){ |
| 313 | zSecure = " secure;"; |
| 314 | } |
| 315 | if( lifetime!=0 ){ |
| 316 | blob_appendf(&extraHeader, |
| 317 | "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; " |
| @@ -330,13 +330,37 @@ | |
| 330 | ** Return true if the response should be sent with Content-Encoding: gzip. |
| 331 | */ |
| 332 | static int is_gzippable(void){ |
| 333 | if( g.fNoHttpCompress ) return 0; |
| 334 | if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0; |
| 335 | return strncmp(zContentType, "text/", 5)==0 |
| 336 | || sqlite3_strglob("application/*xml", zContentType)==0 |
| 337 | || sqlite3_strglob("application/*javascript", zContentType)==0; |
| 338 | } |
| 339 | |
| 340 | |
| 341 | /* |
| 342 | ** The following routines read or write content from/to the wire for |
| @@ -419,10 +443,29 @@ | |
| 419 | if( !g.httpUseSSL ){ |
| 420 | fflush(g.httpOut); |
| 421 | } |
| 422 | } |
| 423 | |
| 424 | |
| 425 | /* |
| 426 | ** Generate the reply to a web request. The output might be an |
| 427 | ** full HTTP response, or a CGI response, depending on how things have |
| 428 | ** be set up. |
| @@ -493,11 +536,12 @@ | |
| 493 | |
| 494 | /* Content intended for logged in users should only be cached in |
| 495 | ** the browser, not some shared location. |
| 496 | */ |
| 497 | if( iReplyStatus!=304 ) { |
| 498 | blob_appendf(&hdr, "Content-Type: %s; charset=utf-8\r\n", zContentType); |
| 499 | if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){ |
| 500 | cgi_combine_header_and_body(); |
| 501 | blob_compress(&cgiContent[0], &cgiContent[0]); |
| 502 | } |
| 503 | |
| @@ -569,11 +613,12 @@ | |
| 569 | int iStat, |
| 570 | const char *zStat |
| 571 | ){ |
| 572 | char *zLocation; |
| 573 | CGIDEBUG(("redirect to %s\n", zURL)); |
| 574 | if( strncmp(zURL,"http:",5)==0 || strncmp(zURL,"https:",6)==0 ){ |
| 575 | zLocation = mprintf("Location: %s\r\n", zURL); |
| 576 | }else if( *zURL=='/' ){ |
| 577 | int n1 = (int)strlen(g.zBaseURL); |
| 578 | int n2 = (int)strlen(g.zTop); |
| 579 | if( g.zBaseURL[n1-1]=='/' ) zURL++; |
| @@ -653,11 +698,11 @@ | |
| 653 | const char *zMethod = P("REQUEST_METHOD"); |
| 654 | if( zMethod==0 ) return 0; |
| 655 | if( strcmp(zMethod,"POST")!=0 ) return 0; |
| 656 | } |
| 657 | nBase = (int)strlen(g.zBaseURL); |
| 658 | if( strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0; |
| 659 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 660 | return 1; |
| 661 | } |
| 662 | |
| 663 | /* |
| @@ -920,11 +965,12 @@ | |
| 920 | int len = *pLen; |
| 921 | int i; |
| 922 | int nBoundary = strlen(zBoundary); |
| 923 | *pnContent = len; |
| 924 | for(i=0; i<len; i++){ |
| 925 | if( z[i]=='\n' && strncmp(zBoundary, &z[i+1], nBoundary)==0 ){ |
| 926 | if( i>0 && z[i-1]=='\r' ) i--; |
| 927 | z[i] = 0; |
| 928 | *pnContent = i; |
| 929 | i += nBoundary; |
| 930 | break; |
| @@ -1348,11 +1394,11 @@ | |
| 1348 | */ |
| 1349 | void cgi_decode_post_parameters(void){ |
| 1350 | int len = blob_size(&g.cgiIn); |
| 1351 | if( len==0 ) return; |
| 1352 | if( fossil_strcmp(g.zContentType,"application/x-www-form-urlencoded")==0 |
| 1353 | || strncmp(g.zContentType,"multipart/form-data",19)==0 |
| 1354 | ){ |
| 1355 | char *z = blob_str(&g.cgiIn); |
| 1356 | cgi_trace(z); |
| 1357 | if( g.zContentType[0]=='a' ){ |
| 1358 | add_param_list(z, '&'); |
| @@ -2326,11 +2372,11 @@ | |
| 2326 | if( zBrowser ){ |
| 2327 | assert( strstr(zBrowser,"%d")!=0 ); |
| 2328 | zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort); |
| 2329 | #if defined(__CYGWIN__) |
| 2330 | /* On Cygwin, we can do better than "echo" */ |
| 2331 | if( strncmp(zBrowser, "echo ", 5)==0 ){ |
| 2332 | wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5); |
| 2333 | wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */ |
| 2334 | if( (size_t)ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){ |
| 2335 | fossil_warning("cannot start browser\n"); |
| 2336 | } |
| @@ -2486,11 +2532,11 @@ | |
| 2486 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; |
| 2487 | if( 7==sscanf(zDate, "%3[A-Za-z], %d %3[A-Za-z] %d %d:%d:%d", zIgnore, |
| 2488 | &mday, zMonth, &year, &hour, &min, &sec)){ |
| 2489 | if( year > 1900 ) year -= 1900; |
| 2490 | for(mon=0; azMonths[mon]; mon++){ |
| 2491 | if( !strncmp( azMonths[mon], zMonth, 3 )){ |
| 2492 | int nDay; |
| 2493 | int isLeapYr; |
| 2494 | static int priorDays[] = |
| 2495 | { 0, 31, 59, 90,120,151,181,212,243,273,304,334 }; |
| 2496 | if( mon<0 ){ |
| 2497 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -307,11 +307,11 @@ | |
| 307 | if(!g.isHTTP) return /* e.g. JSON CLI mode, where g.zTop is not set */; |
| 308 | else if( zPath==0 ){ |
| 309 | zPath = g.zTop; |
| 310 | if( zPath[0]==0 ) zPath = "/"; |
| 311 | } |
| 312 | if( g.zBaseURL!=0 && fossil_strncmp(g.zBaseURL, "https:", 6)==0 ){ |
| 313 | zSecure = " secure;"; |
| 314 | } |
| 315 | if( lifetime!=0 ){ |
| 316 | blob_appendf(&extraHeader, |
| 317 | "Set-Cookie: %s=%t; Path=%s; max-age=%d; HttpOnly; " |
| @@ -330,13 +330,37 @@ | |
| 330 | ** Return true if the response should be sent with Content-Encoding: gzip. |
| 331 | */ |
| 332 | static int is_gzippable(void){ |
| 333 | if( g.fNoHttpCompress ) return 0; |
| 334 | if( strstr(PD("HTTP_ACCEPT_ENCODING", ""), "gzip")==0 ) return 0; |
| 335 | /* Maintenance note: this oddball structure is intended to make |
| 336 | ** adding new mimetypes to this list less of a performance hit than |
| 337 | ** doing a strcmp/glob over a growing set of compressible types. */ |
| 338 | switch(zContentType ? *zContentType : 0){ |
| 339 | case (int)'a': |
| 340 | if(0==fossil_strncmp("application/",zContentType,12)){ |
| 341 | const char * z = &zContentType[12]; |
| 342 | switch(*z){ |
| 343 | case (int)'j': |
| 344 | return fossil_strcmp("javascript", z)==0 |
| 345 | || fossil_strcmp("json", z)==0; |
| 346 | case (int)'w': return fossil_strcmp("wasm", z)==0; |
| 347 | case (int)'x': |
| 348 | return fossil_strcmp("x-tcl", z)==0 |
| 349 | || fossil_strcmp("x-tar", z)==0; |
| 350 | default: |
| 351 | return sqlite3_strglob("*xml", z)==0; |
| 352 | } |
| 353 | } |
| 354 | break; |
| 355 | case (int)'i': |
| 356 | return fossil_strcmp(zContentType, "image/svg+xml")==0 |
| 357 | || fossil_strcmp(zContentType, "image/vnd.microsoft.icon")==0; |
| 358 | case (int)'t': |
| 359 | return fossil_strncmp(zContentType, "text/", 5)==0; |
| 360 | } |
| 361 | return 0; |
| 362 | } |
| 363 | |
| 364 | |
| 365 | /* |
| 366 | ** The following routines read or write content from/to the wire for |
| @@ -419,10 +443,29 @@ | |
| 443 | if( !g.httpUseSSL ){ |
| 444 | fflush(g.httpOut); |
| 445 | } |
| 446 | } |
| 447 | |
| 448 | /* |
| 449 | ** Given a Content-Type value, returns a string suitable for appending |
| 450 | ** to the Content-Type header for adding (or not) the "; charset=..." |
| 451 | ** part. It returns an empty string for most types or if zContentType |
| 452 | ** is NULL. |
| 453 | ** |
| 454 | ** See forum post f60dece061c364d1 for the discussions which lead to |
| 455 | ** this. Previously we always appended the charset, but WASM loaders |
| 456 | ** are pedantic and refuse to load any responses which have a |
| 457 | ** charset. Also, adding a charset is not strictly appropriate for |
| 458 | ** most types (and not required for many others which may ostensibly |
| 459 | ** benefit from one, as detailed in that forum post). |
| 460 | */ |
| 461 | static const char * content_type_charset(const char *zContentType){ |
| 462 | if(0==fossil_strncmp(zContentType,"text/",5)){ |
| 463 | return "; charset=utf-8"; |
| 464 | } |
| 465 | return ""; |
| 466 | } |
| 467 | |
| 468 | /* |
| 469 | ** Generate the reply to a web request. The output might be an |
| 470 | ** full HTTP response, or a CGI response, depending on how things have |
| 471 | ** be set up. |
| @@ -493,11 +536,12 @@ | |
| 536 | |
| 537 | /* Content intended for logged in users should only be cached in |
| 538 | ** the browser, not some shared location. |
| 539 | */ |
| 540 | if( iReplyStatus!=304 ) { |
| 541 | blob_appendf(&hdr, "Content-Type: %s%s\r\n", zContentType, |
| 542 | content_type_charset(zContentType)); |
| 543 | if( fossil_strcmp(zContentType,"application/x-fossil")==0 ){ |
| 544 | cgi_combine_header_and_body(); |
| 545 | blob_compress(&cgiContent[0], &cgiContent[0]); |
| 546 | } |
| 547 | |
| @@ -569,11 +613,12 @@ | |
| 613 | int iStat, |
| 614 | const char *zStat |
| 615 | ){ |
| 616 | char *zLocation; |
| 617 | CGIDEBUG(("redirect to %s\n", zURL)); |
| 618 | if( fossil_strncmp(zURL,"http:",5)==0 |
| 619 | || fossil_strncmp(zURL,"https:",6)==0 ){ |
| 620 | zLocation = mprintf("Location: %s\r\n", zURL); |
| 621 | }else if( *zURL=='/' ){ |
| 622 | int n1 = (int)strlen(g.zBaseURL); |
| 623 | int n2 = (int)strlen(g.zTop); |
| 624 | if( g.zBaseURL[n1-1]=='/' ) zURL++; |
| @@ -653,11 +698,11 @@ | |
| 698 | const char *zMethod = P("REQUEST_METHOD"); |
| 699 | if( zMethod==0 ) return 0; |
| 700 | if( strcmp(zMethod,"POST")!=0 ) return 0; |
| 701 | } |
| 702 | nBase = (int)strlen(g.zBaseURL); |
| 703 | if( fossil_strncmp(g.zBaseURL,zRef,nBase)!=0 ) return 0; |
| 704 | if( zRef[nBase]!=0 && zRef[nBase]!='/' ) return 0; |
| 705 | return 1; |
| 706 | } |
| 707 | |
| 708 | /* |
| @@ -920,11 +965,12 @@ | |
| 965 | int len = *pLen; |
| 966 | int i; |
| 967 | int nBoundary = strlen(zBoundary); |
| 968 | *pnContent = len; |
| 969 | for(i=0; i<len; i++){ |
| 970 | if( z[i]=='\n' && fossil_strncmp(zBoundary, &z[i+1], |
| 971 | nBoundary)==0 ){ |
| 972 | if( i>0 && z[i-1]=='\r' ) i--; |
| 973 | z[i] = 0; |
| 974 | *pnContent = i; |
| 975 | i += nBoundary; |
| 976 | break; |
| @@ -1348,11 +1394,11 @@ | |
| 1394 | */ |
| 1395 | void cgi_decode_post_parameters(void){ |
| 1396 | int len = blob_size(&g.cgiIn); |
| 1397 | if( len==0 ) return; |
| 1398 | if( fossil_strcmp(g.zContentType,"application/x-www-form-urlencoded")==0 |
| 1399 | || fossil_strncmp(g.zContentType,"multipart/form-data",19)==0 |
| 1400 | ){ |
| 1401 | char *z = blob_str(&g.cgiIn); |
| 1402 | cgi_trace(z); |
| 1403 | if( g.zContentType[0]=='a' ){ |
| 1404 | add_param_list(z, '&'); |
| @@ -2326,11 +2372,11 @@ | |
| 2372 | if( zBrowser ){ |
| 2373 | assert( strstr(zBrowser,"%d")!=0 ); |
| 2374 | zBrowser = mprintf(zBrowser /*works-like:"%d"*/, iPort); |
| 2375 | #if defined(__CYGWIN__) |
| 2376 | /* On Cygwin, we can do better than "echo" */ |
| 2377 | if( fossil_strncmp(zBrowser, "echo ", 5)==0 ){ |
| 2378 | wchar_t *wUrl = fossil_utf8_to_unicode(zBrowser+5); |
| 2379 | wUrl[wcslen(wUrl)-2] = 0; /* Strip terminating " &" */ |
| 2380 | if( (size_t)ShellExecuteW(0, L"open", wUrl, 0, 0, 1)<33 ){ |
| 2381 | fossil_warning("cannot start browser\n"); |
| 2382 | } |
| @@ -2486,11 +2532,11 @@ | |
| 2532 | "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", 0}; |
| 2533 | if( 7==sscanf(zDate, "%3[A-Za-z], %d %3[A-Za-z] %d %d:%d:%d", zIgnore, |
| 2534 | &mday, zMonth, &year, &hour, &min, &sec)){ |
| 2535 | if( year > 1900 ) year -= 1900; |
| 2536 | for(mon=0; azMonths[mon]; mon++){ |
| 2537 | if( !fossil_strncmp( azMonths[mon], zMonth, 3 )){ |
| 2538 | int nDay; |
| 2539 | int isLeapYr; |
| 2540 | static int priorDays[] = |
| 2541 | { 0, 31, 59, 90,120,151,181,212,243,273,304,334 }; |
| 2542 | if( mon<0 ){ |
| 2543 |
+14
-6
| --- src/default.css | ||
| +++ src/default.css | ||
| @@ -1007,10 +1007,13 @@ | ||
| 1007 | 1007 | background-color: #ffb; |
| 1008 | 1008 | } |
| 1009 | 1009 | label { |
| 1010 | 1010 | white-space: nowrap; |
| 1011 | 1011 | } |
| 1012 | +label[for] { | |
| 1013 | + cursor: pointer; | |
| 1014 | +} | |
| 1012 | 1015 | .copy-button { |
| 1013 | 1016 | display: inline-block; |
| 1014 | 1017 | width: 14px; |
| 1015 | 1018 | height: 14px; |
| 1016 | 1019 | /*Note: .24em is slightly smaller than the average width of a normal space.*/ |
| @@ -1075,16 +1078,21 @@ | ||
| 1075 | 1078 | } |
| 1076 | 1079 | .warning { |
| 1077 | 1080 | color: black; |
| 1078 | 1081 | background: yellow; |
| 1079 | 1082 | } |
| 1080 | -.hidden { | |
| 1081 | - /* The framework-wide way of hiding elements is to assign them this | |
| 1082 | - CSS class. To make them visible again, remove it. The !important | |
| 1083 | - qualifiers are unfortunate but sometimes necessary when hidden | |
| 1084 | - element has other classes which specify visibility-related | |
| 1085 | - options. */ | |
| 1083 | +.hidden, .initially-hidden { | |
| 1084 | + /* The framework-wide way of hiding elements is to assign them th | |
| 1085 | + .hidden class. To make them visible again, remove it. The | |
| 1086 | + !important qualifiers are unfortunate but sometimes necessary | |
| 1087 | + when hidden element has other classes which specify | |
| 1088 | + visibility-related options. The .initially-hidden class is for | |
| 1089 | + pages which need to show, e.g., a progress widget while a large | |
| 1090 | + WASM blob loads. Elements aside from that load-time widget can be | |
| 1091 | + made .initially-hidden and then have that class removed once the | |
| 1092 | + long-running startup process is done. See /pikchrshow for an | |
| 1093 | + example. */ | |
| 1086 | 1094 | position: absolute !important; |
| 1087 | 1095 | opacity: 0 !important; |
| 1088 | 1096 | pointer-events: none !important; |
| 1089 | 1097 | display: none !important; |
| 1090 | 1098 | } |
| 1091 | 1099 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -1007,10 +1007,13 @@ | |
| 1007 | background-color: #ffb; |
| 1008 | } |
| 1009 | label { |
| 1010 | white-space: nowrap; |
| 1011 | } |
| 1012 | .copy-button { |
| 1013 | display: inline-block; |
| 1014 | width: 14px; |
| 1015 | height: 14px; |
| 1016 | /*Note: .24em is slightly smaller than the average width of a normal space.*/ |
| @@ -1075,16 +1078,21 @@ | |
| 1075 | } |
| 1076 | .warning { |
| 1077 | color: black; |
| 1078 | background: yellow; |
| 1079 | } |
| 1080 | .hidden { |
| 1081 | /* The framework-wide way of hiding elements is to assign them this |
| 1082 | CSS class. To make them visible again, remove it. The !important |
| 1083 | qualifiers are unfortunate but sometimes necessary when hidden |
| 1084 | element has other classes which specify visibility-related |
| 1085 | options. */ |
| 1086 | position: absolute !important; |
| 1087 | opacity: 0 !important; |
| 1088 | pointer-events: none !important; |
| 1089 | display: none !important; |
| 1090 | } |
| 1091 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -1007,10 +1007,13 @@ | |
| 1007 | background-color: #ffb; |
| 1008 | } |
| 1009 | label { |
| 1010 | white-space: nowrap; |
| 1011 | } |
| 1012 | label[for] { |
| 1013 | cursor: pointer; |
| 1014 | } |
| 1015 | .copy-button { |
| 1016 | display: inline-block; |
| 1017 | width: 14px; |
| 1018 | height: 14px; |
| 1019 | /*Note: .24em is slightly smaller than the average width of a normal space.*/ |
| @@ -1075,16 +1078,21 @@ | |
| 1078 | } |
| 1079 | .warning { |
| 1080 | color: black; |
| 1081 | background: yellow; |
| 1082 | } |
| 1083 | .hidden, .initially-hidden { |
| 1084 | /* The framework-wide way of hiding elements is to assign them th |
| 1085 | .hidden class. To make them visible again, remove it. The |
| 1086 | !important qualifiers are unfortunate but sometimes necessary |
| 1087 | when hidden element has other classes which specify |
| 1088 | visibility-related options. The .initially-hidden class is for |
| 1089 | pages which need to show, e.g., a progress widget while a large |
| 1090 | WASM blob loads. Elements aside from that load-time widget can be |
| 1091 | made .initially-hidden and then have that class removed once the |
| 1092 | long-running startup process is done. See /pikchrshow for an |
| 1093 | example. */ |
| 1094 | position: absolute !important; |
| 1095 | opacity: 0 !important; |
| 1096 | pointer-events: none !important; |
| 1097 | display: none !important; |
| 1098 | } |
| 1099 |
+7
-1
| --- src/doc.c | ||
| +++ src/doc.c | ||
| @@ -156,11 +156,16 @@ | ||
| 156 | 156 | { "jad", 3, "text/vnd.sun.j2me.app-descriptor" }, |
| 157 | 157 | { "jar", 3, "application/java-archive" }, |
| 158 | 158 | { "jpe", 3, "image/jpeg" }, |
| 159 | 159 | { "jpeg", 4, "image/jpeg" }, |
| 160 | 160 | { "jpg", 3, "image/jpeg" }, |
| 161 | - { "js", 2, "application/javascript" }, | |
| 161 | + { "js", 2, "text/javascript" }, | |
| 162 | + /* application/javascript is commonly used for JS, but the | |
| 163 | + ** spec says text/javascript is correct: | |
| 164 | + ** https://html.spec.whatwg.org/multipage/scripting.html | |
| 165 | + ** #scriptingLanguages:javascript-mime-type */ | |
| 166 | + { "json", 4, "application/json" }, | |
| 162 | 167 | { "kar", 3, "audio/midi" }, |
| 163 | 168 | { "latex", 5, "application/x-latex" }, |
| 164 | 169 | { "lha", 3, "application/octet-stream" }, |
| 165 | 170 | { "lsp", 3, "application/x-lisp" }, |
| 166 | 171 | { "lzh", 3, "application/octet-stream" }, |
| @@ -173,10 +178,11 @@ | ||
| 173 | 178 | { "mesh", 4, "model/mesh" }, |
| 174 | 179 | { "mid", 3, "audio/midi" }, |
| 175 | 180 | { "midi", 4, "audio/midi" }, |
| 176 | 181 | { "mif", 3, "application/x-mif" }, |
| 177 | 182 | { "mime", 4, "www/mime" }, |
| 183 | + { "mjs", 3, "text/javascript" /*EM6 modules*/ }, | |
| 178 | 184 | { "mkd", 3, "text/x-markdown" }, |
| 179 | 185 | { "mov", 3, "video/quicktime" }, |
| 180 | 186 | { "movie", 5, "video/x-sgi-movie" }, |
| 181 | 187 | { "mp2", 3, "audio/mpeg" }, |
| 182 | 188 | { "mp3", 3, "audio/mpeg" }, |
| 183 | 189 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -156,11 +156,16 @@ | |
| 156 | { "jad", 3, "text/vnd.sun.j2me.app-descriptor" }, |
| 157 | { "jar", 3, "application/java-archive" }, |
| 158 | { "jpe", 3, "image/jpeg" }, |
| 159 | { "jpeg", 4, "image/jpeg" }, |
| 160 | { "jpg", 3, "image/jpeg" }, |
| 161 | { "js", 2, "application/javascript" }, |
| 162 | { "kar", 3, "audio/midi" }, |
| 163 | { "latex", 5, "application/x-latex" }, |
| 164 | { "lha", 3, "application/octet-stream" }, |
| 165 | { "lsp", 3, "application/x-lisp" }, |
| 166 | { "lzh", 3, "application/octet-stream" }, |
| @@ -173,10 +178,11 @@ | |
| 173 | { "mesh", 4, "model/mesh" }, |
| 174 | { "mid", 3, "audio/midi" }, |
| 175 | { "midi", 4, "audio/midi" }, |
| 176 | { "mif", 3, "application/x-mif" }, |
| 177 | { "mime", 4, "www/mime" }, |
| 178 | { "mkd", 3, "text/x-markdown" }, |
| 179 | { "mov", 3, "video/quicktime" }, |
| 180 | { "movie", 5, "video/x-sgi-movie" }, |
| 181 | { "mp2", 3, "audio/mpeg" }, |
| 182 | { "mp3", 3, "audio/mpeg" }, |
| 183 |
| --- src/doc.c | |
| +++ src/doc.c | |
| @@ -156,11 +156,16 @@ | |
| 156 | { "jad", 3, "text/vnd.sun.j2me.app-descriptor" }, |
| 157 | { "jar", 3, "application/java-archive" }, |
| 158 | { "jpe", 3, "image/jpeg" }, |
| 159 | { "jpeg", 4, "image/jpeg" }, |
| 160 | { "jpg", 3, "image/jpeg" }, |
| 161 | { "js", 2, "text/javascript" }, |
| 162 | /* application/javascript is commonly used for JS, but the |
| 163 | ** spec says text/javascript is correct: |
| 164 | ** https://html.spec.whatwg.org/multipage/scripting.html |
| 165 | ** #scriptingLanguages:javascript-mime-type */ |
| 166 | { "json", 4, "application/json" }, |
| 167 | { "kar", 3, "audio/midi" }, |
| 168 | { "latex", 5, "application/x-latex" }, |
| 169 | { "lha", 3, "application/octet-stream" }, |
| 170 | { "lsp", 3, "application/x-lisp" }, |
| 171 | { "lzh", 3, "application/octet-stream" }, |
| @@ -173,10 +178,11 @@ | |
| 178 | { "mesh", 4, "model/mesh" }, |
| 179 | { "mid", 3, "audio/midi" }, |
| 180 | { "midi", 4, "audio/midi" }, |
| 181 | { "mif", 3, "application/x-mif" }, |
| 182 | { "mime", 4, "www/mime" }, |
| 183 | { "mjs", 3, "text/javascript" /*EM6 modules*/ }, |
| 184 | { "mkd", 3, "text/x-markdown" }, |
| 185 | { "mov", 3, "video/quicktime" }, |
| 186 | { "movie", 5, "video/x-sgi-movie" }, |
| 187 | { "mp2", 3, "audio/mpeg" }, |
| 188 | { "mp3", 3, "audio/mpeg" }, |
| 189 |
+9
-1
| --- src/fossil.page.pikchrshow.js | ||
| +++ src/fossil.page.pikchrshow.js | ||
| @@ -1,12 +1,20 @@ | ||
| 1 | 1 | (function(F/*the fossil object*/){ |
| 2 | 2 | "use strict"; |
| 3 | 3 | /** |
| 4 | - Client-side implementation of the /pikchrshow app. Requires that | |
| 4 | + Client-side implementation of the /pikchrshowcs app. Requires that | |
| 5 | 5 | the fossil JS bootstrapping is complete and that these fossil JS |
| 6 | 6 | APIs have been installed: fossil.fetch, fossil.dom, |
| 7 | 7 | fossil.copybutton, fossil.popupwidget, fossil.storage |
| 8 | + | |
| 9 | + Maintenance funkiness note: this file is for the legacy | |
| 10 | + /pikchrshowcs app, which was formerly named /pikchrshow. This | |
| 11 | + file and its replacement were not renamed because the replacement | |
| 12 | + impl would end up getting this file's name and cause confusion in | |
| 13 | + the file history. Whether that confusion would be less than this | |
| 14 | + file's name matching the _other_ /pikchrshow impl will cause more | |
| 15 | + or less confusion than that remains to be seen. | |
| 8 | 16 | */ |
| 9 | 17 | const E = (s)=>document.querySelector(s), |
| 10 | 18 | D = F.dom, |
| 11 | 19 | P = F.page; |
| 12 | 20 | |
| 13 | 21 | |
| 14 | 22 | ADDED src/fossil.page.pikchrshowasm.js |
| --- src/fossil.page.pikchrshow.js | |
| +++ src/fossil.page.pikchrshow.js | |
| @@ -1,12 +1,20 @@ | |
| 1 | (function(F/*the fossil object*/){ |
| 2 | "use strict"; |
| 3 | /** |
| 4 | Client-side implementation of the /pikchrshow app. Requires that |
| 5 | the fossil JS bootstrapping is complete and that these fossil JS |
| 6 | APIs have been installed: fossil.fetch, fossil.dom, |
| 7 | fossil.copybutton, fossil.popupwidget, fossil.storage |
| 8 | */ |
| 9 | const E = (s)=>document.querySelector(s), |
| 10 | D = F.dom, |
| 11 | P = F.page; |
| 12 | |
| 13 | |
| 14 | DDED src/fossil.page.pikchrshowasm.js |
| --- src/fossil.page.pikchrshow.js | |
| +++ src/fossil.page.pikchrshow.js | |
| @@ -1,12 +1,20 @@ | |
| 1 | (function(F/*the fossil object*/){ |
| 2 | "use strict"; |
| 3 | /** |
| 4 | Client-side implementation of the /pikchrshowcs app. Requires that |
| 5 | the fossil JS bootstrapping is complete and that these fossil JS |
| 6 | APIs have been installed: fossil.fetch, fossil.dom, |
| 7 | fossil.copybutton, fossil.popupwidget, fossil.storage |
| 8 | |
| 9 | Maintenance funkiness note: this file is for the legacy |
| 10 | /pikchrshowcs app, which was formerly named /pikchrshow. This |
| 11 | file and its replacement were not renamed because the replacement |
| 12 | impl would end up getting this file's name and cause confusion in |
| 13 | the file history. Whether that confusion would be less than this |
| 14 | file's name matching the _other_ /pikchrshow impl will cause more |
| 15 | or less confusion than that remains to be seen. |
| 16 | */ |
| 17 | const E = (s)=>document.querySelector(s), |
| 18 | D = F.dom, |
| 19 | P = F.page; |
| 20 | |
| 21 | |
| 22 | DDED src/fossil.page.pikchrshowasm.js |
| --- a/src/fossil.page.pikchrshowasm.js | ||
| +++ b/src/fossil.page.pikchrshowasm.js | ||
| @@ -0,0 +1,24 @@ | ||
| 1 | +/* | |
| 2 | + 2022-05-20 | |
| 3 | + | |
| 4 | + The author disclaims copyright to this source code. In place of a | |
| 5 | + legal notice, here is a blessing: | |
| 6 | + | |
| 7 | + * May you do good and not evil. | |
| 8 | + * May you find forgiveness for yourself and forgive others. | |
| 9 | + * May you share freely, never taking more than you give. | |
| 10 | + | |
| 11 | + *********************************************************************** | |
| 12 | + | |
| 13 | + This is the main entry point for the WASM r | |
| 14 | + * May you share fre/* | |
| 15 | + :div.didiv. ttr(selectScript, 'aria-label', 'Example Scripts'); | |
| 16 | + D.attr(selectScript,...EAll('body > *:not(.content)let ht = whht -= F.dom.effectiveHeight(e)) | |
| 17 | + ]; | |
| 18 | + | |
| 19 | + | |
| 20 | +})(window.fossil); | |
| 21 | +E('body > header.header'), | |
| 22 | + E('body > nav.mainmenu'), | |
| 23 | + E('body > footer.footervar ht; | |
| 24 | + var extra = 0e ? extra + ht = wh - extradivdidivshowshow-ready',show#btn-options |
| --- a/src/fossil.page.pikchrshowasm.js | |
| +++ b/src/fossil.page.pikchrshowasm.js | |
| @@ -0,0 +1,24 @@ | |
| --- a/src/fossil.page.pikchrshowasm.js | |
| +++ b/src/fossil.page.pikchrshowasm.js | |
| @@ -0,0 +1,24 @@ | |
| 1 | /* |
| 2 | 2022-05-20 |
| 3 | |
| 4 | The author disclaims copyright to this source code. In place of a |
| 5 | legal notice, here is a blessing: |
| 6 | |
| 7 | * May you do good and not evil. |
| 8 | * May you find forgiveness for yourself and forgive others. |
| 9 | * May you share freely, never taking more than you give. |
| 10 | |
| 11 | *********************************************************************** |
| 12 | |
| 13 | This is the main entry point for the WASM r |
| 14 | * May you share fre/* |
| 15 | :div.didiv. ttr(selectScript, 'aria-label', 'Example Scripts'); |
| 16 | D.attr(selectScript,...EAll('body > *:not(.content)let ht = whht -= F.dom.effectiveHeight(e)) |
| 17 | ]; |
| 18 | |
| 19 | |
| 20 | })(window.fossil); |
| 21 | E('body > header.header'), |
| 22 | E('body > nav.mainmenu'), |
| 23 | E('body > footer.footervar ht; |
| 24 | var extra = 0e ? extra + ht = wh - extradivdidivshowshow-ready',show#btn-options |
+10
-8
| --- src/json.c | ||
| +++ src/json.c | ||
| @@ -558,11 +558,11 @@ | ||
| 558 | 558 | /* |
| 559 | 559 | ** Guesses a RESPONSE Content-Type value based (primarily) on the |
| 560 | 560 | ** HTTP_ACCEPT header. |
| 561 | 561 | ** |
| 562 | 562 | ** It will try to figure out if the client can support |
| 563 | -** application/json or application/javascript, and will fall back to | |
| 563 | +** application/json, text/javascript, and will fall back to | |
| 564 | 564 | ** text/plain if it cannot figure out anything more specific. |
| 565 | 565 | ** |
| 566 | 566 | ** Returned memory is static and immutable, but if the environment |
| 567 | 567 | ** changes after calling this then subsequent calls to this function |
| 568 | 568 | ** might return different (also static/immutable) values. |
| @@ -573,12 +573,12 @@ | ||
| 573 | 573 | cset = PD("HTTP_ACCEPT_CHARSET",NULL); |
| 574 | 574 | doUtf8 = ((NULL == cset) || (NULL!=strstr("utf-8",cset))) |
| 575 | 575 | ? 1 : 0; |
| 576 | 576 | if( g.json.jsonp ){ |
| 577 | 577 | return doUtf8 |
| 578 | - ? "application/javascript; charset=utf-8" | |
| 579 | - : "application/javascript"; | |
| 578 | + ? "text/javascript; charset=utf-8" | |
| 579 | + : "text/javascript"; | |
| 580 | 580 | }else{ |
| 581 | 581 | /* |
| 582 | 582 | Content-type |
| 583 | 583 | |
| 584 | 584 | If the browser does not sent an ACCEPT for application/json |
| @@ -605,18 +605,19 @@ | ||
| 605 | 605 | |
| 606 | 606 | /* |
| 607 | 607 | ** Given a request CONTENT_TYPE value, this function returns true |
| 608 | 608 | ** if it is of a type which the JSON API can ostensibly read. |
| 609 | 609 | ** |
| 610 | - ** It accepts any of application/json, text/plain, or | |
| 611 | - ** application/javascript. The former is preferred, but was not | |
| 612 | - ** widespread when this API was initially built, so the latter forms | |
| 613 | - ** are permitted as fallbacks. | |
| 610 | + ** It accepts any of application/json, text/plain, | |
| 611 | + ** application/javascript, or text/javascript. The former is | |
| 612 | + ** preferred, but was not widespread when this API was initially | |
| 613 | + ** built, so the latter forms are permitted as fallbacks. | |
| 614 | 614 | */ |
| 615 | 615 | int json_can_consume_content_type(const char * zType){ |
| 616 | 616 | return fossil_strcmp(zType, "application/json")==0 |
| 617 | 617 | || fossil_strcmp(zType,"text/plain")==0/*assume this MIGHT be JSON*/ |
| 618 | + || fossil_strcmp(zType,"text/javascript")==0 | |
| 618 | 619 | || fossil_strcmp(zType,"application/javascript")==0; |
| 619 | 620 | } |
| 620 | 621 | |
| 621 | 622 | /* |
| 622 | 623 | ** Sends pResponse to the output stream as the response object. This |
| @@ -627,18 +628,19 @@ | ||
| 627 | 628 | ** In CLI mode pResponse is sent to stdout immediately. In HTTP |
| 628 | 629 | ** mode pResponse replaces any current CGI content but cgi_reply() |
| 629 | 630 | ** is not called to flush the output. |
| 630 | 631 | ** |
| 631 | 632 | ** If g.json.jsonp is not NULL then the content type is set to |
| 632 | -** application/javascript and the output is wrapped in a jsonp | |
| 633 | +** text/javascript and the output is wrapped in a jsonp | |
| 633 | 634 | ** wrapper. |
| 634 | 635 | */ |
| 635 | 636 | void json_send_response( cson_value const * pResponse ){ |
| 636 | 637 | assert( NULL != pResponse ); |
| 637 | 638 | if( g.isHTTP ){ |
| 638 | 639 | cgi_reset_content(); |
| 639 | 640 | if( g.json.jsonp ){ |
| 641 | + cgi_set_content_type("text/javascript"); | |
| 640 | 642 | cgi_printf("%s(",g.json.jsonp); |
| 641 | 643 | } |
| 642 | 644 | cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt ); |
| 643 | 645 | if( g.json.jsonp ){ |
| 644 | 646 | cgi_append_content(")",1); |
| 645 | 647 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -558,11 +558,11 @@ | |
| 558 | /* |
| 559 | ** Guesses a RESPONSE Content-Type value based (primarily) on the |
| 560 | ** HTTP_ACCEPT header. |
| 561 | ** |
| 562 | ** It will try to figure out if the client can support |
| 563 | ** application/json or application/javascript, and will fall back to |
| 564 | ** text/plain if it cannot figure out anything more specific. |
| 565 | ** |
| 566 | ** Returned memory is static and immutable, but if the environment |
| 567 | ** changes after calling this then subsequent calls to this function |
| 568 | ** might return different (also static/immutable) values. |
| @@ -573,12 +573,12 @@ | |
| 573 | cset = PD("HTTP_ACCEPT_CHARSET",NULL); |
| 574 | doUtf8 = ((NULL == cset) || (NULL!=strstr("utf-8",cset))) |
| 575 | ? 1 : 0; |
| 576 | if( g.json.jsonp ){ |
| 577 | return doUtf8 |
| 578 | ? "application/javascript; charset=utf-8" |
| 579 | : "application/javascript"; |
| 580 | }else{ |
| 581 | /* |
| 582 | Content-type |
| 583 | |
| 584 | If the browser does not sent an ACCEPT for application/json |
| @@ -605,18 +605,19 @@ | |
| 605 | |
| 606 | /* |
| 607 | ** Given a request CONTENT_TYPE value, this function returns true |
| 608 | ** if it is of a type which the JSON API can ostensibly read. |
| 609 | ** |
| 610 | ** It accepts any of application/json, text/plain, or |
| 611 | ** application/javascript. The former is preferred, but was not |
| 612 | ** widespread when this API was initially built, so the latter forms |
| 613 | ** are permitted as fallbacks. |
| 614 | */ |
| 615 | int json_can_consume_content_type(const char * zType){ |
| 616 | return fossil_strcmp(zType, "application/json")==0 |
| 617 | || fossil_strcmp(zType,"text/plain")==0/*assume this MIGHT be JSON*/ |
| 618 | || fossil_strcmp(zType,"application/javascript")==0; |
| 619 | } |
| 620 | |
| 621 | /* |
| 622 | ** Sends pResponse to the output stream as the response object. This |
| @@ -627,18 +628,19 @@ | |
| 627 | ** In CLI mode pResponse is sent to stdout immediately. In HTTP |
| 628 | ** mode pResponse replaces any current CGI content but cgi_reply() |
| 629 | ** is not called to flush the output. |
| 630 | ** |
| 631 | ** If g.json.jsonp is not NULL then the content type is set to |
| 632 | ** application/javascript and the output is wrapped in a jsonp |
| 633 | ** wrapper. |
| 634 | */ |
| 635 | void json_send_response( cson_value const * pResponse ){ |
| 636 | assert( NULL != pResponse ); |
| 637 | if( g.isHTTP ){ |
| 638 | cgi_reset_content(); |
| 639 | if( g.json.jsonp ){ |
| 640 | cgi_printf("%s(",g.json.jsonp); |
| 641 | } |
| 642 | cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt ); |
| 643 | if( g.json.jsonp ){ |
| 644 | cgi_append_content(")",1); |
| 645 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -558,11 +558,11 @@ | |
| 558 | /* |
| 559 | ** Guesses a RESPONSE Content-Type value based (primarily) on the |
| 560 | ** HTTP_ACCEPT header. |
| 561 | ** |
| 562 | ** It will try to figure out if the client can support |
| 563 | ** application/json, text/javascript, and will fall back to |
| 564 | ** text/plain if it cannot figure out anything more specific. |
| 565 | ** |
| 566 | ** Returned memory is static and immutable, but if the environment |
| 567 | ** changes after calling this then subsequent calls to this function |
| 568 | ** might return different (also static/immutable) values. |
| @@ -573,12 +573,12 @@ | |
| 573 | cset = PD("HTTP_ACCEPT_CHARSET",NULL); |
| 574 | doUtf8 = ((NULL == cset) || (NULL!=strstr("utf-8",cset))) |
| 575 | ? 1 : 0; |
| 576 | if( g.json.jsonp ){ |
| 577 | return doUtf8 |
| 578 | ? "text/javascript; charset=utf-8" |
| 579 | : "text/javascript"; |
| 580 | }else{ |
| 581 | /* |
| 582 | Content-type |
| 583 | |
| 584 | If the browser does not sent an ACCEPT for application/json |
| @@ -605,18 +605,19 @@ | |
| 605 | |
| 606 | /* |
| 607 | ** Given a request CONTENT_TYPE value, this function returns true |
| 608 | ** if it is of a type which the JSON API can ostensibly read. |
| 609 | ** |
| 610 | ** It accepts any of application/json, text/plain, |
| 611 | ** application/javascript, or text/javascript. The former is |
| 612 | ** preferred, but was not widespread when this API was initially |
| 613 | ** built, so the latter forms are permitted as fallbacks. |
| 614 | */ |
| 615 | int json_can_consume_content_type(const char * zType){ |
| 616 | return fossil_strcmp(zType, "application/json")==0 |
| 617 | || fossil_strcmp(zType,"text/plain")==0/*assume this MIGHT be JSON*/ |
| 618 | || fossil_strcmp(zType,"text/javascript")==0 |
| 619 | || fossil_strcmp(zType,"application/javascript")==0; |
| 620 | } |
| 621 | |
| 622 | /* |
| 623 | ** Sends pResponse to the output stream as the response object. This |
| @@ -627,18 +628,19 @@ | |
| 628 | ** In CLI mode pResponse is sent to stdout immediately. In HTTP |
| 629 | ** mode pResponse replaces any current CGI content but cgi_reply() |
| 630 | ** is not called to flush the output. |
| 631 | ** |
| 632 | ** If g.json.jsonp is not NULL then the content type is set to |
| 633 | ** text/javascript and the output is wrapped in a jsonp |
| 634 | ** wrapper. |
| 635 | */ |
| 636 | void json_send_response( cson_value const * pResponse ){ |
| 637 | assert( NULL != pResponse ); |
| 638 | if( g.isHTTP ){ |
| 639 | cgi_reset_content(); |
| 640 | if( g.json.jsonp ){ |
| 641 | cgi_set_content_type("text/javascript"); |
| 642 | cgi_printf("%s(",g.json.jsonp); |
| 643 | } |
| 644 | cson_output( pResponse, cson_data_dest_cgi, NULL, &g.json.outOpt ); |
| 645 | if( g.json.jsonp ){ |
| 646 | cgi_append_content(")",1); |
| 647 |
+10
| --- src/main.mk | ||
| +++ src/main.mk | ||
| @@ -163,10 +163,13 @@ | ||
| 163 | 163 | $(SRCDIR)/xfer.c \ |
| 164 | 164 | $(SRCDIR)/xfersetup.c \ |
| 165 | 165 | $(SRCDIR)/zip.c |
| 166 | 166 | |
| 167 | 167 | EXTRA_FILES = \ |
| 168 | + $(SRCDIR)/../extsrc/pikchr-worker.js \ | |
| 169 | + $(SRCDIR)/../extsrc/pikchr.js \ | |
| 170 | + $(SRCDIR)/../extsrc/pikchr.wasm \ | |
| 168 | 171 | $(SRCDIR)/../skins/ardoise/css.txt \ |
| 169 | 172 | $(SRCDIR)/../skins/ardoise/details.txt \ |
| 170 | 173 | $(SRCDIR)/../skins/ardoise/footer.txt \ |
| 171 | 174 | $(SRCDIR)/../skins/ardoise/header.txt \ |
| 172 | 175 | $(SRCDIR)/../skins/black_and_white/css.txt \ |
| @@ -231,10 +234,11 @@ | ||
| 231 | 234 | $(SRCDIR)/fossil.page.brlist.js \ |
| 232 | 235 | $(SRCDIR)/fossil.page.chat.js \ |
| 233 | 236 | $(SRCDIR)/fossil.page.fileedit.js \ |
| 234 | 237 | $(SRCDIR)/fossil.page.forumpost.js \ |
| 235 | 238 | $(SRCDIR)/fossil.page.pikchrshow.js \ |
| 239 | + $(SRCDIR)/fossil.page.pikchrshowasm.js \ | |
| 236 | 240 | $(SRCDIR)/fossil.page.whistory.js \ |
| 237 | 241 | $(SRCDIR)/fossil.page.wikiedit.js \ |
| 238 | 242 | $(SRCDIR)/fossil.pikchr.js \ |
| 239 | 243 | $(SRCDIR)/fossil.popupwidget.js \ |
| 240 | 244 | $(SRCDIR)/fossil.storage.js \ |
| @@ -266,10 +270,11 @@ | ||
| 266 | 270 | $(SRCDIR)/sounds/e.wav \ |
| 267 | 271 | $(SRCDIR)/sounds/f.wav \ |
| 268 | 272 | $(SRCDIR)/style.admin_log.css \ |
| 269 | 273 | $(SRCDIR)/style.chat.css \ |
| 270 | 274 | $(SRCDIR)/style.fileedit.css \ |
| 275 | + $(SRCDIR)/style.pikchrshow.css \ | |
| 271 | 276 | $(SRCDIR)/style.wikiedit.css \ |
| 272 | 277 | $(SRCDIR)/tree.js \ |
| 273 | 278 | $(SRCDIR)/useredit.js \ |
| 274 | 279 | $(SRCDIR)/wiki.wiki |
| 275 | 280 | |
| @@ -2108,13 +2113,18 @@ | ||
| 2108 | 2113 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c |
| 2109 | 2114 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2110 | 2115 | |
| 2111 | 2116 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 2112 | 2117 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2118 | + | |
| 2119 | +$(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c | |
| 2120 | + $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry -sEXPORTED_RUNTIME_METHODS=cwrap,setValue,getValue,stackSave,stackRestore -sEXPORTED_FUNCTIONS=_pikchr $(SRCDIR_extsrc)/pikchr.c -sENVIRONMENT=web -sMODULARIZE -sEXPORT_NAME=initPikchrModule --minify 0 | |
| 2121 | + @chmod -x $(SRCDIR_extsrc)/pikchr.wasm | |
| 2122 | +wasm: $(SRCDIR_extsrc)/pikchr.js | |
| 2113 | 2123 | |
| 2114 | 2124 | # |
| 2115 | 2125 | # The list of all the targets that do not correspond to real files. This stops |
| 2116 | 2126 | # 'make' from getting confused when someone makes an error in a rule. |
| 2117 | 2127 | # |
| 2118 | 2128 | |
| 2119 | 2129 | .PHONY: all install test clean |
| 2120 | 2130 | |
| 2121 | 2131 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -163,10 +163,13 @@ | |
| 163 | $(SRCDIR)/xfer.c \ |
| 164 | $(SRCDIR)/xfersetup.c \ |
| 165 | $(SRCDIR)/zip.c |
| 166 | |
| 167 | EXTRA_FILES = \ |
| 168 | $(SRCDIR)/../skins/ardoise/css.txt \ |
| 169 | $(SRCDIR)/../skins/ardoise/details.txt \ |
| 170 | $(SRCDIR)/../skins/ardoise/footer.txt \ |
| 171 | $(SRCDIR)/../skins/ardoise/header.txt \ |
| 172 | $(SRCDIR)/../skins/black_and_white/css.txt \ |
| @@ -231,10 +234,11 @@ | |
| 231 | $(SRCDIR)/fossil.page.brlist.js \ |
| 232 | $(SRCDIR)/fossil.page.chat.js \ |
| 233 | $(SRCDIR)/fossil.page.fileedit.js \ |
| 234 | $(SRCDIR)/fossil.page.forumpost.js \ |
| 235 | $(SRCDIR)/fossil.page.pikchrshow.js \ |
| 236 | $(SRCDIR)/fossil.page.whistory.js \ |
| 237 | $(SRCDIR)/fossil.page.wikiedit.js \ |
| 238 | $(SRCDIR)/fossil.pikchr.js \ |
| 239 | $(SRCDIR)/fossil.popupwidget.js \ |
| 240 | $(SRCDIR)/fossil.storage.js \ |
| @@ -266,10 +270,11 @@ | |
| 266 | $(SRCDIR)/sounds/e.wav \ |
| 267 | $(SRCDIR)/sounds/f.wav \ |
| 268 | $(SRCDIR)/style.admin_log.css \ |
| 269 | $(SRCDIR)/style.chat.css \ |
| 270 | $(SRCDIR)/style.fileedit.css \ |
| 271 | $(SRCDIR)/style.wikiedit.css \ |
| 272 | $(SRCDIR)/tree.js \ |
| 273 | $(SRCDIR)/useredit.js \ |
| 274 | $(SRCDIR)/wiki.wiki |
| 275 | |
| @@ -2108,13 +2113,18 @@ | |
| 2108 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c |
| 2109 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2110 | |
| 2111 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 2112 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2113 | |
| 2114 | # |
| 2115 | # The list of all the targets that do not correspond to real files. This stops |
| 2116 | # 'make' from getting confused when someone makes an error in a rule. |
| 2117 | # |
| 2118 | |
| 2119 | .PHONY: all install test clean |
| 2120 | |
| 2121 |
| --- src/main.mk | |
| +++ src/main.mk | |
| @@ -163,10 +163,13 @@ | |
| 163 | $(SRCDIR)/xfer.c \ |
| 164 | $(SRCDIR)/xfersetup.c \ |
| 165 | $(SRCDIR)/zip.c |
| 166 | |
| 167 | EXTRA_FILES = \ |
| 168 | $(SRCDIR)/../extsrc/pikchr-worker.js \ |
| 169 | $(SRCDIR)/../extsrc/pikchr.js \ |
| 170 | $(SRCDIR)/../extsrc/pikchr.wasm \ |
| 171 | $(SRCDIR)/../skins/ardoise/css.txt \ |
| 172 | $(SRCDIR)/../skins/ardoise/details.txt \ |
| 173 | $(SRCDIR)/../skins/ardoise/footer.txt \ |
| 174 | $(SRCDIR)/../skins/ardoise/header.txt \ |
| 175 | $(SRCDIR)/../skins/black_and_white/css.txt \ |
| @@ -231,10 +234,11 @@ | |
| 234 | $(SRCDIR)/fossil.page.brlist.js \ |
| 235 | $(SRCDIR)/fossil.page.chat.js \ |
| 236 | $(SRCDIR)/fossil.page.fileedit.js \ |
| 237 | $(SRCDIR)/fossil.page.forumpost.js \ |
| 238 | $(SRCDIR)/fossil.page.pikchrshow.js \ |
| 239 | $(SRCDIR)/fossil.page.pikchrshowasm.js \ |
| 240 | $(SRCDIR)/fossil.page.whistory.js \ |
| 241 | $(SRCDIR)/fossil.page.wikiedit.js \ |
| 242 | $(SRCDIR)/fossil.pikchr.js \ |
| 243 | $(SRCDIR)/fossil.popupwidget.js \ |
| 244 | $(SRCDIR)/fossil.storage.js \ |
| @@ -266,10 +270,11 @@ | |
| 270 | $(SRCDIR)/sounds/e.wav \ |
| 271 | $(SRCDIR)/sounds/f.wav \ |
| 272 | $(SRCDIR)/style.admin_log.css \ |
| 273 | $(SRCDIR)/style.chat.css \ |
| 274 | $(SRCDIR)/style.fileedit.css \ |
| 275 | $(SRCDIR)/style.pikchrshow.css \ |
| 276 | $(SRCDIR)/style.wikiedit.css \ |
| 277 | $(SRCDIR)/tree.js \ |
| 278 | $(SRCDIR)/useredit.js \ |
| 279 | $(SRCDIR)/wiki.wiki |
| 280 | |
| @@ -2108,13 +2113,18 @@ | |
| 2113 | $(OBJDIR)/pikchr.o: $(SRCDIR_extsrc)/pikchr.c |
| 2114 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 2115 | |
| 2116 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 2117 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 2118 | |
| 2119 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c |
| 2120 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry -sEXPORTED_RUNTIME_METHODS=cwrap,setValue,getValue,stackSave,stackRestore -sEXPORTED_FUNCTIONS=_pikchr $(SRCDIR_extsrc)/pikchr.c -sENVIRONMENT=web -sMODULARIZE -sEXPORT_NAME=initPikchrModule --minify 0 |
| 2121 | @chmod -x $(SRCDIR_extsrc)/pikchr.wasm |
| 2122 | wasm: $(SRCDIR_extsrc)/pikchr.js |
| 2123 | |
| 2124 | # |
| 2125 | # The list of all the targets that do not correspond to real files. This stops |
| 2126 | # 'make' from getting confused when someone makes an error in a rule. |
| 2127 | # |
| 2128 | |
| 2129 | .PHONY: all install test clean |
| 2130 | |
| 2131 |
+147
-9
| --- src/pikchrshow.c | ||
| +++ src/pikchrshow.c | ||
| @@ -230,30 +230,36 @@ | ||
| 230 | 230 | blob_reset(&bIn); |
| 231 | 231 | return isErr; |
| 232 | 232 | } |
| 233 | 233 | |
| 234 | 234 | /* |
| 235 | -** WEBPAGE: pikchrshow | |
| 235 | +** Legacy impl of /pikchrshow. pikchrshow_page() will delegate to | |
| 236 | +** this one if the "legacy" or "ajax" request arguments are set. | |
| 236 | 237 | ** |
| 237 | 238 | ** A pikchr code editor and previewer, allowing users to experiment |
| 238 | 239 | ** with pikchr code or prototype it for use in copy/pasting into forum |
| 239 | -** posts, wiki pages, or embedded docs. | |
| 240 | -** | |
| 241 | -** It optionally accepts a p=pikchr-script-code URL parameter or POST | |
| 242 | -** value to pre-populate the editor with that code. | |
| 240 | +** posts, wiki pages, or embedded docs. This version of pikchrshow | |
| 241 | +** uses JavaScript to send pikchr code to the server for | |
| 242 | +** processing. The newer /pikchrshow applications runs pikchr on the | |
| 243 | +** client machine, without the need for back-and-forth network | |
| 244 | +** traffic. | |
| 243 | 245 | */ |
| 244 | -void pikchrshow_page(void){ | |
| 246 | +void pikchrshowcs_page(void){ | |
| 245 | 247 | const char *zContent = 0; |
| 246 | 248 | int isDark; /* true if the current skin is "dark" */ |
| 247 | 249 | int pikFlags = |
| 248 | 250 | PIKCHR_PROCESS_DIV |
| 249 | 251 | | PIKCHR_PROCESS_SRC |
| 250 | 252 | | PIKCHR_PROCESS_ERR_PRE; |
| 251 | 253 | |
| 252 | 254 | login_check_credentials(); |
| 253 | 255 | if( !g.perm.RdWiki && !g.perm.Read && !g.perm.RdForum ){ |
| 254 | - cgi_redirectf("%R/login?g=pikchrshow"); | |
| 256 | + cgi_redirectf("%R/login?g=pikchrshowcs"); | |
| 257 | + } | |
| 258 | + if(P("wasm")){ | |
| 259 | + pikchrshow_page(); | |
| 260 | + return; | |
| 255 | 261 | } |
| 256 | 262 | zContent = PD("content",P("p")); |
| 257 | 263 | if(P("ajax")!=0){ |
| 258 | 264 | /* Called from the JS-side preview updater. |
| 259 | 265 | TODO: respond with JSON instead.*/ |
| @@ -279,11 +285,11 @@ | ||
| 279 | 285 | "box rad 10px \"Markdown\" \"Formatter\" \"(markdown.c)\" fit\n" |
| 280 | 286 | "arrow right 200% \"HTML+SVG\" \"Output\"\n" |
| 281 | 287 | "arrow <-> down from last box.s\n" |
| 282 | 288 | "box same \"Pikchr\" \"Formatter\" \"(pikchr.c)\" fit\n"; |
| 283 | 289 | } |
| 284 | - style_header("PikchrShow"); | |
| 290 | + style_header("PikchrShow Client/Server"); | |
| 285 | 291 | CX("<style>"); { |
| 286 | 292 | CX("div.content { padding-top: 0.5em }\n"); |
| 287 | 293 | CX("#sbs-wrapper {" |
| 288 | 294 | "display: flex; flex-direction: column;" |
| 289 | 295 | "}\n"); |
| @@ -336,11 +342,11 @@ | ||
| 336 | 342 | "vertical-align: middle" |
| 337 | 343 | "}\n"); |
| 338 | 344 | CX(".dragover {border: 3px dotted rgba(0,255,0,0.6)}\n"); |
| 339 | 345 | } CX("</style>"); |
| 340 | 346 | CX("<div>Input pikchr code and tap Preview (or Shift-Enter) to render " |
| 341 | - "it:</div>"); | |
| 347 | + "it. <a href='?wasm'>Switch to WASM mode</a>.</div>"); | |
| 342 | 348 | CX("<div id='sbs-wrapper'>"); { |
| 343 | 349 | CX("<div id='pikchrshow-form'>"); { |
| 344 | 350 | CX("<textarea id='content' name='content' rows='15'>" |
| 345 | 351 | "%s</textarea>",zContent/*safe-for-%s*/); |
| 346 | 352 | CX("<div id='pikchrshow-controls'>"); { |
| @@ -376,10 +382,142 @@ | ||
| 376 | 382 | "storage", "pikchr", NULL); |
| 377 | 383 | builtin_request_js("fossil.page.pikchrshow.js"); |
| 378 | 384 | builtin_fulfill_js_requests(); |
| 379 | 385 | style_finish_page(); |
| 380 | 386 | } |
| 387 | + | |
| 388 | +/* | |
| 389 | +** WEBPAGE: pikchrshow | |
| 390 | +** | |
| 391 | +** A pikchr code editor and previewer, allowing users to experiment | |
| 392 | +** with pikchr code or prototype it for use in copy/pasting into forum | |
| 393 | +** posts, wiki pages, or embedded docs. This version of pikchrshow | |
| 394 | +** uses WebAssembly to run entirely in the client browser, without a | |
| 395 | +** need for back-and-forth client/server traffic to perform the | |
| 396 | +** rendering. The "legacy" version of this application, which sends | |
| 397 | +** all input to the server for rendering, can be accessed by adding | |
| 398 | +** the "legacy" URL argument. | |
| 399 | +** | |
| 400 | +** It optionally accepts a p=pikchr-script-code URL parameter or POST | |
| 401 | +** value to pre-populate the editor with that code. | |
| 402 | +*/ | |
| 403 | +void pikchrshow_page(void){ | |
| 404 | + const char *zContent = 0; | |
| 405 | + | |
| 406 | + if(P("legacy") || P("ajax")){ | |
| 407 | + pikchrshowcs_page(); | |
| 408 | + return; | |
| 409 | + } | |
| 410 | + login_check_credentials(); | |
| 411 | + if( !g.perm.RdWiki && !g.perm.Read && !g.perm.RdForum ){ | |
| 412 | + cgi_redirectf("%R/login?g=pikchrshow"); | |
| 413 | + } | |
| 414 | + style_emit_noscript_for_js_page(); | |
| 415 | + style_header("PikchrShow"); | |
| 416 | + zContent = PD("content",P("p")); | |
| 417 | + if(!zContent){ | |
| 418 | + zContent = "arrow right 200% \"Markdown\" \"Source\"\n" | |
| 419 | + "box rad 10px \"Markdown\" \"Formatter\" \"(markdown.c)\" fit\n" | |
| 420 | + "arrow right 200% \"HTML+SVG\" \"Output\"\n" | |
| 421 | + "arrow <-> down from last box.s\n" | |
| 422 | + "box same \"Pikchr\" \"Formatter\" \"(pikchr.c)\" fit\n"; | |
| 423 | + } | |
| 424 | + /* Wasm load/init progress widget... */ | |
| 425 | + CX("<div class='emscripten'>"); { | |
| 426 | + CX("<figure id='module-spinner'>"); | |
| 427 | + CX("<div class='spinner'></div>"); | |
| 428 | + CX("<div class='center'><strong>Initializing app...</strong></div>"); | |
| 429 | + CX("<div class='center'>"); | |
| 430 | + CX("On a slow internet connection this may take a moment. If this "); | |
| 431 | + CX("message displays for \"a long time\", intialization may have "); | |
| 432 | + CX("failed and the JavaScript console may contain clues as to why. "); | |
| 433 | + CX("</div>"); | |
| 434 | + CX("<div><a href='?legacy'>Switch to legacy mode</a></div>"); | |
| 435 | + CX("</figure>"); | |
| 436 | + CX("<div class='emscripten' id='module-status'>Downloading...</div>"); | |
| 437 | + CX("<progress value='0' max='100' id='module-progress' hidden='1'>" | |
| 438 | + "</progress>"); | |
| 439 | + } CX("</div><!-- .emscripten -->"); | |
| 440 | + /* Main view... */ | |
| 441 | + CX("<div id='view-split' class='app-view initially-hidden'>"); { | |
| 442 | + CX("<fieldset class='options collapsible'>"); { | |
| 443 | + CX("<legend><button id='btn-options-toggle'>Options</button></legend>"); | |
| 444 | + CX("<div>"); | |
| 445 | + CX("<span class='labeled-input'>"); | |
| 446 | + CX("<input type='checkbox' id='opt-cb-sbs' "); | |
| 447 | + CX("data-csstgt='#main-wrapper' "); | |
| 448 | + CX("data-cssclass='side-by-side' "); | |
| 449 | + CX("data-config='sideBySide'>"); | |
| 450 | + CX("<label for='opt-cb-sbs'>Side-by-side</label>"); | |
| 451 | + CX("</span>"); | |
| 452 | + CX("<span class='labeled-input'>"); | |
| 453 | + CX("<input type='checkbox' id='opt-cb-swapio' "); | |
| 454 | + CX("data-csstgt='#main-wrapper' "); | |
| 455 | + CX("data-cssclass='swapio' "); | |
| 456 | + CX("data-config='swapInOut'>"); | |
| 457 | + CX("<label for='opt-cb-swapio'>Swap in/out</label>"); | |
| 458 | + CX("</span>"); | |
| 459 | + CX("<span class='labeled-input'>"); | |
| 460 | + CX("<input type='checkbox' id='opt-cb-autofit' "); | |
| 461 | + CX("data-config='renderAutofit'>"); | |
| 462 | + CX("<label for='opt-cb-autofit' " | |
| 463 | + "title='Attempt to scale SVG to fit viewport. " | |
| 464 | + "Whether it will work depends in part on the size " | |
| 465 | + "and shape of the image and the viewport.'" | |
| 466 | + ">Auto-fit SVG</label>"); | |
| 467 | + CX("</span>"); | |
| 468 | + CX("<span class='labeled-input'>"); | |
| 469 | + CX("<input type='checkbox' id='opt-cb-autorender' "); | |
| 470 | + CX("data-csstgt='#main-wrapper' "); | |
| 471 | + CX("data-cssclass='auto-render' "); | |
| 472 | + CX("data-config='renderWhileTyping'>"); | |
| 473 | + CX("<label for='opt-cb-autorender'>Render while typing</label>"); | |
| 474 | + CX("</span>"); | |
| 475 | + CX("<span class='labeled-input'>"); | |
| 476 | + CX("<a href='?legacy'>Legacy mode</a>"); | |
| 477 | + CX("</span>"); | |
| 478 | + CX("</div><!-- options wrapper -->"); | |
| 479 | + } CX("</fieldset>"); | |
| 480 | + CX("<div id='main-wrapper' class=''>"); { | |
| 481 | + CX("<fieldset class='zone-wrapper input'>"); { | |
| 482 | + CX("<legend><div class='button-bar'>"); | |
| 483 | + CX("<button id='btn-render' " | |
| 484 | + "title='Ctrl-Enter/Shift-Enter'>Render</button>"); | |
| 485 | + CX("<button id='btn-clear'>Clear Input</button>"); | |
| 486 | + CX("</div></legend>"); | |
| 487 | + CX("<div><textarea id='input'"); | |
| 488 | + CX("placeholder='Pikchr input. Ctrl-enter/shift-enter runs it.'>"); | |
| 489 | + CX("/**\n"); | |
| 490 | + CX(" Use ctrl-enter or shift-enter to execute\n"); | |
| 491 | + CX(" pikchr code. If only a subset is currently\n"); | |
| 492 | + CX(" selected, only that part is evaluated.\n*/\n"); | |
| 493 | + CX("%s</textarea></div>",zContent/*safe-for-%s*/); | |
| 494 | + } CX("</fieldset><!-- .zone-wrapper.input -->"); | |
| 495 | + /*CX("<div class='splitter-handle hidden'></div>");*/ | |
| 496 | + CX("<fieldset class='zone-wrapper output'>"); { | |
| 497 | + CX("<legend><div class='button-bar'>"); | |
| 498 | + CX("<button id='btn-render-mode'>Render Mode</button> "); | |
| 499 | + CX("<span style='white-space:nowrap'>" | |
| 500 | + "<span id='preview-copy-button' " | |
| 501 | + "title='Tap to copy to clipboard.'></span>" | |
| 502 | + "<label for='preview-copy-button' " | |
| 503 | + "title='Tap to copy to clipboard.'></label>" | |
| 504 | + "</span>"); | |
| 505 | + CX("</div></legend>"); | |
| 506 | + CX("<div id='pikchr-output-wrapper'>"); | |
| 507 | + CX("<div id='pikchr-output'></div>"); | |
| 508 | + CX("<textarea class='hidden' id='pikchr-output-text'></textarea>"); | |
| 509 | + CX("</div>"); | |
| 510 | + } CX("</fieldset> <!-- .zone-wrapper.output -->"); | |
| 511 | + } CX("</div><!-- #main-wrapper -->"); | |
| 512 | + } CX("</div><!-- #view-split -->"); | |
| 513 | + builtin_fossil_js_bundle_or("dom", "storage", "copybutton", NULL); | |
| 514 | + builtin_request_js("fossil.page.pikchrshowasm.js"); | |
| 515 | + builtin_fulfill_js_requests(); | |
| 516 | + style_finish_page(); | |
| 517 | +} | |
| 518 | + | |
| 381 | 519 | |
| 382 | 520 | /* |
| 383 | 521 | ** COMMAND: pikchr* |
| 384 | 522 | ** |
| 385 | 523 | ** Usage: %fossil pikchr [options] ?INFILE? ?OUTFILE? |
| 386 | 524 |
| --- src/pikchrshow.c | |
| +++ src/pikchrshow.c | |
| @@ -230,30 +230,36 @@ | |
| 230 | blob_reset(&bIn); |
| 231 | return isErr; |
| 232 | } |
| 233 | |
| 234 | /* |
| 235 | ** WEBPAGE: pikchrshow |
| 236 | ** |
| 237 | ** A pikchr code editor and previewer, allowing users to experiment |
| 238 | ** with pikchr code or prototype it for use in copy/pasting into forum |
| 239 | ** posts, wiki pages, or embedded docs. |
| 240 | ** |
| 241 | ** It optionally accepts a p=pikchr-script-code URL parameter or POST |
| 242 | ** value to pre-populate the editor with that code. |
| 243 | */ |
| 244 | void pikchrshow_page(void){ |
| 245 | const char *zContent = 0; |
| 246 | int isDark; /* true if the current skin is "dark" */ |
| 247 | int pikFlags = |
| 248 | PIKCHR_PROCESS_DIV |
| 249 | | PIKCHR_PROCESS_SRC |
| 250 | | PIKCHR_PROCESS_ERR_PRE; |
| 251 | |
| 252 | login_check_credentials(); |
| 253 | if( !g.perm.RdWiki && !g.perm.Read && !g.perm.RdForum ){ |
| 254 | cgi_redirectf("%R/login?g=pikchrshow"); |
| 255 | } |
| 256 | zContent = PD("content",P("p")); |
| 257 | if(P("ajax")!=0){ |
| 258 | /* Called from the JS-side preview updater. |
| 259 | TODO: respond with JSON instead.*/ |
| @@ -279,11 +285,11 @@ | |
| 279 | "box rad 10px \"Markdown\" \"Formatter\" \"(markdown.c)\" fit\n" |
| 280 | "arrow right 200% \"HTML+SVG\" \"Output\"\n" |
| 281 | "arrow <-> down from last box.s\n" |
| 282 | "box same \"Pikchr\" \"Formatter\" \"(pikchr.c)\" fit\n"; |
| 283 | } |
| 284 | style_header("PikchrShow"); |
| 285 | CX("<style>"); { |
| 286 | CX("div.content { padding-top: 0.5em }\n"); |
| 287 | CX("#sbs-wrapper {" |
| 288 | "display: flex; flex-direction: column;" |
| 289 | "}\n"); |
| @@ -336,11 +342,11 @@ | |
| 336 | "vertical-align: middle" |
| 337 | "}\n"); |
| 338 | CX(".dragover {border: 3px dotted rgba(0,255,0,0.6)}\n"); |
| 339 | } CX("</style>"); |
| 340 | CX("<div>Input pikchr code and tap Preview (or Shift-Enter) to render " |
| 341 | "it:</div>"); |
| 342 | CX("<div id='sbs-wrapper'>"); { |
| 343 | CX("<div id='pikchrshow-form'>"); { |
| 344 | CX("<textarea id='content' name='content' rows='15'>" |
| 345 | "%s</textarea>",zContent/*safe-for-%s*/); |
| 346 | CX("<div id='pikchrshow-controls'>"); { |
| @@ -376,10 +382,142 @@ | |
| 376 | "storage", "pikchr", NULL); |
| 377 | builtin_request_js("fossil.page.pikchrshow.js"); |
| 378 | builtin_fulfill_js_requests(); |
| 379 | style_finish_page(); |
| 380 | } |
| 381 | |
| 382 | /* |
| 383 | ** COMMAND: pikchr* |
| 384 | ** |
| 385 | ** Usage: %fossil pikchr [options] ?INFILE? ?OUTFILE? |
| 386 |
| --- src/pikchrshow.c | |
| +++ src/pikchrshow.c | |
| @@ -230,30 +230,36 @@ | |
| 230 | blob_reset(&bIn); |
| 231 | return isErr; |
| 232 | } |
| 233 | |
| 234 | /* |
| 235 | ** Legacy impl of /pikchrshow. pikchrshow_page() will delegate to |
| 236 | ** this one if the "legacy" or "ajax" request arguments are set. |
| 237 | ** |
| 238 | ** A pikchr code editor and previewer, allowing users to experiment |
| 239 | ** with pikchr code or prototype it for use in copy/pasting into forum |
| 240 | ** posts, wiki pages, or embedded docs. This version of pikchrshow |
| 241 | ** uses JavaScript to send pikchr code to the server for |
| 242 | ** processing. The newer /pikchrshow applications runs pikchr on the |
| 243 | ** client machine, without the need for back-and-forth network |
| 244 | ** traffic. |
| 245 | */ |
| 246 | void pikchrshowcs_page(void){ |
| 247 | const char *zContent = 0; |
| 248 | int isDark; /* true if the current skin is "dark" */ |
| 249 | int pikFlags = |
| 250 | PIKCHR_PROCESS_DIV |
| 251 | | PIKCHR_PROCESS_SRC |
| 252 | | PIKCHR_PROCESS_ERR_PRE; |
| 253 | |
| 254 | login_check_credentials(); |
| 255 | if( !g.perm.RdWiki && !g.perm.Read && !g.perm.RdForum ){ |
| 256 | cgi_redirectf("%R/login?g=pikchrshowcs"); |
| 257 | } |
| 258 | if(P("wasm")){ |
| 259 | pikchrshow_page(); |
| 260 | return; |
| 261 | } |
| 262 | zContent = PD("content",P("p")); |
| 263 | if(P("ajax")!=0){ |
| 264 | /* Called from the JS-side preview updater. |
| 265 | TODO: respond with JSON instead.*/ |
| @@ -279,11 +285,11 @@ | |
| 285 | "box rad 10px \"Markdown\" \"Formatter\" \"(markdown.c)\" fit\n" |
| 286 | "arrow right 200% \"HTML+SVG\" \"Output\"\n" |
| 287 | "arrow <-> down from last box.s\n" |
| 288 | "box same \"Pikchr\" \"Formatter\" \"(pikchr.c)\" fit\n"; |
| 289 | } |
| 290 | style_header("PikchrShow Client/Server"); |
| 291 | CX("<style>"); { |
| 292 | CX("div.content { padding-top: 0.5em }\n"); |
| 293 | CX("#sbs-wrapper {" |
| 294 | "display: flex; flex-direction: column;" |
| 295 | "}\n"); |
| @@ -336,11 +342,11 @@ | |
| 342 | "vertical-align: middle" |
| 343 | "}\n"); |
| 344 | CX(".dragover {border: 3px dotted rgba(0,255,0,0.6)}\n"); |
| 345 | } CX("</style>"); |
| 346 | CX("<div>Input pikchr code and tap Preview (or Shift-Enter) to render " |
| 347 | "it. <a href='?wasm'>Switch to WASM mode</a>.</div>"); |
| 348 | CX("<div id='sbs-wrapper'>"); { |
| 349 | CX("<div id='pikchrshow-form'>"); { |
| 350 | CX("<textarea id='content' name='content' rows='15'>" |
| 351 | "%s</textarea>",zContent/*safe-for-%s*/); |
| 352 | CX("<div id='pikchrshow-controls'>"); { |
| @@ -376,10 +382,142 @@ | |
| 382 | "storage", "pikchr", NULL); |
| 383 | builtin_request_js("fossil.page.pikchrshow.js"); |
| 384 | builtin_fulfill_js_requests(); |
| 385 | style_finish_page(); |
| 386 | } |
| 387 | |
| 388 | /* |
| 389 | ** WEBPAGE: pikchrshow |
| 390 | ** |
| 391 | ** A pikchr code editor and previewer, allowing users to experiment |
| 392 | ** with pikchr code or prototype it for use in copy/pasting into forum |
| 393 | ** posts, wiki pages, or embedded docs. This version of pikchrshow |
| 394 | ** uses WebAssembly to run entirely in the client browser, without a |
| 395 | ** need for back-and-forth client/server traffic to perform the |
| 396 | ** rendering. The "legacy" version of this application, which sends |
| 397 | ** all input to the server for rendering, can be accessed by adding |
| 398 | ** the "legacy" URL argument. |
| 399 | ** |
| 400 | ** It optionally accepts a p=pikchr-script-code URL parameter or POST |
| 401 | ** value to pre-populate the editor with that code. |
| 402 | */ |
| 403 | void pikchrshow_page(void){ |
| 404 | const char *zContent = 0; |
| 405 | |
| 406 | if(P("legacy") || P("ajax")){ |
| 407 | pikchrshowcs_page(); |
| 408 | return; |
| 409 | } |
| 410 | login_check_credentials(); |
| 411 | if( !g.perm.RdWiki && !g.perm.Read && !g.perm.RdForum ){ |
| 412 | cgi_redirectf("%R/login?g=pikchrshow"); |
| 413 | } |
| 414 | style_emit_noscript_for_js_page(); |
| 415 | style_header("PikchrShow"); |
| 416 | zContent = PD("content",P("p")); |
| 417 | if(!zContent){ |
| 418 | zContent = "arrow right 200% \"Markdown\" \"Source\"\n" |
| 419 | "box rad 10px \"Markdown\" \"Formatter\" \"(markdown.c)\" fit\n" |
| 420 | "arrow right 200% \"HTML+SVG\" \"Output\"\n" |
| 421 | "arrow <-> down from last box.s\n" |
| 422 | "box same \"Pikchr\" \"Formatter\" \"(pikchr.c)\" fit\n"; |
| 423 | } |
| 424 | /* Wasm load/init progress widget... */ |
| 425 | CX("<div class='emscripten'>"); { |
| 426 | CX("<figure id='module-spinner'>"); |
| 427 | CX("<div class='spinner'></div>"); |
| 428 | CX("<div class='center'><strong>Initializing app...</strong></div>"); |
| 429 | CX("<div class='center'>"); |
| 430 | CX("On a slow internet connection this may take a moment. If this "); |
| 431 | CX("message displays for \"a long time\", intialization may have "); |
| 432 | CX("failed and the JavaScript console may contain clues as to why. "); |
| 433 | CX("</div>"); |
| 434 | CX("<div><a href='?legacy'>Switch to legacy mode</a></div>"); |
| 435 | CX("</figure>"); |
| 436 | CX("<div class='emscripten' id='module-status'>Downloading...</div>"); |
| 437 | CX("<progress value='0' max='100' id='module-progress' hidden='1'>" |
| 438 | "</progress>"); |
| 439 | } CX("</div><!-- .emscripten -->"); |
| 440 | /* Main view... */ |
| 441 | CX("<div id='view-split' class='app-view initially-hidden'>"); { |
| 442 | CX("<fieldset class='options collapsible'>"); { |
| 443 | CX("<legend><button id='btn-options-toggle'>Options</button></legend>"); |
| 444 | CX("<div>"); |
| 445 | CX("<span class='labeled-input'>"); |
| 446 | CX("<input type='checkbox' id='opt-cb-sbs' "); |
| 447 | CX("data-csstgt='#main-wrapper' "); |
| 448 | CX("data-cssclass='side-by-side' "); |
| 449 | CX("data-config='sideBySide'>"); |
| 450 | CX("<label for='opt-cb-sbs'>Side-by-side</label>"); |
| 451 | CX("</span>"); |
| 452 | CX("<span class='labeled-input'>"); |
| 453 | CX("<input type='checkbox' id='opt-cb-swapio' "); |
| 454 | CX("data-csstgt='#main-wrapper' "); |
| 455 | CX("data-cssclass='swapio' "); |
| 456 | CX("data-config='swapInOut'>"); |
| 457 | CX("<label for='opt-cb-swapio'>Swap in/out</label>"); |
| 458 | CX("</span>"); |
| 459 | CX("<span class='labeled-input'>"); |
| 460 | CX("<input type='checkbox' id='opt-cb-autofit' "); |
| 461 | CX("data-config='renderAutofit'>"); |
| 462 | CX("<label for='opt-cb-autofit' " |
| 463 | "title='Attempt to scale SVG to fit viewport. " |
| 464 | "Whether it will work depends in part on the size " |
| 465 | "and shape of the image and the viewport.'" |
| 466 | ">Auto-fit SVG</label>"); |
| 467 | CX("</span>"); |
| 468 | CX("<span class='labeled-input'>"); |
| 469 | CX("<input type='checkbox' id='opt-cb-autorender' "); |
| 470 | CX("data-csstgt='#main-wrapper' "); |
| 471 | CX("data-cssclass='auto-render' "); |
| 472 | CX("data-config='renderWhileTyping'>"); |
| 473 | CX("<label for='opt-cb-autorender'>Render while typing</label>"); |
| 474 | CX("</span>"); |
| 475 | CX("<span class='labeled-input'>"); |
| 476 | CX("<a href='?legacy'>Legacy mode</a>"); |
| 477 | CX("</span>"); |
| 478 | CX("</div><!-- options wrapper -->"); |
| 479 | } CX("</fieldset>"); |
| 480 | CX("<div id='main-wrapper' class=''>"); { |
| 481 | CX("<fieldset class='zone-wrapper input'>"); { |
| 482 | CX("<legend><div class='button-bar'>"); |
| 483 | CX("<button id='btn-render' " |
| 484 | "title='Ctrl-Enter/Shift-Enter'>Render</button>"); |
| 485 | CX("<button id='btn-clear'>Clear Input</button>"); |
| 486 | CX("</div></legend>"); |
| 487 | CX("<div><textarea id='input'"); |
| 488 | CX("placeholder='Pikchr input. Ctrl-enter/shift-enter runs it.'>"); |
| 489 | CX("/**\n"); |
| 490 | CX(" Use ctrl-enter or shift-enter to execute\n"); |
| 491 | CX(" pikchr code. If only a subset is currently\n"); |
| 492 | CX(" selected, only that part is evaluated.\n*/\n"); |
| 493 | CX("%s</textarea></div>",zContent/*safe-for-%s*/); |
| 494 | } CX("</fieldset><!-- .zone-wrapper.input -->"); |
| 495 | /*CX("<div class='splitter-handle hidden'></div>");*/ |
| 496 | CX("<fieldset class='zone-wrapper output'>"); { |
| 497 | CX("<legend><div class='button-bar'>"); |
| 498 | CX("<button id='btn-render-mode'>Render Mode</button> "); |
| 499 | CX("<span style='white-space:nowrap'>" |
| 500 | "<span id='preview-copy-button' " |
| 501 | "title='Tap to copy to clipboard.'></span>" |
| 502 | "<label for='preview-copy-button' " |
| 503 | "title='Tap to copy to clipboard.'></label>" |
| 504 | "</span>"); |
| 505 | CX("</div></legend>"); |
| 506 | CX("<div id='pikchr-output-wrapper'>"); |
| 507 | CX("<div id='pikchr-output'></div>"); |
| 508 | CX("<textarea class='hidden' id='pikchr-output-text'></textarea>"); |
| 509 | CX("</div>"); |
| 510 | } CX("</fieldset> <!-- .zone-wrapper.output -->"); |
| 511 | } CX("</div><!-- #main-wrapper -->"); |
| 512 | } CX("</div><!-- #view-split -->"); |
| 513 | builtin_fossil_js_bundle_or("dom", "storage", "copybutton", NULL); |
| 514 | builtin_request_js("fossil.page.pikchrshowasm.js"); |
| 515 | builtin_fulfill_js_requests(); |
| 516 | style_finish_page(); |
| 517 | } |
| 518 | |
| 519 | |
| 520 | /* |
| 521 | ** COMMAND: pikchr* |
| 522 | ** |
| 523 | ** Usage: %fossil pikchr [options] ?INFILE? ?OUTFILE? |
| 524 |
+2
-2
| --- src/style.c | ||
| +++ src/style.c | ||
| @@ -901,11 +901,11 @@ | ||
| 901 | 901 | static void style_load_all_js_files(void){ |
| 902 | 902 | if( needHrefJs && g.perm.Hyperlink ){ |
| 903 | 903 | int nDelay = db_get_int("auto-hyperlink-delay",0); |
| 904 | 904 | int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0) |
| 905 | 905 | && sqlite3_strglob("*Android*",PD("HTTP_USER_AGENT","")); |
| 906 | - @ <script id='href-data' type='application/json'>\ | |
| 906 | + @ <script id='href-data' type='text/json'>\ | |
| 907 | 907 | @ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script> |
| 908 | 908 | } |
| 909 | 909 | @ <script nonce="%h(style_nonce())">/* style.c:%d(__LINE__) */ |
| 910 | 910 | @ function debugMsg(msg){ |
| 911 | 911 | @ var n = document.getElementById("debugMsg"); |
| @@ -1220,11 +1220,11 @@ | ||
| 1220 | 1220 | /* Render the script as plain-text for testing purposes, if the "test" |
| 1221 | 1221 | ** query parameter is present */ |
| 1222 | 1222 | cgi_set_content_type("text/plain"); |
| 1223 | 1223 | }else{ |
| 1224 | 1224 | /* Default behavior is to return javascript */ |
| 1225 | - cgi_set_content_type("application/javascript"); | |
| 1225 | + cgi_set_content_type("text/javascript"); | |
| 1226 | 1226 | } |
| 1227 | 1227 | style_init_th1_vars(0); |
| 1228 | 1228 | Th_Render(zScript?zScript:""); |
| 1229 | 1229 | } |
| 1230 | 1230 | |
| 1231 | 1231 | |
| 1232 | 1232 | ADDED src/style.pikchrshow.css |
| 1233 | 1233 | ADDED tools/emcc.sh.in |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -901,11 +901,11 @@ | |
| 901 | static void style_load_all_js_files(void){ |
| 902 | if( needHrefJs && g.perm.Hyperlink ){ |
| 903 | int nDelay = db_get_int("auto-hyperlink-delay",0); |
| 904 | int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0) |
| 905 | && sqlite3_strglob("*Android*",PD("HTTP_USER_AGENT","")); |
| 906 | @ <script id='href-data' type='application/json'>\ |
| 907 | @ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script> |
| 908 | } |
| 909 | @ <script nonce="%h(style_nonce())">/* style.c:%d(__LINE__) */ |
| 910 | @ function debugMsg(msg){ |
| 911 | @ var n = document.getElementById("debugMsg"); |
| @@ -1220,11 +1220,11 @@ | |
| 1220 | /* Render the script as plain-text for testing purposes, if the "test" |
| 1221 | ** query parameter is present */ |
| 1222 | cgi_set_content_type("text/plain"); |
| 1223 | }else{ |
| 1224 | /* Default behavior is to return javascript */ |
| 1225 | cgi_set_content_type("application/javascript"); |
| 1226 | } |
| 1227 | style_init_th1_vars(0); |
| 1228 | Th_Render(zScript?zScript:""); |
| 1229 | } |
| 1230 | |
| 1231 | |
| 1232 | DDED src/style.pikchrshow.css |
| 1233 | DDED tools/emcc.sh.in |
| --- src/style.c | |
| +++ src/style.c | |
| @@ -901,11 +901,11 @@ | |
| 901 | static void style_load_all_js_files(void){ |
| 902 | if( needHrefJs && g.perm.Hyperlink ){ |
| 903 | int nDelay = db_get_int("auto-hyperlink-delay",0); |
| 904 | int bMouseover = db_get_boolean("auto-hyperlink-mouseover",0) |
| 905 | && sqlite3_strglob("*Android*",PD("HTTP_USER_AGENT","")); |
| 906 | @ <script id='href-data' type='text/json'>\ |
| 907 | @ {"delay":%d(nDelay),"mouseover":%d(bMouseover)}</script> |
| 908 | } |
| 909 | @ <script nonce="%h(style_nonce())">/* style.c:%d(__LINE__) */ |
| 910 | @ function debugMsg(msg){ |
| 911 | @ var n = document.getElementById("debugMsg"); |
| @@ -1220,11 +1220,11 @@ | |
| 1220 | /* Render the script as plain-text for testing purposes, if the "test" |
| 1221 | ** query parameter is present */ |
| 1222 | cgi_set_content_type("text/plain"); |
| 1223 | }else{ |
| 1224 | /* Default behavior is to return javascript */ |
| 1225 | cgi_set_content_type("text/javascript"); |
| 1226 | } |
| 1227 | style_init_th1_vars(0); |
| 1228 | Th_Render(zScript?zScript:""); |
| 1229 | } |
| 1230 | |
| 1231 | |
| 1232 | DDED src/style.pikchrshow.css |
| 1233 | DDED tools/emcc.sh.in |
+64
| --- a/src/style.pikchrshow.css | ||
| +++ b/src/style.pikchrshow.css | ||
| @@ -0,0 +1,64 @@ | ||
| 1 | + during the module load/initialization processes... */ | |
| 2 | +.emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; } | |
| 3 | +div.emscripten { text-align: center; } | |
| 4 | +div.emscripten_border { border: 1px solid black; } | |
| 5 | +#module-spinner { overflow: visible; } | |
| 6 | +#module-spinner > * { | |
| 7 | + margin-top: 1em; | |
| 8 | +} | |
| 9 | +.spinner { | |
| 10 | + height: 50px; | |
| 11 | + width: 50px; | |
| 12 | + margin: 0px auto; | |
| 13 | + animation: rotation 0.8s linear infinite; | |
| 14 | + border-left: 10px solid rgb(0,150,240); | |
| 15 | + border-right: 10px solid rgb(0,150,240); | |
| 16 | + border-bottom: 10px solid rgb(0,150,240); | |
| 17 | + border-top: 10px solid rgb(100,0,200); | |
| 18 | + border-radius: 100%; | |
| 19 | + background-color: rgb(200,100,250); | |
| 20 | +} | |
| 21 | +@keyframes rotation { | |
| 22 | + from {transform: rotate(0deg);} | |
| 23 | + to {transform: rotate(360deg);} | |
| 24 | +} | |
| 25 | + | |
| 26 | +/* The following styles are for app-level use. */ | |
| 27 | +/* TODO: consolidate the WASM- and legacy-mode CSS into this file. | |
| 28 | + Since both versions of /pikchrshow share a URI, they both load this | |
| 29 | + file. */theytextarea { | |
| 30 | + font-family: monospawrapper { | |
| 31 | + display: flex; | |
| 32 | + flex-direction: column-reverse; | |
| 33 | + flex: 1 1 auto; | |
| 34 | + margin: 0.5em 0; | |
| 35 | + overflow: hidden; | |
| 36 | +} | |
| 37 | +#main-wrapper.side-by-side { | |
| 38 | + flex-direction: row; | |
| 39 | +} | |
| 40 | +#main-wrapper.side-by-side > fieldset { | |
| 41 | + margin-left: 0.25em; | |
| 42 | + margin-right: 0.25em; | |
| 43 | +} | |
| 44 | +#main-wrapper:not(.side-by-side) > fieldset { | |
| 45 | + margin-bottom: 0.25em; | |
| 46 | +} | |
| 47 | +#main-wrapper.swapio { | |
| 48 | + flex-direction: column; | |
| 49 | +} | |
| 50 | +#main-wrapper.side-by-side.swapio { | |
| 51 | + flex-direction: row-reverse; | |
| 52 | +} | |
| 53 | +.zone-wrapper{ | |
| 54 | + display: flex; | |
| 55 | + margin: 0; | |
| 56 | + flex: 1 1 0%; | |
| 57 | + border-rad#main-wrapper .splitter-ha 1px outsetR@vq,T@JC,V:.splitter-handle { | |
| 58 | + width: 2pxH@K0,13::not(.side-by-side) .splitter-handle { | |
| 59 | + width: 100%; | |
| 60 | + height: 2px3u@OQ,M@pR,Y@aB,2:0%R@jE,T@JC,IS@TJ,2:/*H@ZW,c@l0,2:*/T@mb,2T:-top: 0.1em/*avoid crowding if the controls wrap*/; | |
| 61 | + vertical-align: middle; | |
| 62 | +} | |
| 63 | +.button-bar > * + * /*all children except the first*/ { | |
| 64 | + margin-left: 0.65em3U@o0,V:options > legend > #btn-optionsV@tt,4:hideS@uR,n:fieldset.options.collapsed > legend > #btn-options~@tt,7B@ur,Rr7eC; |
| --- a/src/style.pikchrshow.css | |
| +++ b/src/style.pikchrshow.css | |
| @@ -0,0 +1,64 @@ | |
| --- a/src/style.pikchrshow.css | |
| +++ b/src/style.pikchrshow.css | |
| @@ -0,0 +1,64 @@ | |
| 1 | during the module load/initialization processes... */ |
| 2 | .emscripten { padding-right: 0; margin-left: auto; margin-right: auto; display: block; } |
| 3 | div.emscripten { text-align: center; } |
| 4 | div.emscripten_border { border: 1px solid black; } |
| 5 | #module-spinner { overflow: visible; } |
| 6 | #module-spinner > * { |
| 7 | margin-top: 1em; |
| 8 | } |
| 9 | .spinner { |
| 10 | height: 50px; |
| 11 | width: 50px; |
| 12 | margin: 0px auto; |
| 13 | animation: rotation 0.8s linear infinite; |
| 14 | border-left: 10px solid rgb(0,150,240); |
| 15 | border-right: 10px solid rgb(0,150,240); |
| 16 | border-bottom: 10px solid rgb(0,150,240); |
| 17 | border-top: 10px solid rgb(100,0,200); |
| 18 | border-radius: 100%; |
| 19 | background-color: rgb(200,100,250); |
| 20 | } |
| 21 | @keyframes rotation { |
| 22 | from {transform: rotate(0deg);} |
| 23 | to {transform: rotate(360deg);} |
| 24 | } |
| 25 | |
| 26 | /* The following styles are for app-level use. */ |
| 27 | /* TODO: consolidate the WASM- and legacy-mode CSS into this file. |
| 28 | Since both versions of /pikchrshow share a URI, they both load this |
| 29 | file. */theytextarea { |
| 30 | font-family: monospawrapper { |
| 31 | display: flex; |
| 32 | flex-direction: column-reverse; |
| 33 | flex: 1 1 auto; |
| 34 | margin: 0.5em 0; |
| 35 | overflow: hidden; |
| 36 | } |
| 37 | #main-wrapper.side-by-side { |
| 38 | flex-direction: row; |
| 39 | } |
| 40 | #main-wrapper.side-by-side > fieldset { |
| 41 | margin-left: 0.25em; |
| 42 | margin-right: 0.25em; |
| 43 | } |
| 44 | #main-wrapper:not(.side-by-side) > fieldset { |
| 45 | margin-bottom: 0.25em; |
| 46 | } |
| 47 | #main-wrapper.swapio { |
| 48 | flex-direction: column; |
| 49 | } |
| 50 | #main-wrapper.side-by-side.swapio { |
| 51 | flex-direction: row-reverse; |
| 52 | } |
| 53 | .zone-wrapper{ |
| 54 | display: flex; |
| 55 | margin: 0; |
| 56 | flex: 1 1 0%; |
| 57 | border-rad#main-wrapper .splitter-ha 1px outsetR@vq,T@JC,V:.splitter-handle { |
| 58 | width: 2pxH@K0,13::not(.side-by-side) .splitter-handle { |
| 59 | width: 100%; |
| 60 | height: 2px3u@OQ,M@pR,Y@aB,2:0%R@jE,T@JC,IS@TJ,2:/*H@ZW,c@l0,2:*/T@mb,2T:-top: 0.1em/*avoid crowding if the controls wrap*/; |
| 61 | vertical-align: middle; |
| 62 | } |
| 63 | .button-bar > * + * /*all children except the first*/ { |
| 64 | margin-left: 0.65em3U@o0,V:options > legend > #btn-optionsV@tt,4:hideS@uR,n:fieldset.options.collapsed > legend > #btn-options~@tt,7B@ur,Rr7eC; |
+65
| --- a/tools/emcc.sh.in | ||
| +++ b/tools/emcc.sh.in | ||
| @@ -0,0 +1,65 @@ | ||
| 1 | +#!/usr/bin/bash | |
| 2 | +############################################# | |
| 3 | +# WARNING: emcc.sh is generated from emcc.sh.in by the configure | |
| 4 | +# process. Do not edit emcc.sh directly, as it may be deleted or | |
| 5 | +# overwritten by the configure script. | |
| 6 | +# | |
| 7 | +# A wrapper around the emcc compiler which uses configure-time state | |
| 8 | +# to locate the Emscripten SDK and import the SDK's environment | |
| 9 | +# script, if needed. | |
| 10 | +######################################################################## | |
| 11 | +# EMSDK_HOME comes from the configure --with-emsdk=/dir flag. | |
| 12 | +# EMSDK_ENVk=/dir flag. | |
| 13 | +# EMSDK_ENV_SH is ${thatDir}/emsdk_env.sh and is also set by the | |
| 14 | +# ="@EMSDK_ENV@" | |
| 15 | + | |
| 16 | +emc`which emcc 2>/dev/null` | |
| 17 | +fi | |
| 18 | + | |
| 19 | +if [ x = "x${emcc}" ]; then | |
| 20 | + # If emcc is not found in the path, try to find it via an emsdk | |
| 21 | + # installation. The SDK variant i | |
| 22 | + # style^^^^ Please try to keep this #!/bin/sh | |
| 23 | + emcc is also available | |
| 24 | + # via package managers on some OSes. | |
| 25 | + if [ x = "x${EMSDK_HOME}" ]; then | |
| 26 | + echo "EMSDK_HOME is not set. Pass --with-emsdk=/path/to/emsdk" \ | |
| 27 | + "to the configure script." 1>&2 | |
| 28 | + exit 1 | |
| 29 | + fi | |
| 30 | + | |
| 31 | + if [ x = "x${EMSDK_ENV_SH}" ]; then | |
| 32 | + if [ -f "${EMSDK_HOME}/emsdk_env.sh" ]; then | |
| 33 | + EMSDK_ENV_SH="${EMSDK_HOME}/emsdk_env.sh" | |
| 34 | + else | |
| 35 | + echo "EMSDK_ENV_SH is not set. Expecting configure script to set it." 1>&2 | |
| 36 | + exit 2 | |
| 37 | + fi | |
| 38 | + fi | |
| 39 | + | |
| 40 | + if [ ! -f "${EMSDK_ENV_SH}" ]; then | |
| 41 | + echo "emsdk_env script not found: $EMSDK_ENV_SH" 1>&2 | |
| 42 | + exit 3 | |
| 43 | + fi | |
| 44 | + | |
| 45 | + # $EMSDK is part of the state set by emsdk_env.sh. | |
| 46 | + if [ x = "x${EMSDK}" ]; then | |
| 47 | + EMSDK_QUIET=1 | |
| 48 | + export EMSDK_QUIET | |
| 49 | + # ^^^ Squelches informational output from ${EMSDK_ENV_SH}. | |
| 50 | + source "${EMSDK_ENV_SH}" || { | |
| 51 | + rc=$? | |
| 52 | + echo "Error sourcing ${EMSDK_ENV_SH}" | |
| 53 | + exit $rc | |
| 54 | + } | |
| 55 | + fi | |
| 56 | + emcc=`which emcc 2>/dev/null` | |
| 57 | + if [ x = "x${emcc}" ]; then | |
| 58 | + echo "emcc not found in PATH. Normally that's set up by ${EMSDK_ENV_SH}." 1>&2 | |
| 59 | + exit 4 | |
| 60 | + fi | |
| 61 | +fi | |
| 62 | + | |
| 63 | +exec $emcc "$@" | |
| 64 | +}" ]; then | |
| 65 | + emcc "$@" |
| --- a/tools/emcc.sh.in | |
| +++ b/tools/emcc.sh.in | |
| @@ -0,0 +1,65 @@ | |
| --- a/tools/emcc.sh.in | |
| +++ b/tools/emcc.sh.in | |
| @@ -0,0 +1,65 @@ | |
| 1 | #!/usr/bin/bash |
| 2 | ############################################# |
| 3 | # WARNING: emcc.sh is generated from emcc.sh.in by the configure |
| 4 | # process. Do not edit emcc.sh directly, as it may be deleted or |
| 5 | # overwritten by the configure script. |
| 6 | # |
| 7 | # A wrapper around the emcc compiler which uses configure-time state |
| 8 | # to locate the Emscripten SDK and import the SDK's environment |
| 9 | # script, if needed. |
| 10 | ######################################################################## |
| 11 | # EMSDK_HOME comes from the configure --with-emsdk=/dir flag. |
| 12 | # EMSDK_ENVk=/dir flag. |
| 13 | # EMSDK_ENV_SH is ${thatDir}/emsdk_env.sh and is also set by the |
| 14 | # ="@EMSDK_ENV@" |
| 15 | |
| 16 | emc`which emcc 2>/dev/null` |
| 17 | fi |
| 18 | |
| 19 | if [ x = "x${emcc}" ]; then |
| 20 | # If emcc is not found in the path, try to find it via an emsdk |
| 21 | # installation. The SDK variant i |
| 22 | # style^^^^ Please try to keep this #!/bin/sh |
| 23 | emcc is also available |
| 24 | # via package managers on some OSes. |
| 25 | if [ x = "x${EMSDK_HOME}" ]; then |
| 26 | echo "EMSDK_HOME is not set. Pass --with-emsdk=/path/to/emsdk" \ |
| 27 | "to the configure script." 1>&2 |
| 28 | exit 1 |
| 29 | fi |
| 30 | |
| 31 | if [ x = "x${EMSDK_ENV_SH}" ]; then |
| 32 | if [ -f "${EMSDK_HOME}/emsdk_env.sh" ]; then |
| 33 | EMSDK_ENV_SH="${EMSDK_HOME}/emsdk_env.sh" |
| 34 | else |
| 35 | echo "EMSDK_ENV_SH is not set. Expecting configure script to set it." 1>&2 |
| 36 | exit 2 |
| 37 | fi |
| 38 | fi |
| 39 | |
| 40 | if [ ! -f "${EMSDK_ENV_SH}" ]; then |
| 41 | echo "emsdk_env script not found: $EMSDK_ENV_SH" 1>&2 |
| 42 | exit 3 |
| 43 | fi |
| 44 | |
| 45 | # $EMSDK is part of the state set by emsdk_env.sh. |
| 46 | if [ x = "x${EMSDK}" ]; then |
| 47 | EMSDK_QUIET=1 |
| 48 | export EMSDK_QUIET |
| 49 | # ^^^ Squelches informational output from ${EMSDK_ENV_SH}. |
| 50 | source "${EMSDK_ENV_SH}" || { |
| 51 | rc=$? |
| 52 | echo "Error sourcing ${EMSDK_ENV_SH}" |
| 53 | exit $rc |
| 54 | } |
| 55 | fi |
| 56 | emcc=`which emcc 2>/dev/null` |
| 57 | if [ x = "x${emcc}" ]; then |
| 58 | echo "emcc not found in PATH. Normally that's set up by ${EMSDK_ENV_SH}." 1>&2 |
| 59 | exit 4 |
| 60 | fi |
| 61 | fi |
| 62 | |
| 63 | exec $emcc "$@" |
| 64 | }" ]; then |
| 65 | emcc "$@" |
+14
-1
| --- tools/makemake.tcl | ||
| +++ tools/makemake.tcl | ||
| @@ -217,10 +217,12 @@ | ||
| 217 | 217 | default.css |
| 218 | 218 | style.*.css |
| 219 | 219 | ../skins/*/*.txt |
| 220 | 220 | sounds/*.wav |
| 221 | 221 | alerts/*.wav |
| 222 | + ../extsrc/pikchr.wasm | |
| 223 | + ../extsrc/pikchr*.js | |
| 222 | 224 | } |
| 223 | 225 | |
| 224 | 226 | # Options used to compile the included SQLite library. |
| 225 | 227 | # |
| 226 | 228 | set SQLITE_OPTIONS { |
| @@ -559,10 +561,21 @@ | ||
| 559 | 561 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 560 | 562 | |
| 561 | 563 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 562 | 564 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 563 | 565 | |
| 566 | +$(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c | |
| 567 | + $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \ | |
| 568 | + -sEXPORTED_RUNTIME_METHODS=cwrap,setValue,getValue,stackSave,stackRestore \ | |
| 569 | + -sEXPORTED_FUNCTIONS=_pikchr $(SRCDIR_extsrc)/pikchr.c \ | |
| 570 | + -sENVIRONMENT=web \ | |
| 571 | + -sMODULARIZE \ | |
| 572 | + -sEXPORT_NAME=initPikchrModule \ | |
| 573 | + --minify 0 | |
| 574 | + @chmod -x $(SRCDIR_extsrc)/pikchr.wasm | |
| 575 | +wasm: $(SRCDIR_extsrc)/pikchr.js | |
| 576 | + | |
| 564 | 577 | # |
| 565 | 578 | # The list of all the targets that do not correspond to real files. This stops |
| 566 | 579 | # 'make' from getting confused when someone makes an error in a rule. |
| 567 | 580 | # |
| 568 | 581 | |
| @@ -637,11 +650,11 @@ | ||
| 637 | 650 | |
| 638 | 651 | #### Enable compiling with debug symbols (much larger binary) |
| 639 | 652 | # |
| 640 | 653 | # FOSSIL_ENABLE_SYMBOLS = 1 |
| 641 | 654 | |
| 642 | -#### Enable JSON (http://www.json.org) support using "cson" | |
| 655 | +#### Enable JSON (https://www.json.org) support using "cson" | |
| 643 | 656 | # |
| 644 | 657 | # FOSSIL_ENABLE_JSON = 1 |
| 645 | 658 | |
| 646 | 659 | #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) |
| 647 | 660 | # |
| 648 | 661 |
| --- tools/makemake.tcl | |
| +++ tools/makemake.tcl | |
| @@ -217,10 +217,12 @@ | |
| 217 | default.css |
| 218 | style.*.css |
| 219 | ../skins/*/*.txt |
| 220 | sounds/*.wav |
| 221 | alerts/*.wav |
| 222 | } |
| 223 | |
| 224 | # Options used to compile the included SQLite library. |
| 225 | # |
| 226 | set SQLITE_OPTIONS { |
| @@ -559,10 +561,21 @@ | |
| 559 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 560 | |
| 561 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 562 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 563 | |
| 564 | # |
| 565 | # The list of all the targets that do not correspond to real files. This stops |
| 566 | # 'make' from getting confused when someone makes an error in a rule. |
| 567 | # |
| 568 | |
| @@ -637,11 +650,11 @@ | |
| 637 | |
| 638 | #### Enable compiling with debug symbols (much larger binary) |
| 639 | # |
| 640 | # FOSSIL_ENABLE_SYMBOLS = 1 |
| 641 | |
| 642 | #### Enable JSON (http://www.json.org) support using "cson" |
| 643 | # |
| 644 | # FOSSIL_ENABLE_JSON = 1 |
| 645 | |
| 646 | #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) |
| 647 | # |
| 648 |
| --- tools/makemake.tcl | |
| +++ tools/makemake.tcl | |
| @@ -217,10 +217,12 @@ | |
| 217 | default.css |
| 218 | style.*.css |
| 219 | ../skins/*/*.txt |
| 220 | sounds/*.wav |
| 221 | alerts/*.wav |
| 222 | ../extsrc/pikchr.wasm |
| 223 | ../extsrc/pikchr*.js |
| 224 | } |
| 225 | |
| 226 | # Options used to compile the included SQLite library. |
| 227 | # |
| 228 | set SQLITE_OPTIONS { |
| @@ -559,10 +561,21 @@ | |
| 561 | $(XTCC) $(PIKCHR_OPTIONS) -c $(SRCDIR_extsrc)/pikchr.c -o $@ |
| 562 | |
| 563 | $(OBJDIR)/cson_amalgamation.o: $(SRCDIR_extsrc)/cson_amalgamation.c |
| 564 | $(XTCC) -c $(SRCDIR_extsrc)/cson_amalgamation.c -o $@ |
| 565 | |
| 566 | $(SRCDIR_extsrc)/pikchr.js: $(SRCDIR_extsrc)/pikchr.c |
| 567 | $(EMCC_WRAPPER) -o $@ $(EMCC_OPT) --no-entry \ |
| 568 | -sEXPORTED_RUNTIME_METHODS=cwrap,setValue,getValue,stackSave,stackRestore \ |
| 569 | -sEXPORTED_FUNCTIONS=_pikchr $(SRCDIR_extsrc)/pikchr.c \ |
| 570 | -sENVIRONMENT=web \ |
| 571 | -sMODULARIZE \ |
| 572 | -sEXPORT_NAME=initPikchrModule \ |
| 573 | --minify 0 |
| 574 | @chmod -x $(SRCDIR_extsrc)/pikchr.wasm |
| 575 | wasm: $(SRCDIR_extsrc)/pikchr.js |
| 576 | |
| 577 | # |
| 578 | # The list of all the targets that do not correspond to real files. This stops |
| 579 | # 'make' from getting confused when someone makes an error in a rule. |
| 580 | # |
| 581 | |
| @@ -637,11 +650,11 @@ | |
| 650 | |
| 651 | #### Enable compiling with debug symbols (much larger binary) |
| 652 | # |
| 653 | # FOSSIL_ENABLE_SYMBOLS = 1 |
| 654 | |
| 655 | #### Enable JSON (https://www.json.org) support using "cson" |
| 656 | # |
| 657 | # FOSSIL_ENABLE_JSON = 1 |
| 658 | |
| 659 | #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) |
| 660 | # |
| 661 |
+6
-1
| --- win/Makefile.mingw | ||
| +++ win/Makefile.mingw | ||
| @@ -54,11 +54,11 @@ | ||
| 54 | 54 | |
| 55 | 55 | #### Enable compiling with debug symbols (much larger binary) |
| 56 | 56 | # |
| 57 | 57 | # FOSSIL_ENABLE_SYMBOLS = 1 |
| 58 | 58 | |
| 59 | -#### Enable JSON (http://www.json.org) support using "cson" | |
| 59 | +#### Enable JSON (https://www.json.org) support using "cson" | |
| 60 | 60 | # |
| 61 | 61 | # FOSSIL_ENABLE_JSON = 1 |
| 62 | 62 | |
| 63 | 63 | #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) |
| 64 | 64 | # |
| @@ -549,10 +549,13 @@ | ||
| 549 | 549 | $(SRCDIR)/xfer.c \ |
| 550 | 550 | $(SRCDIR)/xfersetup.c \ |
| 551 | 551 | $(SRCDIR)/zip.c |
| 552 | 552 | |
| 553 | 553 | EXTRA_FILES = \ |
| 554 | + $(SRCDIR)/../extsrc/pikchr-worker.js \ | |
| 555 | + $(SRCDIR)/../extsrc/pikchr.js \ | |
| 556 | + $(SRCDIR)/../extsrc/pikchr.wasm \ | |
| 554 | 557 | $(SRCDIR)/../skins/ardoise/css.txt \ |
| 555 | 558 | $(SRCDIR)/../skins/ardoise/details.txt \ |
| 556 | 559 | $(SRCDIR)/../skins/ardoise/footer.txt \ |
| 557 | 560 | $(SRCDIR)/../skins/ardoise/header.txt \ |
| 558 | 561 | $(SRCDIR)/../skins/black_and_white/css.txt \ |
| @@ -617,10 +620,11 @@ | ||
| 617 | 620 | $(SRCDIR)/fossil.page.brlist.js \ |
| 618 | 621 | $(SRCDIR)/fossil.page.chat.js \ |
| 619 | 622 | $(SRCDIR)/fossil.page.fileedit.js \ |
| 620 | 623 | $(SRCDIR)/fossil.page.forumpost.js \ |
| 621 | 624 | $(SRCDIR)/fossil.page.pikchrshow.js \ |
| 625 | + $(SRCDIR)/fossil.page.pikchrshowasm.js \ | |
| 622 | 626 | $(SRCDIR)/fossil.page.whistory.js \ |
| 623 | 627 | $(SRCDIR)/fossil.page.wikiedit.js \ |
| 624 | 628 | $(SRCDIR)/fossil.pikchr.js \ |
| 625 | 629 | $(SRCDIR)/fossil.popupwidget.js \ |
| 626 | 630 | $(SRCDIR)/fossil.storage.js \ |
| @@ -652,10 +656,11 @@ | ||
| 652 | 656 | $(SRCDIR)/sounds/e.wav \ |
| 653 | 657 | $(SRCDIR)/sounds/f.wav \ |
| 654 | 658 | $(SRCDIR)/style.admin_log.css \ |
| 655 | 659 | $(SRCDIR)/style.chat.css \ |
| 656 | 660 | $(SRCDIR)/style.fileedit.css \ |
| 661 | + $(SRCDIR)/style.pikchrshow.css \ | |
| 657 | 662 | $(SRCDIR)/style.wikiedit.css \ |
| 658 | 663 | $(SRCDIR)/tree.js \ |
| 659 | 664 | $(SRCDIR)/useredit.js \ |
| 660 | 665 | $(SRCDIR)/wiki.wiki |
| 661 | 666 | |
| 662 | 667 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -54,11 +54,11 @@ | |
| 54 | |
| 55 | #### Enable compiling with debug symbols (much larger binary) |
| 56 | # |
| 57 | # FOSSIL_ENABLE_SYMBOLS = 1 |
| 58 | |
| 59 | #### Enable JSON (http://www.json.org) support using "cson" |
| 60 | # |
| 61 | # FOSSIL_ENABLE_JSON = 1 |
| 62 | |
| 63 | #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) |
| 64 | # |
| @@ -549,10 +549,13 @@ | |
| 549 | $(SRCDIR)/xfer.c \ |
| 550 | $(SRCDIR)/xfersetup.c \ |
| 551 | $(SRCDIR)/zip.c |
| 552 | |
| 553 | EXTRA_FILES = \ |
| 554 | $(SRCDIR)/../skins/ardoise/css.txt \ |
| 555 | $(SRCDIR)/../skins/ardoise/details.txt \ |
| 556 | $(SRCDIR)/../skins/ardoise/footer.txt \ |
| 557 | $(SRCDIR)/../skins/ardoise/header.txt \ |
| 558 | $(SRCDIR)/../skins/black_and_white/css.txt \ |
| @@ -617,10 +620,11 @@ | |
| 617 | $(SRCDIR)/fossil.page.brlist.js \ |
| 618 | $(SRCDIR)/fossil.page.chat.js \ |
| 619 | $(SRCDIR)/fossil.page.fileedit.js \ |
| 620 | $(SRCDIR)/fossil.page.forumpost.js \ |
| 621 | $(SRCDIR)/fossil.page.pikchrshow.js \ |
| 622 | $(SRCDIR)/fossil.page.whistory.js \ |
| 623 | $(SRCDIR)/fossil.page.wikiedit.js \ |
| 624 | $(SRCDIR)/fossil.pikchr.js \ |
| 625 | $(SRCDIR)/fossil.popupwidget.js \ |
| 626 | $(SRCDIR)/fossil.storage.js \ |
| @@ -652,10 +656,11 @@ | |
| 652 | $(SRCDIR)/sounds/e.wav \ |
| 653 | $(SRCDIR)/sounds/f.wav \ |
| 654 | $(SRCDIR)/style.admin_log.css \ |
| 655 | $(SRCDIR)/style.chat.css \ |
| 656 | $(SRCDIR)/style.fileedit.css \ |
| 657 | $(SRCDIR)/style.wikiedit.css \ |
| 658 | $(SRCDIR)/tree.js \ |
| 659 | $(SRCDIR)/useredit.js \ |
| 660 | $(SRCDIR)/wiki.wiki |
| 661 | |
| 662 |
| --- win/Makefile.mingw | |
| +++ win/Makefile.mingw | |
| @@ -54,11 +54,11 @@ | |
| 54 | |
| 55 | #### Enable compiling with debug symbols (much larger binary) |
| 56 | # |
| 57 | # FOSSIL_ENABLE_SYMBOLS = 1 |
| 58 | |
| 59 | #### Enable JSON (https://www.json.org) support using "cson" |
| 60 | # |
| 61 | # FOSSIL_ENABLE_JSON = 1 |
| 62 | |
| 63 | #### Enable HTTPS support via OpenSSL (links to libssl and libcrypto) |
| 64 | # |
| @@ -549,10 +549,13 @@ | |
| 549 | $(SRCDIR)/xfer.c \ |
| 550 | $(SRCDIR)/xfersetup.c \ |
| 551 | $(SRCDIR)/zip.c |
| 552 | |
| 553 | EXTRA_FILES = \ |
| 554 | $(SRCDIR)/../extsrc/pikchr-worker.js \ |
| 555 | $(SRCDIR)/../extsrc/pikchr.js \ |
| 556 | $(SRCDIR)/../extsrc/pikchr.wasm \ |
| 557 | $(SRCDIR)/../skins/ardoise/css.txt \ |
| 558 | $(SRCDIR)/../skins/ardoise/details.txt \ |
| 559 | $(SRCDIR)/../skins/ardoise/footer.txt \ |
| 560 | $(SRCDIR)/../skins/ardoise/header.txt \ |
| 561 | $(SRCDIR)/../skins/black_and_white/css.txt \ |
| @@ -617,10 +620,11 @@ | |
| 620 | $(SRCDIR)/fossil.page.brlist.js \ |
| 621 | $(SRCDIR)/fossil.page.chat.js \ |
| 622 | $(SRCDIR)/fossil.page.fileedit.js \ |
| 623 | $(SRCDIR)/fossil.page.forumpost.js \ |
| 624 | $(SRCDIR)/fossil.page.pikchrshow.js \ |
| 625 | $(SRCDIR)/fossil.page.pikchrshowasm.js \ |
| 626 | $(SRCDIR)/fossil.page.whistory.js \ |
| 627 | $(SRCDIR)/fossil.page.wikiedit.js \ |
| 628 | $(SRCDIR)/fossil.pikchr.js \ |
| 629 | $(SRCDIR)/fossil.popupwidget.js \ |
| 630 | $(SRCDIR)/fossil.storage.js \ |
| @@ -652,10 +656,11 @@ | |
| 656 | $(SRCDIR)/sounds/e.wav \ |
| 657 | $(SRCDIR)/sounds/f.wav \ |
| 658 | $(SRCDIR)/style.admin_log.css \ |
| 659 | $(SRCDIR)/style.chat.css \ |
| 660 | $(SRCDIR)/style.fileedit.css \ |
| 661 | $(SRCDIR)/style.pikchrshow.css \ |
| 662 | $(SRCDIR)/style.wikiedit.css \ |
| 663 | $(SRCDIR)/tree.js \ |
| 664 | $(SRCDIR)/useredit.js \ |
| 665 | $(SRCDIR)/wiki.wiki |
| 666 | |
| 667 |
+12
-2
| --- win/Makefile.msc | ||
| +++ win/Makefile.msc | ||
| @@ -505,11 +505,14 @@ | ||
| 505 | 505 | "$(OX)\xfer_.c" \ |
| 506 | 506 | "$(OX)\xfersetup_.c" \ |
| 507 | 507 | "$(OX)\zip_.c" \ |
| 508 | 508 | "$(SRCDIR_extsrc)\pikchr.c" |
| 509 | 509 | |
| 510 | -EXTRA_FILES = "$(SRCDIR)\..\skins\ardoise\css.txt" \ | |
| 510 | +EXTRA_FILES = "$(SRCDIR)\..\extsrc\pikchr-worker.js" \ | |
| 511 | + "$(SRCDIR)\..\extsrc\pikchr.js" \ | |
| 512 | + "$(SRCDIR)\..\extsrc\pikchr.wasm" \ | |
| 513 | + "$(SRCDIR)\..\skins\ardoise\css.txt" \ | |
| 511 | 514 | "$(SRCDIR)\..\skins\ardoise\details.txt" \ |
| 512 | 515 | "$(SRCDIR)\..\skins\ardoise\footer.txt" \ |
| 513 | 516 | "$(SRCDIR)\..\skins\ardoise\header.txt" \ |
| 514 | 517 | "$(SRCDIR)\..\skins\black_and_white\css.txt" \ |
| 515 | 518 | "$(SRCDIR)\..\skins\black_and_white\details.txt" \ |
| @@ -573,10 +576,11 @@ | ||
| 573 | 576 | "$(SRCDIR)\fossil.page.brlist.js" \ |
| 574 | 577 | "$(SRCDIR)\fossil.page.chat.js" \ |
| 575 | 578 | "$(SRCDIR)\fossil.page.fileedit.js" \ |
| 576 | 579 | "$(SRCDIR)\fossil.page.forumpost.js" \ |
| 577 | 580 | "$(SRCDIR)\fossil.page.pikchrshow.js" \ |
| 581 | + "$(SRCDIR)\fossil.page.pikchrshowasm.js" \ | |
| 578 | 582 | "$(SRCDIR)\fossil.page.whistory.js" \ |
| 579 | 583 | "$(SRCDIR)\fossil.page.wikiedit.js" \ |
| 580 | 584 | "$(SRCDIR)\fossil.pikchr.js" \ |
| 581 | 585 | "$(SRCDIR)\fossil.popupwidget.js" \ |
| 582 | 586 | "$(SRCDIR)\fossil.storage.js" \ |
| @@ -608,10 +612,11 @@ | ||
| 608 | 612 | "$(SRCDIR)\sounds\e.wav" \ |
| 609 | 613 | "$(SRCDIR)\sounds\f.wav" \ |
| 610 | 614 | "$(SRCDIR)\style.admin_log.css" \ |
| 611 | 615 | "$(SRCDIR)\style.chat.css" \ |
| 612 | 616 | "$(SRCDIR)\style.fileedit.css" \ |
| 617 | + "$(SRCDIR)\style.pikchrshow.css" \ | |
| 613 | 618 | "$(SRCDIR)\style.wikiedit.css" \ |
| 614 | 619 | "$(SRCDIR)\tree.js" \ |
| 615 | 620 | "$(SRCDIR)\useredit.js" \ |
| 616 | 621 | "$(SRCDIR)\wiki.wiki" |
| 617 | 622 | |
| @@ -1129,11 +1134,14 @@ | ||
| 1129 | 1134 | "$(OBJDIR)\json_timeline$O" : "$(SRCDIR)\json_detail.h" |
| 1130 | 1135 | "$(OBJDIR)\json_user$O" : "$(SRCDIR)\json_detail.h" |
| 1131 | 1136 | "$(OBJDIR)\json_wiki$O" : "$(SRCDIR)\json_detail.h" |
| 1132 | 1137 | |
| 1133 | 1138 | "$(OX)\builtin_data.reslist": $(EXTRA_FILES) "$(B)\win\Makefile.msc" |
| 1134 | - echo "$(SRCDIR)\../skins/ardoise/css.txt" > $@ | |
| 1139 | + echo "$(SRCDIR)\../extsrc/pikchr-worker.js" > $@ | |
| 1140 | + echo "$(SRCDIR)\../extsrc/pikchr.js" >> $@ | |
| 1141 | + echo "$(SRCDIR)\../extsrc/pikchr.wasm" >> $@ | |
| 1142 | + echo "$(SRCDIR)\../skins/ardoise/css.txt" >> $@ | |
| 1135 | 1143 | echo "$(SRCDIR)\../skins/ardoise/details.txt" >> $@ |
| 1136 | 1144 | echo "$(SRCDIR)\../skins/ardoise/footer.txt" >> $@ |
| 1137 | 1145 | echo "$(SRCDIR)\../skins/ardoise/header.txt" >> $@ |
| 1138 | 1146 | echo "$(SRCDIR)\../skins/black_and_white/css.txt" >> $@ |
| 1139 | 1147 | echo "$(SRCDIR)\../skins/black_and_white/details.txt" >> $@ |
| @@ -1197,10 +1205,11 @@ | ||
| 1197 | 1205 | echo "$(SRCDIR)\fossil.page.brlist.js" >> $@ |
| 1198 | 1206 | echo "$(SRCDIR)\fossil.page.chat.js" >> $@ |
| 1199 | 1207 | echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@ |
| 1200 | 1208 | echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@ |
| 1201 | 1209 | echo "$(SRCDIR)\fossil.page.pikchrshow.js" >> $@ |
| 1210 | + echo "$(SRCDIR)\fossil.page.pikchrshowasm.js" >> $@ | |
| 1202 | 1211 | echo "$(SRCDIR)\fossil.page.whistory.js" >> $@ |
| 1203 | 1212 | echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@ |
| 1204 | 1213 | echo "$(SRCDIR)\fossil.pikchr.js" >> $@ |
| 1205 | 1214 | echo "$(SRCDIR)\fossil.popupwidget.js" >> $@ |
| 1206 | 1215 | echo "$(SRCDIR)\fossil.storage.js" >> $@ |
| @@ -1232,10 +1241,11 @@ | ||
| 1232 | 1241 | echo "$(SRCDIR)\sounds/e.wav" >> $@ |
| 1233 | 1242 | echo "$(SRCDIR)\sounds/f.wav" >> $@ |
| 1234 | 1243 | echo "$(SRCDIR)\style.admin_log.css" >> $@ |
| 1235 | 1244 | echo "$(SRCDIR)\style.chat.css" >> $@ |
| 1236 | 1245 | echo "$(SRCDIR)\style.fileedit.css" >> $@ |
| 1246 | + echo "$(SRCDIR)\style.pikchrshow.css" >> $@ | |
| 1237 | 1247 | echo "$(SRCDIR)\style.wikiedit.css" >> $@ |
| 1238 | 1248 | echo "$(SRCDIR)\tree.js" >> $@ |
| 1239 | 1249 | echo "$(SRCDIR)\useredit.js" >> $@ |
| 1240 | 1250 | echo "$(SRCDIR)\wiki.wiki" >> $@ |
| 1241 | 1251 | |
| 1242 | 1252 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -505,11 +505,14 @@ | |
| 505 | "$(OX)\xfer_.c" \ |
| 506 | "$(OX)\xfersetup_.c" \ |
| 507 | "$(OX)\zip_.c" \ |
| 508 | "$(SRCDIR_extsrc)\pikchr.c" |
| 509 | |
| 510 | EXTRA_FILES = "$(SRCDIR)\..\skins\ardoise\css.txt" \ |
| 511 | "$(SRCDIR)\..\skins\ardoise\details.txt" \ |
| 512 | "$(SRCDIR)\..\skins\ardoise\footer.txt" \ |
| 513 | "$(SRCDIR)\..\skins\ardoise\header.txt" \ |
| 514 | "$(SRCDIR)\..\skins\black_and_white\css.txt" \ |
| 515 | "$(SRCDIR)\..\skins\black_and_white\details.txt" \ |
| @@ -573,10 +576,11 @@ | |
| 573 | "$(SRCDIR)\fossil.page.brlist.js" \ |
| 574 | "$(SRCDIR)\fossil.page.chat.js" \ |
| 575 | "$(SRCDIR)\fossil.page.fileedit.js" \ |
| 576 | "$(SRCDIR)\fossil.page.forumpost.js" \ |
| 577 | "$(SRCDIR)\fossil.page.pikchrshow.js" \ |
| 578 | "$(SRCDIR)\fossil.page.whistory.js" \ |
| 579 | "$(SRCDIR)\fossil.page.wikiedit.js" \ |
| 580 | "$(SRCDIR)\fossil.pikchr.js" \ |
| 581 | "$(SRCDIR)\fossil.popupwidget.js" \ |
| 582 | "$(SRCDIR)\fossil.storage.js" \ |
| @@ -608,10 +612,11 @@ | |
| 608 | "$(SRCDIR)\sounds\e.wav" \ |
| 609 | "$(SRCDIR)\sounds\f.wav" \ |
| 610 | "$(SRCDIR)\style.admin_log.css" \ |
| 611 | "$(SRCDIR)\style.chat.css" \ |
| 612 | "$(SRCDIR)\style.fileedit.css" \ |
| 613 | "$(SRCDIR)\style.wikiedit.css" \ |
| 614 | "$(SRCDIR)\tree.js" \ |
| 615 | "$(SRCDIR)\useredit.js" \ |
| 616 | "$(SRCDIR)\wiki.wiki" |
| 617 | |
| @@ -1129,11 +1134,14 @@ | |
| 1129 | "$(OBJDIR)\json_timeline$O" : "$(SRCDIR)\json_detail.h" |
| 1130 | "$(OBJDIR)\json_user$O" : "$(SRCDIR)\json_detail.h" |
| 1131 | "$(OBJDIR)\json_wiki$O" : "$(SRCDIR)\json_detail.h" |
| 1132 | |
| 1133 | "$(OX)\builtin_data.reslist": $(EXTRA_FILES) "$(B)\win\Makefile.msc" |
| 1134 | echo "$(SRCDIR)\../skins/ardoise/css.txt" > $@ |
| 1135 | echo "$(SRCDIR)\../skins/ardoise/details.txt" >> $@ |
| 1136 | echo "$(SRCDIR)\../skins/ardoise/footer.txt" >> $@ |
| 1137 | echo "$(SRCDIR)\../skins/ardoise/header.txt" >> $@ |
| 1138 | echo "$(SRCDIR)\../skins/black_and_white/css.txt" >> $@ |
| 1139 | echo "$(SRCDIR)\../skins/black_and_white/details.txt" >> $@ |
| @@ -1197,10 +1205,11 @@ | |
| 1197 | echo "$(SRCDIR)\fossil.page.brlist.js" >> $@ |
| 1198 | echo "$(SRCDIR)\fossil.page.chat.js" >> $@ |
| 1199 | echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@ |
| 1200 | echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@ |
| 1201 | echo "$(SRCDIR)\fossil.page.pikchrshow.js" >> $@ |
| 1202 | echo "$(SRCDIR)\fossil.page.whistory.js" >> $@ |
| 1203 | echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@ |
| 1204 | echo "$(SRCDIR)\fossil.pikchr.js" >> $@ |
| 1205 | echo "$(SRCDIR)\fossil.popupwidget.js" >> $@ |
| 1206 | echo "$(SRCDIR)\fossil.storage.js" >> $@ |
| @@ -1232,10 +1241,11 @@ | |
| 1232 | echo "$(SRCDIR)\sounds/e.wav" >> $@ |
| 1233 | echo "$(SRCDIR)\sounds/f.wav" >> $@ |
| 1234 | echo "$(SRCDIR)\style.admin_log.css" >> $@ |
| 1235 | echo "$(SRCDIR)\style.chat.css" >> $@ |
| 1236 | echo "$(SRCDIR)\style.fileedit.css" >> $@ |
| 1237 | echo "$(SRCDIR)\style.wikiedit.css" >> $@ |
| 1238 | echo "$(SRCDIR)\tree.js" >> $@ |
| 1239 | echo "$(SRCDIR)\useredit.js" >> $@ |
| 1240 | echo "$(SRCDIR)\wiki.wiki" >> $@ |
| 1241 | |
| 1242 |
| --- win/Makefile.msc | |
| +++ win/Makefile.msc | |
| @@ -505,11 +505,14 @@ | |
| 505 | "$(OX)\xfer_.c" \ |
| 506 | "$(OX)\xfersetup_.c" \ |
| 507 | "$(OX)\zip_.c" \ |
| 508 | "$(SRCDIR_extsrc)\pikchr.c" |
| 509 | |
| 510 | EXTRA_FILES = "$(SRCDIR)\..\extsrc\pikchr-worker.js" \ |
| 511 | "$(SRCDIR)\..\extsrc\pikchr.js" \ |
| 512 | "$(SRCDIR)\..\extsrc\pikchr.wasm" \ |
| 513 | "$(SRCDIR)\..\skins\ardoise\css.txt" \ |
| 514 | "$(SRCDIR)\..\skins\ardoise\details.txt" \ |
| 515 | "$(SRCDIR)\..\skins\ardoise\footer.txt" \ |
| 516 | "$(SRCDIR)\..\skins\ardoise\header.txt" \ |
| 517 | "$(SRCDIR)\..\skins\black_and_white\css.txt" \ |
| 518 | "$(SRCDIR)\..\skins\black_and_white\details.txt" \ |
| @@ -573,10 +576,11 @@ | |
| 576 | "$(SRCDIR)\fossil.page.brlist.js" \ |
| 577 | "$(SRCDIR)\fossil.page.chat.js" \ |
| 578 | "$(SRCDIR)\fossil.page.fileedit.js" \ |
| 579 | "$(SRCDIR)\fossil.page.forumpost.js" \ |
| 580 | "$(SRCDIR)\fossil.page.pikchrshow.js" \ |
| 581 | "$(SRCDIR)\fossil.page.pikchrshowasm.js" \ |
| 582 | "$(SRCDIR)\fossil.page.whistory.js" \ |
| 583 | "$(SRCDIR)\fossil.page.wikiedit.js" \ |
| 584 | "$(SRCDIR)\fossil.pikchr.js" \ |
| 585 | "$(SRCDIR)\fossil.popupwidget.js" \ |
| 586 | "$(SRCDIR)\fossil.storage.js" \ |
| @@ -608,10 +612,11 @@ | |
| 612 | "$(SRCDIR)\sounds\e.wav" \ |
| 613 | "$(SRCDIR)\sounds\f.wav" \ |
| 614 | "$(SRCDIR)\style.admin_log.css" \ |
| 615 | "$(SRCDIR)\style.chat.css" \ |
| 616 | "$(SRCDIR)\style.fileedit.css" \ |
| 617 | "$(SRCDIR)\style.pikchrshow.css" \ |
| 618 | "$(SRCDIR)\style.wikiedit.css" \ |
| 619 | "$(SRCDIR)\tree.js" \ |
| 620 | "$(SRCDIR)\useredit.js" \ |
| 621 | "$(SRCDIR)\wiki.wiki" |
| 622 | |
| @@ -1129,11 +1134,14 @@ | |
| 1134 | "$(OBJDIR)\json_timeline$O" : "$(SRCDIR)\json_detail.h" |
| 1135 | "$(OBJDIR)\json_user$O" : "$(SRCDIR)\json_detail.h" |
| 1136 | "$(OBJDIR)\json_wiki$O" : "$(SRCDIR)\json_detail.h" |
| 1137 | |
| 1138 | "$(OX)\builtin_data.reslist": $(EXTRA_FILES) "$(B)\win\Makefile.msc" |
| 1139 | echo "$(SRCDIR)\../extsrc/pikchr-worker.js" > $@ |
| 1140 | echo "$(SRCDIR)\../extsrc/pikchr.js" >> $@ |
| 1141 | echo "$(SRCDIR)\../extsrc/pikchr.wasm" >> $@ |
| 1142 | echo "$(SRCDIR)\../skins/ardoise/css.txt" >> $@ |
| 1143 | echo "$(SRCDIR)\../skins/ardoise/details.txt" >> $@ |
| 1144 | echo "$(SRCDIR)\../skins/ardoise/footer.txt" >> $@ |
| 1145 | echo "$(SRCDIR)\../skins/ardoise/header.txt" >> $@ |
| 1146 | echo "$(SRCDIR)\../skins/black_and_white/css.txt" >> $@ |
| 1147 | echo "$(SRCDIR)\../skins/black_and_white/details.txt" >> $@ |
| @@ -1197,10 +1205,11 @@ | |
| 1205 | echo "$(SRCDIR)\fossil.page.brlist.js" >> $@ |
| 1206 | echo "$(SRCDIR)\fossil.page.chat.js" >> $@ |
| 1207 | echo "$(SRCDIR)\fossil.page.fileedit.js" >> $@ |
| 1208 | echo "$(SRCDIR)\fossil.page.forumpost.js" >> $@ |
| 1209 | echo "$(SRCDIR)\fossil.page.pikchrshow.js" >> $@ |
| 1210 | echo "$(SRCDIR)\fossil.page.pikchrshowasm.js" >> $@ |
| 1211 | echo "$(SRCDIR)\fossil.page.whistory.js" >> $@ |
| 1212 | echo "$(SRCDIR)\fossil.page.wikiedit.js" >> $@ |
| 1213 | echo "$(SRCDIR)\fossil.pikchr.js" >> $@ |
| 1214 | echo "$(SRCDIR)\fossil.popupwidget.js" >> $@ |
| 1215 | echo "$(SRCDIR)\fossil.storage.js" >> $@ |
| @@ -1232,10 +1241,11 @@ | |
| 1241 | echo "$(SRCDIR)\sounds/e.wav" >> $@ |
| 1242 | echo "$(SRCDIR)\sounds/f.wav" >> $@ |
| 1243 | echo "$(SRCDIR)\style.admin_log.css" >> $@ |
| 1244 | echo "$(SRCDIR)\style.chat.css" >> $@ |
| 1245 | echo "$(SRCDIR)\style.fileedit.css" >> $@ |
| 1246 | echo "$(SRCDIR)\style.pikchrshow.css" >> $@ |
| 1247 | echo "$(SRCDIR)\style.wikiedit.css" >> $@ |
| 1248 | echo "$(SRCDIR)\tree.js" >> $@ |
| 1249 | echo "$(SRCDIR)\useredit.js" >> $@ |
| 1250 | echo "$(SRCDIR)\wiki.wiki" >> $@ |
| 1251 | |
| 1252 |
+123
-3
| --- www/build.wiki | ||
| +++ www/build.wiki | ||
| @@ -332,11 +332,11 @@ | ||
| 332 | 332 | |
| 333 | 333 | <h2>6.0 Building on/for Android</h2> |
| 334 | 334 | |
| 335 | 335 | <h3>6.1 Cross-compiling from Linux</h3> |
| 336 | 336 | |
| 337 | -The following instructions for building Fossil for Android, | |
| 337 | +The following instructions for building Fossil for Android via Linux, | |
| 338 | 338 | without requiring a rooted OS, are adapted from |
| 339 | 339 | [https://fossil-scm.org/forum/forumpost/e0e9de4a7e | forumpost/e0e9de4a7e]. |
| 340 | 340 | |
| 341 | 341 | On the development machine, from the fossil source tree: |
| 342 | 342 | |
| @@ -381,13 +381,12 @@ | ||
| 381 | 381 | Some information about these (reportedly harmless) warnings can |
| 382 | 382 | be found |
| 383 | 383 | [https://stackoverflow.com/a/41900551 | on this StackOverflow post]. |
| 384 | 384 | |
| 385 | 385 | |
| 386 | - | |
| 387 | 386 | <a id='fuzzer'></a> |
| 388 | -<h2>Building for Fuzz Testing</h2> | |
| 387 | +<h2>7.0 Building for Fuzz Testing</h2> | |
| 389 | 388 | |
| 390 | 389 | This feature is primarily intended for fossil's developers and may |
| 391 | 390 | change at any time. It is only known to work on Linux systems and has |
| 392 | 391 | been seen to work on x86/64 and ARM. |
| 393 | 392 | |
| @@ -460,5 +459,126 @@ | ||
| 460 | 459 | e.g. <tt>-jobs=4</tt> to start four fuzzer jobs in parallel, but doing |
| 461 | 460 | so may cause the fuzzer to <em>strip the --fuzztype flag</em>, leading |
| 462 | 461 | to it testing the wrong thing. When passing on fuzzer-specific flags |
| 463 | 462 | along with <tt>--fuzztype</tt>, be sure to check your system's process |
| 464 | 463 | list to ensure that your <tt>--fuzztype</tt> flag is there. |
| 464 | + | |
| 465 | + | |
| 466 | +<a id='wasm'></a> | |
| 467 | +<h2>8.0 Building WebAssembly Components</h2> | |
| 468 | + | |
| 469 | +As of version 2.19, fossil uses one component built as | |
| 470 | +[https://developer.mozilla.org/en-US/docs/WebAssembly | WebAssembly] | |
| 471 | +a.k.a. WASM. Because compiling WASM code requires non-trivial | |
| 472 | +client-side tooling, the repository includes compiled copies of these | |
| 473 | +pieces. Most Fossil hackers should never need to concern themselves | |
| 474 | +with the WASM parts, but this section describes how to for those who | |
| 475 | +want or need to do so. | |
| 476 | + | |
| 477 | +<strong>The bits described in this section are necessary when updating | |
| 478 | +<tt>extsrc/pikchr.c</tt></strong> from the upstream source, or the | |
| 479 | +fossil binary will use a different version of pikchr than | |
| 480 | +[/pikchrshow] does (as the latter runs the WASM build of pikchr). | |
| 481 | + | |
| 482 | +These instructions have only ever been tested on Linux systems. They | |
| 483 | +"should" work on any Unix-like system supported by Emscripten. The | |
| 484 | +fossil makefiles for Windows builds <em>do not</em> include any of the | |
| 485 | +WASM-related components (patches to add that would be welcomed, of | |
| 486 | +course). | |
| 487 | + | |
| 488 | +The first step is to configure the tree with support for | |
| 489 | +[https://emscripten.org/|Emscripten]. This requires that the system | |
| 490 | +has the Emscripten SDK (a.k.a. emsdk) installed, as documented at: | |
| 491 | + | |
| 492 | +[https://emscripten.org/docs/getting_started/downloads.html] | |
| 493 | + | |
| 494 | +For instructions on keeping the SDK up to date, see: | |
| 495 | + | |
| 496 | +[https://emscripten.org/docs/tools_reference/emsdk.html] | |
| 497 | + | |
| 498 | + Sidebar: getting Emscripten up and running is trivial and | |
| 499 | + painless, at least on Linux systems, but the installer downloads | |
| 500 | + many hundreds of megabytes of tools and dependencies, all of which | |
| 501 | + will be installed under the single SDK directory (as opposed to | |
| 502 | + being installed at the system level). It does, however, require | |
| 503 | + that python3 be installed at the system level and it can | |
| 504 | + optionally make use of a system-level cmake for certain tasks | |
| 505 | + unrelated to how fossil uses the SDK. | |
| 506 | + | |
| 507 | +After installing the SDK, configure the fossil tree with emsdk | |
| 508 | +support: | |
| 509 | + | |
| 510 | +<pre><code>$ ./configure --with-emsdk=/path/to/emsdk ...other options... | |
| 511 | +</code></pre> | |
| 512 | + | |
| 513 | +If the <tt>--with-emsdk</tt> flag is not provided, the configure | |
| 514 | +script will check for the environment variable <tt>EMSDK</tt>, which | |
| 515 | +is one of the standard variables the SDK environment uses. If that | |
| 516 | +variable is found, its value will implicitly be used in place of the | |
| 517 | +missing <tt>--with-emsdk</tt> flag. Thus, if the <tt>emsdk_env.sh</tt> | |
| 518 | +script is sourced into the shell before running the configure script, | |
| 519 | +the SDK will be detected even without the config flag. | |
| 520 | + | |
| 521 | +The configure script installs some makefile variables which tell the | |
| 522 | +build where to find the SDK and it generates a script named | |
| 523 | +<tt>tools/emcc.sh</tt> (from the template file | |
| 524 | +<tt>[/file/tools/emcc.sh.in|/tools/emcc.sh.in]</tt>), which is a | |
| 525 | +wrapper around the Emscripten C compiler (<tt>emcc</tt>). The wrapper | |
| 526 | +script uses the configure-time state to attempt to set up the various | |
| 527 | +environment variables which are required by <tt>emcc</tt> and will | |
| 528 | +fail if it cannot do so. Once it's set up the environment, it passes | |
| 529 | +on all of its arguments to <tt>emcc</tt>. | |
| 530 | + | |
| 531 | +The WASM-related build parts are set up such that none of them should | |
| 532 | +ever trigger implicity (e.g. via dependencies resolution) in a normal | |
| 533 | +build cycle. They are instead explicitly built as described below. | |
| 534 | + | |
| 535 | +From the top of the source tree, all WASM-related components can be | |
| 536 | +built with: | |
| 537 | + | |
| 538 | +<pre><code>$ make wasm</code></pre> | |
| 539 | + | |
| 540 | +As of this writing, those parts include: | |
| 541 | + | |
| 542 | + * <tt>extsrc/pikchr.wasm</tt> is a WASM-compiled form of | |
| 543 | + <tt>extsrc/pikchr.c</tt>. | |
| 544 | + * <tt>extsrc/pikchr.js</tt> is JS/WASM glue code generated by Emscripten | |
| 545 | + to give JS code access to the API exported by the WASM file. | |
| 546 | + | |
| 547 | + Sidebar: The file | |
| 548 | + <tt>[/file/extsrc/pikcher-worker.js|extsrc/pikcher-worker.js]</tt> | |
| 549 | + is hand-coded and intended to be loaded as a "Worker" in | |
| 550 | + JavaScript. That file loads the main module and provides an | |
| 551 | + interface via which a main JavaScript thread can communicate with | |
| 552 | + pikchr running in a Worker thread. The file | |
| 553 | + <tt>[/file/src/fossil.page.pikchrshowasm.js|src/fossil.page.pikchrshowasm.js]</tt> | |
| 554 | + implements the [/pikchrshow] app and demonstrates how | |
| 555 | + <tt>pikchr-worker.js</tt> is used. | |
| 556 | + | |
| 557 | +When a new version of <tt>extsrc/pikchr.c</tt> is installed, the | |
| 558 | +files <tt>pikchr.{js,wasm}</tt> will need to be recompiled to account | |
| 559 | +for that. Running <tt>make wasm</tt> will, if the build is set up for | |
| 560 | +the emsdk, recompile those: | |
| 561 | + | |
| 562 | +<pre><code>$ make wasm | |
| 563 | +./tools/emcc.sh -o extsrc/pikchr.js ... | |
| 564 | +$ ls -la extsrc/pikchr.{js,wasm} | |
| 565 | +-rw-rw-r-- 1 stephan stephan 17263 Jun 8 03:59 extsrc/pikchr.js | |
| 566 | +-rw-rw-r-- 1 stephan stephan 97578 Jun 8 03:59 extsrc/pikchr.wasm | |
| 567 | +</code></pre> | |
| 568 | + | |
| 569 | +Then run the normal build so that those files can be compiled in to | |
| 570 | +the fossil binary, accessible via the [/help?cmd=/builtin|/builtin page]: | |
| 571 | + | |
| 572 | +<pre><code>$ make</code></pre> | |
| 573 | + | |
| 574 | +Before checking in those newly-built files, they need to be tested by | |
| 575 | +running the [/pikchrshow] page. If that page loads, the compilation | |
| 576 | +process fundamentally worked (a load failure will be made obvious to | |
| 577 | +the viewer). If it fails to load then the browser's dev tools console | |
| 578 | +likely provides at least a small hint (and <em>sometimes</em> a useful | |
| 579 | +hint) about the nature of the problem. Don't check those files in | |
| 580 | +until [/pikchrshow] runs, though! | |
| 581 | + | |
| 582 | +Should pikchr's C interface ever changes, <tt>pikchr-worker.js</tt> | |
| 583 | +will need to be updated to accommodate it, but such modification is | |
| 584 | +typically trivial. | |
| 465 | 585 |
| --- www/build.wiki | |
| +++ www/build.wiki | |
| @@ -332,11 +332,11 @@ | |
| 332 | |
| 333 | <h2>6.0 Building on/for Android</h2> |
| 334 | |
| 335 | <h3>6.1 Cross-compiling from Linux</h3> |
| 336 | |
| 337 | The following instructions for building Fossil for Android, |
| 338 | without requiring a rooted OS, are adapted from |
| 339 | [https://fossil-scm.org/forum/forumpost/e0e9de4a7e | forumpost/e0e9de4a7e]. |
| 340 | |
| 341 | On the development machine, from the fossil source tree: |
| 342 | |
| @@ -381,13 +381,12 @@ | |
| 381 | Some information about these (reportedly harmless) warnings can |
| 382 | be found |
| 383 | [https://stackoverflow.com/a/41900551 | on this StackOverflow post]. |
| 384 | |
| 385 | |
| 386 | |
| 387 | <a id='fuzzer'></a> |
| 388 | <h2>Building for Fuzz Testing</h2> |
| 389 | |
| 390 | This feature is primarily intended for fossil's developers and may |
| 391 | change at any time. It is only known to work on Linux systems and has |
| 392 | been seen to work on x86/64 and ARM. |
| 393 | |
| @@ -460,5 +459,126 @@ | |
| 460 | e.g. <tt>-jobs=4</tt> to start four fuzzer jobs in parallel, but doing |
| 461 | so may cause the fuzzer to <em>strip the --fuzztype flag</em>, leading |
| 462 | to it testing the wrong thing. When passing on fuzzer-specific flags |
| 463 | along with <tt>--fuzztype</tt>, be sure to check your system's process |
| 464 | list to ensure that your <tt>--fuzztype</tt> flag is there. |
| 465 |
| --- www/build.wiki | |
| +++ www/build.wiki | |
| @@ -332,11 +332,11 @@ | |
| 332 | |
| 333 | <h2>6.0 Building on/for Android</h2> |
| 334 | |
| 335 | <h3>6.1 Cross-compiling from Linux</h3> |
| 336 | |
| 337 | The following instructions for building Fossil for Android via Linux, |
| 338 | without requiring a rooted OS, are adapted from |
| 339 | [https://fossil-scm.org/forum/forumpost/e0e9de4a7e | forumpost/e0e9de4a7e]. |
| 340 | |
| 341 | On the development machine, from the fossil source tree: |
| 342 | |
| @@ -381,13 +381,12 @@ | |
| 381 | Some information about these (reportedly harmless) warnings can |
| 382 | be found |
| 383 | [https://stackoverflow.com/a/41900551 | on this StackOverflow post]. |
| 384 | |
| 385 | |
| 386 | <a id='fuzzer'></a> |
| 387 | <h2>7.0 Building for Fuzz Testing</h2> |
| 388 | |
| 389 | This feature is primarily intended for fossil's developers and may |
| 390 | change at any time. It is only known to work on Linux systems and has |
| 391 | been seen to work on x86/64 and ARM. |
| 392 | |
| @@ -460,5 +459,126 @@ | |
| 459 | e.g. <tt>-jobs=4</tt> to start four fuzzer jobs in parallel, but doing |
| 460 | so may cause the fuzzer to <em>strip the --fuzztype flag</em>, leading |
| 461 | to it testing the wrong thing. When passing on fuzzer-specific flags |
| 462 | along with <tt>--fuzztype</tt>, be sure to check your system's process |
| 463 | list to ensure that your <tt>--fuzztype</tt> flag is there. |
| 464 | |
| 465 | |
| 466 | <a id='wasm'></a> |
| 467 | <h2>8.0 Building WebAssembly Components</h2> |
| 468 | |
| 469 | As of version 2.19, fossil uses one component built as |
| 470 | [https://developer.mozilla.org/en-US/docs/WebAssembly | WebAssembly] |
| 471 | a.k.a. WASM. Because compiling WASM code requires non-trivial |
| 472 | client-side tooling, the repository includes compiled copies of these |
| 473 | pieces. Most Fossil hackers should never need to concern themselves |
| 474 | with the WASM parts, but this section describes how to for those who |
| 475 | want or need to do so. |
| 476 | |
| 477 | <strong>The bits described in this section are necessary when updating |
| 478 | <tt>extsrc/pikchr.c</tt></strong> from the upstream source, or the |
| 479 | fossil binary will use a different version of pikchr than |
| 480 | [/pikchrshow] does (as the latter runs the WASM build of pikchr). |
| 481 | |
| 482 | These instructions have only ever been tested on Linux systems. They |
| 483 | "should" work on any Unix-like system supported by Emscripten. The |
| 484 | fossil makefiles for Windows builds <em>do not</em> include any of the |
| 485 | WASM-related components (patches to add that would be welcomed, of |
| 486 | course). |
| 487 | |
| 488 | The first step is to configure the tree with support for |
| 489 | [https://emscripten.org/|Emscripten]. This requires that the system |
| 490 | has the Emscripten SDK (a.k.a. emsdk) installed, as documented at: |
| 491 | |
| 492 | [https://emscripten.org/docs/getting_started/downloads.html] |
| 493 | |
| 494 | For instructions on keeping the SDK up to date, see: |
| 495 | |
| 496 | [https://emscripten.org/docs/tools_reference/emsdk.html] |
| 497 | |
| 498 | Sidebar: getting Emscripten up and running is trivial and |
| 499 | painless, at least on Linux systems, but the installer downloads |
| 500 | many hundreds of megabytes of tools and dependencies, all of which |
| 501 | will be installed under the single SDK directory (as opposed to |
| 502 | being installed at the system level). It does, however, require |
| 503 | that python3 be installed at the system level and it can |
| 504 | optionally make use of a system-level cmake for certain tasks |
| 505 | unrelated to how fossil uses the SDK. |
| 506 | |
| 507 | After installing the SDK, configure the fossil tree with emsdk |
| 508 | support: |
| 509 | |
| 510 | <pre><code>$ ./configure --with-emsdk=/path/to/emsdk ...other options... |
| 511 | </code></pre> |
| 512 | |
| 513 | If the <tt>--with-emsdk</tt> flag is not provided, the configure |
| 514 | script will check for the environment variable <tt>EMSDK</tt>, which |
| 515 | is one of the standard variables the SDK environment uses. If that |
| 516 | variable is found, its value will implicitly be used in place of the |
| 517 | missing <tt>--with-emsdk</tt> flag. Thus, if the <tt>emsdk_env.sh</tt> |
| 518 | script is sourced into the shell before running the configure script, |
| 519 | the SDK will be detected even without the config flag. |
| 520 | |
| 521 | The configure script installs some makefile variables which tell the |
| 522 | build where to find the SDK and it generates a script named |
| 523 | <tt>tools/emcc.sh</tt> (from the template file |
| 524 | <tt>[/file/tools/emcc.sh.in|/tools/emcc.sh.in]</tt>), which is a |
| 525 | wrapper around the Emscripten C compiler (<tt>emcc</tt>). The wrapper |
| 526 | script uses the configure-time state to attempt to set up the various |
| 527 | environment variables which are required by <tt>emcc</tt> and will |
| 528 | fail if it cannot do so. Once it's set up the environment, it passes |
| 529 | on all of its arguments to <tt>emcc</tt>. |
| 530 | |
| 531 | The WASM-related build parts are set up such that none of them should |
| 532 | ever trigger implicity (e.g. via dependencies resolution) in a normal |
| 533 | build cycle. They are instead explicitly built as described below. |
| 534 | |
| 535 | From the top of the source tree, all WASM-related components can be |
| 536 | built with: |
| 537 | |
| 538 | <pre><code>$ make wasm</code></pre> |
| 539 | |
| 540 | As of this writing, those parts include: |
| 541 | |
| 542 | * <tt>extsrc/pikchr.wasm</tt> is a WASM-compiled form of |
| 543 | <tt>extsrc/pikchr.c</tt>. |
| 544 | * <tt>extsrc/pikchr.js</tt> is JS/WASM glue code generated by Emscripten |
| 545 | to give JS code access to the API exported by the WASM file. |
| 546 | |
| 547 | Sidebar: The file |
| 548 | <tt>[/file/extsrc/pikcher-worker.js|extsrc/pikcher-worker.js]</tt> |
| 549 | is hand-coded and intended to be loaded as a "Worker" in |
| 550 | JavaScript. That file loads the main module and provides an |
| 551 | interface via which a main JavaScript thread can communicate with |
| 552 | pikchr running in a Worker thread. The file |
| 553 | <tt>[/file/src/fossil.page.pikchrshowasm.js|src/fossil.page.pikchrshowasm.js]</tt> |
| 554 | implements the [/pikchrshow] app and demonstrates how |
| 555 | <tt>pikchr-worker.js</tt> is used. |
| 556 | |
| 557 | When a new version of <tt>extsrc/pikchr.c</tt> is installed, the |
| 558 | files <tt>pikchr.{js,wasm}</tt> will need to be recompiled to account |
| 559 | for that. Running <tt>make wasm</tt> will, if the build is set up for |
| 560 | the emsdk, recompile those: |
| 561 | |
| 562 | <pre><code>$ make wasm |
| 563 | ./tools/emcc.sh -o extsrc/pikchr.js ... |
| 564 | $ ls -la extsrc/pikchr.{js,wasm} |
| 565 | -rw-rw-r-- 1 stephan stephan 17263 Jun 8 03:59 extsrc/pikchr.js |
| 566 | -rw-rw-r-- 1 stephan stephan 97578 Jun 8 03:59 extsrc/pikchr.wasm |
| 567 | </code></pre> |
| 568 | |
| 569 | Then run the normal build so that those files can be compiled in to |
| 570 | the fossil binary, accessible via the [/help?cmd=/builtin|/builtin page]: |
| 571 | |
| 572 | <pre><code>$ make</code></pre> |
| 573 | |
| 574 | Before checking in those newly-built files, they need to be tested by |
| 575 | running the [/pikchrshow] page. If that page loads, the compilation |
| 576 | process fundamentally worked (a load failure will be made obvious to |
| 577 | the viewer). If it fails to load then the browser's dev tools console |
| 578 | likely provides at least a small hint (and <em>sometimes</em> a useful |
| 579 | hint) about the nature of the problem. Don't check those files in |
| 580 | until [/pikchrshow] runs, though! |
| 581 | |
| 582 | Should pikchr's C interface ever changes, <tt>pikchr-worker.js</tt> |
| 583 | will need to be updated to accommodate it, but such modification is |
| 584 | typically trivial. |
| 585 |
+4
-1
| --- www/changes.wiki | ||
| +++ www/changes.wiki | ||
| @@ -25,11 +25,14 @@ | ||
| 25 | 25 | * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"] |
| 26 | 26 | columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables. |
| 27 | 27 | * Fix [/timeline?r=fix_remote_url_overwrite_with_proxy|remote-url-overwrite] |
| 28 | 28 | bug where remote-url is overwritten by the proxy setting during sync |
| 29 | 29 | operation. Also require explicit "system" proxy setting to use |
| 30 | - "http_proxy" environment variable. | |
| 30 | + "http_proxy" environment variable. | |
| 31 | + * Reimplemented the [/pikchrshow] app to use a WebAssembly build of | |
| 32 | + pikchr so that it can render pikchrs on the client instead of requiring | |
| 33 | + a server round-trip. | |
| 31 | 34 | * Add the [/help?cmd=email-listid|email-listid setting]. If set, it is |
| 32 | 35 | used as the List-ID header for all outbound notification emails. |
| 33 | 36 | |
| 34 | 37 | <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2> |
| 35 | 38 | * Added support for [./ssl-server.md|SSL/TLS server mode] for commands |
| 36 | 39 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -25,11 +25,14 @@ | |
| 25 | * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"] |
| 26 | columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables. |
| 27 | * Fix [/timeline?r=fix_remote_url_overwrite_with_proxy|remote-url-overwrite] |
| 28 | bug where remote-url is overwritten by the proxy setting during sync |
| 29 | operation. Also require explicit "system" proxy setting to use |
| 30 | "http_proxy" environment variable. |
| 31 | * Add the [/help?cmd=email-listid|email-listid setting]. If set, it is |
| 32 | used as the List-ID header for all outbound notification emails. |
| 33 | |
| 34 | <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2> |
| 35 | * Added support for [./ssl-server.md|SSL/TLS server mode] for commands |
| 36 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -25,11 +25,14 @@ | |
| 25 | * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"] |
| 26 | columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables. |
| 27 | * Fix [/timeline?r=fix_remote_url_overwrite_with_proxy|remote-url-overwrite] |
| 28 | bug where remote-url is overwritten by the proxy setting during sync |
| 29 | operation. Also require explicit "system" proxy setting to use |
| 30 | "http_proxy" environment variable. |
| 31 | * Reimplemented the [/pikchrshow] app to use a WebAssembly build of |
| 32 | pikchr so that it can render pikchrs on the client instead of requiring |
| 33 | a server round-trip. |
| 34 | * Add the [/help?cmd=email-listid|email-listid setting]. If set, it is |
| 35 | used as the List-ID header for all outbound notification emails. |
| 36 | |
| 37 | <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2> |
| 38 | * Added support for [./ssl-server.md|SSL/TLS server mode] for commands |
| 39 |
+4
-1
| --- www/changes.wiki | ||
| +++ www/changes.wiki | ||
| @@ -25,11 +25,14 @@ | ||
| 25 | 25 | * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"] |
| 26 | 26 | columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables. |
| 27 | 27 | * Fix [/timeline?r=fix_remote_url_overwrite_with_proxy|remote-url-overwrite] |
| 28 | 28 | bug where remote-url is overwritten by the proxy setting during sync |
| 29 | 29 | operation. Also require explicit "system" proxy setting to use |
| 30 | - "http_proxy" environment variable. | |
| 30 | + "http_proxy" environment variable. | |
| 31 | + * Reimplemented the [/pikchrshow] app to use a WebAssembly build of | |
| 32 | + pikchr so that it can render pikchrs on the client instead of requiring | |
| 33 | + a server round-trip. | |
| 31 | 34 | * Add the [/help?cmd=email-listid|email-listid setting]. If set, it is |
| 32 | 35 | used as the List-ID header for all outbound notification emails. |
| 33 | 36 | |
| 34 | 37 | <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2> |
| 35 | 38 | * Added support for [./ssl-server.md|SSL/TLS server mode] for commands |
| 36 | 39 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -25,11 +25,14 @@ | |
| 25 | * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"] |
| 26 | columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables. |
| 27 | * Fix [/timeline?r=fix_remote_url_overwrite_with_proxy|remote-url-overwrite] |
| 28 | bug where remote-url is overwritten by the proxy setting during sync |
| 29 | operation. Also require explicit "system" proxy setting to use |
| 30 | "http_proxy" environment variable. |
| 31 | * Add the [/help?cmd=email-listid|email-listid setting]. If set, it is |
| 32 | used as the List-ID header for all outbound notification emails. |
| 33 | |
| 34 | <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2> |
| 35 | * Added support for [./ssl-server.md|SSL/TLS server mode] for commands |
| 36 |
| --- www/changes.wiki | |
| +++ www/changes.wiki | |
| @@ -25,11 +25,14 @@ | |
| 25 | * Support [/wiki?name=branch/generated-tkt-mimetype&p|generated "mimetype"] |
| 26 | columns in the <var>TICKET</var> and <var>TICKETCHNG</var> tables. |
| 27 | * Fix [/timeline?r=fix_remote_url_overwrite_with_proxy|remote-url-overwrite] |
| 28 | bug where remote-url is overwritten by the proxy setting during sync |
| 29 | operation. Also require explicit "system" proxy setting to use |
| 30 | "http_proxy" environment variable. |
| 31 | * Reimplemented the [/pikchrshow] app to use a WebAssembly build of |
| 32 | pikchr so that it can render pikchrs on the client instead of requiring |
| 33 | a server round-trip. |
| 34 | * Add the [/help?cmd=email-listid|email-listid setting]. If set, it is |
| 35 | used as the List-ID header for all outbound notification emails. |
| 36 | |
| 37 | <h2 id='v2_18'>Changes for version 2.18 (2022-02-23)</h2> |
| 38 | * Added support for [./ssl-server.md|SSL/TLS server mode] for commands |
| 39 |