https://github.com/akkartik/mu/blob/master/061read-byte.subx
  1 # read-byte-buffered: one higher-level abstraction atop 'read'.
  2 #
  3 # There are many situations where 'read' is a lot to manage, and we need
  4 # to abstract some details away. One of them is when we want to read a file
  5 # character by character. In this situation we follow C's FILE data structure,
  6 # which manages the underlying file descriptor together with the buffer it
  7 # reads into. We call our version 'buffered-file'. Should be useful with other
  8 # primitives as well, in later layers.
  9 
 10 == data
 11 
 12 # The buffered file for standard input. Also illustrates the layout for
 13 # b

81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 58 # . f->read must now be 0; update its cache at ecx 59 31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx 60 # . eax = read(f->fd, stream = f+4) 61 # . . push args 62 50/push-eax 63 ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi 64 # . . call 65 e8/call read/disp32 66 # . . discard args 67 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 68 # if (eax == 0) return 0xffffffff 69 3d/compare-eax-and 0/imm32 70 75/jump-if-not-equal $read-byte-buffered:from-stream/disp8 71 b8/copy-to-eax 0xffffffff/imm32/Eof 72 eb/jump $read-byte-buffered:end/disp8 73 $read-byte-buffered:from-stream: 74 # read byte from stream 75 # AL = f->data[f->read] 76 31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax 77 8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0x10/disp8 . # copy byte at *(esi+ecx+16) to AL 78 # ++f->read 79 ff 0/subop/increment 1/mod/*+disp8 6/rm32/esi . . . . 8/disp8 . # increment *(esi+8) 80 $read-byte-buffered:end: 81 # . restore registers 82 5e/pop-to-esi 83 59/pop-to-ecx 84 # . epilogue 85 89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp 86 5d/pop-to-ebp 87 c3/return 88 89 # - tests 90 91 test-read-byte-buffered-single: 92 # - check that read-byte-buffered returns first byte of 'file' 93 # setup 94 # . clear-stream(_test-stream) 95 # . . push args 96 68/push _test-stream/imm32 97 # . . call 98 e8/call clear-stream/disp32 99 # . . discard args 100 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 101 # . clear-stream(_test-buffered-file+4) 102 # . . push args 103 b8/copy-to-eax _test-buffered-file/imm32 104 05/add-to-eax 4/imm32 105 50/push-eax 106 # . . call 107 e8/call clear-stream/disp32 108 # . . discard args 109 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 110 # . write(_test-stream, "Ab") 111 # . . push args 112 68/push "Ab"/imm32 113 68/push _test-stream/imm32 114 # . . call 115 e8/call write/disp32 116 # . . discard args 117 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 118 # read-byte-buffered(_test-buffered-file) 119 # . . push args 120 68/push _test-buffered-file/imm32 121 # . . call 122 e8/call read-byte-buffered/disp32 123 # . . discard args 124 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 125 # check-ints-equal(eax, 'A', msg) 126 # . . push args 127 68/push "F - test-read-byte-buffered-single"/imm32 128 68/push 0x41/imm32 129 50/push-eax 130 # . . call 131 e8/call check-ints-equal/disp32 132 # . . discard args 133 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 134 # . end 135 c3/return 136 137 test-read-byte-buffered-multiple: 138 # - call read-byte-buffered twice, check that second call returns second byte 139 # setup 140 # . clear-stream(_test-stream) 141 # . . push args 142 68/push _test-stream/imm32 143 # . . call 144 e8/call clear-stream/disp32 145 # . . discard args 146 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 147 # . clear-stream(_test-buffered-file+4) 148 # . . push args 149 b8/copy-to-eax _test-buffered-file/imm32 150 05/add-to-eax 4/imm32 151 50/push-eax 152 # . . call 153 e8/call clear-stream/disp32 154 # . . discard args 155 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 156 # . write(_test-stream, "Ab") 157 # . . push args 158 68/push "Ab"/imm32 159 68/push _test-stream/imm32 160 # . . call 161 e8/call write/disp32 162 # . . discard args 163 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 164 # read-byte-buffered(_test-buffered-file) 165 # . . push args 166 68/push _test-buffered-file/imm32 167 # . . call 168 e8/call read-byte-buffered/disp32 169 # . . discard args 170 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 171 # read-byte-buffered(_test-buffered-file) 172 # . . push args 173 68/push _test-buffered-file/imm32 174 # . . call 175 e8/call read-byte-buffered/disp32 176 # . . discard args 177 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 178 # check-ints-equal(eax, 'b', msg) 179 # . . push args 180 68/push "F - test-read-byte-buffered-multiple"/imm32 181 68/push 0x62/imm32 182 50/push-eax 183 # . . call 184 e8/call check-ints-equal/disp32 185 # . . discard args 186 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 187 # . end 188 c3/return 189 190 test-read-byte-buffered-end-of-file: 191 # - call read-byte-buffered on an empty 'file', check that it returns Eof 192 # setup 193 # . clear-stream(_test-stream) 194 # . . push args 195 68/push _test-stream/imm32 196 # . . call 197 e8/call clear-stream/disp32 198 # . . discard args 199 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 200 # . clear-stream(_test-buffered-file+4) 201 # . . push args 202 b8/copy-to-eax _test-buffered-file/imm32 203 05/add-to-eax 4/imm32 204 50/push-eax 205 # . . call 206 e8/call clear-stream/disp32 207 # . . discard args 208 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 209 # read-byte-buffered(_test-buffered-file) 210 # . . push args 211 68/push _test-buffered-file/imm32 212 # . . call 213 e8/call read-byte-buffered/disp32 214 # . . discard args 215 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 216 # check-ints-equal(eax, 0xffffffff, msg) 217 # . . push args 218 68/push "F - test-read-byte-buffered-end-of-file"/imm32 219 68/push 0xffffffff/imm32/Eof 220 50/push-eax 221 # . . call 222 e8/call check-ints-equal/disp32 223 # . . discard args 224 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 225 # . end 226 c3/return 227 228 test-read-byte-buffered-refills-buffer: 229 # - consume buffered-file's buffer, check that next read-byte-buffered still works 230 # setup 231 # . clear-stream(_test-stream) 232 # . . push args 233 68/push _test-stream/imm32 234 # . . call 235 e8/call clear-stream/disp32 236 # . . discard args 237 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 238 # . clear-stream(_test-buffered-file+4) 239 # . . push args 240 b8/copy-to-eax _test-buffered-file/imm32 241 05/add-to-eax 4/imm32 242 50/push-eax 243 # . . call 244 e8/call clear-stream/disp32 245 # . . discard args 246 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 247 # . write(_test-stream, "Abcdefgh") 248 # . . push args 249 68/push "Abcdefgh"/imm32 250 68/push _test-stream/imm32 251 # . . call 252 e8/call write/disp32 253 # . . discard args 254 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp 255 # pretend buffer is full 256 # . _test-buffered-file->read = 6 # >= _test-buffered-file->length 257 b8/copy-to-eax _test-buffered-file/imm32 258 c7 0/subop/copy 1/mod/*+disp8 0/rm32/eax . . . . 8/disp8 6/imm32 # copy to *(eax+8) 259 # read-byte-buffered(_test-buffered-file) 260 # . . push args 261 68/push _test-buffered-file/imm32 262 # . . call 263 e8/call read-byte-buffered/disp32 264 # . . discard args 265 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp 266 # check-ints-equal(eax, 'A', msg) 267 # . . push args 268 68/push "F - test-read-byte-buffered-refills-buffer"/imm32 269 68/push 0x41/imm32 270 50/push-eax 271 # . . call 272 e8/call check-ints-equal/disp32 273 # . . discard args 274 81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp 275 # . end 276 c3/return 277 278 == data 279 280 # a test buffered file for _test-stream 281 _test-buffered-file: 282 # file descriptor or (address stream) 283 _test-stream/imm32 284 # current write index 285 0/imm32 286 # current read index 287 0/imm32 288 # length 289 6/imm32 290 # data 291 00 00 00 00 00 00 # 6 bytes 292 293 _test-input-stream: 294 # current write index 295 0/imm32 296 # current read index 297 0/imm32 298 # length 299 0x100/imm32 # 256 bytes 300 # data (16 lines x 16 bytes/line) 301 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 302 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 303 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 304 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 305 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 306 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 307 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 308 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 309 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 310 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 311 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 312 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 313 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 314 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 315 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 316 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 317 318 # a test buffered file for _test-input-stream 319 _test-input-buffered-file: 320 # file descriptor or (address stream) 321 _test-input-stream/imm32 322 # current write index 323 0/imm32 324 # current read index 325 0/imm32 326 # length 327 6/imm32 328 # data 329 00 00 00 00 00 00 # 6 bytes 330 331 # . . vim:nowrap:textwidth=0