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.

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