added system.del; delete; insert

This commit is contained in:
Andreas Rumpf
2010-02-02 19:20:16 +01:00
parent e22c73fd89
commit 6ecbed7284
5 changed files with 93 additions and 34 deletions

View File

@@ -17,7 +17,7 @@ type
TResponse* = tuple[
version: string, status: string, headers: seq[THeader],
body: string]
THeader* = tuple[htype: string, hvalue: string]
THeader* = tuple[htype, hvalue: string]
EInvalidProtocol* = object of EBase ## exception that is raised when server
## does not conform to the implemented
@@ -54,20 +54,49 @@ proc getHeaderValue*(headers: seq[THeader], name: string): string =
return headers[i].hvalue
return ""
proc parseChunks(data: var string, start: int, s: TSocket): string =
proc charAt(d: var string, i: var int, s: TSocket): char {.inline.} =
result = d[i]
while result == '\0':
d = s.recv()
i = 0
result = d[i]
proc parseChunks(d: var string, start: int, s: TSocket): string =
# get chunks:
var i = start
result = ""
while true:
var chunkSize = 0
var j = parseHex(data, chunkSize, i)
if j <= 0: break
inc(i, j)
while data[i] notin {'\C', '\L', '\0'}: inc(i)
if data[i] == '\C': inc(i)
if data[i] == '\L': inc(i)
if chunkSize <= 0: break
var x = copy(data, i, i+chunkSize-1)
var digitFound = false
echo "number: ", copy(d, i, i + 10)
while true:
case d[i]
of '0'..'9':
digitFound = true
chunkSize = chunkSize shl 4 or (ord(d[i]) - ord('0'))
of 'a'..'f':
digitFound = true
chunkSize = chunkSize shl 4 or (ord(d[i]) - ord('a') + 10)
of 'A'..'F':
digitFound = true
chunkSize = chunkSize shl 4 or (ord(d[i]) - ord('A') + 10)
of '\0':
d = s.recv()
i = -1
else: break
inc(i)
echo "chunksize: ", chunkSize
if chunkSize <= 0:
echo copy(d, i)
assert digitFound
break
while charAt(d, i, s) notin {'\C', '\L', '\0'}: inc(i)
if charAt(d, i, s) == '\C': inc(i)
if charAt(d, i, s) == '\L': inc(i)
else: httpError("CR-LF after chunksize expected")
var x = copy(d, i, i+chunkSize-1)
var size = x.len
result.add(x)
@@ -82,18 +111,17 @@ proc parseChunks(data: var string, start: int, s: TSocket): string =
dec(missing, bytesRead)
# next chunk:
data = s.recv()
d = s.recv()
i = 0
# skip trailing CR-LF:
while data[i] in {'\C', '\L'}: inc(i)
if data[i] == '\0': data.add(s.recv())
while charAt(d, i, s) in {'\C', '\L'}: inc(i)
proc parseBody(data: var string, start: int, s: TSocket,
proc parseBody(d: var string, start: int, s: TSocket,
headers: seq[THeader]): string =
if getHeaderValue(headers, "Transfer-Encoding") == "chunked":
result = parseChunks(data, start, s)
result = parseChunks(d, start, s)
else:
result = copy(data, start)
result = copy(d, start)
# -REGION- Content-Length
# (http://tools.ietf.org/html/rfc2616#section-4.4) NR.3
var contentLengthHeader = getHeaderValue(headers, "Content-Length")
@@ -112,7 +140,7 @@ proc parseBody(data: var string, start: int, s: TSocket,
result.add(moreData)
proc parseResponse(s: TSocket): TResponse =
var data = s.recv()
var d = s.recv()
var i = 0
# Parse the version
@@ -120,8 +148,8 @@ proc parseResponse(s: TSocket): TResponse =
# ``HTTP/1.1`` 200 OK
var matches: array[0..1, string]
var L = data.matchLen(peg"\i 'HTTP/' {'1.1'/'1.0'} \s+ {(!\n .)*}\n",
matches, i)
var L = d.matchLen(peg"\i 'HTTP/' {'1.1'/'1.0'} \s+ {(!\n .)*}\n",
matches, i)
if L < 0: httpError("invalid HTTP header")
result.version = matches[0]
@@ -135,29 +163,29 @@ proc parseResponse(s: TSocket): TResponse =
result.headers = @[]
while true:
var key = ""
while data[i] != ':':
if data[i] == '\0': httpError("invalid HTTP header, ':' expected")
key.add(data[i])
while d[i] != ':':
if d[i] == '\0': httpError("invalid HTTP header, ':' expected")
key.add(d[i])
inc(i)
inc(i) # skip ':'
if data[i] == ' ': inc(i) # skip if the character is a space
if d[i] == ' ': inc(i) # skip if the character is a space
var val = ""
while data[i] notin {'\C', '\L', '\0'}:
val.add(data[i])
while d[i] notin {'\C', '\L', '\0'}:
val.add(d[i])
inc(i)
result.headers.add((key, val))
if data[i] == '\C': inc(i)
if data[i] == '\L': inc(i)
if d[i] == '\C': inc(i)
if d[i] == '\L': inc(i)
else: httpError("invalid HTTP header, CR-LF expected")
if data[i] == '\C': inc(i)
if data[i] == '\L':
if d[i] == '\C': inc(i)
if d[i] == '\L':
inc(i)
break
result.body = parseBody(data, i, s, result.headers)
result.body = parseBody(d, i, s, result.headers)
proc request*(url: string): TResponse =
var r = parse(url)
@@ -169,6 +197,8 @@ proc request*(url: string): TResponse =
headers = "GET / HTTP/1.1\c\L"
add(headers, "Host: " & r.hostname & "\c\L\c\L")
add(headers, "User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.1; pl;" &
" rv:1.9.2) Gecko/20100115 Firefox/3.6")
var s = socket()
s.connect(r.hostname, TPort(80))
@@ -210,4 +240,7 @@ proc downloadFile*(url: string, outputFilename: string) =
when isMainModule:
downloadFile("http://www.google.com", "GoogleTest.html")
#downloadFile("http://force7.de/nimrod/index.html", "nimrodindex.html")
#downloadFile("http://www.httpwatch.com/", "ChunkTest.html")
downloadFile("http://www.httpwatch.com/httpgallery/chunked/", "ChunkTest.html")

0
lib/pure/parseutils.nim Normal file → Executable file
View File

View File

@@ -321,8 +321,8 @@ proc parseEntity(my: var TXmlParser, dest: var string) =
elif buf[pos] == 'g' and buf[pos+1] == 't' and buf[pos+2] == ';':
add(dest, '>')
inc(pos, 2)
elif buf[pos] == 'a' and buf[pos+1] == 'm' and buf[pos+2] == 'p'
and buf[pos+3] == ';':
elif buf[pos] == 'a' and buf[pos+1] == 'm' and buf[pos+2] == 'p' and
buf[pos+3] == ';':
add(dest, '&')
inc(pos, 3)
elif buf[pos] == 'a' and buf[pos+1] == 'p' and buf[pos+2] == 'o' and

View File

@@ -698,6 +698,31 @@ proc add *[T](x: var seq[T], y: openArray[T]) {.noSideEffect.} =
setLen(x, xl + y.len)
for i in 0..high(y): x[xl+i] = y[i]
proc del* [T](x: var seq[T], i: int) {.noSideEffect.} =
## deletes the item at index `i` by putting ``x[high(x)]`` into position `i`.
## This is an O(1) operation.
var xl = x.len
x[i] = x[xl-1]
setLen(x, xl-1)
proc delete*[T](x: var seq[T], i: int) {.noSideEffect.} =
## deletes the item at index `i` by moving ``x[i+1..]`` by one position.
## This is an O(n) operation.
var xl = x.len
for j in i..xl-2: x[j] = x[j+1]
setLen(x, xl-1)
proc insert*[T](x: var seq[T], item: T, i = 0) {.noSideEffect.} =
## inserts `item` into `x` at position `i`.
var xl = x.len
setLen(x, xl+1)
var j = xl-1
while j >= i:
x[j+1] = x[j]
inc(j)
x[i] = item
proc repr*[T](x: T): string {.magic: "Repr", noSideEffect.}
## takes any Nimrod variable and returns its string representation. It
## works even for complex data graphs with cycles. This is a great

View File

@@ -311,7 +311,8 @@ proc typeToYamlAux(n: PType, marker: var TIntSet, indent: int, maxRecDepth: int)
toRope("align"), toRope(n.align),
toRope("sons"), result])
proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int, maxRecDepth: int): PRope =
proc treeToYamlAux(n: PNode, marker: var TIntSet, indent: int,
maxRecDepth: int): PRope =
var istr: PRope
if n == nil:
result = toRope("null")