parseutils added
This commit is contained in:
parent
262a47887d
commit
e22c73fd89
7 changed files with 292 additions and 221 deletions
|
|
@ -11,7 +11,7 @@
|
||||||
## webpages/other data.
|
## webpages/other data.
|
||||||
|
|
||||||
# neuer Code:
|
# neuer Code:
|
||||||
import sockets, strutils, parseurl, pegs, os, parseutils
|
import sockets, strutils, parseurl, pegs, parseutils
|
||||||
|
|
||||||
type
|
type
|
||||||
TResponse* = tuple[
|
TResponse* = tuple[
|
||||||
|
|
@ -19,8 +19,8 @@ type
|
||||||
body: string]
|
body: string]
|
||||||
THeader* = tuple[htype: string, hvalue: string]
|
THeader* = tuple[htype: string, hvalue: string]
|
||||||
|
|
||||||
EInvalidHttp* = object of EBase ## exception that is raised when server does
|
EInvalidProtocol* = object of EBase ## exception that is raised when server
|
||||||
## not conform to the implemented HTTP
|
## does not conform to the implemented
|
||||||
## protocol
|
## protocol
|
||||||
|
|
||||||
EHttpRequestErr* = object of EBase ## Thrown in the ``getContent`` proc,
|
EHttpRequestErr* = object of EBase ## Thrown in the ``getContent`` proc,
|
||||||
|
|
@ -35,7 +35,7 @@ template newException(exceptn, message: expr): expr =
|
||||||
e
|
e
|
||||||
|
|
||||||
proc httpError(msg: string) =
|
proc httpError(msg: string) =
|
||||||
var e: ref EInvalidHttp
|
var e: ref EInvalidProtocol
|
||||||
new(e)
|
new(e)
|
||||||
e.msg = msg
|
e.msg = msg
|
||||||
raise e
|
raise e
|
||||||
|
|
@ -54,9 +54,7 @@ proc getHeaderValue*(headers: seq[THeader], name: string): string =
|
||||||
return headers[i].hvalue
|
return headers[i].hvalue
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
proc parseBody(data: var string, start: int, s: TSocket,
|
proc parseChunks(data: var string, start: int, s: TSocket): string =
|
||||||
headers: seq[THeader]): string =
|
|
||||||
if getHeaderValue(headers, "Transfer-Encoding") == "chunked":
|
|
||||||
# get chunks:
|
# get chunks:
|
||||||
var i = start
|
var i = start
|
||||||
result = ""
|
result = ""
|
||||||
|
|
@ -68,9 +66,7 @@ proc parseBody(data: var string, start: int, s: TSocket,
|
||||||
while data[i] notin {'\C', '\L', '\0'}: inc(i)
|
while data[i] notin {'\C', '\L', '\0'}: inc(i)
|
||||||
if data[i] == '\C': inc(i)
|
if data[i] == '\C': inc(i)
|
||||||
if data[i] == '\L': inc(i)
|
if data[i] == '\L': inc(i)
|
||||||
echo "ChunkSize: ", chunkSize
|
|
||||||
if chunkSize <= 0: break
|
if chunkSize <= 0: break
|
||||||
|
|
||||||
var x = copy(data, i, i+chunkSize-1)
|
var x = copy(data, i, i+chunkSize-1)
|
||||||
var size = x.len
|
var size = x.len
|
||||||
result.add(x)
|
result.add(x)
|
||||||
|
|
@ -80,16 +76,22 @@ proc parseBody(data: var string, start: int, s: TSocket,
|
||||||
var missing = chunkSize - size
|
var missing = chunkSize - size
|
||||||
var L = result.len
|
var L = result.len
|
||||||
setLen(result, L + missing)
|
setLen(result, L + missing)
|
||||||
discard s.recv(addr(result[L]), missing)
|
while missing > 0:
|
||||||
|
var bytesRead = s.recv(addr(result[L]), missing)
|
||||||
|
inc(L, bytesRead)
|
||||||
|
dec(missing, bytesRead)
|
||||||
|
|
||||||
# next chunk:
|
# next chunk:
|
||||||
data = s.recv()
|
data = s.recv()
|
||||||
echo data
|
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
# skip trailing CR-LF:
|
# skip trailing CR-LF:
|
||||||
while data[i] in {'\C', '\L'}: inc(i)
|
while data[i] in {'\C', '\L'}: inc(i)
|
||||||
|
if data[i] == '\0': data.add(s.recv())
|
||||||
|
|
||||||
|
proc parseBody(data: var string, start: int, s: TSocket,
|
||||||
|
headers: seq[THeader]): string =
|
||||||
|
if getHeaderValue(headers, "Transfer-Encoding") == "chunked":
|
||||||
|
result = parseChunks(data, start, s)
|
||||||
else:
|
else:
|
||||||
result = copy(data, start)
|
result = copy(data, start)
|
||||||
# -REGION- Content-Length
|
# -REGION- Content-Length
|
||||||
|
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
#
|
|
||||||
#
|
|
||||||
# Nimrod's Runtime Library
|
|
||||||
# (c) Copyright 2010 Andreas Rumpf
|
|
||||||
#
|
|
||||||
# See the file "copying.txt", included in this
|
|
||||||
# distribution, for details about the copyright.
|
|
||||||
#
|
|
||||||
|
|
||||||
## Helpers for parsing.
|
|
||||||
|
|
||||||
import strutils
|
|
||||||
|
|
||||||
proc parseHex*(s: string, number: var int, start = 0): int =
|
|
||||||
## parses a hexadecimal number and stores its value in ``number``. Returns
|
|
||||||
## the number of the parsed characters or 0 in case of an error.
|
|
||||||
var i = start
|
|
||||||
var foundDigit = false
|
|
||||||
if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
|
||||||
elif s[i] == '#': inc(i)
|
|
||||||
while true:
|
|
||||||
case s[i]
|
|
||||||
of '_': nil
|
|
||||||
of '0'..'9':
|
|
||||||
number = number shl 4 or (ord(s[i]) - ord('0'))
|
|
||||||
foundDigit = true
|
|
||||||
of 'a'..'f':
|
|
||||||
number = number shl 4 or (ord(s[i]) - ord('a') + 10)
|
|
||||||
foundDigit = true
|
|
||||||
of 'A'..'F':
|
|
||||||
number = number shl 4 or (ord(s[i]) - ord('A') + 10)
|
|
||||||
foundDigit = true
|
|
||||||
else: break
|
|
||||||
inc(i)
|
|
||||||
if foundDigit: result = i-start
|
|
||||||
|
|
||||||
proc parseIdent*(s: string, ident: var string, start = 0): int =
|
|
||||||
## parses an identifier and stores it in ``ident``. Returns
|
|
||||||
## the number of the parsed characters or 0 in case of an error.
|
|
||||||
var i = start
|
|
||||||
if s[i] in IdentStartChars:
|
|
||||||
inc(i)
|
|
||||||
while s[i] in IdentChars: inc(i)
|
|
||||||
ident = copy(s, start, i-1)
|
|
||||||
result = i-start
|
|
||||||
|
|
||||||
proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
|
||||||
while s[start+result] in Whitespace: inc(result)
|
|
||||||
|
|
||||||
proc skip*(s, token: string, start = 0): int =
|
|
||||||
while result < token.len and s[result+start] == token[result]: inc(result)
|
|
||||||
if result != token.len: result = 0
|
|
||||||
|
|
||||||
proc skipIgnoreCase*(s, token: string, start = 0): int =
|
|
||||||
while result < token.len and
|
|
||||||
toLower(s[result+start]) == toLower(token[result]): inc(result)
|
|
||||||
if result != token.len: result = 0
|
|
||||||
|
|
||||||
proc parseBiggestInt*(s: string, number: var biggestInt, start = 0): int =
|
|
||||||
assert(false) # to implement
|
|
||||||
|
|
||||||
proc parseBiggestFloat*(s: string, number: var biggestFloat, start = 0): int =
|
|
||||||
assert(false) # to implement
|
|
||||||
225
lib/pure/parseutils.nim
Normal file
225
lib/pure/parseutils.nim
Normal file
|
|
@ -0,0 +1,225 @@
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Nimrod's Runtime Library
|
||||||
|
# (c) Copyright 2010 Andreas Rumpf
|
||||||
|
#
|
||||||
|
# See the file "copying.txt", included in this
|
||||||
|
# distribution, for details about the copyright.
|
||||||
|
#
|
||||||
|
|
||||||
|
## Helpers for parsing.
|
||||||
|
|
||||||
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
|
{.push debugger:off .} # the user does not want to trace a part
|
||||||
|
# of the standard library!
|
||||||
|
|
||||||
|
# copied from excpt.nim, because I don't want to make this template public
|
||||||
|
template newException(exceptn, message: expr): expr =
|
||||||
|
block: # open a new scope
|
||||||
|
var
|
||||||
|
e: ref exceptn
|
||||||
|
new(e)
|
||||||
|
e.msg = message
|
||||||
|
e
|
||||||
|
|
||||||
|
const
|
||||||
|
Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
|
||||||
|
Letters = {'A'..'Z', 'a'..'z'}
|
||||||
|
Digits = {'0'..'9'}
|
||||||
|
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
|
||||||
|
IdentStartChars = {'a'..'z', 'A'..'Z', '_'}
|
||||||
|
## copied from strutils
|
||||||
|
|
||||||
|
proc toLower(c: char): char {.inline.} =
|
||||||
|
result = if c in {'A'..'Z'}: chr(ord(c)-ord('A')+ord('a')) else: c
|
||||||
|
|
||||||
|
proc parseHex*(s: string, number: var int, start = 0): int =
|
||||||
|
## parses a hexadecimal number and stores its value in ``number``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error.
|
||||||
|
var i = start
|
||||||
|
var foundDigit = false
|
||||||
|
if s[i] == '0' and (s[i+1] == 'x' or s[i+1] == 'X'): inc(i, 2)
|
||||||
|
elif s[i] == '#': inc(i)
|
||||||
|
while true:
|
||||||
|
case s[i]
|
||||||
|
of '_': nil
|
||||||
|
of '0'..'9':
|
||||||
|
number = number shl 4 or (ord(s[i]) - ord('0'))
|
||||||
|
foundDigit = true
|
||||||
|
of 'a'..'f':
|
||||||
|
number = number shl 4 or (ord(s[i]) - ord('a') + 10)
|
||||||
|
foundDigit = true
|
||||||
|
of 'A'..'F':
|
||||||
|
number = number shl 4 or (ord(s[i]) - ord('A') + 10)
|
||||||
|
foundDigit = true
|
||||||
|
else: break
|
||||||
|
inc(i)
|
||||||
|
if foundDigit: result = i-start
|
||||||
|
|
||||||
|
proc parseOct*(s: string, number: var int, start = 0): int =
|
||||||
|
## parses an octal number and stores its value in ``number``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error.
|
||||||
|
var i = start
|
||||||
|
var foundDigit = false
|
||||||
|
if s[i] == '0' and (s[i+1] == 'o' or s[i+1] == 'O'): inc(i, 2)
|
||||||
|
while true:
|
||||||
|
case s[i]
|
||||||
|
of '_': nil
|
||||||
|
of '0'..'7':
|
||||||
|
number = number shl 3 or (ord(s[i]) - ord('0'))
|
||||||
|
foundDigit = true
|
||||||
|
else: break
|
||||||
|
inc(i)
|
||||||
|
if foundDigit: result = i-start
|
||||||
|
|
||||||
|
proc parseIdent*(s: string, ident: var string, start = 0): int =
|
||||||
|
## parses an identifier and stores it in ``ident``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error.
|
||||||
|
var i = start
|
||||||
|
if s[i] in IdentStartChars:
|
||||||
|
inc(i)
|
||||||
|
while s[i] in IdentChars: inc(i)
|
||||||
|
ident = copy(s, start, i-1)
|
||||||
|
result = i-start
|
||||||
|
|
||||||
|
proc parseToken*(s: string, token: var string, validChars: set[char],
|
||||||
|
start = 0): int =
|
||||||
|
## parses a token and stores it in ``token``. Returns
|
||||||
|
## the number of the parsed characters or 0 in case of an error. A token
|
||||||
|
## consists of the characters in `validChars`.
|
||||||
|
var i = start
|
||||||
|
while s[i] in validChars: inc(i)
|
||||||
|
result = i-start
|
||||||
|
token = copy(s, start, i-1)
|
||||||
|
|
||||||
|
proc skipWhitespace*(s: string, start = 0): int {.inline.} =
|
||||||
|
## skips the whitespace starting at ``s[start]``. Returns the number of
|
||||||
|
## skipped characters.
|
||||||
|
while s[start+result] in Whitespace: inc(result)
|
||||||
|
|
||||||
|
proc skip*(s, token: string, start = 0): int =
|
||||||
|
while result < token.len and s[result+start] == token[result]: inc(result)
|
||||||
|
if result != token.len: result = 0
|
||||||
|
|
||||||
|
proc skipIgnoreCase*(s, token: string, start = 0): int =
|
||||||
|
while result < token.len and
|
||||||
|
toLower(s[result+start]) == toLower(token[result]): inc(result)
|
||||||
|
if result != token.len: result = 0
|
||||||
|
|
||||||
|
{.push overflowChecks: on.}
|
||||||
|
# this must be compiled with overflow checking turned on:
|
||||||
|
proc rawParseInt(s: string, b: var biggestInt, start = 0): int =
|
||||||
|
var
|
||||||
|
sign: BiggestInt = -1
|
||||||
|
i = start
|
||||||
|
if s[i] == '+': inc(i)
|
||||||
|
elif s[i] == '-':
|
||||||
|
inc(i)
|
||||||
|
sign = 1
|
||||||
|
if s[i] in {'0'..'9'}:
|
||||||
|
b = 0
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
b = b * 10 - (ord(s[i]) - ord('0'))
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i) # underscores are allowed and ignored
|
||||||
|
b = b * sign
|
||||||
|
result = i - start
|
||||||
|
{.pop.} # overflowChecks
|
||||||
|
|
||||||
|
proc parseBiggestInt*(s: string, number: var biggestInt, start = 0): int =
|
||||||
|
## parses an integer starting at `start` and stores the value into `number`.
|
||||||
|
## Result is the number of processed chars or 0 if there is no integer.
|
||||||
|
## `EOverflow` is raised if an overflow occurs.
|
||||||
|
result = rawParseInt(s, number, start)
|
||||||
|
|
||||||
|
proc parseInt*(s: string, number: var int, start = 0): int =
|
||||||
|
## parses an integer starting at `start` and stores the value into `number`.
|
||||||
|
## Result is the number of processed chars or 0 if there is no integer.
|
||||||
|
## `EOverflow` is raised if an overflow occurs.
|
||||||
|
var res: biggestInt
|
||||||
|
result = parseBiggestInt(s, res, start)
|
||||||
|
if (sizeof(int) <= 4) and
|
||||||
|
((res < low(int)) or (res > high(int))):
|
||||||
|
raise newException(EOverflow, "overflow")
|
||||||
|
else:
|
||||||
|
number = int(res)
|
||||||
|
|
||||||
|
proc parseBiggestFloat*(s: string, number: var biggestFloat, start = 0): int =
|
||||||
|
## parses a float starting at `start` and stores the value into `number`.
|
||||||
|
## Result is the number of processed chars or 0 if there occured a parsing
|
||||||
|
## error.
|
||||||
|
var
|
||||||
|
esign = 1.0
|
||||||
|
sign = 1.0
|
||||||
|
i = start
|
||||||
|
exponent: int
|
||||||
|
flags: int
|
||||||
|
number = 0.0
|
||||||
|
if s[i] == '+': inc(i)
|
||||||
|
elif s[i] == '-':
|
||||||
|
sign = -1.0
|
||||||
|
inc(i)
|
||||||
|
if s[i] == 'N' or s[i] == 'n':
|
||||||
|
if s[i+1] == 'A' or s[i+1] == 'a':
|
||||||
|
if s[i+2] == 'N' or s[i+2] == 'n':
|
||||||
|
if s[i+3] notin IdentChars:
|
||||||
|
number = NaN
|
||||||
|
return i+3 - start
|
||||||
|
return 0
|
||||||
|
if s[i] == 'I' or s[i] == 'i':
|
||||||
|
if s[i+1] == 'N' or s[i+1] == 'n':
|
||||||
|
if s[i+2] == 'F' or s[i+2] == 'f':
|
||||||
|
if s[i+3] notin IdentChars:
|
||||||
|
number = Inf*sign
|
||||||
|
return i+3 - start
|
||||||
|
return 0
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
# Read integer part
|
||||||
|
flags = flags or 1
|
||||||
|
number = number * 10.0 + toFloat(ord(s[i]) - ord('0'))
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
# Decimal?
|
||||||
|
if s[i] == '.':
|
||||||
|
var hd = 1.0
|
||||||
|
inc(i)
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
# Read fractional part
|
||||||
|
flags = flags or 2
|
||||||
|
number = number * 10.0 + toFloat(ord(s[i]) - ord('0'))
|
||||||
|
hd = hd * 10.0
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
number = number / hd # this complicated way preserves precision
|
||||||
|
# Again, read integer and fractional part
|
||||||
|
if flags == 0: return 0
|
||||||
|
# Exponent?
|
||||||
|
if s[i] in {'e', 'E'}:
|
||||||
|
inc(i)
|
||||||
|
if s[i] == '+':
|
||||||
|
inc(i)
|
||||||
|
elif s[i] == '-':
|
||||||
|
esign = -1.0
|
||||||
|
inc(i)
|
||||||
|
if s[i] notin {'0'..'9'}:
|
||||||
|
return 0
|
||||||
|
while s[i] in {'0'..'9'}:
|
||||||
|
exponent = exponent * 10 + ord(s[i]) - ord('0')
|
||||||
|
inc(i)
|
||||||
|
while s[i] == '_': inc(i)
|
||||||
|
# Calculate Exponent
|
||||||
|
var hd = 1.0
|
||||||
|
for j in 1..exponent: hd = hd * 10.0
|
||||||
|
if esign > 0.0: number = number * hd
|
||||||
|
else: number = number / hd
|
||||||
|
# evaluate sign
|
||||||
|
number = number * sign
|
||||||
|
result = i - start
|
||||||
|
|
||||||
|
proc parseFloat*(s: string, number: var float, start = 0): int =
|
||||||
|
var bf: biggestFloat
|
||||||
|
result = parseBiggestFloat(s, bf, start)
|
||||||
|
number = bf
|
||||||
|
|
||||||
|
{.pop.}
|
||||||
|
|
@ -315,21 +315,22 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
|
||||||
r = r * 10 + (ord(buf[pos]) - ord('0'))
|
r = r * 10 + (ord(buf[pos]) - ord('0'))
|
||||||
inc(pos)
|
inc(pos)
|
||||||
add(dest, toUTF8(TRune(r)))
|
add(dest, toUTF8(TRune(r)))
|
||||||
elif buf[pos] == 'l' and buf[pos+1] == 't':
|
elif buf[pos] == 'l' and buf[pos+1] == 't' and buf[pos+2] == ';':
|
||||||
add(dest, '<')
|
add(dest, '<')
|
||||||
inc(pos, 2)
|
inc(pos, 2)
|
||||||
elif buf[pos] == 'g' and buf[pos+1] == 't':
|
elif buf[pos] == 'g' and buf[pos+1] == 't' and buf[pos+2] == ';':
|
||||||
add(dest, '>')
|
add(dest, '>')
|
||||||
inc(pos, 2)
|
inc(pos, 2)
|
||||||
elif buf[pos] == 'a' and buf[pos+1] == 'm' and buf[pos+2] == 'p':
|
elif buf[pos] == 'a' and buf[pos+1] == 'm' and buf[pos+2] == 'p'
|
||||||
|
and buf[pos+3] == ';':
|
||||||
add(dest, '&')
|
add(dest, '&')
|
||||||
inc(pos, 3)
|
inc(pos, 3)
|
||||||
elif buf[pos] == 'a' and buf[pos+1] == 'p' and buf[pos+2] == 'o' and
|
elif buf[pos] == 'a' and buf[pos+1] == 'p' and buf[pos+2] == 'o' and
|
||||||
buf[pos+3] == 's':
|
buf[pos+3] == 's' and buf[pos+4] == ';':
|
||||||
add(dest, '\'')
|
add(dest, '\'')
|
||||||
inc(pos, 4)
|
inc(pos, 4)
|
||||||
elif buf[pos] == 'q' and buf[pos+1] == 'u' and buf[pos+2] == 'o' and
|
elif buf[pos] == 'q' and buf[pos+1] == 'u' and buf[pos+2] == 'o' and
|
||||||
buf[pos+3] == 't':
|
buf[pos+3] == 't' and buf[pos+4] == ';':
|
||||||
add(dest, '"')
|
add(dest, '"')
|
||||||
inc(pos, 4)
|
inc(pos, 4)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@
|
||||||
## This module contains various string utility routines.
|
## This module contains various string utility routines.
|
||||||
## See the module `regexprs` for regular expression support.
|
## See the module `regexprs` for regular expression support.
|
||||||
|
|
||||||
|
import parseutils
|
||||||
|
|
||||||
{.deadCodeElim: on.}
|
{.deadCodeElim: on.}
|
||||||
|
|
||||||
{.push debugger:off .} # the user does not want to trace a part
|
{.push debugger:off .} # the user does not want to trace a part
|
||||||
|
|
@ -440,7 +442,7 @@ proc findNormalized(x: string, inArray: openarray[string]): int =
|
||||||
while i < high(inArray):
|
while i < high(inArray):
|
||||||
if cmpIgnoreStyle(x, inArray[i]) == 0: return i
|
if cmpIgnoreStyle(x, inArray[i]) == 0: return i
|
||||||
inc(i, 2) # incrementing by 1 would probably result in a
|
inc(i, 2) # incrementing by 1 would probably result in a
|
||||||
# security whole ...
|
# security hole ...
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
proc addf(s: var string, formatstr: string, a: openarray[string]) =
|
proc addf(s: var string, formatstr: string, a: openarray[string]) =
|
||||||
|
|
@ -686,56 +688,13 @@ proc toHex(x: BiggestInt, len: int): string =
|
||||||
result[j] = HexChars[toU32(x shr shift) and 0xF'i32]
|
result[j] = HexChars[toU32(x shr shift) and 0xF'i32]
|
||||||
shift = shift + 4
|
shift = shift + 4
|
||||||
|
|
||||||
{.push overflowChecks: on.}
|
|
||||||
# this must be compiled with overflow checking turned on:
|
|
||||||
proc rawParseInt(s: string, index: var int): BiggestInt =
|
|
||||||
# index contains the start position at proc entry; end position will be
|
|
||||||
# an index before the proc returns; index = -1 on error (no number at all)
|
|
||||||
# the problem here is that integers have an asymmetrical range: there is
|
|
||||||
# one more valid negative than prositive integer. Thus we perform the
|
|
||||||
# computation as a negative number and then change the sign at the end.
|
|
||||||
var
|
|
||||||
i = index # a local i is more efficient than accessing a var parameter
|
|
||||||
sign: BiggestInt = -1
|
|
||||||
if s[i] == '+':
|
|
||||||
inc(i)
|
|
||||||
elif s[i] == '-':
|
|
||||||
inc(i)
|
|
||||||
sign = 1
|
|
||||||
if s[i] in {'0'..'9'}:
|
|
||||||
result = 0
|
|
||||||
while s[i] in {'0'..'9'}:
|
|
||||||
result = result * 10 - (ord(s[i]) - ord('0'))
|
|
||||||
inc(i)
|
|
||||||
while s[i] == '_':
|
|
||||||
inc(i) # underscores are allowed and ignored
|
|
||||||
result = result * sign
|
|
||||||
if s[i] == '\0':
|
|
||||||
index = i # store index back
|
|
||||||
else:
|
|
||||||
index = -1 # BUGFIX: error!
|
|
||||||
else:
|
|
||||||
index = -1
|
|
||||||
|
|
||||||
{.pop.} # overflowChecks
|
|
||||||
|
|
||||||
proc parseInt(s: string): int =
|
proc parseInt(s: string): int =
|
||||||
var
|
var L = parseutils.parseInt(s, result, 0)
|
||||||
index = 0
|
if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)
|
||||||
res = rawParseInt(s, index)
|
|
||||||
if index == -1:
|
|
||||||
raise newException(EInvalidValue, "invalid integer: " & s)
|
|
||||||
elif (sizeof(int) <= 4) and
|
|
||||||
((res < low(int)) or (res > high(int))):
|
|
||||||
raise newException(EOverflow, "overflow")
|
|
||||||
else:
|
|
||||||
result = int(res) # convert to smaller integer type
|
|
||||||
|
|
||||||
proc ParseBiggestInt(s: string): biggestInt =
|
proc ParseBiggestInt(s: string): biggestInt =
|
||||||
var index = 0
|
var L = parseutils.parseBiggestInt(s, result, 0)
|
||||||
result = rawParseInt(s, index)
|
if L != s.len: raise newException(EInvalidValue, "invalid integer: " & s)
|
||||||
if index == -1:
|
|
||||||
raise newException(EInvalidValue, "invalid integer: " & s)
|
|
||||||
|
|
||||||
proc ParseOctInt*(s: string): int =
|
proc ParseOctInt*(s: string): int =
|
||||||
var i = 0
|
var i = 0
|
||||||
|
|
@ -769,72 +728,8 @@ proc ParseHexInt(s: string): int =
|
||||||
else: raise newException(EInvalidValue, "invalid integer: " & s)
|
else: raise newException(EInvalidValue, "invalid integer: " & s)
|
||||||
|
|
||||||
proc ParseFloat(s: string): float =
|
proc ParseFloat(s: string): float =
|
||||||
var
|
var L = parseutils.parseFloat(s, result, 0)
|
||||||
esign = 1.0
|
if L != s.len: raise newException(EInvalidValue, "invalid float: " & s)
|
||||||
sign = 1.0
|
|
||||||
i = 0
|
|
||||||
exponent: int
|
|
||||||
flags: int
|
|
||||||
result = 0.0
|
|
||||||
if s[i] == '+': inc(i)
|
|
||||||
elif s[i] == '-':
|
|
||||||
sign = -1.0
|
|
||||||
inc(i)
|
|
||||||
if s[i] == 'N' or s[i] == 'n':
|
|
||||||
if s[i+1] == 'A' or s[i+1] == 'a':
|
|
||||||
if s[i+2] == 'N' or s[i+2] == 'n':
|
|
||||||
if s[i+3] == '\0': return NaN
|
|
||||||
raise newException(EInvalidValue, "invalid float: " & s)
|
|
||||||
if s[i] == 'I' or s[i] == 'i':
|
|
||||||
if s[i+1] == 'N' or s[i+1] == 'n':
|
|
||||||
if s[i+2] == 'F' or s[i+2] == 'f':
|
|
||||||
if s[i+3] == '\0': return Inf*sign
|
|
||||||
raise newException(EInvalidValue, "invalid float: " & s)
|
|
||||||
while s[i] in {'0'..'9'}:
|
|
||||||
# Read integer part
|
|
||||||
flags = flags or 1
|
|
||||||
result = result * 10.0 + toFloat(ord(s[i]) - ord('0'))
|
|
||||||
inc(i)
|
|
||||||
while s[i] == '_': inc(i)
|
|
||||||
# Decimal?
|
|
||||||
if s[i] == '.':
|
|
||||||
var hd = 1.0
|
|
||||||
inc(i)
|
|
||||||
while s[i] in {'0'..'9'}:
|
|
||||||
# Read fractional part
|
|
||||||
flags = flags or 2
|
|
||||||
result = result * 10.0 + toFloat(ord(s[i]) - ord('0'))
|
|
||||||
hd = hd * 10.0
|
|
||||||
inc(i)
|
|
||||||
while s[i] == '_': inc(i)
|
|
||||||
result = result / hd # this complicated way preserves precision
|
|
||||||
# Again, read integer and fractional part
|
|
||||||
if flags == 0:
|
|
||||||
raise newException(EInvalidValue, "invalid float: " & s)
|
|
||||||
# Exponent?
|
|
||||||
if s[i] in {'e', 'E'}:
|
|
||||||
inc(i)
|
|
||||||
if s[i] == '+':
|
|
||||||
inc(i)
|
|
||||||
elif s[i] == '-':
|
|
||||||
esign = -1.0
|
|
||||||
inc(i)
|
|
||||||
if s[i] notin {'0'..'9'}:
|
|
||||||
raise newException(EInvalidValue, "invalid float: " & s)
|
|
||||||
while s[i] in {'0'..'9'}:
|
|
||||||
exponent = exponent * 10 + ord(s[i]) - ord('0')
|
|
||||||
inc(i)
|
|
||||||
while s[i] == '_': inc(i)
|
|
||||||
# Calculate Exponent
|
|
||||||
var hd = 1.0
|
|
||||||
for j in 1..exponent:
|
|
||||||
hd = hd * 10.0
|
|
||||||
if esign > 0.0: result = result * hd
|
|
||||||
else: result = result / hd
|
|
||||||
# Not all characters are read?
|
|
||||||
if s[i] != '\0': raise newException(EInvalidValue, "invalid float: " & s)
|
|
||||||
# evaluate sign
|
|
||||||
result = result * sign
|
|
||||||
|
|
||||||
proc toOct*(x: BiggestInt, len: int): string =
|
proc toOct*(x: BiggestInt, len: int): string =
|
||||||
## converts `x` into its octal representation. The resulting string is
|
## converts `x` into its octal representation. The resulting string is
|
||||||
|
|
|
||||||
|
|
@ -1460,6 +1460,13 @@ when not defined(EcmaScript) and not defined(NimrodVM):
|
||||||
yield res
|
yield res
|
||||||
Close(f)
|
Close(f)
|
||||||
|
|
||||||
|
iterator lines*(f: TFile): string =
|
||||||
|
## Iterate over any line in the file `f`.
|
||||||
|
var res = ""
|
||||||
|
while not endOfFile(f):
|
||||||
|
rawReadLine(f, res)
|
||||||
|
yield res
|
||||||
|
|
||||||
proc fileHandle*(f: TFile): TFileHandle {.importc: "fileno",
|
proc fileHandle*(f: TFile): TFileHandle {.importc: "fileno",
|
||||||
header: "<stdio.h>"}
|
header: "<stdio.h>"}
|
||||||
## returns the OS file handle of the file ``f``. This is only useful for
|
## returns the OS file handle of the file ``f``. This is only useful for
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,8 @@ Bugfixes
|
||||||
- Fixed bug #502670 (underscores in identifiers).
|
- Fixed bug #502670 (underscores in identifiers).
|
||||||
- Fixed a bug in the ``parsexml`` module concerning the parsing of
|
- Fixed a bug in the ``parsexml`` module concerning the parsing of
|
||||||
``<tag attr="value" />``.
|
``<tag attr="value" />``.
|
||||||
|
- Fixed a bug in the ``parsexml`` module concerning the parsing of
|
||||||
|
enities like ``<XX``.
|
||||||
- ``system.write(f: TFile, s: string)`` now works even if ``s`` contains binary
|
- ``system.write(f: TFile, s: string)`` now works even if ``s`` contains binary
|
||||||
zeros.
|
zeros.
|
||||||
|
|
||||||
|
|
@ -21,11 +23,13 @@ Bugfixes
|
||||||
Additions
|
Additions
|
||||||
---------
|
---------
|
||||||
- Added ``system.cstringArrayToSeq``.
|
- Added ``system.cstringArrayToSeq``.
|
||||||
|
- Added ``system.lines(f: TFile)`` iterator.
|
||||||
- Added ``cgi.decodeData(data: string): tuple[key, value: string]``.
|
- Added ``cgi.decodeData(data: string): tuple[key, value: string]``.
|
||||||
- Added ``ropes`` module.
|
- Added ``ropes`` module.
|
||||||
- Added ``sockets`` module.
|
- Added ``sockets`` module.
|
||||||
- Added ``browsers`` module.
|
- Added ``browsers`` module.
|
||||||
- Added ``httpserver`` module.
|
- Added ``httpserver`` module.
|
||||||
|
- Added ``parseutils`` module.
|
||||||
- Many wrappers now do not contain redundant name prefixes (like ``GTK_``,
|
- Many wrappers now do not contain redundant name prefixes (like ``GTK_``,
|
||||||
``lua``). The new wrappers are available in ``lib/newwrap``. Change
|
``lua``). The new wrappers are available in ``lib/newwrap``. Change
|
||||||
your configuration file to use these.
|
your configuration file to use these.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue