view modules/file.tp @ 331:61f5b794d939

Breaking change: method call syntax now always uses the syntactic receiver as the actual receiver. This makes its behavior different from function call syntax, but solves some problems with methods being shadowed by local variables and the like.
author Michael Pavone <pavone@retrodev.com>
date Sat, 28 Mar 2015 14:21:04 -0700
parents dcb495cf2b97
children
line wrap: on
line source

{
	_getStdin <- {
		_stdin <- (file fromFD: 0)
		_getStdin <- { _stdin }
		_stdin
	}
	_getStdout <- {
		_stdout <- (file fromFD: 1)
		_getStdout <- { _stdout }
		_stdout
	}
	_getStderr <- {
		_stderr <- (file fromFD: 2)
		_getStderr <- { _stderr }
		_stderr
	}
	#{
		fromFD <- :_fd {
			_buffers <- #[]
			_readPos <- 0
			_buffered <- 0
			_bufferChunk <- 4096
			_eof? <- false
			_addBuffer <- {
				newbuf <- bytearray normal: _bufferChunk
				justRead <- os readFrom: _fd to: newbuf
				if: justRead > 0 {
					_buffered <- _buffered + justRead
					_buffers append: (newbuf shrinkTo: justRead)
				} else: {
					_eof? <- true
				}
			}
			_lineIter <- :f {
				iter <- #{
					foreach <- :self fun {
						idx <- 0
						while: { not: (f eof?) } do: {
							line <- f nextLine
							fun: idx line
							idx <- idx + 1
						}
						self
					}

					map <- :fun {
						new <- #[]
						foreach: :idx el {
							new append: (fun: el)
						}
						new
					}

					filter <- :fun {
						new <- #[]
						foreach: :idx el {
							if: (fun: el) {
								new append: el
							}
						}
						new
					}

					fold:with <- :acc :fun {
						foreach: :idx el {
							acc <- fun: acc el
						}
						acc
					}

					foldr:with <- :acc :fun {
						(map: :el { el }) foldr: acc with: fun
					}
				}
				_lineIter <- { iter }
				iter
			}
			#{
				fd <- { _fd }
				read <- :bytes {
					while: { bytes > _buffered && (not: _eof?)} do: {
						_addBuffer:
					}
					nextBuffers <- #[]
					pieces <- #[]
					toRead <- bytes
					i <- 0
					while: { toRead > 0 && i < (_buffers length) } do: {
						curBuf <- _buffers get: i
						if: toRead >= (curBuf length) - _readPos {
							pieces append: (curBuf stringFrom: _readPos to: (curBuf length))
							_buffered <- _buffered - ((curBuf length) - _readPos)
							toRead <- toRead - ((curBuf length) - _readPos)
							_readPos <- 0
						} else: {
							nextPos <- _readPos + toRead
							pieces append: (curBuf stringFrom: _readPos to: nextPos)
							_readPos <- nextPos
							_buffered <- _buffered - toRead
							toRead <- 0
							nextBuffers append: curBuf
						}
						i <- i + 1
					}

					while: {i < (_buffers length)} do: {
						nextBuffers append: (_buffers get: i)
						i <- i + 1
					}
					_buffers <- nextBuffers
					pieces join: ""
				}
				readAll <- {
					while: { not: _eof? } do: {
						_addBuffer:
					}
					read: _buffered
				}
				write <- :data {
					//TODO: write buffering for small writes
					os write: _fd data
				}
				nextLine <- {
					nl <- "\n" byte: 0
					notfound <- true
					pos <- 0
					i <- 0
					while: { notfound } do: {
						while: { notfound && i < (_buffers length) } do: {
							curBuf <- _buffers get: i
							start <- if: i = 0 { _readPos } else: { 0 }
							curBuf findChar: nl from: start :idx {
								notfound <- false
								pos <- pos + idx + 1
							} else: {
								pos <- pos + (curBuf length)
							}

							i <- i + 1
						}

						if: notfound && (not: _eof?) {
							_addBuffer:
						} else: {
							notfound <- false
						}
					}
					read: pos - _readPos
				}
				lines <- {
					_lineIter: self
				}
				close <- {
					os close: _fd
				}
				eof? <- { _eof? && _buffered <= 0 }
			}
		}

		open <- :filename {
			fromFD: (os open: filename (os O_RDONLY))
		}

		openWrite <- :filename {
			fromFD: (os open: filename ((os O_WRONLY) or (os O_CREAT) or (os O_TRUNC)) 0x1B6)
		}

		openAppend <- :filename {
			fromFD: (os open: filename ((os O_RDWR) or (os O_CREAT) or (os O_APPEND)) 0x1B6)
		}

		stdin <- { _getStdin: }
		stdout <- { _getStdout: }
		stderr <- { _getStderr: }
	}
}