Mirror of CollapseOS
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

172 lines
4.2KB

  1. ; *** Consts ***
  2. ; maximum number of bytes to receive as args in all commands. Determines the
  3. ; size of the args variable.
  4. .equ PARSE_ARG_MAXCOUNT 3
  5. ; *** Code ***
  6. ; Parse the hex char at A and extract it's 0-15 numerical value. Put the result
  7. ; in A.
  8. ;
  9. ; On success, the carry flag is reset. On error, it is set.
  10. parseHex:
  11. ; First, let's see if we have an easy 0-9 case
  12. cp '0'
  13. jr c, .error ; if < '0', we have a problem
  14. cp '9'+1
  15. jr nc, .alpha ; if >= '9'+1, we might have alpha
  16. ; We are in the 0-9 range
  17. sub '0' ; C is clear
  18. ret
  19. .alpha:
  20. call upcase
  21. cp 'A'
  22. jr c, .error ; if < 'A', we have a problem
  23. cp 'F'+1
  24. jr nc, .error ; if >= 'F', we have a problem
  25. ; We have alpha.
  26. sub 'A'-10 ; C is clear
  27. ret
  28. .error:
  29. scf
  30. ret
  31. ; Parses 2 characters of the string pointed to by HL and returns the numerical
  32. ; value in A. If the second character is a "special" character (<0x21) we don't
  33. ; error out: the result will be the one from the first char only.
  34. ; HL is set to point to the last char of the pair.
  35. ;
  36. ; On success, the carry flag is reset. On error, it is set.
  37. parseHexPair:
  38. push bc
  39. ld a, (hl)
  40. call parseHex
  41. jr c, .end ; error? goto end, keeping the C flag on
  42. rla \ rla \ rla \ rla ; let's push this in MSB
  43. ld b, a
  44. inc hl
  45. ld a, (hl)
  46. cp 0x21
  47. jr c, .single ; special char? single digit
  48. call parseHex
  49. jr c, .end ; error?
  50. or b ; join left-shifted + new. we're done!
  51. ; C flag was set on parseHex and is necessarily clear at this point
  52. jr .end
  53. .single:
  54. ; If we have a single digit, our result is already stored in B, but
  55. ; we have to right-shift it back.
  56. ld a, b
  57. and 0xf0
  58. rra \ rra \ rra \ rra
  59. dec hl
  60. .end:
  61. pop bc
  62. ret
  63. ; Parse arguments at (HL) with specifiers at (DE) into (IX).
  64. ;
  65. ; Args specifiers are a series of flag for each arg:
  66. ; Bit 0 - arg present: if unset, we stop parsing there
  67. ; Bit 1 - is word: this arg is a word rather than a byte. Because our
  68. ; destination are bytes anyway, this doesn't change much except
  69. ; for whether we expect a space between the hex pairs. If set,
  70. ; you still need to have a specifier for the second part of
  71. ; the multibyte.
  72. ; Bit 2 - optional: If set and not present during parsing, we don't error out
  73. ; and write zero
  74. ;
  75. ; Bit 3 - String argument: If set, this argument is a string. A pointer to the
  76. ; read string, null terminated (max 0x20 chars) will
  77. ; be placed in the next two bytes. This has to be the
  78. ; last argument of the list and it stops parsing.
  79. ; Sets A to nonzero if there was an error during parsing, zero otherwise.
  80. parseArgs:
  81. push bc
  82. push de
  83. push hl
  84. push ix
  85. ; init the arg value to a default 0
  86. xor a
  87. ld (ix), a
  88. ld (ix+1), a
  89. ld (ix+2), a
  90. ld b, PARSE_ARG_MAXCOUNT
  91. .loop:
  92. ld a, (hl)
  93. ; is this the end of the line?
  94. or a ; cp 0
  95. jr z, .endofargs
  96. ; Get the specs
  97. ld a, (de)
  98. bit 0, a ; do we have an arg?
  99. jr z, .error ; not set? then we have too many args
  100. ld c, a ; save the specs for multibyte check later
  101. bit 3, a ; is our arg a string?
  102. jr z, .notAString
  103. ; our arg is a string. Let's place HL in our next two bytes and call
  104. ; it a day. Little endian, remember
  105. ld (ix), l
  106. ld (ix+1), h
  107. jr .success ; directly to success: skip endofargs checks
  108. .notAString:
  109. call parseHexPair
  110. jr c, .error
  111. ; we have a good arg and we need to write A in (IX).
  112. ld (ix), a
  113. ; Good! increase counters
  114. inc de
  115. inc ix
  116. inc hl ; get to following char (generally a space)
  117. ; Our arg is parsed, our pointers are increased. Normally, HL should
  118. ; point to a space *unless* our argspec indicates a multibyte arg.
  119. bit 1, c
  120. jr nz, .nospacecheck ; bit set? no space check
  121. ; do we have a proper space char (or null char)?
  122. ld a, (hl)
  123. or a
  124. jr z, .endofargs
  125. cp ' '
  126. jr nz, .error
  127. inc hl
  128. .nospacecheck:
  129. djnz .loop
  130. ; If we get here, it means that our next char *has* to be a null char
  131. ld a, (hl)
  132. or a ; cp 0
  133. jr z, .success ; zero? great!
  134. jr .error
  135. .endofargs:
  136. ; We encountered our null char. Let's verify that we either have no
  137. ; more args or that they are optional
  138. ld a, (de)
  139. or a
  140. jr z, .success ; no arg? success
  141. bit 2, a
  142. jr z, .error ; if unset, arg is not optional. error
  143. ; success
  144. .success:
  145. xor a
  146. jr .end
  147. .error:
  148. inc a
  149. .end:
  150. pop ix
  151. pop hl
  152. pop de
  153. pop bc
  154. ret