about summary refs log tree commit diff stats
path: root/109stream-equal.subx
blob: 8f6cf1bf9b15bb46ba238c04e25bbcf5c0c25525 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
format 70

classinstance 128258 class_ref 169218 // Main
  name ""   xyz 64 4 2000 life_line_z 2000
classinstance 128386 class_ref 149378 // FM
  name ""   xyz 185 32 2000 life_line_z 2000
classinstance 128898 class_ref 128258 // DefaultUI
  name ""   mortal  xyz 289 80 2000 life_line_z 2000
classinstance 132226 class_ref 149122 // Environment
  name ""   xyz 421 84 2000 life_line_z 2000
classinstance 133122 class_ref 156034 // Widget
  name ""   xyz 544 107 2000 life_line_z 2000
classinstance 133762 class_ref 149250 // curses
  name ""   xyz 632 4 2000 life_line_z 2000
classinstance 134530 class_ref 148866 // Command
  name ""   xyz 727 4 2000 life_line_z 2000
note 136962 "This is outdated."
  xyzwh 352 23 2000 145 35
durationcanvas 128514 classinstance_ref 128258 // :Main
  xyzwh 83 82 2010 11 40
end
durationcanvas 128642 classinstance_ref 128386 // :FM
  xyzwh 204 82 2010 11 25
end
durationcanvas 129026 classinstance_ref 128258 // :Main
  xyzwh 83 130 2010 11 34
end
durationcanvas 129154 classinstance_ref 128898 // :DefaultUI
  xyzwh 325 130 2010 11 58
  overlappingdurationcanvas 135426
    xyzwh 331 142 2020 11 40
    overlappingdurationcanvas 135682
      xyzwh 337 151 2030 11 25
    end
  end
end
durationcanvas 129410 classinstance_ref 128258 // :Main
  xyzwh 83 180 2010 11 35
end
durationcanvas 129538 classinstance_ref 128386 // :FM
  xyzwh 204 172 2010 11 468
  overlappingdurationcanvas 136450
    xyzwh 210 537 2020 11 25
  end
end
durationcanvas 129794 classinstance_ref 128258 // :Main
  xyzwh 83 655 2010 11 27
end
durationcanvas 129922 classinstance_ref 128898 // :DefaultUI
  xyzwh 325 655 2010 11 27
end
durationcanvas 130178 classinstance_ref 128898 // :DefaultUI
  xyzwh 325 265 2010 11 26
end
durationcanvas 130434 classinstance_ref 128898 // :DefaultUI
  xyzwh 325 311 2010 11 26
end
durationcanvas 130690 classinstance_ref 128898 // :DefaultUI
  xyzwh 325 381 2010 11 43
end
durationcanvas 131074 classinstance_ref 128898 // :DefaultUI
  xyzwh 325 467 2010 11 53
  overlappingdurationcanvas 134914
    xyzwh 331 489 2020 11 25
  end
end
durationcanvas 132354 classinstance_ref 132226 // :Environment
  xyzwh 469 606 2010 11 32
end
durationcanvas 132866 classinstance_ref 132226 // :Environment
  xyzwh 469 184 2010 11 27
end
durationcanvas 133250 classinstance_ref 133122 // :Widget
  xyzwh 571 280 2010 11 25
end
durationcanvas 133506 classinstance_ref 133122 // :Widget
  xyzwh 571 323 2010 11 25
end
durationcanvas 133890 classinstance_ref 133762 // :curses
  xyzwh 658 389 2010 11 31
end
durationcanvas 135170 classinstance_ref 133122 // :Widget
  xyzwh 571 501 2010 11 27
end
durationcanvas 135938 classinstance_ref 134530 // :Command
  xyzwh 767 506 2010 11 72
end
durationcanvas 136706 classinstance_ref 133122 // :Widget
  xyzwh 571 563 2010 11 34
end
msg 128770 synchronous
  from durationcanvas_ref 128514
  to durationcanvas_ref 128642
  yz 82 2015 msg operation_ref 141826 // "initialize()"
  show_full_operations_definition default drawing_language default
  label_xy 117 64
msg 129282 synchronous
  from durationcanvas_ref 129026
  to durationcanvas_ref 129154
  yz 130 2015 msg operation_ref 171138 // "initialize()"
  show_full_operations_definition default drawing_language default
  label_xy 124 111
msg 129666 synchronous
  from durationcanvas_ref 129410
  to durationcanvas_ref 129538
  yz 180 2015 msg operation_ref 141954 // "loop()"
  show_full_operations_definition default drawing_language default
  label_xy 129 162
msg 130050 synchronous
  from durationcanvas_ref 129794
  to durationcanvas_ref 129922
  yz 655 2015 msg operation_ref 134914 // "destroy()"
  show_full_operations_definition default drawing_language default
  label_xy 119 636
msg 130306 synchronous
  from durationcanvas_ref 129538
  to durationcanvas_ref 130178
  yz 265 2015 msg operation_ref 134530 // "draw()"
  show_full_operations_definition default drawing_language default
  label_xy 245 247
msg 130562 synchronous
  from durationcanvas_ref 129538
  to durationcanvas_ref 130434
  yz 311 2015 msg operation_ref 149378 // "finalize()"
  show_full_operations_definition default drawing_language default
  label_xy 240 293
msg 130818 synchronous
  from durationcanvas_ref 129538
  to durationcanvas_ref 130690
  yz 382 2015 msg operation_ref 148738 // "get_next_key()"
  show_full_operations_definition default drawing_language default
  label_xy 229 361
msg 130946 return
  from durationcanvas_ref 130690
  to durationcanvas_ref 129538
  yz 412 2020 unspecifiedmsg
  show_full_operations_definition default drawing_language default
msg 131202 synchronous
  from durationcanvas_ref 129538
  to durationcanvas_ref 131074
  yz 467 2015 msg operation_ref 148610 // "handle_key()"
  show_full_operations_definition default drawing_language default
  label_xy 234 449
msg 132482 synchronous
  from durationcanvas_ref 129538
  to durationcanvas_ref 132354
  yz 606 2015 msg operation_ref 171522 // "garbage_collect()"
  show_full_operations_definition default drawing_language default
  label_xy 260 587
msg 132994 synchronous
  from durationcanvas_ref 129538
  to durationcanvas_ref 132866
  yz 185 2020 msg operation_ref 171650 // "enter_dir()"
  show_full_operations_definition default drawing_language default
  label_xy 222 164
msg 133378 synchronous
  from durationcanvas_ref 130178
  to durationcanvas_ref 133250
  yz 280 2015 msg operation_ref 134530 // "draw()"
  show_full_operations_definition default drawing_language default
  label_xy 407 262
msg 133634 synchronous
  from durationcanvas_ref 130434
  to durationcanvas_ref 133506
  yz 323 2015 msg operation_ref 149378 // "finalize()"
  show_full_operations_definition default drawing_language default
  label_xy 405 303
msg 134018 synchronous
  from durationcanvas_ref 130690
  to durationcanvas_ref 133890
  yz 391 2015 msg operation_ref 171778 // "getch()"
  show_full_operations_definition default drawing_language default
  label_xy 713 361
msg 134402 return
  from durationcanvas_ref 133890
  to durationcanvas_ref 130690
  yz 408 2020 unspecifiedmsg
  show_full_operations_definition default drawing_language default
reflexivemsg 135042 synchronous
  to durationcanvas_ref 134914
  yz 489 2025 msg operation_ref 148482 // "handle_mouse()"
  show_full_operations_definition default drawing_language default
  label_xy 345 462
msg 135298 synchronous
  from durationcanvas_ref 134914
  to durationcanvas_ref 135170
  yz 502 2030 msg operation_ref 134786 // "click()"
  show_full_operations_definition default drawing_language default
  label_xy 474 484
reflexivemsg 135554 synchronous
  to durationcanvas_ref 135426
  yz 142 2025 msg operation_ref 148866 // "setup()"
  show_full_operations_definition default drawing_language default
  label_xy 340 120
reflexivemsg 135810 synchronous
  to durationcanvas_ref 135682
  yz 151 2035 msg operation_ref 149890 // "add_obj()"
  show_full_operations_definition default drawing_language default
  label_xy 372 143
msg 136066 synchronous
  from durationcanvas_ref 135170
  to durationcanvas_ref 135938
  yz 506 2015 msg operation_ref 164226 // "execute()"
  show_full_operations_definitio
# some primitives for checking stream contents

== code
#   instruction                     effective address                                                   register    displacement    immediate
# . op          subop               mod             rm32          base        index         scale       r32
# . 1-3 bytes   3 bits              2 bits          3 bits        3 bits      3 bits        2 bits      2 bits      0/1/2/4 bytes   0/1/2/4 bytes

# compare all the data in a stream (ignoring the read pointer)
stream-data-equal?:  # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    52/push-edx
    56/push-esi
    57/push-edi
    # esi = f
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # eax = f->write
    8b/copy                         0/mod/indirect  6/rm32/esi    .           .             .           0/r32/eax   .               .                 # copy *esi to eax
    # var maxf/edx: (addr byte) = &f->data[f->write]
    8d/copy-address                 1/mod/*+disp8   4/rm32/sib    6/base/esi  0/index/eax   .           2/r32/edx   0xc/disp8       .                 # copy esi+eax+12 to edx
    # var currf/esi: (addr byte) = f->data
    81          0/subop/add         3/mod/direct    6/rm32/esi    .           .             .           .           .               0xc/imm32         # add to esi
    # edi = s
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
$stream-data-equal?:compare-sizes:
    # if (f->write != s->size) return false
    39/compare                      0/mod/indirect  7/rm32/edi    .           .             .           0/r32/eax   .               .                 # compare *edi and eax
    75/jump-if-!=  $stream-data-equal?:false/disp8
    # var currs/edi: (addr byte) = s->data
    81          0/subop/add         3/mod/direct    7/rm32/edi    .           .             .           .           .               4/imm32           # add to edi
    # var eax: byte = 0
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    # var ecx: byte = 0
    31/xor                          3/mod/direct    1/rm32/ecx    .           .             .           1/r32/ecx   .               .                 # clear ecx
$stream-data-equal?:loop:
    # if (currf >= maxf) return true
    39/compare                      3/mod/direct    6/rm32/esi    .           .             .           2/r32/edx   .               .                 # compare esi with edx
    73/jump-if-addr>=  $stream-data-equal?:true/disp8
    # AL = *currs
    8a/copy-byte                    0/mod/indirect  6/rm32/esi    .           .             .           0/r32/AL    .               .                 # copy byte at *esi to AL
    # CL = *curr
    8a/copy-byte                    0/mod/indirect  7/rm32/edi    .           .             .           1/r32/CL    .               .                 # copy byte at *edi to CL
    # if (eax != ecx) return false
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           1/r32/ecx   .               .                 # compare eax and ecx
    75/jump-if-!=  $stream-data-equal?:false/disp8
    # ++f
    46/increment-esi
    # ++curr
    47/increment-edi
    eb/jump $stream-data-equal?:loop/disp8
$stream-data-equal?:false:
    b8/copy-to-eax  0/imm32
    eb/jump  $stream-data-equal?:end/disp8
$stream-data-equal?:true:
    b8/copy-to-eax  1/imm32
$stream-data-equal?:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-stream-data-equal:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # write(_test-stream, "Abc")
    # . . push args
    68/push  "Abc"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = stream-data-equal?(_test-stream, "Abc")
    # . . push args
    68/push  "Abc"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  stream-data-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-stream-data-equal"/imm32
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-stream-data-equal-2:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # write(_test-stream, "Abc")
    # . . push args
    68/push  "Abc"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = stream-data-equal?(_test-stream, "Abd")
    # . . push args
    68/push  "Abd"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  stream-data-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-stream-data-equal-2"/imm32
    68/push  0/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-stream-data-equal-size-check:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # write(_test-stream, "Abc")
    # . . push args
    68/push  "Abc"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = stream-data-equal?(_test-stream, "Abcd")
    # . . push args
    68/push  "Abcd"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  stream-data-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-stream-data-equal-size-check"/imm32
    68/push  0/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# helper for later tests
check-stream-equal:  # f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    # eax = stream-data-equal?(f, s)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  stream-data-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
$check-stream-equal:end:
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# scan the next line until newline starting from f->read and compare it with
# 's' (ignoring the trailing newline)
# on success, set f->read to after the next newline
# on failure, leave f->read unmodified
# this function is usually used only in tests, so we repeatedly write f->read
next-stream-line-equal?:  # f: (addr stream byte), s: (addr array byte) -> result/eax: boolean
    # pseudocode:
    #   currf = f->read  # bound: f->write
    #   currs = 0  # bound: s->size
    #   while true
    #     if currf >= f->write
    #       return currs >= s->size
    #     if f[currf] == '\n'
    #       ++currf
    #       return currs >= s->size
    #     if (currs >= s->size) return false  # the current line of f still has data to match
    #     if (f[currf] != s[currs]) return false
    #     ++currf
    #     ++currs
    #
    # collapsing the two branches that can return true:
    #   currf = f->read  # bound: f->write
    #   currs = 0  # bound: s->size
    #   while true
    #     if (currf >= f->write) break
    #     if (f[currf] == '\n') break
    #     if (currs >= s->size) return false  # the current line of f still has data to match
    #     if (f[currf] != s[currs]) return false
    #     ++currf
    #     ++currs
    #   ++currf  # skip '\n'
    #   return currs >= s->size
    # Here the final `++currf` is sometimes unnecessary (if we're already at the end of the stream)
    #
    # registers:
    #   f: esi
    #   s: edi
    #   currf: ecx
    #   currs: edx
    #   f[currf]: eax
    #   s[currs]: ebx
    #
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    51/push-ecx
    52/push-edx
    56/push-esi
    57/push-edi
    # esi = f
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           6/r32/esi   8/disp8         .                 # copy *(ebp+8) to esi
    # var currf/ecx: int = f->read
    8b/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy *(esi+4) to ecx
    # edi = s
    8b/copy                         1/mod/*+disp8   5/rm32/ebp    .           .             .           7/r32/edi   0xc/disp8       .                 # copy *(ebp+12) to edi
    # var currs/edx: int = 0
    31/xor                          3/mod/direct    2/rm32/edx    .           .             .           2/r32/edx   .               .                 # clear edx
    # var c1/eax: byte = 0
    31/xor                          3/mod/direct    0/rm32/eax    .           .             .           0/r32/eax   .               .                 # clear eax
    # var c2/ebx: byte = 0
    31/xor                          3/mod/direct    3/rm32/ebx    .           .             .           3/r32/ebx   .               .                 # clear ebx
$next-stream-line-equal?:loop:
    # if (currf >= f->write) break
    3b/compare                      0/mod/indirect  6/rm32/esi    .           .             .           1/r32/ecx   .               .                 # compare ecx with *esi
    7d/jump-if->=  $next-stream-line-equal?:break/disp8
    # c1 = f->data[f->read]
    8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    6/base/esi  1/index/ecx   .           0/r32/AL    0xc/disp8       .                 # copy byte at *(esi+ecx+12) to AL
    # if (c1 == '\n') break
    3d/compare-eax-and  0xa/imm32/newline
    74/jump-if-=  $next-stream-line-equal?:break/disp8
    # if (currs >= s->size) return false
    3b/compare                      0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edx with *edi
    7d/jump-if->=  $next-stream-line-equal?:false/disp8
    # c2 = s->data[currs]
    8a/copy-byte                    1/mod/*+disp8   4/rm32/sib    7/base/edi  2/index/edx   .           3/r32/BL    4/disp8         .                 # copy byte at *(edi+edx+4) to BL
    # if (c1 != c2) return false
    39/compare                      3/mod/direct    0/rm32/eax    .           .             .           3/r32/ebx   .               .                 # compare eax and ebx
    75/jump-if-!=  $next-stream-line-equal?:false/disp8
    # ++currf
    41/increment-ecx
    # ++currs
    42/increment-edx
    eb/jump $next-stream-line-equal?:loop/disp8
$next-stream-line-equal?:break:
    # ++currf
    41/increment-ecx
    # if (currs >= s->size) return true
    3b/compare                      0/mod/indirect  7/rm32/edi    .           .             .           2/r32/edx   .               .                 # compare edx with *edi
    7c/jump-if-<  $next-stream-line-equal?:false/disp8
$next-stream-line-equal?:true:
    b8/copy-to-eax  1/imm32
    # persist f->read on success
    89/copy                         1/mod/*+disp8   6/rm32/esi    .           .             .           1/r32/ecx   4/disp8         .                 # copy ecx to *(esi+4)
    eb/jump  $next-stream-line-equal?:end/disp8
$next-stream-line-equal?:false:
    b8/copy-to-eax  0/imm32
$next-stream-line-equal?:end:
    # . restore registers
    5f/pop-to-edi
    5e/pop-to-esi
    5a/pop-to-edx
    59/pop-to-ecx
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-stream-line-equal-stops-at-newline:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # write(_test-stream, "Abc\ndef")
    # . . push args
    68/push  "Abc\ndef"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = next-stream-line-equal?(_test-stream, "Abc")
    # . . push args
    68/push  "Abc"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-next-stream-line-equal-stops-at-newline"/imm32
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-stream-line-equal-stops-at-newline-2:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # write(_test-stream, "Abc\ndef")
    # . . push args
    68/push  "Abc\ndef"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = next-stream-line-equal?(_test-stream, "def")
    # . . push args
    68/push  "def"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-next-stream-line-equal-stops-at-newline-2"/imm32
    68/push  0/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-stream-line-equal-skips-newline:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # write(_test-stream, "Abc\ndef\n")
    # . . push args
    68/push  "Abc\ndef\n"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # next-stream-line-equal?(_test-stream, "Abc")
    # . . push args
    68/push  "Abc"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = next-stream-line-equal?(_test-stream, "def")
    # . . push args
    68/push  "def"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-next-stream-line-equal-skips-newline"/imm32
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-stream-line-equal-handles-final-line:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # write(_test-stream, "Abc\ndef")
    # . . push args
    68/push  "Abc\ndef"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  write/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # next-stream-line-equal?(_test-stream, "Abc")
    # . . push args
    68/push  "Abc"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # eax = next-stream-line-equal?(_test-stream, "def")
    # . . push args
    68/push  "def"/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    68/push  "F - test-next-stream-line-equal-skips-newline"/imm32
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

test-next-stream-line-equal-always-fails-after-Eof:
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # clear-stream(_test-stream)
    # . . push args
    68/push  _test-stream/imm32
    # . . call
    e8/call  clear-stream/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               4/imm32           # add to esp
    # write nothing
    # eax = next-stream-line-equal?(_test-stream, "")
    # . . push args
    68/push  ""/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-next-stream-line-equal-always-fails-after-Eof"/imm32
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # eax = next-stream-line-equal?(_test-stream, "")
    # . . push args
    68/push  ""/imm32
    68/push  _test-stream/imm32
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 0, msg)
    # . . push args
    68/push  "F - test-next-stream-line-equal-always-fails-after-Eof/2"/imm32
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# helper for later tests
check-next-stream-line-equal:  # f: (addr stream byte), s: (addr array byte), msg: (addr array byte)
    # . prologue
    55/push-ebp
    89/copy                         3/mod/direct    5/rm32/ebp    .           .             .           4/r32/esp   .               .                 # copy esp to ebp
    # . save registers
    50/push-eax
    # eax = next-stream-line-equal?(f, s)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0xc/disp8       .                 # push *(ebp+12)
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           8/disp8         .                 # push *(ebp+8)
    # . . call
    e8/call  next-stream-line-equal?/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               8/imm32           # add to esp
    # check-ints-equal(eax, 1, msg)
    # . . push args
    ff          6/subop/push        1/mod/*+disp8   5/rm32/ebp    .           .             .           .           0x10/disp8      .                 # push *(ebp+16)
    68/push  1/imm32
    50/push-eax
    # . . call
    e8/call  check-ints-equal/disp32
    # . . discard args
    81          0/subop/add         3/mod/direct    4/rm32/esp    .           .             .           .           .               0xc/imm32         # add to esp
    # . restore registers
    58/pop-to-eax
    # . epilogue
    89/copy                         3/mod/direct    4/rm32/esp    .           .             .           5/r32/ebp   .               .                 # copy ebp to esp
    5d/pop-to-ebp
    c3/return

# . . vim:nowrap:textwidth=0