forth-wordlist wordlist dup set-current 2 set-order : assert ( n -- ) 0= if abort then ; : linked-list create 0 , 0 , ; : allocate' ( n -- a ) allocate 0= assert ; : zero ( a n -- ) 0 fill ; : allocate0 ( n -- a ) dup allocate' swap 2dup zero drop ; : chain-new ( n -- a ) 1+ cells allocate0 ; : chain-fillout ( .. a n -- a ) 0 do dup i 1+ cells + swap >r ! r> loop ; : chain-link ( ..n -- a ) dup chain-new swap chain-fillout ; : chain-first ( ..n head[t] -- ) >r chain-link r> 2dup ! cell+ ! ; : chain-rest ( ..n head[t] -- ) >r chain-link r> 2dup cell+ @ ! cell+ ! ; : chain ( ..n head[t] -- ) dup @ if chain-rest else chain-first then ; : ->next ( a -- a' ) @ ; : $clone ( $ - $ ) dup allocate 0= assert swap 2dup >r >r move r> r> ; : 3dup ( xyz -- xyzxyz ) dup 2over rot ; : atom-length@ ( A -- n ) 1 cells + @ ; : atom-data@ ( A -- a ) 2 cells + @ ; : atom-string@ ( A -- $ ) dup atom-data@ swap atom-length@ ; : atom-meaning-head ( A -- A[head] ) 3 cells + ; linked-list atom-root : $atom-new ( $ -- A ) >r >r 0 0 r> r> 4 atom-root chain atom-root cell+ @ ; : atom-new ( $ -- A ) $clone $atom-new ; : atom= ( $ A -- f ) atom-string@ compare 0= ; : atom-find' ( $ A -- A ) begin dup 0= if nip nip exit then 3dup atom= if nip nip exit then ->next again ; : atom-find ( $ -- A ) atom-root @ atom-find' ; : $atom ( $ -- A ) 2dup atom-find dup if nip nip else drop $atom-new then ; : atom ( $ -- A ) 2dup atom-find dup if nip nip else drop atom-new then ; : atom. ( A -- ) atom-string@ type ; : atoms. ( -- ) atom-root @ begin dup while dup atom. cr ->next repeat drop ; : atom" ( -- A ) [char] " parse state @ if postpone sliteral postpone atom else atom then ; immediate : atom{ ( -- A ) [char] } parse state @ if postpone sliteral postpone atom else atom then ; immediate : atom"" ( -- A ) 0 0 atom ; : atom-append ( A n Ad -- ) atom-meaning-head 2 swap chain ; : atom+=$ ( A Ad -- ) 0 swap atom-append ; : atom+=ref ( A Ad -- ) 1 swap atom-append ; : ref-parts ( ref -- A ref? ) cell+ dup cell+ @ swap @ ; : atom-walk ( fn A -- ) atom-meaning-head @ begin dup while 2dup >r >r ref-parts if recurse else swap execute then r> r> ->next repeat 2drop ; : tally-length ( n A -- n ) atom-length@ + ; : gather-string ( a A -- a' ) 2dup atom-string@ >r swap r> move tally-length ; : atom-walk-length ( A -- n ) 0 swap ['] tally-length swap atom-walk ; : atom-walk-gather ( a A -- ) swap ['] gather-string swap atom-walk drop ; : means ( A -- A' ) dup atom-walk-length dup allocate 0= assert swap 2dup >r >r drop atom-walk-gather r> r> $atom ; : atom>>$ ( A d -- d' ) 2dup >r atom-string@ r> swap move swap atom-length@ + ; : atom+ ( A A -- A ) swap 2dup atom-length@ swap atom-length@ + dup >r allocate 0= assert dup >r atom>>$ atom>>$ drop r> r> $atom ; : atom-ch ( ch -- A ) 1 allocate 0= assert 2dup c! nip 1 atom ; 10 atom-ch constant atom-cr : atom-cr+ ( A -- A ) atom-cr atom+ ; atom" foo" atom" foo" = assert atom" bar" atom" foo" <> assert atom" testing" atom" 123" atom+ atom" testing123" = assert atom" abc" atom" bar" atom+=$ atom" def" atom" bar" atom+=$ atom" 1234" atom" foo" atom+=$ atom" bar" atom" foo" atom+=ref atom" 5678 9" atom" foo" atom+=$ atom" bar" atom" foo" atom+=ref atom" foo" means atom" 1234abcdef5678 9abcdef" = assert : file!-dangle ( A A -- fileid ) atom-string@ r/w bin create-file 0= assert swap over >r atom-string@ r> write-file 0= assert dup flush-file 0= assert ; : file! ( A A -- ) file!-dangle close-file 0= assert ; : file!-tmp ( A A -- fileid ) file!-dangle dup 0 s>d rot reposition-file 0= assert ; : escape-ch ( ch -- ) dup [char] < = if [char] & c, [char] l c, [char] t c, [char] ; c, drop exit then dup [char] > = if [char] & c, [char] g c, [char] t c, [char] ; c, drop exit then dup [char] " = if [char] & c, [char] q c, [char] u c, [char] o c, [char] t c, [char] ; c, drop exit then dup [char] & = if [char] & c, [char] a c, [char] m c, [char] p c, [char] ; c, drop exit then c, ; : escape-each ( A -- ) atom-string@ 0 ?do dup i + c@ escape-ch loop drop ; : here! ( a -- ) here - allot ; : escape ( A -- A ) here dup >r swap escape-each here over - atom r> here! ; : source@ source ( -- a ) drop >in @ + ; : source-remaining ( -- n ) source nip >in @ - ; : drop| ( -- ) source@ 1- c@ [char] | = if -1 >in +! then ; : need-refill? ( -- f) source nip >in @ <= ; : on|? ( -- f ) need-refill? if false exit then source@ c@ [char] | = ; : replenish ( -- f ) need-refill? if refill else true then ; : ?atom-cr+ ( A -- A ) on|? 0= if atom-cr+ then ; : eat| ( -- ) [char] | parse drop| atom atom+ ?atom-cr+ ; : parse..| ( -- A ) atom"" begin replenish 0= if exit then eat| on|? until ; : parse-cr ( -- A ) source@ source-remaining atom source nip >in ! ; variable chunk : chunk+=$ ( A -- ) chunk @ if chunk @ atom+=$ else drop then ; : chunk+=ref ( A -- ) chunk @ if chunk @ atom+=ref else drop then ; atom" ~~~DOC" constant main-documentation variable documentation-chunk main-documentation documentation-chunk ! : documentation ( -- A ) documentation-chunk @ ; : doc! ( back to documentation) 0 chunk ! ; : doc+=$ ( A -- ) documentation atom+=$ ; : .d{ ( -- ) postpone atom{ postpone doc+=$ ; immediate : .d| ( -- ) parse..| ; immediate : |.d ( -- ) postpone literal postpone doc+=$ ; immediate : .dcr atom-cr doc+=$ ; : doc+=ref ( A -- ) documentation atom+=ref ; : doc+=use ( A -- ) .d{ <b>} doc+=$ .d{ </b>} ; : doc+=def ( A -- ) .d{ </p><tt><b>} doc+=$ .d{ </b> +≡</tt><div class="chunk"><pre>} ; : feed ( read into current chunk ) parse..| dup ?atom-cr+ escape doc+=$ atom-cr+ chunk+=$ ; variable doc-base atom" index" doc-base ! : |document-base: parse-cr doc-base ! feed ; variable title atom" Untitled" title ! : |title: parse-cr title ! feed ; variable author atom" Anonymous" author ! : |author: parse-cr author ! feed ; variable isbn atom" 9999999999" isbn ! : |isbn: parse-cr isbn ! feed ; variable subject atom" Article" subject ! : |subject: parse-cr subject ! feed ; variable doc-date atom" Unknown" doc-date ! : |date: parse-cr doc-date ! feed ; variable description atom" No description available." description ! : |description: parse-cr description ! feed ; linked-list out-files : |file: ( add a new output file ) parse-cr dup 1 out-files chain .d{ <tt><i>} doc+=$ .d{ </i></tt>} feed ; : file-name@ ( file -- A ) cell+ @ ; variable slide-chapter variable chapter-count linked-list chapters : chapter-name ( chp -- A ) cell+ @ ; : chapter-text ( chp -- A ) cell+ @ means ; : chapter-number ( chp -- n ) 2 cells + @ ; atom" .html" constant .html : chapter-filename ( chp -- A ) chapter-number s>d <# # # # #s #> atom doc-base @ atom" _" atom+ swap .html atom+ atom+ ; : chapter-finish .d{ </p></div></body></html>} ; : raw-chapter ( -- ) chapter-finish parse-cr chapter-count @ 1 chapter-count +! over 2 chapters chain dup documentation-chunk ! doc! .d| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html> <head> |.d slide-chapter @ if .d| <script type="text/javascript"> function SlideCount() { var sections = document.getElementsByClassName('section'); return sections.length; } function ShowSlide(index) { var sections = document.getElementsByClassName('section'); for (var i = 0; i < sections.length; i++) { sections[i].style.display = ((i == index) ? 'inline' : 'none'); } } var current_slide = 0; function Load() { ShowSlide(0); window.onkeydown = function(e) { if (e.keyCode == 37) { // left current_slide = Math.max(0, current_slide - 1); } else if (e.keyCode == 39) { // right current_slide = Math.min(SlideCount() - 1, current_slide + 1); } else if (e.keyCode == 38) { // up current_slide = 0; } else if (e.keyCode == 40) { // down current_slide = SlideCount() - 1; } ShowSlide(current_slide); }; } </script> |.d then .d| <style type="text/css"> div.chunk { margin: 0em 0.5em; } pre { margin: 0em 0em; } |.d slide-chapter @ if .d| div.section { page-break-before: always; } |.d then .d| </style> <title>|.d dup doc+=$ .d{ </title></head>} slide-chapter @ if .d{ <body onload="Load()">} else .d{ <body>} then .d{ <div class="section"><h1>} doc+=$ .d{ </h1><p>} feed ; : |chapter: false slide-chapter ! raw-chapter ; : |slide-chapter: true slide-chapter ! raw-chapter ; : |section: parse-cr .d{ </p></div><div class="section"><h2>} doc+=$ .d{ </h2><p>} feed ; : |page parse-cr .d{ </p><p style="page-break-before:always;">} feed ; : |br parse-cr .d{ <br/>} feed ; : |$ ( paragraph ) .d{ </p><p>} feed ; : |\ ( whole line) parse-cr atom-cr+ dup chunk+=$ escape doc+=$ feed ; : |b{ .d{ <b>} feed ; : |}b .d{ </b>} feed ; : |i{ .d{ <i>} feed ; : |}i .d{ </i>} feed ; : |u{ .d{ <u>} feed ; : |}u .d{ </u>} feed ; : |sup{ .d{ <sup>} feed ; : |}sup .d{ </sup>} feed ; : |sub{ .d{ <sub>} feed ; : |}sub .d{ </sub>} feed ; : |tt{ .d{ <tt>} feed ; : |}tt .d{ </tt>} feed ; : |code{ .d{ <div class="chunk"><pre>} feed ; : |}code .d{ </pre></div>} feed ; variable bullet-depth : bullet+ 1 bullet-depth +! bullet-depth @ 1 = if .d{ </p>} then ; : bullet- -1 bullet-depth +! bullet-depth @ 0 = if .d{ <p>} then ; : |{- bullet+ .d{ <ul><li>} feed ; : |-- .d{ </li><li>} feed ; : |-} .d{ </li></ul>} bullet- feed ; : |TeX .d{ <span>T<sub><big>E</big></sub>X</span>} feed ; : |LaTeX .d{ <span>L<sup><small>A</small></sup>T<sub><big>E</big></sub>X</span>} feed ; : |<-| .d{ ←} feed ; : |->| .d{ →} feed ; : |^| .d{ ↑} feed ; : |v| .d{ ↓} feed ; : |: ( add to a chunk ) parse-cr dup chunk ! doc+=def feed ; : |; ( documentation ) .d{ </pre></div><p>} doc! feed ; : |@ ( use a chunk ) parse-cr dup chunk+=ref doc+=use .dcr feed ; : |@@ ( use a chunk in documentation ) parse-cr means escape doc+=$ feed ; variable literate-mode : literate-setup depth 0<= if 0 then literate-mode ! ; literate-setup literate-mode @ 0 = constant running? literate-mode @ 1 = constant tangling? literate-mode @ 2 = constant weaving? weaving? tangling? or running? or assert atom" ~~~TOC" constant atom-toc : toc-filename doc-base @ atom" .html" atom+ ; : weave-toc-chapter ( chapter -- ) .d{ <h4><b><a href="} dup chapter-filename doc+=$ .d{ ">} chapter-name doc+=$ .d{ </a></b></h4>} .dcr ; : weave-toc atom-toc documentation-chunk ! doc! .d| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><title>Table of Contents</title></head> <body> <div> <h1><b>TABLE OF CONTENTS</b></h1> |.d chapters @ begin dup while dup weave-toc-chapter ->next repeat drop .d{ </div></body></html>} .dcr documentation means toc-filename file! ; atom" ~~~NCX" constant atom-ncx : ncx-filename ( -- A ) doc-base @ atom" .ncx" atom+ ; : weave-ncx-chapter ( chapter -- ) .d{ <navPoint class="chapter" id="} dup chapter-filename doc+=$ .d{ " playOrder="} dup chapter-filename doc+=$ .d{ "><navLabel><text>} dup chapter-name doc+=$ .d{ </text></navLabel><content src="} chapter-filename doc+=$ .d{ "/></navPoint>} ; : weave-ncx atom-ncx documentation-chunk ! doc! .d| <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE ncx PUBLIC "-//NISO//DTD ncx 2005-1//EN" "http://www.daisy.org/z3986/2005/ncx-2005-1.dtd"> <ncx xmlns="http://www.daisy.org/z3986/2005/ncx/" version="2005-1" xml:lang="en-US"> <head> <meta name="dtb:uid" content="BookId"/> <meta name="dtb:depth" content="2"/> <meta name="dtb:totalPageCount" content="0"/> <meta name="dtb:maxPageNumber" content="0"/> </head> |.d .d{ <docTitle><text>} title @ doc+=$ .d| </text></docTitle> <docAuthor><text>me</text></docAuthor> <navMap> <navPoint class="toc" id="toc" playOrder="1"> <navLabel> <text>Table of Contents</text> </navLabel> <content src="|.d toc-filename doc+=$ .d| "/> </navPoint> |.d chapters @ begin dup while dup weave-ncx-chapter ->next repeat drop .d{ </navMap></ncx>} documentation means ncx-filename file! ; : cover-filename doc-base @ atom" _cover.bmp" atom+ ; variable image-width variable image-height variable image-data : image-data-size ( -- n ) image-width @ image-height @ * 4 * ; : image-pick-size ( w h -- ) image-height ! image-width ! ; : image-free-old image-data @ dup if free 0= assert else drop then ; : image-allocate image-data-size allocate 0= assert image-data ! ; : image-clear image-data @ image-data-size 0 fill ; : image-setup ( w h -- ) image-pick-size image-free-old image-allocate image-clear ; variable red variable green variable blue : rgb ( r g b -- ) blue ! green ! red ! ; : f>primary ( f -- n ) 255e f* f>s 0 max 255 min ; : rgbf ( rf gf bf -- ) f>primary f>primary f>primary rgb ; : black ( -- ) 0 0 0 rgb ; : white ( -- ) 255 255 255 rgb ; : gray ( n -- ) dup dup rgb ; : image-xy ( x y -- a ) image-width @ * + 4 * image-data @ + ; : plot ( x y -- ) image-xy red @ over c! green @ over 1+ c! blue @ over 2 + c! 0 swap 3 + c! ; variable bmp-file : bmp-begin ( A -- ) atom-string@ w/o bin create-file 0= assert bmp-file ! ; : bmp-end ( -- ) bmp-file @ close-file 0= assert ; : bmp-write ( $ -- ) bmp-file @ write-file 0= assert ; : bmp-byte ( b -- ) here c! here 1 bmp-write ; : bmp-word ( w -- ) dup 255 and bmp-byte 8 rshift 255 and bmp-byte ; : bmp-dword ( d -- ) dup 65535 and bmp-word 16 rshift 65535 and bmp-word ; 3 2 * 2 4 * + constant bmp-header-size 10 4 * constant dib-header-size : bmp-save ( A -- ) bmp-begin \ BMP header s" BM" bmp-write bmp-header-size dib-header-size + image-data-size + bmp-dword \ size of bmp file in bytes 0 bmp-word \ unused 0 bmp-word \ unused bmp-header-size dib-header-size + bmp-dword \ offset to start of bitmap image data \ DIB header dib-header-size bmp-dword \ size of header in bytes image-width @ bmp-dword \ width image-height @ bmp-dword \ height 1 bmp-word \ color planes 32 bmp-word \ bits per pixel 0 bmp-dword \ BI_RGB (uncompressed) image-data-size bmp-dword \ pixel data size 0 bmp-dword \ horizontal pixels per meter 0 bmp-dword \ vertical pixels per meter 0 bmp-dword \ colors in color palette 0 bmp-dword \ important colors in palette \ Image data image-data @ image-data-size bmp-write bmp-end ; fvariable xx fvariable yy : x ( -- f ) xx f@ ; : y ( -- f ) yy f@ ; variable xn variable yn fvariable aspect 1e aspect f! : haiku ( f -- ) image-height @ 0 do i yn ! i s>f 0.5e f+ image-width @ s>f aspect f@ f/ f/ yy f! image-width @ 0 do i xn ! i s>f 0.5e f+ image-width @ s>f f/ xx f! dup execute rgbf i j plot loop loop drop ; 0.0722e fconstant red-luminance 0.7152e fconstant green-luminance 0.2126e fconstant blue-luminance : luminance ( rf gf bf -- f ) blue-luminance f* fswap green-luminance f* f+ fswap red-luminance f* f+ ; create dither-table 1 , 49 , 13 , 61 , 4 , 52 , 16 , 64 , 33 , 17 , 45 , 29 , 36 , 20 , 48 , 32 , 9 , 57 , 5 , 53 , 12 , 60 , 8 , 56 , 41 , 25 , 37 , 21 , 44 , 28 , 40 , 24 , 3 , 51 , 15 , 63 , 2 , 50 , 14 , 62 , 35 , 19 , 47 , 31 , 34 , 18 , 46 , 30 , 11 , 59 , 7 , 55 , 10 , 58 , 6 , 54 , 43 , 27 , 39 , 23 , 42 , 26 , 38 , 22 , : dither-map ( x y -- f ) 8 mod 8 * swap 8 mod + cells dither-table + @ s>f 65e f/ 0.5e f- ; : dither ( -- f ) xn @ yn @ dither-map 7e f/ ; : 3dither-scale ( f -- f ) 7e f/ ; : 3dither ( rgb -- rgb' ) dither blue-luminance f/ 3dither-scale f+ frot dither green-luminance f/ 3dither-scale f+ frot dither red-luminance f/ 3dither-scale f+ frot ; fvariable gradient-scale : 3fg* ( f f f -- f f f ) gradient-scale f@ f* frot gradient-scale f@ f* frot gradient-scale f@ f* frot ; : gradient-invert 1e gradient-scale f@ f- gradient-scale f! ; : gradient1 1e x f- 0.3e f* y f+ 0.5e f+ 10e f** 0e fmax 1e fmin gradient-scale f! ; fvariable 3f+temp : 3f+ ( xyz abc -- x+a y+b z+c ) fswap 3f+temp f! frot f+ ( x y a z+c ) frot 3f+temp f@ f+ ( x a z+c y+b ) 3f+temp f! frot frot f+ ( z+c x+a ) 3f+temp f@ frot ( x+a y+b z+c ) ; : 4spire x x 23e f* fsin 2e f/ y fmax f/ fsin y x 23e f* fsin 2e f/ y fmax f/ fsin fover fover f/ fsin ; : scales-x' x 0.3e f- ; : scales-y' y 0.1e f+ ; : scales scales-x' scales-y' f* 40e f* fsin 1e scales-x' f- scales-y' f* 30e f* fsin f* scales-x' 1e scales-y' f- f* 20e f* fsin f* fdup scales-x' f/ fsin fdup scales-y' f/ fcos 1e x f- 1e y f- f+ f* ; : scales-4spire scales gradient1 3fg* 4spire gradient1 gradient-invert 3fg* 3f+ ; : scales-4spire-dithered scales-4spire 3dither ; : scales-4spire-gray scales-4spire luminance dither f+ fdup fdup ; : weave-cover 600 800 image-setup ['] scales-4spire-dithered haiku cover-filename bmp-save ; atom" ~~~OPF" constant atom-opf : opf-filename ( -- A ) doc-base @ atom" .opf" atom+ ; : opf-chapter ( A -- ) .d{ <item id="} dup doc+=$ .d{ " media-type="application/xhtml+xml" href="} doc+=$ .d{ "></item>} .dcr ; : opf-chapter' ( A -- ) .d{ <itemref idref="} doc+=$ .d{ "/>} .dcr ; : weave-opf atom-opf documentation-chunk ! doc! .d| <?xml version="1.0" encoding="utf-8"?> <package xmlns="http://www.idpf.org/2007/opf" version="2.0" unique-identifier="BookId"> <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf"> |.d .d{ <dc:title>} title @ doc+=$ .d{ </dc:title>} .dcr .d{ <dc:language>en-us</dc:language>} .dcr .d{ <meta name="cover" content="My_Cover"/> } .dcr .d{ <dc:identifier id="BookId" opf:scheme="ISBN">} isbn @ doc+=$ .d{ </dc:identifier>} .dcr .d{ <dc:creator>} author @ doc+=$ .d{ </dc:creator>} .dcr .d{ <dc:publisher>} author @ doc+=$ .d{ </dc:publisher>} .dcr .d{ <dc:subject>} subject @ doc+=$ .d{ </dc:subject>} .dcr .d{ <dc:date>} doc-date @ doc+=$ .d{ </dc:date>} .dcr .d{ <dc:description>} description @ doc+=$ .d{ </dc:description>} .dcr .d| </metadata> <manifest> <item id="My_Table_of_Contents" media-type="application/x-dtbncx+xml" href="|.d ncx-filename doc+=$ .d| "/> <item id="toc" media-type="application/xhtml+xml" href="|.d toc-filename doc+=$ .d{ "></item>} chapters @ begin dup while dup chapter-filename opf-chapter ->next repeat drop .d{ <item id="My_Cover" media-type="image/gif"} .dcr .d{ href="} cover-filename doc+=$ .d{ "/>} .dcr .d{ </manifest>} .d{ <spine toc="My_Table_of_Contents"><itemref idref="toc"/>} chapters @ begin dup while dup chapter-filename opf-chapter' ->next repeat drop .d{ </spine>} .d| <guide> <reference type="toc" title="Table of Contents" href="|.d toc-filename doc+=$ .d| "></reference> </guide> </package> |.d documentation means opf-filename file! ; : weave-chapter ( chapter -- ) dup chapter-text swap chapter-filename file! ; : weave-chapters chapters @ begin dup while dup weave-chapter ->next repeat drop ; : weave ( -- ) weave-opf weave-ncx weave-cover weave-toc weave-chapters ; : tangle-file ( file -- ) file-name@ dup means swap file! ; : tangle out-files @ begin dup while dup tangle-file ->next repeat drop ; : run-filename ( -- A ) doc-base @ atom" _running.tmp" atom+ ; : run-cleanup run-filename atom-string@ delete-file drop ; : bye run-cleanup bye ; : run atom" *" means run-filename file!-tmp forth-wordlist 1 set-order forth-wordlist set-current include-file run-cleanup ; : |. ( exit literate mode ) chapter-finish weaving? if weave bye then tangling? if tangle bye then running? if run then ;