# Multi-line text reader (x64 ASM)

Building upon my previous question, I have come up with a method that'll search through a buffer and return a pointer to the end of the line. The primary purpose of the function to extract rows from a csv file using the logic specified in RFC4180; the third parameter isQuotedSequence can be used in cases where parsing is parallelized or started in the middle of a string that is known to be quoted.

Notes:

• the excessive amount of comments are for people who may not know the language but still want to try and understand what the code is doing
• registers are renamed primarily to aid in refactoring but also enable some rudimentary static analysis to be performed
• the isQuotedSequence variable is placed in the rdx register in order to mimic operations like mul that return a 128-bit result; I'm not sure if this is actually usable by anything other than ASM or supported by the Windows x64 or System V ABIs though...

Anything info that could be used to make the function safer or more performant would be most useful; thanks for your review!

Code:

COMMENT @
C Interface:
extern char* ReadLine(const char* bufferOffset, const char* bufferTail, long long isQuotedSequence);

Reference:
https://tools.ietf.org/html/rfc4180
@

;-----------------------------; (CONSTANTS)
CARRIAGE_RETURN  = 00000000Dh
DOUBLE_QUOTE     = 000000022h
LINE_FEED        = 00000000Ah
TRUE             = 000000001h
;-----------------------------; (ARGUMENTS)
arg0             textequ <rcx>
arg1             textequ <rdx>
arg2             textequ <r8>
;-----------------------------; (LOCALS)
bufferOffset     textequ <rax>
bufferTail       textequ <r9>
currentCharacter textequ <ecx>
isQuotedSequence textequ <rdx>
nextCharacter    textequ <r8d>

.code

mov bufferOffset, arg0                         ; initialize [bufferOffset]
mov bufferTail, arg1                           ; initialize [bufferTail]
mov isQuotedSequence, arg2                     ; initialize [isQuotedSequence]
cmp bufferOffset, bufferTail                   ; validate that there are more characters to read
movzx nextCharacter, byte ptr[bufferOffset]    ; extract [nextCharacter] from [bufferOffset]
mov currentCharacter, nextCharacter            ; shift [nextCharacter] into [currentCharacter]
add bufferOffset, 1h                           ; increment [bufferOffset]
cmp bufferOffset, bufferTail                   ; validate that there are more characters to read
movzx nextCharacter, byte ptr[bufferOffset]    ; extract [nextCharacter] from [bufferOffset]
cmp currentCharacter, DOUBLE_QUOTE             ; compare [currentCharacter] to QUOTE_DOUBLE
cmp currentCharacter, CARRIAGE_RETURN          ; compare [currentCharacter] to CARRIAGE_RETURN
cmp currentCharacter, LINE_FEED                ; compare [currentCharacter] to LINE_FEED
xor isQuotedSequence, TRUE                     ; invert [isQuotedSequence] indicator
cmp nextCharacter, LINE_FEED                   ; compare [nextCharacter] to LINE_FEED
cmp isQuotedSequence, TRUE                     ; compare [isQuotedSequence] to TRUE

You're treating comparison of addresses as signed values, instead of unsigned. For example, after you execute cmp bufferOffset, bufferTail, you use the jge condition, which is jump greater or equal. This is intended for signed values. You should use jae jump above or equal instruction instead. This condition needs to be changed in several places.
Rather than add bufferOffset, 1h, just use inc bufferOffset.
• @Kittoes0124 I got confused by the nextCharacter check. I've removed that paragraph from the review. – 1201ProgramAlarm Mar 11 at 19:24