1# 2# 3# Nim's Runtime Library 4# (c) Copyright 2015 Andreas Rumpf 5# 6# See the file "copying.txt", included in this 7# distribution, for details about the copyright. 8# 9 10## This module provides a stream interface and two implementations thereof: 11## the `FileStream <#FileStream>`_ and the `StringStream <#StringStream>`_ 12## which implement the stream interface for Nim file objects (`File`) and 13## strings. 14## 15## Other modules may provide other implementations for this standard 16## stream interface. 17## 18## Basic usage 19## =========== 20## 21## The basic flow of using this module is: 22## 23## 1. Open input stream 24## 2. Read or write stream 25## 3. Close stream 26## 27## StringStream example 28## -------------------- 29## 30## .. code-block:: Nim 31## 32## import std/streams 33## 34## var strm = newStringStream("""The first line 35## the second line 36## the third line""") 37## 38## var line = "" 39## 40## while strm.readLine(line): 41## echo line 42## 43## # Output: 44## # The first line 45## # the second line 46## # the third line 47## 48## strm.close() 49## 50## FileStream example 51## ------------------ 52## 53## Write file stream example: 54## 55## .. code-block:: Nim 56## 57## import std/streams 58## 59## var strm = newFileStream("somefile.txt", fmWrite) 60## var line = "" 61## 62## if not isNil(strm): 63## strm.writeLine("The first line") 64## strm.writeLine("the second line") 65## strm.writeLine("the third line") 66## strm.close() 67## 68## # Output (somefile.txt): 69## # The first line 70## # the second line 71## # the third line 72## 73## Read file stream example: 74## 75## .. code-block:: Nim 76## 77## import std/streams 78## 79## var strm = newFileStream("somefile.txt", fmRead) 80## var line = "" 81## 82## if not isNil(strm): 83## while strm.readLine(line): 84## echo line 85## strm.close() 86## 87## # Output: 88## # The first line 89## # the second line 90## # the third line 91## 92## See also 93## ======== 94## * `asyncstreams module <asyncstreams.html>`_ 95## * `io module <io.html>`_ for `FileMode enum <io.html#FileMode>`_ 96 97import std/private/since 98 99proc newEIO(msg: string): owned(ref IOError) = 100 new(result) 101 result.msg = msg 102 103type 104 Stream* = ref StreamObj 105 ## All procedures of this module use this type. 106 ## Procedures don't directly use `StreamObj <#StreamObj>`_. 107 StreamObj* = object of RootObj 108 ## Stream interface that supports writing or reading. 109 ## 110 ## **Note:** 111 ## * That these fields here shouldn't be used directly. 112 ## They are accessible so that a stream implementation can override them. 113 closeImpl*: proc (s: Stream) 114 {.nimcall, raises: [Exception, IOError, OSError], tags: [WriteIOEffect], gcsafe.} 115 atEndImpl*: proc (s: Stream): bool 116 {.nimcall, raises: [Defect, IOError, OSError], tags: [], gcsafe.} 117 setPositionImpl*: proc (s: Stream, pos: int) 118 {.nimcall, raises: [Defect, IOError, OSError], tags: [], gcsafe.} 119 getPositionImpl*: proc (s: Stream): int 120 {.nimcall, raises: [Defect, IOError, OSError], tags: [], gcsafe.} 121 122 readDataStrImpl*: proc (s: Stream, buffer: var string, slice: Slice[int]): int 123 {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.} 124 125 readLineImpl*: proc(s: Stream, line: var string): bool 126 {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.} 127 128 readDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int): int 129 {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.} 130 peekDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int): int 131 {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.} 132 writeDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int) 133 {.nimcall, raises: [Defect, IOError, OSError], tags: [WriteIOEffect], gcsafe.} 134 135 flushImpl*: proc (s: Stream) 136 {.nimcall, raises: [Defect, IOError, OSError], tags: [WriteIOEffect], gcsafe.} 137 138proc flush*(s: Stream) = 139 ## Flushes the buffers that the stream `s` might use. 140 ## 141 ## This procedure causes any unwritten data for that stream to be delivered 142 ## to the host environment to be written to the file. 143 ## 144 ## See also: 145 ## * `close proc <#close,Stream>`_ 146 runnableExamples: 147 from std/os import removeFile 148 149 var strm = newFileStream("somefile.txt", fmWrite) 150 151 doAssert "Before write:" & readFile("somefile.txt") == "Before write:" 152 strm.write("hello") 153 doAssert "After write:" & readFile("somefile.txt") == "After write:" 154 155 strm.flush() 156 doAssert "After flush:" & readFile("somefile.txt") == "After flush:hello" 157 strm.write("HELLO") 158 strm.flush() 159 doAssert "After flush:" & readFile("somefile.txt") == "After flush:helloHELLO" 160 161 strm.close() 162 doAssert "After close:" & readFile("somefile.txt") == "After close:helloHELLO" 163 removeFile("somefile.txt") 164 165 if not isNil(s.flushImpl): s.flushImpl(s) 166 167proc close*(s: Stream) = 168 ## Closes the stream `s`. 169 ## 170 ## See also: 171 ## * `flush proc <#flush,Stream>`_ 172 runnableExamples: 173 var strm = newStringStream("The first line\nthe second line\nthe third line") 174 ## do something... 175 strm.close() 176 if not isNil(s.closeImpl): s.closeImpl(s) 177 178proc atEnd*(s: Stream): bool = 179 ## Checks if more data can be read from `s`. Returns ``true`` if all data has 180 ## been read. 181 runnableExamples: 182 var strm = newStringStream("The first line\nthe second line\nthe third line") 183 var line = "" 184 doAssert strm.atEnd() == false 185 while strm.readLine(line): 186 discard 187 doAssert strm.atEnd() == true 188 strm.close() 189 190 result = s.atEndImpl(s) 191 192proc setPosition*(s: Stream, pos: int) = 193 ## Sets the position `pos` of the stream `s`. 194 runnableExamples: 195 var strm = newStringStream("The first line\nthe second line\nthe third line") 196 strm.setPosition(4) 197 doAssert strm.readLine() == "first line" 198 strm.setPosition(0) 199 doAssert strm.readLine() == "The first line" 200 strm.close() 201 202 s.setPositionImpl(s, pos) 203 204proc getPosition*(s: Stream): int = 205 ## Retrieves the current position in the stream `s`. 206 runnableExamples: 207 var strm = newStringStream("The first line\nthe second line\nthe third line") 208 doAssert strm.getPosition() == 0 209 discard strm.readLine() 210 doAssert strm.getPosition() == 15 211 strm.close() 212 213 result = s.getPositionImpl(s) 214 215proc readData*(s: Stream, buffer: pointer, bufLen: int): int = 216 ## Low level proc that reads data into an untyped `buffer` of `bufLen` size. 217 ## 218 ## **JS note:** `buffer` is treated as a ``ptr string`` and written to between 219 ## ``0..<bufLen``. 220 runnableExamples: 221 var strm = newStringStream("abcde") 222 var buffer: array[6, char] 223 doAssert strm.readData(addr(buffer), 1024) == 5 224 doAssert buffer == ['a', 'b', 'c', 'd', 'e', '\x00'] 225 doAssert strm.atEnd() == true 226 strm.close() 227 228 result = s.readDataImpl(s, buffer, bufLen) 229 230proc readDataStr*(s: Stream, buffer: var string, slice: Slice[int]): int = 231 ## Low level proc that reads data into a string ``buffer`` at ``slice``. 232 runnableExamples: 233 var strm = newStringStream("abcde") 234 var buffer = "12345" 235 doAssert strm.readDataStr(buffer, 0..3) == 4 236 doAssert buffer == "abcd5" 237 strm.close() 238 239 if s.readDataStrImpl != nil: 240 result = s.readDataStrImpl(s, buffer, slice) 241 else: 242 # fallback 243 result = s.readData(addr buffer[slice.a], slice.b + 1 - slice.a) 244 245template jsOrVmBlock(caseJsOrVm, caseElse: untyped): untyped = 246 when nimvm: 247 block: 248 caseJsOrVm 249 else: 250 block: 251 when defined(js) or defined(nimscript): 252 # nimscript has to be here to avoid semantic checking of caseElse 253 caseJsOrVm 254 else: 255 caseElse 256 257when (NimMajor, NimMinor) >= (1, 3) or not defined(js): 258 proc readAll*(s: Stream): string = 259 ## Reads all available data. 260 runnableExamples: 261 var strm = newStringStream("The first line\nthe second line\nthe third line") 262 doAssert strm.readAll() == "The first line\nthe second line\nthe third line" 263 doAssert strm.atEnd() == true 264 strm.close() 265 266 const bufferSize = 1024 267 jsOrVmBlock: 268 var buffer2: string 269 buffer2.setLen(bufferSize) 270 while true: 271 let readBytes = readDataStr(s, buffer2, 0..<bufferSize) 272 if readBytes == 0: 273 break 274 let prevLen = result.len 275 result.setLen(prevLen + readBytes) 276 result[prevLen..<prevLen+readBytes] = buffer2[0..<readBytes] 277 if readBytes < bufferSize: 278 break 279 do: # not JS or VM 280 var buffer {.noinit.}: array[bufferSize, char] 281 while true: 282 let readBytes = readData(s, addr(buffer[0]), bufferSize) 283 if readBytes == 0: 284 break 285 let prevLen = result.len 286 result.setLen(prevLen + readBytes) 287 copyMem(addr(result[prevLen]), addr(buffer[0]), readBytes) 288 if readBytes < bufferSize: 289 break 290 291proc peekData*(s: Stream, buffer: pointer, bufLen: int): int = 292 ## Low level proc that reads data into an untyped `buffer` of `bufLen` size 293 ## without moving stream position. 294 ## 295 ## **JS note:** `buffer` is treated as a ``ptr string`` and written to between 296 ## ``0..<bufLen``. 297 runnableExamples: 298 var strm = newStringStream("abcde") 299 var buffer: array[6, char] 300 doAssert strm.peekData(addr(buffer), 1024) == 5 301 doAssert buffer == ['a', 'b', 'c', 'd', 'e', '\x00'] 302 doAssert strm.atEnd() == false 303 strm.close() 304 305 result = s.peekDataImpl(s, buffer, bufLen) 306 307proc writeData*(s: Stream, buffer: pointer, bufLen: int) = 308 ## Low level proc that writes an untyped `buffer` of `bufLen` size 309 ## to the stream `s`. 310 ## 311 ## **JS note:** `buffer` is treated as a ``ptr string`` and read between 312 ## ``0..<bufLen``. 313 runnableExamples: 314 ## writeData 315 var strm = newStringStream("") 316 var buffer = ['a', 'b', 'c', 'd', 'e'] 317 strm.writeData(addr(buffer), sizeof(buffer)) 318 doAssert strm.atEnd() == true 319 ## readData 320 strm.setPosition(0) 321 var buffer2: array[6, char] 322 doAssert strm.readData(addr(buffer2), sizeof(buffer2)) == 5 323 doAssert buffer2 == ['a', 'b', 'c', 'd', 'e', '\x00'] 324 strm.close() 325 326 s.writeDataImpl(s, buffer, bufLen) 327 328proc write*[T](s: Stream, x: T) = 329 ## Generic write procedure. Writes `x` to the stream `s`. Implementation: 330 ## 331 ## **Note:** Not available for JS backend. Use `write(Stream, string) 332 ## <#write,Stream,string>`_ for now. 333 ## 334 ## .. code-block:: Nim 335 ## 336 ## s.writeData(s, unsafeAddr(x), sizeof(x)) 337 runnableExamples: 338 var strm = newStringStream("") 339 strm.write("abcde") 340 strm.setPosition(0) 341 doAssert strm.readAll() == "abcde" 342 strm.close() 343 344 writeData(s, unsafeAddr(x), sizeof(x)) 345 346proc write*(s: Stream, x: string) = 347 ## Writes the string `x` to the stream `s`. No length field or 348 ## terminating zero is written. 349 runnableExamples: 350 var strm = newStringStream("") 351 strm.write("THE FIRST LINE") 352 strm.setPosition(0) 353 doAssert strm.readLine() == "THE FIRST LINE" 354 strm.close() 355 356 when nimvm: 357 writeData(s, cstring(x), x.len) 358 else: 359 if x.len > 0: 360 when defined(js): 361 var x = x 362 writeData(s, addr(x), x.len) 363 else: 364 writeData(s, cstring(x), x.len) 365 366proc write*(s: Stream, args: varargs[string, `$`]) = 367 ## Writes one or more strings to the the stream. No length fields or 368 ## terminating zeros are written. 369 runnableExamples: 370 var strm = newStringStream("") 371 strm.write(1, 2, 3, 4) 372 strm.setPosition(0) 373 doAssert strm.readLine() == "1234" 374 strm.close() 375 376 for str in args: write(s, str) 377 378proc writeLine*(s: Stream, args: varargs[string, `$`]) = 379 ## Writes one or more strings to the the stream `s` followed 380 ## by a new line. No length field or terminating zero is written. 381 runnableExamples: 382 var strm = newStringStream("") 383 strm.writeLine(1, 2) 384 strm.writeLine(3, 4) 385 strm.setPosition(0) 386 doAssert strm.readAll() == "12\n34\n" 387 strm.close() 388 389 for str in args: write(s, str) 390 write(s, "\n") 391 392proc read*[T](s: Stream, result: var T) = 393 ## Generic read procedure. Reads `result` from the stream `s`. 394 ## 395 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 396 runnableExamples: 397 var strm = newStringStream("012") 398 ## readInt 399 var i: int8 400 strm.read(i) 401 doAssert i == 48 402 ## readData 403 var buffer: array[2, char] 404 strm.read(buffer) 405 doAssert buffer == ['1', '2'] 406 strm.close() 407 408 if readData(s, addr(result), sizeof(T)) != sizeof(T): 409 raise newEIO("cannot read from stream") 410 411proc peek*[T](s: Stream, result: var T) = 412 ## Generic peek procedure. Peeks `result` from the stream `s`. 413 ## 414 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 415 runnableExamples: 416 var strm = newStringStream("012") 417 ## peekInt 418 var i: int8 419 strm.peek(i) 420 doAssert i == 48 421 ## peekData 422 var buffer: array[2, char] 423 strm.peek(buffer) 424 doAssert buffer == ['0', '1'] 425 strm.close() 426 427 if peekData(s, addr(result), sizeof(T)) != sizeof(T): 428 raise newEIO("cannot read from stream") 429 430proc readChar*(s: Stream): char = 431 ## Reads a char from the stream `s`. 432 ## 433 ## Raises `IOError` if an error occurred. 434 ## Returns '\\0' as an EOF marker. 435 runnableExamples: 436 var strm = newStringStream("12\n3") 437 doAssert strm.readChar() == '1' 438 doAssert strm.readChar() == '2' 439 doAssert strm.readChar() == '\n' 440 doAssert strm.readChar() == '3' 441 doAssert strm.readChar() == '\x00' 442 strm.close() 443 444 jsOrVmBlock: 445 var str = " " 446 if readDataStr(s, str, 0..0) != 1: result = '\0' 447 else: result = str[0] 448 do: 449 if readData(s, addr(result), sizeof(result)) != 1: result = '\0' 450 451proc peekChar*(s: Stream): char = 452 ## Peeks a char from the stream `s`. Raises `IOError` if an error occurred. 453 ## Returns '\\0' as an EOF marker. 454 runnableExamples: 455 var strm = newStringStream("12\n3") 456 doAssert strm.peekChar() == '1' 457 doAssert strm.peekChar() == '1' 458 discard strm.readAll() 459 doAssert strm.peekChar() == '\x00' 460 strm.close() 461 462 when defined(js): 463 var str = " " 464 if peekData(s, addr(str), sizeof(result)) != 1: result = '\0' 465 else: result = str[0] 466 else: 467 if peekData(s, addr(result), sizeof(result)) != 1: result = '\0' 468 469proc readBool*(s: Stream): bool = 470 ## Reads a bool from the stream `s`. 471 ## 472 ## A bool is one byte long and it is `true` for every non-zero 473 ## (`0000_0000`) value. 474 ## Raises `IOError` if an error occurred. 475 ## 476 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 477 runnableExamples: 478 var strm = newStringStream() 479 ## setup for reading data 480 strm.write(true) 481 strm.write(false) 482 strm.flush() 483 strm.setPosition(0) 484 ## get data 485 doAssert strm.readBool() == true 486 doAssert strm.readBool() == false 487 doAssertRaises(IOError): discard strm.readBool() 488 strm.close() 489 490 var t: byte 491 read(s, t) 492 result = t != 0.byte 493 494proc peekBool*(s: Stream): bool = 495 ## Peeks a bool from the stream `s`. 496 ## 497 ## A bool is one byte long and it is `true` for every non-zero 498 ## (`0000_0000`) value. 499 ## Raises `IOError` if an error occurred. 500 ## 501 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 502 runnableExamples: 503 var strm = newStringStream() 504 ## setup for reading data 505 strm.write(true) 506 strm.write(false) 507 strm.flush() 508 strm.setPosition(0) 509 ## get data 510 doAssert strm.peekBool() == true 511 ## not false 512 doAssert strm.peekBool() == true 513 doAssert strm.readBool() == true 514 doAssert strm.peekBool() == false 515 strm.close() 516 517 var t: byte 518 peek(s, t) 519 result = t != 0.byte 520 521proc readInt8*(s: Stream): int8 = 522 ## Reads an int8 from the stream `s`. Raises `IOError` if an error occurred. 523 ## 524 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 525 runnableExamples: 526 var strm = newStringStream() 527 ## setup for reading data 528 strm.write(1'i8) 529 strm.write(2'i8) 530 strm.flush() 531 strm.setPosition(0) 532 ## get data 533 doAssert strm.readInt8() == 1'i8 534 doAssert strm.readInt8() == 2'i8 535 doAssertRaises(IOError): discard strm.readInt8() 536 strm.close() 537 538 read(s, result) 539 540proc peekInt8*(s: Stream): int8 = 541 ## Peeks an int8 from the stream `s`. Raises `IOError` if an error occurred. 542 ## 543 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 544 runnableExamples: 545 var strm = newStringStream() 546 ## setup for reading data 547 strm.write(1'i8) 548 strm.write(2'i8) 549 strm.flush() 550 strm.setPosition(0) 551 ## get data 552 doAssert strm.peekInt8() == 1'i8 553 ## not 2'i8 554 doAssert strm.peekInt8() == 1'i8 555 doAssert strm.readInt8() == 1'i8 556 doAssert strm.peekInt8() == 2'i8 557 strm.close() 558 559 peek(s, result) 560 561proc readInt16*(s: Stream): int16 = 562 ## Reads an int16 from the stream `s`. Raises `IOError` if an error occurred. 563 ## 564 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 565 runnableExamples: 566 var strm = newStringStream() 567 ## setup for reading data 568 strm.write(1'i16) 569 strm.write(2'i16) 570 strm.flush() 571 strm.setPosition(0) 572 ## get data 573 doAssert strm.readInt16() == 1'i16 574 doAssert strm.readInt16() == 2'i16 575 doAssertRaises(IOError): discard strm.readInt16() 576 strm.close() 577 578 read(s, result) 579 580proc peekInt16*(s: Stream): int16 = 581 ## Peeks an int16 from the stream `s`. Raises `IOError` if an error occurred. 582 ## 583 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 584 runnableExamples: 585 var strm = newStringStream() 586 ## setup for reading data 587 strm.write(1'i16) 588 strm.write(2'i16) 589 strm.flush() 590 strm.setPosition(0) 591 ## get data 592 doAssert strm.peekInt16() == 1'i16 593 ## not 2'i16 594 doAssert strm.peekInt16() == 1'i16 595 doAssert strm.readInt16() == 1'i16 596 doAssert strm.peekInt16() == 2'i16 597 strm.close() 598 599 peek(s, result) 600 601proc readInt32*(s: Stream): int32 = 602 ## Reads an int32 from the stream `s`. Raises `IOError` if an error occurred. 603 ## 604 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 605 runnableExamples: 606 var strm = newStringStream() 607 ## setup for reading data 608 strm.write(1'i32) 609 strm.write(2'i32) 610 strm.flush() 611 strm.setPosition(0) 612 ## get data 613 doAssert strm.readInt32() == 1'i32 614 doAssert strm.readInt32() == 2'i32 615 doAssertRaises(IOError): discard strm.readInt32() 616 strm.close() 617 618 read(s, result) 619 620proc peekInt32*(s: Stream): int32 = 621 ## Peeks an int32 from the stream `s`. Raises `IOError` if an error occurred. 622 ## 623 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 624 runnableExamples: 625 var strm = newStringStream() 626 ## setup for reading data 627 strm.write(1'i32) 628 strm.write(2'i32) 629 strm.flush() 630 strm.setPosition(0) 631 ## get data 632 doAssert strm.peekInt32() == 1'i32 633 ## not 2'i32 634 doAssert strm.peekInt32() == 1'i32 635 doAssert strm.readInt32() == 1'i32 636 doAssert strm.peekInt32() == 2'i32 637 strm.close() 638 639 peek(s, result) 640 641proc readInt64*(s: Stream): int64 = 642 ## Reads an int64 from the stream `s`. Raises `IOError` if an error occurred. 643 ## 644 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 645 runnableExamples: 646 var strm = newStringStream() 647 ## setup for reading data 648 strm.write(1'i64) 649 strm.write(2'i64) 650 strm.flush() 651 strm.setPosition(0) 652 ## get data 653 doAssert strm.readInt64() == 1'i64 654 doAssert strm.readInt64() == 2'i64 655 doAssertRaises(IOError): discard strm.readInt64() 656 strm.close() 657 658 read(s, result) 659 660proc peekInt64*(s: Stream): int64 = 661 ## Peeks an int64 from the stream `s`. Raises `IOError` if an error occurred. 662 ## 663 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 664 runnableExamples: 665 var strm = newStringStream() 666 ## setup for reading data 667 strm.write(1'i64) 668 strm.write(2'i64) 669 strm.flush() 670 strm.setPosition(0) 671 ## get data 672 doAssert strm.peekInt64() == 1'i64 673 ## not 2'i64 674 doAssert strm.peekInt64() == 1'i64 675 doAssert strm.readInt64() == 1'i64 676 doAssert strm.peekInt64() == 2'i64 677 strm.close() 678 679 peek(s, result) 680 681proc readUint8*(s: Stream): uint8 = 682 ## Reads an uint8 from the stream `s`. Raises `IOError` if an error occurred. 683 ## 684 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 685 runnableExamples: 686 var strm = newStringStream() 687 ## setup for reading data 688 strm.write(1'u8) 689 strm.write(2'u8) 690 strm.flush() 691 strm.setPosition(0) 692 ## get data 693 doAssert strm.readUint8() == 1'u8 694 doAssert strm.readUint8() == 2'u8 695 doAssertRaises(IOError): discard strm.readUint8() 696 strm.close() 697 698 read(s, result) 699 700proc peekUint8*(s: Stream): uint8 = 701 ## Peeks an uint8 from the stream `s`. Raises `IOError` if an error occurred. 702 ## 703 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 704 runnableExamples: 705 var strm = newStringStream() 706 ## setup for reading data 707 strm.write(1'u8) 708 strm.write(2'u8) 709 strm.flush() 710 strm.setPosition(0) 711 ## get data 712 doAssert strm.peekUint8() == 1'u8 713 ## not 2'u8 714 doAssert strm.peekUint8() == 1'u8 715 doAssert strm.readUint8() == 1'u8 716 doAssert strm.peekUint8() == 2'u8 717 strm.close() 718 719 peek(s, result) 720 721proc readUint16*(s: Stream): uint16 = 722 ## Reads an uint16 from the stream `s`. Raises `IOError` if an error occurred. 723 ## 724 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 725 runnableExamples: 726 var strm = newStringStream() 727 ## setup for reading data 728 strm.write(1'u16) 729 strm.write(2'u16) 730 strm.flush() 731 strm.setPosition(0) 732 ## get data 733 doAssert strm.readUint16() == 1'u16 734 doAssert strm.readUint16() == 2'u16 735 doAssertRaises(IOError): discard strm.readUint16() 736 strm.close() 737 738 read(s, result) 739 740proc peekUint16*(s: Stream): uint16 = 741 ## Peeks an uint16 from the stream `s`. Raises `IOError` if an error occurred. 742 ## 743 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 744 runnableExamples: 745 var strm = newStringStream() 746 ## setup for reading data 747 strm.write(1'u16) 748 strm.write(2'u16) 749 strm.flush() 750 strm.setPosition(0) 751 ## get data 752 doAssert strm.peekUint16() == 1'u16 753 ## not 2'u16 754 doAssert strm.peekUint16() == 1'u16 755 doAssert strm.readUint16() == 1'u16 756 doAssert strm.peekUint16() == 2'u16 757 strm.close() 758 759 peek(s, result) 760 761proc readUint32*(s: Stream): uint32 = 762 ## Reads an uint32 from the stream `s`. Raises `IOError` if an error occurred. 763 ## 764 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 765 runnableExamples: 766 var strm = newStringStream() 767 ## setup for reading data 768 strm.write(1'u32) 769 strm.write(2'u32) 770 strm.flush() 771 strm.setPosition(0) 772 773 ## get data 774 doAssert strm.readUint32() == 1'u32 775 doAssert strm.readUint32() == 2'u32 776 doAssertRaises(IOError): discard strm.readUint32() 777 strm.close() 778 779 read(s, result) 780 781proc peekUint32*(s: Stream): uint32 = 782 ## Peeks an uint32 from the stream `s`. Raises `IOError` if an error occurred. 783 ## 784 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 785 runnableExamples: 786 var strm = newStringStream() 787 ## setup for reading data 788 strm.write(1'u32) 789 strm.write(2'u32) 790 strm.flush() 791 strm.setPosition(0) 792 ## get data 793 doAssert strm.peekUint32() == 1'u32 794 ## not 2'u32 795 doAssert strm.peekUint32() == 1'u32 796 doAssert strm.readUint32() == 1'u32 797 doAssert strm.peekUint32() == 2'u32 798 strm.close() 799 800 peek(s, result) 801 802proc readUint64*(s: Stream): uint64 = 803 ## Reads an uint64 from the stream `s`. Raises `IOError` if an error occurred. 804 ## 805 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 806 runnableExamples: 807 var strm = newStringStream() 808 ## setup for reading data 809 strm.write(1'u64) 810 strm.write(2'u64) 811 strm.flush() 812 strm.setPosition(0) 813 ## get data 814 doAssert strm.readUint64() == 1'u64 815 doAssert strm.readUint64() == 2'u64 816 doAssertRaises(IOError): discard strm.readUint64() 817 strm.close() 818 819 read(s, result) 820 821proc peekUint64*(s: Stream): uint64 = 822 ## Peeks an uint64 from the stream `s`. Raises `IOError` if an error occurred. 823 ## 824 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 825 runnableExamples: 826 var strm = newStringStream() 827 ## setup for reading data 828 strm.write(1'u64) 829 strm.write(2'u64) 830 strm.flush() 831 strm.setPosition(0) 832 ## get data 833 doAssert strm.peekUint64() == 1'u64 834 ## not 2'u64 835 doAssert strm.peekUint64() == 1'u64 836 doAssert strm.readUint64() == 1'u64 837 doAssert strm.peekUint64() == 2'u64 838 strm.close() 839 840 peek(s, result) 841 842proc readFloat32*(s: Stream): float32 = 843 ## Reads a float32 from the stream `s`. Raises `IOError` if an error occurred. 844 ## 845 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 846 runnableExamples: 847 var strm = newStringStream() 848 ## setup for reading data 849 strm.write(1'f32) 850 strm.write(2'f32) 851 strm.flush() 852 strm.setPosition(0) 853 ## get data 854 doAssert strm.readFloat32() == 1'f32 855 doAssert strm.readFloat32() == 2'f32 856 doAssertRaises(IOError): discard strm.readFloat32() 857 strm.close() 858 859 read(s, result) 860 861proc peekFloat32*(s: Stream): float32 = 862 ## Peeks a float32 from the stream `s`. Raises `IOError` if an error occurred. 863 ## 864 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 865 runnableExamples: 866 var strm = newStringStream() 867 ## setup for reading data 868 strm.write(1'f32) 869 strm.write(2'f32) 870 strm.flush() 871 strm.setPosition(0) 872 ## get data 873 doAssert strm.peekFloat32() == 1'f32 874 ## not 2'f32 875 doAssert strm.peekFloat32() == 1'f32 876 doAssert strm.readFloat32() == 1'f32 877 doAssert strm.peekFloat32() == 2'f32 878 strm.close() 879 880 peek(s, result) 881 882proc readFloat64*(s: Stream): float64 = 883 ## Reads a float64 from the stream `s`. Raises `IOError` if an error occurred. 884 ## 885 ## **Note:** Not available for JS backend. Use `readStr <#readStr,Stream,int>`_ for now. 886 runnableExamples: 887 var strm = newStringStream() 888 ## setup for reading data 889 strm.write(1'f64) 890 strm.write(2'f64) 891 strm.flush() 892 strm.setPosition(0) 893 ## get data 894 doAssert strm.readFloat64() == 1'f64 895 doAssert strm.readFloat64() == 2'f64 896 doAssertRaises(IOError): discard strm.readFloat64() 897 strm.close() 898 899 read(s, result) 900 901proc peekFloat64*(s: Stream): float64 = 902 ## Peeks a float64 from the stream `s`. Raises `IOError` if an error occurred. 903 ## 904 ## **Note:** Not available for JS backend. Use `peekStr <#peekStr,Stream,int>`_ for now. 905 runnableExamples: 906 var strm = newStringStream() 907 ## setup for reading data 908 strm.write(1'f64) 909 strm.write(2'f64) 910 strm.flush() 911 strm.setPosition(0) 912 ## get data 913 doAssert strm.peekFloat64() == 1'f64 914 ## not 2'f64 915 doAssert strm.peekFloat64() == 1'f64 916 doAssert strm.readFloat64() == 1'f64 917 doAssert strm.peekFloat64() == 2'f64 918 strm.close() 919 920 peek(s, result) 921 922proc readStrPrivate(s: Stream, length: int, str: var string) = 923 if length > len(str): setLen(str, length) 924 when defined(js): 925 let L = readData(s, addr(str), length) 926 else: 927 let L = readData(s, cstring(str), length) 928 if L != len(str): setLen(str, L) 929 930proc readStr*(s: Stream, length: int, str: var string) {.since: (1, 3).} = 931 ## Reads a string of length `length` from the stream `s`. Raises `IOError` if 932 ## an error occurred. 933 readStrPrivate(s, length, str) 934 935proc readStr*(s: Stream, length: int): string = 936 ## Reads a string of length `length` from the stream `s`. Raises `IOError` if 937 ## an error occurred. 938 runnableExamples: 939 var strm = newStringStream("abcde") 940 doAssert strm.readStr(2) == "ab" 941 doAssert strm.readStr(2) == "cd" 942 doAssert strm.readStr(2) == "e" 943 doAssert strm.readStr(2) == "" 944 strm.close() 945 result = newString(length) 946 readStrPrivate(s, length, result) 947 948proc peekStrPrivate(s: Stream, length: int, str: var string) = 949 if length > len(str): setLen(str, length) 950 when defined(js): 951 let L = peekData(s, addr(str), length) 952 else: 953 let L = peekData(s, cstring(str), length) 954 if L != len(str): setLen(str, L) 955 956proc peekStr*(s: Stream, length: int, str: var string) {.since: (1, 3).} = 957 ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if 958 ## an error occurred. 959 peekStrPrivate(s, length, str) 960 961proc peekStr*(s: Stream, length: int): string = 962 ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if 963 ## an error occurred. 964 runnableExamples: 965 var strm = newStringStream("abcde") 966 doAssert strm.peekStr(2) == "ab" 967 ## not "cd 968 doAssert strm.peekStr(2) == "ab" 969 doAssert strm.readStr(2) == "ab" 970 doAssert strm.peekStr(2) == "cd" 971 strm.close() 972 result = newString(length) 973 peekStrPrivate(s, length, result) 974 975proc readLine*(s: Stream, line: var string): bool = 976 ## Reads a line of text from the stream `s` into `line`. `line` must not be 977 ## ``nil``! May throw an IO exception. 978 ## 979 ## A line of text may be delimited by ``LF`` or ``CRLF``. 980 ## The newline character(s) are not part of the returned string. 981 ## Returns ``false`` if the end of the file has been reached, ``true`` 982 ## otherwise. If ``false`` is returned `line` contains no new data. 983 ## 984 ## See also: 985 ## * `readLine(Stream) proc <#readLine,Stream>`_ 986 ## * `peekLine(Stream) proc <#peekLine,Stream>`_ 987 ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ 988 runnableExamples: 989 var strm = newStringStream("The first line\nthe second line\nthe third line") 990 var line = "" 991 doAssert strm.readLine(line) == true 992 doAssert line == "The first line" 993 doAssert strm.readLine(line) == true 994 doAssert line == "the second line" 995 doAssert strm.readLine(line) == true 996 doAssert line == "the third line" 997 doAssert strm.readLine(line) == false 998 doAssert line == "" 999 strm.close() 1000 1001 if s.readLineImpl != nil: 1002 result = s.readLineImpl(s, line) 1003 else: 1004 # fallback 1005 line.setLen(0) 1006 while true: 1007 var c = readChar(s) 1008 if c == '\c': 1009 c = readChar(s) 1010 break 1011 elif c == '\L': break 1012 elif c == '\0': 1013 if line.len > 0: break 1014 else: return false 1015 line.add(c) 1016 result = true 1017 1018proc peekLine*(s: Stream, line: var string): bool = 1019 ## Peeks a line of text from the stream `s` into `line`. `line` must not be 1020 ## ``nil``! May throw an IO exception. 1021 ## 1022 ## A line of text may be delimited by ``CR``, ``LF`` or 1023 ## ``CRLF``. The newline character(s) are not part of the returned string. 1024 ## Returns ``false`` if the end of the file has been reached, ``true`` 1025 ## otherwise. If ``false`` is returned `line` contains no new data. 1026 ## 1027 ## See also: 1028 ## * `readLine(Stream) proc <#readLine,Stream>`_ 1029 ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ 1030 ## * `peekLine(Stream) proc <#peekLine,Stream>`_ 1031 runnableExamples: 1032 var strm = newStringStream("The first line\nthe second line\nthe third line") 1033 var line = "" 1034 doAssert strm.peekLine(line) == true 1035 doAssert line == "The first line" 1036 doAssert strm.peekLine(line) == true 1037 ## not "the second line" 1038 doAssert line == "The first line" 1039 doAssert strm.readLine(line) == true 1040 doAssert line == "The first line" 1041 doAssert strm.peekLine(line) == true 1042 doAssert line == "the second line" 1043 strm.close() 1044 1045 let pos = getPosition(s) 1046 defer: setPosition(s, pos) 1047 result = readLine(s, line) 1048 1049proc readLine*(s: Stream): string = 1050 ## Reads a line from a stream `s`. Raises `IOError` if an error occurred. 1051 ## 1052 ## **Note:** This is not very efficient. 1053 ## 1054 ## See also: 1055 ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ 1056 ## * `peekLine(Stream) proc <#peekLine,Stream>`_ 1057 ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ 1058 runnableExamples: 1059 var strm = newStringStream("The first line\nthe second line\nthe third line") 1060 doAssert strm.readLine() == "The first line" 1061 doAssert strm.readLine() == "the second line" 1062 doAssert strm.readLine() == "the third line" 1063 doAssertRaises(IOError): discard strm.readLine() 1064 strm.close() 1065 1066 result = "" 1067 if s.atEnd: 1068 raise newEIO("cannot read from stream") 1069 while true: 1070 var c = readChar(s) 1071 if c == '\c': 1072 c = readChar(s) 1073 break 1074 if c == '\L' or c == '\0': 1075 break 1076 else: 1077 result.add(c) 1078 1079proc peekLine*(s: Stream): string = 1080 ## Peeks a line from a stream `s`. Raises `IOError` if an error occurred. 1081 ## 1082 ## **Note:** This is not very efficient. 1083 ## 1084 ## See also: 1085 ## * `readLine(Stream) proc <#readLine,Stream>`_ 1086 ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ 1087 ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_ 1088 runnableExamples: 1089 var strm = newStringStream("The first line\nthe second line\nthe third line") 1090 doAssert strm.peekLine() == "The first line" 1091 ## not "the second line" 1092 doAssert strm.peekLine() == "The first line" 1093 doAssert strm.readLine() == "The first line" 1094 doAssert strm.peekLine() == "the second line" 1095 strm.close() 1096 1097 let pos = getPosition(s) 1098 defer: setPosition(s, pos) 1099 result = readLine(s) 1100 1101iterator lines*(s: Stream): string = 1102 ## Iterates over every line in the stream. 1103 ## The iteration is based on ``readLine``. 1104 ## 1105 ## See also: 1106 ## * `readLine(Stream) proc <#readLine,Stream>`_ 1107 ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_ 1108 runnableExamples: 1109 var strm = newStringStream("The first line\nthe second line\nthe third line") 1110 var lines: seq[string] 1111 for line in strm.lines(): 1112 lines.add line 1113 doAssert lines == @["The first line", "the second line", "the third line"] 1114 strm.close() 1115 1116 var line: string 1117 while s.readLine(line): 1118 yield line 1119 1120type 1121 StringStream* = ref StringStreamObj 1122 ## A stream that encapsulates a string. 1123 StringStreamObj* = object of StreamObj 1124 ## A string stream object. 1125 data*: string ## A string data. 1126 ## This is updated when called `writeLine` etc. 1127 pos: int 1128 1129when (NimMajor, NimMinor) < (1, 3) and defined(js): 1130 proc ssAtEnd(s: Stream): bool {.compileTime.} = 1131 var s = StringStream(s) 1132 return s.pos >= s.data.len 1133 1134 proc ssSetPosition(s: Stream, pos: int) {.compileTime.} = 1135 var s = StringStream(s) 1136 s.pos = clamp(pos, 0, s.data.len) 1137 1138 proc ssGetPosition(s: Stream): int {.compileTime.} = 1139 var s = StringStream(s) 1140 return s.pos 1141 1142 proc ssReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int {.compileTime.} = 1143 var s = StringStream(s) 1144 result = min(slice.b + 1 - slice.a, s.data.len - s.pos) 1145 if result > 0: 1146 buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result] 1147 inc(s.pos, result) 1148 else: 1149 result = 0 1150 1151 proc ssClose(s: Stream) {.compileTime.} = 1152 var s = StringStream(s) 1153 s.data = "" 1154 1155 proc newStringStream*(s: string = ""): owned StringStream {.compileTime.} = 1156 new(result) 1157 result.data = s 1158 result.pos = 0 1159 result.closeImpl = ssClose 1160 result.atEndImpl = ssAtEnd 1161 result.setPositionImpl = ssSetPosition 1162 result.getPositionImpl = ssGetPosition 1163 result.readDataStrImpl = ssReadDataStr 1164 1165 proc readAll*(s: Stream): string {.compileTime.} = 1166 const bufferSize = 1024 1167 var bufferr: string 1168 bufferr.setLen(bufferSize) 1169 while true: 1170 let readBytes = readDataStr(s, bufferr, 0..<bufferSize) 1171 if readBytes == 0: 1172 break 1173 let prevLen = result.len 1174 result.setLen(prevLen + readBytes) 1175 result[prevLen..<prevLen+readBytes] = bufferr[0..<readBytes] 1176 if readBytes < bufferSize: 1177 break 1178 1179else: # after 1.3 or JS not defined 1180 proc ssAtEnd(s: Stream): bool = 1181 var s = StringStream(s) 1182 return s.pos >= s.data.len 1183 1184 proc ssSetPosition(s: Stream, pos: int) = 1185 var s = StringStream(s) 1186 s.pos = clamp(pos, 0, s.data.len) 1187 1188 proc ssGetPosition(s: Stream): int = 1189 var s = StringStream(s) 1190 return s.pos 1191 1192 proc ssReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = 1193 var s = StringStream(s) 1194 result = min(slice.b + 1 - slice.a, s.data.len - s.pos) 1195 if result > 0: 1196 jsOrVmBlock: 1197 buffer[slice.a..<slice.a+result] = s.data[s.pos..<s.pos+result] 1198 do: 1199 copyMem(unsafeAddr buffer[slice.a], addr s.data[s.pos], result) 1200 inc(s.pos, result) 1201 else: 1202 result = 0 1203 1204 proc ssReadData(s: Stream, buffer: pointer, bufLen: int): int = 1205 var s = StringStream(s) 1206 result = min(bufLen, s.data.len - s.pos) 1207 if result > 0: 1208 when defined(js): 1209 try: 1210 cast[ptr string](buffer)[][0..<result] = s.data[s.pos..<s.pos+result] 1211 except: 1212 raise newException(Defect, "could not read string stream, " & 1213 "did you use a non-string buffer pointer?", getCurrentException()) 1214 elif not defined(nimscript): 1215 copyMem(buffer, addr(s.data[s.pos]), result) 1216 inc(s.pos, result) 1217 else: 1218 result = 0 1219 1220 proc ssPeekData(s: Stream, buffer: pointer, bufLen: int): int = 1221 var s = StringStream(s) 1222 result = min(bufLen, s.data.len - s.pos) 1223 if result > 0: 1224 when defined(js): 1225 try: 1226 cast[ptr string](buffer)[][0..<result] = s.data[s.pos..<s.pos+result] 1227 except: 1228 raise newException(Defect, "could not peek string stream, " & 1229 "did you use a non-string buffer pointer?", getCurrentException()) 1230 elif not defined(nimscript): 1231 copyMem(buffer, addr(s.data[s.pos]), result) 1232 else: 1233 result = 0 1234 1235 proc ssWriteData(s: Stream, buffer: pointer, bufLen: int) = 1236 var s = StringStream(s) 1237 if bufLen <= 0: 1238 return 1239 if s.pos + bufLen > s.data.len: 1240 setLen(s.data, s.pos + bufLen) 1241 when defined(js): 1242 try: 1243 s.data[s.pos..<s.pos+bufLen] = cast[ptr string](buffer)[][0..<bufLen] 1244 except: 1245 raise newException(Defect, "could not write to string stream, " & 1246 "did you use a non-string buffer pointer?", getCurrentException()) 1247 elif not defined(nimscript): 1248 copyMem(addr(s.data[s.pos]), buffer, bufLen) 1249 inc(s.pos, bufLen) 1250 1251 proc ssClose(s: Stream) = 1252 var s = StringStream(s) 1253 s.data = "" 1254 1255 proc newStringStream*(s: sink string = ""): owned StringStream = 1256 ## Creates a new stream from the string `s`. 1257 ## 1258 ## See also: 1259 ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from 1260 ## opened File. 1261 ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ creates a 1262 ## file stream from the file name and the mode. 1263 ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a 1264 ## file stream from the file name and the mode. 1265 runnableExamples: 1266 var strm = newStringStream("The first line\nthe second line\nthe third line") 1267 doAssert strm.readLine() == "The first line" 1268 doAssert strm.readLine() == "the second line" 1269 doAssert strm.readLine() == "the third line" 1270 strm.close() 1271 1272 new(result) 1273 result.data = s 1274 result.pos = 0 1275 result.closeImpl = ssClose 1276 result.atEndImpl = ssAtEnd 1277 result.setPositionImpl = ssSetPosition 1278 result.getPositionImpl = ssGetPosition 1279 result.readDataStrImpl = ssReadDataStr 1280 when nimvm: 1281 discard 1282 else: 1283 result.readDataImpl = ssReadData 1284 result.peekDataImpl = ssPeekData 1285 result.writeDataImpl = ssWriteData 1286 1287type 1288 FileStream* = ref FileStreamObj 1289 ## A stream that encapsulates a `File`. 1290 ## 1291 ## **Note:** Not available for JS backend. 1292 FileStreamObj* = object of Stream 1293 ## A file stream object. 1294 ## 1295 ## **Note:** Not available for JS backend. 1296 f: File 1297 1298proc fsClose(s: Stream) = 1299 if FileStream(s).f != nil: 1300 close(FileStream(s).f) 1301 FileStream(s).f = nil 1302proc fsFlush(s: Stream) = flushFile(FileStream(s).f) 1303proc fsAtEnd(s: Stream): bool = return endOfFile(FileStream(s).f) 1304proc fsSetPosition(s: Stream, pos: int) = setFilePos(FileStream(s).f, pos) 1305proc fsGetPosition(s: Stream): int = return int(getFilePos(FileStream(s).f)) 1306 1307proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int = 1308 result = readBuffer(FileStream(s).f, buffer, bufLen) 1309 1310proc fsReadDataStr(s: Stream, buffer: var string, slice: Slice[int]): int = 1311 result = readBuffer(FileStream(s).f, addr buffer[slice.a], slice.b + 1 - slice.a) 1312 1313proc fsPeekData(s: Stream, buffer: pointer, bufLen: int): int = 1314 let pos = fsGetPosition(s) 1315 defer: fsSetPosition(s, pos) 1316 result = readBuffer(FileStream(s).f, buffer, bufLen) 1317 1318proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) = 1319 if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: 1320 raise newEIO("cannot write to stream") 1321 1322proc fsReadLine(s: Stream, line: var string): bool = 1323 result = readLine(FileStream(s).f, line) 1324 1325proc newFileStream*(f: File): owned FileStream = 1326 ## Creates a new stream from the file `f`. 1327 ## 1328 ## **Note:** Not available for JS backend. 1329 ## 1330 ## See also: 1331 ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream 1332 ## from string. 1333 ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ is the same 1334 ## as using `open proc <io.html#open,File,string,FileMode,int>`_ 1335 ## on Examples. 1336 ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a 1337 ## file stream from the file name and the mode. 1338 runnableExamples: 1339 ## Input (somefile.txt): 1340 ## The first line 1341 ## the second line 1342 ## the third line 1343 var f: File 1344 if open(f, "somefile.txt", fmRead, -1): 1345 var strm = newFileStream(f) 1346 var line = "" 1347 while strm.readLine(line): 1348 echo line 1349 ## Output: 1350 ## The first line 1351 ## the second line 1352 ## the third line 1353 strm.close() 1354 1355 new(result) 1356 result.f = f 1357 result.closeImpl = fsClose 1358 result.atEndImpl = fsAtEnd 1359 result.setPositionImpl = fsSetPosition 1360 result.getPositionImpl = fsGetPosition 1361 result.readDataStrImpl = fsReadDataStr 1362 result.readDataImpl = fsReadData 1363 result.readLineImpl = fsReadLine 1364 result.peekDataImpl = fsPeekData 1365 result.writeDataImpl = fsWriteData 1366 result.flushImpl = fsFlush 1367 1368proc newFileStream*(filename: string, mode: FileMode = fmRead, 1369 bufSize: int = -1): owned FileStream = 1370 ## Creates a new stream from the file named `filename` with the mode `mode`. 1371 ## 1372 ## If the file cannot be opened, `nil` is returned. See the `io module 1373 ## <io.html>`_ for a list of available `FileMode enums <io.html#FileMode>`_. 1374 ## 1375 ## **Note:** 1376 ## * **This function returns nil in case of failure.** 1377 ## To prevent unexpected behavior and ensure proper error handling, 1378 ## use `openFileStream proc <#openFileStream,string,FileMode,int>`_ 1379 ## instead. 1380 ## * Not available for JS backend. 1381 ## 1382 ## See also: 1383 ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream 1384 ## from string. 1385 ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from 1386 ## opened File. 1387 ## * `openFileStream proc <#openFileStream,string,FileMode,int>`_ creates a 1388 ## file stream from the file name and the mode. 1389 runnableExamples: 1390 from std/os import removeFile 1391 var strm = newFileStream("somefile.txt", fmWrite) 1392 if not isNil(strm): 1393 strm.writeLine("The first line") 1394 strm.writeLine("the second line") 1395 strm.writeLine("the third line") 1396 strm.close() 1397 ## Output (somefile.txt) 1398 ## The first line 1399 ## the second line 1400 ## the third line 1401 removeFile("somefile.txt") 1402 1403 var f: File 1404 if open(f, filename, mode, bufSize): result = newFileStream(f) 1405 1406proc openFileStream*(filename: string, mode: FileMode = fmRead, 1407 bufSize: int = -1): owned FileStream = 1408 ## Creates a new stream from the file named `filename` with the mode `mode`. 1409 ## If the file cannot be opened, an IO exception is raised. 1410 ## 1411 ## **Note:** Not available for JS backend. 1412 ## 1413 ## See also: 1414 ## * `newStringStream proc <#newStringStream,string>`_ creates a new stream 1415 ## from string. 1416 ## * `newFileStream proc <#newFileStream,File>`_ creates a file stream from 1417 ## opened File. 1418 ## * `newFileStream proc <#newFileStream,string,FileMode,int>`_ creates a 1419 ## file stream from the file name and the mode. 1420 runnableExamples: 1421 try: 1422 ## Input (somefile.txt): 1423 ## The first line 1424 ## the second line 1425 ## the third line 1426 var strm = openFileStream("somefile.txt") 1427 echo strm.readLine() 1428 ## Output: 1429 ## The first line 1430 strm.close() 1431 except: 1432 stderr.write getCurrentExceptionMsg() 1433 1434 var f: File 1435 if open(f, filename, mode, bufSize): 1436 return newFileStream(f) 1437 else: 1438 raise newEIO("cannot open file stream: " & filename) 1439 1440when false: 1441 type 1442 FileHandleStream* = ref FileHandleStreamObj 1443 FileHandleStreamObj* = object of Stream 1444 handle*: FileHandle 1445 pos: int 1446 1447 proc newEOS(msg: string): ref OSError = 1448 new(result) 1449 result.msg = msg 1450 1451 proc hsGetPosition(s: FileHandleStream): int = 1452 return s.pos 1453 1454 when defined(windows): 1455 # do not import windows as this increases compile times: 1456 discard 1457 else: 1458 import posix 1459 1460 proc hsSetPosition(s: FileHandleStream, pos: int) = 1461 discard lseek(s.handle, pos, SEEK_SET) 1462 1463 proc hsClose(s: FileHandleStream) = discard close(s.handle) 1464 proc hsAtEnd(s: FileHandleStream): bool = 1465 var pos = hsGetPosition(s) 1466 var theEnd = lseek(s.handle, 0, SEEK_END) 1467 result = pos >= theEnd 1468 hsSetPosition(s, pos) # set position back 1469 1470 proc hsReadData(s: FileHandleStream, buffer: pointer, bufLen: int): int = 1471 result = posix.read(s.handle, buffer, bufLen) 1472 inc(s.pos, result) 1473 1474 proc hsPeekData(s: FileHandleStream, buffer: pointer, bufLen: int): int = 1475 result = posix.read(s.handle, buffer, bufLen) 1476 1477 proc hsWriteData(s: FileHandleStream, buffer: pointer, bufLen: int) = 1478 if posix.write(s.handle, buffer, bufLen) != bufLen: 1479 raise newEIO("cannot write to stream") 1480 inc(s.pos, bufLen) 1481 1482 proc newFileHandleStream*(handle: FileHandle): owned FileHandleStream = 1483 new(result) 1484 result.handle = handle 1485 result.pos = 0 1486 result.close = hsClose 1487 result.atEnd = hsAtEnd 1488 result.setPosition = hsSetPosition 1489 result.getPosition = hsGetPosition 1490 result.readData = hsReadData 1491 result.peekData = hsPeekData 1492 result.writeData = hsWriteData 1493 1494 proc newFileHandleStream*(filename: string, 1495 mode: FileMode): owned FileHandleStream = 1496 when defined(windows): 1497 discard 1498 else: 1499 var flags: cint 1500 case mode 1501 of fmRead: flags = posix.O_RDONLY 1502 of fmWrite: flags = O_WRONLY or int(O_CREAT) 1503 of fmReadWrite: flags = O_RDWR or int(O_CREAT) 1504 of fmReadWriteExisting: flags = O_RDWR 1505 of fmAppend: flags = O_WRONLY or int(O_CREAT) or O_APPEND 1506 static: doAssert false # handle bug #17888 1507 var handle = open(filename, flags) 1508 if handle < 0: raise newEOS("posix.open() call failed") 1509 result = newFileHandleStream(handle) 1510