RosettaCodeData/Task/Canonicalize-CIDR/FutureBasic/canonicalize-cidr.basic
2026-04-30 12:34:36 -04:00

132 lines
3.4 KiB
Text

//
// Canonicalize CIDR
//
// Using FutureBasic 7.0.34
// August 25, R.W
//
// Given a Classless Inter-Domain Routing (CIDR)
// IPv4 address, returns the canonical form.
//
Int networkWidth // network width in bits
CFStringRef errorCode // global err and CCIDR
CFStringRef CCIDR // canonical CIDR IPv4
// Type for IP address
begin record IPv4_Address
Int octets[3] // xxx.xxx.xxx.xx/xx
end record
// Validate CIDR string
local fn ValidateCIDR(ip as IPv4_Address, SnetworkWidth as Int, cidr as CFStringRef) as Boolean
Int i
boolean result
result = _True
if instr(0, cidr, @"/") == NSNotFound
errorCode = concat(@"Bad CIDR ",cidr)
result = _False
return result
end if
if SnetworkWidth < 1 || SnetworkWidth > 32 //validate network width
errorCode = concat(@"Bad Net Width",str(networkWidth))
result = _False
return result
end if
for i = 0 to 3
if ip.octets[i] > 255
errorCode = concat(@"Bad Octet ",str(ip.octets[i]))
result = _False
return result
end if
next
end fn = result
// Check if a character is a digit
local fn IsDigit(ch as CFStringRef) as boolean
Boolean IsDigit
IsDigit = (ucc(ch) > 47) && (ucc(ch) < 58)
end fn = IsDigit
// Parse CIDR string into IP structure and network width
local fn ParseIPv4_Address(cidr as CFStringRef) as IPv4_Address
IPv4_Address ip
Int i, slashPos, currentOctet, octetValue
CFStringRef ipPart
ipPart = @""
slashPos = instr(0, cidr, @"/")
if slashPos > 0
ipPart = left(cidr, slashPos)
networkWidth = Intval(mid(cidr, slashPos + 1))
else
ipPart = cidr
networkWidth = -1
end if
currentOctet = 0: octetValue = 0
for i = 0 to len(ipPart)-1
select case mid(ipPart, i, 1)
case @"."
ip.octets[currentOctet] = octetValue
currentOctet ++
octetValue = 0
case else
if fn IsDigit(mid(ipPart, i, 1))
octetValue = octetValue * 10 + Intval(mid(ipPart, i, 1))
end if
end select
next
ip.octets[currentOctet] = octetValue
end fn = ip
// Apply network mask to IP
local fn ApplyNetworkMask(ip as IPv4_Address, SnetworkWidth as Int) as IPv4_Address
IPv4_Address result
Int completeOctets, remainingBits, i
result = ip
completeOctets = SnetworkWidth \ 8 //octet bits
remainingBits = SnetworkWidth AND 7
if completeOctets < 4
result.octets[completeOctets] = result.octets[completeOctets] AND (255 - 2^(8 - remainingBits) + 1)
for i = completeOctets + 1 to 3
result.octets[i] = 0
next
end if
end fn = result
// Process a CIDR string, sets global CCIDR
local fn ProcessCIDR(cidr as CFStringRef) as CFStringRef
IPv4_Address ip
CFStringRef result
Int i
result = @""
ip = fn ParseIPv4_Address(cidr)
if fn ValidateCIDR(ip, networkWidth, cidr) // validate
ip = fn ApplyNetworkMask(ip, networkWidth)
result = mid(str(ip.octets[0]),1)
for i = 1 to 3
result = concat(result,@".",mid(str(ip.octets[i]),1))
next
result = concat(result,@"/",mid(str(networkWidth),1))
else
print@ errorCode
end if
CCIDR = result
end fn = result
//
// Main
Window 1,@"Canonicalize CIDR"
print@
// Test data from the Rosetta Stone task
CFStringRef cidr(5) = {@"87.70.141.1/22", @"36.18.154.103/12", @"62.62.197.11/29", ¬
@"67.137.119.181/4", @"161.214.74.21/24", @"184.232.176.184/18"}
for Int i = 0 to 5
print@ fn ProcessCIDR(cidr(i))
next
HandleEvents
//