# get_line: Read up to a line from file stream. Uses internal buffering for efficient
#           reading and the maximum length field of string
# This implementation may read nothing once before returning zero if the last call read
# an incomplete line

	.set	BUFFER_SIZE, 512
	.section	.data

# Reserve BUFFER_SIZE bytes
	.type	buffer, @object
buffer:
	.space	BUFFER_SIZE

# Current location in the buffer. Initially set to zero
	.type	index, @object
index:
	.long	0

# The length of string. Initially set to zero
	.type	length, @object
length:
	.long	0

# Flag for end of file. Initially set to zero
	.type	end_flag, @object
end_flag:
	.long	0

	.section	.text
	.intel_syntax
read_string:
	cmp	dword ptr end_flag, 0
	je	read_string.poke	# Read file if the end has not been found
	mov	%eax, 0			# Nothing to read
	mov	dword ptr end_flag, 0
	jmp	read_string.reset
read_string.poke:
	mov	%eax, 3			# Read system call
	lea	%ecx, buffer		# Calculate the address of buffer
	.ifdef	NetBSD
	push	BUFFER_SIZE
	push	%ecx			# Buffer
	push	[%esp + 4]		# File descriptor
	push	0			# Extra double-word for C calling convention
	int	128
	add	%esp, 16		# Clean up the stack
	.else
	push	%ebx
	mov	%ebx, [%esp + 8]	# File descriptor
	mov	%edx, BUFFER_SIZE
	int	128
	pop	%ebx
	.endif
	test	%eax, %eax
	js	read_string.end		# Return immediately if an error occured
	cmp	%eax, BUFFER_SIZE
	je	read_string.reset	# The end has yet to be found
	mov	dword ptr end_flag, 1
read_string.reset:
	mov	length, %eax
	mov	dword ptr index, 0
read_string.end:
	ret				# pop %eip

	.global	get_line
	.type	get_line, @function
get_line:
	push	%ebp
	mov	%ebp, %esp
	sub	%esp, 8			# Allocate space
	mov	dword ptr [%ebp - 4], 0	# length = 0
get_line.compare_byte:
	mov	%edx, index
	cmp	%edx, length
	jne	get_line.copy_byte	# index <> internal length
	push	[%ebp + 8]		# File descriptor
	call	read_string
	add	%esp, 4			# Clean up the stack
	test	%eax, %eax
	js	get_line.end		# Return if an error occured
	jz	get_line.assign_length	# Set length if nothing was read
	mov	%edx, index
get_line.copy_byte:
	mov	%eax, [%ebp - 4]	# Length
	mov	%ecx, [%ebp + 12]	# Copy address of buffer
	cmp	%eax, [%ecx - 8]
	je	get_line.overflow	# Length == Maximum length
	add	%ecx, %eax		# buffer = buffer + length
	mov	%al, [%edx + buffer]	# Get next byte in internal buffer
	mov	[%ecx], %al		# ^buffer = byte
	add	dword ptr [%ebp - 4], 1	# length = length + 1
	add	dword ptr index, 1	# index = index + 1
	cmp	%al, 10
	jne	get_line.compare_byte	# Assign the length if its a new-line character
get_line.assign_length:
	mov	%eax, [%ebp - 4]	# length
	mov	%ecx, [%ebp + 12]	# Copy buffer address
	mov	[%ecx - 4], %eax	# Set length of string
	jmp	get_line.end
get_line.overflow:
	mov	%eax, -35		# Error number for string overflow
get_line.end:
	mov	%esp, %ebp		# Deallocate space
	pop	%ebp			# Leave
	ret				# pop %eip
