; ip.inc ; ; An include file that provides the "ip" macro ; for creating ip address declarations ifndef ip_inc ip_inc = 1 option casemap:none ; Some useful structures for holding ; socket addresses (IP address + port number): ipBytes struct b3 byte ? b2 byte ? b1 byte ? b0 byte ? ipBytes ends portBytes struct HO byte ? LO byte ? portBytes ends bipadrs struct adrs ipBytes {} port portBytes {} bipadrs ends ; ip_adrs is the actual type that the ; ip macro uses to declare initialized ; IP address variables: ip_adrs struct adrs dword ? port word ? ip_adrs ends ;---------------------------------------------------- ; ; getByte- ; ; Extracts a single byte from the beginning of an IP ; address string (xxx.yyy.zzz.ttt:pppp). The sep ; argument is the separator (either "." or ":"). getByte macro adrs, sep local sepPosn, theByte, byteVal local tAdrs ; Have to convert macro argument to a test string. tAdrs textequ <&adrs> ; Locate the "." or ":" character that ends the ; current 8-bit value in the dotted IP address: sepPosn instr 1, tAdrs, <&sep> ; If a separator was present, extract the ; proceeding byte: if sepPosn gt 0 theByte substr tAdrs, 1, sepPosn-1 else ; Syntax error if separator not found: echo Syntax error in IP address (getByte) .err exitm <> endif ; Convert the byte value to a number and ensure it ; is less than 256: byteVal = theByte if byteVal gt 255 echo IP address contains a value that % echo is greater than 255 (&byte0) .err exitm <> endif ; Return a textequ directive for this byte value: exitm endm ;---------------------------------------------------- ; ; getRem- ; ; Extracts the remainder of the string after the ; IP address byte at the beginning of the string. ; The sep argument is either "." or ":". getRem macro adrs, sep local sepPosn, rem, tAdrs ; Have to convert macro argument to a test string. tAdrs textequ <&adrs> ; Determine the location of the "." or ":" ; delimiter: sepPosn instr 1, tAdrs, <&sep> ; If the delimiter is present, extract all the text ; beyond the delimiter character: if sepPosn gt 0 rem substr tAdrs, sepPosn+1 else ; If no delimiter, we have a syntax error: echo Syntax error in IP address (getRem) .err exitm <> endif ; Return the remainder after removing the first ; byte prefix: exitm endm ;------------------------------------------------------ ; ; getIP- ; ; Extracts the four bytes from the dotted IP address ; and returns them as a text string of the form: ; ; extractIP macro ipAdrs local byte0, byte1, byte2, byte3 local rem0, rem1, rem2 local ipVal ;; Get the first byte of the IP address: byte0 getByte (<&ipAdrs>, <.>) rem0 getRem (<&ipAdrs>, <.>) byte1 getByte (rem0, <.>) rem1 getRem (rem0, <.>) byte2 getByte (rem1, <.>) rem2 getRem (rem1, <.>) byte3 getByte (rem2, <:>) ipVal = byte0 + (byte1 shl 8) + \ (byte2 shl 16) + (byte3 shl 24) exitm %ipVal endm ;------------------------------------------------------ ; ; getPort- ; ; Extracts the port value from the end of the IP ; address (after the ":" separator), verifies that ; it is less than 65536, and returns a string of ; the form: ; ; getPort macro ipAdrs local tAdrs, sepPosn, port local portVal, pOutput ; Have to convert macro argument to a test string. tAdrs textequ <&ipAdrs> ; Determine the location of the ":" ; delimiter: sepPosn instr 1, tAdrs, <:> ; No need to check for ":", extractIP would have ; already complained if it was not present. If it ; is not present, this code may generate some ; additional errors, but that's okay. ; ; Get the port value: port substr tAdrs, sepPosn+1 ; Convert port to a numeric value and verify ; that it is less than 65,536: portVal = port if portVal gt 65535 echo Port value is out of range. % echo Should be 0..65535, is (&port) .err exitm <> endif ;; Convert portVal to network byte order (big endian): pOutput catstr %(portVal shr 8)+((portVal and 0ffh) shl 8) exitm pOutput endm ;-------------------------------------------------- ; ; ip: ; ; Data declaration to handle IP addresses. ; ; Syntax: ; ; {label} ip (xxx.yyy.zzz.ttt:pppp {,...}) ; ; ; ; Given an argument of the form: ; ; xxx.yyy.zzz.ttt:ppp ; ; this macro produces a string of the form: ; ; ip_adrs {xxx + (yyy shl 8) + (zzz shl 16) + ; (ttt shl 24)}, (pppp shr 8) + ; ((pppp and 0ffh) shl 8)} ip macro args:vararg local curIP, exip, output, port output textequ <> for curIP, <&args> exip textequ extractIP(&curIP) ifnb output output catstr output, <,> endif output catstr output, <{>, exip port textequ getPort(&curIP) output catstr output, <,>, port, <}> endm exitm endm endif ;ip_inc