about summary refs log blame commit diff stats
path: root/403unicode.mu
blob: dcb1e6582281cd31a45906884365d64ed224b769 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
                      


                                                        
                                            






                                                                            
                                        

                                                                          


                                                                               


                                                                             





































                                                    
                           










                                                             






                               
                          


                       



                             


                        



















                                                                        
                                                                                                         

                                   
                                                                                                              

                                         
                                                                                                              



                                   
                                                                                                              

                                         
                                                                                                              



                                     
                                                                                                              

                                         
                                                                                                              

 





                                                                                                              

 





                                                                                                              

 





                                                                                                              

 
































































































                                                                                                            




































































                                                                                                            












































                                                                                     
                                           
                                 
                          
              
                
    




















                                                              
# Helpers for Unicode.
#
# Mu has no characters, only code points and graphemes.
# Code points are the indivisible atoms of text streams.
#   https://en.wikipedia.org/wiki/Code_point
# Graphemes are the smallest self-contained unit of text.
# Graphemes may consist of multiple code points.
#
# Mu graphemes are always represented in utf-8, and they are required to fit
# in 4 bytes.
#
# Mu doesn't currently support combining code points, or graphemes made of
# multiple code points. One day we will.
# We also don't currently support code points that translate into multiple
# or wide graphemes. (In particular, Tab will never be supported.)

# transliterated from tb_utf8_unicode_to_char in https://github.com/nsf/termbox
# https://wiki.tcl-lang.org/page/UTF%2D8+bit+by+bit explains the algorithm
#
# The day we want to support combining characters, this function will need to
# take multiple code points. Or something.
fn to-grapheme in: code-point -> out/eax: grapheme {
$to-grapheme:body: {
  var c/eax: int <- copy in
  var num-trailers/ecx: int <- copy 0
  var first/edx: int <- copy 0
  $to-grapheme:compute-length: {
    # single byte: just return it
    compare c, 0x7f
    {
      break-if->
      out <- copy c
      break $to-grapheme:body
    }
    # 2 bytes
    compare c, 0x7ff
    {
      break-if->
      num-trailers <- copy 1
      first <- copy 0xc0
      break $to-grapheme:compute-length
    }
    # 3 bytes
    compare c, 0xffff
    {
      break-if->
      num-trailers <- copy 2
      first <- copy 0xe0
      break $to-grapheme:compute-length
    }
    # 4 bytes
    compare c, 0x1fffff
    {
      break-if->
      num-trailers <- copy 3
      first <- copy 0xf0
      break $to-grapheme:compute-length
    }
    # more than 4 bytes: unsupported
    # TODO: print to stderr
    compare c, 0x1fffff
    {
      break-if->
      print-string-to-real-screen "unsupported code point "
      print-int32-hex-to-real-screen c
      print-string-to-real-screen "\n"
      var exit-status/ebx: int <- copy 1
      syscall_exit
    }
  }
  # emit trailer bytes, 6 bits from 'in', first two bits '10'
  var result/edi: int <- copy 0
  {
    compare num-trailers, 0
    break-if-<=
    var tmp/esi: int <- copy c
    tmp <- and 0x3f
    tmp <- or 0x80
    result <- shift-left 8
    result <- or tmp
    # update loop state
    c <- shift-right 6
    num-trailers <- decrement
    loop
  }
  # emit engine
  result <- shift-left 8
  result <- or c
  result <- or first
  #
  out <- copy result
}
}

# single-byte code point have identical graphemes
fn test-to-grapheme-single-byte {
  var in-int/ecx: int <- copy 0
  {
    compare in-int, 0x7f
    break-if->
    var in/eax: code-point <- copy in-int
    var out/eax: grapheme <- to-grapheme in
    var out-int/eax: int <- copy out
    check-ints-equal out-int, in-int, "F - test-to-grapheme-single-byte"
    in-int <- increment
    loop
  }
}

                                                              # byte       | byte      | byte      | byte
# smallest 2-byte utf-8
fn test-to-grapheme-two-bytes-min {
  var in/eax: code-point <- copy 0x80                         #                                 10     00-0000
  var out/eax: grapheme <- to-grapheme in
  var out-int/eax: int <- copy out
  check-ints-equal out-int, 0x80c2, "F - to-grapheme/2a"      #                         110 0-0010  10 00-0000
}

# largest 2-byte utf-8
fn test-to-grapheme-two-bytes-max {
  var in/eax: code-point <- copy 0x7ff                        #                             1-1111     11-1111
  var out/eax: grapheme <- to-grapheme in
  var out-int/eax: int <- copy out
  check-ints-equal out-int, 0xbfdf, "F - to-grapheme/2b"      #                         110 1-1111  10 11-1111
}

# smallest 3-byte utf-8
fn test-to-grapheme-three-bytes-min {
  var in/eax: code-point <- copy 0x800                        #                            10-0000     00-0000
  var out/eax: grapheme <- to-grapheme in
  var out-int/eax: int <- copy out
  check-ints-equal out-int, 0x80a0e0, "F - to-grapheme/3a"    #              1110 0000  10 10-0000  10 00-0000
}

# largest 3-byte utf-8
fn test-to-grapheme-three-bytes-max {
  var in/eax: code-point <- copy 0xffff                       #                   1111     11-1111     11-1111
  var out/eax: grapheme <- to-grapheme in
  var out-int/eax: int <- copy out
  check-ints-equal out-int, 0xbfbfef, "F - to-grapheme/3b"    #              1110 1111  10 11-1111  10 11-1111
}

# smallest 4-byte utf-8
fn test-to-grapheme-four-bytes-min {
  var in/eax: code-point <- copy 0x10000                      #                 1-0000     00-0000     00-0000
  var out/eax: grapheme <- to-grapheme in
  var out-int/eax: int <- copy out
  check-ints-equal out-int, 0x808090f0, "F - to-grapheme/4a"  # 1111-0 000  10 01-0000  10 00-0000  10 00-0000
}

# largest 4-byte utf-8
fn test-to-grapheme-four-bytes-max {
  var in/eax: code-point <- copy 0x1fffff                     #        111     11-1111     11-1111     11-1111
  var out/eax: grapheme <- to-grapheme in
  var out-int/eax: int <- copy out
  check-ints-equal out-int, 0xbfbfbff7, "F - to-grapheme/4b"  # 1111-0 111  10 11-1111  10 11-1111  10 11-1111
}

# read the next grapheme from a stream of bytes
fn read-grapheme in: (addr stream byte) -> out/eax: grapheme {
$read-grapheme:body: {
  var c/eax: byte <- read-byte in
  var num-trailers/ecx: int <- copy 0
  $read-grapheme:compute-length: {
    # single byte: just return it
    compare c, 0xc0
    {
      break-if->=
      out <- copy c
      num-trailers <- copy 0
      break $read-grapheme:body
    }
    compare c, 0xfe
    {
      break-if-<
      out <- copy c
      break $read-grapheme:body
    }
    # 2 bytes
    compare c, 0xe0
    {
      break-if->=
      num-trailers <- copy 1
      break $read-grapheme:compute-length
    }
    # 3 bytes
    compare c, 0xf0
    {
      break-if->=
      num-trailers <- copy 2
      break $read-grapheme:compute-length
    }
    # 4 bytes
    compare c, 0xf8
    {
      break-if->=
      num-trailers <- copy 3
      break $read-grapheme:compute-length
    }
$read-grapheme:abort: {
      # TODO: print to stderr
      print-string-to-real-screen "utf-8 encodings larger than 4 bytes are not supported. First byte seen: "
      var n/eax: int <- copy c
      print-int32-hex-to-real-screen n
      print-string-to-real-screen "\n"
      var exit-status/ebx: int <- copy 1
      syscall_exit
    }
  }
  # prepend trailer bytes
  var result/edi: int <- copy c
  var num-byte-shifts/edx: int <- copy 1
  {
    compare num-trailers, 0
    break-if-<=
    var tmp/eax: byte <- read-byte in
    var tmp2/eax: int <- copy tmp
    tmp2 <- shift-left-bytes tmp2, num-byte-shifts
    result <- or tmp2
    # update loop state
    num-byte-shifts <- increment
    num-trailers <- decrement
    loop
  }
  out <- copy result
}
}

fn test-read-grapheme {
  var s: (stream byte 0x30)
  var s2/ecx: (addr stream byte) <- address s
  write s2, "aΒc世d界e"
  var c/eax: grapheme <- read-grapheme s2
  var n/eax: int <- copy c
  check-ints-equal n, 0x61, "F - test grapheme/0"
  var c/eax: grapheme <- read-grapheme s2
  var n/eax: int <- copy c
  check-ints-equal n, 0x92ce, "F - test grapheme/1"  # greek capital letter beta
  var c/eax: grapheme <- read-grapheme s2
  var n/eax: int <- copy c
  check-ints-equal n, 0x63, "F - test grapheme/2"
  var c/eax: grapheme <- read-grapheme s2
  var n/eax: int <- copy c
  check-ints-equal n, 0x96b8e4, "F - test grapheme/3"
  var c/eax: grapheme <- read-grapheme s2
  var n/eax: int <- copy c
  check-ints-equal n, 0x64, "F - test grapheme/4"
  var c/eax: grapheme <- read-grapheme s2
  var n/eax: int <- copy c
  check-ints-equal n, 0x8c95e7, "F - test grapheme/5"
  var c/eax: grapheme <- read-grapheme s2
  var n/eax: int <- copy c
  check-ints-equal n, 0x65, "F - test grapheme/6"
}

fn read-grapheme-buffered in: (addr buffered-file) -> out/eax: grapheme {
$read-grapheme-buffered:body: {
  var c/eax: byte <- read-byte-buffered in
  var num-trailers/ecx: int <- copy 0
  $read-grapheme-buffered:compute-length: {
    # single byte: just return it
    compare c, 0xc0
    {
      break-if->=
      out <- copy c
      num-trailers <- copy 0
      break $read-grapheme-buffered:body
    }
    compare c, 0xfe
    {
      break-if-<
      out <- copy c
      break $read-grapheme-buffered:body
    }
    # 2 bytes
    compare c, 0xe0
    {
      break-if->=
      num-trailers <- copy 1
      break $read-grapheme-buffered:compute-length
    }
    # 3 bytes
    compare c, 0xf0
    {
      break-if->=
      num-trailers <- copy 2
      break $read-grapheme-buffered:compute-length
    }
    # 4 bytes
    compare c, 0xf8
    {
      break-if->=
      num-trailers <- copy 3
      break $read-grapheme-buffered:compute-length
    }
$read-grapheme-buffered:abort: {
      # TODO: print to stderr
      print-string-to-real-screen "utf-8 encodings larger than 4 bytes are not supported. First byte seen: "
      var n/eax: int <- copy c
      print-int32-hex-to-real-screen n
      print-string-to-real-screen "\n"
      var exit-status/ebx: int <- copy 1
      syscall_exit
    }
  }
  # prepend trailer bytes
  var result/edi: int <- copy c
  var num-byte-shifts/edx: int <- copy 1
  {
    compare num-trailers, 0
    break-if-<=
    var tmp/eax: byte <- read-byte-buffered in
    var tmp2/eax: int <- copy tmp
    tmp2 <- shift-left-bytes tmp2, num-byte-shifts
    result <- or tmp2
    # update loop state
    num-byte-shifts <- increment
    num-trailers <- decrement
    loop
  }
  out <- copy result
}
}

# needed because available primitives only shift by a literal/constant number of bits
fn shift-left-bytes n: int, k: int -> result/eax: int {
  var i/ecx: int <- copy 0
  result <- copy n
  {
    compare i, k
    break-if->=
    compare i, 4  # only 4 bytes in 32 bits
    break-if->=
    result <- shift-left 8
    i <- increment
    loop
  }
}

fn test-shift-left-bytes-0 {
  var result/eax: int <- shift-left-bytes 1, 0
  check-ints-equal result, 1, "F - shift-left-bytes 0"
}

fn test-shift-left-bytes-1 {
  var result/eax: int <- shift-left-bytes 1, 1
  check-ints-equal result, 0x100, "F - shift-left-bytes 1"
}

fn test-shift-left-bytes-2 {
  var result/eax: int <- shift-left-bytes 1, 2
  check-ints-equal result, 0x10000, "F - shift-left-bytes 2"
}

fn test-shift-left-bytes-3 {
  var result/eax: int <- shift-left-bytes 1, 3
  check-ints-equal result, 0x1000000, "F - shift-left-bytes 3"
}

fn test-shift-left-bytes-4 {
  var result/eax: int <- shift-left-bytes 1, 4
  check-ints-equal result, 0, "F - shift-left-bytes 4"
}

fn test-shift-left-bytes-5 {
  var result/eax: int <- shift-left-bytes 1, 5
  check-ints-equal result, 0, "F - shift-left-bytes >4"
}

# To run all tests, uncomment this and run:
#   $ ./translate_mu  &&  ./a.elf
#? fn main -> r/ebx: int {
#?   run-tests
#?   r <- copy 0
#? }

# write a grapheme to a stream of bytes
# this is like write-to-stream, except we skip leading 0 bytes
fn write-grapheme out: (addr stream byte), g: grapheme {
$write-grapheme:body: {
  var c/eax: int <- copy g
  append-byte out, c  # first byte is always written
  c <- shift-right 8
  compare c, 0
  break-if-= $write-grapheme:body
  append-byte out, c
  c <- shift-right 8
  compare c, 0
  break-if-= $write-grapheme:body
  append-byte out, c
  c <- shift-right 8
  compare c, 0
  break-if-= $write-grapheme:body
  append-byte out, c
}
}
an>"L176" class="LineNr">176 </span> (<a href='501draw-text.mu.html#L332'>draw-text-wrapping-right-then-down-from-cursor-over-full-screen</a> 0 <span class="Constant">&quot;done loading&quot;</span> 7 0) <span id="L177" class="LineNr">177 </span> { <span id="L178" class="LineNr">178 </span> eb/jump <span class="Constant">loop</span>/disp8 <span id="L179" class="LineNr">179 </span> } <span id="L180" class="LineNr">180 </span> } <span id="L181" class="LineNr">181 </span> 3d/compare-eax-and 0x20/imm32/space <span id="L182" class="LineNr">182 </span> { <span id="L183" class="LineNr">183 </span> 75/jump-if-!= <span class="Constant">break</span>/disp8 <span id="L184" class="LineNr">184 </span> (<a href='501draw-text.mu.html#L332'>draw-text-wrapping-right-then-down-from-cursor-over-full-screen</a> 0 <span class="Constant">&quot;unexpected space&quot;</span> 7 0) <span id="L185" class="LineNr">185 </span> { <span id="L186" class="LineNr">186 </span> eb/jump <span class="Constant">loop</span>/disp8 <span id="L187" class="LineNr">187 </span> } <span id="L188" class="LineNr">188 </span> } <span id="L189" class="LineNr">189 </span> 43/increment-ebx <span id="L190" class="LineNr">190 </span> e9/jump <span class="Constant">loop</span>/disp32 <span id="L191" class="LineNr">191 </span> } <span id="L192" class="LineNr">192 </span><span class="Constant">$skip-to-next-newline:end</span>: <span id="L193" class="LineNr">193 </span> <span class="subxS1Comment"># . restore registers</span> <span id="L194" class="LineNr">194 </span> 58/pop-to-eax <span id="L195" class="LineNr">195 </span> <span class="subxS1Comment"># . epilogue</span> <span id="L196" class="LineNr">196 </span> 89/&lt;- %esp 5/r32/ebp <span id="L197" class="LineNr">197 </span> 5d/pop-to-ebp <span id="L198" class="LineNr">198 </span> c3/return <span id="L199" class="LineNr">199 </span> <span id="L200" class="LineNr">200 </span><span class="subxFunction">label-append</span>: <span class="subxComment"># labels: (addr stream {start-address, label-slice}), address: int, start: int, end: int</span> <span id="L201" class="LineNr">201 </span> <span class="subxS1Comment"># . prologue</span> <span id="L202" class="LineNr">202 </span> 55/push-ebp <span id="L203" class="LineNr">203 </span> 89/&lt;- %ebp 4/r32/esp <span id="L204" class="LineNr">204 </span> <span class="subxS1Comment"># . save registers</span> <span id="L205" class="LineNr">205 </span> 50/push-eax <span id="L206" class="LineNr">206 </span> 51/push-ecx <span id="L207" class="LineNr">207 </span> 56/push-esi <span id="L208" class="LineNr">208 </span> <span class="subxComment"># esi = labels</span> <span id="L209" class="LineNr">209 </span> 8b/-&gt; *(ebp+8) 6/r32/esi <span id="L210" class="LineNr">210 </span> <span class="subxComment"># ecx = labels-&gt;write</span> <span id="L211" class="LineNr">211 </span> 8b/-&gt; *esi 1/r32/ecx <span id="L212" class="LineNr">212 </span> <span class="subxComment"># labels-&gt;data[labels-&gt;write] = address</span> <span id="L213" class="LineNr">213 </span> 8b/-&gt; *(ebp+0xc) 0/r32/eax <span id="L214" class="LineNr">214 </span> 89/&lt;- *(esi+ecx+0xc) 0/r32/eax <span id="L215" class="LineNr">215 </span> <span class="subxComment"># labels-&gt;data[labels-&gt;write+4] = start</span> <span id="L216" class="LineNr">216 </span> 8b/-&gt; *(ebp+0x10) 0/r32/eax <span id="L217" class="LineNr">217 </span> 89/&lt;- *(esi+ecx+0x10) 0/r32/eax <span id="L218" class="LineNr">218 </span> <span class="subxComment"># labels-&gt;data[labels-&gt;write+8] = end</span> <span id="L219" class="LineNr">219 </span> 8b/-&gt; *(ebp+0x14) 0/r32/eax <span id="L220" class="LineNr">220 </span> 89/&lt;- *(esi+ecx+0x14) 0/r32/eax <span id="L221" class="LineNr">221 </span> <span class="subxComment"># labels-&gt;write += 12</span> <span id="L222" class="LineNr">222 </span> 81 0/subop/add *esi 0xc/imm32 <span id="L223" class="LineNr">223 </span><span class="Constant">$label-append:end</span>: <span id="L224" class="LineNr">224 </span> <span class="subxS1Comment"># . restore registers</span> <span id="L225" class="LineNr">225 </span> 5e/pop-to-esi <span id="L226" class="LineNr">226 </span> 59/pop-to-ecx <span id="L227" class="LineNr">227 </span> 58/pop-to-eax <span id="L228" class="LineNr">228 </span> <span class="subxS1Comment"># . epilogue</span> <span id="L229" class="LineNr">229 </span> 89/&lt;- %esp 5/r32/ebp <span id="L230" class="LineNr">230 </span> 5d/pop-to-ebp <span id="L231" class="LineNr">231 </span> c3/return <span id="L232" class="LineNr">232 </span> <span id="L233" class="LineNr">233 </span><span class="subxFunction">containing-function</span>: <span class="subxComment"># labels: (addr stream {start-address, label-slice}), address: int -&gt; start/eax: (addr byte), end/ecx: (addr byte)</span> <span id="L234" class="LineNr">234 </span> <span class="subxS1Comment"># . prologue</span> <span id="L235" class="LineNr">235 </span> 55/push-ebp <span id="L236" class="LineNr">236 </span> 89/&lt;- %ebp 4/r32/esp <span id="L237" class="LineNr">237 </span> <span class="subxS1Comment"># . save registers</span> <span id="L238" class="LineNr">238 </span> 52/push-edx <span id="L239" class="LineNr">239 </span> 53/push-ebx <span id="L240" class="LineNr">240 </span> 56/push-esi <span id="L241" class="LineNr">241 </span> <span class="subxComment"># esi = labels</span> <span id="L242" class="LineNr">242 </span> 8b/-&gt; *(ebp+8) 6/r32/esi <span id="L243" class="LineNr">243 </span> <span class="subxComment"># var curr/ecx: (addr byte) = labels-&gt;data</span> <span id="L244" class="LineNr">244 </span> 8d/copy-address *(esi+0xc) 1/r32/ecx <span id="L245" class="LineNr">245 </span> <span class="subxComment"># var max/edx: (addr byte) = labels-&gt;data + labels-&gt;write</span> <span id="L246" class="LineNr">246 </span> 8b/-&gt; *esi 2/r32/edx <span id="L247" class="LineNr">247 </span> 01/add-to %edx 1/r32/ecx <span id="L248" class="LineNr">248 </span> <span class="subxComment"># var previous-function-name/ebx: (addr slice) = 0</span> <span id="L249" class="LineNr">249 </span> bb/copy-to-ebx 0/imm32 <span id="L250" class="LineNr">250 </span> { <span id="L251" class="LineNr">251 </span> <span class="subxComment"># abort if not found</span> <span id="L252" class="LineNr">252 </span> 39/compare %ecx 2/r32/edx <span id="L253" class="LineNr">253 </span> { <span id="L254" class="LineNr">254 </span> 0f 82/jump-if-addr&lt; <span class="Constant">break</span>/disp32 <span id="L255" class="LineNr">255 </span> (<a href='501draw-text.mu.html#L332'>draw-text-wrapping-right-then-down-from-cursor-over-full-screen</a> 0 <span class="Constant">&quot;failed to find function for address &quot;</span> 7 0) <span id="L256" class="LineNr">256 </span> (<a href='501draw-text.mu.html#L387'>draw-int32-hex-wrapping-right-then-down-from-cursor-over-full-screen</a> 0 *(ebp+0xc) 7 0) <span id="L257" class="LineNr">257 </span> { <span id="L258" class="LineNr">258 </span> eb/jump <span class="Constant">loop</span>/disp8 <span id="L259" class="LineNr">259 </span> } <span id="L260" class="LineNr">260 </span> } <span id="L261" class="LineNr">261 </span> <span class="subxComment"># if *curr &gt; address, break</span> <span id="L262" class="LineNr">262 </span> 8b/-&gt; *ecx 0/r32/eax <span id="L263" class="LineNr">263 </span> 3b/compare 0/r32/eax *(ebp+0xc) <span id="L264" class="LineNr">264 </span> 0f 87/jump-if-addr&gt; <span class="Constant">break</span>/disp32 <span id="L265" class="LineNr">265 </span> <span class="subxComment"># if **(curr+4) not '$' or '@', save curr to previous-function-name</span> <span id="L266" class="LineNr">266 </span> { <span id="L267" class="LineNr">267 </span> 8b/-&gt; *(ecx+4) 0/r32/eax <span id="L268" class="LineNr">268 </span> 8a/byte-&gt; *eax 0/r32/eax <span id="L269" class="LineNr">269 </span> 25/and-with-eax 0xff/imm32 <span id="L270" class="LineNr">270 </span> 3d/compare-eax-and 0x24/imm32/$ <span id="L271" class="LineNr">271 </span> 74/jump-if-= <span class="Constant">break</span>/disp8 <span id="L272" class="LineNr">272 </span> 3d/compare-eax-and 0x40/imm32/@ <span id="L273" class="LineNr">273 </span> 74/jump-if-= <span class="Constant">break</span>/disp8 <span id="L274" class="LineNr">274 </span> 8d/copy-address *(ecx+4) 3/r32/ebx <span id="L275" class="LineNr">275 </span> } <span id="L276" class="LineNr">276 </span> <span class="subxComment"># loop update</span> <span id="L277" class="LineNr">277 </span> 81 0/subop/add %ecx 0xc/imm32 <span id="L278" class="LineNr">278 </span> <span class="subxComment">#</span> <span id="L279" class="LineNr">279 </span> e9/jump <span class="Constant">loop</span>/disp32 <span id="L280" class="LineNr">280 </span> } <span id="L281" class="LineNr">281 </span> 8b/-&gt; *ebx 0/r32/eax <span id="L282" class="LineNr">282 </span> 8b/-&gt; *(ebx+4) 1/r32/ecx <span id="L283" class="LineNr">283 </span><span class="Constant">$containing-function:end</span>: <span id="L284" class="LineNr">284 </span> <span class="subxS1Comment"># . restore registers</span> <span id="L285" class="LineNr">285 </span> 5e/pop-to-esi <span id="L286" class="LineNr">286 </span> 5b/pop-to-ebx <span id="L287" class="LineNr">287 </span> 5a/pop-to-edx <span id="L288" class="LineNr">288 </span> <span class="subxS1Comment"># . epilogue</span> <span id="L289" class="LineNr">289 </span> 89/&lt;- %esp 5/r32/ebp <span id="L290" class="LineNr">290 </span> 5d/pop-to-ebp <span id="L291" class="LineNr">291 </span> c3/return <span id="L292" class="LineNr">292 </span> <span id="L293" class="LineNr">293 </span><span class="subxComment"># unlike variants in .mu files, this only supports ASCII</span> <span id="L294" class="LineNr">294 </span><span class="subxFunction">draw-slice-wrapping-right-then-down-from-cursor-over-full-screen</span>: <span class="subxComment"># screen: (addr screen), start: (addr byte), end: (addr byte), color: int, background-color: int</span> <span id="L295" class="LineNr">295 </span> <span class="subxS1Comment"># . prologue</span> <span id="L296" class="LineNr">296 </span> 55/push-ebp <span id="L297" class="LineNr">297 </span> 89/&lt;- %ebp 4/r32/esp <span id="L298" class="LineNr">298 </span> <span class="subxS1Comment"># . save registers</span> <span id="L299" class="LineNr">299 </span> 50/push-eax <span id="L300" class="LineNr">300 </span> 51/push-ecx <span id="L301" class="LineNr">301 </span> 52/push-edx <span id="L302" class="LineNr">302 </span> <span class="subxComment"># var curr/ecx: (addr byte) = start</span> <span id="L303" class="LineNr">303 </span> 8b/-&gt; *(ebp+0xc) 1/r32/ecx <span id="L304" class="LineNr">304 </span> <span class="subxComment"># edx = end</span> <span id="L305" class="LineNr">305 </span> 8b/-&gt; *(ebp+0x10) 2/r32/edx <span id="L306" class="LineNr">306 </span> <span class="subxComment"># eax = 0</span> <span id="L307" class="LineNr">307 </span> b8/copy-to-eax 0/imm32 <span id="L308" class="LineNr">308 </span> { <span id="L309" class="LineNr">309 </span> <span class="subxComment"># if (curr &gt;= end) break</span> <span id="L310" class="LineNr">310 </span> 39/compare %ecx 2/r32/edx <span id="L311" class="LineNr">311 </span> 73/jump-if-addr&gt;= <span class="Constant">break</span>/disp8 <span id="L312" class="LineNr">312 </span> <span class="subxComment"># print *curr</span> <span id="L313" class="LineNr">313 </span> 8a/byte-&gt; *ecx 0/r32/eax <span id="L314" class="LineNr">314 </span> (<a href='501draw-text.mu.html#L84'>draw-code-point-at-cursor-over-full-screen</a> *(ebp+8) %eax *(ebp+0x14) *(ebp+0x18)) <span id="L315" class="LineNr">315 </span> <span class="subxComment">#</span> <span id="L316" class="LineNr">316 </span> 41/increment-ecx <span id="L317" class="LineNr">317 </span> <span class="subxComment">#</span> <span id="L318" class="LineNr">318 </span> eb/jump <span class="Constant">loop</span>/disp8 <span id="L319" class="LineNr">319 </span> } <span id="L320" class="LineNr">320 </span><span class="Constant">$draw-slice-wrapping-right-then-down-from-cursor-over-full-screen:end</span>: <span id="L321" class="LineNr">321 </span> <span class="subxS1Comment"># . restore registers</span> <span id="L322" class="LineNr">322 </span> 5a/pop-to-edx <span id="L323" class="LineNr">323 </span> 59/pop-to-ecx <span id="L324" class="LineNr">324 </span> 58/pop-to-eax <span id="L325" class="LineNr">325 </span> <span class="subxS1Comment"># . epilogue</span> <span id="L326" class="LineNr">326 </span> 89/&lt;- %esp 5/r32/ebp <span id="L327" class="LineNr">327 </span> 5d/pop-to-ebp <span id="L328" class="LineNr">328 </span> c3/return </pre> </body> </html> <!-- vim: set foldmethod=manual : -->