Merge branch 'devel' into newasync

This commit is contained in:
Dominik Picheta 2014-02-08 15:59:42 +00:00
commit a3f3efa1ba
848 changed files with 25966 additions and 75620 deletions

View file

@ -45,28 +45,28 @@ when noDeadlocks:
locksLen {.threadvar.}: int
locks {.threadvar.}: array [0..MaxLocksPerThread-1, pointer]
proc OrderedLocks(): bool =
proc orderedLocks(): bool =
for i in 0 .. locksLen-2:
if locks[i] >= locks[i+1]: return false
result = true
proc InitLock*(lock: var TLock) {.inline.} =
proc initLock*(lock: var TLock) {.inline.} =
## Initializes the given lock.
InitSysLock(lock)
initSysLock(lock)
proc DeinitLock*(lock: var TLock) {.inline.} =
proc deinitLock*(lock: var TLock) {.inline.} =
## Frees the resources associated with the lock.
DeinitSys(lock)
deinitSys(lock)
proc TryAcquire*(lock: var TLock): bool {.tags: [FAquireLock].} =
proc tryAcquire*(lock: var TLock): bool {.tags: [FAquireLock].} =
## Tries to acquire the given lock. Returns `true` on success.
result = TryAcquireSys(lock)
result = tryAcquireSys(lock)
when noDeadlocks:
if not result: return
# we have to add it to the ordered list. Oh, and we might fail if
# there is no space in the array left ...
if locksLen >= len(locks):
ReleaseSys(lock)
releaseSys(lock)
raise newException(EResourceExhausted, "cannot acquire additional lock")
# find the position to add:
var p = addr(lock)
@ -83,14 +83,14 @@ proc TryAcquire*(lock: var TLock): bool {.tags: [FAquireLock].} =
dec L
locks[i] = p
inc(locksLen)
assert OrderedLocks()
assert orderedLocks()
return
# simply add to the end:
locks[locksLen] = p
inc(locksLen)
assert OrderedLocks()
assert orderedLocks()
proc Acquire*(lock: var TLock) {.tags: [FAquireLock].} =
proc acquire*(lock: var TLock) {.tags: [FAquireLock].} =
## Acquires the given lock.
when nodeadlocks:
var p = addr(lock)
@ -106,36 +106,36 @@ proc Acquire*(lock: var TLock) {.tags: [FAquireLock].} =
raise newException(EResourceExhausted,
"cannot acquire additional lock")
while L >= i:
ReleaseSys(cast[ptr TSysLock](locks[L])[])
releaseSys(cast[ptr TSysLock](locks[L])[])
locks[L+1] = locks[L]
dec L
# acquire the current lock:
AcquireSys(lock)
acquireSys(lock)
locks[i] = p
inc(locksLen)
# acquire old locks in proper order again:
L = locksLen-1
inc i
while i <= L:
AcquireSys(cast[ptr TSysLock](locks[i])[])
acquireSys(cast[ptr TSysLock](locks[i])[])
inc(i)
# DANGER: We can only modify this global var if we gained every lock!
# NO! We need an atomic increment. Crap.
discard system.atomicInc(deadlocksPrevented, 1)
assert OrderedLocks()
assert orderedLocks()
return
# simply add to the end:
if locksLen >= len(locks):
raise newException(EResourceExhausted, "cannot acquire additional lock")
AcquireSys(lock)
acquireSys(lock)
locks[locksLen] = p
inc(locksLen)
assert OrderedLocks()
assert orderedLocks()
else:
AcquireSys(lock)
acquireSys(lock)
proc Release*(lock: var TLock) {.tags: [FReleaseLock].} =
proc release*(lock: var TLock) {.tags: [FReleaseLock].} =
## Releases the given lock.
when nodeadlocks:
var p = addr(lock)
@ -145,20 +145,20 @@ proc Release*(lock: var TLock) {.tags: [FReleaseLock].} =
for j in i..L-2: locks[j] = locks[j+1]
dec locksLen
break
ReleaseSys(lock)
releaseSys(lock)
proc InitCond*(cond: var TCond) {.inline.} =
proc initCond*(cond: var TCond) {.inline.} =
## Initializes the given condition variable.
InitSysCond(cond)
initSysCond(cond)
proc DeinitCond*(cond: var TCond) {.inline.} =
proc deinitCond*(cond: var TCond) {.inline.} =
## Frees the resources associated with the lock.
DeinitSysCond(cond)
deinitSysCond(cond)
proc wait*(cond: var TCond, lock: var TLock) {.inline.} =
## waits on the condition variable `cond`.
WaitSysCond(cond, lock)
waitSysCond(cond, lock)
proc signal*(cond: var TCond) {.inline.} =
## sends a signal to the condition variable `cond`.

View file

@ -59,7 +59,8 @@ type
nnkBindStmt, nnkMixinStmt, nnkUsingStmt,
nnkCommentStmt, nnkStmtListExpr, nnkBlockExpr,
nnkStmtListType, nnkBlockType, nnkTypeOfExpr, nnkObjectTy,
nnkTupleTy, nnkTypeClassTy, nnkRecList, nnkRecCase, nnkRecWhen,
nnkTupleTy, nnkTypeClassTy, nnkStaticTy,
nnkRecList, nnkRecCase, nnkRecWhen,
nnkRefTy, nnkPtrTy, nnkVarTy,
nnkConstTy, nnkMutableTy,
nnkDistinctTy,
@ -147,18 +148,24 @@ proc del*(father: PNimrodNode, idx = 0, n = 1) {.magic: "NDel".}
proc kind*(n: PNimrodNode): TNimrodNodeKind {.magic: "NKind".}
## returns the `kind` of the node `n`.
proc intVal*(n: PNimrodNode): biggestInt {.magic: "NIntVal".}
proc floatVal*(n: PNimrodNode): biggestFloat {.magic: "NFloatVal".}
proc intVal*(n: PNimrodNode): BiggestInt {.magic: "NIntVal".}
proc floatVal*(n: PNimrodNode): BiggestFloat {.magic: "NFloatVal".}
proc symbol*(n: PNimrodNode): PNimrodSymbol {.magic: "NSymbol".}
proc ident*(n: PNimrodNode): TNimrodIdent {.magic: "NIdent".}
proc typ*(n: PNimrodNode): typedesc {.magic: "NGetType".}
proc strVal*(n: PNimrodNode): string {.magic: "NStrVal".}
proc `intVal=`*(n: PNimrodNode, val: biggestInt) {.magic: "NSetIntVal".}
proc `floatVal=`*(n: PNimrodNode, val: biggestFloat) {.magic: "NSetFloatVal".}
proc `intVal=`*(n: PNimrodNode, val: BiggestInt) {.magic: "NSetIntVal".}
proc `floatVal=`*(n: PNimrodNode, val: BiggestFloat) {.magic: "NSetFloatVal".}
proc `symbol=`*(n: PNimrodNode, val: PNimrodSymbol) {.magic: "NSetSymbol".}
proc `ident=`*(n: PNimrodNode, val: TNimrodIdent) {.magic: "NSetIdent".}
proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
#proc `typ=`*(n: PNimrodNode, typ: typedesc) {.magic: "NSetType".}
# this is not sound! Unfortunately forbidding 'typ=' is not enough, as you
# can easily do:
# let bracket = semCheck([1, 2])
# let fake = semCheck(2.0)
# bracket[0] = fake # constructs a mixed array with ints and floats!
proc `strVal=`*(n: PNimrodNode, val: string) {.magic: "NSetStrVal".}
proc newNimNode*(kind: TNimrodNodeKind,
@ -181,12 +188,12 @@ proc newStrLitNode*(s: string): PNimrodNode {.compileTime.} =
result = newNimNode(nnkStrLit)
result.strVal = s
proc newIntLitNode*(i: biggestInt): PNimrodNode {.compileTime.} =
proc newIntLitNode*(i: BiggestInt): PNimrodNode {.compileTime.} =
## creates a int literal node from `i`
result = newNimNode(nnkIntLit)
result.intVal = i
proc newFloatLitNode*(f: biggestFloat): PNimrodNode {.compileTime.} =
proc newFloatLitNode*(f: BiggestFloat): PNimrodNode {.compileTime.} =
## creates a float literal node from `f`
result = newNimNode(nnkFloatLit)
result.floatVal = f
@ -268,6 +275,8 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
##
## Example:
##
## .. code-block:: nimrod
##
## macro check(ex: expr): stmt =
## # this is a simplified version of the check macro from the
## # unittest module.
@ -285,15 +294,6 @@ proc quote*(bl: stmt, op = "``"): PNimrodNode {.magic: "QuoteAst".}
## if not `ex`:
## echo `info` & ": Check failed: " & `expString`
template emit*(e: expr[string]): stmt =
## accepts a single string argument and treats it as nimrod code
## that should be inserted verbatim in the program
## Example:
##
## emit("echo " & '"' & "hello world".toUpper & '"')
##
eval: result = e.parseStmt
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case,
## compilation aborts with an error message. This is useful for writing
@ -341,12 +341,12 @@ proc newLit*(c: char): PNimrodNode {.compileTime.} =
result = newNimNode(nnkCharLit)
result.intVal = ord(c)
proc newLit*(i: biggestInt): PNimrodNode {.compileTime.} =
proc newLit*(i: BiggestInt): PNimrodNode {.compileTime.} =
## produces a new integer literal node.
result = newNimNode(nnkIntLit)
result.intVal = i
proc newLit*(f: biggestFloat): PNimrodNode {.compileTime.} =
proc newLit*(f: BiggestFloat): PNimrodNode {.compileTime.} =
## produces a new float literal node.
result = newNimNode(nnkFloatLit)
result.floatVal = f
@ -377,7 +377,7 @@ proc treeRepr*(n: PNimrodNode): string {.compileTime.} =
res.add(($n.kind).substr(3))
case n.kind
of nnkEmpty: nil # same as nil node in this representation
of nnkEmpty: discard # same as nil node in this representation
of nnkNilLit: res.add(" nil")
of nnkCharLit..nnkInt64Lit: res.add(" " & $n.intVal)
of nnkFloatLit..nnkFloat64Lit: res.add(" " & $n.floatVal)
@ -402,13 +402,14 @@ proc lispRepr*(n: PNimrodNode): string {.compileTime.} =
add(result, "(")
case n.kind
of nnkEmpty: nil # same as nil node in this representation
of nnkEmpty: discard # same as nil node in this representation
of nnkNilLit: add(result, "nil")
of nnkCharLit..nnkInt64Lit: add(result, $n.intVal)
of nnkFloatLit..nnkFloat64Lit: add(result, $n.floatVal)
of nnkStrLit..nnkTripleStrLit: add(result, $n.strVal)
of nnkIdent: add(result, "!\"" & $n.ident & '"')
of nnkSym, nnkNone: assert false
of nnkSym: add(result, $n.symbol)
of nnkNone: assert false
else:
add(result, lispRepr(n[0]))
for j in 1..n.len-1:
@ -474,6 +475,34 @@ proc newDotExpr*(a, b: PNimrodNode): PNimrodNode {.compileTime.} =
proc newIdentDefs*(name, kind: PNimrodNode;
default = newEmptyNode()): PNimrodNode {.compileTime.} =
## Creates a new ``nnkIdentDefs`` node of a specific kind and value.
##
## ``nnkIdentDefs`` need to have at least three children, but they can have
## more: first comes a list of identifiers followed by a type and value
## nodes. This helper proc creates a three node subtree, the first subnode
## being a single identifier name. Both the ``kind`` node and ``default``
## (value) nodes may be empty depending on where the ``nnkIdentDefs``
## appears: tuple or object definitions will have an empty ``default`` node,
## ``let`` or ``var`` blocks may have an empty ``kind`` node if the
## identifier is being assigned a value. Example:
##
## .. code-block:: nimrod
##
## var varSection = newNimNode(nnkVarSection).add(
## newIdentDefs(ident("a"), ident("string")),
## newIdentDefs(ident("b"), newEmptyNode(), newLit(3)))
## # --> var
## # a: string
## # b = 3
##
## If you need to create multiple identifiers you need to use the lower level
## ``newNimNode``:
##
## .. code-block:: nimrod
##
## result = newNimNode(nnkIdentDefs).add(
## ident("a"), ident("b"), ident("c"), ident("string"),
## newStrLitNode("Hello"))
newNimNode(nnkIdentDefs).add(name, kind, default)
proc newNilLit*(): PNimrodNode {.compileTime.} =
@ -494,14 +523,14 @@ const
from strutils import cmpIgnoreStyle, format
proc ExpectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
proc expectKind*(n: PNimrodNode; k: set[TNimrodNodeKind]) {.compileTime.} =
assert n.kind in k, "Expected one of $1, got $2".format(k, n.kind)
proc newProc*(name = newEmptyNode(); params: openarray[PNimrodNode] = [];
proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()];
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
## shortcut for creating a new proc
##
## The ``params`` array should start with the return type of the proc,
## The ``params`` array must start with the return type of the proc,
## followed by a list of IdentDefs which specify the params.
assert procType in RoutineNodes
result = newNimNode(procType).add(
@ -535,7 +564,7 @@ proc copyChildrenTo*(src, dest: PNimrodNode) {.compileTime.}=
dest.add src[i].copyNimTree
template expectRoutine(node: PNimrodNode): stmt =
expectKind(node, routineNodes)
expectKind(node, RoutineNodes)
proc name*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
someProc.expectRoutine
@ -572,7 +601,7 @@ proc body*(someProc: PNimrodNode): PNimrodNode {.compileTime.} =
of routineNodes:
return someProc[6]
of nnkBlockStmt, nnkWhileStmt:
return someproc[1]
return someProc[1]
of nnkForStmt:
return someProc.last
else:
@ -596,7 +625,7 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} =
of nnkIdent:
result = $node.ident
of nnkStrLit:
result = node.strval
result = node.strVal
else:
badNodeKind node.kind, "$"
@ -607,10 +636,13 @@ iterator children*(n: PNimrodNode): PNimrodNode {.inline.}=
for i in 0 .. high(n):
yield n[i]
template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.immediate, dirty.} =
## Find the first child node matching condition (or nil)
## var res = findChild(n, it.kind == nnkPostfix and it.basename.ident == !"foo")
template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.
immediate, dirty.} =
## Find the first child node matching condition (or nil).
##
## .. code-block:: nimrod
## var res = findChild(n, it.kind == nnkPostfix and
## it.basename.ident == !"foo")
block:
var result: PNimrodNode
for it in n.children:
@ -619,7 +651,7 @@ template findChild*(n: PNimrodNode; cond: expr): PNimrodNode {.immediate, dirty.
break
result
proc insert*(a: PNimrodNOde; pos: int; b: PNimrodNode) {.compileTime.} =
proc insert*(a: PNimrodNode; pos: int; b: PNimrodNode) {.compileTime.} =
## Insert node B into A at pos
if high(a) < pos:
## add some empty nodes first
@ -640,14 +672,14 @@ proc basename*(a: PNimrodNode): PNimrodNode {.compiletime.} =
of nnkIdent: return a
of nnkPostfix, nnkPrefix: return a[1]
else:
quit "Do not know how to get basename of ("& treerepr(a) &")\n"& repr(a)
quit "Do not know how to get basename of ("& treeRepr(a) &")\n"& repr(a)
proc `basename=`*(a: PNimrodNode; val: string) {.compileTime.}=
case a.kind
of nnkIdent: macros.`ident=`(a, !val)
of nnkPostfix, nnkPrefix: a[1] = ident(val)
else:
quit "Do not know how to get basename of ("& treerepr(a)& ")\n"& repr(a)
quit "Do not know how to get basename of ("& treeRepr(a)& ")\n"& repr(a)
proc postfix*(node: PNimrodNode; op: string): PNimrodNode {.compileTime.} =
newNimNode(nnkPostfix).add(ident(op), node)
@ -698,6 +730,18 @@ proc addIdentIfAbsent*(dest: PNimrodNode, ident: string) {.compiletime.} =
if ident.eqIdent($node): return
of nnkExprColonExpr:
if ident.eqIdent($node[0]): return
else: nil
else: discard
dest.add(ident(ident))
when not defined(booting):
template emit*(e: static[string]): stmt =
## accepts a single string argument and treats it as nimrod code
## that should be inserted verbatim in the program
## Example:
##
## .. code-block:: nimrod
## emit("echo " & '"' & "hello world".toUpper & '"')
##
macro payload: stmt {.gensym.} =
result = parseStmt(e)
payload()

View file

@ -47,18 +47,18 @@ proc dbError*(db: TDbConn, msg: string) {.noreturn.} =
e.msg = $db.err & " " & msg
raise e
proc Close*(db: var TDbConn) {.tags: [FDB].} =
proc close*(db: var TDbConn) {.tags: [FDB].} =
## closes the database connection.
disconnect(db)
destroy(db)
proc Open*(host: string = defaultHost, port: int = defaultPort): TDbConn {.
proc open*(host: string = defaultHost, port: int = defaultPort): TDbConn {.
tags: [FDB].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established.
init(result)
let x = connect(result, host, port.cint)
let x = client(result, host, port.cint)
if x != 0'i32:
dbError(result, "cannot open: " & host)
@ -113,13 +113,13 @@ proc getId*(obj: var TBSon): TOid =
else:
raise newException(EInvalidIndex, "_id not in object")
proc insertID*(db: var TDbConn, namespace: string, data: PJsonNode): TOid {.
proc insertId*(db: var TDbConn, namespace: string, data: PJsonNode): TOid {.
tags: [FWriteDb].} =
## converts `data` to BSON format and inserts it in `namespace`. Returns
## the generated OID for the ``_id`` field.
result = genOid()
var x = jsonToBSon(data, result)
insert(db, namespace, x)
insert(db, namespace, x, nil)
destroy(x)
proc insert*(db: var TDbConn, namespace: string, data: PJsonNode) {.

View file

@ -65,7 +65,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc TryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool {.
proc tryExec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]): bool {.
tags: [FReadDB, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var q = dbFormat(query, args)
@ -75,7 +75,7 @@ proc rawExec(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) =
var q = dbFormat(query, args)
if mysql.RealQuery(db, q, q.len) != 0'i32: dbError(db)
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDB, FWriteDb].} =
## executes the query and raises EDB if not successful.
var q = dbFormat(query, args)
@ -90,7 +90,7 @@ proc properFreeResult(sqlres: mysql.PRES, row: cstringArray) =
while mysql.FetchRow(sqlres) != nil: nil
mysql.FreeResult(sqlres)
iterator FastRows*(db: TDbConn, query: TSqlQuery,
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
@ -126,7 +126,7 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
add(result[i], row[i])
properFreeResult(sqlres, row)
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
## executes the query and returns the whole result dataset.
result = @[]
@ -145,12 +145,12 @@ proc GetAllRows*(db: TDbConn, query: TSqlQuery,
inc(j)
mysql.FreeResult(sqlres)
iterator Rows*(db: TDbConn, query: TSqlQuery,
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
## same as `FastRows`, but slower and safe.
for r in items(GetAllRows(db, query, args)): yield r
proc GetValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -160,7 +160,7 @@ proc GetValue*(db: TDbConn, query: TSqlQuery,
result = row[0]
break
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
proc tryInsertId*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error.
@ -170,14 +170,14 @@ proc TryInsertID*(db: TDbConn, query: TSqlQuery,
else:
result = mysql.InsertId(db)
proc InsertID*(db: TDbConn, query: TSqlQuery,
proc insertId*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row.
result = TryInsertID(db, query, args)
if result < 0: dbError(db)
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.
tags: [FReadDB, FWriteDb].} =
## runs the query (typically "UPDATE") and returns the
@ -185,11 +185,11 @@ proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
rawExec(db, query, args)
result = mysql.AffectedRows(db)
proc Close*(db: TDbConn) {.tags: [FDb].} =
proc close*(db: TDbConn) {.tags: [FDb].} =
## closes the database connection.
if db != nil: mysql.Close(db)
if db != nil: mysql.close(db)
proc Open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): TDbConn {.
tags: [FDb].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established.

View file

@ -64,7 +64,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc TryExec*(db: TDbConn, query: TSqlQuery,
proc tryExec*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var q = dbFormat(query, args)
@ -72,7 +72,7 @@ proc TryExec*(db: TDbConn, query: TSqlQuery,
result = PQresultStatus(res) == PGRES_COMMAND_OK
PQclear(res)
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDB, FWriteDb].} =
## executes the query and raises EDB if not successful.
var q = dbFormat(query, args)
@ -96,7 +96,7 @@ proc setRow(res: PPGresult, r: var TRow, line, cols: int32) =
var x = PQgetvalue(res, line, col)
add(r[col], x)
iterator FastRows*(db: TDbConn, query: TSqlQuery,
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
@ -119,19 +119,19 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
setRow(res, result, 0, L)
PQclear(res)
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
## executes the query and returns the whole result dataset.
result = @[]
for r in FastRows(db, query, args):
result.add(r)
iterator Rows*(db: TDbConn, query: TSqlQuery,
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
## same as `FastRows`, but slower and safe.
for r in items(GetAllRows(db, query, args)): yield r
proc GetValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -139,7 +139,7 @@ proc GetValue*(db: TDbConn, query: TSqlQuery,
var x = PQgetvalue(setupQuery(db, query, args), 0, 0)
result = if isNil(x): "" else: $x
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].}=
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error. For Postgre this adds
@ -152,7 +152,7 @@ proc TryInsertID*(db: TDbConn, query: TSqlQuery,
else:
result = -1
proc InsertID*(db: TDbConn, query: TSqlQuery,
proc insertID*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row. For Postgre this adds
@ -161,7 +161,7 @@ proc InsertID*(db: TDbConn, query: TSqlQuery,
result = TryInsertID(db, query, args)
if result < 0: dbError(db)
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.tags: [
FReadDB, FWriteDb].} =
## executes the query (typically "UPDATE") and returns the
@ -172,14 +172,29 @@ proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
result = parseBiggestInt($PQcmdTuples(res))
PQclear(res)
proc Close*(db: TDbConn) {.tags: [FDb].} =
proc close*(db: TDbConn) {.tags: [FDb].} =
## closes the database connection.
if db != nil: PQfinish(db)
proc Open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): TDbConn {.
tags: [FDb].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established.
##
## Clients can also use Postgres keyword/value connection strings to
## connect.
##
## Example:
##
## .. code-block:: nimrod
##
## con = Open("", "", "", "host=localhost port=5432 dbname=mydb")
##
## See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
## for more information.
##
## Note that the connection parameter is not used but exists to maintain
## the nimrod db api.
result = PQsetdbLogin(nil, nil, nil, nil, database, user, password)
if PQStatus(result) != CONNECTION_OK: dbError(result) # result = nil

View file

@ -64,7 +64,7 @@ proc dbFormat(formatstr: TSqlQuery, args: varargs[string]): string =
else:
add(result, c)
proc TryExec*(db: TDbConn, query: TSqlQuery,
proc tryExec*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): bool {.tags: [FReadDB, FWriteDb].} =
## tries to execute the query and returns true if successful, false otherwise.
var q = dbFormat(query, args)
@ -73,10 +73,10 @@ proc TryExec*(db: TDbConn, query: TSqlQuery,
if step(stmt) == SQLITE_DONE:
result = finalize(stmt) == SQLITE_OK
proc Exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
proc exec*(db: TDbConn, query: TSqlQuery, args: varargs[string, `$`]) {.
tags: [FReadDB, FWriteDb].} =
## executes the query and raises EDB if not successful.
if not TryExec(db, query, args): dbError(db)
if not tryExec(db, query, args): dbError(db)
proc newRow(L: int): TRow =
newSeq(result, L)
@ -94,7 +94,7 @@ proc setRow(stmt: PStmt, r: var TRow, cols: cint) =
let x = column_text(stmt, col)
if not isNil(x): add(r[col], x)
iterator FastRows*(db: TDbConn, query: TSqlQuery,
iterator fastRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
## executes the query and iterates over the result dataset. This is very
## fast, but potenially dangerous: If the for-loop-body executes another
@ -118,19 +118,19 @@ proc getRow*(db: TDbConn, query: TSqlQuery,
setRow(stmt, result, L)
if finalize(stmt) != SQLITE_OK: dbError(db)
proc GetAllRows*(db: TDbConn, query: TSqlQuery,
proc getAllRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): seq[TRow] {.tags: [FReadDB].} =
## executes the query and returns the whole result dataset.
result = @[]
for r in FastRows(db, query, args):
for r in fastRows(db, query, args):
result.add(r)
iterator Rows*(db: TDbConn, query: TSqlQuery,
iterator rows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): TRow {.tags: [FReadDB].} =
## same as `FastRows`, but slower and safe.
for r in FastRows(db, query, args): yield r
for r in fastRows(db, query, args): yield r
proc GetValue*(db: TDbConn, query: TSqlQuery,
proc getValue*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): string {.tags: [FReadDB].} =
## executes the query and returns the first column of the first row of the
## result dataset. Returns "" if the dataset contains no rows or the database
@ -143,44 +143,46 @@ proc GetValue*(db: TDbConn, query: TSqlQuery,
else:
result = newStringOfCap(cb)
add(result, column_text(stmt, 0))
if finalize(stmt) != SQLITE_OK: dbError(db)
else:
result = ""
if finalize(stmt) != SQLITE_OK: dbError(db)
proc TryInsertID*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
proc tryInsertID*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64
{.tags: [FWriteDb], raises: [].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row or -1 in case of an error.
var q = dbFormat(query, args)
var stmt: sqlite3.PStmt
result = -1
if prepare_v2(db, q, q.len.cint, stmt, nil) == SQLITE_OK:
if step(stmt) == SQLITE_DONE:
if finalize(stmt) == SQLITE_OK:
return last_insert_rowid(db)
result = -1
result = last_insert_rowid(db)
if finalize(stmt) != SQLITE_OK:
result = -1
proc InsertID*(db: TDbConn, query: TSqlQuery,
proc insertID*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.tags: [FWriteDb].} =
## executes the query (typically "INSERT") and returns the
## generated ID for the row. For Postgre this adds
## ``RETURNING id`` to the query, so it only works if your primary key is
## named ``id``.
result = TryInsertID(db, query, args)
result = tryInsertID(db, query, args)
if result < 0: dbError(db)
proc ExecAffectedRows*(db: TDbConn, query: TSqlQuery,
proc execAffectedRows*(db: TDbConn, query: TSqlQuery,
args: varargs[string, `$`]): int64 {.
tags: [FReadDB, FWriteDb].} =
## executes the query (typically "UPDATE") and returns the
## number of affected rows.
Exec(db, query, args)
exec(db, query, args)
result = changes(db)
proc Close*(db: TDbConn) {.tags: [FDB].} =
proc close*(db: TDbConn) {.tags: [FDB].} =
## closes the database connection.
if sqlite3.close(db) != SQLITE_OK: dbError(db)
proc Open*(connection, user, password, database: string): TDbConn {.
proc open*(connection, user, password, database: string): TDbConn {.
tags: [FDB].} =
## opens a database connection. Raises `EDb` if the connection could not
## be established. Only the ``connection`` parameter is used for ``sqlite``.
@ -192,7 +194,7 @@ proc Open*(connection, user, password, database: string): TDbConn {.
when isMainModule:
var db = open("db.sql", "", "", "")
Exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
exec(db, sql"insert into tbl1 values('hello!',10)", [])
exec(db, sql"insert into tbl1 values('goodbye', 20)", [])
#db.query("create table tbl1(one varchar(10), two smallint)")

View file

@ -57,7 +57,7 @@ proc error*(window: PWindow, msg: string) =
destroy(PWidget(dialog))
proc ChooseFileToOpen*(window: PWindow, root: string = ""): string =
proc chooseFileToOpen*(window: PWindow, root: string = ""): string =
## Opens a dialog that requests a filename from the user. Returns ""
## if the user closed the dialog without selecting a file. On Windows,
## the native dialog is used, else the GTK dialog is used.
@ -92,7 +92,7 @@ proc ChooseFileToOpen*(window: PWindow, root: string = ""): string =
result = ""
destroy(PWidget(chooser))
proc ChooseFilesToOpen*(window: PWindow, root: string = ""): seq[string] =
proc chooseFilesToOpen*(window: PWindow, root: string = ""): seq[string] =
## Opens a dialog that requests filenames from the user. Returns ``@[]``
## if the user closed the dialog without selecting a file. On Windows,
## the native dialog is used, else the GTK dialog is used.
@ -153,7 +153,7 @@ proc ChooseFilesToOpen*(window: PWindow, root: string = ""): seq[string] =
destroy(PWidget(chooser))
proc ChooseFileToSave*(window: PWindow, root: string = ""): string =
proc chooseFileToSave*(window: PWindow, root: string = ""): string =
## Opens a dialog that requests a filename to save to from the user.
## Returns "" if the user closed the dialog without selecting a file.
## On Windows, the native dialog is used, else the GTK dialog is used.
@ -190,7 +190,7 @@ proc ChooseFileToSave*(window: PWindow, root: string = ""): string =
destroy(PWidget(chooser))
proc ChooseDir*(window: PWindow, root: string = ""): string =
proc chooseDir*(window: PWindow, root: string = ""): string =
## Opens a dialog that requests a directory from the user.
## Returns "" if the user closed the dialog without selecting a directory.
## On Windows, the native dialog is used, else the GTK dialog is used.

View file

@ -343,7 +343,7 @@ proc fillRect*(sur: PSurface, r: TRect, col: TColor) =
if sdl.FillRect(sur.s, addr(rect), sur.createSdlColor(col)) == -1:
raiseEGraphics()
proc Plot4EllipsePoints(sur: PSurface, CX, CY, X, Y: Natural, col: TColor) =
proc plot4EllipsePoints(sur: PSurface, CX, CY, X, Y: Natural, col: TColor) =
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch.int div ColSize
if CX+X <= sur.s.w-1:

View file

@ -151,7 +151,7 @@ const
# GetSystemMetrics
SM_SERVERR2 = 89
proc GlobalMemoryStatusEx*(lpBuffer: var TMEMORYSTATUSEX){.stdcall, dynlib: "kernel32",
proc globalMemoryStatusEx*(lpBuffer: var TMEMORYSTATUSEX){.stdcall, dynlib: "kernel32",
importc: "GlobalMemoryStatusEx".}
proc getMemoryInfo*(): TMemoryInfo =
@ -159,7 +159,7 @@ proc getMemoryInfo*(): TMemoryInfo =
var statex: TMEMORYSTATUSEX
statex.dwLength = sizeof(statex).int32
GlobalMemoryStatusEx(statex)
globalMemoryStatusEx(statex)
result.MemoryLoad = statex.dwMemoryLoad
result.TotalPhysMem = statex.ullTotalPhys
result.AvailablePhysMem = statex.ullAvailPhys
@ -168,20 +168,20 @@ proc getMemoryInfo*(): TMemoryInfo =
result.TotalVirtualMem = statex.ullTotalVirtual
result.AvailableVirtualMem = statex.ullAvailExtendedVirtual
proc GetVersionEx*(lpVersionInformation: var TOSVERSIONINFOEX): WINBOOL{.stdcall,
proc getVersionEx*(lpVersionInformation: var TOSVERSIONINFOEX): WINBOOL{.stdcall,
dynlib: "kernel32", importc: "GetVersionExA".}
proc GetProcAddress*(hModule: int, lpProcName: cstring): pointer{.stdcall,
proc getProcAddress*(hModule: int, lpProcName: cstring): pointer{.stdcall,
dynlib: "kernel32", importc: "GetProcAddress".}
proc GetModuleHandleA*(lpModuleName: cstring): int{.stdcall,
dynlib: "kernel32", importc.}
proc getModuleHandleA*(lpModuleName: cstring): int{.stdcall,
dynlib: "kernel32", importc: "GetModuleHandleA".}
proc getVersionInfo*(): TVersionInfo =
## Retrieves operating system info
var osvi: TOSVERSIONINFOEX
osvi.dwOSVersionInfoSize = sizeof(osvi).int32
discard GetVersionEx(osvi)
discard getVersionEx(osvi)
result.majorVersion = osvi.dwMajorVersion
result.minorVersion = osvi.dwMinorVersion
result.buildNumber = osvi.dwBuildNumber
@ -197,8 +197,8 @@ proc getProductInfo*(majorVersion, minorVersion, SPMajorVersion,
## Retrieves Windows' ProductInfo, this function only works in Vista and 7
var pGPI = cast[proc (dwOSMajorVersion, dwOSMinorVersion,
dwSpMajorVersion, dwSpMinorVersion: int32, outValue: Pint32)](GetProcAddress(
GetModuleHandleA("kernel32.dll"), "GetProductInfo"))
dwSpMajorVersion, dwSpMinorVersion: int32, outValue: Pint32)](getProcAddress(
getModuleHandleA("kernel32.dll"), "GetProductInfo"))
if pGPI != nil:
var dwType: int32
@ -207,25 +207,25 @@ proc getProductInfo*(majorVersion, minorVersion, SPMajorVersion,
else:
return PRODUCT_UNDEFINED
proc GetSystemInfo*(lpSystemInfo: LPSYSTEM_INFO){.stdcall, dynlib: "kernel32",
proc getSystemInfo*(lpSystemInfo: LPSYSTEM_INFO){.stdcall, dynlib: "kernel32",
importc: "GetSystemInfo".}
proc getSystemInfo*(): TSYSTEM_INFO =
## Returns the SystemInfo
# Use GetNativeSystemInfo if it's available
var pGNSI = cast[proc (lpSystemInfo: LPSYSTEM_INFO)](GetProcAddress(
GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"))
var pGNSI = cast[proc (lpSystemInfo: LPSYSTEM_INFO)](getProcAddress(
getModuleHandleA("kernel32.dll"), "GetNativeSystemInfo"))
var systemi: TSYSTEM_INFO
if pGNSI != nil:
pGNSI(addr(systemi))
else:
GetSystemInfo(addr(systemi))
getSystemInfo(addr(systemi))
return systemi
proc GetSystemMetrics*(nIndex: int32): int32{.stdcall, dynlib: "user32",
proc getSystemMetrics*(nIndex: int32): int32{.stdcall, dynlib: "user32",
importc: "GetSystemMetrics".}
proc `$`*(osvi: TVersionInfo): string =
@ -283,11 +283,11 @@ proc `$`*(osvi: TVersionInfo): string =
of PRODUCT_WEB_SERVER:
result.add("Web Server Edition")
else:
nil
discard
# End of Windows 6.*
if osvi.majorVersion == 5 and osvi.minorVersion == 2:
if GetSystemMetrics(SM_SERVERR2) != 0:
if getSystemMetrics(SM_SERVERR2) != 0:
result.add("Windows Server 2003 R2, ")
elif (osvi.SuiteMask and VER_SUITE_PERSONAL) != 0: # Not sure if this will work
result.add("Windows Storage Server 2003")
@ -365,21 +365,21 @@ proc `$`*(osvi: TVersionInfo): string =
result = "Unknown version of windows[Kernel version <= 4]"
proc getFileSize*(file: string): biggestInt =
proc getFileSize*(file: string): BiggestInt =
var fileData: TWIN32_FIND_DATA
when useWinUnicode:
var aa = newWideCString(file)
var hFile = FindFirstFileW(aa, fileData)
var hFile = findFirstFileW(aa, fileData)
else:
var hFile = FindFirstFileA(file, fileData)
var hFile = findFirstFileA(file, fileData)
if hFile == INVALID_HANDLE_VALUE:
raise newException(EIO, $GetLastError())
raise newException(EIO, $getLastError())
return fileData.nFileSizeLow
proc GetDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,
proc getDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,
lpTotalNumberOfBytes,
lpTotalNumberOfFreeBytes: var TFiletime): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetDiskFreeSpaceExA".}
@ -387,7 +387,7 @@ proc GetDiskFreeSpaceEx*(lpDirectoryName: cstring, lpFreeBytesAvailableToCaller,
proc getPartitionInfo*(partition: string): TPartitionInfo =
## Retrieves partition info, for example ``partition`` may be ``"C:\"``
var FreeBytes, TotalBytes, TotalFreeBytes: TFiletime
var res = GetDiskFreeSpaceEx(r"C:\", FreeBytes, TotalBytes,
var res = getDiskFreeSpaceEx(r"C:\", FreeBytes, TotalBytes,
TotalFreeBytes)
return (FreeBytes, TotalBytes)

View file

@ -14,13 +14,13 @@
## wanted functionality.
when defined(Windows):
proc ReadLineFromStdin*(prompt: string): TaintedString {.
proc readLineFromStdin*(prompt: string): TaintedString {.
tags: [FReadIO, FWriteIO].} =
## Reads a line from stdin.
stdout.write(prompt)
result = readLine(stdin)
proc ReadLineFromStdin*(prompt: string, line: var TaintedString): bool {.
proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {.
tags: [FReadIO, FWriteIO].} =
## Reads a `line` from stdin. `line` must not be
## ``nil``! May throw an IO exception.
@ -34,7 +34,7 @@ when defined(Windows):
else:
import readline, history
proc ReadLineFromStdin*(prompt: string): TaintedString {.
proc readLineFromStdin*(prompt: string): TaintedString {.
tags: [FReadIO, FWriteIO].} =
var buffer = readline.readLine(prompt)
if isNil(buffer): quit(0)
@ -43,7 +43,7 @@ else:
add_history(buffer)
readline.free(buffer)
proc ReadLineFromStdin*(prompt: string, line: var TaintedString): bool {.
proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {.
tags: [FReadIO, FWriteIO].} =
var buffer = readline.readLine(prompt)
if isNil(buffer): quit(0)
@ -56,7 +56,7 @@ else:
# initialization:
# disable auto-complete:
proc doNothing(a, b: cint): cint {.cdecl, procvar.} = nil
proc doNothing(a, b: cint): cint {.cdecl, procvar.} = discard
discard readline.bind_key('\t'.ord, doNothing)

View file

@ -28,7 +28,7 @@ const
## More subpatterns cannot be captured!
type
TRegExFlag* = enum ## options for regular expressions
TRegexFlag* = enum ## options for regular expressions
reIgnoreCase = 0, ## do caseless matching
reMultiLine = 1, ## ``^`` and ``$`` match newlines within data
reDotAll = 2, ## ``.`` matches anything including NL
@ -36,11 +36,11 @@ type
reStudy = 4 ## study the expression (may be omitted if the
## expression will be used only once)
TRegExDesc {.pure, final.} = object
TRegexDesc {.pure, final.} = object
h: PPcre
e: ptr TExtra
TRegEx* = ref TRegExDesc ## a compiled regular expression
TRegex* = ref TRegexDesc ## a compiled regular expression
EInvalidRegEx* = object of EInvalidValue
## is raised if the pattern is no valid regular expression.
@ -53,13 +53,13 @@ proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
proc rawCompile(pattern: string, flags: cint): PPcre =
var
msg: CString
msg: cstring
offset: cint
result = pcre.Compile(pattern, flags, addr(msg), addr(offset), nil)
if result == nil:
raiseInvalidRegEx($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
raiseInvalidRegex($msg & "\n" & pattern & "\n" & repeatChar(offset) & "^\n")
proc finalizeRegEx(x: TRegEx) =
proc finalizeRegEx(x: TRegex) =
# XXX This is a hack, but PCRE does not export its "free" function properly.
# Sigh. The hack relies on PCRE's implementation (see ``pcre_get.c``).
# Fortunately the implementation is unlikely to change.
@ -67,7 +67,7 @@ proc finalizeRegEx(x: TRegEx) =
if not isNil(x.e):
pcre.free_substring(cast[cstring](x.e))
proc re*(s: string, flags = {reExtended, reStudy}): TRegEx =
proc re*(s: string, flags = {reExtended, reStudy}): TRegex =
## Constructor of regular expressions. Note that Nimrod's
## extended raw string literals support this syntax ``re"[abc]"`` as
## a short form for ``re(r"[abc]")``.
@ -78,7 +78,7 @@ proc re*(s: string, flags = {reExtended, reStudy}): TRegEx =
result.e = pcre.study(result.h, 0, msg)
if not isNil(msg): raiseInvalidRegex($msg)
proc matchOrFind(s: string, pattern: TRegEx, matches: var openarray[string],
proc matchOrFind(s: string, pattern: TRegex, matches: var openArray[string],
start, flags: cint): cint =
var
rawMatches: array[0..maxSubpatterns * 3 - 1, cint]
@ -92,7 +92,7 @@ proc matchOrFind(s: string, pattern: TRegEx, matches: var openarray[string],
else: matches[i-1] = ""
return rawMatches[1] - rawMatches[0]
proc findBounds*(s: string, pattern: TRegEx, matches: var openarray[string],
proc findBounds*(s: string, pattern: TRegex, matches: var openArray[string],
start = 0): tuple[first, last: int] =
## returns the starting position and end position of `pattern` in `s`
## and the captured
@ -110,8 +110,8 @@ proc findBounds*(s: string, pattern: TRegEx, matches: var openarray[string],
else: matches[i-1] = ""
return (rawMatches[0].int, rawMatches[1].int - 1)
proc findBounds*(s: string, pattern: TRegEx,
matches: var openarray[tuple[first, last: int]],
proc findBounds*(s: string, pattern: TRegex,
matches: var openArray[tuple[first, last: int]],
start = 0): tuple[first, last: int] =
## returns the starting position and end position of ``pattern`` in ``s``
## and the captured substrings in the array `matches`.
@ -129,7 +129,7 @@ proc findBounds*(s: string, pattern: TRegEx,
else: matches[i-1] = (-1,0)
return (rawMatches[0].int, rawMatches[1].int - 1)
proc findBounds*(s: string, pattern: TRegEx,
proc findBounds*(s: string, pattern: TRegex,
start = 0): tuple[first, last: int] =
## returns the starting position of `pattern` in `s`. If it does not
## match, ``(-1,0)`` is returned.
@ -140,14 +140,14 @@ proc findBounds*(s: string, pattern: TRegEx,
if res < 0'i32: return (int(res), 0)
return (int(rawMatches[0]), int(rawMatches[1]-1))
proc matchOrFind(s: string, pattern: TRegEx, start, flags: cint): cint =
proc matchOrFind(s: string, pattern: TRegex, start, flags: cint): cint =
var rawMatches: array [0..maxSubpatterns * 3 - 1, cint]
result = pcre.Exec(pattern.h, pattern.e, s, len(s).cint, start, flags,
cast[ptr cint](addr(rawMatches)), maxSubpatterns * 3)
if result >= 0'i32:
result = rawMatches[1] - rawMatches[0]
proc match*(s: string, pattern: TRegEx, matches: var openarray[string],
proc match*(s: string, pattern: TRegex, matches: var openArray[string],
start = 0): bool =
## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
## the captured substrings in the array ``matches``. If it does not
@ -156,24 +156,24 @@ proc match*(s: string, pattern: TRegEx, matches: var openarray[string],
return matchOrFind(s, pattern, matches, start.cint,
pcre.ANCHORED) == cint(s.len - start)
proc match*(s: string, pattern: TRegEx, start = 0): bool =
proc match*(s: string, pattern: TRegex, start = 0): bool =
## returns ``true`` if ``s[start..]`` matches the ``pattern``.
return matchOrFind(s, pattern, start.cint, pcre.ANCHORED) == cint(s.len-start)
proc matchLen*(s: string, pattern: TRegEx, matches: var openarray[string],
proc matchLen*(s: string, pattern: TRegex, matches: var openArray[string],
start = 0): int =
## the same as ``match``, but it returns the length of the match,
## if there is no match, -1 is returned. Note that a match length
## of zero can happen.
return matchOrFind(s, pattern, matches, start.cint, pcre.ANCHORED)
proc matchLen*(s: string, pattern: TRegEx, start = 0): int =
proc matchLen*(s: string, pattern: TRegex, start = 0): int =
## the same as ``match``, but it returns the length of the match,
## if there is no match, -1 is returned. Note that a match length
## of zero can happen.
return matchOrFind(s, pattern, start.cint, pcre.ANCHORED)
proc find*(s: string, pattern: TRegEx, matches: var openarray[string],
proc find*(s: string, pattern: TRegex, matches: var openArray[string],
start = 0): int =
## returns the starting position of ``pattern`` in ``s`` and the captured
## substrings in the array ``matches``. If it does not match, nothing
@ -190,7 +190,7 @@ proc find*(s: string, pattern: TRegEx, matches: var openarray[string],
else: matches[i-1] = ""
return rawMatches[0]
proc find*(s: string, pattern: TRegEx, start = 0): int =
proc find*(s: string, pattern: TRegex, start = 0): int =
## returns the starting position of ``pattern`` in ``s``. If it does not
## match, -1 is returned.
var
@ -200,7 +200,7 @@ proc find*(s: string, pattern: TRegEx, start = 0): int =
if res < 0'i32: return res
return rawMatches[0]
iterator findAll*(s: string, pattern: TRegEx, start = 0): string =
iterator findAll*(s: string, pattern: TRegex, start = 0): string =
## Yields all matching *substrings* of `s` that match `pattern`.
##
## Note that since this is an iterator you should not modify the string you
@ -216,7 +216,7 @@ iterator findAll*(s: string, pattern: TRegEx, start = 0): string =
yield substr(s, int(a), int(b)-1)
i = b
proc findAll*(s: string, pattern: TRegEx, start = 0): seq[string] =
proc findAll*(s: string, pattern: TRegex, start = 0): seq[string] =
## returns all matching *substrings* of `s` that match `pattern`.
## If it does not match, @[] is returned.
accumulateResult(findAll(s, pattern, start))
@ -224,7 +224,7 @@ proc findAll*(s: string, pattern: TRegEx, start = 0): seq[string] =
when not defined(nimhygiene):
{.pragma: inject.}
template `=~` *(s: string, pattern: TRegEx): expr =
template `=~` *(s: string, pattern: TRegex): expr =
## This calls ``match`` with an implicit declared ``matches`` array that
## can be used in the scope of the ``=~`` call:
##
@ -244,30 +244,30 @@ template `=~` *(s: string, pattern: TRegEx): expr =
##
bind maxSubPatterns
when not definedInScope(matches):
var matches {.inject.}: array[0..maxSubPatterns-1, string]
var matches {.inject.}: array[0..MaxSubpatterns-1, string]
match(s, pattern, matches)
# ------------------------- more string handling ------------------------------
proc contains*(s: string, pattern: TRegEx, start = 0): bool =
proc contains*(s: string, pattern: TRegex, start = 0): bool =
## same as ``find(s, pattern, start) >= 0``
return find(s, pattern, start) >= 0
proc contains*(s: string, pattern: TRegEx, matches: var openArray[string],
proc contains*(s: string, pattern: TRegex, matches: var openArray[string],
start = 0): bool =
## same as ``find(s, pattern, matches, start) >= 0``
return find(s, pattern, matches, start) >= 0
proc startsWith*(s: string, prefix: TRegEx): bool =
proc startsWith*(s: string, prefix: TRegex): bool =
## returns true if `s` starts with the pattern `prefix`
result = matchLen(s, prefix) >= 0
proc endsWith*(s: string, suffix: TRegEx): bool =
proc endsWith*(s: string, suffix: TRegex): bool =
## returns true if `s` ends with the pattern `prefix`
for i in 0 .. s.len-1:
if matchLen(s, suffix, i) == s.len - i: return true
proc replace*(s: string, sub: TRegEx, by = ""): string =
proc replace*(s: string, sub: TRegex, by = ""): string =
## Replaces `sub` in `s` by the string `by`. Captures cannot be
## accessed in `by`. Examples:
##
@ -289,7 +289,7 @@ proc replace*(s: string, sub: TRegEx, by = ""): string =
prev = match.last + 1
add(result, substr(s, prev))
proc replacef*(s: string, sub: TRegEx, by: string): string =
proc replacef*(s: string, sub: TRegex, by: string): string =
## Replaces `sub` in `s` by the string `by`. Captures can be accessed in `by`
## with the notation ``$i`` and ``$#`` (see strutils.`%`). Examples:
##
@ -327,7 +327,7 @@ proc replacef*(s: string, sub: TRegEx, by: string): string =
add(result, substr(s, i))
proc parallelReplace*(s: string, subs: openArray[
tuple[pattern: TRegEx, repl: string]]): string =
tuple[pattern: TRegex, repl: string]]): string =
## Returns a modified copy of `s` with the substitutions in `subs`
## applied in parallel.
result = ""
@ -347,14 +347,14 @@ proc parallelReplace*(s: string, subs: openArray[
add(result, substr(s, i))
proc transformFile*(infile, outfile: string,
subs: openArray[tuple[pattern: TRegEx, repl: string]]) =
subs: openArray[tuple[pattern: TRegex, repl: string]]) =
## reads in the file `infile`, performs a parallel replacement (calls
## `parallelReplace`) and writes back to `outfile`. Raises ``EIO`` if an
## error occurs. This is supposed to be used for quick scripting.
var x = readFile(infile).string
writeFile(outfile, x.parallelReplace(subs))
iterator split*(s: string, sep: TRegEx): string =
iterator split*(s: string, sep: TRegex): string =
## Splits the string `s` into substrings.
##
## Substrings are separated by the regular expression `sep`.
@ -386,7 +386,7 @@ iterator split*(s: string, sep: TRegEx): string =
if first < last:
yield substr(s, first, last-1)
proc split*(s: string, sep: TRegEx): seq[string] =
proc split*(s: string, sep: TRegex): seq[string] =
## Splits the string `s` into substrings.
accumulateResult(split(s, sep))

View file

@ -71,7 +71,7 @@ proc addFile*(z: var TZipArchive, file: string) =
addFile(z, file, file)
proc mySourceCallback(state, data: pointer, len: int,
cmd: Tzip_source_cmd): int {.cdecl.} =
cmd: TZipSourceCmd): int {.cdecl.} =
var src = cast[PStream](state)
case cmd
of ZIP_SOURCE_OPEN:
@ -108,7 +108,7 @@ proc addFile*(z: var TZipArchive, dest: string, src: PStream) =
type
TZipFileStream = object of TStream
f: Pzip_file
f: PZipFile
PZipFileStream* =
ref TZipFileStream ## a reader stream of a file within a zip archive

View file

@ -19,7 +19,7 @@ type
gtEof, gtNone, gtWhitespace, gtDecNumber, gtBinNumber, gtHexNumber,
gtOctNumber, gtFloatNumber, gtIdentifier, gtKeyword, gtStringLit,
gtLongStringLit, gtCharLit, gtEscapeSequence, # escape sequence like \xff
gtOperator, gtPunctation, gtComment, gtLongComment, gtRegularExpression,
gtOperator, gtPunctuation, gtComment, gtLongComment, gtRegularExpression,
gtTagStart, gtTagEnd, gtKey, gtValue, gtRawData, gtAssembler,
gtPreprocessor, gtDirective, gtCommand, gtRule, gtHyperlink, gtLabel,
gtReference, gtOther
@ -39,7 +39,7 @@ const
tokenClassToStr*: array[TTokenClass, string] = ["Eof", "None", "Whitespace",
"DecNumber", "BinNumber", "HexNumber", "OctNumber", "FloatNumber",
"Identifier", "Keyword", "StringLit", "LongStringLit", "CharLit",
"EscapeSequence", "Operator", "Punctation", "Comment", "LongComment",
"EscapeSequence", "Operator", "Punctuation", "Comment", "LongComment",
"RegularExpression", "TagStart", "TagEnd", "Key", "Value", "RawData",
"Assembler", "Preprocessor", "Directive", "Command", "Rule", "Hyperlink",
"Label", "Reference", "Other"]
@ -53,7 +53,7 @@ const
"interface", "is", "isnot", "iterator", "lambda", "let", "macro", "method",
"mixin", "mod", "nil", "not", "notin", "object", "of", "or", "out", "proc",
"ptr", "raise", "ref", "return", "shared", "shl", "shr", "static",
"template", "try", "tuple", "type", "var", "when", "while", "with",
"template", "try", "tuple", "type", "using", "var", "when", "while", "with",
"without", "xor", "yield"]
proc getSourceLanguage*(name: string): TSourceLanguage =
@ -73,7 +73,7 @@ proc initGeneralTokenizer*(g: var TGeneralTokenizer, buf: string) =
g.pos = pos
proc deinitGeneralTokenizer*(g: var TGeneralTokenizer) =
nil
discard
proc nimGetKeyword(id: string): TTokenClass =
for k in nimrodKeywords:
@ -102,7 +102,7 @@ proc nimNumberPostfix(g: var TGeneralTokenizer, position: int): int =
if g.buf[pos] in {'0'..'9'}: inc(pos)
if g.buf[pos] in {'0'..'9'}: inc(pos)
else:
nil
discard
result = pos
proc nimNumber(g: var TGeneralTokenizer, position: int): int =
@ -258,7 +258,7 @@ proc nimNextToken(g: var TGeneralTokenizer) =
else: inc(pos)
of '(', ')', '[', ']', '{', '}', '`', ':', ',', ';':
inc(pos)
g.kind = gtPunctation
g.kind = gtPunctuation
of '\0':
g.kind = gtEof
else:
@ -321,7 +321,7 @@ proc generalStrLit(g: var TGeneralTokenizer, position: int): int =
inc(pos)
result = pos
proc isKeyword(x: openarray[string], y: string): int =
proc isKeyword(x: openArray[string], y: string): int =
var a = 0
var b = len(x) - 1
while a <= b:
@ -335,7 +335,7 @@ proc isKeyword(x: openarray[string], y: string): int =
return mid
result = - 1
proc isKeywordIgnoreCase(x: openarray[string], y: string): int =
proc isKeywordIgnoreCase(x: openArray[string], y: string): int =
var a = 0
var b = len(x) - 1
while a <= b:
@ -354,7 +354,7 @@ type
hasPreprocessor, hasNestedComments
TTokenizerFlags = set[TTokenizerFlag]
proc clikeNextToken(g: var TGeneralTokenizer, keywords: openarray[string],
proc clikeNextToken(g: var TGeneralTokenizer, keywords: openArray[string],
flags: TTokenizerFlags) =
const
hexChars = {'0'..'9', 'A'..'F', 'a'..'f'}
@ -428,7 +428,7 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openarray[string],
g.kind = gtOperator
of 'a'..'z', 'A'..'Z', '_', '\x80'..'\xFF':
var id = ""
while g.buf[pos] in SymChars:
while g.buf[pos] in symChars:
add(id, g.buf[pos])
inc(pos)
if isKeyword(keywords, id) >= 0: g.kind = gtKeyword
@ -473,7 +473,7 @@ proc clikeNextToken(g: var TGeneralTokenizer, keywords: openarray[string],
else: inc(pos)
of '(', ')', '[', ']', '{', '}', ':', ',', ';', '.':
inc(pos)
g.kind = gtPunctation
g.kind = gtPunctuation
of '\0':
g.kind = gtEof
else:

View file

@ -130,7 +130,7 @@ proc getThing(L: var TLexer, tok: var TToken, s: TCharSet) =
tok.line = L.line
tok.col = L.col
var pos = L.bufpos
while True:
while true:
add(tok.symbol, L.buf[pos])
inc(pos)
if L.buf[pos] notin s: break
@ -143,7 +143,7 @@ proc getAdornment(L: var TLexer, tok: var TToken) =
tok.col = L.col
var pos = L.bufpos
var c = L.buf[pos]
while True:
while true:
add(tok.symbol, L.buf[pos])
inc(pos)
if L.buf[pos] != c: break
@ -162,7 +162,7 @@ proc getIndentAux(L: var TLexer, start: int): int =
if L.skipPounds:
if buf[pos] == '#': inc(pos)
if buf[pos] == '#': inc(pos)
while True:
while true:
case buf[pos]
of ' ', '\x0B', '\x0C':
inc(pos)
@ -242,7 +242,7 @@ proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
inc(result)
while true:
inc(length)
setlen(tokens, length)
setLen(tokens, length)
rawGetTok(L, tokens[length - 1])
if tokens[length - 1].kind == tkEof: break
if tokens[0].kind == tkWhite:
@ -251,7 +251,7 @@ proc getTokens(buffer: string, skipPounds: bool, tokens: var TTokenSeq): int =
tokens[0].kind = tkIndent
type
TLevelMap = array[Char, int]
TLevelMap = array[char, int]
TSubstitution{.final.} = object
key*: string
value*: PRstNode
@ -294,11 +294,11 @@ proc whichMsgClass*(k: TMsgKind): TMsgClass =
proc defaultMsgHandler*(filename: string, line, col: int, msgkind: TMsgKind,
arg: string) {.procvar.} =
let mc = msgKind.whichMsgClass
let a = messages[msgKind] % arg
let mc = msgkind.whichMsgClass
let a = messages[msgkind] % arg
let message = "$1($2, $3) $4: $5" % [filename, $line, $col, $mc, a]
if mc == mcError: raise newException(EParseError, message)
else: Writeln(stdout, message)
else: writeln(stdout, message)
proc defaultFindFile*(filename: string): string {.procvar.} =
if existsFile(filename): result = filename
@ -339,7 +339,7 @@ proc pushInd(p: var TRstParser, ind: int) =
add(p.indentStack, ind)
proc popInd(p: var TRstParser) =
if len(p.indentStack) > 1: setlen(p.indentStack, len(p.indentStack) - 1)
if len(p.indentStack) > 1: setLen(p.indentStack, len(p.indentStack) - 1)
proc initParser(p: var TRstParser, sharedState: PSharedState) =
p.indentStack = @[0]
@ -408,7 +408,7 @@ proc setSub(p: var TRstParser, key: string, value: PRstNode) =
if key == p.s.subs[i].key:
p.s.subs[i].value = value
return
setlen(p.s.subs, length + 1)
setLen(p.s.subs, length + 1)
p.s.subs[length].key = key
p.s.subs[length].value = value
@ -421,7 +421,7 @@ proc setRef(p: var TRstParser, key: string, value: PRstNode) =
p.s.refs[i].value = value
return
setlen(p.s.refs, length + 1)
setLen(p.s.refs, length + 1)
p.s.refs[length].key = key
p.s.refs[length].value = value
@ -479,7 +479,7 @@ proc isInlineMarkupEnd(p: TRstParser, markup: string): bool =
result = false
proc isInlineMarkupStart(p: TRstParser, markup: string): bool =
var d: Char
var d: char
result = p.tok[p.idx].symbol == markup
if not result:
return # Rule 1:
@ -535,7 +535,7 @@ proc match(p: TRstParser, start: int, expr: string): bool =
case p.tok[j].symbol[0]
of 'a'..'z', 'A'..'Z': result = len(p.tok[j].symbol) == 1
of '0'..'9': result = allCharsInSet(p.tok[j].symbol, {'0'..'9'})
else: nil
else: discard
else:
var c = expr[i]
var length = 0
@ -615,7 +615,7 @@ proc matchVerbatim(p: TRstParser, start: int, expr: string): int =
proc parseSmiley(p: var TRstParser): PRstNode =
if p.tok[p.idx].symbol[0] notin SmileyStartChars: return
for key, val in items(smilies):
for key, val in items(Smilies):
let m = matchVerbatim(p, p.idx, key)
if m > 0:
p.idx = m
@ -629,18 +629,18 @@ when false:
'$', '(', ')', '~', '_', '?', '+', '-', '=', '\\', '.', '&',
'\128'..'\255'}
proc isURL(p: TRstParser, i: int): bool =
proc isUrl(p: TRstParser, i: int): bool =
result = (p.tok[i+1].symbol == ":") and (p.tok[i+2].symbol == "//") and
(p.tok[i+3].kind == tkWord) and
(p.tok[i].symbol in ["http", "https", "ftp", "telnet", "file"])
proc parseURL(p: var TRstParser, father: PRstNode) =
proc parseUrl(p: var TRstParser, father: PRstNode) =
#if p.tok[p.idx].symbol[strStart] == '<':
if isURL(p, p.idx):
if isUrl(p, p.idx):
var n = newRstNode(rnStandaloneHyperlink)
while true:
case p.tok[p.idx].kind
of tkWord, tkAdornment, tkOther: nil
of tkWord, tkAdornment, tkOther: discard
of tkPunct:
if p.tok[p.idx+1].kind notin {tkWord, tkAdornment, tkOther, tkPunct}:
break
@ -806,7 +806,7 @@ proc parseInline(p: var TRstParser, father: PRstNode) =
return
add(father, newLeaf(p))
inc(p.idx)
else: nil
else: discard
proc getDirective(p: var TRstParser): string =
if p.tok[p.idx].kind == tkWhite and p.tok[p.idx+1].kind == tkWord:
@ -835,14 +835,14 @@ proc parseComment(p: var TRstParser): PRstNode =
inc(p.idx) # empty comment
else:
var indent = p.tok[p.idx].ival
while True:
while true:
case p.tok[p.idx].kind
of tkEof:
break
of tkIndent:
if (p.tok[p.idx].ival < indent): break
else:
nil
discard
inc(p.idx)
else:
while p.tok[p.idx].kind notin {tkIndent, tkEof}: inc(p.idx)
@ -864,18 +864,24 @@ proc getDirKind(s: string): TDirKind =
else: result = dkNone
proc parseLine(p: var TRstParser, father: PRstNode) =
while True:
while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkOther, tkPunct: parseInline(p, father)
else: break
proc parseUntilNewline(p: var TRstParser, father: PRstNode) =
while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
of tkEof, tkIndent: break
proc parseSection(p: var TRstParser, result: PRstNode)
proc parseField(p: var TRstParser): PRstNode =
result = newRstNode(rnField)
var col = p.tok[p.idx].col
var fieldname = newRstNode(rnFieldname)
var fieldname = newRstNode(rnFieldName)
parseUntil(p, fieldname, ":", false)
var fieldbody = newRstNode(rnFieldbody)
var fieldbody = newRstNode(rnFieldBody)
if p.tok[p.idx].kind != tkIndent: parseLine(p, fieldbody)
if p.tok[p.idx].kind == tkIndent:
var indent = p.tok[p.idx].ival
@ -927,7 +933,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
if p.tok[p.idx].kind == tkIndent:
var indent = p.tok[p.idx].ival
inc(p.idx)
while True:
while true:
case p.tok[p.idx].kind
of tkEof:
break
@ -947,7 +953,7 @@ proc parseLiteralBlock(p: var TRstParser): PRstNode =
inc(p.idx)
add(result, n)
proc getLevel(map: var TLevelMap, lvl: var int, c: Char): int =
proc getLevel(map: var TLevelMap, lvl: var int, c: char): int =
if map[c] == 0:
inc(lvl)
map[c] = lvl
@ -993,7 +999,7 @@ proc whichSection(p: TRstParser): TRstNodeKind =
elif match(p, p.idx + 1, "i"): result = rnOverline
else: result = rnLeaf
of tkPunct:
if match(p, tokenAfterNewLine(p), "ai"):
if match(p, tokenAfterNewline(p), "ai"):
result = rnHeadline
elif p.tok[p.idx].symbol == "::":
result = rnLiteralBlock
@ -1020,7 +1026,7 @@ proc whichSection(p: TRstParser): TRstNodeKind =
else:
result = rnParagraph
of tkWord, tkOther, tkWhite:
if match(p, tokenAfterNewLine(p), "ai"): result = rnHeadline
if match(p, tokenAfterNewline(p), "ai"): result = rnHeadline
elif match(p, p.idx, "e) ") or match(p, p.idx, "e. "): result = rnEnumList
elif isDefList(p): result = rnDefList
else: result = rnParagraph
@ -1046,7 +1052,7 @@ proc parseLineBlock(p: var TRstParser): PRstNode =
popInd(p)
proc parseParagraph(p: var TRstParser, result: PRstNode) =
while True:
while true:
case p.tok[p.idx].kind
of tkIndent:
if p.tok[p.idx + 1].kind == tkIndent:
@ -1078,7 +1084,7 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
proc parseHeadline(p: var TRstParser): PRstNode =
result = newRstNode(rnHeadline)
parseLine(p, result)
parseUntilNewline(p, result)
assert(p.tok[p.idx].kind == tkIndent)
assert(p.tok[p.idx + 1].kind == tkAdornment)
var c = p.tok[p.idx + 1].symbol[0]
@ -1095,7 +1101,7 @@ proc getColumns(p: var TRstParser, cols: var TIntSeq) =
var L = 0
while true:
inc(L)
setlen(cols, L)
setLen(cols, L)
cols[L - 1] = tokEnd(p)
assert(p.tok[p.idx].kind == tkAdornment)
inc(p.idx)
@ -1113,7 +1119,7 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
cols: TIntSeq
row: seq[string]
i, last, line: int
c: Char
c: char
q: TRstParser
a, b: PRstNode
result = newRstNode(rnTable)
@ -1129,7 +1135,7 @@ proc parseSimpleTable(p: var TRstParser): PRstNode =
p.idx = last
break
getColumns(p, cols)
setlen(row, len(cols))
setLen(row, len(cols))
if a != nil:
for j in 0..len(a)-1: a.sons[j].kind = rnTableHeaderCell
if p.tok[p.idx].kind == tkEof: break
@ -1172,7 +1178,7 @@ proc parseOverline(p: var TRstParser): PRstNode =
inc(p.idx, 2)
result = newRstNode(rnOverline)
while true:
parseLine(p, result)
parseUntilNewline(p, result)
if p.tok[p.idx].kind == tkIndent:
inc(p.idx)
if p.tok[p.idx - 1].ival > currInd(p):
@ -1237,7 +1243,7 @@ proc parseOptionList(p: var TRstParser): PRstNode =
proc parseDefinitionList(p: var TRstParser): PRstNode =
result = nil
var j = tokenAfterNewLine(p) - 1
var j = tokenAfterNewline(p) - 1
if (j >= 1) and (p.tok[j].kind == tkIndent) and
(p.tok[j].ival > currInd(p)) and (p.tok[j - 1].symbol != "::"):
var col = p.tok[p.idx].col
@ -1263,10 +1269,10 @@ proc parseDefinitionList(p: var TRstParser): PRstNode =
break
if (p.tok[p.idx].kind == tkIndent) and (p.tok[p.idx].ival == col):
inc(p.idx)
j = tokenAfterNewLine(p) - 1
j = tokenAfterNewline(p) - 1
if j >= 1 and p.tok[j].kind == tkIndent and p.tok[j].ival > col and
p.tok[j-1].symbol != "::" and p.tok[j+1].kind != tkIndent:
nil
discard
else:
break
if len(result) == 0: result = nil
@ -1284,7 +1290,7 @@ proc parseEnumList(p: var TRstParser): PRstNode =
var col = p.tok[p.idx].col
result = newRstNode(rnEnumList)
inc(p.idx, wildpos[w] + 3)
var j = tokenAfterNewLine(p)
var j = tokenAfterNewline(p)
if (p.tok[j].col == p.tok[p.idx].col) or match(p, j, wildcards[w]):
pushInd(p, p.tok[p.idx].col)
while true:
@ -1329,11 +1335,11 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
inc(p.idx) # skip '::'
a = parseLiteralBlock(p)
of rnBulletList: a = parseBulletList(p)
of rnLineblock: a = parseLineBlock(p)
of rnLineBlock: a = parseLineBlock(p)
of rnDirective: a = parseDotDot(p)
of rnEnumList: a = parseEnumList(p)
of rnLeaf: rstMessage(p, meNewSectionExpected)
of rnParagraph: nil
of rnParagraph: discard
of rnDefList: a = parseDefinitionList(p)
of rnFieldList:
if p.idx > 0: dec(p.idx)
@ -1345,7 +1351,7 @@ proc parseSection(p: var TRstParser, result: PRstNode) =
of rnOptionList: a = parseOptionList(p)
else:
#InternalError("rst.parseSection()")
nil
discard
if a == nil and k != rnDirective:
a = newRstNode(rnParagraph)
parseParagraph(p, a)
@ -1388,7 +1394,7 @@ proc parseDirective(p: var TRstParser, flags: TDirFlags): PRstNode =
if hasArg in flags:
args = newRstNode(rnDirArg)
if argIsFile in flags:
while True:
while true:
case p.tok[p.idx].kind
of tkWord, tkOther, tkPunct, tkAdornment:
add(args, newLeaf(p))
@ -1560,7 +1566,7 @@ proc parseDotDot(p: var TRstParser): PRstNode =
result = dirRaw(p)
else:
rstMessage(p, meInvalidDirective, d)
of dkCodeblock: result = dirCodeBlock(p)
of dkCodeBlock: result = dirCodeBlock(p)
of dkIndex: result = dirIndex(p)
else: rstMessage(p, meInvalidDirective, d)
popInd(p)
@ -1618,7 +1624,7 @@ proc resolveSubs(p: var TRstParser, n: PRstNode): PRstNode =
add(result, n)
add(result, y)
of rnLeaf:
nil
discard
of rnContents:
p.hasToc = true
else:

View file

@ -62,9 +62,9 @@ type
# leaf val
PRSTNode* = ref TRstNode ## an RST node
PRstNode* = ref TRstNode ## an RST node
TRstNodeSeq* = seq[PRstNode]
TRSTNode* {.acyclic, final.} = object ## an RST node's description
TRstNode* {.acyclic, final.} = object ## an RST node's description
kind*: TRstNodeKind ## the node's kind
text*: string ## valid for leafs in the AST; and the title of
## the document or the section
@ -120,11 +120,11 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
let oldLen = result.len
renderRstSons(d, n, result)
let HeadlineLen = result.len - oldLen
let headlineLen = result.len - oldLen
result.add("\n")
result.add(ind)
result.add repeatChar(HeadlineLen, lvlToChar[n.level])
result.add repeatChar(headlineLen, lvlToChar[n.level])
of rnOverline:
result.add("\n")
result.add(ind)
@ -132,7 +132,7 @@ proc renderRstToRst(d: var TRenderContext, n: PRstNode, result: var string) =
var headline = ""
renderRstSons(d, n, headline)
let lvl = repeatChar(headline.Len - d.indent, lvlToChar[n.level])
let lvl = repeatChar(headline.len - d.indent, lvlToChar[n.level])
result.add(lvl)
result.add("\n")
result.add(headline)

View file

@ -7,7 +7,18 @@
# distribution, for details about the copyright.
#
## This module implements a generator of HTML/Latex from `reStructuredText`:idx:.
## This module implements a generator of HTML/Latex from
## `reStructuredText`:idx: (see http://docutils.sourceforge.net/rst.html for
## information on this markup syntax). You can generate HTML output through the
## convenience proc ``rstToHtml``, which provided an input string with rst
## markup returns a string with the generated HTML. The final output is meant
## to be embedded inside a full document you provide yourself, so it won't
## contain the usual ``<header>`` or ``<body>`` parts.
##
## You can also create a ``TRstGenerator`` structure and populate it with the
## other lower level methods to finally build complete documents. This requires
## many options and tweaking, but you are not limited to snippets and can
## generate `LaTeX documents <https://en.wikipedia.org/wiki/LaTeX>`_ too.
import strutils, os, hashes, strtabs, rstast, rst, highlite
@ -33,20 +44,58 @@ type
splitAfter*: int # split too long entries in the TOC
tocPart*: seq[TTocEntry]
hasToc*: bool
theIndex: string
theIndex: string # Contents of the index file to be dumped at the end.
options*: TRstParseOptions
findFile*: TFindFileHandler
msgHandler*: TMsgHandler
filename*: string
meta*: array[TMetaEnum, string]
PDoc = var TRstGenerator
PDoc = var TRstGenerator ## Alias to type less.
proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
config: PStringTable, filename: string,
options: TRstParseOptions,
findFile: TFindFileHandler,
msgHandler: TMsgHandler) =
## Initializes a ``TRstGenerator``.
##
## You need to call this before using a ``TRstGenerator`` with any other
## procs in this module. Pass a non ``nil`` ``PStringTable`` value as
## ``config`` with parameters used by the HTML output generator. If you
## don't know what to use, pass the results of the ``defaultConfig()`` proc.
## The ``filename`` is symbolic and used only for error reporting, you can
## pass any non ``nil`` string here.
##
## The ``TRstParseOptions``, ``TFindFileHandler`` and ``TMsgHandler`` types
## are defined in the the `packages/docutils/rst module <rst.html>`_.
## ``options`` selects the behaviour of the rst parser.
##
## ``findFile`` is a proc used by the rst ``include`` directive among others.
## The purpose of this proc is to mangle or filter paths. It receives paths
## specified in the rst document and has to return a valid path to existing
## files or the empty string otherwise. If you pass ``nil``, a default proc
## will be used which given a path returns the input path only if the file
## exists. One use for this proc is to transform relative paths found in the
## document to absolute path, useful if the rst file and the resources it
## references are not in the same directory as the current working directory.
##
## The ``msgHandler`` is a proc used for user error reporting. It will be
## called with the filename, line, col, and type of any error found during
## parsing. If you pass ``nil``, a default message handler will be used which
## writes the messages to the standard output.
##
## Example:
##
## .. code-block:: nimrod
##
## import packages/docutils/rstgen
##
## var gen: TRstGenerator
##
## gen.initRstGenerator(outHtml, defaultConfig(),
## "filename", {}, nil, nil)
g.config = config
g.target = target
g.tocPart = @[]
@ -62,9 +111,13 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
## Writes the current index buffer to the specified output file.
##
## You previously need to add entries to the index with the ``setIndexTerm``
## proc. If the index is empty the file won't be created.
if g.theIndex.len > 0: writeFile(outfile, g.theIndex)
proc addXmlChar(dest: var string, c: Char) =
proc addXmlChar(dest: var string, c: char) =
case c
of '&': add(dest, "&amp;")
of '<': add(dest, "&lt;")
@ -72,14 +125,14 @@ proc addXmlChar(dest: var string, c: Char) =
of '\"': add(dest, "&quot;")
else: add(dest, c)
proc addRtfChar(dest: var string, c: Char) =
proc addRtfChar(dest: var string, c: char) =
case c
of '{': add(dest, "\\{")
of '}': add(dest, "\\}")
of '\\': add(dest, "\\\\")
else: add(dest, c)
proc addTexChar(dest: var string, c: Char) =
proc addTexChar(dest: var string, c: char) =
case c
of '_': add(dest, "\\_")
of '{': add(dest, "\\symbol{123}")
@ -99,7 +152,7 @@ proc addTexChar(dest: var string, c: Char) =
var splitter*: string = "<wbr />"
proc escChar*(target: TOutputTarget, dest: var string, c: Char) {.inline.} =
proc escChar*(target: TOutputTarget, dest: var string, c: char) {.inline.} =
case target
of outHtml: addXmlChar(dest, c)
of outLatex: addTexChar(dest, c)
@ -112,7 +165,7 @@ proc nextSplitPoint*(s: string, start: int): int =
of 'a'..'z':
if result + 1 < len(s) + 0:
if s[result + 1] in {'A'..'Z'}: return
else: nil
else: discard
inc(result)
dec(result) # last valid index
@ -147,7 +200,19 @@ proc dispA(target: TOutputTarget, dest: var string,
if target != outLatex: addf(dest, xml, args)
else: addf(dest, tex, args)
proc renderRstToOut*(d: PDoc, n: PRstNode, result: var string)
proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
## Writes into ``result`` the rst ast ``n`` using the ``d`` configuration.
##
## Before using this proc you need to initialise a ``TRstGenerator`` with
## ``initRstGenerator`` and parse a rst file with ``rstParse`` from the
## `packages/docutils/rst module <rst.html>`_. Example:
##
## .. code-block:: nimrod
##
## # ...configure gen and rst vars...
## var generatedHTML = ""
## renderRstToOut(gen, rst, generatedHTML)
## echo generatedHTML
proc renderAux(d: PDoc, n: PRstNode, result: var string) =
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
@ -162,7 +227,14 @@ proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
# ---------------- index handling --------------------------------------------
proc setIndexTerm*(d: PDoc, id, term: string) =
proc setIndexTerm*(d: var TRstGenerator, id, term: string) =
## Adds a `term` to the index using the specified hyperlink identifier.
##
## The ``d.theIndex`` string will be used to append the term in the format
## ``term<tab>file#id``. The anchor will be the based on the name of the file
## currently being parsed plus the `id`, which will be appended after a hash.
##
## The index won't be written to disk unless you call ``writeIndexFile``.
d.theIndex.add(term)
d.theIndex.add('\t')
let htmlFile = changeFileExt(extractFilename(d.filename), HtmlExt)
@ -202,14 +274,14 @@ proc `<-`(a: var TIndexEntry, b: TIndexEntry) =
proc sortIndex(a: var openArray[TIndexEntry]) =
# we use shellsort here; fast and simple
let N = len(a)
let n = len(a)
var h = 1
while true:
h = 3 * h + 1
if h > N: break
if h > n: break
while true:
h = h div 3
for i in countup(h, N - 1):
for i in countup(h, n - 1):
var v: TIndexEntry
v <- a[i]
var j = i
@ -259,7 +331,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
var refname = rstnodeToRefname(n)
if d.hasToc:
var length = len(d.tocPart)
setlen(d.tocPart, length + 1)
setLen(d.tocPart, length + 1)
d.tocPart[length].refname = refname
d.tocPart[length].n = n
d.tocPart[length].header = tmp
@ -295,7 +367,7 @@ proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
"\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
proc renderTocEntries*(d: PDoc, j: var int, lvl: int, result: var string) =
proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int, result: var string) =
var tmp = ""
while j <= high(d.tocPart):
var a = abs(d.tocPart[j].n.level)
@ -395,7 +467,7 @@ proc renderField(d: PDoc, n: PRstNode, result: var string) =
if d.meta[metaAuthor].len == 0:
d.meta[metaAuthor] = fieldval
b = true
elif cmpIgnoreStyle(fieldName, "version") == 0:
elif cmpIgnoreStyle(fieldname, "version") == 0:
if d.meta[metaVersion].len == 0:
d.meta[metaVersion] = fieldval
b = true
@ -559,14 +631,14 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
# -----------------------------------------------------------------------------
proc getVarIdx(varnames: openarray[string], id: string): int =
proc getVarIdx(varnames: openArray[string], id: string): int =
for i in countup(0, high(varnames)):
if cmpIgnoreStyle(varnames[i], id) == 0:
return i
result = -1
proc formatNamedVars*(frmt: string, varnames: openarray[string],
varvalues: openarray[string]): string =
proc formatNamedVars*(frmt: string, varnames: openArray[string],
varvalues: openArray[string]): string =
var i = 0
var L = len(frmt)
result = ""
@ -585,7 +657,7 @@ proc formatNamedVars*(frmt: string, varnames: openarray[string],
of '0'..'9':
var j = 0
while true:
j = (j * 10) + Ord(frmt[i]) - ord('0')
j = (j * 10) + ord(frmt[i]) - ord('0')
inc(i)
if i > L-1 or frmt[i] notin {'0'..'9'}: break
if j > high(varvalues) + 1:
@ -627,7 +699,18 @@ proc formatNamedVars*(frmt: string, varnames: openarray[string],
proc defaultConfig*(): PStringTable =
## creates a default configuration for HTML generation.
## Returns a default configuration for embedded HTML generation.
##
## The returned ``PStringTable`` contains the paramters used by the HTML
## engine to build the final output. For information on what these parameters
## are and their purpose, please look up the file ``config/nimdoc.cfg``
## bundled with the compiler.
##
## The only difference between the contents of that file and the values
## provided by this proc is the ``doc.file`` variable. The ``doc.file``
## variable of the configuration file contains HTML to build standalone
## pages, while this proc returns just the content for procs like
## ``rstToHtml`` to generate the bare minimum HTML.
result = newStringTable(modeStyleInsensitive)
template setConfigVar(key, val: expr) =
@ -678,8 +761,26 @@ $content
proc rstToHtml*(s: string, options: TRstParseOptions,
config: PStringTable): string =
## exported for *nimforum*.
## Converts an input rst string into embeddable HTML.
##
## This convenience proc parses any input string using rst markup (it doesn't
## have to be a full document!) and returns an embeddable piece of HTML. The
## proc is meant to be used in *online* environments without access to a
## meaningful filesystem, and therefore rst ``include`` like directives won't
## work. For an explanation of the ``config`` parameter see the
## ``initRstGenerator`` proc. Example:
##
## .. code-block:: nimrod
## import packages/docutils/rstgen, strtabs
##
## echo rstToHtml("*Hello* **world**!", {},
## newStringTable(modeStyleInsensitive))
## # --> <em>Hello</em> <strong>world</strong>!
##
## If you need to allow the rst ``include`` directive or tweak the generated
## output you have to create your own ``TRstGenerator`` with
## ``initRstGenerator`` and related procs.
proc myFindFile(filename: string): string =
# we don't find any files in online mode:
result = ""
@ -692,4 +793,8 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
result = ""
renderRstToOut(d, rst, result)
when isMainModule:
echo rstToHtml("*Hello* **world**!", {},
newStringTable(modeStyleInsensitive))

File diff suppressed because it is too large Load diff

View file

@ -34,7 +34,7 @@ proc reverse*[T](a: var openArray[T]) =
## reverses the array `a`.
reverse(a, 0, a.high)
proc binarySearch*[T](a: openarray[T], key: T): int =
proc binarySearch*[T](a: openArray[T], key: T): int =
## binary search for `key` in `a`. Returns -1 if not found.
var b = len(a)
while result < b:
@ -79,7 +79,7 @@ proc merge[T](a, b: var openArray[T], lo, m, hi: int,
inc(bb)
inc(j)
else:
CopyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1))
copyMem(addr(b[0]), addr(a[j]), sizeof(T)*(m-j+1))
j = m+1
var i = 0
var k = lo
@ -131,3 +131,36 @@ proc sort*[T](a: var openArray[T],
dec(m, s*2)
s = s*2
proc product*[T](x: openarray[seq[T]]): seq[seq[T]] =
## produces the Cartesian product of the array. Warning: complexity
## may explode.
result = @[]
if x.len == 0:
return
if x.len == 1:
result = @x
return
var
indexes = newSeq[int](x.len)
initial = newSeq[int](x.len)
index = 0
# replace with newSeq as soon as #853 is fixed
var next: seq[T] = @[]
next.setLen(x.len)
for i in 0..(x.len-1):
if len(x[i]) == 0: return
initial[i] = len(x[i])-1
indexes = initial
while true:
while indexes[index] == -1:
indexes[index] = initial[index]
index +=1
if index == x.len: return
indexes[index] -=1
for ni, i in indexes:
next[ni] = x[ni][i]
var res: seq[T]
shallowCopy(res, next)
result.add(res)
index = 0
indexes[index] -=1

View file

@ -139,27 +139,27 @@ type
proc newDelegate*(): PDelegate =
## Creates a new delegate.
new(result)
result.handleRead = (proc (h: PObject) = nil)
result.handleWrite = (proc (h: PObject) = nil)
result.handleError = (proc (h: PObject) = nil)
result.handleRead = (proc (h: PObject) = discard)
result.handleWrite = (proc (h: PObject) = discard)
result.handleError = (proc (h: PObject) = discard)
result.hasDataBuffered = (proc (h: PObject): bool = return false)
result.task = (proc (h: PObject) = nil)
result.task = (proc (h: PObject) = discard)
result.mode = fmRead
proc newAsyncSocket(): PAsyncSocket =
new(result)
result.info = SockIdle
result.handleRead = (proc (s: PAsyncSocket) = nil)
result.handleRead = (proc (s: PAsyncSocket) = discard)
result.handleWrite = nil
result.handleConnect = (proc (s: PAsyncSocket) = nil)
result.handleAccept = (proc (s: PAsyncSocket) = nil)
result.handleTask = (proc (s: PAsyncSocket) = nil)
result.handleConnect = (proc (s: PAsyncSocket) = discard)
result.handleAccept = (proc (s: PAsyncSocket) = discard)
result.handleTask = (proc (s: PAsyncSocket) = discard)
result.lineBuffer = "".TaintedString
result.sendBuffer = ""
proc AsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
proc asyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
protocol: TProtocol = IPPROTO_TCP,
buffered = true): PAsyncSocket =
## Initialises an AsyncSocket object. If a socket cannot be initialised
@ -233,8 +233,11 @@ proc asyncSockHandleWrite(h: PObject) =
let sock = PAsyncSocket(h)
try:
let bytesSent = sock.socket.sendAsync(sock.sendBuffer)
assert bytesSent > 0
if bytesSent != sock.sendBuffer.len:
if bytesSent == 0:
# Apparently the socket cannot be written to. Even though select
# just told us that it can be... This used to be an assert. Just
# do nothing instead.
elif bytesSent != sock.sendBuffer.len:
sock.sendBuffer = sock.sendBuffer[bytesSent .. -1]
elif bytesSent == sock.sendBuffer.len:
sock.sendBuffer = ""
@ -686,5 +689,5 @@ when isMainModule:
server.listen()
d.register(server)
while d.poll(-1): nil
while d.poll(-1): discard

View file

@ -1,117 +1,127 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a base64 encoder and decoder.
const
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
var total = ((len(s) + 2) div 3) * 4
var numLines = (total + lineLen - 1) div lineLen
#
#
# Nimrod's Runtime Library
# (c) Copyright 2010 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a base64 encoder and decoder.
const
cb64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
template encodeInternal(s: expr, lineLen: int, newLine: string): stmt {.immediate.} =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
var total = ((len(s) + 2) div 3) * 4
var numLines = (total + lineLen - 1) div lineLen
if numLines > 0: inc(total, (numLines-1) * newLine.len)
result = newString(total)
var i = 0
var r = 0
var currLine = 0
while i < s.len - 2:
var a = ord(s[i])
var b = ord(s[i+1])
var c = ord(s[i+2])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result[r+3] = cb64[c and 0x3F]
inc(r, 4)
inc(i, 3)
inc(currLine, 4)
if currLine >= lineLen and i != s.len-2:
for x in items(newLine):
result[r] = x
inc(r)
currLine = 0
if i < s.len-1:
var a = ord(s[i])
var b = ord(s[i+1])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2)]
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
elif i < s.len:
var a = ord(s[i])
result[r] = cb64[a shr 2]
result[r+1] = cb64[(a and 3) shl 4]
result[r+2] = '='
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
else:
assert(r == result.len)
proc decodeByte(b: char): int {.inline.} =
case b
of '+': result = ord('>')
of '0'..'9': result = ord(b) + 4
of 'A'..'Z': result = ord(b) - ord('A')
of 'a'..'z': result = ord(b) - 71
else: result = 63
proc decode*(s: string): string =
## decodes a string in base64 representation back into its original form.
## Whitespace is skipped.
const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
var total = ((len(s) + 3) div 4) * 3
# total is an upper bound, as we will skip arbitrary whitespace:
result = newString(total)
var i = 0
var r = 0
while true:
while s[i] in Whitespace: inc(i)
if i < s.len-3:
var a = s[i].decodeByte
var b = s[i+1].decodeByte
var c = s[i+2].decodeByte
var d = s[i+3].decodeByte
result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03))
result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F))
result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F))
inc(r, 3)
inc(i, 4)
else: break
assert i == s.len
# adjust the length:
if i > 0 and s[i-1] == '=':
dec(r)
if i > 1 and s[i-2] == '=': dec(r)
setLen(result, r)
when isMainModule:
assert encode("leasure.") == "bGVhc3VyZS4="
assert encode("easure.") == "ZWFzdXJlLg=="
assert encode("asure.") == "YXN1cmUu"
assert encode("sure.") == "c3VyZS4="
const longText = """Man is distinguished, not only by his reason, but by this
singular passion from other animals, which is a lust of the mind,
that by a perseverance of delight in the continued and indefatigable
generation of knowledge, exceeds the short vehemence of any carnal
pleasure."""
const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
"asure.", longText]
for t in items(tests):
assert decode(encode(t)) == t
result = newString(total)
var i = 0
var r = 0
var currLine = 0
while i < s.len - 2:
var a = ord(s[i])
var b = ord(s[i+1])
var c = ord(s[i+2])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2) or ((c and 0xC0) shr 6)]
result[r+3] = cb64[c and 0x3F]
inc(r, 4)
inc(i, 3)
inc(currLine, 4)
if currLine >= lineLen and i != s.len-2:
for x in items(newLine):
result[r] = x
inc(r)
currLine = 0
if i < s.len-1:
var a = ord(s[i])
var b = ord(s[i+1])
result[r] = cb64[a shr 2]
result[r+1] = cb64[((a and 3) shl 4) or ((b and 0xF0) shr 4)]
result[r+2] = cb64[((b and 0x0F) shl 2)]
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
elif i < s.len:
var a = ord(s[i])
result[r] = cb64[a shr 2]
result[r+1] = cb64[(a and 3) shl 4]
result[r+2] = '='
result[r+3] = '='
if r+4 != result.len:
setLen(result, r+4)
else:
assert(r == result.len)
proc encode*[T:TInteger|char](s: openarray[T], lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
encodeInternal(s, lineLen, newLine)
proc encode*(s: string, lineLen = 75, newLine="\13\10"): string =
## encodes `s` into base64 representation. After `lineLen` characters, a
## `newline` is added.
encodeInternal(s, lineLen, newLine)
proc decodeByte(b: char): int {.inline.} =
case b
of '+': result = ord('>')
of '0'..'9': result = ord(b) + 4
of 'A'..'Z': result = ord(b) - ord('A')
of 'a'..'z': result = ord(b) - 71
else: result = 63
proc decode*(s: string): string =
## decodes a string in base64 representation back into its original form.
## Whitespace is skipped.
const Whitespace = {' ', '\t', '\v', '\r', '\l', '\f'}
var total = ((len(s) + 3) div 4) * 3
# total is an upper bound, as we will skip arbitrary whitespace:
result = newString(total)
var i = 0
var r = 0
while true:
while s[i] in Whitespace: inc(i)
if i < s.len-3:
var a = s[i].decodeByte
var b = s[i+1].decodeByte
var c = s[i+2].decodeByte
var d = s[i+3].decodeByte
result[r] = chr((a shl 2) and 0xff or ((b shr 4) and 0x03))
result[r+1] = chr((b shl 4) and 0xff or ((c shr 2) and 0x0F))
result[r+2] = chr((c shl 6) and 0xff or (d and 0x3F))
inc(r, 3)
inc(i, 4)
else: break
assert i == s.len
# adjust the length:
if i > 0 and s[i-1] == '=':
dec(r)
if i > 1 and s[i-2] == '=': dec(r)
setLen(result, r)
when isMainModule:
assert encode("leasure.") == "bGVhc3VyZS4="
assert encode("easure.") == "ZWFzdXJlLg=="
assert encode("asure.") == "YXN1cmUu"
assert encode("sure.") == "c3VyZS4="
const longText = """Man is distinguished, not only by his reason, but by this
singular passion from other animals, which is a lust of the mind,
that by a perseverance of delight in the continued and indefatigable
generation of knowledge, exceeds the short vehemence of any carnal
pleasure."""
const tests = ["", "abc", "xyz", "man", "leasure.", "sure.", "easure.",
"asure.", longText]
for t in items(tests):
assert decode(encode(t)) == t

View file

@ -29,14 +29,14 @@ proc openDefaultBrowser*(url: string) =
when useWinUnicode:
var o = newWideCString("open")
var u = newWideCString(url)
discard ShellExecuteW(0'i32, o, u, nil, nil, SW_SHOWNORMAL)
discard shellExecuteW(0'i32, o, u, nil, nil, SW_SHOWNORMAL)
else:
discard ShellExecuteA(0'i32, "open", url, nil, nil, SW_SHOWNORMAL)
discard shellExecuteA(0'i32, "open", url, nil, nil, SW_SHOWNORMAL)
elif defined(macosx):
discard execShellCmd("open " & quoteIfContainsWhite(url))
discard execShellCmd("open " & quoteShell(url))
else:
const attempts = ["gnome-open ", "kde-open ", "xdg-open "]
var u = quoteIfContainsWhite(url)
var u = quoteShell(url)
for a in items(attempts):
if execShellCmd(a & u) == 0: return
for b in getEnv("BROWSER").string.split(PathSep):
@ -45,4 +45,4 @@ proc openDefaultBrowser*(url: string) =
discard startProcess(command=b, args=[url], options={poUseShell})
return
except EOS:
nil
discard

View file

@ -342,16 +342,35 @@ proc writeContentType*() =
##
## .. code-block:: Nimrod
## write(stdout, "Content-type: text/html\n\n")
##
## It also modifies the debug stack traces so that they contain
## ``<br />`` and are easily readable in a browser.
write(stdout, "Content-type: text/html\n\n")
system.stackTraceNewLine = "<br />\n"
proc setStackTraceNewLine*() =
## Modifies the debug stack traces so that they contain
## ``<br />`` and are easily readable in a browser.
system.stackTraceNewLine = "<br />\n"
proc resetForStacktrace() =
stdout.write """<!--: spam
Content-Type: text/html
<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> -->
<body bgcolor=#f0f0f8><font color=#f0f0f8 size=-5> --> -->
</font> </font> </font> </script> </object> </blockquote> </pre>
</table> </table> </table> </table> </table> </font> </font> </font>
"""
proc writeErrorMessage*(data: string) =
## Tries to reset browser state and writes `data` to stdout in
## <plaintext> tag.
resetForStacktrace()
# We use <plaintext> here, instead of escaping, so stacktrace can
# be understood by human looking at source.
stdout.write("<plaintext>\n")
stdout.write(data)
proc setStackTraceStdout*() =
## Makes Nimrod output stacktraces to stdout, instead of server log.
errorMessageWriter = writeErrorMessage
proc setStackTraceNewLine*() {.deprecated.} =
## Makes Nimrod output stacktraces to stdout, instead of server log.
## Depracated alias for setStackTraceStdout.
setStackTraceStdout()
proc setCookie*(name, value: string) =
## Sets a cookie.
@ -374,4 +393,3 @@ when isMainModule:
const test1 = "abc\L+def xyz"
assert UrlEncode(test1) == "abc%0A%2Bdef+xyz"
assert UrlDecode(UrlEncode(test1)) == test1

View file

@ -0,0 +1,582 @@
#nimrod c -t:-march=i686 --cpu:amd64 --threads:on -d:release lockfreehash.nim
import baseutils, unsigned, math, hashes
const
minTableSize = 8
reProbeLimit = 12
minCopyWork = 4096
intSize = sizeof(int)
when sizeof(int) == 4: # 32bit
type
TRaw = range[0..1073741823]
## The range of uint values that can be stored directly in a value slot
## when on a 32 bit platform
elif sizeof(int) == 8: # 64bit
type
TRaw = range[0..4611686018427387903]
## The range of uint values that can be stored directly in a value slot
## when on a 64 bit platform
else:
{.error: "unsupported platform".}
type
TEntry = tuple
key: int
value: int
TEntryArr = ptr array[0..10_000_000, TEntry]
PConcTable[K,V] = ptr object {.pure.}
len: int
used: int
active: int
copyIdx: int
copyDone: int
next: PConcTable[K,V]
data: TEntryArr
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int
#------------------------------------------------------------------------------
# Create a new table
proc newLFTable*[K,V](size: int = minTableSize): PConcTable[K,V] =
let
dataLen = max(nextPowerOfTwo(size), minTableSize)
dataSize = dataLen*sizeof(TEntry)
dataMem = allocShared0(dataSize)
tableSize = 7 * intSize
tableMem = allocShared0(tableSize)
table = cast[PConcTable[K,V]](tableMem)
table.len = dataLen
table.used = 0
table.active = 0
table.copyIdx = 0
table.copyDone = 0
table.next = nil
table.data = cast[TEntryArr](dataMem)
result = table
#------------------------------------------------------------------------------
# Delete a table
proc deleteConcTable[K,V](tbl: PConcTable[K,V]) =
deallocShared(tbl.data)
deallocShared(tbl)
#------------------------------------------------------------------------------
proc `[]`[K,V](table: var PConcTable[K,V], i: int): var TEntry {.inline.} =
table.data[i]
#------------------------------------------------------------------------------
# State flags stored in ptr
proc pack[T](x: T): int {.inline.} =
result = (cast[int](x) shl 2)
#echo("packKey ",cast[int](x) , " -> ", result)
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
proc pop(x: int): int {.inline.} =
result = x and 0xFFFFFFFC'i32
# Pop the raw value off of our Key or Val
proc popRaw(x: int): int {.inline.} =
result = x shr 2
# Pop the flags off returning a 4 byte aligned ptr to our Key or Val
proc popPtr[V](x: int): ptr V {.inline.} =
result = cast[ptr V](pop(x))
#echo("popPtr " & $x & " -> " & $cast[int](result))
# Ghost (sentinel)
# K or V is no longer valid use new table
const Ghost = 0xFFFFFFFC
proc isGhost(x: int): bool {.inline.} =
result = x == 0xFFFFFFFC
# Tombstone
# applied to V = K is dead
proc isTomb(x: int): bool {.inline.} =
result = (x and 0x00000002) != 0
proc setTomb(x: int): int {.inline.} =
result = x or 0x00000002
# Prime
# K or V is in new table copied from old
proc isPrime(x: int): bool {.inline.} =
result = (x and 0x00000001) != 0
proc setPrime(x: int): int {.inline.} =
result = x or 0x00000001
#------------------------------------------------------------------------------
##This is for i32 only need to override for i64
proc hashInt(x: int):int {.inline.} =
var h = uint32(x) #shr 2'u32
h = h xor (h shr 16'u32)
h *= 0x85ebca6b'u32
h = h xor (h shr 13'u32)
h *= 0xc2b2ae35'u32
h = h xor (h shr 16'u32)
result = int(h)
#------------------------------------------------------------------------------
proc resize[K,V](self: PConcTable[K,V]): PConcTable[K,V] =
var next = atomic_load_n(self.next.addr, ATOMIC_RELAXED)
#echo("next = " & $cast[int](next))
if next != nil:
#echo("A new table already exists, copy in progress")
return next
var
oldLen = atomic_load_n(self.len.addr, ATOMIC_RELAXED)
newTable = newLFTable[K,V](oldLen*2)
success = atomic_compare_exchange_n(self.next.addr, next.addr, newTable,
false, ATOMIC_RELAXED, ATOMIC_RELAXED)
if not success:
echo("someone beat us to it! delete table we just created and return his " & $cast[int](next))
deleteConcTable(newTable)
return next
else:
echo("Created New Table! " & $cast[int](newTable) & " Size = " & $newTable.len)
return newTable
#------------------------------------------------------------------------------
#proc keyEQ[K](key1: ptr K, key2: ptr K): bool {.inline.} =
proc keyEQ[K](key1: int, key2: int): bool {.inline.} =
result = false
when K is TRaw:
if key1 == key2:
result = true
else:
var
p1 = popPtr[K](key1)
p2 = popPtr[K](key2)
if p1 != nil and p2 != nil:
if cast[int](p1) == cast[int](p2):
return true
if p1[] == p2[]:
return true
#------------------------------------------------------------------------------
#proc tableFull(self: var PConcTable[K,V]) : bool {.inline.} =
#------------------------------------------------------------------------------
proc copySlot[K,V](idx: int, oldTbl: var PConcTable[K,V], newTbl: var PConcTable[K,V]): bool =
#echo("Copy idx " & $idx)
var
oldVal = 0
oldkey = 0
ok = false
result = false
#Block the key so no other threads waste time here
while not ok:
ok = atomic_compare_exchange_n(oldTbl[idx].key.addr, oldKey.addr,
setTomb(oldKey), false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("oldKey was = " & $oldKey & " set it to tomb " & $setTomb(oldKey))
#Prevent new values from appearing in the old table by priming
oldVal = atomic_load_n(oldTbl[idx].value.addr, ATOMIC_RELAXED)
while not isPrime(oldVal):
var box = if oldVal == NULL or isTomb(oldVal) : oldVal.setTomb.setPrime
else: oldVal.setPrime
if atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
box, false, ATOMIC_RELAXED, ATOMIC_RELAXED):
if isPrime(box) and isTomb(box):
return true
oldVal = box
break
#echo("oldVal was = ", oldVal, " set it to prime ", box)
if isPrime(oldVal) and isTomb(oldVal):
#when not (K is TRaw):
# deallocShared(popPtr[K](oldKey))
return false
if isTomb(oldVal):
echo("oldVal is Tomb!!!, should not happen")
if pop(oldVal) != NULL:
result = setVal(newTbl, pop(oldKey), pop(oldVal), NULL, true) == NULL
if result:
#echo("Copied a Slot! idx= " & $idx & " key= " & $oldKey & " val= " & $oldVal)
else:
#echo("copy slot failed")
# Our copy is done so we disable the old slot
while not ok:
ok = atomic_compare_exchange_n(oldTbl[idx].value.addr, oldVal.addr,
oldVal.setTomb.setPrime , false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("disabled old slot")
#echo"---------------------"
#------------------------------------------------------------------------------
proc promote[K,V](table: var PConcTable[K,V]) =
var
newData = atomic_load_n(table.next.data.addr, ATOMIC_RELAXED)
newLen = atomic_load_n(table.next.len.addr, ATOMIC_RELAXED)
newUsed = atomic_load_n(table.next.used.addr, ATOMIC_RELAXED)
deallocShared(table.data)
atomic_store_n(table.data.addr, newData, ATOMIC_RELAXED)
atomic_store_n(table.len.addr, newLen, ATOMIC_RELAXED)
atomic_store_n(table.used.addr, newUsed, ATOMIC_RELAXED)
atomic_store_n(table.copyIdx.addr, 0, ATOMIC_RELAXED)
atomic_store_n(table.copyDone.addr, 0, ATOMIC_RELAXED)
deallocShared(table.next)
atomic_store_n(table.next.addr, nil, ATOMIC_RELAXED)
echo("new table swapped!")
#------------------------------------------------------------------------------
proc checkAndPromote[K,V](table: var PConcTable[K,V], workDone: int): bool =
var
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
ok: bool
result = false
if workDone > 0:
#echo("len to copy =" & $oldLen)
#echo("copyDone + workDone = " & $copyDone & " + " & $workDone)
while not ok:
ok = atomic_compare_exchange_n(table.copyDone.addr, copyDone.addr,
copyDone + workDone, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#if ok: echo("set copyDone")
# If the copy is done we can promote this table
if copyDone + workDone >= oldLen:
# Swap new data
#echo("work is done!")
table.promote
result = true
#------------------------------------------------------------------------------
proc copySlotAndCheck[K,V](table: var PConcTable[K,V], idx: int):
PConcTable[K,V] =
var
newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
result = newTable
if newTable != nil and copySlot(idx, table, newTable):
#echo("copied a single slot, idx = " & $idx)
if checkAndPromote(table, 1): return table
#------------------------------------------------------------------------------
proc helpCopy[K,V](table: var PConcTable[K,V]): PConcTable[K,V] =
var
newTable = cast[PConcTable[K,V]](atomic_load_n(table.next.addr, ATOMIC_RELAXED))
result = newTable
if newTable != nil:
var
oldLen = atomic_load_n(table.len.addr, ATOMIC_RELAXED)
copyDone = atomic_load_n(table.copyDone.addr, ATOMIC_RELAXED)
copyIdx = 0
work = min(oldLen, minCopyWork)
#panicStart = -1
workDone = 0
if copyDone < oldLen:
var ok: bool
while not ok:
ok = atomic_compare_exchange_n(table.copyIdx.addr, copyIdx.addr,
copyIdx + work, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
#echo("copy idx = ", copyIdx)
for i in 0..work-1:
var idx = (copyIdx + i) and (oldLen - 1)
if copySlot(idx, table, newTable):
workDone += 1
if workDone > 0:
#echo("did work ", workDone, " on thread ", cast[int](myThreadID[pointer]()))
if checkAndPromote(table, workDone): return table
# In case a thread finished all the work then got stalled before promotion
if checkAndPromote(table, 0): return table
#------------------------------------------------------------------------------
proc setVal[K,V](table: var PConcTable[K,V], key: int, val: int,
expVal: int, match: bool): int =
#echo("-try set- in table ", " key = ", (popPtr[K](key)[]), " val = ", val)
when K is TRaw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
var
nextTable: PConcTable[K,V]
probes = 1
# spin until we find a key slot or build and jump to next table
while true:
idx = idx and (table.len - 1)
#echo("try set idx = " & $idx & "for" & $key)
var
probedKey = NULL
openKey = atomic_compare_exchange_n(table[idx].key.addr, probedKey.addr,
key, false, ATOMIC_RELAXED, ATOMIC_RELAXED)
if openKey:
if val.isTomb:
#echo("val was tomb, bail, no reason to set an open slot to tomb")
return val
#increment used slots
#echo("found an open slot, total used = " &
#$atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED))
discard atomic_add_fetch(table.used.addr, 1, ATOMIC_RELAXED)
break # We found an open slot
#echo("set idx ", idx, " key = ", key, " probed = ", probedKey)
if keyEQ[K](probedKey, key):
#echo("we found the matching slot")
break # We found a matching slot
if (not(expVal != NULL and match)) and (probes >= reProbeLimit or key.isTomb):
if key.isTomb: echo("Key is Tombstone")
#if probes >= reProbeLimit: echo("Too much probing " & $probes)
#echo("try to resize")
#create next bigger table
nextTable = resize(table)
#help do some copying
#echo("help copy old table to new")
nextTable = helpCopy(table)
#now setVal in the new table instead
#echo("jumping to next table to set val")
return setVal(nextTable, key, val, expVal, match)
else:
idx += 1
probes += 1
# Done spinning for a new slot
var oldVal = atomic_load_n(table[idx].value.addr, ATOMIC_RELAXED)
if val == oldVal:
#echo("this val is alredy in the slot")
return oldVal
nextTable = atomic_load_n(table.next.addr, ATOMIC_SEQ_CST)
if nextTable == nil and
((oldVal == NULL and
(probes >= reProbeLimit or table.used / table.len > 0.8)) or
(isPrime(oldVal))):
if table.used / table.len > 0.8: echo("resize because usage ratio = " &
$(table.used / table.len))
if isPrime(oldVal): echo("old val isPrime, should be a rare mem ordering event")
nextTable = resize(table)
if nextTable != nil:
#echo("tomb old slot then set in new table")
nextTable = copySlotAndCheck(table,idx)
return setVal(nextTable, key, val, expVal, match)
# Finaly ready to add new val to table
while true:
if match and oldVal != expVal:
#echo("set failed, no match oldVal= " & $oldVal & " expVal= " & $expVal)
return oldVal
if atomic_compare_exchange_n(table[idx].value.addr, oldVal.addr,
val, false, ATOMIC_RELEASE, ATOMIC_RELAXED):
#echo("val set at table " & $cast[int](table))
if expVal != NULL:
if (oldVal == NULL or isTomb(oldVal)) and not isTomb(val):
discard atomic_add_fetch(table.active.addr, 1, ATOMIC_RELAXED)
elif not (oldVal == NULL or isTomb(oldVal)) and isTomb(val):
discard atomic_add_fetch(table.active.addr, -1, ATOMIC_RELAXED)
if oldVal == NULL and expVal != NULL:
return setTomb(oldVal)
else: return oldVal
if isPrime(oldVal):
nextTable = copySlotAndCheck(table, idx)
return setVal(nextTable, key, val, expVal, match)
#------------------------------------------------------------------------------
proc getVal[K,V](table: var PConcTable[K,V], key: int): int =
#echo("-try get- key = " & $key)
when K is TRaw:
var idx = hashInt(key)
else:
var idx = popPtr[K](key)[].hash
#echo("get idx ", idx)
var
probes = 0
val: int
while true:
idx = idx and (table.len - 1)
var
newTable: PConcTable[K,V] # = atomic_load_n(table.next.addr, ATOMIC_ACQUIRE)
probedKey = atomic_load_n(table[idx].key.addr, ATOMIC_SEQ_CST)
if keyEQ[K](probedKey, key):
#echo("found key after ", probes+1)
val = atomic_load_n(table[idx].value.addr, ATOMIC_ACQUIRE)
if not isPrime(val):
if isTomb(val):
#echo("val was tomb but not prime")
return NULL
else:
#echo("-GotIt- idx = ", idx, " key = ", key, " val ", val )
return val
else:
newTable = copySlotAndCheck(table, idx)
return getVal(newTable, key)
else:
#echo("probe ", probes, " idx = ", idx, " key = ", key, " found ", probedKey )
if probes >= reProbeLimit*4 or key.isTomb:
if newTable == nil:
#echo("too many probes and no new table ", key, " ", idx )
return NULL
else:
newTable = helpCopy(table)
return getVal(newTable, key)
idx += 1
probes += 1
#------------------------------------------------------------------------------
#proc set*(table: var PConcTable[TRaw,TRaw], key: TRaw, val: TRaw) =
# discard setVal(table, pack(key), pack(key), NULL, false)
#proc set*[V](table: var PConcTable[TRaw,V], key: TRaw, val: ptr V) =
# discard setVal(table, pack(key), cast[int](val), NULL, false)
proc set*[K,V](table: var PConcTable[K,V], key: var K, val: var V) =
when not (K is TRaw):
var newKey = cast[int](copyShared(key))
else:
var newKey = pack(key)
when not (V is TRaw):
var newVal = cast[int](copyShared(val))
else:
var newVal = pack(val)
var oldPtr = pop(setVal(table, newKey, newVal, NULL, false))
#echo("oldPtr = ", cast[int](oldPtr), " newPtr = ", cast[int](newPtr))
when not (V is TRaw):
if newVal != oldPtr and oldPtr != NULL:
deallocShared(cast[ptr V](oldPtr))
proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
when not (V is TRaw):
when not (K is TRaw):
return popPtr[V](getVal(table, cast[int](key.addr)))[]
else:
return popPtr[V](getVal(table, pack(key)))[]
else:
when not (K is TRaw):
return popRaw(getVal(table, cast[int](key.addr)))
else:
return popRaw(getVal(table, pack(key)))
#proc `[]`[K,V](table: var PConcTable[K,V], key: K): PEntry[K,V] {.inline.} =
# getVal(table, key)
#proc `[]=`[K,V](table: var PConcTable[K,V], key: K, val: V): PEntry[K,V] {.inline.} =
# setVal(table, key, val)
#Tests ----------------------------
when isMainModule:
import locks, times, mersenne
const
numTests = 100000
numThreads = 10
type
TTestObj = tuple
thr: int
f0: int
f1: int
TData = tuple[k: string,v: TTestObj]
PDataArr = array[0..numTests-1, TData]
Dict = PConcTable[string,TTestObj]
var
thr: array[0..numThreads-1, TThread[Dict]]
table = newLFTable[string,TTestObj](8)
rand = newMersenneTwister(2525)
proc createSampleData(len: int): PDataArr =
#result = cast[PDataArr](allocShared0(sizeof(TData)*numTests))
for i in 0..len-1:
result[i].k = "mark" & $(i+1)
#echo("mark" & $(i+1), " ", hash("mark" & $(i+1)))
result[i].v.thr = 0
result[i].v.f0 = i+1
result[i].v.f1 = 0
#echo("key = " & $(i+1) & " Val ptr = " & $cast[int](result[i].v.addr))
proc threadProc(tp: Dict) {.thread.} =
var t = cpuTime();
for i in 1..numTests:
var key = "mark" & $(i)
var got = table.get(key)
got.thr = cast[int](myThreadID[pointer]())
got.f1 = got.f1 + 1
table.set(key, got)
t = cpuTime() - t
echo t
var testData = createSampleData(numTests)
for i in 0..numTests-1:
table.set(testData[i].k, testData[i].v)
var i = 0
while i < numThreads:
createThread(thr[i], threadProc, table)
i += 1
joinThreads(thr)
var fails = 0
for i in 0..numTests-1:
var got = table.get(testData[i].k)
if got.f0 != i+1 or got.f1 != numThreads:
fails += 1
echo(got)
echo("Failed read or write = ", fails)
#for i in 1..numTests:
# echo(i, " = ", hashInt(i) and 8191)
deleteConcTable(table)

View file

@ -0,0 +1,41 @@
#------------------------------------------------------------------------------
## Useful Constants
const NULL* = 0
#------------------------------------------------------------------------------
## Memory Utility Functions
proc newHeap*[T](): ptr T =
result = cast[ptr T](alloc0(sizeof(T)))
proc copyNew*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = alloc(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
proc copyTo*[T](val: var T, dest: int) =
copyMem(pointer(dest), val.addr, sizeof(T))
proc allocType*[T](): pointer = alloc(sizeof(T))
proc newShared*[T](): ptr T =
result = cast[ptr T](allocShared0(sizeof(T)))
proc copyShared*[T](x: var T): ptr T =
var
size = sizeof(T)
mem = allocShared(size)
copyMem(mem, x.addr, size)
return cast[ptr T](mem)
#------------------------------------------------------------------------------
## Pointer arithmetic
proc `+`*(p: pointer, i: int): pointer {.inline.} =
cast[pointer](cast[int](p) + i)

View file

@ -50,7 +50,7 @@ proc mustRehash(length, counter: int): bool {.inline.} =
proc nextTry(h, maxHash: THash): THash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc IntSetGet(t: TIntSet, key: int): PTrunk =
proc intSetGet(t: TIntSet, key: int): PTrunk =
var h = key and t.max
while t.data[h] != nil:
if t.data[h].key == key:
@ -58,7 +58,7 @@ proc IntSetGet(t: TIntSet, key: int): PTrunk =
h = nextTry(h, t.max)
result = nil
proc IntSetRawInsert(t: TIntSet, data: var TTrunkSeq, desc: PTrunk) =
proc intSetRawInsert(t: TIntSet, data: var TTrunkSeq, desc: PTrunk) =
var h = desc.key and t.max
while data[h] != nil:
assert(data[h] != desc)
@ -66,22 +66,22 @@ proc IntSetRawInsert(t: TIntSet, data: var TTrunkSeq, desc: PTrunk) =
assert(data[h] == nil)
data[h] = desc
proc IntSetEnlarge(t: var TIntSet) =
proc intSetEnlarge(t: var TIntSet) =
var n: TTrunkSeq
var oldMax = t.max
t.max = ((t.max + 1) * 2) - 1
newSeq(n, t.max + 1)
for i in countup(0, oldmax):
if t.data[i] != nil: IntSetRawInsert(t, n, t.data[i])
for i in countup(0, oldMax):
if t.data[i] != nil: intSetRawInsert(t, n, t.data[i])
swap(t.data, n)
proc IntSetPut(t: var TIntSet, key: int): PTrunk =
proc intSetPut(t: var TIntSet, key: int): PTrunk =
var h = key and t.max
while t.data[h] != nil:
if t.data[h].key == key:
return t.data[h]
h = nextTry(h, t.max)
if mustRehash(t.max + 1, t.counter): IntSetEnlarge(t)
if mustRehash(t.max + 1, t.counter): intSetEnlarge(t)
inc(t.counter)
h = key and t.max
while t.data[h] != nil: h = nextTry(h, t.max)
@ -94,7 +94,7 @@ proc IntSetPut(t: var TIntSet, key: int): PTrunk =
proc contains*(s: TIntSet, key: int): bool =
## returns true iff `key` is in `s`.
var t = IntSetGet(s, `shr`(key, TrunkShift))
var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil:
var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0
@ -103,14 +103,14 @@ proc contains*(s: TIntSet, key: int): bool =
proc incl*(s: var TIntSet, key: int) =
## includes an element `key` in `s`.
var t = IntSetPut(s, `shr`(key, TrunkShift))
var t = intSetPut(s, `shr`(key, TrunkShift))
var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] or
`shl`(1, u and IntMask)
proc excl*(s: var TIntSet, key: int) =
## excludes `key` from the set `s`.
var t = IntSetGet(s, `shr`(key, TrunkShift))
var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil:
var u = key and TrunkMask
t.bits[`shr`(u, IntShift)] = t.bits[`shr`(u, IntShift)] and
@ -119,7 +119,7 @@ proc excl*(s: var TIntSet, key: int) =
proc containsOrIncl*(s: var TIntSet, key: int): bool =
## returns true if `s` contains `key`, otherwise `key` is included in `s`
## and false is returned.
var t = IntSetGet(s, `shr`(key, TrunkShift))
var t = intSetGet(s, `shr`(key, TrunkShift))
if t != nil:
var u = key and TrunkMask
result = (t.bits[`shr`(u, IntShift)] and `shl`(1, u and IntMask)) != 0

View file

@ -41,19 +41,19 @@ type
proc initSinglyLinkedList*[T](): TSinglyLinkedList[T] =
## creates a new singly linked list that is empty.
nil
discard
proc initDoublyLinkedList*[T](): TDoublyLinkedList[T] =
## creates a new doubly linked list that is empty.
nil
discard
proc initSinglyLinkedRing*[T](): TSinglyLinkedRing[T] =
## creates a new singly linked ring that is empty.
nil
discard
proc initDoublyLinkedRing*[T](): TDoublyLinkedRing[T] =
## creates a new doubly linked ring that is empty.
nil
discard
proc newDoublyLinkedNode*[T](value: T): PDoublyLinkedNode[T] =
## creates a new doubly linked node with the given `value`.

View file

@ -136,7 +136,7 @@ proc delete*[T](s: var seq[T], first=0, last=0) =
s[i].shallowCopy(s[j])
inc(i)
inc(j)
setlen(s, newLen)
setLen(s, newLen)
proc insert*[T](dest: var seq[T], src: openArray[T], pos=0) =
## Inserts items from `src` into `dest` at position `pos`. This modifies
@ -276,6 +276,38 @@ template foldr*(sequence, operation: expr): expr =
result = operation
result
template mapIt*(seq1, typ, pred: expr): expr =
## Convenience template around the ``map`` proc to reduce typing.
##
## The template injects the ``it`` variable which you can use directly in an
## expression. You also need to pass as `typ` the type of the expression,
## since the new returned sequence can have a different type than the
## original. Example:
##
## .. code-block:: nimrod
## let
## nums = @[1, 2, 3, 4]
## strings = nums.mapIt(string, $(4 * it))
var result {.gensym.}: seq[typ] = @[]
for it {.inject.} in items(seq1):
result.add(pred)
result
template mapIt*(varSeq, pred: expr) =
## Convenience template around the mutable ``map`` proc to reduce typing.
##
## The template injects the ``it`` variable which you can use directly in an
## expression. The expression has to return the same type as the sequence you
## are mutating. Example:
##
## .. code-block:: nimrod
## var nums = @[1, 2, 3, 4]
## nums.mapIt(it * 3)
## assert nums[0] + nums[3] == 15
for i in 0 .. <len(varSeq):
let it {.inject.} = varSeq[i]
varSeq[i] = pred
when isMainModule:
import strutils
block: # concat test
@ -381,4 +413,11 @@ when isMainModule:
Inserting [2,2,2,2,2,2] into [1,1,1,1,1,1,1,1]
at 3 is [1,1,1,2,2,2,2,2,2,1,1,1,1,1]"""
block: # mapIt tests
var
nums = @[1, 2, 3, 4]
strings = nums.mapIt(string, $(4 * it))
nums.mapIt(it * 3)
assert nums[0] + nums[3] == 15
echo "Finished doc tests"

View file

@ -65,38 +65,38 @@ template rawInsertImpl() {.dirty.} =
data[h].key = key
data[h].slot = seFilled
proc RawGet[A](s: TSet[A], key: A): int =
proc rawGet[A](s: TSet[A], key: A): int =
rawGetImpl()
proc contains*[A](s: TSet[A], key: A): bool =
## returns true iff `key` is in `s`.
var index = RawGet(s, key)
var index = rawGet(s, key)
result = index >= 0
proc RawInsert[A](s: var TSet[A], data: var TKeyValuePairSeq[A], key: A) =
proc rawInsert[A](s: var TSet[A], data: var TKeyValuePairSeq[A], key: A) =
rawInsertImpl()
proc Enlarge[A](s: var TSet[A]) =
proc enlarge[A](s: var TSet[A]) =
var n: TKeyValuePairSeq[A]
newSeq(n, len(s.data) * growthFactor)
for i in countup(0, high(s.data)):
if s.data[i].slot == seFilled: RawInsert(s, n, s.data[i].key)
if s.data[i].slot == seFilled: rawInsert(s, n, s.data[i].key)
swap(s.data, n)
template inclImpl() {.dirty.} =
var index = RawGet(s, key)
var index = rawGet(s, key)
if index < 0:
if mustRehash(len(s.data), s.counter): Enlarge(s)
RawInsert(s, s.data, key)
if mustRehash(len(s.data), s.counter): enlarge(s)
rawInsert(s, s.data, key)
inc(s.counter)
template containsOrInclImpl() {.dirty.} =
var index = RawGet(s, key)
var index = rawGet(s, key)
if index >= 0:
result = true
else:
if mustRehash(len(s.data), s.counter): Enlarge(s)
RawInsert(s, s.data, key)
if mustRehash(len(s.data), s.counter): enlarge(s)
rawInsert(s, s.data, key)
inc(s.counter)
proc incl*[A](s: var TSet[A], key: A) =
@ -105,7 +105,7 @@ proc incl*[A](s: var TSet[A], key: A) =
proc excl*[A](s: var TSet[A], key: A) =
## excludes `key` from the set `s`.
var index = RawGet(s, key)
var index = rawGet(s, key)
if index >= 0:
s.data[index].slot = seDeleted
dec(s.counter)
@ -122,7 +122,7 @@ proc initSet*[A](initialSize=64): TSet[A] =
result.counter = 0
newSeq(result.data, initialSize)
proc toSet*[A](keys: openarray[A]): TSet[A] =
proc toSet*[A](keys: openArray[A]): TSet[A] =
## creates a new hash set that contains the given `keys`.
result = initSet[A](nextPowerOfTwo(keys.len+10))
for key in items(keys): result.incl(key)
@ -169,15 +169,15 @@ iterator items*[A](s: TOrderedSet[A]): A =
forAllOrderedPairs:
yield s.data[h].key
proc RawGet[A](s: TOrderedSet[A], key: A): int =
proc rawGet[A](s: TOrderedSet[A], key: A): int =
rawGetImpl()
proc contains*[A](s: TOrderedSet[A], key: A): bool =
## returns true iff `key` is in `s`.
var index = RawGet(s, key)
var index = rawGet(s, key)
result = index >= 0
proc RawInsert[A](s: var TOrderedSet[A],
proc rawInsert[A](s: var TOrderedSet[A],
data: var TOrderedKeyValuePairSeq[A], key: A) =
rawInsertImpl()
data[h].next = -1
@ -185,7 +185,7 @@ proc RawInsert[A](s: var TOrderedSet[A],
if s.last >= 0: data[s.last].next = h
s.last = h
proc Enlarge[A](s: var TOrderedSet[A]) =
proc enlarge[A](s: var TOrderedSet[A]) =
var n: TOrderedKeyValuePairSeq[A]
newSeq(n, len(s.data) * growthFactor)
var h = s.first
@ -194,7 +194,7 @@ proc Enlarge[A](s: var TOrderedSet[A]) =
while h >= 0:
var nxt = s.data[h].next
if s.data[h].slot == seFilled:
RawInsert(s, n, s.data[h].key)
rawInsert(s, n, s.data[h].key)
h = nxt
swap(s.data, n)
@ -216,7 +216,7 @@ proc initOrderedSet*[A](initialSize=64): TOrderedSet[A] =
result.last = -1
newSeq(result.data, initialSize)
proc toOrderedSet*[A](keys: openarray[A]): TOrderedSet[A] =
proc toOrderedSet*[A](keys: openArray[A]): TOrderedSet[A] =
## creates a new ordered hash set that contains the given `keys`.
result = initOrderedSet[A](nextPowerOfTwo(keys.len+10))
for key in items(keys): result.incl(key)
@ -225,4 +225,19 @@ proc `$`*[A](s: TOrderedSet[A]): string =
## The `$` operator for ordered hash sets.
dollarImpl()
proc `<`*[A](s, t: TSet[A]): bool =
## Is s a strict subset of t?
s.counter != t.counter and s <= t
proc `<=`*[A](s, t: TSet[A]): bool =
## Is s a subset of t?
result = false
if s.counter > t.counter: return
result = true
for item in s:
if not(t.contains(item)):
result = false
return
proc `==`*[A](s, t: TSet[A]): bool =
s.counter == t.counter and s <= t

View file

@ -85,7 +85,7 @@ template rawInsertImpl() {.dirty.} =
data[h].val = val
data[h].slot = seFilled
proc RawGet[A, B](t: TTable[A, B], key: A): int =
proc rawGet[A, B](t: TTable[A, B], key: A): int =
rawGetImpl()
proc `[]`*[A, B](t: TTable[A, B], key: A): B =
@ -93,13 +93,13 @@ proc `[]`*[A, B](t: TTable[A, B], key: A): B =
## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var TTable[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0: result = t.data[index].val
else: raise newException(EInvalidKey, "key not found: " & $key)
@ -107,39 +107,39 @@ proc hasKey*[A, B](t: TTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
proc RawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B],
proc rawInsert[A, B](t: var TTable[A, B], data: var TKeyValuePairSeq[A, B],
key: A, val: B) =
rawInsertImpl()
proc Enlarge[A, B](t: var TTable[A, B]) =
proc enlarge[A, B](t: var TTable[A, B]) =
var n: TKeyValuePairSeq[A, B]
newSeq(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
if t.data[i].slot == seFilled: RawInsert(t, n, t.data[i].key, t.data[i].val)
if t.data[i].slot == seFilled: rawInsert(t, n, t.data[i].key, t.data[i].val)
swap(t.data, n)
template AddImpl() {.dirty.} =
if mustRehash(len(t.data), t.counter): Enlarge(t)
RawInsert(t, t.data, key, val)
template addImpl() {.dirty.} =
if mustRehash(len(t.data), t.counter): enlarge(t)
rawInsert(t, t.data, key, val)
inc(t.counter)
template PutImpl() {.dirty.} =
var index = RawGet(t, key)
template putImpl() {.dirty.} =
var index = rawGet(t, key)
if index >= 0:
t.data[index].val = val
else:
AddImpl()
addImpl()
when false:
# not yet used:
template HasKeyOrPutImpl() {.dirty.} =
var index = RawGet(t, key)
template hasKeyOrPutImpl() {.dirty.} =
var index = rawGet(t, key)
if index >= 0:
t.data[index].val = val
result = true
else:
if mustRehash(len(t.data), t.counter): Enlarge(t)
RawInsert(t, t.data, key, val)
if mustRehash(len(t.data), t.counter): enlarge(t)
rawInsert(t, t.data, key, val)
inc(t.counter)
result = false
@ -149,11 +149,11 @@ proc `[]=`*[A, B](t: var TTable[A, B], key: A, val: B) =
proc add*[A, B](t: var TTable[A, B], key: A, val: B) =
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
AddImpl()
addImpl()
proc del*[A, B](t: var TTable[A, B], key: A) =
## deletes `key` from hash table `t`.
var index = RawGet(t, key)
let index = rawGet(t, key)
if index >= 0:
t.data[index].slot = seDeleted
dec(t.counter)
@ -168,7 +168,7 @@ proc initTable*[A, B](initialSize=64): TTable[A, B] =
result.counter = 0
newSeq(result.data, initialSize)
proc toTable*[A, B](pairs: openarray[tuple[key: A,
proc toTable*[A, B](pairs: openArray[tuple[key: A,
val: B]]): TTable[A, B] =
## creates a new hash table that contains the given `pairs`.
result = initTable[A, B](nextPowerOfTwo(pairs.len+10))
@ -189,6 +189,16 @@ template dollarImpl(): stmt {.dirty.} =
proc `$`*[A, B](t: TTable[A, B]): string =
## The `$` operator for hash tables.
dollarImpl()
proc `==`*[A, B](s, t: TTable[A, B]): bool =
s.counter == t.counter and s.data == t.data
proc indexBy*[A, B, C](collection: A, index: proc(x: B): C): TTable[C, B] =
## Index the collection with the proc provided.
# TODO: As soon as supported, change collection: A to collection: A[B]
result = initTable[C, B]()
for item in collection:
result[index(item)] = item
# ------------------------------ ordered table ------------------------------
@ -240,7 +250,7 @@ iterator mvalues*[A, B](t: var TOrderedTable[A, B]): var B =
forAllOrderedPairs:
yield t.data[h].val
proc RawGet[A, B](t: TOrderedTable[A, B], key: A): int =
proc rawGet[A, B](t: TOrderedTable[A, B], key: A): int =
rawGetImpl()
proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B =
@ -248,13 +258,13 @@ proc `[]`*[A, B](t: TOrderedTable[A, B], key: A): B =
## default empty value for the type `B` is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0: result = t.data[index].val
proc mget*[A, B](t: var TOrderedTable[A, B], key: A): var B =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0: result = t.data[index].val
else: raise newException(EInvalidKey, "key not found: " & $key)
@ -262,7 +272,7 @@ proc hasKey*[A, B](t: TOrderedTable[A, B], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
proc RawInsert[A, B](t: var TOrderedTable[A, B],
proc rawInsert[A, B](t: var TOrderedTable[A, B],
data: var TOrderedKeyValuePairSeq[A, B],
key: A, val: B) =
rawInsertImpl()
@ -271,7 +281,7 @@ proc RawInsert[A, B](t: var TOrderedTable[A, B],
if t.last >= 0: data[t.last].next = h
t.last = h
proc Enlarge[A, B](t: var TOrderedTable[A, B]) =
proc enlarge[A, B](t: var TOrderedTable[A, B]) =
var n: TOrderedKeyValuePairSeq[A, B]
newSeq(n, len(t.data) * growthFactor)
var h = t.first
@ -280,7 +290,7 @@ proc Enlarge[A, B](t: var TOrderedTable[A, B]) =
while h >= 0:
var nxt = t.data[h].next
if t.data[h].slot == seFilled:
RawInsert(t, n, t.data[h].key, t.data[h].val)
rawInsert(t, n, t.data[h].key, t.data[h].val)
h = nxt
swap(t.data, n)
@ -290,7 +300,7 @@ proc `[]=`*[A, B](t: var TOrderedTable[A, B], key: A, val: B) =
proc add*[A, B](t: var TOrderedTable[A, B], key: A, val: B) =
## puts a new (key, value)-pair into `t` even if ``t[key]`` already exists.
AddImpl()
addImpl()
proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] =
## creates a new ordered hash table that is empty.
@ -304,7 +314,7 @@ proc initOrderedTable*[A, B](initialSize=64): TOrderedTable[A, B] =
result.last = -1
newSeq(result.data, initialSize)
proc toOrderedTable*[A, B](pairs: openarray[tuple[key: A,
proc toOrderedTable*[A, B](pairs: openArray[tuple[key: A,
val: B]]): TOrderedTable[A, B] =
## creates a new ordered hash table that contains the given `pairs`.
result = initOrderedTable[A, B](nextPowerOfTwo(pairs.len+10))
@ -398,7 +408,7 @@ iterator mvalues*[A](t: TCountTable[A]): var int =
for h in 0..high(t.data):
if t.data[h].val != 0: yield t.data[h].val
proc RawGet[A](t: TCountTable[A], key: A): int =
proc rawGet[A](t: TCountTable[A], key: A): int =
var h: THash = hash(key) and high(t.data) # start with real hash value
while t.data[h].val != 0:
if t.data[h].key == key: return h
@ -409,13 +419,13 @@ proc `[]`*[A](t: TCountTable[A], key: A): int =
## retrieves the value at ``t[key]``. If `key` is not in `t`,
## 0 is returned. One can check with ``hasKey`` whether the key
## exists.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0: result = t.data[index].val
proc mget*[A](t: var TCountTable[A], key: A): var int =
## retrieves the value at ``t[key]``. The value can be modified.
## If `key` is not in `t`, the ``EInvalidKey`` exception is raised.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0: result = t.data[index].val
else: raise newException(EInvalidKey, "key not found: " & $key)
@ -423,24 +433,24 @@ proc hasKey*[A](t: TCountTable[A], key: A): bool =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
proc RawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]],
proc rawInsert[A](t: TCountTable[A], data: var seq[tuple[key: A, val: int]],
key: A, val: int) =
var h: THash = hash(key) and high(data)
while data[h].val != 0: h = nextTry(h, high(data))
data[h].key = key
data[h].val = val
proc Enlarge[A](t: var TCountTable[A]) =
proc enlarge[A](t: var TCountTable[A]) =
var n: seq[tuple[key: A, val: int]]
newSeq(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
if t.data[i].val != 0: RawInsert(t, n, t.data[i].key, t.data[i].val)
if t.data[i].val != 0: rawInsert(t, n, t.data[i].key, t.data[i].val)
swap(t.data, n)
proc `[]=`*[A](t: var TCountTable[A], key: A, val: int) =
## puts a (key, value)-pair into `t`. `val` has to be positive.
assert val > 0
PutImpl()
putImpl()
proc initCountTable*[A](initialSize=64): TCountTable[A] =
## creates a new count table that is empty.
@ -463,15 +473,15 @@ proc `$`*[A](t: TCountTable[A]): string =
proc inc*[A](t: var TCountTable[A], key: A, val = 1) =
## increments `t[key]` by `val`.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0:
inc(t.data[index].val, val)
else:
if mustRehash(len(t.data), t.counter): Enlarge(t)
RawInsert(t, t.data, key, val)
if mustRehash(len(t.data), t.counter): enlarge(t)
rawInsert(t, t.data, key, val)
inc(t.counter)
proc Smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
proc smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
## returns the largest (key,val)-pair. Efficiency: O(n)
assert t.len > 0
var minIdx = 0
@ -480,7 +490,7 @@ proc Smallest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
result.key = t.data[minIdx].key
result.val = t.data[minIdx].val
proc Largest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
proc largest*[A](t: TCountTable[A]): tuple[key: A, val: int] =
## returns the (key,val)-pair with the largest `val`. Efficiency: O(n)
assert t.len > 0
var maxIdx = 0

View file

@ -14,15 +14,15 @@
type
TLibHandle* = pointer ## a handle to a dynamically loaded library
proc LoadLib*(path: string): TLibHandle
proc loadLib*(path: string): TLibHandle
## loads a library from `path`. Returns nil if the library could not
## be loaded.
proc LoadLib*(): TLibHandle
proc loadLib*(): TLibHandle
## gets the handle from the current executable. Returns nil if the
## library could not be loaded.
proc UnloadLib*(lib: TLibHandle)
proc unloadLib*(lib: TLibHandle)
## unloads the library `lib`
proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} =
@ -60,9 +60,9 @@ when defined(posix):
proc dlsym(lib: TLibHandle, name: cstring): pointer {.
importc, header: "<dlfcn.h>".}
proc LoadLib(path: string): TLibHandle = return dlopen(path, RTLD_NOW)
proc LoadLib(): TLibHandle = return dlopen(nil, RTLD_NOW)
proc UnloadLib(lib: TLibHandle) = dlclose(lib)
proc loadLib(path: string): TLibHandle = return dlopen(path, RTLD_NOW)
proc loadLib(): TLibHandle = return dlopen(nil, RTLD_NOW)
proc unloadLib(lib: TLibHandle) = dlclose(lib)
proc symAddr(lib: TLibHandle, name: cstring): pointer =
return dlsym(lib, name)
@ -78,14 +78,14 @@ elif defined(windows) or defined(dos):
proc FreeLibrary(lib: THINSTANCE) {.importc, header: "<windows.h>", stdcall.}
proc winLoadLibrary(path: cstring): THINSTANCE {.
importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
proc GetProcAddress(lib: THINSTANCE, name: cstring): pointer {.
proc getProcAddress(lib: THINSTANCE, name: cstring): pointer {.
importc: "GetProcAddress", header: "<windows.h>", stdcall.}
proc LoadLib(path: string): TLibHandle =
proc loadLib(path: string): TLibHandle =
result = cast[TLibHandle](winLoadLibrary(path))
proc LoadLib(): TLibHandle =
proc loadLib(): TLibHandle =
result = cast[TLibHandle](winLoadLibrary(nil))
proc UnloadLib(lib: TLibHandle) = FreeLibrary(cast[THINSTANCE](lib))
proc unloadLib(lib: TLibHandle) = FreeLibrary(cast[THINSTANCE](lib))
proc symAddr(lib: TLibHandle, name: cstring): pointer =
result = GetProcAddress(cast[THINSTANCE](lib), name)

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -14,21 +14,21 @@ import os, parseutils, strutils
when not defined(windows):
type
TConverter = object {.pure, final.}
TConverter = object
PConverter* = ptr TConverter ## can convert between two character sets
else:
type
TCodePage = distinct int32
PConverter* = object {.pure.}
PConverter* = object
dest, src: TCodePage
type
EInvalidEncoding* = object of EInvalidValue ## exception that is raised
## for encoding errors
when defined(windows):
proc EqEncodingNames(a, b: string): bool =
proc eqEncodingNames(a, b: string): bool =
var i = 0
var j = 0
while i < a.len and j < b.len:
@ -208,31 +208,31 @@ when defined(windows):
when false:
# not needed yet:
type
TCpInfo = object {.pure.}
MaxCharSize: int32
DefaultChar: array[0..1, char]
LeadByte: array[0..12-1, char]
TCpInfo = object
maxCharSize: int32
defaultChar: array[0..1, char]
leadByte: array[0..12-1, char]
proc GetCPInfo(CodePage: TCodePage, lpCPInfo: var TCpInfo): int32 {.
proc getCPInfo(codePage: TCodePage, lpCPInfo: var TCpInfo): int32 {.
stdcall, importc: "GetCPInfo", dynlib: "kernel32".}
proc nameToCodePage(name: string): TCodePage =
var nameAsInt: int
if parseInt(name, nameAsInt) == 0: nameAsInt = -1
for no, na in items(winEncodings):
if no == nameAsInt or EqEncodingNames(na, name): return TCodePage(no)
if no == nameAsInt or eqEncodingNames(na, name): return TCodePage(no)
result = TCodePage(-1)
proc codePageToName(c: TCodePage): string =
for no, na in items(winEncodings):
if no == int(c):
if no == int(c):
return if na.len != 0: na else: $no
result = ""
proc GetACP(): TCodePage {.stdcall, importc: "GetACP", dynlib: "kernel32".}
proc getACP(): TCodePage {.stdcall, importc: "GetACP", dynlib: "kernel32".}
proc MultiByteToWideChar(
CodePage: TCodePage,
proc multiByteToWideChar(
codePage: TCodePage,
dwFlags: int32,
lpMultiByteStr: cstring,
cbMultiByte: cint,
@ -240,8 +240,8 @@ when defined(windows):
cchWideChar: cint): cint {.
stdcall, importc: "MultiByteToWideChar", dynlib: "kernel32".}
proc WideCharToMultiByte(
CodePage: TCodePage,
proc wideCharToMultiByte(
codePage: TCodePage,
dwFlags: int32,
lpWideCharStr: cstring,
cchWideChar: cint,
@ -321,7 +321,6 @@ proc close*(c: PConverter) =
iconvClose(c)
when defined(windows):
proc convert*(c: PConverter, s: string): string =
## converts `s` to `destEncoding` that was given to the converter `c`. It
## assumed that `s` is in `srcEncoding`.
@ -333,26 +332,26 @@ when defined(windows):
var cap = s.len + s.len shr 2
result = newStringOfCap(cap*2)
# convert to utf-16 LE
var m = MultiByteToWideChar(CodePage = c.src, dwFlags = 0'i32,
var m = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32,
lpMultiByteStr = cstring(s),
cbMultiByte = cint(s.len),
lpWideCharStr = cstring(result),
cchWideChar = cint(cap))
if m == 0:
# try again; ask for capacity:
cap = MultiByteToWideChar(CodePage = c.src, dwFlags = 0'i32,
cap = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32,
lpMultiByteStr = cstring(s),
cbMultiByte = cint(s.len),
lpWideCharStr = nil,
cchWideChar = cint(0))
# and do the conversion properly:
result = newStringOfCap(cap*2)
m = MultiByteToWideChar(CodePage = c.src, dwFlags = 0'i32,
m = multiByteToWideChar(codePage = c.src, dwFlags = 0'i32,
lpMultiByteStr = cstring(s),
cbMultiByte = cint(s.len),
lpWideCharStr = cstring(result),
cchWideChar = cint(cap))
if m == 0: OSError()
if m == 0: osError(osLastError())
setLen(result, m*2)
elif m <= cap:
setLen(result, m*2)
@ -364,8 +363,8 @@ when defined(windows):
# otherwise the fun starts again:
cap = s.len + s.len shr 2
var res = newStringOfCap(cap)
m = WideCharToMultiByte(
CodePage = c.dest,
m = wideCharToMultiByte(
codePage = c.dest,
dwFlags = 0'i32,
lpWideCharStr = cstring(result),
cchWideChar = cint(result.len div 2),
@ -373,8 +372,8 @@ when defined(windows):
cbMultiByte = cap.cint)
if m == 0:
# try again; ask for capacity:
cap = WideCharToMultiByte(
CodePage = c.dest,
cap = wideCharToMultiByte(
codePage = c.dest,
dwFlags = 0'i32,
lpWideCharStr = cstring(result),
cchWideChar = cint(result.len div 2),
@ -382,14 +381,14 @@ when defined(windows):
cbMultiByte = cint(0))
# and do the conversion properly:
res = newStringOfCap(cap)
m = WideCharToMultiByte(
CodePage = c.dest,
m = wideCharToMultiByte(
codePage = c.dest,
dwFlags = 0'i32,
lpWideCharStr = cstring(result),
cchWideChar = cint(result.len div 2),
lpMultiByteStr = cstring(res),
cbMultiByte = cap.cint)
if m == 0: OSError()
if m == 0: osError(osLastError())
setLen(res, m)
result = res
elif m <= cap:
@ -399,15 +398,14 @@ when defined(windows):
assert(false) # cannot happen
else:
proc convert*(c: PConverter, s: string): string =
result = newString(s.len)
var inLen = len(S)
var inLen = len(s)
var outLen = len(result)
var src = cstring(S)
var src = cstring(s)
var dst = cstring(result)
var iconvres: int
while InLen > 0:
while inLen > 0:
iconvres = iconv(c, src, inLen, dst, outLen)
if iconvres == -1:
var lerr = errno
@ -425,11 +423,11 @@ else:
dst = cast[cstring](cast[int](cstring(result)) + offset)
outLen = len(result) - offset
else:
OSError()
osError(lerr.TOSErrorCode)
# iconv has a buffer that needs flushing, specially if the last char is
# not '\0'
discard iconv(c, nil, nil, dst, outlen)
if iconvres == Cint(-1) and errno == E2BIG:
if iconvres == cint(-1) and errno == E2BIG:
var offset = cast[int](dst) - cast[int](cstring(result))
setLen(result, len(result)+inLen*2+5)
# 5 is minimally one utf-8 char
@ -450,7 +448,7 @@ proc convert*(s: string, destEncoding = "UTF-8",
finally:
close(c)
when IsMainModule:
when isMainModule:
let
orig = "öäüß"
cp1252 = convert(orig, "CP1252", "UTF-8")

View file

@ -34,14 +34,26 @@ proc swapEndian32*(outp, inp: pointer) =
o[2] = i[1]
o[3] = i[0]
proc swapEndian16*(outp, inp: pointer) =
## copies `inp` to `outp` swapping bytes. Both buffers are supposed to
## contain at least 2 bytes.
var
i = cast[cstring](inp)
o = cast[cstring](outp)
o[0] = i[1]
o[1] = i[0]
when system.cpuEndian == bigEndian:
proc littleEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp)
proc littleEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp)
proc littleEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp)
proc bigEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8)
proc bigEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4)
proc bigEndian16*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 2)
else:
proc littleEndian64*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 8)
proc littleEndian32*(outp, inp: pointer) {.inline.} = copyMem(outp, inp, 4)
proc littleEndian16*(outp, inp: pointer){.inline.} = copyMem(outp, inp, 2)
proc bigEndian64*(outp, inp: pointer) {.inline.} = swapEndian64(outp, inp)
proc bigEndian32*(outp, inp: pointer) {.inline.} = swapEndian32(outp, inp)
proc bigEndian16*(outp, inp: pointer) {.inline.} = swapEndian16(outp, inp)

View file

@ -64,10 +64,10 @@ const
proc newMonitor*(): PFSMonitor =
## Creates a new file system monitor.
new(result)
result.fd = inotifyInit()
result.targets = initTable[cint, string]()
result.fd = inotifyInit()
if result.fd < 0:
OSError()
OSError(OSLastError())
proc add*(monitor: PFSMonitor, target: string,
filters = {MonitorAll}): cint {.discardable.} =
@ -93,7 +93,7 @@ proc add*(monitor: PFSMonitor, target: string,
result = inotifyAddWatch(monitor.fd, target, INFilter.uint32)
if result < 0:
OSError()
OSError(OSLastError())
monitor.targets.add(result, target)
proc del*(monitor: PFSMonitor, wd: cint) =
@ -101,7 +101,7 @@ proc del*(monitor: PFSMonitor, wd: cint) =
##
## If ``wd`` is not a part of ``monitor`` an EOS error is raised.
if inotifyRmWatch(monitor.fd, wd) < 0:
OSError()
OSError(OSLastError())
proc getEvent(m: PFSMonitor, fd: cint): seq[TMonitorEvent] =
result = @[]
@ -184,7 +184,7 @@ proc FSMonitorRead(h: PObject) =
proc toDelegate(m: PFSMonitor): PDelegate =
result = newDelegate()
result.deleVal = m
result.fd = m.fd
result.fd = (type(result.fd))(m.fd)
result.mode = fmRead
result.handleRead = FSMonitorRead
result.open = true

View file

@ -95,7 +95,7 @@ type
EInvalidReply* = object of ESynch
EFTP* = object of ESynch
proc FTPClient*(address: string, port = TPort(21),
proc ftpClient*(address: string, port = TPort(21),
user, pass = ""): PFTPClient =
## Create a ``PFTPClient`` object.
new(result)
@ -298,7 +298,7 @@ proc getLines(ftp: PFTPClient, async: bool = false): bool =
var readSocks: seq[TSocket] = @[ftp.getCSock()]
# This is only needed here. Asyncio gets this socket...
blockingOperation(ftp.getCSock()):
if readSocks.select(1) != 0 and ftp.getCSock() notin readSocks:
if readSocks.select(1) != 0 and ftp.getCSock() in readSocks:
assertReply ftp.expectReply(), "226"
return true
@ -315,7 +315,7 @@ proc listDirs*(ftp: PFTPClient, dir: string = "",
assertReply ftp.send("NLST " & dir.normalizePathSep), ["125", "150"]
if not async:
while not ftp.job.prc(ftp, false): nil
while not ftp.job.prc(ftp, false): discard
result = splitLines(ftp.job.lines)
ftp.deleteJob()
else: return @[]
@ -390,7 +390,7 @@ proc list*(ftp: PFTPClient, dir: string = "", async = false): string =
assertReply(ftp.send("LIST" & " " & dir.normalizePathSep), ["125", "150"])
if not async:
while not ftp.job.prc(ftp, false): nil
while not ftp.job.prc(ftp, false): discard
result = ftp.job.lines
ftp.deleteJob()
else:
@ -405,7 +405,7 @@ proc retrText*(ftp: PFTPClient, file: string, async = false): string =
assertReply ftp.send("RETR " & file.normalizePathSep), ["125", "150"]
if not async:
while not ftp.job.prc(ftp, false): nil
while not ftp.job.prc(ftp, false): discard
result = ftp.job.lines
ftp.deleteJob()
else:
@ -434,7 +434,7 @@ proc getFile(ftp: PFTPClient, async = false): bool =
if not async:
var readSocks: seq[TSocket] = @[ftp.getCSock()]
blockingOperation(ftp.getCSock()):
if readSocks.select(1) != 0 and ftp.getCSock() notin readSocks:
if readSocks.select(1) != 0 and ftp.getCSock() in readSocks:
assertReply ftp.expectReply(), "226"
return true
@ -460,7 +460,7 @@ proc retrFile*(ftp: PFTPClient, file, dest: string, async = false) =
ftp.job.filename = file.normalizePathSep
if not async:
while not ftp.job.prc(ftp, false): nil
while not ftp.job.prc(ftp, false): discard
ftp.deleteJob()
proc doUpload(ftp: PFTPClient, async = false): bool =
@ -518,7 +518,7 @@ proc store*(ftp: PFTPClient, file, dest: string, async = false) =
assertReply ftp.send("STOR " & dest.normalizePathSep), ["125", "150"]
if not async:
while not ftp.job.prc(ftp, false): nil
while not ftp.job.prc(ftp, false): discard
ftp.deleteJob()
proc close*(ftp: PFTPClient) =
@ -554,10 +554,10 @@ proc csockHandleRead(s: PAsyncSocket, ftp: PAsyncFTPClient) =
ftp.handleEvent(ftp, r)
proc AsyncFTPClient*(address: string, port = TPort(21),
proc asyncFTPClient*(address: string, port = TPort(21),
user, pass = "",
handleEvent: proc (ftp: PAsyncFTPClient, ev: TFTPEvent) {.closure.} =
(proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = nil)): PAsyncFTPClient =
(proc (ftp: PAsyncFTPClient, ev: TFTPEvent) = discard)): PAsyncFTPClient =
## Create a ``PAsyncFTPClient`` object.
##
## Use this if you want to use asyncio's dispatcher.
@ -604,7 +604,7 @@ when isMainModule:
ftp.close()
echo d.len
else: assert(false)
var ftp = AsyncFTPClient("picheta.me", user = "test", pass = "asf", handleEvent = hev)
var ftp = asyncFTPClient("picheta.me", user = "test", pass = "asf", handleEvent = hev)
d.register(ftp)
d.len.echo()
@ -618,7 +618,7 @@ when isMainModule:
when isMainModule and false:
var ftp = FTPClient("picheta.me", user = "asdasd", pass = "asfwq")
var ftp = ftpClient("picheta.me", user = "asdasd", pass = "asfwq")
ftp.connect()
echo ftp.pwd()
echo ftp.list()

View file

@ -32,26 +32,26 @@ proc `!$`*(h: THash): THash {.inline.} =
result = result xor (result shr 11)
result = result +% result shl 15
proc hashData*(Data: Pointer, Size: int): THash =
proc hashData*(data: pointer, size: int): THash =
## hashes an array of bytes of size `size`
var h: THash = 0
when defined(js):
var p: cstring
asm """`p` = `Data`;"""
else:
var p = cast[cstring](Data)
var p = cast[cstring](data)
var i = 0
var s = size
while s > 0:
h = h !& ord(p[i])
Inc(i)
Dec(s)
inc(i)
dec(s)
result = !$h
when defined(js):
var objectID = 0
proc hash*(x: Pointer): THash {.inline.} =
proc hash*(x: pointer): THash {.inline.} =
## efficient hashing of pointers
when defined(js):
asm """
@ -126,6 +126,6 @@ proc hash*(x: float): THash {.inline.} =
var y = x + 1.0
result = cast[ptr THash](addr(y))[]
proc hash*[A](x: openarray[A]): THash =
proc hash*[A](x: openArray[A]): THash =
for it in items(x): result = result !& hash(it)
result = !$result

View file

@ -88,7 +88,7 @@ proc xmlCheckedTag*(e: PNimrodNode, tag: string,
result.add(newStrLitNode("</"))
result.add(newStrLitNode(tag))
result.add(newStrLitNode(">"))
result = NestList(!"&", result)
result = nestList(!"&", result)
macro a*(e: expr): expr {.immediate.} =

View file

@ -17,11 +17,37 @@
##
## echo loadHtml("mydirty.html")
##
##
## Every tag in the resulting tree is in lower case.
##
## **Note:** The resulting ``PXmlNode`` already uses the ``clientData`` field,
## so it cannot be used by clients of this library.
##
## Example: Transforming hyperlinks
## ================================
##
## This code demonstrates how you can iterate over all the tags in an HTML file
## and write back the modified version. In this case we look for hyperlinks
## ending with the extension ``.rst`` and convert them to ``.html``.
##
## .. code-block:: nimrod
##
## import htmlparser
## import xmltree # To use '$' for PXmlNode
## import strtabs # To access PXmlAttributes
## import os # To use splitFile
## import strutils # To use cmpIgnoreCase
##
## proc transformHyperlinks() =
## let html = loadHTML("input.html")
##
## for a in html.findAll("a"):
## let href = a.attrs["href"]
## if not href.isNil:
## let (dir, filename, ext) = splitFile(href)
## if cmpIgnoreCase(ext, ".rst") == 0:
## a.attrs["href"] = dir / filename & ".html"
##
## writeFile("output.html", $html)
import strutils, streams, parsexml, xmltree, unicode, strtabs
@ -454,7 +480,7 @@ proc untilElementEnd(x: var TXmlParser, result: PXmlNode,
if htmlTag(x.elemName) in {tagOption, tagOptgroup}:
errors.add(expected(x, result))
break
else: nil
else: discard
result.addNode(parse(x, errors))
of xmlElementEnd:
if cmpIgnoreCase(x.elemName, result.tag) == 0:
@ -521,14 +547,14 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
var u = entityToUtf8(x.rawData)
if u.len != 0: result = newText(u)
next(x)
of xmlEof: nil
of xmlEof: discard
proc parseHtml*(s: PStream, filename: string,
errors: var seq[string]): PXmlNode =
## parses the XML from stream `s` and returns a ``PXmlNode``. Every
## occured parsing error is added to the `errors` sequence.
var x: TXmlParser
open(x, s, filename, {reportComments})
open(x, s, filename, {reportComments, reportWhitespace})
next(x)
# skip the DOCTYPE:
if x.kind == xmlSpecial: next(x)

View file

@ -220,9 +220,8 @@ proc parseResponse(s: TSocket, getBody: bool, timeout: int): TResponse =
inc(linei, le)
if line[linei] != ':': httpError("invalid headers")
inc(linei) # Skip :
linei += skipWhitespace(line, linei)
result.headers[name] = line[linei.. -1]
result.headers[name] = line[linei.. -1].strip()
if not fullyRead:
httpError("Connection was closed before full request has been made")
if getBody:

View file

@ -401,8 +401,9 @@ proc nextAsync(s: PAsyncHTTPServer) =
var value = ""
i = header.parseUntil(key, ':')
inc(i) # skip :
i += header.skipWhiteSpace(i)
i += header.parseUntil(value, {'\c', '\L'}, i)
if i < header.len:
i += header.skipWhiteSpace(i)
i += header.parseUntil(value, {'\c', '\L'}, i)
s.headers[key] = value
else:
s.client.close()

View file

@ -98,6 +98,7 @@ type
params*: seq[string] ## Parameters of the IRC message
origin*: string ## The channel/user that this msg originated from
raw*: string ## Raw IRC message
timestamp*: TTime ## UNIX epoch time the message was received
proc send*(irc: PIRC, message: string, sendImmediately = false) =
## Sends ``message`` as a raw command. It adds ``\c\L`` for you.
@ -160,9 +161,10 @@ proc isNumber(s: string): bool =
result = i == s.len and s.len > 0
proc parseMessage(msg: string): TIRCEvent =
result.typ = EvMsg
result.cmd = MUnknown
result.raw = msg
result.typ = EvMsg
result.cmd = MUnknown
result.raw = msg
result.timestamp = times.getTime()
var i = 0
# Process the prefix
if msg[i] == ':':
@ -344,7 +346,7 @@ proc poll*(irc: PIRC, ev: var TIRCEvent,
var line = TaintedString""
var socks = @[irc.sock]
var ret = socks.select(timeout)
if socks.len() == 0 and ret != 0:
if socks.len() != 0 and ret != 0:
irc.sock.readLine(line)
ev = irc.processLine(line.string)
result = true
@ -474,12 +476,12 @@ when isMainModule:
var client = irc("amber.tenthbit.net", nick="TestBot1234",
joinChans = @["#flood"])
client.connect()
while True:
while true:
var event: TIRCEvent
if client.poll(event):
case event.typ
of EvConnected:
nil
discard
of EvDisconnected:
break
of EvMsg:

View file

@ -135,7 +135,7 @@ proc str*(my: TJsonParser): string {.inline.} =
assert(my.kind in {jsonInt, jsonFloat, jsonString})
return my.a
proc getInt*(my: TJsonParser): biggestInt {.inline.} =
proc getInt*(my: TJsonParser): BiggestInt {.inline.} =
## returns the number for the event: ``jsonInt``
assert(my.kind == jsonInt)
return parseBiggestInt(my.a)
@ -151,11 +151,11 @@ proc kind*(my: TJsonParser): TJsonEventKind {.inline.} =
proc getColumn*(my: TJsonParser): int {.inline.} =
## get the current column the parser has arrived at.
result = getColNumber(my, my.bufPos)
result = getColNumber(my, my.bufpos)
proc getLine*(my: TJsonParser): int {.inline.} =
## get the current line the parser has arrived at.
result = my.linenumber
result = my.lineNumber
proc getFilename*(my: TJsonParser): string {.inline.} =
## get the filename of the file that the parser processes.
@ -173,7 +173,7 @@ proc errorMsgExpected*(my: TJsonParser, e: string): string =
result = "$1($2, $3) Error: $4" % [
my.filename, $getLine(my), $getColumn(my), e & " expected"]
proc handleHexChar(c: Char, x: var int): bool =
proc handleHexChar(c: char, x: var int): bool =
result = true # Success
case c
of '0'..'9': x = (x shl 4) or (ord(c) - ord('0'))
@ -227,11 +227,11 @@ proc parseString(my: var TJsonParser): TTokKind =
add(my.a, buf[pos])
inc(pos)
of '\c':
pos = lexbase.HandleCR(my, pos)
pos = lexbase.handleCR(my, pos)
buf = my.buf
add(my.a, '\c')
of '\L':
pos = lexbase.HandleLF(my, pos)
pos = lexbase.handleLF(my, pos)
buf = my.buf
add(my.a, '\L')
else:
@ -253,11 +253,11 @@ proc skip(my: var TJsonParser) =
of '\0':
break
of '\c':
pos = lexbase.HandleCR(my, pos)
pos = lexbase.handleCR(my, pos)
buf = my.buf
break
of '\L':
pos = lexbase.HandleLF(my, pos)
pos = lexbase.handleLF(my, pos)
buf = my.buf
break
else:
@ -271,10 +271,10 @@ proc skip(my: var TJsonParser) =
my.err = errEOC_Expected
break
of '\c':
pos = lexbase.HandleCR(my, pos)
pos = lexbase.handleCR(my, pos)
buf = my.buf
of '\L':
pos = lexbase.HandleLF(my, pos)
pos = lexbase.handleLF(my, pos)
buf = my.buf
of '*':
inc(pos)
@ -286,12 +286,12 @@ proc skip(my: var TJsonParser) =
else:
break
of ' ', '\t':
Inc(pos)
inc(pos)
of '\c':
pos = lexbase.HandleCR(my, pos)
pos = lexbase.handleCR(my, pos)
buf = my.buf
of '\L':
pos = lexbase.HandleLF(my, pos)
pos = lexbase.handleLF(my, pos)
buf = my.buf
else:
break
@ -517,7 +517,7 @@ type
of JString:
str*: string
of JInt:
num*: biggestInt
num*: BiggestInt
of JFloat:
fnum*: float
of JBool:
@ -535,30 +535,30 @@ proc raiseParseErr*(p: TJsonParser, msg: string) {.noinline, noreturn.} =
## raises an `EJsonParsingError` exception.
raise newException(EJsonParsingError, errorMsgExpected(p, msg))
proc newJString*(s: String): PJsonNode =
proc newJString*(s: string): PJsonNode =
## Creates a new `JString PJsonNode`.
new(result)
result.kind = JString
result.str = s
proc newJStringMove(s: String): PJsonNode =
proc newJStringMove(s: string): PJsonNode =
new(result)
result.kind = JString
shallowCopy(result.str, s)
proc newJInt*(n: biggestInt): PJsonNode =
proc newJInt*(n: BiggestInt): PJsonNode =
## Creates a new `JInt PJsonNode`.
new(result)
result.kind = JInt
result.num = n
proc newJFloat*(n: Float): PJsonNode =
proc newJFloat*(n: float): PJsonNode =
## Creates a new `JFloat PJsonNode`.
new(result)
result.kind = JFloat
result.fnum = n
proc newJBool*(b: Bool): PJsonNode =
proc newJBool*(b: bool): PJsonNode =
## Creates a new `JBool PJsonNode`.
new(result)
result.kind = JBool
@ -587,7 +587,7 @@ proc `%`*(s: string): PJsonNode =
result.kind = JString
result.str = s
proc `%`*(n: biggestInt): PJsonNode =
proc `%`*(n: BiggestInt): PJsonNode =
## Generic constructor for JSON data. Creates a new `JInt PJsonNode`.
new(result)
result.kind = JInt
@ -612,7 +612,7 @@ proc `%`*(keyVals: openArray[tuple[key: string, val: PJsonNode]]): PJsonNode =
newSeq(result.fields, keyVals.len)
for i, p in pairs(keyVals): result.fields[i] = p
proc `%`*(elements: openArray[PJSonNode]): PJsonNode =
proc `%`*(elements: openArray[PJsonNode]): PJsonNode =
## Generic constructor for JSON data. Creates a new `JArray PJsonNode`
new(result)
result.kind = JArray
@ -626,9 +626,9 @@ proc len*(n: PJsonNode): int =
case n.kind
of JArray: result = n.elems.len
of JObject: result = n.fields.len
else: nil
else: discard
proc `[]`*(node: PJsonNode, name: String): PJsonNode =
proc `[]`*(node: PJsonNode, name: string): PJsonNode =
## Gets a field from a `JObject`. Returns nil if the key is not found.
assert(node.kind == JObject)
for key, item in items(node.fields):
@ -636,17 +636,18 @@ proc `[]`*(node: PJsonNode, name: String): PJsonNode =
return item
return nil
proc `[]`*(node: PJsonNode, index: Int): PJsonNode =
proc `[]`*(node: PJsonNode, index: int): PJsonNode =
## Gets the node at `index` in an Array.
assert(node.kind == JArray)
return node.elems[index]
proc hasKey*(node: PJsonNode, key: String): Bool =
proc hasKey*(node: PJsonNode, key: string): bool =
## Checks if `key` exists in `node`.
assert(node.kind == JObject)
for k, item in items(node.fields):
if k == key: return True
proc existsKey*(node: PJsonNode, key: String): Bool {.deprecated.} = node.hasKey(key)
if k == key: return true
proc existsKey*(node: PJsonNode, key: string): bool {.deprecated.} = node.hasKey(key)
## Deprecated for `hasKey`
proc add*(father, child: PJsonNode) =
@ -661,7 +662,7 @@ proc add*(obj: PJsonNode, key: string, val: PJsonNode) =
assert obj.kind == JObject
obj.fields.add((key, val))
proc `[]=`*(obj: PJsonNode, key: String, val: PJsonNode) =
proc `[]=`*(obj: PJsonNode, key: string, val: PJsonNode) =
## Sets a field from a `JObject`. Performs a check for duplicate keys.
assert(obj.kind == JObject)
for i in 0..obj.fields.len-1:
@ -706,7 +707,7 @@ proc copy*(p: PJsonNode): PJsonNode =
proc indent(s: var string, i: int) =
s.add(repeatChar(i))
proc newIndent(curr, indent: int, ml: bool): Int =
proc newIndent(curr, indent: int, ml: bool): int =
if ml: return curr + indent
else: return indent
@ -730,8 +731,8 @@ proc escapeJson*(s: string): string =
result.add(toHex(r, 4))
result.add("\"")
proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = True,
lstArr = False, currIndent = 0) =
proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = true,
lstArr = false, currIndent = 0) =
case node.kind
of JObject:
if currIndent != 0 and not lstArr: result.nl(ml)
@ -747,7 +748,7 @@ proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = True,
result.indent(newIndent(currIndent, indent, ml))
result.add(escapeJson(node.fields[i].key))
result.add(": ")
toPretty(result, node.fields[i].val, indent, ml, False,
toPretty(result, node.fields[i].val, indent, ml, false,
newIndent(currIndent, indent, ml))
result.nl(ml)
result.indent(currIndent) # indent the same as {
@ -776,7 +777,7 @@ proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = True,
result.add(", ")
result.nl(ml) # New Line
toPretty(result, node.elems[i], indent, ml,
True, newIndent(currIndent, indent, ml))
true, newIndent(currIndent, indent, ml))
result.nl(ml)
result.indent(currIndent)
result.add("]")
@ -785,18 +786,18 @@ proc toPretty(result: var string, node: PJsonNode, indent = 2, ml = True,
if lstArr: result.indent(currIndent)
result.add("null")
proc pretty*(node: PJsonNode, indent = 2): String =
proc pretty*(node: PJsonNode, indent = 2): string =
## Converts `node` to its JSON Representation, with indentation and
## on multiple lines.
result = ""
toPretty(result, node, indent)
proc `$`*(node: PJsonNode): String =
proc `$`*(node: PJsonNode): string =
## Converts `node` to its JSON Representation on one line.
result = ""
toPretty(result, node, 1, False)
toPretty(result, node, 1, false)
iterator items*(node: PJsonNode): PJSonNode =
iterator items*(node: PJsonNode): PJsonNode =
## Iterator for the items of `node`. `node` has to be a JArray.
assert node.kind == JArray
for i in items(node.elems):

View file

@ -31,7 +31,7 @@ type
buf*: cstring ## the buffer itself
bufLen*: int ## length of buffer in characters
input: PStream ## the input stream
LineNumber*: int ## the current line number
lineNumber*: int ## the current line number
sentinel: int
lineStart: int # index of last line start in buffer
fileOpened: bool
@ -48,11 +48,11 @@ proc getCurrentLine*(L: TBaseLexer, marker: bool = true): string
proc getColNumber*(L: TBaseLexer, pos: int): int
## retrieves the current column.
proc HandleCR*(L: var TBaseLexer, pos: int): int
proc handleCR*(L: var TBaseLexer, pos: int): int
## Call this if you scanned over '\c' in the buffer; it returns the the
## position to continue the scanning from. `pos` must be the position
## of the '\c'.
proc HandleLF*(L: var TBaseLexer, pos: int): int
proc handleLF*(L: var TBaseLexer, pos: int): int
## Call this if you scanned over '\L' in the buffer; it returns the the
## position to continue the scanning from. `pos` must be the position
## of the '\L'.
@ -66,7 +66,7 @@ proc close(L: var TBaseLexer) =
dealloc(L.buf)
close(L.input)
proc FillBuffer(L: var TBaseLexer) =
proc fillBuffer(L: var TBaseLexer) =
var
charsRead, toCopy, s: int # all are in characters,
# not bytes (in case this
@ -75,10 +75,10 @@ proc FillBuffer(L: var TBaseLexer) =
# we know here that pos == L.sentinel, but not if this proc
# is called the first time by initBaseLexer()
assert(L.sentinel < L.bufLen)
toCopy = L.BufLen - L.sentinel - 1
toCopy = L.bufLen - L.sentinel - 1
assert(toCopy >= 0)
if toCopy > 0:
MoveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
moveMem(L.buf, addr(L.buf[L.sentinel + 1]), toCopy * chrSize)
# "moveMem" handles overlapping regions
charsRead = readData(L.input, addr(L.buf[toCopy]),
(L.sentinel + 1) * chrSize) div chrSize
@ -91,7 +91,7 @@ proc FillBuffer(L: var TBaseLexer) =
dec(s) # BUGFIX (valgrind)
while true:
assert(s < L.bufLen)
while (s >= 0) and not (L.buf[s] in NewLines): Dec(s)
while (s >= 0) and not (L.buf[s] in NewLines): dec(s)
if s >= 0:
# we found an appropriate character for a sentinel:
L.sentinel = s
@ -99,11 +99,11 @@ proc FillBuffer(L: var TBaseLexer) =
else:
# rather than to give up here because the line is too long,
# double the buffer's size and try again:
oldBufLen = L.BufLen
L.bufLen = L.BufLen * 2
oldBufLen = L.bufLen
L.bufLen = L.bufLen * 2
L.buf = cast[cstring](realloc(L.buf, L.bufLen * chrSize))
assert(L.bufLen - oldBuflen == oldBufLen)
charsRead = ReadData(L.input, addr(L.buf[oldBufLen]),
assert(L.bufLen - oldBufLen == oldBufLen)
charsRead = readData(L.input, addr(L.buf[oldBufLen]),
oldBufLen * chrSize) div chrSize
if charsRead < oldBufLen:
L.buf[oldBufLen + charsRead] = EndOfFile
@ -121,19 +121,19 @@ proc fillBaseLexer(L: var TBaseLexer, pos: int): int =
result = 0
L.lineStart = result
proc HandleCR(L: var TBaseLexer, pos: int): int =
proc handleCR(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == '\c')
inc(L.linenumber)
inc(L.lineNumber)
result = fillBaseLexer(L, pos)
if L.buf[result] == '\L':
result = fillBaseLexer(L, result)
proc HandleLF(L: var TBaseLexer, pos: int): int =
proc handleLF(L: var TBaseLexer, pos: int): int =
assert(L.buf[pos] == '\L')
inc(L.linenumber)
inc(L.lineNumber)
result = fillBaseLexer(L, pos) #L.lastNL := result-1; // BUGFIX: was: result;
proc skip_UTF_8_BOM(L: var TBaseLexer) =
proc skipUtf8Bom(L: var TBaseLexer) =
if (L.buf[0] == '\xEF') and (L.buf[1] == '\xBB') and (L.buf[2] == '\xBF'):
inc(L.bufpos, 3)
inc(L.lineStart, 3)
@ -147,9 +147,9 @@ proc open(L: var TBaseLexer, input: PStream, bufLen: int = 8192) =
L.buf = cast[cstring](alloc(bufLen * chrSize))
L.sentinel = bufLen - 1
L.lineStart = 0
L.linenumber = 1 # lines start at 1
L.lineNumber = 1 # lines start at 1
fillBuffer(L)
skip_UTF_8_BOM(L)
skipUtf8Bom(L)
proc getColNumber(L: TBaseLexer, pos: int): int =
result = abs(pos - L.lineStart)
@ -163,5 +163,5 @@ proc getCurrentLine(L: TBaseLexer, marker: bool = true): string =
inc(i)
add(result, "\n")
if marker:
add(result, RepeatChar(getColNumber(L, L.bufpos)) & "^\n")
add(result, repeatChar(getColNumber(L, L.bufpos)) & "^\n")

267
lib/pure/logging.nim Normal file
View file

@ -0,0 +1,267 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2014 Andreas Rumpf, Dominik Picheta
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements a simple logger. It has been designed to be as simple
## as possible to avoid bloat, if this library does not fullfill your needs,
## write your own.
##
## Format strings support the following variables which must be prefixed with
## the dollar operator (``$``):
##
## ============ =======================
## Operator Output
## ============ =======================
## $date Current date
## $time Current time
## $app ``os.getAppFilename()``
## ============ =======================
##
##
## The following example demonstrates logging to three different handlers
## simultaneously:
##
## .. code-block:: nimrod
##
## var L = newConsoleLogger()
## var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
## var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
## handlers.add(L)
## handlers.add(fL)
## handlers.add(rL)
## info("920410:52 accepted")
## warn("4 8 15 16 23 4-- Error")
## error("922044:16 SYSTEM FAILURE")
## fatal("SYSTEM FAILURE SYSTEM FAILURE")
import strutils, os, times
type
TLevel* = enum ## logging level
lvlAll, ## all levels active
lvlDebug, ## debug level (and any above) active
lvlInfo, ## info level (and any above) active
lvlWarn, ## warn level (and any above) active
lvlError, ## error level (and any above) active
lvlFatal, ## fatal level (and any above) active
lvlNone ## no levels active
const
LevelNames*: array [TLevel, string] = [
"DEBUG", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "NONE"
]
defaultFmtStr* = "" ## default string between log level and message per logger
verboseFmtStr* = "$date $time "
type
PLogger* = ref object of PObject ## abstract logger; the base type of all loggers
levelThreshold*: TLevel ## only messages of level >= levelThreshold
## should be processed
fmtStr: string ## = defaultFmtStr by default, see substituteLog for $date etc.
PConsoleLogger* = ref object of PLogger ## logger that writes the messages to the
## console
PFileLogger* = ref object of PLogger ## logger that writes the messages to a file
f: TFile
PRollingFileLogger* = ref object of PFileLogger ## logger that writes the
## messages to a file and
## performs log rotation
maxLines: int # maximum number of lines
curLine : int
baseName: string # initial filename
baseMode: TFileMode # initial file mode
logFiles: int # how many log files already created, e.g. basename.1, basename.2...
proc substituteLog(frmt: string): string =
## converts $date to the current date
## converts $time to the current time
## converts $app to getAppFilename()
## converts
result = newStringOfCap(frmt.len + 20)
var i = 0
while i < frmt.len:
if frmt[i] != '$':
result.add(frmt[i])
inc(i)
else:
inc(i)
var v = ""
var app = getAppFilename()
while frmt[i] in IdentChars:
v.add(toLower(frmt[i]))
inc(i)
case v
of "date": result.add(getDateStr())
of "time": result.add(getClockStr())
of "app": result.add(app)
of "appdir": result.add(app.splitFile.dir)
of "appname": result.add(app.splitFile.name)
method log*(logger: PLogger, level: TLevel,
frmt: string, args: varargs[string, `$`]) {.raises: [EBase], tags: [FTime, FWriteIO, FReadIO].} =
## Override this method in custom loggers. Default implementation does
## nothing.
discard
method log*(logger: PConsoleLogger, level: TLevel,
frmt: string, args: varargs[string, `$`]) =
## Logs to the console using ``logger`` only.
if level >= logger.levelThreshold:
writeln(stdout, LevelNames[level], " ", substituteLog(logger.fmtStr),
frmt % args)
method log*(logger: PFileLogger, level: TLevel,
frmt: string, args: varargs[string, `$`]) =
## Logs to a file using ``logger`` only.
if level >= logger.levelThreshold:
writeln(logger.f, LevelNames[level], " ",
substituteLog(logger.fmtStr), frmt % args)
proc defaultFilename*(): string =
## Returns the default filename for a logger.
var (path, name, ext) = splitFile(getAppFilename())
result = changeFileExt(path / name, "log")
proc newConsoleLogger*(levelThreshold = lvlAll, fmtStr = defaultFmtStr): PConsoleLogger =
## Creates a new console logger. This logger logs to the console.
new result
result.fmtStr = fmtStr
result.levelThreshold = levelThreshold
proc newFileLogger*(filename = defaultFilename(),
mode: TFileMode = fmAppend,
levelThreshold = lvlAll,
fmtStr = defaultFmtStr): PFileLogger =
## Creates a new file logger. This logger logs to a file.
new(result)
result.levelThreshold = levelThreshold
result.f = open(filename, mode)
result.fmtStr = fmtStr
# ------
proc countLogLines(logger: PRollingFileLogger): int =
result = 0
for line in logger.f.lines():
result.inc()
proc countFiles(filename: string): int =
# Example: file.log.1
result = 0
let (dir, name, ext) = splitFile(filename)
for kind, path in walkDir(dir):
if kind == pcFile:
let llfn = name & ext & ExtSep
if path.extractFilename.startsWith(llfn):
let numS = path.extractFilename[llfn.len .. -1]
try:
let num = parseInt(numS)
if num > result:
result = num
except EInvalidValue: discard
proc newRollingFileLogger*(filename = defaultFilename(),
mode: TFileMode = fmReadWrite,
levelThreshold = lvlAll,
fmtStr = defaultFmtStr,
maxLines = 1000): PRollingFileLogger =
## Creates a new rolling file logger. Once a file reaches ``maxLines`` lines
## a new log file will be started and the old will be renamed.
new(result)
result.levelThreshold = levelThreshold
result.fmtStr = defaultFmtStr
result.maxLines = maxLines
result.f = open(filename, mode)
result.curLine = 0
result.baseName = filename
result.baseMode = mode
result.logFiles = countFiles(filename)
if mode == fmAppend:
# We need to get a line count because we will be appending to the file.
result.curLine = countLogLines(result)
proc rotate(logger: PRollingFileLogger) =
let (dir, name, ext) = splitFile(logger.baseName)
for i in countdown(logger.logFiles, 0):
let srcSuff = if i != 0: ExtSep & $i else: ""
moveFile(dir / (name & ext & srcSuff),
dir / (name & ext & ExtSep & $(i+1)))
method log*(logger: PRollingFileLogger, level: TLevel,
frmt: string, args: varargs[string, `$`]) =
## Logs to a file using rolling ``logger`` only.
if level >= logger.levelThreshold:
if logger.curLine >= logger.maxLines:
logger.f.close()
rotate(logger)
logger.logFiles.inc
logger.curLine = 0
logger.f = open(logger.baseName, logger.baseMode)
writeln(logger.f, LevelNames[level], " ", frmt % args)
logger.curLine.inc
# --------
var
level* = lvlAll ## global log filter
handlers*: seq[PLogger] = @[] ## handlers with their own log levels
proc logLoop(level: TLevel, frmt: string, args: varargs[string, `$`]) =
for logger in items(handlers):
if level >= logger.levelThreshold:
log(logger, level, frmt, args)
template log*(level: TLevel, frmt: string, args: varargs[string, `$`]) =
## Logs a message to all registered handlers at the given level.
bind logLoop
bind `%`
bind logging.Level
if level >= logging.Level:
logLoop(level, frmt, args)
template debug*(frmt: string, args: varargs[string, `$`]) =
## Logs a debug message to all registered handlers.
log(lvlDebug, frmt, args)
template info*(frmt: string, args: varargs[string, `$`]) =
## Logs an info message to all registered handlers.
log(lvlInfo, frmt, args)
template warn*(frmt: string, args: varargs[string, `$`]) =
## Logs a warning message to all registered handlers.
log(lvlWarn, frmt, args)
template error*(frmt: string, args: varargs[string, `$`]) =
## Logs an error message to all registered handlers.
log(lvlError, frmt, args)
template fatal*(frmt: string, args: varargs[string, `$`]) =
## Logs a fatal error message to all registered handlers.
log(lvlFatal, frmt, args)
# --------------
when isMainModule:
var L = newConsoleLogger()
var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
handlers.add(L)
handlers.add(fL)
handlers.add(rL)
for i in 0 .. 25:
info("hello" & $i, [])

View file

@ -54,7 +54,7 @@ proc parseInt*(s: string, value: var int, validRange: TSlice[int]) {.
try:
discard parseutils.parseInt(s, x, 0)
except EOverflow:
nil
discard
if x in validRange: value = x
when isMainModule:

View file

@ -94,7 +94,7 @@ proc nextPowerOfTwo*(x: int): int =
result = result or (result shr 4)
result = result or (result shr 2)
result = result or (result shr 1)
Inc(result)
inc(result)
proc countBits32*(n: int32): int {.noSideEffect.} =
## counts the set bits in `n`.
@ -103,17 +103,17 @@ proc countBits32*(n: int32): int {.noSideEffect.} =
v = (v and 0x33333333'i32) +% ((v shr 2'i32) and 0x33333333'i32)
result = ((v +% (v shr 4'i32) and 0xF0F0F0F'i32) *% 0x1010101'i32) shr 24'i32
proc sum*[T](x: openarray[T]): T {.noSideEffect.} =
proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
## computes the sum of the elements in `x`.
## If `x` is empty, 0 is returned.
for i in items(x): result = result + i
proc mean*(x: openarray[float]): float {.noSideEffect.} =
proc mean*(x: openArray[float]): float {.noSideEffect.} =
## computes the mean of the elements in `x`.
## If `x` is empty, NaN is returned.
result = sum(x) / toFloat(len(x))
proc variance*(x: openarray[float]): float {.noSideEffect.} =
proc variance*(x: openArray[float]): float {.noSideEffect.} =
## computes the variance of the elements in `x`.
## If `x` is empty, NaN is returned.
result = 0.0

View file

@ -16,9 +16,9 @@ type
MD5Digest* = array[0..15, int8]
MD5Buffer = array[0..63, int8]
MD5Context* {.final.} = object
State: MD5State
Count: array[0..1, int32]
Buffer: MD5Buffer
state: MD5State
count: array[0..1, int32]
buffer: MD5Buffer
const
padding: cstring = "\x80\0\0\0" &
@ -32,16 +32,16 @@ const
"\0\0\0\0"
proc F(x, y, z: int32): int32 {.inline.} =
Result = (x and y) or ((not x) and z)
result = (x and y) or ((not x) and z)
proc G(x, y, z: int32): int32 {.inline.} =
Result = (x and z) or (y and (not z))
result = (x and z) or (y and (not z))
proc H(x, y, z: int32): int32 {.inline.} =
Result = x xor y xor z
result = x xor y xor z
proc I(x, y, z: int32): int32 {.inline.} =
Result = y xor (x or (not z))
result = y xor (x or (not z))
proc rot(x: var int32, n: int8) {.inline.} =
x = toU32(x shl ze(n)) or (x shr toU32(32 -% ze(n)))
@ -75,7 +75,7 @@ proc encode(dest: var MD5Block, src: cstring) =
ord(src[j+3]) shl 24)
inc(j, 4)
proc decode(dest: var openarray[int8], src: openarray[int32]) =
proc decode(dest: var openArray[int8], src: openArray[int32]) =
var i = 0
for j in 0..high(src):
dest[i] = toU8(src[j] and 0xff'i32)
@ -87,7 +87,7 @@ proc decode(dest: var openarray[int8], src: openarray[int32]) =
proc transform(Buffer: pointer, State: var MD5State) =
var
myBlock: MD5Block
encode(myBlock, cast[cstring](buffer))
encode(myBlock, cast[cstring](Buffer))
var a = State[0]
var b = State[1]
var c = State[2]
@ -161,7 +161,7 @@ proc transform(Buffer: pointer, State: var MD5State) =
State[2] = State[2] +% c
State[3] = State[3] +% d
proc MD5Init*(c: var MD5Context) =
proc md5Init*(c: var MD5Context) =
## initializes a MD5Context
c.State[0] = 0x67452301'i32
c.State[1] = 0xEFCDAB89'i32
@ -169,64 +169,64 @@ proc MD5Init*(c: var MD5Context) =
c.State[3] = 0x10325476'i32
c.Count[0] = 0'i32
c.Count[1] = 0'i32
ZeroMem(addr(c.Buffer), SizeOf(MD5Buffer))
zeroMem(addr(c.Buffer), sizeof(MD5Buffer))
proc MD5Update*(c: var MD5Context, input: cstring, len: int) =
proc md5Update*(c: var MD5Context, input: cstring, len: int) =
## updates the MD5Context with the `input` data of length `len`
var input = input
var Index = (c.Count[0] shr 3) and 0x3F
var Index = (c.count[0] shr 3) and 0x3F
c.Count[0] = c.count[0] +% toU32(len shl 3)
if c.Count[0] < (len shl 3): c.Count[1] = c.count[1] +% 1'i32
c.Count[1] = c.count[1] +% toU32(len shr 29)
var PartLen = 64 - Index
if len >= PartLen:
CopyMem(addr(c.Buffer[Index]), Input, PartLen)
copyMem(addr(c.Buffer[Index]), input, PartLen)
transform(addr(c.Buffer), c.State)
var i = PartLen
while i + 63 < len:
Transform(addr(Input[I]), c.State)
transform(addr(input[i]), c.State)
inc(i, 64)
CopyMem(addr(c.Buffer[0]), addr(Input[i]), len-i)
copyMem(addr(c.Buffer[0]), addr(input[i]), len-i)
else:
CopyMem(addr(c.Buffer[Index]), addr(Input[0]), len)
copyMem(addr(c.Buffer[Index]), addr(input[0]), len)
proc MD5Final*(c: var MD5Context, digest: var MD5Digest) =
proc md5Final*(c: var MD5Context, digest: var MD5Digest) =
## finishes the MD5Context and stores the result in `digest`
var
Bits: MD5CBits
PadLen: int
decode(bits, c.Count)
decode(Bits, c.Count)
var Index = (c.Count[0] shr 3) and 0x3F
if Index < 56: PadLen = 56 - Index
else: PadLen = 120 - Index
MD5Update(c, padding, PadLen)
MD5Update(c, cast[cstring](addr(Bits)), 8)
md5Update(c, padding, PadLen)
md5Update(c, cast[cstring](addr(Bits)), 8)
decode(digest, c.State)
ZeroMem(addr(c), SizeOf(MD5Context))
zeroMem(addr(c), sizeof(MD5Context))
proc toMD5*(s: string): MD5Digest =
## computes the MD5Digest value for a string `s`
var c: MD5Context
MD5Init(c)
MD5Update(c, cstring(s), len(s))
MD5Final(c, result)
md5Init(c)
md5Update(c, cstring(s), len(s))
md5Final(c, result)
proc `$`*(D: MD5Digest): string =
## converts a MD5Digest value into its string representation
const digits = "0123456789abcdef"
result = ""
for i in 0..15:
add(result, Digits[(D[I] shr 4) and 0xF])
add(result, Digits[D[I] and 0xF])
add(result, Digits[(D[i] shr 4) and 0xF])
add(result, Digits[D[i] and 0xF])
proc getMD5*(s: string): string =
## computes an MD5 value of `s` and returns its string representation
var
c: MD5Context
d: MD5Digest
MD5Init(c)
MD5Update(c, cstring(s), len(s))
MD5Final(c, d)
md5Init(c)
md5Update(c, cstring(s), len(s))
md5Final(c, d)
result = $d
proc `==`*(D1, D2: MD5Digest): bool =

View file

@ -52,9 +52,9 @@ proc open*(filename: string, mode: TFileMode = fmRead,
when defined(windows):
template fail(errCode: TOSErrorCode, msg: expr) =
rollback()
if result.fHandle != 0: discard CloseHandle(result.fHandle)
if result.mapHandle != 0: discard CloseHandle(result.mapHandle)
OSError(errCode)
if result.fHandle != 0: discard closeHandle(result.fHandle)
if result.mapHandle != 0: discard closeHandle(result.mapHandle)
osError(errCode)
# return false
#raise newException(EIO, msg)
@ -69,36 +69,36 @@ proc open*(filename: string, mode: TFileMode = fmRead,
0)
when useWinUnicode:
result.fHandle = callCreateFile(CreateFileW, newWideCString(filename))
result.fHandle = callCreateFile(createFileW, newWideCString(filename))
else:
result.fHandle = callCreateFile(CreateFileA, filename)
if result.fHandle == INVALID_HANDLE_VALUE:
fail(OSLastError(), "error opening file")
fail(osLastError(), "error opening file")
if newFileSize != -1:
var
sizeHigh = int32(newFileSize shr 32)
sizeLow = int32(newFileSize and 0xffffffff)
var status = SetFilePointer(result.fHandle, sizeLow, addr(sizeHigh),
var status = setFilePointer(result.fHandle, sizeLow, addr(sizeHigh),
FILE_BEGIN)
let lastErr = OSLastError()
let lastErr = osLastError()
if (status == INVALID_SET_FILE_POINTER and lastErr.int32 != NO_ERROR) or
(SetEndOfFile(result.fHandle) == 0):
(setEndOfFile(result.fHandle) == 0):
fail(lastErr, "error setting file size")
# since the strings are always 'nil', we simply always call
# CreateFileMappingW which should be slightly faster anyway:
result.mapHandle = CreateFileMappingW(
result.mapHandle = createFileMappingW(
result.fHandle, nil,
if readonly: PAGE_READONLY else: PAGE_READWRITE,
0, 0, nil)
if result.mapHandle == 0:
fail(OSLastError(), "error creating mapping")
fail(osLastError(), "error creating mapping")
result.mem = MapViewOfFileEx(
result.mem = mapViewOfFileEx(
result.mapHandle,
if readonly: FILE_MAP_READ else: FILE_MAP_WRITE,
int32(offset shr 32),
@ -107,12 +107,12 @@ proc open*(filename: string, mode: TFileMode = fmRead,
nil)
if result.mem == nil:
fail(OSLastError(), "error mapping view")
fail(osLastError(), "error mapping view")
var hi, low: int32
low = GetFileSize(result.fHandle, addr(hi))
low = getFileSize(result.fHandle, addr(hi))
if low == INVALID_FILE_SIZE:
fail(OSLastError(), "error getting file size")
fail(osLastError(), "error getting file size")
else:
var fileSize = (int64(hi) shr 32) or low
if mappedSize != -1: result.size = min(fileSize, mappedSize).int
@ -122,7 +122,7 @@ proc open*(filename: string, mode: TFileMode = fmRead,
template fail(errCode: TOSErrorCode, msg: expr) =
rollback()
if result.handle != 0: discard close(result.handle)
OSError(errCode)
osError(errCode)
var flags = if readonly: O_RDONLY else: O_RDWR
@ -133,22 +133,22 @@ proc open*(filename: string, mode: TFileMode = fmRead,
if result.handle == -1:
# XXX: errno is supposed to be set here
# Is there an exception that wraps it?
fail(OSLastError(), "error opening file")
fail(osLastError(), "error opening file")
if newFileSize != -1:
if ftruncate(result.handle, newFileSize) == -1:
fail(OSLastError(), "error setting file size")
fail(osLastError(), "error setting file size")
if mappedSize != -1:
result.size = mappedSize
else:
var stat: Tstat
var stat: TStat
if fstat(result.handle, stat) != -1:
# XXX: Hmm, this could be unsafe
# Why is mmap taking int anyway?
result.size = int(stat.st_size)
else:
fail(OSLastError(), "error getting file size")
fail(osLastError(), "error getting file size")
result.mem = mmap(
nil,
@ -159,7 +159,7 @@ proc open*(filename: string, mode: TFileMode = fmRead,
offset)
if result.mem == cast[pointer](MAP_FAILED):
fail(OSLastError(), "file mapping failed")
fail(osLastError(), "file mapping failed")
proc close*(f: var TMemFile) =
## closes the memory mapped file `f`. All changes are written back to the
@ -170,13 +170,13 @@ proc close*(f: var TMemFile) =
when defined(windows):
if f.fHandle != INVALID_HANDLE_VALUE:
lastErr = OSLastError()
error = UnmapViewOfFile(f.mem) == 0
error = (CloseHandle(f.mapHandle) == 0) or error
error = (CloseHandle(f.fHandle) == 0) or error
lastErr = osLastError()
error = unmapViewOfFile(f.mem) == 0
error = (closeHandle(f.mapHandle) == 0) or error
error = (closeHandle(f.fHandle) == 0) or error
else:
if f.handle != 0:
lastErr = OSLastError()
lastErr = osLastError()
error = munmap(f.mem, f.size) != 0
error = (close(f.handle) != 0) or error
@ -189,5 +189,5 @@ proc close*(f: var TMemFile) =
else:
f.handle = 0
if error: OSError(lastErr)
if error: osError(lastErr)

39
lib/pure/mersenne.nim Normal file
View file

@ -0,0 +1,39 @@
import unsigned
type
TMersenneTwister* = object
mt: array[0..623, uint32]
index: int
proc newMersenneTwister*(seed: int): TMersenneTwister =
result.index = 0
result.mt[0]= uint32(seed)
for i in 1..623'u32:
result.mt[i]= (0x6c078965'u32 * (result.mt[i-1] xor (result.mt[i-1] shr 30'u32)) + i)
proc generateNumbers(m: var TMersenneTwister) =
for i in 0..623:
var y = (m.mt[i] and 0x80000000'u32) + (m.mt[(i+1) mod 624] and 0x7fffffff'u32)
m.mt[i] = m.mt[(i+397) mod 624] xor uint32(y shr 1'u32)
if (y mod 2'u32) != 0:
m.mt[i] = m.mt[i] xor 0x9908b0df'u32
proc getNum*(m: var TMersenneTwister): int =
if m.index == 0:
generateNumbers(m)
var y = m.mt[m.index]
y = y xor (y shr 11'u32)
y = y xor ((7'u32 shl y) and 0x9d2c5680'u32)
y = y xor ((15'u32 shl y) and 0xefc60000'u32)
y = y xor (y shr 18'u32)
m.index = (m.index+1) mod 624
return int(y)
# Test
when isMainModule:
var mt = newMersenneTwister(2525)
for i in 0..99:
echo mt.getNum

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
# (c) Copyright 2013 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -28,7 +28,7 @@ proc hexbyte*(hex: char): int =
of '0'..'9': result = (ord(hex) - ord('0'))
of 'a'..'f': result = (ord(hex) - ord('a') + 10)
of 'A'..'F': result = (ord(hex) - ord('A') + 10)
else: nil
else: discard
proc parseOid*(str: cstring): TOid =
## parses an OID.
@ -52,6 +52,10 @@ proc oidToString*(oid: TOid, str: cstring) =
inc(i)
str[24] = '\0'
proc `$`*(oid: TOid): string =
result = newString(25)
oidToString(oid, result)
var
incr: int
fuzz: int32

File diff suppressed because it is too large Load diff

View file

@ -13,7 +13,7 @@
include "system/inclrtl"
import
strutils, os, strtabs, streams
strutils, os, strtabs, streams, sequtils
when defined(windows):
import winlean
@ -23,7 +23,7 @@ else:
type
TProcess = object of TObject
when defined(windows):
FProcessHandle: Thandle
fProcessHandle: THandle
inHandle, outHandle, errHandle: TFileHandle
id: THandle
else:
@ -36,18 +36,81 @@ type
TProcessOption* = enum ## options that can be passed `startProcess`
poEchoCmd, ## echo the command before execution
poUseShell, ## use the shell to execute the command; NOTE: This
## often creates a security hole!
poUsePath, ## Asks system to search for executable using PATH environment
## variable.
## On Windows, this is the default.
poEvalCommand, ## Pass `command` directly to the shell, without quoting.
## Use it only if `command` comes from trused source.
poStdErrToStdOut, ## merge stdout and stderr to the stdout stream
poParentStreams ## use the parent's streams
template poUseShell*: TProcessOption {.deprecated.} = poUsePath
## Deprecated alias for poUsePath.
proc quoteShellWindows*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
## Quote s, so it can be safely passed to Windows API.
## Based on Python's subprocess.list2cmdline
## See http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
let needQuote = {' ', '\t'} in s or s.len == 0
result = ""
var backslashBuff = ""
if needQuote:
result.add("\"")
for c in s:
if c == '\\':
backslashBuff.add(c)
elif c == '\"':
result.add(backslashBuff)
result.add(backslashBuff)
backslashBuff.setLen(0)
result.add("\\\"")
else:
if backslashBuff.len != 0:
result.add(backslashBuff)
backslashBuff.setLen(0)
result.add(c)
if needQuote:
result.add("\"")
proc quoteShellPosix*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
## Quote s, so it can be safely passed to POSIX shell.
## Based on Python's pipes.quote
const safeUnixChars = {'%', '+', '-', '.', '/', '_', ':', '=', '@',
'0'..'9', 'A'..'Z', 'a'..'z'}
if s.len == 0:
return "''"
let safe = s.allCharsInSet(safeUnixChars)
if safe:
return s
else:
return "'" & s.replace("'", "'\"'\"'") & "'"
proc quoteShell*(s: string): string {.noSideEffect, rtl, extern: "nosp$1".} =
## Quote s, so it can be safely passed to shell.
when defined(Windows):
return quoteShellWindows(s)
elif defined(posix):
return quoteShellPosix(s)
else:
{.error:"quoteShell is not supported on your system".}
proc execProcess*(command: string,
args: openarray[string] = [],
env: PStringTable = nil,
options: set[TProcessOption] = {poStdErrToStdOut,
poUseShell}): TaintedString {.
poUsePath,
poEvalCommand}): TaintedString {.
rtl, extern: "nosp$1",
tags: [FExecIO, FReadIO].}
## A convenience procedure that executes ``command`` with ``startProcess``
## and returns its output as a string.
## WARNING: this function uses poEvalCommand by default for backward compatibility.
## Make sure to pass options explicitly.
proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [FExecIO].}
## Executes ``command`` and returns its error code. Standard input, output,
@ -56,9 +119,9 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [FExecIO].}
proc startProcess*(command: string,
workingDir: string = "",
args: openarray[string] = [],
env: PStringTable = nil,
options: set[TProcessOption] = {poStdErrToStdOut}):
args: openArray[string] = [],
env: PStringTable = nil,
options: set[TProcessOption] = {poStdErrToStdOut}):
PProcess {.rtl, extern: "nosp$1", tags: [FExecIO, FReadEnv].}
## Starts a process. `Command` is the executable file, `workingDir` is the
## process's working directory. If ``workingDir == ""`` the current directory
@ -75,16 +138,10 @@ proc startProcess*(command: string,
## but ``EOS`` is raised in case of an error.
proc startCmd*(command: string, options: set[TProcessOption] = {
poStdErrToStdOut, poUseShell}): PProcess {.
tags: [FExecIO, FReadEnv].} =
## a simpler version of `startProcess` that parses the command line into
## program and arguments and then calls `startProcess` with the empty string
## for `workingDir` and the nil string table for `env`.
var c = parseCmdLine(command)
var a: seq[string]
newSeq(a, c.len-1) # avoid slicing for now (still unstable)
for i in 1 .. c.len-1: a[i-1] = c[i]
result = startProcess(command=c[0], args=a, options=options)
poStdErrToStdOut, poUsePath}): PProcess {.
tags: [FExecIO, FReadEnv], deprecated.} =
## Deprecated - use `startProcess` directly.
result = startProcess(command=command, options=options + {poEvalCommand})
proc close*(p: PProcess) {.rtl, extern: "nosp$1", tags: [].}
## When the process has finished executing, cleanup related handles
@ -105,7 +162,7 @@ proc processID*(p: PProcess): int {.rtl, extern: "nosp$1".} =
## returns `p`'s process ID.
return p.id
proc waitForExit*(p: PProcess, timeout: int = -1): int {.rtl,
proc waitForExit*(p: PProcess, timeout: int = -1): int {.rtl,
extern: "nosp$1", tags: [].}
## waits for the process to finish and returns `p`'s error code.
@ -115,19 +172,19 @@ proc peekExitCode*(p: PProcess): int {.tags: [].}
proc inputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s input stream for writing to.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc outputStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s output stream for reading from.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc errorStream*(p: PProcess): PStream {.rtl, extern: "nosp$1", tags: [].}
## returns ``p``'s error stream for reading from.
##
## **Warning**: The returned `PStream` should not be closed manually as it
## **Warning**: The returned `PStream` should not be closed manually as it
## is closed when closing the PProcess ``p``.
proc inputHandle*(p: PProcess): TFileHandle {.rtl, extern: "nosp$1",
@ -167,7 +224,7 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
## returns the numer of the processors/cores the machine has.
## Returns 0 if it cannot be detected.
when defined(windows):
var x = getenv("NUMBER_OF_PROCESSORS")
var x = getEnv("NUMBER_OF_PROCESSORS")
if x.len > 0: result = parseInt(x.string)
elif defined(macosx) or defined(bsd):
var
@ -193,15 +250,15 @@ proc countProcessors*(): int {.rtl, extern: "nosp$1".} =
proc execProcesses*(cmds: openArray[string],
options = {poStdErrToStdOut, poParentStreams},
n = countProcessors()): int {.rtl, extern: "nosp$1",
tags: [FExecIO, FTime, FReadEnv].} =
n = countProcessors()): int {.rtl, extern: "nosp$1",
tags: [FExecIO, FTime, FReadEnv]} =
## executes the commands `cmds` in parallel. Creates `n` processes
## that execute in parallel. The highest return value of all processes
## is returned.
when defined(posix):
# poParentStreams causes problems on Posix, so we simply disable it:
var options = options - {poParentStreams}
assert n > 0
if n > 1:
var q: seq[PProcess]
@ -255,13 +312,17 @@ proc select*(readfds: var seq[PProcess], timeout = 500): int
when not defined(useNimRtl):
proc execProcess(command: string,
args: openarray[string] = [],
env: PStringTable = nil,
options: set[TProcessOption] = {poStdErrToStdOut,
poUseShell}): TaintedString =
var p = startCmd(command, options=options)
poUsePath,
poEvalCommand}): TaintedString =
var p = startProcess(command, args=args, env=env, options=options)
var outp = outputStream(p)
result = TaintedString""
var line = newStringOfCap(120).TaintedString
while true:
# FIXME: converts CR-LF to LF.
if outp.readLine(line):
result.string.add(line.string)
result.string.add("\n")
@ -277,18 +338,18 @@ when defined(Windows) and not defined(useNimRtl):
handle: THandle
atTheEnd: bool
proc hsClose(s: PStream) = nil # nothing to do here
proc hsClose(s: PStream) = discard # nothing to do here
proc hsAtEnd(s: PStream): bool = return PFileHandleStream(s).atTheEnd
proc hsReadData(s: PStream, buffer: pointer, bufLen: int): int =
var s = PFileHandleStream(s)
if s.atTheEnd: return 0
var br: int32
var a = winlean.ReadFile(s.handle, buffer, bufLen.cint, br, nil)
var a = winlean.readFile(s.handle, buffer, bufLen.cint, br, nil)
# TRUE and zero bytes returned (EOF).
# TRUE and n (>0) bytes returned (good data).
# FALSE and bytes returned undefined (system error).
if a == 0 and br != 0: OSError(OSLastError())
if a == 0 and br != 0: osError(osLastError())
s.atTheEnd = br < bufLen
result = br
@ -296,7 +357,7 @@ when defined(Windows) and not defined(useNimRtl):
var s = PFileHandleStream(s)
var bytesWritten: int32
var a = winlean.writeFile(s.handle, buffer, bufLen.cint, bytesWritten, nil)
if a == 0: OSError(OSLastError())
if a == 0: osError(osLastError())
proc newFileHandleStream(handle: THandle): PFileHandleStream =
new(result)
@ -306,11 +367,11 @@ when defined(Windows) and not defined(useNimRtl):
result.readDataImpl = hsReadData
result.writeDataImpl = hsWriteData
proc buildCommandLine(a: string, args: openarray[string]): cstring =
var res = quoteIfContainsWhite(a)
proc buildCommandLine(a: string, args: openArray[string]): cstring =
var res = quoteShell(a)
for i in 0..high(args):
res.add(' ')
res.add(quoteIfContainsWhite(args[i]))
res.add(quoteShell(args[i]))
result = cast[cstring](alloc0(res.len+1))
copyMem(result, cstring(res), res.len)
@ -331,52 +392,53 @@ when defined(Windows) and not defined(useNimRtl):
# O_WRONLY {.importc: "_O_WRONLY", header: "<fcntl.h>".}: int
# O_RDONLY {.importc: "_O_RDONLY", header: "<fcntl.h>".}: int
proc CreatePipeHandles(Rdhandle, WrHandle: var THandle) =
var piInheritablePipe: TSecurityAttributes
piInheritablePipe.nlength = SizeOF(TSecurityAttributes).cint
proc createPipeHandles(rdHandle, wrHandle: var THandle) =
var piInheritablePipe: TSECURITY_ATTRIBUTES
piInheritablePipe.nLength = sizeof(TSECURITY_ATTRIBUTES).cint
piInheritablePipe.lpSecurityDescriptor = nil
piInheritablePipe.Binherithandle = 1
if CreatePipe(Rdhandle, Wrhandle, piInheritablePipe, 1024) == 0'i32:
OSError(OSLastError())
piInheritablePipe.bInheritHandle = 1
if createPipe(rdHandle, wrHandle, piInheritablePipe, 1024) == 0'i32:
osError(osLastError())
proc fileClose(h: THandle) {.inline.} =
if h > 4: discard CloseHandle(h)
if h > 4: discard closeHandle(h)
proc startProcess(command: string,
workingDir: string = "",
args: openarray[string] = [],
args: openArray[string] = [],
env: PStringTable = nil,
options: set[TProcessOption] = {poStdErrToStdOut}): PProcess =
var
SI: TStartupInfo
ProcInfo: TProcessInformation
si: TSTARTUPINFO
procInfo: TPROCESS_INFORMATION
success: int
hi, ho, he: THandle
new(result)
SI.cb = SizeOf(SI).cint
si.cb = sizeof(si).cint
if poParentStreams notin options:
SI.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
CreatePipeHandles(SI.hStdInput, HI)
CreatePipeHandles(HO, Si.hStdOutput)
si.dwFlags = STARTF_USESTDHANDLES # STARTF_USESHOWWINDOW or
createPipeHandles(si.hStdInput, hi)
createPipeHandles(ho, si.hStdOutput)
if poStdErrToStdOut in options:
SI.hStdError = SI.hStdOutput
HE = HO
si.hStdError = si.hStdOutput
he = ho
else:
CreatePipeHandles(HE, Si.hStdError)
createPipeHandles(he, si.hStdError)
result.inHandle = TFileHandle(hi)
result.outHandle = TFileHandle(ho)
result.errHandle = TFileHandle(he)
else:
SI.hStdError = GetStdHandle(STD_ERROR_HANDLE)
SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE)
SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
si.hStdError = getStdHandle(STD_ERROR_HANDLE)
si.hStdInput = getStdHandle(STD_INPUT_HANDLE)
si.hStdOutput = getStdHandle(STD_OUTPUT_HANDLE)
result.inHandle = TFileHandle(si.hStdInput)
result.outHandle = TFileHandle(si.hStdOutput)
result.errHandle = TFileHandle(si.hStdError)
var cmdl: cstring
when false: # poUseShell in options:
cmdl = buildCommandLine(getEnv("COMSPEC"), @["/c", command] & args)
if poEvalCommand in options:
cmdl = command
assert args.len == 0
else:
cmdl = buildCommandLine(command, args)
var wd: cstring = nil
@ -388,64 +450,63 @@ when defined(Windows) and not defined(useNimRtl):
var tmp = newWideCString(cmdl)
var ee = newWideCString(e)
var wwd = newWideCString(wd)
success = winlean.CreateProcessW(nil,
tmp, nil, nil, 1, NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT,
ee, wwd, SI, ProcInfo)
success = winlean.createProcessW(nil,
tmp, nil, nil, 1, NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT,
ee, wwd, si, procInfo)
else:
success = winlean.CreateProcessA(nil,
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
let lastError = OSLastError()
success = winlean.createProcessA(nil,
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, si, procInfo)
let lastError = osLastError()
if poParentStreams notin options:
FileClose(si.hStdInput)
FileClose(si.hStdOutput)
fileClose(si.hStdInput)
fileClose(si.hStdOutput)
if poStdErrToStdOut notin options:
FileClose(si.hStdError)
fileClose(si.hStdError)
if e != nil: dealloc(e)
dealloc(cmdl)
if success == 0: OSError(lastError)
if success == 0: osError(lastError)
# Close the handle now so anyone waiting is woken:
discard closeHandle(procInfo.hThread)
result.FProcessHandle = procInfo.hProcess
result.id = procInfo.dwProcessID
result.fProcessHandle = procInfo.hProcess
result.id = procInfo.dwProcessId
proc close(p: PProcess) =
when false:
# somehow this does not work on Windows:
discard CloseHandle(p.inHandle)
discard CloseHandle(p.outHandle)
discard CloseHandle(p.errHandle)
discard CloseHandle(p.FProcessHandle)
discard closeHandle(p.inHandle)
discard closeHandle(p.outHandle)
discard closeHandle(p.errHandle)
discard closeHandle(p.FProcessHandle)
proc suspend(p: PProcess) =
discard SuspendThread(p.FProcessHandle)
discard suspendThread(p.fProcessHandle)
proc resume(p: PProcess) =
discard ResumeThread(p.FProcessHandle)
discard resumeThread(p.fProcessHandle)
proc running(p: PProcess): bool =
var x = waitForSingleObject(p.FProcessHandle, 50)
var x = waitForSingleObject(p.fProcessHandle, 50)
return x == WAIT_TIMEOUT
proc terminate(p: PProcess) =
if running(p):
discard TerminateProcess(p.FProcessHandle, 0)
discard terminateProcess(p.fProcessHandle, 0)
proc waitForExit(p: PProcess, timeout: int = -1): int =
discard WaitForSingleObject(p.FProcessHandle, timeout.int32)
discard waitForSingleObject(p.fProcessHandle, timeout.int32)
var res: int32
discard GetExitCodeProcess(p.FProcessHandle, res)
discard getExitCodeProcess(p.fProcessHandle, res)
result = res
discard CloseHandle(p.FProcessHandle)
discard closeHandle(p.fProcessHandle)
proc peekExitCode(p: PProcess): int =
var b = waitForSingleObject(p.FProcessHandle, 50) == WAIT_TIMEOUT
var b = waitForSingleObject(p.fProcessHandle, 50) == WAIT_TIMEOUT
if b: result = -1
else:
else:
var res: int32
discard GetExitCodeProcess(p.FProcessHandle, res)
discard getExitCodeProcess(p.fProcessHandle, res)
return res
proc inputStream(p: PProcess): PStream =
@ -459,46 +520,46 @@ when defined(Windows) and not defined(useNimRtl):
proc execCmd(command: string): int =
var
SI: TStartupInfo
ProcInfo: TProcessInformation
si: TSTARTUPINFO
procInfo: TPROCESS_INFORMATION
process: THandle
L: int32
SI.cb = SizeOf(SI).cint
SI.hStdError = GetStdHandle(STD_ERROR_HANDLE)
SI.hStdInput = GetStdHandle(STD_INPUT_HANDLE)
SI.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE)
si.cb = sizeof(si).cint
si.hStdError = getStdHandle(STD_ERROR_HANDLE)
si.hStdInput = getStdHandle(STD_INPUT_HANDLE)
si.hStdOutput = getStdHandle(STD_OUTPUT_HANDLE)
when useWinUnicode:
var c = newWideCString(command)
var res = winlean.CreateProcessW(nil, c, nil, nil, 0,
NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
var res = winlean.createProcessW(nil, c, nil, nil, 0,
NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo)
else:
var res = winlean.CreateProcessA(nil, command, nil, nil, 0,
NORMAL_PRIORITY_CLASS, nil, nil, SI, ProcInfo)
var res = winlean.createProcessA(nil, command, nil, nil, 0,
NORMAL_PRIORITY_CLASS, nil, nil, si, procInfo)
if res == 0:
OSError(OSLastError())
osError(osLastError())
else:
Process = ProcInfo.hProcess
discard CloseHandle(ProcInfo.hThread)
if WaitForSingleObject(Process, INFINITE) != -1:
discard GetExitCodeProcess(Process, L)
process = procInfo.hProcess
discard closeHandle(procInfo.hThread)
if waitForSingleObject(process, INFINITE) != -1:
discard getExitCodeProcess(process, L)
result = int(L)
else:
result = -1
discard CloseHandle(Process)
discard closeHandle(process)
proc select(readfds: var seq[PProcess], timeout = 500): int =
proc select(readfds: var seq[PProcess], timeout = 500): int =
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
var rfds: TWOHandleArray
for i in 0..readfds.len()-1:
rfds[i] = readfds[i].FProcessHandle
var ret = waitForMultipleObjects(readfds.len.int32,
rfds[i] = readfds[i].fProcessHandle
var ret = waitForMultipleObjects(readfds.len.int32,
addr(rfds), 0'i32, timeout.int32)
case ret
of WAIT_TIMEOUT:
return 0
of WAIT_FAILED:
OSError(OSLastError())
osError(osLastError())
else:
var i = ret - WAIT_OBJECT_0
readfds.del(i)
@ -509,22 +570,7 @@ elif not defined(useNimRtl):
readIdx = 0
writeIdx = 1
proc addCmdArgs(command: string, args: openarray[string]): string =
result = quoteIfContainsWhite(command)
for i in 0 .. high(args):
add(result, " ")
add(result, quoteIfContainsWhite(args[i]))
proc toCStringArray(b, a: openarray[string]): cstringArray =
result = cast[cstringArray](alloc0((a.len + b.len + 1) * sizeof(cstring)))
for i in 0..high(b):
result[i] = cast[cstring](alloc(b[i].len+1))
copyMem(result[i], cstring(b[i]), b[i].len+1)
for i in 0..high(a):
result[i+b.len] = cast[cstring](alloc(a[i].len+1))
copyMem(result[i+b.len], cstring(a[i]), a[i].len+1)
proc ToCStringArray(t: PStringTable): cstringArray =
proc envToCStringArray(t: PStringTable): cstringArray =
result = cast[cstringArray](alloc0((t.len + 1) * sizeof(cstring)))
var i = 0
for key, val in pairs(t):
@ -533,7 +579,7 @@ elif not defined(useNimRtl):
copyMem(result[i], addr(x[0]), x.len+1)
inc(i)
proc EnvToCStringArray(): cstringArray =
proc envToCStringArray(): cstringArray =
var counter = 0
for key, val in envPairs(): inc counter
result = cast[cstringArray](alloc0((counter + 1) * sizeof(cstring)))
@ -543,104 +589,113 @@ elif not defined(useNimRtl):
result[i] = cast[cstring](alloc(x.len+1))
copyMem(result[i], addr(x[0]), x.len+1)
inc(i)
proc startProcess(command: string,
workingDir: string = "",
args: openarray[string] = [],
args: openArray[string] = [],
env: PStringTable = nil,
options: set[TProcessOption] = {poStdErrToStdOut}): PProcess =
var
p_stdin, p_stdout, p_stderr: array [0..1, cint]
pStdin, pStdout, pStderr: array [0..1, cint]
new(result)
result.exitCode = -3 # for ``waitForExit``
if poParentStreams notin options:
if pipe(p_stdin) != 0'i32 or pipe(p_stdout) != 0'i32 or
pipe(p_stderr) != 0'i32:
OSError(OSLastError())
if pipe(pStdin) != 0'i32 or pipe(pStdout) != 0'i32 or
pipe(pStderr) != 0'i32:
osError(osLastError())
var sys_command: string
var sys_args_raw: seq[string]
if poEvalCommand in options:
sys_command = "/bin/sh"
sys_args_raw = @[sys_command, "-c", command]
assert args.len == 0
else:
sys_command = command
sys_args_raw = @[command]
for arg in args.items:
sys_args_raw.add arg
var sys_args = allocCStringArray(sys_args_raw)
finally: deallocCStringArray(sys_args)
var pid: TPid
when defined(posix_spawn) and not defined(useFork):
var attr: Tposix_spawnattr
var fops: Tposix_spawn_file_actions
template chck(e: expr) =
if e != 0'i32: OSError(OSLastError())
template chck(e: expr) =
if e != 0'i32: osError(osLastError())
chck posix_spawn_file_actions_init(fops)
chck posix_spawnattr_init(attr)
var mask: Tsigset
chck sigemptyset(mask)
chck posix_spawnattr_setsigmask(attr, mask)
chck posix_spawnattr_setpgroup(attr, 0'i32)
chck posix_spawnattr_setflags(attr, POSIX_SPAWN_USEVFORK or
POSIX_SPAWN_SETSIGMASK or
POSIX_SPAWN_SETPGROUP)
if poParentStreams notin options:
chck posix_spawn_file_actions_addclose(fops, p_stdin[writeIdx])
chck posix_spawn_file_actions_adddup2(fops, p_stdin[readIdx], readIdx)
chck posix_spawn_file_actions_addclose(fops, p_stdout[readIdx])
chck posix_spawn_file_actions_adddup2(fops, p_stdout[writeIdx], writeIdx)
chck posix_spawn_file_actions_addclose(fops, p_stderr[readIdx])
chck posix_spawn_file_actions_addclose(fops, pStdin[writeIdx])
chck posix_spawn_file_actions_adddup2(fops, pStdin[readIdx], readIdx)
chck posix_spawn_file_actions_addclose(fops, pStdout[readIdx])
chck posix_spawn_file_actions_adddup2(fops, pStdout[writeIdx], writeIdx)
chck posix_spawn_file_actions_addclose(fops, pStderr[readIdx])
if poStdErrToStdOut in options:
chck posix_spawn_file_actions_adddup2(fops, p_stdout[writeIdx], 2)
chck posix_spawn_file_actions_adddup2(fops, pStdout[writeIdx], 2)
else:
chck posix_spawn_file_actions_adddup2(fops, p_stderr[writeIdx], 2)
var e = if env == nil: EnvToCStringArray() else: ToCStringArray(env)
var a: cstringArray
var sys_env = if env == nil: envToCStringArray() else: envToCStringArray(env)
var res: cint
# This is incorrect!
if workingDir.len > 0: os.setCurrentDir(workingDir)
if poUseShell notin options:
a = toCStringArray([extractFilename(command)], args)
res = posix_spawn(pid, command, fops, attr, a, e)
if poUsePath in options:
res = posix_spawnp(pid, sys_command, fops, attr, sys_args, sys_env)
else:
var x = addCmdArgs(command, args)
a = toCStringArray(["sh", "-c"], [x])
res = posix_spawn(pid, "/bin/sh", fops, attr, a, e)
deallocCStringArray(a)
deallocCStringArray(e)
res = posix_spawn(pid, sys_command, fops, attr, sys_args, sys_env)
deallocCStringArray(sys_env)
discard posix_spawn_file_actions_destroy(fops)
discard posix_spawnattr_destroy(attr)
chck res
else:
Pid = fork()
if Pid < 0: OSError(OSLastError())
pid = fork()
if pid < 0: osError(osLastError())
if pid == 0:
## child process:
if poParentStreams notin options:
discard close(p_stdin[writeIdx])
if dup2(p_stdin[readIdx], readIdx) < 0: OSError(OSLastError())
if dup2(p_stdin[readIdx], readIdx) < 0: osError(osLastError())
discard close(p_stdout[readIdx])
if dup2(p_stdout[writeIdx], writeIdx) < 0: OSError(OSLastError())
if dup2(p_stdout[writeIdx], writeIdx) < 0: osError(osLastError())
discard close(p_stderr[readIdx])
if poStdErrToStdOut in options:
if dup2(p_stdout[writeIdx], 2) < 0: OSError(OSLastError())
if dup2(p_stdout[writeIdx], 2) < 0: osError(osLastError())
else:
if dup2(p_stderr[writeIdx], 2) < 0: OSError(OSLastError())
if dup2(p_stderr[writeIdx], 2) < 0: osError(osLastError())
# Create a new process group
if setpgid(0, 0) == -1: quit("setpgid call failed: " & $strerror(errno))
if workingDir.len > 0: os.setCurrentDir(workingDir)
if poUseShell notin options:
var a = toCStringArray([extractFilename(command)], args)
if env == nil:
discard execv(command, a)
if env == nil:
if poUsePath in options:
discard execvp(sys_command, sys_args)
else:
discard execve(command, a, ToCStringArray(env))
discard execv(sys_command, sys_args)
else:
var x = addCmdArgs(command, args)
var a = toCStringArray(["sh", "-c"], [x])
if env == nil:
discard execv("/bin/sh", a)
var c_env = envToCStringArray(env)
if poUsePath in options:
discard execvpe(sys_command, sys_args, c_env)
else:
discard execve("/bin/sh", a, ToCStringArray(env))
discard execve(sys_command, sys_args, c_env)
# too risky to raise an exception here:
quit("execve call failed: " & $strerror(errno))
# Parent process. Copy process information.
@ -657,16 +712,16 @@ elif not defined(useNimRtl):
else:
result.errHandle = 2
else:
result.inHandle = p_stdin[writeIdx]
result.outHandle = p_stdout[readIdx]
result.inHandle = pStdin[writeIdx]
result.outHandle = pStdout[readIdx]
if poStdErrToStdOut in options:
result.errHandle = result.outHandle
discard close(p_stderr[readIdx])
discard close(pStderr[readIdx])
else:
result.errHandle = p_stderr[readIdx]
discard close(p_stderr[writeIdx])
discard close(p_stdin[readIdx])
discard close(p_stdout[writeIdx])
result.errHandle = pStderr[readIdx]
discard close(pStderr[writeIdx])
discard close(pStdin[readIdx])
discard close(pStdout[writeIdx])
proc close(p: PProcess) =
if p.inStream != nil: close(p.inStream)
@ -677,21 +732,21 @@ elif not defined(useNimRtl):
discard close(p.errHandle)
proc suspend(p: PProcess) =
if kill(-p.id, SIGSTOP) != 0'i32: OSError(OSLastError())
if kill(-p.id, SIGSTOP) != 0'i32: osError(osLastError())
proc resume(p: PProcess) =
if kill(-p.id, SIGCONT) != 0'i32: OSError(OSLastError())
if kill(-p.id, SIGCONT) != 0'i32: osError(osLastError())
proc running(p: PProcess): bool =
var ret = waitPid(p.id, p.exitCode, WNOHANG)
var ret = waitpid(p.id, p.exitCode, WNOHANG)
if ret == 0: return true # Can't establish status. Assume running.
result = ret == int(p.id)
proc terminate(p: PProcess) =
if kill(-p.id, SIGTERM) == 0'i32:
if p.running():
if kill(-p.id, SIGKILL) != 0'i32: OSError(OSLastError())
else: OSError(OSLastError())
if kill(-p.id, SIGKILL) != 0'i32: osError(osLastError())
else: osError(osLastError())
proc waitForExit(p: PProcess, timeout: int = -1): int =
#if waitPid(p.id, p.exitCode, 0) == int(p.id):
@ -699,14 +754,14 @@ elif not defined(useNimRtl):
# ``running`` probably set ``p.exitCode`` for us. Since ``p.exitCode`` is
# initialized with -3, wrong success exit codes are prevented.
if p.exitCode != -3: return p.exitCode
if waitPid(p.id, p.exitCode, 0) < 0:
if waitpid(p.id, p.exitCode, 0) < 0:
p.exitCode = -3
OSError(OSLastError())
osError(osLastError())
result = int(p.exitCode) shr 8
proc peekExitCode(p: PProcess): int =
if p.exitCode != -3: return p.exitCode
var ret = waitPid(p.id, p.exitCode, WNOHANG)
var ret = waitpid(p.id, p.exitCode, WNOHANG)
var b = ret == int(p.id)
if b: result = -1
if p.exitCode == -3: result = -1
@ -715,7 +770,7 @@ elif not defined(useNimRtl):
proc createStream(stream: var PStream, handle: var TFileHandle,
fileMode: TFileMode) =
var f: TFile
if not open(f, handle, fileMode): OSError(OSLastError())
if not open(f, handle, fileMode): osError(osLastError())
stream = newFileStream(f)
proc inputStream(p: PProcess): PStream =
@ -736,45 +791,45 @@ elif not defined(useNimRtl):
proc csystem(cmd: cstring): cint {.nodecl, importc: "system".}
proc execCmd(command: string): int =
result = csystem(command)
result = csystem(command) shr 8
proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
proc createFdSet(fd: var TFdSet, s: seq[PProcess], m: var int) =
FD_ZERO(fd)
for i in items(s):
for i in items(s):
m = max(m, int(i.outHandle))
FD_SET(cint(i.outHandle), fd)
proc pruneProcessSet(s: var seq[PProcess], fd: var TFdSet) =
proc pruneProcessSet(s: var seq[PProcess], fd: var TFdSet) =
var i = 0
var L = s.len
while i < L:
if FD_ISSET(cint(s[i].outHandle), fd) != 0'i32:
if FD_ISSET(cint(s[i].outHandle), fd) == 0'i32:
s[i] = s[L-1]
dec(L)
else:
inc(i)
setLen(s, L)
proc select(readfds: var seq[PProcess], timeout = 500): int =
proc select(readfds: var seq[PProcess], timeout = 500): int =
var tv: TTimeVal
tv.tv_sec = 0
tv.tv_usec = timeout * 1000
var rd: TFdSet
var m = 0
createFdSet((rd), readfds, m)
if timeout != -1:
result = int(select(cint(m+1), addr(rd), nil, nil, addr(tv)))
else:
result = int(select(cint(m+1), addr(rd), nil, nil, nil))
pruneProcessSet(readfds, (rd))
proc execCmdEx*(command: string, options: set[TProcessOption] = {
poStdErrToStdOut, poUseShell}): tuple[
output: TaintedString,
poStdErrToStdOut, poUsePath}): tuple[
output: TaintedString,
exitCode: int] {.tags: [FExecIO, FReadIO].} =
## a convenience proc that runs the `command`, grabs all its output and
## exit code and returns both.
@ -792,5 +847,14 @@ proc execCmdEx*(command: string, options: set[TProcessOption] = {
close(p)
when isMainModule:
var x = execProcess("gcc -v")
echo "ECHO ", x
assert quoteShellWindows("aaa") == "aaa"
assert quoteShellWindows("aaa\"") == "aaa\\\""
assert quoteShellWindows("") == "\"\""
assert quoteShellPosix("aaa") == "aaa"
assert quoteShellPosix("aaa a") == "'aaa a'"
assert quoteShellPosix("") == "''"
assert quoteShellPosix("a'a") == "'a'\"'\"'a'"
when defined(posix):
assert quoteShell("") == "''"

View file

@ -82,7 +82,7 @@ proc open*(c: var TCfgParser, input: PStream, filename: string,
c.filename = filename
c.tok.kind = tkInvalid
c.tok.literal = ""
inc(c.linenumber, lineOffset)
inc(c.lineNumber, lineOffset)
rawGetTok(c, c.tok)
proc close*(c: var TCfgParser) {.rtl, extern: "npc$1".} =
@ -91,11 +91,11 @@ proc close*(c: var TCfgParser) {.rtl, extern: "npc$1".} =
proc getColumn*(c: TCfgParser): int {.rtl, extern: "npc$1".} =
## get the current column the parser has arrived at.
result = getColNumber(c, c.bufPos)
result = getColNumber(c, c.bufpos)
proc getLine*(c: TCfgParser): int {.rtl, extern: "npc$1".} =
## get the current line the parser has arrived at.
result = c.linenumber
result = c.lineNumber
proc getFilename*(c: TCfgParser): string {.rtl, extern: "npc$1".} =
## get the filename of the file that the parser processes.
@ -113,7 +113,7 @@ proc handleHexChar(c: var TCfgParser, xi: var int) =
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
inc(c.bufpos)
else:
nil
discard
proc handleDecChars(c: var TCfgParser, xi: var int) =
while c.buf[c.bufpos] in {'0'..'9'}:
@ -125,74 +125,74 @@ proc getEscapedChar(c: var TCfgParser, tok: var TToken) =
case c.buf[c.bufpos]
of 'n', 'N':
add(tok.literal, "\n")
Inc(c.bufpos)
inc(c.bufpos)
of 'r', 'R', 'c', 'C':
add(tok.literal, '\c')
Inc(c.bufpos)
inc(c.bufpos)
of 'l', 'L':
add(tok.literal, '\L')
Inc(c.bufpos)
inc(c.bufpos)
of 'f', 'F':
add(tok.literal, '\f')
inc(c.bufpos)
of 'e', 'E':
add(tok.literal, '\e')
Inc(c.bufpos)
inc(c.bufpos)
of 'a', 'A':
add(tok.literal, '\a')
Inc(c.bufpos)
inc(c.bufpos)
of 'b', 'B':
add(tok.literal, '\b')
Inc(c.bufpos)
inc(c.bufpos)
of 'v', 'V':
add(tok.literal, '\v')
Inc(c.bufpos)
inc(c.bufpos)
of 't', 'T':
add(tok.literal, '\t')
Inc(c.bufpos)
inc(c.bufpos)
of '\'', '"':
add(tok.literal, c.buf[c.bufpos])
Inc(c.bufpos)
inc(c.bufpos)
of '\\':
add(tok.literal, '\\')
Inc(c.bufpos)
inc(c.bufpos)
of 'x', 'X':
inc(c.bufpos)
var xi = 0
handleHexChar(c, xi)
handleHexChar(c, xi)
add(tok.literal, Chr(xi))
add(tok.literal, chr(xi))
of '0'..'9':
var xi = 0
handleDecChars(c, xi)
if (xi <= 255): add(tok.literal, Chr(xi))
if (xi <= 255): add(tok.literal, chr(xi))
else: tok.kind = tkInvalid
else: tok.kind = tkInvalid
proc HandleCRLF(c: var TCfgParser, pos: int): int =
proc handleCRLF(c: var TCfgParser, pos: int): int =
case c.buf[pos]
of '\c': result = lexbase.HandleCR(c, pos)
of '\L': result = lexbase.HandleLF(c, pos)
of '\c': result = lexbase.handleCR(c, pos)
of '\L': result = lexbase.handleLF(c, pos)
else: result = pos
proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
var pos = c.bufPos + 1 # skip "
var pos = c.bufpos + 1 # skip "
var buf = c.buf # put `buf` in a register
tok.kind = tkSymbol
if (buf[pos] == '"') and (buf[pos + 1] == '"'):
# long string literal:
inc(pos, 2) # skip ""
# skip leading newline:
pos = HandleCRLF(c, pos)
pos = handleCRLF(c, pos)
buf = c.buf
while true:
case buf[pos]
of '"':
if (buf[pos + 1] == '"') and (buf[pos + 2] == '"'): break
add(tok.literal, '"')
Inc(pos)
inc(pos)
of '\c', '\L':
pos = HandleCRLF(c, pos)
pos = handleCRLF(c, pos)
buf = c.buf
add(tok.literal, "\n")
of lexbase.EndOfFile:
@ -200,7 +200,7 @@ proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
break
else:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
c.bufpos = pos + 3 # skip the three """
else:
# ordinary string literal
@ -213,12 +213,12 @@ proc getString(c: var TCfgParser, tok: var TToken, rawMode: bool) =
tok.kind = tkInvalid
break
if (ch == '\\') and not rawMode:
c.bufPos = pos
c.bufpos = pos
getEscapedChar(c, tok)
pos = c.bufPos
pos = c.bufpos
else:
add(tok.literal, ch)
Inc(pos)
inc(pos)
c.bufpos = pos
proc getSymbol(c: var TCfgParser, tok: var TToken) =
@ -226,7 +226,7 @@ proc getSymbol(c: var TCfgParser, tok: var TToken) =
var buf = c.buf
while true:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
if not (buf[pos] in SymChars): break
c.bufpos = pos
tok.kind = tkSymbol
@ -237,11 +237,11 @@ proc skip(c: var TCfgParser) =
while true:
case buf[pos]
of ' ', '\t':
Inc(pos)
inc(pos)
of '#', ';':
while not (buf[pos] in {'\c', '\L', lexbase.EndOfFile}): inc(pos)
of '\c', '\L':
pos = HandleCRLF(c, pos)
pos = handleCRLF(c, pos)
buf = c.buf
else:
break # EndOfFile also leaves the loop
@ -249,7 +249,7 @@ proc skip(c: var TCfgParser) =
proc rawGetTok(c: var TCfgParser, tok: var TToken) =
tok.kind = tkInvalid
setlen(tok.literal, 0)
setLen(tok.literal, 0)
skip(c)
case c.buf[c.bufpos]
of '=':
@ -257,8 +257,8 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) =
inc(c.bufpos)
tok.literal = "="
of '-':
inc(c.bufPos)
if c.buf[c.bufPos] == '-': inc(c.bufPos)
inc(c.bufpos)
if c.buf[c.bufpos] == '-': inc(c.bufpos)
tok.kind = tkDashDash
tok.literal = "--"
of ':':
@ -266,8 +266,8 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) =
inc(c.bufpos)
tok.literal = ":"
of 'r', 'R':
if c.buf[c.bufPos + 1] == '\"':
Inc(c.bufPos)
if c.buf[c.bufpos + 1] == '\"':
inc(c.bufpos)
getString(c, tok, true)
else:
getSymbol(c, tok)
@ -277,7 +277,7 @@ proc rawGetTok(c: var TCfgParser, tok: var TToken) =
tok.literal = "]"
of ']':
tok.kind = tkBracketRi
Inc(c.bufpos)
inc(c.bufpos)
tok.literal = "]"
of '"':
getString(c, tok, false)

View file

@ -149,7 +149,7 @@ proc readRow*(my: var TCsvParser, columns = 0): bool =
of '\c': my.bufpos = handleCR(my, my.bufpos)
of '\l': my.bufpos = handleLF(my, my.bufpos)
else: break
of '\0': nil
of '\0': discard
else: error(my, my.bufpos, my.sep & " expected")
break

View file

@ -10,7 +10,10 @@
## This module provides the standard Nimrod command line parser.
## It supports one convenience iterator over all command line options and some
## lower-level features.
##
## **Deprecated since version 0.9.3:** Use the `parseopt2 <parseopt2.html>`_
## module instead as this version has issues with spaces in arguments.
{.deprecated.}
{.push debugger: off.}
include "system/inclrtl"
@ -34,7 +37,7 @@ type
## or the argument, ``value`` is not "" if
## the option was given a value
when defined(os.ParamCount):
when defined(os.paramCount):
# we cannot provide this for NimRtl creation on Posix, because we can't
# access the command line arguments then!
@ -47,7 +50,7 @@ when defined(os.ParamCount):
result.cmd = cmdline
else:
result.cmd = ""
for i in countup(1, ParamCount()):
for i in countup(1, paramCount()):
result.cmd = result.cmd & quoteIfContainsWhite(paramStr(i).string) & ' '
result.kind = cmdEnd
result.key = TaintedString""
@ -91,8 +94,8 @@ proc next*(p: var TOptParser) {.
var i = p.pos
while p.cmd[i] in {'\x09', ' '}: inc(i)
p.pos = i
setlen(p.key.string, 0)
setlen(p.val.string, 0)
setLen(p.key.string, 0)
setLen(p.val.string, 0)
if p.inShortState:
handleShortOption(p)
return
@ -102,7 +105,7 @@ proc next*(p: var TOptParser) {.
of '-':
inc(i)
if p.cmd[i] == '-':
p.kind = cmdLongOption
p.kind = cmdLongoption
inc(i)
i = parseWord(p.cmd, i, p.key.string, {'\0', ' ', '\x09', ':', '='})
while p.cmd[i] in {'\x09', ' '}: inc(i)

148
lib/pure/parseopt2.nim Normal file
View file

@ -0,0 +1,148 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module provides the standard Nimrod command line parser.
## It supports one convenience iterator over all command line options and some
## lower-level features.
##
## Supported syntax:
##
## 1. short options - ``-abcd``, where a, b, c, d are names
## 2. long option - ``--foo:bar``, ``--foo=bar`` or ``--foo``
## 3. argument - everything else
{.push debugger: off.}
include "system/inclrtl"
import
os, strutils
type
TCmdLineKind* = enum ## the detected command line token
cmdEnd, ## end of command line reached
cmdArgument, ## argument detected
cmdLongOption, ## a long option ``--option`` detected
cmdShortOption ## a short option ``-c`` detected
TOptParser* =
object of TObject ## this object implements the command line parser
cmd: seq[string]
pos: int
remainingShortOptions: string
kind*: TCmdLineKind ## the dected command line token
key*, val*: TaintedString ## key and value pair; ``key`` is the option
## or the argument, ``value`` is not "" if
## the option was given a value
proc initOptParser*(cmdline: seq[string]): TOptParser {.rtl.} =
## Initalizes option parses with cmdline. cmdline should not contain
## argument 0 - program name.
## If cmdline == nil default to current command line arguments.
result.remainingShortOptions = ""
when not defined(createNimRtl):
if cmdline == nil:
result.cmd = commandLineParams()
return
else:
assert cmdline != nil, "Cannot determine command line arguments."
result.cmd = @cmdline
proc initOptParser*(cmdline: string): TOptParser {.rtl, deprecated.} =
## Initalizes option parses with cmdline. Splits cmdline in on spaces
## and calls initOptParser(openarray[string])
## Do not use.
if cmdline == "": # backward compatibilty
return initOptParser(seq[string](nil))
else:
return initOptParser(cmdline.split)
when not defined(createNimRtl):
proc initOptParser*(): TOptParser =
## Initializes option parser from current command line arguments.
return initOptParser(commandLineParams())
proc next*(p: var TOptParser) {.rtl, extern: "npo$1".}
proc nextOption(p: var TOptParser, token: string, allowEmpty: bool) =
for splitchar in [':', '=']:
if splitchar in token:
let pos = token.find(splitchar)
p.key = token[0..pos-1]
p.val = token[pos+1..token.len-1]
return
p.key = token
if allowEmpty:
p.val = ""
else:
p.remainingShortOptions = token[0..token.len-1]
p.next()
proc next(p: var TOptParser) =
if p.remainingShortOptions.len != 0:
p.kind = cmdShortOption
p.key = TaintedString(p.remainingShortOptions[0..0])
p.val = ""
p.remainingShortOptions = p.remainingShortOptions[1..p.remainingShortOptions.len-1]
return
if p.pos >= p.cmd.len:
p.kind = cmdEnd
return
let token = p.cmd[p.pos]
p.pos += 1
if token.startswith("--"):
p.kind = cmdLongOption
nextOption(p, token[2..token.len-1], allowEmpty=true)
elif token.startswith("-"):
p.kind = cmdShortOption
nextOption(p, token[1..token.len-1], allowEmpty=true)
else:
p.kind = cmdArgument
p.key = token
p.val = ""
proc cmdLineRest*(p: TOptParser): TaintedString {.rtl, extern: "npo$1", deprecated.} =
## Returns part of command line string that has not been parsed yet.
## Do not use - does not correctly handle whitespace.
return p.cmd[p.pos..p.cmd.len-1].join(" ")
type
TGetoptResult* = tuple[kind: TCmdLineKind, key, val: TaintedString]
when defined(paramCount):
iterator getopt*(): TGetoptResult =
## This is an convenience iterator for iterating over the command line.
## This uses the TOptParser object. Example:
##
## .. code-block:: nimrod
## var
## filename = ""
## for kind, key, val in getopt():
## case kind
## of cmdArgument:
## filename = key
## of cmdLongOption, cmdShortOption:
## case key
## of "help", "h": writeHelp()
## of "version", "v": writeVersion()
## of cmdEnd: assert(false) # cannot happen
## if filename == "":
## # no filename has been given, so we show the help:
## writeHelp()
var p = initOptParser()
while true:
next(p)
if p.kind == cmdEnd: break
yield (p.kind, p.key, p.val)
{.pop.}

View file

@ -79,7 +79,7 @@ proc handleHexChar(c: var TSqlLexer, xi: var int) =
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
inc(c.bufpos)
else:
nil
discard
proc handleOctChar(c: var TSqlLexer, xi: var int) =
if c.buf[c.bufpos] in {'0'..'7'}:
@ -373,7 +373,7 @@ proc getOperator(c: var TSqlLexer, tok: var TToken) =
of '+':
if not trailingPlusMinus and buf[pos+1] notin operators and
tok.literal.len > 0: break
of '*', '<', '>', '=': nil
of '*', '<', '>', '=': discard
else: break
add(tok.literal, buf[pos])
inc(pos)
@ -1120,7 +1120,7 @@ proc rs(n: PSqlNode, s: var string, indent: int,
proc ra(n: PSqlNode, s: var string, indent: int) =
if n == nil: return
case n.kind
of nkNone: nil
of nkNone: discard
of nkIdent:
if allCharsInSet(n.strVal, {'\33'..'\127'}):
s.add(n.strVal)

View file

@ -51,7 +51,7 @@ proc parseHex*(s: string, number: var int, start = 0): int {.
elif s[i] == '#': inc(i)
while true:
case s[i]
of '_': nil
of '_': discard
of '0'..'9':
number = number shl 4 or (ord(s[i]) - ord('0'))
foundDigit = true
@ -74,7 +74,7 @@ proc parseOct*(s: string, number: var int, start = 0): int {.
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 '_': discard
of '0'..'7':
number = number shl 3 or (ord(s[i]) - ord('0'))
foundDigit = true
@ -189,7 +189,7 @@ proc captureBetween*(s: string, first: char, second = '\0', start = 0): string =
{.push overflowChecks: on.}
# this must be compiled with overflow checking turned on:
proc rawParseInt(s: string, b: var biggestInt, start = 0): int =
proc rawParseInt(s: string, b: var BiggestInt, start = 0): int =
var
sign: BiggestInt = -1
i = start
@ -207,12 +207,12 @@ proc rawParseInt(s: string, b: var biggestInt, start = 0): int =
result = i - start
{.pop.} # overflowChecks
proc parseBiggestInt*(s: string, number: var biggestInt, start = 0): int {.
proc parseBiggestInt*(s: string, number: var BiggestInt, start = 0): int {.
rtl, extern: "npuParseBiggestInt", noSideEffect.} =
## 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
var res: BiggestInt
# use 'res' for exception safety (don't write to 'number' in case of an
# overflow exception:
result = rawParseInt(s, res, start)
@ -223,7 +223,7 @@ 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
var res: BiggestInt
result = parseBiggestInt(s, res, start)
if (sizeof(int) <= 4) and
((res < low(int)) or (res > high(int))):
@ -231,7 +231,7 @@ proc parseInt*(s: string, number: var int, start = 0): int {.
else:
number = int(res)
proc tenToThePowerOf(b: int): biggestFloat =
proc tenToThePowerOf(b: int): BiggestFloat =
var b = b
var a = 10.0
result = 1.0
@ -242,7 +242,7 @@ proc tenToThePowerOf(b: int): biggestFloat =
if b == 0: break
a *= a
proc parseBiggestFloat*(s: string, number: var biggestFloat, start = 0): int {.
proc parseBiggestFloat*(s: string, number: var BiggestFloat, start = 0): int {.
rtl, extern: "npuParseBiggestFloat", noSideEffect.} =
## 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
@ -319,7 +319,7 @@ proc parseFloat*(s: string, number: var float, 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 bf: biggestFloat
var bf: BiggestFloat
result = parseBiggestFloat(s, bf, start)
number = bf
@ -370,7 +370,7 @@ iterator interpolatedFragments*(s: string): tuple[kind: TInterpolatedKind,
of '\0':
raise newException(EInvalidValue,
"Expected closing '}': " & s[i..s.len])
else: nil
else: discard
inc j
inc i, 2 # skip ${
kind = ikExpr

View file

@ -249,23 +249,23 @@ proc newLine*: TPeg {.inline.} =
## constructs the PEG `newline`:idx: (``\n``)
result.kind = pkNewline
proc UnicodeLetter*: TPeg {.inline.} =
proc unicodeLetter*: TPeg {.inline.} =
## constructs the PEG ``\letter`` which matches any Unicode letter.
result.kind = pkLetter
proc UnicodeLower*: TPeg {.inline.} =
proc unicodeLower*: TPeg {.inline.} =
## constructs the PEG ``\lower`` which matches any Unicode lowercase letter.
result.kind = pkLower
proc UnicodeUpper*: TPeg {.inline.} =
proc unicodeUpper*: TPeg {.inline.} =
## constructs the PEG ``\upper`` which matches any Unicode uppercase letter.
result.kind = pkUpper
proc UnicodeTitle*: TPeg {.inline.} =
proc unicodeTitle*: TPeg {.inline.} =
## constructs the PEG ``\title`` which matches any Unicode title letter.
result.kind = pkTitle
proc UnicodeWhitespace*: TPeg {.inline.} =
proc unicodeWhitespace*: TPeg {.inline.} =
## constructs the PEG ``\white`` which matches any Unicode
## whitespace character.
result.kind = pkWhitespace
@ -306,7 +306,7 @@ proc backrefIgnoreStyle*(index: range[1..MaxSubPatterns]): TPeg {.
proc spaceCost(n: TPeg): int =
case n.kind
of pkEmpty: nil
of pkEmpty: discard
of pkTerminal, pkTerminalIgnoreCase, pkTerminalIgnoreStyle, pkChar,
pkGreedyRepChar, pkCharChoice, pkGreedyRepSet,
pkAny..pkWhitespace, pkGreedyAny:
@ -340,28 +340,28 @@ proc newNonTerminal*(name: string, line, column: int): PNonTerminal {.
template letters*: expr =
## expands to ``charset({'A'..'Z', 'a'..'z'})``
charset({'A'..'Z', 'a'..'z'})
charSet({'A'..'Z', 'a'..'z'})
template digits*: expr =
## expands to ``charset({'0'..'9'})``
charset({'0'..'9'})
charSet({'0'..'9'})
template whitespace*: expr =
## expands to ``charset({' ', '\9'..'\13'})``
charset({' ', '\9'..'\13'})
charSet({' ', '\9'..'\13'})
template identChars*: expr =
## expands to ``charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})``
charset({'a'..'z', 'A'..'Z', '0'..'9', '_'})
charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'})
template identStartChars*: expr =
## expands to ``charset({'A'..'Z', 'a'..'z', '_'})``
charset({'a'..'z', 'A'..'Z', '_'})
charSet({'a'..'z', 'A'..'Z', '_'})
template ident*: expr =
## same as ``[a-zA-Z_][a-zA-z_0-9]*``; standard identifier
sequence(charset({'a'..'z', 'A'..'Z', '_'}),
*charset({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
sequence(charSet({'a'..'z', 'A'..'Z', '_'}),
*charSet({'a'..'z', 'A'..'Z', '0'..'9', '_'}))
template natural*: expr =
## same as ``\d+``
@ -385,7 +385,7 @@ proc esc(c: char, reserved = {'\0'..'\255'}): string =
elif c in reserved: result = '\\' & c
else: result = $c
proc singleQuoteEsc(c: Char): string = return "'" & esc(c, {'\''}) & "'"
proc singleQuoteEsc(c: char): string = return "'" & esc(c, {'\''}) & "'"
proc singleQuoteEsc(str: string): string =
result = "'"
@ -409,11 +409,11 @@ proc charSetEscAux(cc: set[char]): string =
c1 = c2
inc(c1)
proc CharSetEsc(cc: set[char]): string =
proc charSetEsc(cc: set[char]): string =
if card(cc) >= 128+64:
result = "[^" & CharSetEscAux({'\1'..'\xFF'} - cc) & ']'
result = "[^" & charSetEscAux({'\1'..'\xFF'} - cc) & ']'
else:
result = '[' & CharSetEscAux(cc) & ']'
result = '[' & charSetEscAux(cc) & ']'
proc toStrAux(r: TPeg, res: var string) =
case r.kind
@ -590,7 +590,7 @@ proc rawMatch*(s: string, p: TPeg, start: int, c: var TCaptures): int {.
var a: TRune
result = start
fastRuneAt(s, result, a)
if isWhitespace(a): dec(result, start)
if isWhiteSpace(a): dec(result, start)
else: result = -1
else:
result = -1
@ -747,7 +747,7 @@ template fillMatches(s, caps, c: expr) =
for k in 0..c.ml-1:
caps[k] = substr(s, c.matches[k][0], c.matches[k][1])
proc match*(s: string, pattern: TPeg, matches: var openarray[string],
proc match*(s: string, pattern: TPeg, matches: var openArray[string],
start = 0): bool {.nosideEffect, rtl, extern: "npegs$1Capture".} =
## returns ``true`` if ``s[start..]`` matches the ``pattern`` and
## the captured substrings in the array ``matches``. If it does not
@ -765,7 +765,7 @@ proc match*(s: string, pattern: TPeg,
c.origStart = start
result = rawMatch(s, pattern, start, c) == len(s)-start
proc matchLen*(s: string, pattern: TPeg, matches: var openarray[string],
proc matchLen*(s: string, pattern: TPeg, matches: var openArray[string],
start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
## the same as ``match``, but it returns the length of the match,
## if there is no match, -1 is returned. Note that a match length
@ -786,7 +786,7 @@ proc matchLen*(s: string, pattern: TPeg,
c.origStart = start
result = rawMatch(s, pattern, start, c)
proc find*(s: string, pattern: TPeg, matches: var openarray[string],
proc find*(s: string, pattern: TPeg, matches: var openArray[string],
start = 0): int {.nosideEffect, rtl, extern: "npegs$1Capture".} =
## returns the starting position of ``pattern`` in ``s`` and the captured
## substrings in the array ``matches``. If it does not match, nothing
@ -801,7 +801,7 @@ proc find*(s: string, pattern: TPeg, matches: var openarray[string],
return -1
# could also use the pattern here: (!P .)* P
proc findBounds*(s: string, pattern: TPeg, matches: var openarray[string],
proc findBounds*(s: string, pattern: TPeg, matches: var openArray[string],
start = 0): tuple[first, last: int] {.
nosideEffect, rtl, extern: "npegs$1Capture".} =
## returns the starting position and end position of ``pattern`` in ``s``
@ -869,7 +869,7 @@ template `=~`*(s: string, pattern: TPeg): bool =
##
bind maxSubpatterns
when not definedInScope(matches):
var matches {.inject.}: array[0..maxSubpatterns-1, string]
var matches {.inject.}: array[0..MaxSubpatterns-1, string]
match(s, pattern, matches)
# ------------------------- more string handling ------------------------------
@ -1074,14 +1074,14 @@ const
"@", "built-in", "escaped", "$", "$", "^"
]
proc HandleCR(L: var TPegLexer, pos: int): int =
proc handleCR(L: var TPegLexer, pos: int): int =
assert(L.buf[pos] == '\c')
inc(L.linenumber)
result = pos+1
if L.buf[result] == '\L': inc(result)
L.lineStart = result
proc HandleLF(L: var TPegLexer, pos: int): int =
proc handleLF(L: var TPegLexer, pos: int): int =
assert(L.buf[pos] == '\L')
inc(L.linenumber)
result = pos+1
@ -1117,45 +1117,45 @@ proc handleHexChar(c: var TPegLexer, xi: var int) =
of 'A'..'F':
xi = (xi shl 4) or (ord(c.buf[c.bufpos]) - ord('A') + 10)
inc(c.bufpos)
else: nil
else: discard
proc getEscapedChar(c: var TPegLexer, tok: var TToken) =
inc(c.bufpos)
case c.buf[c.bufpos]
of 'r', 'R', 'c', 'C':
add(tok.literal, '\c')
Inc(c.bufpos)
inc(c.bufpos)
of 'l', 'L':
add(tok.literal, '\L')
Inc(c.bufpos)
inc(c.bufpos)
of 'f', 'F':
add(tok.literal, '\f')
inc(c.bufpos)
of 'e', 'E':
add(tok.literal, '\e')
Inc(c.bufpos)
inc(c.bufpos)
of 'a', 'A':
add(tok.literal, '\a')
Inc(c.bufpos)
inc(c.bufpos)
of 'b', 'B':
add(tok.literal, '\b')
Inc(c.bufpos)
inc(c.bufpos)
of 'v', 'V':
add(tok.literal, '\v')
Inc(c.bufpos)
inc(c.bufpos)
of 't', 'T':
add(tok.literal, '\t')
Inc(c.bufpos)
inc(c.bufpos)
of 'x', 'X':
inc(c.bufpos)
var xi = 0
handleHexChar(c, xi)
handleHexChar(c, xi)
if xi == 0: tok.kind = tkInvalid
else: add(tok.literal, Chr(xi))
else: add(tok.literal, chr(xi))
of '0'..'9':
var val = ord(c.buf[c.bufpos]) - ord('0')
Inc(c.bufpos)
inc(c.bufpos)
var i = 1
while (i <= 3) and (c.buf[c.bufpos] in {'0'..'9'}):
val = val * 10 + ord(c.buf[c.bufpos]) - ord('0')
@ -1169,7 +1169,7 @@ proc getEscapedChar(c: var TPegLexer, tok: var TToken) =
tok.kind = tkInvalid
else:
add(tok.literal, c.buf[c.bufpos])
Inc(c.bufpos)
inc(c.bufpos)
proc skip(c: var TPegLexer) =
var pos = c.bufpos
@ -1177,14 +1177,14 @@ proc skip(c: var TPegLexer) =
while true:
case buf[pos]
of ' ', '\t':
Inc(pos)
inc(pos)
of '#':
while not (buf[pos] in {'\c', '\L', '\0'}): inc(pos)
of '\c':
pos = HandleCR(c, pos)
pos = handleCR(c, pos)
buf = c.buf
of '\L':
pos = HandleLF(c, pos)
pos = handleLF(c, pos)
buf = c.buf
else:
break # EndOfFile also leaves the loop
@ -1209,7 +1209,7 @@ proc getString(c: var TPegLexer, tok: var TToken) =
break
else:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
c.bufpos = pos
proc getDollar(c: var TPegLexer, tok: var TToken) =
@ -1250,7 +1250,7 @@ proc getCharSet(c: var TPegLexer, tok: var TToken) =
break
else:
ch = buf[pos]
Inc(pos)
inc(pos)
incl(tok.charset, ch)
if buf[pos] == '-':
if buf[pos+1] == ']':
@ -1270,7 +1270,7 @@ proc getCharSet(c: var TPegLexer, tok: var TToken) =
break
else:
ch2 = buf[pos]
Inc(pos)
inc(pos)
for i in ord(ch)+1 .. ord(ch2):
incl(tok.charset, chr(i))
c.bufpos = pos
@ -1281,7 +1281,7 @@ proc getSymbol(c: var TPegLexer, tok: var TToken) =
var buf = c.buf
while true:
add(tok.literal, buf[pos])
Inc(pos)
inc(pos)
if buf[pos] notin strutils.IdentChars: break
c.bufpos = pos
tok.kind = tkIdentifier
@ -1298,7 +1298,7 @@ proc getBuiltin(c: var TPegLexer, tok: var TToken) =
proc getTok(c: var TPegLexer, tok: var TToken) =
tok.kind = tkInvalid
tok.modifier = modNone
setlen(tok.literal, 0)
setLen(tok.literal, 0)
skip(c)
case c.buf[c.bufpos]
of '{':
@ -1315,14 +1315,14 @@ proc getTok(c: var TPegLexer, tok: var TToken) =
inc(c.bufpos)
add(tok.literal, '}')
of '[':
getCharset(c, tok)
getCharSet(c, tok)
of '(':
tok.kind = tkParLe
Inc(c.bufpos)
inc(c.bufpos)
add(tok.literal, '(')
of ')':
tok.kind = tkParRi
Inc(c.bufpos)
inc(c.bufpos)
add(tok.literal, ')')
of '.':
tok.kind = tkAny
@ -1347,7 +1347,7 @@ proc getTok(c: var TPegLexer, tok: var TToken) =
of "i": tok.modifier = modIgnoreCase
of "y": tok.modifier = modIgnoreStyle
of "v": tok.modifier = modVerbatim
else: nil
else: discard
setLen(tok.literal, 0)
if c.buf[c.bufpos] == '$':
getDollar(c, tok)
@ -1452,28 +1452,28 @@ proc modifiedTerm(s: string, m: TModifier): TPeg =
proc modifiedBackref(s: int, m: TModifier): TPeg =
case m
of modNone, modVerbatim: result = backRef(s)
of modIgnoreCase: result = backRefIgnoreCase(s)
of modIgnoreStyle: result = backRefIgnoreStyle(s)
of modNone, modVerbatim: result = backref(s)
of modIgnoreCase: result = backrefIgnoreCase(s)
of modIgnoreStyle: result = backrefIgnoreStyle(s)
proc builtin(p: var TPegParser): TPeg =
# do not use "y", "skip" or "i" as these would be ambiguous
case p.tok.literal
of "n": result = newLine()
of "d": result = charset({'0'..'9'})
of "D": result = charset({'\1'..'\xff'} - {'0'..'9'})
of "s": result = charset({' ', '\9'..'\13'})
of "S": result = charset({'\1'..'\xff'} - {' ', '\9'..'\13'})
of "w": result = charset({'a'..'z', 'A'..'Z', '_', '0'..'9'})
of "W": result = charset({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'})
of "a": result = charset({'a'..'z', 'A'..'Z'})
of "A": result = charset({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'})
of "d": result = charSet({'0'..'9'})
of "D": result = charSet({'\1'..'\xff'} - {'0'..'9'})
of "s": result = charSet({' ', '\9'..'\13'})
of "S": result = charSet({'\1'..'\xff'} - {' ', '\9'..'\13'})
of "w": result = charSet({'a'..'z', 'A'..'Z', '_', '0'..'9'})
of "W": result = charSet({'\1'..'\xff'} - {'a'..'z','A'..'Z','_','0'..'9'})
of "a": result = charSet({'a'..'z', 'A'..'Z'})
of "A": result = charSet({'\1'..'\xff'} - {'a'..'z', 'A'..'Z'})
of "ident": result = pegs.ident
of "letter": result = UnicodeLetter()
of "upper": result = UnicodeUpper()
of "lower": result = UnicodeLower()
of "title": result = UnicodeTitle()
of "white": result = UnicodeWhitespace()
of "letter": result = unicodeLetter()
of "upper": result = unicodeUpper()
of "lower": result = unicodeLower()
of "title": result = unicodeTitle()
of "white": result = unicodeWhitespace()
else: pegError(p, "unknown built-in: " & p.tok.literal)
proc token(terminal: TPeg, p: TPegParser): TPeg =
@ -1494,7 +1494,7 @@ proc primary(p: var TPegParser): TPeg =
of tkCurlyAt:
getTok(p)
return !*\primary(p).token(p)
else: nil
else: discard
case p.tok.kind
of tkIdentifier:
if p.identIsVerbatim:
@ -1505,7 +1505,7 @@ proc primary(p: var TPegParser): TPeg =
elif not arrowIsNextTok(p):
var nt = getNonTerminal(p, p.tok.literal)
incl(nt.flags, ntUsed)
result = nonTerminal(nt).token(p)
result = nonterminal(nt).token(p)
getTok(p)
else:
pegError(p, "expression expected, but found: " & p.tok.literal)
@ -1517,7 +1517,7 @@ proc primary(p: var TPegParser): TPeg =
of tkCharSet:
if '\0' in p.tok.charset:
pegError(p, "binary zero ('\\0') not allowed in character class")
result = charset(p.tok.charset).token(p)
result = charSet(p.tok.charset).token(p)
getTok(p)
of tkParLe:
getTok(p)
@ -1549,7 +1549,7 @@ proc primary(p: var TPegParser): TPeg =
of tkBackref:
var m = p.tok.modifier
if m == modNone: m = p.modifier
result = modifiedBackRef(p.tok.index, m).token(p)
result = modifiedBackref(p.tok.index, m).token(p)
if p.tok.index < 0 or p.tok.index > p.captures:
pegError(p, "invalid back reference index: " & $p.tok.index)
getTok(p)

View file

@ -119,7 +119,7 @@ proc next*(s: var TScgistate, timeout: int = -1): bool =
## request, if ``timeout`` is `-1` then this function will never time out.
## Returns `True` if a new request has been processed.
var rsocks = @[s.server]
if select(rsocks, timeout) == 1 and rsocks.len == 0:
if select(rsocks, timeout) == 1 and rsocks.len == 1:
new(s.client)
accept(s.server, s.client)
var L = 0

View file

@ -66,13 +66,15 @@ proc checkReply(smtp: var TSMTP, reply: string) =
if not line.string.startswith(reply):
quitExcpt(smtp, "Expected " & reply & " reply, got: " & line.string)
const compiledWithSsl = defined(ssl)
proc connect*(address: string, port = 25,
ssl = false, debug = false): TSMTP =
## Establishes a connection with a SMTP server.
## May fail with EInvalidReply or with a socket error.
result.sock = socket()
if ssl:
when defined(ssl):
when compiledWithSsl:
let ctx = newContext(verifyMode = CVerifyNone)
ctx.wrapSocket(result.sock)
else:

View file

@ -26,7 +26,7 @@
{.deadCodeElim: on.}
when hostos == "solaris":
when hostOS == "solaris":
{.passl: "-lsocket -lnsl".}
import os, parseutils
@ -132,17 +132,17 @@ type
ETimeout* = object of ESynch
let
InvalidSocket*: TSocket = nil ## invalid socket
invalidSocket*: TSocket = nil ## invalid socket
when defined(windows):
let
OSInvalidSocket = winlean.INVALID_SOCKET
osInvalidSocket = winlean.INVALID_SOCKET
else:
let
OSInvalidSocket = posix.INVALID_SOCKET
osInvalidSocket = posix.INVALID_SOCKET
proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket =
if fd == OSInvalidSocket:
if fd == osInvalidSocket:
return nil
new(result)
result.fd = fd
@ -154,9 +154,8 @@ proc newTSocket(fd: TSocketHandle, isBuff: bool): TSocket =
proc `==`*(a, b: TPort): bool {.borrow.}
## ``==`` for ports.
proc `$`*(p: TPort): string =
proc `$`*(p: TPort): string {.borrow.}
## returns the port number as a string
result = $ze(int16(p))
proc ntohl*(x: int32): int32 =
## Converts 32-bit integers from network to host byte order.
@ -188,22 +187,22 @@ proc htons*(x: int16): int16 =
result = sockets.ntohs(x)
when defined(Posix):
proc ToInt(domain: TDomain): cint =
proc toInt(domain: TDomain): cint =
case domain
of AF_UNIX: result = posix.AF_UNIX
of AF_INET: result = posix.AF_INET
of AF_INET6: result = posix.AF_INET6
else: nil
else: discard
proc ToInt(typ: TType): cint =
proc toInt(typ: TType): cint =
case typ
of SOCK_STREAM: result = posix.SOCK_STREAM
of SOCK_DGRAM: result = posix.SOCK_DGRAM
of SOCK_SEQPACKET: result = posix.SOCK_SEQPACKET
of SOCK_RAW: result = posix.SOCK_RAW
else: nil
else: discard
proc ToInt(p: TProtocol): cint =
proc toInt(p: TProtocol): cint =
case p
of IPPROTO_TCP: result = posix.IPPROTO_TCP
of IPPROTO_UDP: result = posix.IPPROTO_UDP
@ -211,16 +210,16 @@ when defined(Posix):
of IPPROTO_IPV6: result = posix.IPPROTO_IPV6
of IPPROTO_RAW: result = posix.IPPROTO_RAW
of IPPROTO_ICMP: result = posix.IPPROTO_ICMP
else: nil
else: discard
else:
proc toInt(domain: TDomain): cint =
result = toU16(ord(domain))
proc ToInt(typ: TType): cint =
proc toInt(typ: TType): cint =
result = cint(ord(typ))
proc ToInt(p: TProtocol): cint =
proc toInt(p: TProtocol): cint =
result = cint(ord(p))
proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
@ -231,7 +230,7 @@ proc socket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM,
when defined(Windows):
result = newTSocket(winlean.socket(ord(domain), ord(typ), ord(protocol)), buffered)
else:
result = newTSocket(posix.socket(ToInt(domain), ToInt(typ), ToInt(protocol)), buffered)
result = newTSocket(posix.socket(toInt(domain), toInt(typ), toInt(protocol)), buffered)
when defined(ssl):
CRYPTO_malloc_init()
@ -312,7 +311,8 @@ when defined(ssl):
newCTX.SSLCTXSetVerify(SSLVerifyNone, nil)
if newCTX == nil:
SSLError()
discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY)
newCTX.loadCertificates(certFile, keyFile)
return PSSLContext(newCTX)
@ -334,7 +334,7 @@ when defined(ssl):
if SSLSetFd(socket.sslHandle, socket.fd) != 1:
SSLError()
proc SocketError*(socket: TSocket, err: int = -1, async = false) =
proc socketError*(socket: TSocket, err: int = -1, async = false) =
## Raises proper errors based on return values of ``recv`` functions.
##
## If ``async`` is ``True`` no error will be thrown in the case when the
@ -363,28 +363,28 @@ proc SocketError*(socket: TSocket, err: int = -1, async = false) =
else: SSLError("Unknown Error")
if err == -1 and not (when defined(ssl): socket.isSSL else: false):
let lastError = OSLastError()
let lastError = osLastError()
if async:
when defined(windows):
if lastError.int32 == WSAEWOULDBLOCK:
return
else: OSError(lastError)
else: osError(lastError)
else:
if lastError.int32 == EAGAIN or lastError.int32 == EWOULDBLOCK:
return
else: OSError(lastError)
else: OSError(lastError)
else: osError(lastError)
else: osError(lastError)
proc listen*(socket: TSocket, backlog = SOMAXCONN) {.tags: [FReadIO].} =
## Marks ``socket`` as accepting connections.
## ``Backlog`` specifies the maximum length of the
## queue of pending connections.
if listen(socket.fd, cint(backlog)) < 0'i32: OSError(OSLastError())
if listen(socket.fd, cint(backlog)) < 0'i32: osError(osLastError())
proc invalidIp4(s: string) {.noreturn, noinline.} =
raise newException(EInvalidValue, "invalid ip4 address: " & s)
proc parseIp4*(s: string): biggestInt =
proc parseIp4*(s: string): BiggestInt =
## parses an IP version 4 in dotted decimal form like "a.b.c.d".
##
## This is equivalent to `inet_ntoa`:idx:.
@ -411,14 +411,14 @@ proc parseIp4*(s: string): biggestInt =
if j <= 0: invalidIp4(s)
inc(i, j)
if s[i] != '\0': invalidIp4(s)
result = biggestInt(a shl 24 or b shl 16 or c shl 8 or d)
result = BiggestInt(a shl 24 or b shl 16 or c shl 8 or d)
template gaiNim(a, p, h, list: expr): stmt =
block:
var gaiResult = getAddrInfo(a, $p, addr(h), list)
var gaiResult = getaddrinfo(a, $p, addr(h), list)
if gaiResult != 0'i32:
when defined(windows):
OSError(OSLastError())
osError(osLastError())
else:
raise newException(EOS, $gai_strerror(gaiResult))
@ -437,17 +437,17 @@ proc bindAddr*(socket: TSocket, port = TPort(0), address = "") {.
name.sin_port = sockets.htons(int16(port))
name.sin_addr.s_addr = sockets.htonl(INADDR_ANY)
if bindSocket(socket.fd, cast[ptr TSockAddr](addr(name)),
sizeof(name).TSockLen) < 0'i32:
OSError(OSLastError())
sizeof(name).TSocklen) < 0'i32:
osError(osLastError())
else:
var hints: TAddrInfo
var aiList: ptr TAddrInfo = nil
var hints: Taddrinfo
var aiList: ptr Taddrinfo = nil
hints.ai_family = toInt(AF_INET)
hints.ai_socktype = toInt(SOCK_STREAM)
hints.ai_protocol = toInt(IPPROTO_TCP)
gaiNim(address, port, hints, aiList)
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrLen.TSockLen) < 0'i32:
OSError(OSLastError())
if bindSocket(socket.fd, aiList.ai_addr, aiList.ai_addrlen.TSocklen) < 0'i32:
osError(osLastError())
proc getSockName*(socket: TSocket): TPort =
## returns the socket's associated port number.
@ -458,40 +458,40 @@ proc getSockName*(socket: TSocket): TPort =
name.sin_family = posix.AF_INET
#name.sin_port = htons(cint16(port))
#name.sin_addr.s_addr = htonl(INADDR_ANY)
var namelen = sizeof(name).TSockLen
var namelen = sizeof(name).TSocklen
if getsockname(socket.fd, cast[ptr TSockAddr](addr(name)),
addr(namelen)) == -1'i32:
OSError(OSLastError())
osError(osLastError())
result = TPort(sockets.ntohs(name.sin_port))
template acceptAddrPlain(noClientRet, successRet: expr,
sslImplementation: stmt): stmt {.immediate.} =
assert(client != nil)
var sockAddress: Tsockaddr_in
var addrLen = sizeof(sockAddress).TSockLen
var addrLen = sizeof(sockAddress).TSocklen
var sock = accept(server.fd, cast[ptr TSockAddr](addr(sockAddress)),
addr(addrLen))
if sock == OSInvalidSocket:
let err = OSLastError()
if sock == osInvalidSocket:
let err = osLastError()
when defined(windows):
if err.int32 == WSAEINPROGRESS:
client = InvalidSocket
client = invalidSocket
address = ""
when noClientRet.int == -1:
return
else:
return noClientRet
else: OSError(err)
else: osError(err)
else:
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
client = InvalidSocket
client = invalidSocket
address = ""
when noClientRet.int == -1:
return
else:
return noClientRet
else: OSError(err)
else: osError(err)
else:
client.fd = sock
client.isBuffered = server.isBuffered
@ -629,7 +629,7 @@ proc accept*(server: TSocket): TSocket {.deprecated, tags: [FReadIO].} =
proc close*(socket: TSocket) =
## closes a socket.
when defined(windows):
discard winlean.closeSocket(socket.fd)
discard winlean.closesocket(socket.fd)
else:
discard posix.close(socket.fd)
# TODO: These values should not be discarded. An EOS should be raised.
@ -670,7 +670,7 @@ proc getServByPort*(port: TPort, proto: string): TServent {.tags: [FReadIO].} =
result.port = TPort(s.s_port)
result.proto = $s.s_proto
proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
proc getHostByAddr*(ip: string): Thostent {.tags: [FReadIO].} =
## This function will lookup the hostname of an IP Address.
var myaddr: TInAddr
myaddr.s_addr = inet_addr(ip)
@ -678,43 +678,43 @@ proc getHostByAddr*(ip: string): THostEnt {.tags: [FReadIO].} =
when defined(windows):
var s = winlean.gethostbyaddr(addr(myaddr), sizeof(myaddr).cuint,
cint(sockets.AF_INET))
if s == nil: OSError(OSLastError())
if s == nil: osError(osLastError())
else:
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSockLen,
var s = posix.gethostbyaddr(addr(myaddr), sizeof(myaddr).TSocklen,
cint(posix.AF_INET))
if s == nil:
raise newException(EOS, $hStrError(h_errno))
raise newException(EOS, $hstrerror(h_errno))
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when defined(windows):
result.addrType = TDomain(s.h_addrtype)
result.addrtype = TDomain(s.h_addrtype)
else:
if s.h_addrtype == posix.AF_INET:
result.addrType = AF_INET
result.addrtype = AF_INET
elif s.h_addrtype == posix.AF_INET6:
result.addrType = AF_INET6
result.addrtype = AF_INET6
else:
raise newException(EOS, "unknown h_addrtype")
result.addrList = cstringArrayToSeq(s.h_addr_list)
result.length = int(s.h_length)
proc getHostByName*(name: string): THostEnt {.tags: [FReadIO].} =
proc getHostByName*(name: string): Thostent {.tags: [FReadIO].} =
## This function will lookup the IP address of a hostname.
when defined(Windows):
var s = winlean.gethostbyname(name)
else:
var s = posix.gethostbyname(name)
if s == nil: OSError(OSLastError())
if s == nil: osError(osLastError())
result.name = $s.h_name
result.aliases = cstringArrayToSeq(s.h_aliases)
when defined(windows):
result.addrType = TDomain(s.h_addrtype)
result.addrtype = TDomain(s.h_addrtype)
else:
if s.h_addrtype == posix.AF_INET:
result.addrType = AF_INET
result.addrtype = AF_INET
elif s.h_addrtype == posix.AF_INET6:
result.addrType = AF_INET6
result.addrtype = AF_INET6
else:
raise newException(EOS, "unknown h_addrtype")
result.addrList = cstringArrayToSeq(s.h_addr_list)
@ -724,10 +724,10 @@ proc getSockOptInt*(socket: TSocket, level, optname: int): int {.
tags: [FReadIO].} =
## getsockopt for integer options.
var res: cint
var size = sizeof(res).TSockLen
var size = sizeof(res).TSocklen
if getsockopt(socket.fd, cint(level), cint(optname),
addr(res), addr(size)) < 0'i32:
OSError(OSLastError())
osError(osLastError())
result = int(res)
proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
@ -735,8 +735,8 @@ proc setSockOptInt*(socket: TSocket, level, optname, optval: int) {.
## setsockopt for integer options.
var value = cint(optval)
if setsockopt(socket.fd, cint(level), cint(optname), addr(value),
sizeof(value).TSockLen) < 0'i32:
OSError(OSLastError())
sizeof(value).TSocklen) < 0'i32:
osError(osLastError())
proc toCInt(opt: TSOBool): cint =
case opt
@ -752,10 +752,10 @@ proc getSockOpt*(socket: TSocket, opt: TSOBool, level = SOL_SOCKET): bool {.
tags: [FReadIO].} =
## Retrieves option ``opt`` as a boolean value.
var res: cint
var size = sizeof(res).TSockLen
var size = sizeof(res).TSocklen
if getsockopt(socket.fd, cint(level), toCInt(opt),
addr(res), addr(size)) < 0'i32:
OSError(OSLastError())
osError(osLastError())
result = res != 0
proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET) {.
@ -763,8 +763,8 @@ proc setSockOpt*(socket: TSocket, opt: TSOBool, value: bool, level = SOL_SOCKET)
## Sets option ``opt`` to a boolean value specified by ``value``.
var valuei = cint(if value: 1 else: 0)
if setsockopt(socket.fd, cint(level), toCInt(opt), addr(valuei),
sizeof(valuei).TSockLen) < 0'i32:
OSError(OSLastError())
sizeof(valuei).TSocklen) < 0'i32:
osError(osLastError())
proc connect*(socket: TSocket, address: string, port = TPort(0),
af: TDomain = AF_INET) {.tags: [FReadIO].} =
@ -774,8 +774,8 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
## not do it.
##
## If ``socket`` is an SSL socket a handshake will be automatically performed.
var hints: TAddrInfo
var aiList: ptr TAddrInfo = nil
var hints: Taddrinfo
var aiList: ptr Taddrinfo = nil
hints.ai_family = toInt(af)
hints.ai_socktype = toInt(SOCK_STREAM)
hints.ai_protocol = toInt(IPPROTO_TCP)
@ -785,14 +785,14 @@ proc connect*(socket: TSocket, address: string, port = TPort(0),
var lastError: TOSErrorCode
var it = aiList
while it != nil:
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen) == 0'i32:
if connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen) == 0'i32:
success = true
break
else: lastError = OSLastError()
else: lastError = osLastError()
it = it.ai_next
freeaddrinfo(aiList)
if not success: OSError(lastError)
if not success: osError(lastError)
when defined(ssl):
if socket.isSSL:
@ -837,8 +837,8 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
##
## **Note**: For SSL sockets, the ``handshake`` procedure must be called
## whenever the socket successfully connects to a server.
var hints: TAddrInfo
var aiList: ptr TAddrInfo = nil
var hints: Taddrinfo
var aiList: ptr Taddrinfo = nil
hints.ai_family = toInt(af)
hints.ai_socktype = toInt(SOCK_STREAM)
hints.ai_protocol = toInt(IPPROTO_TCP)
@ -848,12 +848,12 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
var lastError: TOSErrorCode
var it = aiList
while it != nil:
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSockLen)
var ret = connect(socket.fd, it.ai_addr, it.ai_addrlen.TSocklen)
if ret == 0'i32:
success = true
break
else:
lastError = OSLastError()
lastError = osLastError()
when defined(windows):
# Windows EINTR doesn't behave same as POSIX.
if lastError.int32 == WSAEWOULDBLOCK:
@ -867,7 +867,7 @@ proc connectAsync*(socket: TSocket, name: string, port = TPort(0),
it = it.ai_next
freeaddrinfo(aiList)
if not success: OSError(lastError)
if not success: osError(lastError)
when defined(ssl):
if socket.isSSL:
socket.sslNoHandshake = true
@ -913,7 +913,7 @@ when defined(ssl):
else:
SSLError("Socket is not an SSL socket.")
proc timeValFromMilliseconds(timeout = 500): TTimeVal =
proc timeValFromMilliseconds(timeout = 500): Ttimeval =
if timeout != -1:
var seconds = timeout div 1000
result.tv_sec = seconds.int32
@ -929,7 +929,7 @@ proc pruneSocketSet(s: var seq[TSocket], fd: var TFdSet) =
var i = 0
var L = s.len
while i < L:
if FD_ISSET(s[i].fd, fd) != 0'i32:
if FD_ISSET(s[i].fd, fd) == 0'i32:
s[i] = s[L-1]
dec(L)
else:
@ -971,7 +971,7 @@ proc select*(readfds, writefds, exceptfds: var seq[TSocket],
if buffersFilled > 0:
return buffersFilled
var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout)
var rd, wr, ex: TFdSet
var m = 0
@ -994,7 +994,7 @@ proc select*(readfds, writefds: var seq[TSocket],
let buffersFilled = checkBuffer(readfds)
if buffersFilled > 0:
return buffersFilled
var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout)
var rd, wr: TFdSet
var m = 0
@ -1018,7 +1018,7 @@ proc selectWrite*(writefds: var seq[TSocket],
##
## ``timeout`` is specified in miliseconds and ``-1`` can be specified for
## an unlimited time.
var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout)
var wr: TFdSet
var m = 0
@ -1036,7 +1036,7 @@ proc select*(readfds: var seq[TSocket], timeout = 500): int =
let buffersFilled = checkBuffer(readfds)
if buffersFilled > 0:
return buffersFilled
var tv {.noInit.}: TTimeVal = timeValFromMilliseconds(timeout)
var tv {.noInit.}: Ttimeval = timeValFromMilliseconds(timeout)
var rd: TFdSet
var m = 0
@ -1059,7 +1059,7 @@ proc readIntoBuf(socket: TSocket, flags: int32): int =
else:
result = recv(socket.fd, addr(socket.buffer), cint(socket.buffer.high), flags)
if result <= 0:
socket.buflen = 0
socket.bufLen = 0
socket.currPos = 0
return result
socket.bufLen = result
@ -1143,7 +1143,7 @@ proc waitFor(socket: TSocket, waited: var float, timeout, size: int,
var s = @[socket]
var startTime = epochTime()
let selRet = select(s, timeout - int(waited * 1000.0))
if selRet < 0: OSError(OSLastError())
if selRet < 0: osError(osLastError())
if selRet != 1:
raise newException(ETimeout, "Call to '" & funcName & "' timed out.")
waited += (epochTime() - startTime)
@ -1181,7 +1181,7 @@ proc recv*(socket: TSocket, data: var string, size: int, timeout = -1): int =
result = recv(socket, cstring(data), size, timeout)
if result < 0:
data.setLen(0)
socket.SocketError(result)
socket.socketError(result)
data.setLen(result)
proc recvAsync*(socket: TSocket, data: var string, size: int): int =
@ -1195,7 +1195,7 @@ proc recvAsync*(socket: TSocket, data: var string, size: int): int =
result = recv(socket, cstring(data), size)
if result < 0:
data.setLen(0)
socket.SocketError(async = true)
socket.socketError(async = true)
result = -1
data.setLen(result)
@ -1259,10 +1259,10 @@ proc recvLine*(socket: TSocket, line: var TaintedString, timeout = -1): bool {.
if n > 0 and c == '\L':
discard recv(socket, addr(c), 1)
elif n <= 0: return false
addNlIfEmpty()
addNLIfEmpty()
return true
elif c == '\L':
addNlIfEmpty()
addNLIfEmpty()
return true
add(line.string, c)
@ -1292,18 +1292,18 @@ proc readLine*(socket: TSocket, line: var TaintedString, timeout = -1) {.
var c: char
discard waitFor(socket, waited, timeout, 1, "readLine")
var n = recv(socket, addr(c), 1)
if n < 0: OSError(OSLastError())
if n < 0: socket.socketError()
elif n == 0: return
if c == '\r':
discard waitFor(socket, waited, timeout, 1, "readLine")
n = peekChar(socket, c)
if n > 0 and c == '\L':
discard recv(socket, addr(c), 1)
elif n <= 0: OSError(OSLastError())
addNlIfEmpty()
elif n <= 0: socket.socketError()
addNLIfEmpty()
return
elif c == '\L':
addNlIfEmpty()
addNLIfEmpty()
return
add(line.string, c)
@ -1353,7 +1353,7 @@ proc readLineAsync*(socket: TSocket,
setLen(line.string, 0)
template errorOrNone =
socket.SocketError(async = true)
socket.socketError(async = true)
return ReadNone
while true:
@ -1386,7 +1386,7 @@ proc recv*(socket: TSocket): TaintedString {.tags: [FReadIO], deprecated.} =
var pos = 0
while true:
var bytesRead = recv(socket, addr(string(result)[pos]), bufSize-1)
if bytesRead == -1: OSError(OSLastError())
if bytesRead == -1: osError(osLastError())
setLen(result.string, pos + bytesRead)
if bytesRead != bufSize-1: break
# increase capacity:
@ -1455,22 +1455,22 @@ proc recvAsync*(socket: TSocket, s: var TaintedString): bool {.
else: SSLError("Unknown Error")
if bytesRead == -1 and not (when defined(ssl): socket.isSSL else: false):
let err = OSLastError()
let err = osLastError()
when defined(windows):
if err.int32 == WSAEWOULDBLOCK:
return False
else: OSError(err)
return false
else: osError(err)
else:
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return False
else: OSError(err)
return false
else: osError(err)
setLen(s.string, pos + bytesRead)
if bytesRead != bufSize-1: break
# increase capacity:
setLen(s.string, s.string.len + bufSize)
inc(pos, bytesRead)
result = True
result = true
proc recvFrom*(socket: TSocket, data: var string, length: int,
address: var string, port: var TPort, flags = 0'i32): int {.
@ -1489,8 +1489,8 @@ proc recvFrom*(socket: TSocket, data: var string, length: int,
# TODO: Buffered sockets
data.setLen(length)
var sockAddress: Tsockaddr_in
var addrLen = sizeof(sockAddress).TSockLen
result = recvFrom(socket.fd, cstring(data), length.cint, flags.cint,
var addrLen = sizeof(sockAddress).TSocklen
result = recvfrom(socket.fd, cstring(data), length.cint, flags.cint,
cast[ptr TSockAddr](addr(sockAddress)), addr(addrLen))
if result != -1:
@ -1498,7 +1498,7 @@ proc recvFrom*(socket: TSocket, data: var string, length: int,
address = $inet_ntoa(sockAddress.sin_addr)
port = ntohs(sockAddress.sin_port).TPort
proc recvFromAsync*(socket: TSocket, data: var String, length: int,
proc recvFromAsync*(socket: TSocket, data: var string, length: int,
address: var string, port: var TPort,
flags = 0'i32): bool {.tags: [FReadIO].} =
## Variant of ``recvFrom`` for non-blocking sockets. Unlike ``recvFrom``,
@ -1508,15 +1508,15 @@ proc recvFromAsync*(socket: TSocket, data: var String, length: int,
result = true
var callRes = recvFrom(socket, data, length, address, port, flags)
if callRes < 0:
let err = OSLastError()
let err = osLastError()
when defined(windows):
if err.int32 == WSAEWOULDBLOCK:
return False
else: OSError(err)
return false
else: osError(err)
else:
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return False
else: OSError(err)
return false
else: osError(err)
proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
## skips all the data that is pending for the socket
@ -1524,7 +1524,7 @@ proc skip*(socket: TSocket) {.tags: [FReadIO], deprecated.} =
## **Deprecated since version 0.9.2**: This function is not safe for use.
const bufSize = 1000
var buf = alloc(bufSize)
while recv(socket, buf, bufSize) == bufSize: nil
while recv(socket, buf, bufSize) == bufSize: discard
dealloc(buf)
proc skip*(socket: TSocket, size: int, timeout = -1) =
@ -1566,7 +1566,7 @@ proc send*(socket: TSocket, data: string) {.tags: [FWriteIO].} =
if socket.isSSL:
SSLError()
OSError(OSLastError())
osError(osLastError())
if sent != data.len:
raise newException(EOS, "Could not send all data.")
@ -1599,15 +1599,15 @@ proc sendAsync*(socket: TSocket, data: string): int {.tags: [FWriteIO].} =
else:
return
if result == -1:
let err = OSLastError()
let err = osLastError()
when defined(windows):
if err.int32 == WSAEINPROGRESS:
return 0
else: OSError(err)
else: osError(err)
else:
if err.int32 == EAGAIN or err.int32 == EWOULDBLOCK:
return 0
else: OSError(err)
else: osError(err)
proc trySend*(socket: TSocket, data: string): bool {.tags: [FWriteIO].} =
@ -1623,8 +1623,8 @@ proc sendTo*(socket: TSocket, address: string, port: TPort, data: pointer,
## this function will try each IP of that hostname.
##
## **Note:** This proc is not available for SSL sockets.
var hints: TAddrInfo
var aiList: ptr TAddrInfo = nil
var hints: Taddrinfo
var aiList: ptr Taddrinfo = nil
hints.ai_family = toInt(af)
hints.ai_socktype = toInt(SOCK_STREAM)
hints.ai_protocol = toInt(IPPROTO_TCP)
@ -1634,8 +1634,8 @@ proc sendTo*(socket: TSocket, address: string, port: TPort, data: pointer,
var success = false
var it = aiList
while it != nil:
result = sendTo(socket.fd, data, size.cint, flags.cint, it.ai_addr,
it.ai_addrlen.TSockLen)
result = sendto(socket.fd, data, size.cint, flags.cint, it.ai_addr,
it.ai_addrlen.TSocklen)
if result != -1'i32:
success = true
break
@ -1662,16 +1662,16 @@ when defined(Windows):
proc setBlocking(s: TSocket, blocking: bool) =
when defined(Windows):
var mode = clong(ord(not blocking)) # 1 for non-blocking, 0 for blocking
if ioctlsocket(TSocketHandle(s.fd), FIONBIO, addr(mode)) == -1:
OSError(OSLastError())
if ioctlsocket(s.fd, FIONBIO, addr(mode)) == -1:
osError(osLastError())
else: # BSD sockets
var x: int = fcntl(s.fd, F_GETFL, 0)
if x == -1:
OSError(OSLastError())
osError(osLastError())
else:
var mode = if blocking: x and not O_NONBLOCK else: x or O_NONBLOCK
if fcntl(s.fd, F_SETFL, mode) == -1:
OSError(OSLastError())
osError(osLastError())
s.nonblocking = not blocking
discard """ proc setReuseAddr*(s: TSocket) =
@ -1710,7 +1710,7 @@ proc isBlocking*(socket: TSocket): bool = not socket.nonblocking
## Determines whether ``socket`` is blocking.
when defined(Windows):
var wsa: TWSADATA
if WSAStartup(0x0101'i16, addr wsa) != 0: OSError(OSLastError())
var wsa: TWSAData
if wsaStartup(0x0101'i16, addr wsa) != 0: osError(osLastError())

View file

@ -249,7 +249,7 @@ proc fsClose(s: PStream) =
close(PFileStream(s).f)
PFileStream(s).f = nil
proc fsFlush(s: PStream) = flushFile(PFileStream(s).f)
proc fsAtEnd(s: PStream): bool = return EndOfFile(PFileStream(s).f)
proc fsAtEnd(s: PStream): bool = return endOfFile(PFileStream(s).f)
proc fsSetPosition(s: PStream, pos: int) = setFilePos(PFileStream(s).f, pos)
proc fsGetPosition(s: PStream): int = return int(getFilePos(PFileStream(s).f))
@ -277,11 +277,11 @@ proc newFileStream*(filename: string, mode: TFileMode): PFileStream =
## If the file cannot be opened, nil is returned. See the `system
## <system.html>`_ module for a list of available TFileMode enums.
var f: TFile
if Open(f, filename, mode): result = newFileStream(f)
if open(f, filename, mode): result = newFileStream(f)
when true:
nil
discard
else:
type
TFileHandle* = cint ## Operating system file handle

View file

@ -88,10 +88,10 @@ proc mustRehash(length, counter: int): bool =
proc nextTry(h, maxHash: THash): THash {.inline.} =
result = ((5 * h) + 1) and maxHash
proc RawGet(t: PStringTable, key: string): int =
proc rawGet(t: PStringTable, key: string): int =
var h: THash = myhash(t, key) and high(t.data) # start with real hash value
while not isNil(t.data[h].key):
if mycmp(t, t.data[h].key, key):
if myCmp(t, t.data[h].key, key):
return h
h = nextTry(h, high(t.data))
result = - 1
@ -100,7 +100,7 @@ proc `[]`*(t: PStringTable, key: string): string {.rtl, extern: "nstGet".} =
## retrieves the value at ``t[key]``. If `key` is not in `t`, "" is returned
## and no exception is raised. One can check with ``hasKey`` whether the key
## exists.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0: result = t.data[index].val
else: result = ""
@ -108,7 +108,7 @@ proc mget*(t: PStringTable, key: string): var string {.
rtl, extern: "nstTake".} =
## retrieves the location at ``t[key]``. If `key` is not in `t`, the
## ``EInvalidKey`` exception is raised.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0: result = t.data[index].val
else: raise newException(EInvalidKey, "key does not exist: " & key)
@ -116,31 +116,31 @@ proc hasKey*(t: PStringTable, key: string): bool {.rtl, extern: "nst$1".} =
## returns true iff `key` is in the table `t`.
result = rawGet(t, key) >= 0
proc RawInsert(t: PStringTable, data: var TKeyValuePairSeq, key, val: string) =
proc rawInsert(t: PStringTable, data: var TKeyValuePairSeq, key, val: string) =
var h: THash = myhash(t, key) and high(data)
while not isNil(data[h].key):
h = nextTry(h, high(data))
data[h].key = key
data[h].val = val
proc Enlarge(t: PStringTable) =
proc enlarge(t: PStringTable) =
var n: TKeyValuePairSeq
newSeq(n, len(t.data) * growthFactor)
for i in countup(0, high(t.data)):
if not isNil(t.data[i].key): RawInsert(t, n, t.data[i].key, t.data[i].val)
if not isNil(t.data[i].key): rawInsert(t, n, t.data[i].key, t.data[i].val)
swap(t.data, n)
proc `[]=`*(t: PStringTable, key, val: string) {.rtl, extern: "nstPut".} =
## puts a (key, value)-pair into `t`.
var index = RawGet(t, key)
var index = rawGet(t, key)
if index >= 0:
t.data[index].val = val
else:
if mustRehash(len(t.data), t.counter): Enlarge(t)
RawInsert(t, t.data, key, val)
if mustRehash(len(t.data), t.counter): enlarge(t)
rawInsert(t, t.data, key, val)
inc(t.counter)
proc RaiseFormatException(s: string) =
proc raiseFormatException(s: string) =
var e: ref EInvalidValue
new(e)
e.msg = "format string: key not found: " & s
@ -184,7 +184,7 @@ proc newStringTable*(keyValuePairs: varargs[tuple[key, val: string]],
## var mytab = newStringTable({"key1": "val1", "key2": "val2"},
## modeCaseInsensitive)
result = newStringTable(mode)
for key, val in items(keyvaluePairs): result[key] = val
for key, val in items(keyValuePairs): result[key] = val
proc `%`*(f: string, t: PStringTable, flags: set[TFormatFlag] = {}): string {.
rtl, extern: "nstFormat".} =

File diff suppressed because it is too large Load diff

View file

@ -27,15 +27,15 @@ when defined(windows):
var hTemp = GetStdHandle(STD_OUTPUT_HANDLE)
if DuplicateHandle(GetCurrentProcess(), hTemp, GetCurrentProcess(),
addr(conHandle), 0, 1, DUPLICATE_SAME_ACCESS) == 0:
OSError(OSLastError())
osError(osLastError())
proc getCursorPos(): tuple [x,y: int] =
var c: TCONSOLE_SCREEN_BUFFER_INFO
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: OSError(OSLastError())
var c: TCONSOLESCREENBUFFERINFO
if GetConsoleScreenBufferInfo(conHandle, addr(c)) == 0: osError(osLastError())
return (int(c.dwCursorPosition.x), int(c.dwCursorPosition.y))
proc getAttributes(): int16 =
var c: TCONSOLE_SCREEN_BUFFER_INFO
var c: TCONSOLESCREENBUFFERINFO
# workaround Windows bugs: try several times
if GetConsoleScreenBufferInfo(conHandle, addr(c)) != 0:
return c.wAttributes
@ -48,10 +48,10 @@ proc setCursorPos*(x, y: int) =
## sets the terminal's cursor to the (x,y) position. (0,0) is the
## upper left of the screen.
when defined(windows):
var c: TCoord
var c: TCOORD
c.x = int16(x)
c.y = int16(y)
if SetConsoleCursorPosition(conHandle, c) == 0: OSError(OSLastError())
if SetConsoleCursorPosition(conHandle, c) == 0: osError(osLastError())
else:
stdout.write("\e[" & $y & ';' & $x & 'f')
@ -59,12 +59,12 @@ proc setCursorXPos*(x: int) =
## sets the terminal's cursor to the x position. The y position is
## not changed.
when defined(windows):
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
var scrbuf: TCONSOLESCREENBUFFERINFO
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError())
var origin = scrbuf.dwCursorPosition
origin.x = int16(x)
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError())
else:
stdout.write("\e[" & $x & 'G')
@ -73,16 +73,16 @@ when defined(windows):
## sets the terminal's cursor to the y position. The x position is
## not changed. **Warning**: This is not supported on UNIX!
when defined(windows):
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
var scrbuf: TCONSOLESCREENBUFFERINFO
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError())
var origin = scrbuf.dwCursorPosition
origin.y = int16(y)
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError())
else:
nil
discard
proc CursorUp*(count=1) =
proc cursorUp*(count=1) =
## Moves the cursor up by `count` rows.
when defined(windows):
var p = getCursorPos()
@ -91,7 +91,7 @@ proc CursorUp*(count=1) =
else:
stdout.write("\e[" & $count & 'A')
proc CursorDown*(count=1) =
proc cursorDown*(count=1) =
## Moves the cursor down by `count` rows.
when defined(windows):
var p = getCursorPos()
@ -100,7 +100,7 @@ proc CursorDown*(count=1) =
else:
stdout.write("\e[" & $count & 'B')
proc CursorForward*(count=1) =
proc cursorForward*(count=1) =
## Moves the cursor forward by `count` columns.
when defined(windows):
var p = getCursorPos()
@ -109,7 +109,7 @@ proc CursorForward*(count=1) =
else:
stdout.write("\e[" & $count & 'C')
proc CursorBackward*(count=1) =
proc cursorBackward*(count=1) =
## Moves the cursor backward by `count` columns.
when defined(windows):
var p = getCursorPos()
@ -119,78 +119,78 @@ proc CursorBackward*(count=1) =
stdout.write("\e[" & $count & 'D')
when true:
nil
discard
else:
proc EraseLineEnd* =
proc eraseLineEnd* =
## Erases from the current cursor position to the end of the current line.
when defined(windows):
nil
discard
else:
stdout.write("\e[K")
proc EraseLineStart* =
proc eraseLineStart* =
## Erases from the current cursor position to the start of the current line.
when defined(windows):
nil
discard
else:
stdout.write("\e[1K")
proc EraseDown* =
proc eraseDown* =
## Erases the screen from the current line down to the bottom of the screen.
when defined(windows):
nil
discard
else:
stdout.write("\e[J")
proc EraseUp* =
proc eraseUp* =
## Erases the screen from the current line up to the top of the screen.
when defined(windows):
nil
discard
else:
stdout.write("\e[1J")
proc EraseLine* =
proc eraseLine* =
## Erases the entire current line.
when defined(windows):
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
var scrbuf: TCONSOLESCREENBUFFERINFO
var numwrote: DWORD
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError())
var origin = scrbuf.dwCursorPosition
origin.x = 0'i16
if SetConsoleCursorPosition(conHandle, origin) == 0: OSError(OSLastError())
if SetConsoleCursorPosition(conHandle, origin) == 0: osError(osLastError())
var ht = scrbuf.dwSize.Y - origin.Y
var wt = scrbuf.dwSize.X - origin.X
if FillConsoleOutputCharacter(hStdout,' ', ht*wt,
origin, addr(numwrote)) == 0:
OSError(OSLastError())
osError(osLastError())
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes, ht * wt,
scrbuf.dwCursorPosition, addr(numwrote)) == 0:
OSError(OSLastError())
osError(osLastError())
else:
stdout.write("\e[2K")
setCursorXPos(0)
proc EraseScreen* =
proc eraseScreen* =
## Erases the screen with the background colour and moves the cursor to home.
when defined(windows):
var scrbuf: TCONSOLE_SCREEN_BUFFER_INFO
var scrbuf: TCONSOLESCREENBUFFERINFO
var numwrote: DWORD
var origin: TCoord # is inititalized to 0, 0
var origin: TCOORD # is inititalized to 0, 0
var hStdout = conHandle
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: OSError(OSLastError())
if GetConsoleScreenBufferInfo(hStdout, addr(scrbuf)) == 0: osError(osLastError())
if FillConsoleOutputCharacter(hStdout, ' ', scrbuf.dwSize.X*scrbuf.dwSize.Y,
origin, addr(numwrote)) == 0:
OSError(OSLastError())
osError(osLastError())
if FillConsoleOutputAttribute(hStdout, scrbuf.wAttributes,
scrbuf.dwSize.X * scrbuf.dwSize.Y,
origin, addr(numwrote)) == 0:
OSError(OSLastError())
osError(osLastError())
setCursorXPos(0)
else:
stdout.write("\e[2J")
proc ResetAttributes* {.noconv.} =
proc resetAttributes* {.noconv.} =
## resets all attributes; it is advisable to register this as a quit proc
## with ``system.addQuitProc(resetAttributes)``.
when defined(windows):
@ -227,7 +227,7 @@ proc setStyle*(style: set[TStyle]) =
for s in items(style):
stdout.write("\e[" & $ord(s) & 'm')
proc WriteStyled*(txt: string, style: set[TStyle] = {styleBright}) =
proc writeStyled*(txt: string, style: set[TStyle] = {styleBright}) =
## writes the text `txt` in a given `style`.
when defined(windows):
var old = getAttributes()
@ -320,8 +320,8 @@ proc isatty*(f: TFile): bool =
proc styledEchoProcessArg(s: string) = write stdout, s
proc styledEchoProcessArg(style: TStyle) = setStyle({style})
proc styledEchoProcessArg(style: set[TStyle]) = setStyle style
proc styledEchoProcessArg(color: TForegroundColor) = setForeGroundColor color
proc styledEchoProcessArg(color: TBackgroundColor) = setBackGroundColor color
proc styledEchoProcessArg(color: TForegroundColor) = setForegroundColor color
proc styledEchoProcessArg(color: TBackgroundColor) = setBackgroundColor color
macro styledEcho*(m: varargs[expr]): stmt =
## to be documented.
@ -345,4 +345,4 @@ when isMainModule:
writeln(stdout, "ordinary text")
styledEcho("styled text ", {styleBright, styleBlink, styleUnderscore})

View file

@ -146,7 +146,7 @@ proc getGMTime*(t: TTime): TTimeInfo {.tags: [FTime], raises: [].}
## converts the calendar time `t` to broken-down time representation,
## expressed in Coordinated Universal Time (UTC).
proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime {.tags: [].}
proc timeInfoToTime*(timeInfo: TTimeInfo): TTime {.tags: [].}
## converts a broken-down time structure to
## calendar time representation. The function ignores the specified
## contents of the structure members `weekday` and `yearday` and recomputes
@ -211,7 +211,9 @@ proc initInterval*(miliseconds, seconds, minutes, hours, days, months,
result.months = months
result.years = years
proc isLeapYear(year: int): bool =
proc isLeapYear*(year: int): bool =
## returns true if ``year`` is a leap year
if year mod 400 == 0:
return true
elif year mod 100 == 0:
@ -221,7 +223,9 @@ proc isLeapYear(year: int): bool =
else:
return false
proc getDaysInMonth(month: TMonth, year: int): int =
proc getDaysInMonth*(month: TMonth, year: int): int =
## gets the amount of days in a ``month`` of a ``year``
# http://www.dispersiondesign.com/articles/time/number_of_days_in_a_month
case month
of mFeb: result = if isLeapYear(year): 29 else: 28
@ -246,7 +250,8 @@ proc toSeconds(a: TTimeInfo, interval: TTimeInterval): float =
else:
curMonth.inc()
result += float(newinterv.days * 24 * 60 * 60)
result += float(newinterv.minutes * 60 * 60)
result += float(newinterv.hours * 60 * 60)
result += float(newinterv.minutes * 60)
result += float(newinterv.seconds)
result += newinterv.miliseconds / 1000
@ -255,7 +260,7 @@ proc `+`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
##
## **Note:** This has been only briefly tested and it may not be
## very accurate.
let t = toSeconds(TimeInfoToTime(a))
let t = toSeconds(timeInfoToTime(a))
let secs = toSeconds(a, interval)
if a.tzname == "UTC":
result = getGMTime(fromSeconds(t + secs))
@ -267,7 +272,7 @@ proc `-`*(a: TTimeInfo, interval: TTimeInterval): TTimeInfo =
##
## **Note:** This has been only briefly tested, it is inaccurate especially
## when you subtract so much that you reach the Julian calendar.
let t = toSeconds(TimeInfoToTime(a))
let t = toSeconds(timeInfoToTime(a))
let secs = toSeconds(a, interval)
if a.tzname == "UTC":
result = getGMTime(fromSeconds(t - secs))
@ -296,7 +301,7 @@ when not defined(JS):
when not defined(JS):
# C wrapper:
type
structTM {.importc: "struct tm", final.} = object
StructTM {.importc: "struct tm", final.} = object
second {.importc: "tm_sec".},
minute {.importc: "tm_min".},
hour {.importc: "tm_hour".},
@ -307,7 +312,7 @@ when not defined(JS):
yearday {.importc: "tm_yday".},
isdst {.importc: "tm_isdst".}: cint
PTimeInfo = ptr structTM
PTimeInfo = ptr StructTM
PTime = ptr TTime
TClock {.importc: "clock_t".} = distinct int
@ -318,11 +323,11 @@ when not defined(JS):
importc: "gmtime", header: "<time.h>", tags: [].}
proc timec(timer: PTime): TTime {.
importc: "time", header: "<time.h>", tags: [].}
proc mktime(t: structTM): TTime {.
proc mktime(t: StructTM): TTime {.
importc: "mktime", header: "<time.h>", tags: [].}
proc asctime(tblock: structTM): CString {.
proc asctime(tblock: StructTM): cstring {.
importc: "asctime", header: "<time.h>", tags: [].}
proc ctime(time: PTime): CString {.
proc ctime(time: PTime): cstring {.
importc: "ctime", header: "<time.h>", tags: [].}
# strftime(s: CString, maxsize: int, fmt: CString, t: tm): int {.
# importc: "strftime", header: "<time.h>".}
@ -334,7 +339,7 @@ when not defined(JS):
clocksPerSec {.importc: "CLOCKS_PER_SEC", nodecl.}: int
# our own procs on top of that:
proc tmToTimeInfo(tm: structTM, local: bool): TTimeInfo =
proc tmToTimeInfo(tm: StructTM, local: bool): TTimeInfo =
const
weekDays: array [0..6, TWeekDay] = [
dSun, dMon, dTue, dWed, dThu, dFri, dSat]
@ -344,11 +349,11 @@ when not defined(JS):
monthday: int(tm.monthday),
month: TMonth(tm.month),
year: tm.year + 1900'i32,
weekday: weekDays[int(tm.weekDay)],
weekday: weekDays[int(tm.weekday)],
yearday: int(tm.yearday),
isDST: tm.isDST > 0,
isDST: tm.isdst > 0,
tzname: if local:
if tm.isDST > 0:
if tm.isdst > 0:
getTzname().DST
else:
getTzname().nonDST
@ -357,7 +362,7 @@ when not defined(JS):
timezone: if local: getTimezone() else: 0
)
proc timeInfoToTM(t: TTimeInfo): structTM =
proc timeInfoToTM(t: TTimeInfo): StructTM =
const
weekDays: array [TWeekDay, int8] = [1'i8,2'i8,3'i8,4'i8,5'i8,6'i8,0'i8]
result.second = t.second
@ -366,7 +371,7 @@ when not defined(JS):
result.monthday = t.monthday
result.month = ord(t.month)
result.year = t.year - 1900
result.weekday = weekDays[t.weekDay]
result.weekday = weekDays[t.weekday]
result.yearday = t.yearday
result.isdst = if t.isDST: 1 else: 0
@ -400,7 +405,7 @@ when not defined(JS):
# copying is needed anyway to provide reentrancity; thus
# the conversion is not expensive
proc TimeInfoToTime(timeInfo: TTimeInfo): TTime =
proc timeInfoToTime(timeInfo: TTimeInfo): TTime =
var cTimeInfo = timeInfo # for C++ we have to make a copy,
# because the header of mktime is broken in my version of libc
return mktime(timeInfoToTM(cTimeInfo))
@ -452,7 +457,7 @@ when not defined(JS):
result = toFloat(a.tv_sec) + toFloat(a.tv_usec)*0.00_0001
elif defined(windows):
var f: winlean.TFiletime
GetSystemTimeAsFileTime(f)
getSystemTimeAsFileTime(f)
var i64 = rdFileTime(f) - epochDiff
var secs = i64 div rateDiff
var subsecs = i64 mod rateDiff
@ -497,7 +502,7 @@ elif defined(JS):
result.weekday = weekDays[t.getUTCDay()]
result.yearday = 0
proc TimeInfoToTime*(timeInfo: TTimeInfo): TTime =
proc timeInfoToTime*(timeInfo: TTimeInfo): TTime =
result = internGetTime()
result.setSeconds(timeInfo.second)
result.setMinutes(timeInfo.minute)
@ -531,7 +536,7 @@ proc getDateStr*(): string {.rtl, extern: "nt$1", tags: [FTime].} =
## gets the current date as a string of the format ``YYYY-MM-DD``.
var ti = getLocalTime(getTime())
result = $ti.year & '-' & intToStr(ord(ti.month)+1, 2) &
'-' & intToStr(ti.monthDay, 2)
'-' & intToStr(ti.monthday, 2)
proc getClockStr*(): string {.rtl, extern: "nt$1", tags: [FTime].} =
## gets the current clock time as a string of the format ``HH:MM:SS``.
@ -592,7 +597,7 @@ proc format*(info: TTimeInfo, f: string): string =
result = ""
var i = 0
var currentF = ""
while True:
while true:
case f[i]
of ' ', '-', '/', ':', '\'', '\0', '(', ')', '[', ']', ',':
case currentF
@ -697,7 +702,7 @@ proc format*(info: TTimeInfo, f: string): string =
of "ZZZ":
result.add(info.tzname)
of "":
nil # Do nothing.
discard
else:
raise newException(EInvalidValue, "Invalid format string: " & currentF)

View file

@ -14,8 +14,8 @@
include "system/inclrtl"
type
irune = int # underlying type of TRune
TRune* = distinct irune ## type that can hold any Unicode character
IRune = int # underlying type of TRune
TRune* = distinct IRune ## type that can hold any Unicode character
TRune16* = distinct int16 ## 16 bit Unicode character
proc `<=%`*(a, b: TRune): bool = return int(a) <=% int(b)
@ -55,31 +55,31 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
result = TRune(ord(s[i]))
when doInc: inc(i)
elif ord(s[i]) shr 5 == 0b110:
assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
result = TRune((ord(s[i]) and (ones(5))) shl 6 or
(ord(s[i+1]) and ones(6)))
when doInc: inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6)))
when doInc: inc(i, 3)
elif ord(s[i]) shr 3 == 0b11110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6)))
when doInc: inc(i, 4)
elif ord(s[i]) shr 2 == 0b111110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
assert(ord(s[i+4]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
# assert(ord(s[i+4]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(2)) shl 24 or
(ord(s[i+1]) and ones(6)) shl 18 or
(ord(s[i+2]) and ones(6)) shl 12 or
@ -87,11 +87,11 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
(ord(s[i+4]) and ones(6)))
when doInc: inc(i, 5)
elif ord(s[i]) shr 1 == 0b1111110:
assert(ord(s[i+1]) shr 6 == 0b10)
assert(ord(s[i+2]) shr 6 == 0b10)
assert(ord(s[i+3]) shr 6 == 0b10)
assert(ord(s[i+4]) shr 6 == 0b10)
assert(ord(s[i+5]) shr 6 == 0b10)
# assert(ord(s[i+1]) shr 6 == 0b10)
# assert(ord(s[i+2]) shr 6 == 0b10)
# assert(ord(s[i+3]) shr 6 == 0b10)
# assert(ord(s[i+4]) shr 6 == 0b10)
# assert(ord(s[i+5]) shr 6 == 0b10)
result = TRune((ord(s[i]) and ones(1)) shl 30 or
(ord(s[i+1]) and ones(6)) shl 24 or
(ord(s[i+2]) and ones(6)) shl 18 or
@ -109,7 +109,7 @@ proc runeAt*(s: string, i: int): TRune =
proc toUTF8*(c: TRune): string {.rtl, extern: "nuc$1".} =
## converts a rune into its UTF8 representation
var i = irune(c)
var i = IRune(c)
if i <=% 127:
result = newString(1)
result[0] = chr(i)
@ -132,6 +132,10 @@ proc toUTF8*(c: TRune): string {.rtl, extern: "nuc$1".} =
result = newString(1)
result[0] = chr(i)
proc `$`*(rune: TRune): string =
## converts a rune to a string
rune.toUTF8
proc `$`*(runes: seq[TRune]): string =
## converts a sequence of runes to a string
result = ""
@ -1096,7 +1100,7 @@ const
0x01f1, 501, #
0x01f3, 499] #
proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
proc binarySearch(c: IRune, tab: openArray[IRune], len, stride: int): int =
var n = len
var t = 0
while n > 1:
@ -1114,29 +1118,29 @@ proc binarySearch(c: irune, tab: openArray[iRune], len, stride: int): int =
proc toLower*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
## Converts `c` into lower case. This works for any Unicode character.
## If possible, prefer `toLower` over `toUpper`.
var c = irune(c)
var p = binarySearch(c, tolowerRanges, len(toLowerRanges) div 3, 3)
var c = IRune(c)
var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
return TRune(c + tolowerRanges[p+2] - 500)
p = binarySearch(c, toLowerSinglets, len(toLowerSinglets) div 2, 2)
if p >= 0 and c == toLowerSinglets[p]:
return TRune(c + toLowerSinglets[p+1] - 500)
p = binarySearch(c, tolowerSinglets, len(tolowerSinglets) div 2, 2)
if p >= 0 and c == tolowerSinglets[p]:
return TRune(c + tolowerSinglets[p+1] - 500)
return TRune(c)
proc toUpper*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
## Converts `c` into upper case. This works for any Unicode character.
## If possible, prefer `toLower` over `toUpper`.
var c = irune(c)
var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3)
if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]:
return TRune(c + toUpperRanges[p+2] - 500)
p = binarySearch(c, toUpperSinglets, len(toUpperSinglets) div 2, 2)
if p >= 0 and c == toUpperSinglets[p]:
return TRune(c + toUpperSinglets[p+1] - 500)
var c = IRune(c)
var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
return TRune(c + toupperRanges[p+2] - 500)
p = binarySearch(c, toupperSinglets, len(toupperSinglets) div 2, 2)
if p >= 0 and c == toupperSinglets[p]:
return TRune(c + toupperSinglets[p+1] - 500)
return TRune(c)
proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
var c = irune(c)
var c = IRune(c)
var p = binarySearch(c, toTitleSinglets, len(toTitleSinglets) div 2, 2)
if p >= 0 and c == toTitleSinglets[p]:
return TRune(c + toTitleSinglets[p+1] - 500)
@ -1145,32 +1149,32 @@ proc toTitle*(c: TRune): TRune {.rtl, extern: "nuc$1", procvar.} =
proc isLower*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a lower case Unicode character
## If possible, prefer `isLower` over `isUpper`.
var c = irune(c)
var c = IRune(c)
# Note: toUpperRanges is correct here!
var p = binarySearch(c, toUpperRanges, len(toUpperRanges) div 3, 3)
if p >= 0 and c >= toUpperRanges[p] and c <= toUpperRanges[p+1]:
var p = binarySearch(c, toupperRanges, len(toupperRanges) div 3, 3)
if p >= 0 and c >= toupperRanges[p] and c <= toupperRanges[p+1]:
return true
p = binarySearch(c, toUpperSinglets, len(toUpperSinglets) div 2, 2)
if p >= 0 and c == toUpperSinglets[p]:
p = binarySearch(c, toupperSinglets, len(toupperSinglets) div 2, 2)
if p >= 0 and c == toupperSinglets[p]:
return true
proc isUpper*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a upper case Unicode character
## If possible, prefer `isLower` over `isUpper`.
var c = irune(c)
var c = IRune(c)
# Note: toLowerRanges is correct here!
var p = binarySearch(c, toLowerRanges, len(toLowerRanges) div 3, 3)
if p >= 0 and c >= toLowerRanges[p] and c <= toLowerRanges[p+1]:
var p = binarySearch(c, tolowerRanges, len(tolowerRanges) div 3, 3)
if p >= 0 and c >= tolowerRanges[p] and c <= tolowerRanges[p+1]:
return true
p = binarySearch(c, toLowerSinglets, len(toLowerSinglets) div 2, 2)
if p >= 0 and c == toLowerSinglets[p]:
p = binarySearch(c, tolowerSinglets, len(tolowerSinglets) div 2, 2)
if p >= 0 and c == tolowerSinglets[p]:
return true
proc isAlpha*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is an *alpha* Unicode character (i.e. a letter)
if isUpper(c) or isLower(c):
return true
var c = irune(c)
var c = IRune(c)
var p = binarySearch(c, alphaRanges, len(alphaRanges) div 2, 2)
if p >= 0 and c >= alphaRanges[p] and c <= alphaRanges[p+1]:
return true
@ -1183,7 +1187,7 @@ proc isTitle*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
proc isWhiteSpace*(c: TRune): bool {.rtl, extern: "nuc$1", procvar.} =
## returns true iff `c` is a Unicode whitespace character
var c = irune(c)
var c = IRune(c)
var p = binarySearch(c, spaceRanges, len(spaceRanges) div 2, 2)
if p >= 0 and c >= spaceRanges[p] and c <= spaceRanges[p+1]:
return true
@ -1210,7 +1214,7 @@ proc cmpRunesIgnoreCase*(a, b: string): int {.rtl, extern: "nuc$1", procvar.} =
# slow path:
fastRuneAt(a, i, ar)
fastRuneAt(b, j, br)
result = irune(toLower(ar)) - irune(toLower(br))
result = IRune(toLower(ar)) - IRune(toLower(br))
if result != 0: return
result = a.len - b.len

View file

@ -37,8 +37,8 @@ var
checkpoints: seq[string] = @[]
template TestSetupIMPL*: stmt {.immediate, dirty.} = nil
template TestTeardownIMPL*: stmt {.immediate, dirty.} = nil
template TestSetupIMPL*: stmt {.immediate, dirty.} = discard
template TestTeardownIMPL*: stmt {.immediate, dirty.} = discard
proc shouldRun(testName: string): bool =
result = true
@ -98,8 +98,12 @@ template fail* =
when not defined(ECMAScript):
if AbortOnError: quit(1)
TestStatusIMPL = FAILED
when defined(TestStatusIMPL):
TestStatusIMPL = FAILED
else:
program_result += 1
checkpoints = @[]
macro check*(conditions: stmt): stmt {.immediate.} =
@ -111,7 +115,8 @@ macro check*(conditions: stmt): stmt {.immediate.} =
counter = 0
template asgn(a, value: expr): stmt =
let a = value
var a = value # XXX: we need "var: var" here in order to
# preserve the semantics of var params
template print(name, value: expr): stmt =
when compiles(string($value)):
@ -121,7 +126,7 @@ macro check*(conditions: stmt): stmt {.immediate.} =
for i in 1 .. <exp.len:
if exp[i].kind notin nnkLiterals:
inc counter
var arg = newIdentNode(":p" & ($counter))
var arg = newIdentNode(":p" & $counter)
var argStr = exp[i].toStrLit
if exp[i].kind in nnkCallKinds: inspectArgs(exp[i])
argsAsgns.add getAst(asgn(arg, exp[i]))
@ -141,12 +146,14 @@ macro check*(conditions: stmt): stmt {.immediate.} =
var checkedStr = checked.toStrLit
inspectArgs(checked)
result = getAst(rewrite(checked, checked.lineinfo, checkedStr, argsAsgns, argsPrintOuts))
result = getAst(rewrite(checked, checked.lineinfo, checkedStr,
argsAsgns, argsPrintOuts))
of nnkStmtList:
result = newNimNode(nnkStmtList)
for i in countup(0, checked.len - 1):
result.add(newCall(!"check", checked[i]))
if checked[i].kind != nnkCommentStmt:
result.add(newCall(!"check", checked[i]))
else:
template rewrite(Exp, lineInfoLit: expr, expLit: string): stmt =
@ -170,7 +177,7 @@ macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.")
fail()
except errorTypes:
nil
discard
var body = exp[exp.len - 1]

View file

@ -96,7 +96,7 @@ proc parse(x: var TXmlParser, errors: var seq[string]): PXmlNode =
## &entity;
errors.add(errorMsg(x, "unknown entity: " & x.entityName))
next(x)
of xmlEof: nil
of xmlEof: discard
proc parseXml*(s: PStream, filename: string,
errors: var seq[string]): PXmlNode =
@ -110,7 +110,7 @@ proc parseXml*(s: PStream, filename: string,
of xmlElementOpen, xmlElementStart:
result = parse(x, errors)
break
of xmlComment, xmlWhitespace, xmlSpecial, xmlPI: nil # just skip it
of xmlComment, xmlWhitespace, xmlSpecial, xmlPI: discard # just skip it
of xmlError:
errors.add(errorMsg(x))
else:

View file

@ -144,7 +144,7 @@ proc reset*[T](obj: var T) {.magic: "Reset", noSideEffect.}
## be called before any possible `object branch transition`:idx:.
# for low and high the return type T may not be correct, but
# we handle that with compiler magic in SemLowHigh()
# we handle that with compiler magic in semLowHigh()
proc high*[T](x: T): T {.magic: "High", noSideEffect.}
## returns the highest possible index of an array, a sequence, a string or
## the highest possible value of an ordinal value `x`. As a special
@ -159,7 +159,7 @@ type
range*{.magic: "Range".}[T] ## Generic type to construct range types.
array*{.magic: "Array".}[I, T] ## Generic type to construct
## fixed-length arrays.
openarray*{.magic: "OpenArray".}[T] ## Generic type to construct open arrays.
openArray*{.magic: "OpenArray".}[T] ## Generic type to construct open arrays.
## Open arrays are implemented as a
## pointer to the array data and a
## length field.
@ -186,7 +186,10 @@ proc `..`*[T](b: T): TSlice[T] {.noSideEffect, inline.} =
when not defined(niminheritable):
{.pragma: inheritable.}
when not defined(JS) and not defined(NimrodVM):
const NoFakeVars* = defined(NimrodVM) ## true if the backend doesn't support \
## "fake variables" like 'var EBADF {.importc.}: cint'.
when not defined(JS):
type
TGenericSeq {.compilerproc, pure, inheritable.} = object
len, reserved: int
@ -195,14 +198,15 @@ when not defined(JS) and not defined(NimrodVM):
NimStringDesc {.compilerproc, final.} = object of TGenericSeq
data: array[0..100_000_000, char]
NimString = ptr NimStringDesc
when not defined(JS) and not defined(NimrodVM):
template space(s: PGenericSeq): int {.dirty.} =
s.reserved and not seqShallowFlag
include "system/hti"
type
Byte* = uInt8 ## this is an alias for ``uint8``, that is an unsigned
Byte* = uint8 ## this is an alias for ``uint8``, that is an unsigned
## int 8 bits wide.
Natural* = range[0..high(int)]
@ -335,13 +339,13 @@ type
TResult* = enum Failure, Success
proc sizeof*[T](x: T): natural {.magic: "SizeOf", noSideEffect.}
proc sizeof*[T](x: T): Natural {.magic: "SizeOf", noSideEffect.}
## returns the size of ``x`` in bytes. Since this is a low-level proc,
## its usage is discouraged - using ``new`` for the most cases suffices
## that one never needs to know ``x``'s size. As a special semantic rule,
## ``x`` may also be a type identifier (``sizeof(int)`` is valid).
proc `<`*[T](x: ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
proc `<`*[T](x: Ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
## unary ``<`` that can be used for nice looking excluding ranges:
##
## .. code-block:: nimrod
@ -349,22 +353,22 @@ proc `<`*[T](x: ordinal[T]): T {.magic: "UnaryLt", noSideEffect.}
##
## Semantically this is the same as ``pred``.
proc succ*[T](x: ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
proc succ*[T](x: Ordinal[T], y = 1): T {.magic: "Succ", noSideEffect.}
## returns the ``y``-th successor of the value ``x``. ``T`` has to be
## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
## or a compile time error occurs.
proc pred*[T](x: ordinal[T], y = 1): T {.magic: "Pred", noSideEffect.}
proc pred*[T](x: Ordinal[T], y = 1): T {.magic: "Pred", noSideEffect.}
## returns the ``y``-th predecessor of the value ``x``. ``T`` has to be
## an ordinal type. If such a value does not exist, ``EOutOfRange`` is raised
## or a compile time error occurs.
proc inc*[T](x: var ordinal[T], y = 1) {.magic: "Inc", noSideEffect.}
proc inc*[T](x: var Ordinal[T], y = 1) {.magic: "Inc", noSideEffect.}
## increments the ordinal ``x`` by ``y``. If such a value does not
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
## short notation for: ``x = succ(x, y)``.
proc dec*[T](x: var ordinal[T], y = 1) {.magic: "Dec", noSideEffect.}
proc dec*[T](x: var Ordinal[T], y = 1) {.magic: "Dec", noSideEffect.}
## decrements the ordinal ``x`` by ``y``. If such a value does not
## exist, ``EOutOfRange`` is raised or a compile time error occurs. This is a
## short notation for: ``x = pred(x, y)``.
@ -374,10 +378,10 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
## This is equivalent to ``s = @[]; setlen(s, len)``, but more
## efficient since no reallocation is needed.
##
## Note that the sequence will be filled with uninitialized entries, which
## can be a problem for sequences containing strings. After the creation of
## the sequence you should assign entries to the sequence instead of adding
## them. Example:
## Note that the sequence will be filled with zeroed entries, which can be a
## problem for sequences containing strings since their value will be
## ``nil``. After the creation of the sequence you should assign entries to
## the sequence instead of adding them. Example:
##
## .. code-block:: nimrod
## var inputStrings : seq[string]
@ -390,10 +394,10 @@ proc newSeq*[T](s: var seq[T], len: int) {.magic: "NewSeq", noSideEffect.}
proc newSeq*[T](len = 0): seq[T] =
## creates a new sequence of type ``seq[T]`` with length ``len``.
##
## Note that the sequence will be filled with uninitialized entries, which
## can be a problem for sequences containing strings. After the creation of
## the sequence you should assign entries to the sequence instead of adding
## them. Example:
## Note that the sequence will be filled with zeroed entries, which can be a
## problem for sequences containing strings since their value will be
## ``nil``. After the creation of the sequence you should assign entries to
## the sequence instead of adding them. Example:
##
## .. code-block:: nimrod
## var inputStrings = newSeq[string](3)
@ -418,10 +422,18 @@ proc incl*[T](x: var set[T], y: T) {.magic: "Incl", noSideEffect.}
## includes element ``y`` to the set ``x``. This is the same as
## ``x = x + {y}``, but it might be more efficient.
template incl*[T](s: var set[T], flags: set[T]) =
## includes the set of flags to the set ``x``.
s = s + flags
proc excl*[T](x: var set[T], y: T) {.magic: "Excl", noSideEffect.}
## excludes element ``y`` to the set ``x``. This is the same as
## ``x = x - {y}``, but it might be more efficient.
template excl*[T](s: var set[T], flags: set[T]) =
## excludes the set of flags to ``x``.
s = s - flags
proc card*[T](x: set[T]): int {.magic: "Card", noSideEffect.}
## returns the cardinality of the set ``x``, i.e. the number of elements
## in the set.
@ -435,38 +447,38 @@ proc chr*(u: range[0..255]): char {.magic: "Chr", noSideEffect.}
# --------------------------------------------------------------------------
# built-in operators
proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
## zero extends a smaller integer type to ``int``. This treats `x` as
## unsigned.
proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
## zero extends a smaller integer type to ``int``. This treats `x` as
## unsigned.
when not defined(JS):
proc ze*(x: int8): int {.magic: "Ze8ToI", noSideEffect.}
## zero extends a smaller integer type to ``int``. This treats `x` as
## unsigned.
proc ze*(x: int16): int {.magic: "Ze16ToI", noSideEffect.}
## zero extends a smaller integer type to ``int``. This treats `x` as
## unsigned.
proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze64*(x: int8): int64 {.magic: "Ze8ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze64*(x: int16): int64 {.magic: "Ze16ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
## (This is the case on 64 bit processors.)
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
## from `x`.
proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
## 16 bits from `x`.
proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect.}
## treats `x` as unsigned and converts it to an ``int32`` by taking the
## last 32 bits from `x`.
proc ze64*(x: int32): int64 {.magic: "Ze32ToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned.
proc ze64*(x: int): int64 {.magic: "ZeIToI64", noSideEffect.}
## zero extends a smaller integer type to ``int64``. This treats `x` as
## unsigned. Does nothing if the size of an ``int`` is the same as ``int64``.
## (This is the case on 64 bit processors.)
proc toU8*(x: int): int8 {.magic: "ToU8", noSideEffect.}
## treats `x` as unsigned and converts it to a byte by taking the last 8 bits
## from `x`.
proc toU16*(x: int): int16 {.magic: "ToU16", noSideEffect.}
## treats `x` as unsigned and converts it to an ``int16`` by taking the last
## 16 bits from `x`.
proc toU32*(x: int64): int32 {.magic: "ToU32", noSideEffect.}
## treats `x` as unsigned and converts it to an ``int32`` by taking the
## last 32 bits from `x`.
# integer calculations:
proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
@ -584,46 +596,46 @@ proc `<` *(x, y: int64): bool {.magic: "LtI64", noSideEffect.}
## Returns true iff `x` is less than `y`.
type
IntMax32 = bool|int|int8|int16|int32
IntMax32 = int|int8|int16|int32
proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: Int64): Int64 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: int64): int64 {.magic: "AddU", noSideEffect.}
## treats `x` and `y` as unsigned and adds them. The result is truncated to
## fit into the result. This implements modulo arithmetic. No overflow
## errors are possible.
proc `-%` *(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: Int64): Int64 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: int64): int64 {.magic: "SubU", noSideEffect.}
## treats `x` and `y` as unsigned and subtracts them. The result is
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `*%` *(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: Int64): Int64 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: int64): int64 {.magic: "MulU", noSideEffect.}
## treats `x` and `y` as unsigned and multiplies them. The result is
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `/%` *(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: Int64): Int64 {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: int64): int64 {.magic: "DivU", noSideEffect.}
## treats `x` and `y` as unsigned and divides them. The result is
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `%%` *(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.}
proc `%%` *(x, y: Int64): Int64 {.magic: "ModU", noSideEffect.}
proc `%%` *(x, y: int64): int64 {.magic: "ModU", noSideEffect.}
## treats `x` and `y` as unsigned and compute the modulo of `x` and `y`.
## The result is truncated to fit into the result.
## This implements modulo arithmetic.
## No overflow errors are possible.
proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: Int64): bool {.magic: "LeU64", noSideEffect.}
proc `<=%` *(x, y: int64): bool {.magic: "LeU64", noSideEffect.}
## treats `x` and `y` as unsigned and compares them.
## Returns true iff ``unsigned(x) <= unsigned(y)``.
proc `<%` *(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: Int64): bool {.magic: "LtU64", noSideEffect.}
proc `<%` *(x, y: int64): bool {.magic: "LtU64", noSideEffect.}
## treats `x` and `y` as unsigned and compares them.
## Returns true iff ``unsigned(x) < unsigned(y)``.
@ -728,10 +740,10 @@ proc contains*[T](s: TSlice[T], value: T): bool {.noSideEffect, inline.} =
result = s.a <= value and value <= s.b
template `in` * (x, y: expr): expr {.immediate.} = contains(y, x)
template `not_in` * (x, y: expr): expr {.immediate.} = not contains(y, x)
template `notin` * (x, y: expr): expr {.immediate.} = not contains(y, x)
proc `is` *[T, S](x: T, y: S): bool {.magic: "Is", noSideEffect.}
template `is_not` *(x, y: expr): expr {.immediate.} = not (x is y)
template `isnot` *(x, y: expr): expr {.immediate.} = not (x is y)
proc `of` *[T, S](x: T, y: S): bool {.magic: "Of", noSideEffect.}
@ -923,13 +935,16 @@ proc quit*(errorcode: int = QuitSuccess) {.
## The proc ``quit(QuitSuccess)`` is called implicitly when your nimrod
## program finishes without incident. A raised unhandled exception is
## equivalent to calling ``quit(QuitFailure)``.
##
## Note that this is a *runtime* call and using ``quit`` inside a macro won't
## have any compile time effect. If you need to stop the compiler inside a
## macro, use the ``error`` or ``fatal`` pragmas.
template sysAssert(cond: bool, msg: string) =
when defined(useSysAssert):
if not cond:
echo "[SYSASSERT] ", msg
quit 1
nil
include "system/inclrtl"
@ -999,11 +1014,17 @@ type
## platform-dependant in general.
when defined(windows):
type clong* {.importc: "long", nodecl.} = int32
## This is the same as the type ``long`` in *C*.
type
clong* {.importc: "long", nodecl.} = int32
## This is the same as the type ``long`` in *C*.
culong* {.importc: "unsigned long", nodecl.} = uint32
## This is the same as the type ``unsigned long`` in *C*.
else:
type clong* {.importc: "long", nodecl.} = int
## This is the same as the type ``long`` in *C*.
type
clong* {.importc: "long", nodecl.} = int
## This is the same as the type ``long`` in *C*.
culong* {.importc: "unsigned long", nodecl.} = uint
## This is the same as the type ``unsigned long`` in *C*.
type # these work for most platforms:
cchar* {.importc: "char", nodecl.} = char
@ -1032,8 +1053,6 @@ type # these work for most platforms:
## This is the same as the type ``unsigned short`` in *C*.
cuint* {.importc: "int", nodecl.} = uint32
## This is the same as the type ``unsigned int`` in *C*.
culong* {.importc: "unsigned long", nodecl.} = uint
## This is the same as the type ``unsigned long`` in *C*.
culonglong* {.importc: "unsigned long long", nodecl.} = uint64
## This is the same as the type ``unsigned long long`` in *C*.
@ -1042,10 +1061,10 @@ type # these work for most platforms:
## high value is large enough to disable bounds checking in practice.
## Use `cstringArrayToSeq` to convert it into a ``seq[string]``.
PFloat32* = ptr Float32 ## an alias for ``ptr float32``
PFloat64* = ptr Float64 ## an alias for ``ptr float64``
PInt64* = ptr Int64 ## an alias for ``ptr int64``
PInt32* = ptr Int32 ## an alias for ``ptr int32``
PFloat32* = ptr float32 ## an alias for ``ptr float32``
PFloat64* = ptr float64 ## an alias for ``ptr float64``
PInt64* = ptr int64 ## an alias for ``ptr int64``
PInt32* = ptr int32 ## an alias for ``ptr int32``
proc toFloat*(i: int): float {.
magic: "ToFloat", noSideEffect, importc: "toFloat".}
@ -1053,7 +1072,7 @@ proc toFloat*(i: int): float {.
## fails, `EInvalidValue` is raised. However, on most platforms the
## conversion cannot fail.
proc toBiggestFloat*(i: biggestint): biggestfloat {.
proc toBiggestFloat*(i: BiggestInt): BiggestFloat {.
magic: "ToBiggestFloat", noSideEffect, importc: "toBiggestFloat".}
## converts an biggestint `i` into a ``biggestfloat``. If the conversion
## fails, `EInvalidValue` is raised. However, on most platforms the
@ -1065,7 +1084,7 @@ proc toInt*(f: float): int {.
## rounds `f` if it does not contain an integer value. If the conversion
## fails (because `f` is infinite for example), `EInvalidValue` is raised.
proc toBiggestInt*(f: biggestfloat): biggestint {.
proc toBiggestInt*(f: BiggestFloat): BiggestInt {.
magic: "ToBiggestInt", noSideEffect, importc: "toBiggestInt".}
## converts a biggestfloat `f` into a ``biggestint``. Conversion
## rounds `f` if it does not contain an integer value. If the conversion
@ -1107,19 +1126,19 @@ proc substr*(s: string, first, last: int): string {.
## or `limit`:idx: a string's length.
when not defined(nimrodVM):
proc zeroMem*(p: Pointer, size: int) {.importc, noDecl.}
proc zeroMem*(p: pointer, size: int) {.importc, noDecl.}
## overwrites the contents of the memory at ``p`` with the value 0.
## Exactly ``size`` bytes will be overwritten. Like any procedure
## dealing with raw memory this is *unsafe*.
proc copyMem*(dest, source: Pointer, size: int) {.
proc copyMem*(dest, source: pointer, size: int) {.
importc: "memcpy", header: "<string.h>".}
## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory
## regions may not overlap. Like any procedure dealing with raw
## memory this is *unsafe*.
proc moveMem*(dest, source: Pointer, size: int) {.
proc moveMem*(dest, source: pointer, size: int) {.
importc: "memmove", header: "<string.h>".}
## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory
@ -1127,14 +1146,14 @@ when not defined(nimrodVM):
## and is thus somewhat more safe than ``copyMem``. Like any procedure
## dealing with raw memory this is still *unsafe*, though.
proc equalMem*(a, b: Pointer, size: int): bool {.
proc equalMem*(a, b: pointer, size: int): bool {.
importc: "equalMem", noDecl, noSideEffect.}
## compares the memory blocks ``a`` and ``b``. ``size`` bytes will
## be compared. If the blocks are equal, true is returned, false
## otherwise. Like any procedure dealing with raw memory this is
## *unsafe*.
when hostOs != "standalone":
when hostOS != "standalone":
proc alloc*(size: int): pointer {.noconv, rtl, tags: [].}
## allocates a new memory block with at least ``size`` bytes. The
## block has to be freed with ``realloc(block, 0)`` or
@ -1149,7 +1168,7 @@ when not defined(nimrodVM):
## containing zero, so it is somewhat safer than ``alloc``.
## The allocated memory belongs to its allocating thread!
## Use `allocShared0` to allocate from a shared heap.
proc realloc*(p: Pointer, newsize: int): pointer {.noconv, rtl, tags: [].}
proc realloc*(p: pointer, newsize: int): pointer {.noconv, rtl, tags: [].}
## grows or shrinks a given memory block. If p is **nil** then a new
## memory block is returned. In either way the block has at least
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
@ -1157,7 +1176,7 @@ when not defined(nimrodVM):
## be freed with ``dealloc``.
## The allocated memory belongs to its allocating thread!
## Use `reallocShared` to reallocate from a shared heap.
proc dealloc*(p: Pointer) {.noconv, rtl, tags: [].}
proc dealloc*(p: pointer) {.noconv, rtl, tags: [].}
## frees the memory allocated with ``alloc``, ``alloc0`` or
## ``realloc``. This procedure is dangerous! If one forgets to
## free the memory a leak occurs; if one tries to access freed
@ -1178,13 +1197,13 @@ when not defined(nimrodVM):
## ``reallocShared(block, 0)`` or ``deallocShared(block)``.
## The block is initialized with all bytes
## containing zero, so it is somewhat safer than ``allocShared``.
proc reallocShared*(p: Pointer, newsize: int): pointer {.noconv, rtl.}
proc reallocShared*(p: pointer, newsize: int): pointer {.noconv, rtl.}
## grows or shrinks a given memory block on the heap. If p is **nil**
## then a new memory block is returned. In either way the block has at least
## ``newsize`` bytes. If ``newsize == 0`` and p is not **nil**
## ``reallocShared`` calls ``deallocShared(p)``. In other cases the
## block has to be freed with ``deallocShared``.
proc deallocShared*(p: Pointer) {.noconv, rtl.}
proc deallocShared*(p: pointer) {.noconv, rtl.}
## frees the memory allocated with ``allocShared``, ``allocShared0`` or
## ``reallocShared``. This procedure is dangerous! If one forgets to
## free the memory a leak occurs; if one tries to access freed
@ -1229,7 +1248,7 @@ proc `$` *(x: char): string {.magic: "CharToStr", noSideEffect.}
## The stingify operator for a character argument. Returns `x`
## converted to a string.
proc `$` *(x: Cstring): string {.magic: "CStrToStr", noSideEffect.}
proc `$` *(x: cstring): string {.magic: "CStrToStr", noSideEffect.}
## The stingify operator for a CString argument. Returns `x`
## converted to a string.
@ -1251,13 +1270,13 @@ proc getRefcount*[T](x: seq[T]): int {.importc: "getRefcount", noSideEffect.}
## retrieves the reference count of an heap-allocated object. The
## value is implementation-dependent.
# new constants:
const
inf* {.magic: "Inf".} = 1.0 / 0.0
Inf* {.magic: "Inf".} = 1.0 / 0.0
## contains the IEEE floating point value of positive infinity.
neginf* {.magic: "NegInf".} = -inf
NegInf* {.magic: "NegInf".} = -Inf
## contains the IEEE floating point value of negative infinity.
nan* {.magic: "NaN".} = 0.0 / 0.0
NaN* {.magic: "NaN".} = 0.0 / 0.0
## contains an IEEE floating point value of *Not A Number*. Note
## that you cannot compare a floating point value to this value
## and expect a reasonable result - use the `classify` procedure
@ -1311,7 +1330,7 @@ iterator `||`*[S, T](a: S, b: T, annotation=""): T {.
## such isn't aware of the parallelism in your code! Be careful! Later
## versions of ``||`` will get proper support by Nimrod's code generator
## and GC.
nil
discard
{.push stackTrace:off.}
proc min*(x, y: int): int {.magic: "MinI", noSideEffect.} =
@ -1364,7 +1383,7 @@ proc clamp*[T](x, a, b: T): T =
if x > b: return b
return x
iterator items*[T](a: openarray[T]): T {.inline.} =
iterator items*[T](a: openArray[T]): T {.inline.} =
## iterates over each item of `a`.
var i = 0
while i < len(a):
@ -1417,7 +1436,7 @@ iterator items*(E: typedesc[enum]): E =
for v in low(E)..high(E):
yield v
iterator pairs*[T](a: openarray[T]): tuple[key: int, val: T] {.inline.} =
iterator pairs*[T](a: openArray[T]): tuple[key: int, val: T] {.inline.} =
## iterates over each item of `a`. Yields ``(index, a[index])`` pairs.
var i = 0
while i < len(a):
@ -1943,30 +1962,28 @@ when not defined(JS): #and not defined(NimrodVM):
## The standard output stream.
stderr* {.importc: "stderr", header: "<stdio.h>".}: TFile
## The standard error stream.
##
## Note: In my opinion, this should not be used -- the concept of a
## separate error stream is a design flaw of UNIX. A separate *message
## stream* is a good idea, but since it is named ``stderr`` there are few
## programs out there that distinguish properly between ``stdout`` and
## ``stderr``. So, that's what you get if you don't name your variables
## appropriately. It also annoys people if redirection
## via ``>output.txt`` does not work because the program writes
## to ``stderr``.
proc Open*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): Bool {.tags: [].}
when defined(useStdoutAsStdmsg):
template stdmsg*: TFile = stdout
else:
template stdmsg*: TFile = stderr
## Template which expands to either stdout or stderr depending on
## `useStdoutAsStdmsg` compile-time switch.
proc open*(f: var TFile, filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): bool {.tags: [].}
## Opens a file named `filename` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
## This throws no exception if the file could not be opened.
proc Open*(f: var TFile, filehandle: TFileHandle,
mode: TFileMode = fmRead): Bool {.tags: [].}
proc open*(f: var TFile, filehandle: TFileHandle,
mode: TFileMode = fmRead): bool {.tags: [].}
## Creates a ``TFile`` from a `filehandle` with given `mode`.
##
## Default mode is readonly. Returns true iff the file could be opened.
proc Open*(filename: string,
proc open*(filename: string,
mode: TFileMode = fmRead, bufSize: int = -1): TFile =
## Opens a file named `filename` with given `mode`.
##
@ -1983,16 +2000,16 @@ when not defined(JS): #and not defined(NimrodVM):
##
## Default mode is readonly. Returns true iff the file could be reopened.
proc Close*(f: TFile) {.importc: "fclose", header: "<stdio.h>", tags: [].}
proc close*(f: TFile) {.importc: "fclose", header: "<stdio.h>", tags: [].}
## Closes the file.
proc EndOfFile*(f: TFile): Bool {.tags: [].}
proc endOfFile*(f: TFile): bool {.tags: [].}
## Returns true iff `f` is at the end.
proc readChar*(f: TFile): char {.
importc: "fgetc", header: "<stdio.h>", tags: [FReadIO].}
## Reads a single character from the stream `f`.
proc FlushFile*(f: TFile) {.
proc flushFile*(f: TFile) {.
importc: "fflush", header: "<stdio.h>", tags: [FWriteIO].}
## Flushes `f`'s buffer.
@ -2012,10 +2029,10 @@ when not defined(JS): #and not defined(NimrodVM):
proc write*(f: TFile, r: float32) {.tags: [FWriteIO].}
proc write*(f: TFile, i: int) {.tags: [FWriteIO].}
proc write*(f: TFile, i: biggestInt) {.tags: [FWriteIO].}
proc write*(f: TFile, r: biggestFloat) {.tags: [FWriteIO].}
proc write*(f: TFile, i: BiggestInt) {.tags: [FWriteIO].}
proc write*(f: TFile, r: BiggestFloat) {.tags: [FWriteIO].}
proc write*(f: TFile, s: string) {.tags: [FWriteIO].}
proc write*(f: TFile, b: Bool) {.tags: [FWriteIO].}
proc write*(f: TFile, b: bool) {.tags: [FWriteIO].}
proc write*(f: TFile, c: char) {.tags: [FWriteIO].}
proc write*(f: TFile, c: cstring) {.tags: [FWriteIO].}
proc write*(f: TFile, a: varargs[string, `$`]) {.tags: [FWriteIO].}
@ -2041,13 +2058,13 @@ when not defined(JS): #and not defined(NimrodVM):
proc getFileSize*(f: TFile): int64 {.tags: [FReadIO].}
## retrieves the file size (in bytes) of `f`.
proc ReadBytes*(f: TFile, a: var openarray[int8], start, len: int): int {.
proc readBytes*(f: TFile, a: var openArray[int8], start, len: int): int {.
tags: [FReadIO].}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
proc ReadChars*(f: TFile, a: var openarray[char], start, len: int): int {.
proc readChars*(f: TFile, a: var openArray[char], start, len: int): int {.
tags: [FReadIO].}
## reads `len` bytes into the buffer `a` starting at ``a[start]``. Returns
## the actual number of bytes that have been read which may be less than
@ -2058,13 +2075,13 @@ when not defined(JS): #and not defined(NimrodVM):
## the actual number of bytes that have been read which may be less than
## `len` (if not as many bytes are remaining), but not greater.
proc writeBytes*(f: TFile, a: openarray[int8], start, len: int): int {.
proc writeBytes*(f: TFile, a: openArray[int8], start, len: int): int {.
tags: [FWriteIO].}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
## of an error.
proc writeChars*(f: tFile, a: openarray[char], start, len: int): int {.
proc writeChars*(f: TFile, a: openArray[char], start, len: int): int {.
tags: [FWriteIO].}
## writes the bytes of ``a[start..start+len-1]`` to the file `f`. Returns
## the number of actual written bytes, which may be less than `len` in case
@ -2186,7 +2203,7 @@ when not defined(JS): #and not defined(NimrodVM):
const
GenericSeqSize = (2 * sizeof(int))
proc getDiscriminant(aa: Pointer, n: ptr TNimNode): int =
proc getDiscriminant(aa: pointer, n: ptr TNimNode): int =
sysAssert(n.kind == nkCase, "getDiscriminant: node != nkCase")
var d: int
var a = cast[TAddress](aa)
@ -2197,7 +2214,7 @@ when not defined(JS): #and not defined(NimrodVM):
else: sysAssert(false, "getDiscriminant: invalid n.typ.size")
return d
proc selectBranch(aa: Pointer, n: ptr TNimNode): ptr TNimNode =
proc selectBranch(aa: pointer, n: ptr TNimNode): ptr TNimNode =
var discr = getDiscriminant(aa, n)
if discr <% n.len:
result = n.sons[discr]
@ -2219,8 +2236,19 @@ when not defined(JS): #and not defined(NimrodVM):
when hostOS != "standalone":
iterator lines*(filename: string): TaintedString {.tags: [FReadIO].} =
## Iterate over any line in the file named `filename`.
## If the file does not exist `EIO` is raised.
## Iterates over any line in the file named `filename`.
##
## If the file does not exist `EIO` is raised. The trailing newline
## character(s) are removed from the iterated lines. Example:
##
## .. code-block:: nimrod
## import strutils
##
## proc transformLetters(filename: string) =
## var buffer = ""
## for line in filename.lines:
## buffer.add(line.replace("a", "0") & '\x0A')
## writeFile(filename, buffer)
var f = open(filename)
var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield res
@ -2228,6 +2256,17 @@ when not defined(JS): #and not defined(NimrodVM):
iterator lines*(f: TFile): TaintedString {.tags: [FReadIO].} =
## Iterate over any line in the file `f`.
##
## The trailing newline character(s) are removed from the iterated lines.
## Example:
##
## .. code-block:: nimrod
## proc countZeros(filename: TFile): tuple[lines, zeros: int] =
## for line in filename.lines:
## for letter in line:
## if letter == '0':
## result.zeros += 1
## result.lines += 1
var res = TaintedString(newStringOfCap(80))
while f.readLine(res): yield res
@ -2294,29 +2333,29 @@ when not defined(JS): #and not defined(NimrodVM):
elif defined(JS):
# Stubs:
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = nil
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} = discard
proc GC_disable() = nil
proc GC_enable() = nil
proc GC_fullCollect() = nil
proc GC_setStrategy(strategy: TGC_Strategy) = nil
proc GC_enableMarkAndSweep() = nil
proc GC_disableMarkAndSweep() = nil
proc GC_disable() = discard
proc GC_enable() = discard
proc GC_fullCollect() = discard
proc GC_setStrategy(strategy: TGC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard
proc GC_getStatistics(): string = return ""
proc getOccupiedMem(): int = return -1
proc getFreeMem(): int = return -1
proc getTotalMem(): int = return -1
proc dealloc(p: pointer) = nil
proc alloc(size: int): pointer = nil
proc alloc0(size: int): pointer = nil
proc realloc(p: Pointer, newsize: int): pointer = nil
proc dealloc(p: pointer) = discard
proc alloc(size: int): pointer = discard
proc alloc0(size: int): pointer = discard
proc realloc(p: Pointer, newsize: int): pointer = discard
proc allocShared(size: int): pointer = nil
proc allocShared0(size: int): pointer = nil
proc deallocShared(p: pointer) = nil
proc reallocShared(p: pointer, newsize: int): pointer = nil
proc allocShared(size: int): pointer = discard
proc allocShared0(size: int): pointer = discard
proc deallocShared(p: pointer) = discard
proc reallocShared(p: pointer, newsize: int): pointer = discard
when defined(JS):
include "system/jssys"
@ -2451,11 +2490,11 @@ proc staticRead*(filename: string): string {.magic: "Slurp".}
## ``slurp`` is an alias for ``staticRead``.
proc gorge*(command: string, input = ""): string {.
magic: "StaticExec".} = nil
magic: "StaticExec".} = discard
## This is an alias for ``staticExec``.
proc staticExec*(command: string, input = ""): string {.
magic: "StaticExec".} = nil
magic: "StaticExec".} = discard
## Executes an external process at compile-time.
## if `input` is not an empty string, it will be passed as a standard input
## to the executed program.
@ -2522,7 +2561,7 @@ proc instantiationInfo*(index = -1, fullPaths = false): tuple[
## $pos.line, astToStr(code)]
## assert false, "A test expecting failure succeeded?"
## except exception:
## nil
## discard
##
## proc tester(pos: int): int =
## let
@ -2541,7 +2580,7 @@ proc raiseAssert*(msg: string) {.noinline.} =
sysFatal(EAssertionFailed, msg)
when true:
proc hiddenRaiseAssert(msg: string) {.raises: [], tags: [].} =
proc failedAssertImpl*(msg: string) {.raises: [], tags: [].} =
# trick the compiler to not list ``EAssertionFailed`` when called
# by ``assert``.
type THide = proc (msg: string) {.noinline, raises: [], noSideEffect,
@ -2554,11 +2593,11 @@ template assert*(cond: bool, msg = "") =
## raises an ``EAssertionFailure`` exception. However, the compiler may
## not generate any code at all for ``assert`` if it is advised to do so.
## Use ``assert`` for debugging purposes only.
bind instantiationInfo, hiddenRaiseAssert
bind instantiationInfo
mixin failedAssertImpl
when compileOption("assertions"):
{.line.}:
if not cond:
hiddenRaiseAssert(astToStr(cond) & ' ' & msg)
if not cond: failedAssertImpl(astToStr(cond) & ' ' & msg)
template doAssert*(cond: bool, msg = "") =
## same as `assert` but is always turned on and not affected by the
@ -2571,9 +2610,9 @@ template doAssert*(cond: bool, msg = "") =
when not defined(nimhygiene):
{.pragma: inject.}
template onFailedAssert*(msg: expr, code: stmt): stmt =
## Sets an assertion failure handler that will intercept any assert statements
## following `onFailedAssert` in the current lexical scope.
template onFailedAssert*(msg: expr, code: stmt): stmt {.dirty, immediate.} =
## Sets an assertion failure handler that will intercept any assert
## statements following `onFailedAssert` in the current lexical scope.
## Can be defined multiple times in a single function.
##
## .. code-block:: nimrod
@ -2590,8 +2629,8 @@ template onFailedAssert*(msg: expr, code: stmt): stmt =
##
## assert(...)
##
template raiseAssert(msgIMPL: string): stmt =
let msg {.inject.} = msgIMPL
template failedAssertImpl(msgIMPL: string): stmt {.dirty, immediate.} =
let msg = msgIMPL
code
proc shallow*[T](s: var seq[T]) {.noSideEffect, inline.} =
@ -2615,12 +2654,13 @@ type
PNimrodNode* {.magic: "PNimrodNode".} = ref TNimrodNode
## represents a Nimrod AST node. Macros operate on this type.
template eval*(blk: stmt): stmt =
## executes a block of code at compile time just as if it was a macro
## optionally, the block can return an AST tree that will replace the
## eval expression
macro payload: stmt {.gensym.} = blk
payload()
when false:
template eval*(blk: stmt): stmt =
## executes a block of code at compile time just as if it was a macro
## optionally, the block can return an AST tree that will replace the
## eval expression
macro payload: stmt {.gensym.} = blk
payload()
when hostOS != "standalone":
proc insert*(x: var string, item: string, i = 0) {.noSideEffect.} =
@ -2636,7 +2676,7 @@ when hostOS != "standalone":
x[j+i] = item[j]
inc(j)
proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} =
proc compiles*(x): bool {.magic: "Compiles", noSideEffect.} =
## Special compile-time procedure that checks whether `x` can be compiled
## without any semantic error.
## This can be used to check whether a type supports some operation:
@ -2644,7 +2684,7 @@ proc compiles*(x: expr): bool {.magic: "Compiles", noSideEffect.} =
## .. code-block:: Nimrod
## when not compiles(3 + 4):
## echo "'+' for integers is available"
nil
discard
when defined(initDebugger):
initDebugger()
@ -2668,5 +2708,30 @@ proc locals*(): TObject {.magic: "Locals", noSideEffect.} =
## in the current scope. This is quite fast as it does not rely
## on any debug or runtime information. Note that in constrast to what
## the official signature says, the return type is not ``TObject`` but a
## tuple of a structure that depends on the current scope.
nil
## tuple of a structure that depends on the current scope. Example:
##
## .. code-block:: nimrod
## proc testLocals() =
## var
## a = "something"
## b = 4
## c = locals()
## d = "super!"
##
## b = 1
## for name, value in fieldPairs(c):
## echo "name ", name, " with value ", value
## echo "B is ", b
## # -> name a with value something
## # -> name b with value 4
## # -> B is 1
discard
when not defined(booting):
type
semistatic*[T] = static[T] | T
# indicates a param of proc specialized for each static value,
# but also accepting run-time values
template isStatic*(x): expr = compiles(static(x))
# checks whether `x` is a value known at compile-time

View file

@ -59,15 +59,16 @@ elif defined(windows):
MEM_DECOMMIT = 0x4000
MEM_RELEASE = 0x8000
proc VirtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
proc virtualAlloc(lpAddress: pointer, dwSize: int, flAllocationType,
flProtect: int32): pointer {.
header: "<windows.h>", stdcall.}
header: "<windows.h>", stdcall, importc: "VirtualAlloc".}
proc VirtualFree(lpAddress: pointer, dwSize: int,
dwFreeType: int32) {.header: "<windows.h>", stdcall.}
proc virtualFree(lpAddress: pointer, dwSize: int,
dwFreeType: int32) {.header: "<windows.h>", stdcall,
importc: "VirtualFree".}
proc osAllocPages(size: int): pointer {.inline.} =
result = VirtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT,
result = virtualAlloc(nil, size, MEM_RESERVE or MEM_COMMIT,
PAGE_READWRITE)
if result == nil: raiseOutOfMem()
@ -78,7 +79,7 @@ elif defined(windows):
# Windows :-(. We have to live with MEM_DECOMMIT instead.
# Well that used to be the case but MEM_DECOMMIT fragments the address
# space heavily, so we now treat Windows as a strange unmap target.
when reallyOsDealloc: VirtualFree(p, 0, MEM_RELEASE)
when reallyOsDealloc: virtualFree(p, 0, MEM_RELEASE)
#VirtualFree(p, size, MEM_DECOMMIT)
else:
@ -108,7 +109,7 @@ type
data: TTrunkBuckets
type
TAlignType = biggestFloat
TAlignType = BiggestFloat
TFreeCell {.final, pure.} = object
next: ptr TFreeCell # next free cell in chunk (overlaid with refcount)
zeroField: int # 0 means cell is not used (overlaid with typ field)
@ -251,36 +252,36 @@ proc llDeallocAll(a: var TMemRegion) =
osDeallocPages(it, PageSize)
it = next
proc IntSetGet(t: TIntSet, key: int): PTrunk =
proc intSetGet(t: TIntSet, key: int): PTrunk =
var it = t.data[key and high(t.data)]
while it != nil:
if it.key == key: return it
it = it.next
result = nil
proc IntSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
result = IntSetGet(t, key)
proc intSetPut(a: var TMemRegion, t: var TIntSet, key: int): PTrunk =
result = intSetGet(t, key)
if result == nil:
result = cast[PTrunk](llAlloc(a, sizeof(result[])))
result.next = t.data[key and high(t.data)]
t.data[key and high(t.data)] = result
result.key = key
proc Contains(s: TIntSet, key: int): bool =
var t = IntSetGet(s, key shr TrunkShift)
proc contains(s: TIntSet, key: int): bool =
var t = intSetGet(s, key shr TrunkShift)
if t != nil:
var u = key and TrunkMask
result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
else:
result = false
proc Incl(a: var TMemRegion, s: var TIntSet, key: int) =
var t = IntSetPut(a, s, key shr TrunkShift)
proc incl(a: var TMemRegion, s: var TIntSet, key: int) =
var t = intSetPut(a, s, key shr TrunkShift)
var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc Excl(s: var TIntSet, key: int) =
var t = IntSetGet(s, key shr TrunkShift)
proc excl(s: var TIntSet, key: int) =
var t = intSetGet(s, key shr TrunkShift)
if t != nil:
var u = key and TrunkMask
t.bits[u shr IntShift] = t.bits[u shr IntShift] and not
@ -387,7 +388,7 @@ proc freeOsChunks(a: var TMemRegion, p: pointer, size: int) =
#c_fprintf(c_stdout, "[Alloc] back to OS: %ld\n", size)
proc isAccessible(a: TMemRegion, p: pointer): bool {.inline.} =
result = Contains(a.chunkStarts, pageIndex(p))
result = contains(a.chunkStarts, pageIndex(p))
proc contains[T](list, x: T): bool =
var it = list
@ -403,7 +404,7 @@ proc writeFreeList(a: TMemRegion) =
it, it.next, it.prev)
it = it.next
proc ListAdd[T](head: var T, c: T) {.inline.} =
proc listAdd[T](head: var T, c: T) {.inline.} =
sysAssert(c notin head, "listAdd 1")
sysAssert c.prev == nil, "listAdd 2"
sysAssert c.next == nil, "listAdd 3"
@ -413,7 +414,7 @@ proc ListAdd[T](head: var T, c: T) {.inline.} =
head.prev = c
head = c
proc ListRemove[T](head: var T, c: T) {.inline.} =
proc listRemove[T](head: var T, c: T) {.inline.} =
sysAssert(c in head, "listRemove")
if c == head:
head = c.next
@ -443,7 +444,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
if isAccessible(a, ri) and chunkUnused(ri):
sysAssert(not isSmallChunk(ri), "freeBigChunk 3")
if not isSmallChunk(ri):
ListRemove(a.freeChunksList, cast[PBigChunk](ri))
listRemove(a.freeChunksList, cast[PBigChunk](ri))
inc(c.size, ri.size)
excl(a.chunkStarts, pageIndex(ri))
when coalescLeft:
@ -453,7 +454,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
if isAccessible(a, le) and chunkUnused(le):
sysAssert(not isSmallChunk(le), "freeBigChunk 5")
if not isSmallChunk(le):
ListRemove(a.freeChunksList, cast[PBigChunk](le))
listRemove(a.freeChunksList, cast[PBigChunk](le))
inc(le.size, c.size)
excl(a.chunkStarts, pageIndex(c))
c = cast[PBigChunk](le)
@ -461,7 +462,7 @@ proc freeBigChunk(a: var TMemRegion, c: PBigChunk) =
if c.size < ChunkOsReturn or weirdUnmap:
incl(a, a.chunkStarts, pageIndex(c))
updatePrevSize(a, c, c.size)
ListAdd(a.freeChunksList, c)
listAdd(a.freeChunksList, c)
c.used = false
else:
freeOsChunks(a, c, c.size)
@ -477,7 +478,7 @@ proc splitChunk(a: var TMemRegion, c: PBigChunk, size: int) =
updatePrevSize(a, c, rest.size)
c.size = size
incl(a, a.chunkStarts, pageIndex(rest))
ListAdd(a.freeChunksList, rest)
listAdd(a.freeChunksList, rest)
proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
# use first fit for now:
@ -488,10 +489,10 @@ proc getBigChunk(a: var TMemRegion, size: int): PBigChunk =
while result != nil:
sysAssert chunkUnused(result), "getBigChunk 3"
if result.size == size:
ListRemove(a.freeChunksList, result)
listRemove(a.freeChunksList, result)
break search
elif result.size > size:
ListRemove(a.freeChunksList, result)
listRemove(a.freeChunksList, result)
splitChunk(a, result, size)
break search
result = result.next
@ -520,11 +521,18 @@ proc allocInv(a: TMemRegion): bool =
for s in low(a.freeSmallChunks)..high(a.freeSmallChunks):
var c = a.freeSmallChunks[s]
while c != nil:
if c.next == c: return false
if c.size != s * MemAlign: return false
if c.next == c:
echo "[SYSASSERT] c.next == c"
return false
if c.size != s * MemAlign:
echo "[SYSASSERT] c.size != s * MemAlign"
return false
var it = c.freeList
while it != nil:
if it.zeroField != 0: return false
if it.zeroField != 0:
echo "[SYSASSERT] it.zeroField != 0"
c_printf("%ld %p\n", it.zeroField, it)
return false
it = it.next
c = c.next
result = true
@ -549,7 +557,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
c.free = SmallChunkSize - smallChunkOverhead() - size
c.next = nil
c.prev = nil
ListAdd(a.freeSmallChunks[s], c)
listAdd(a.freeSmallChunks[s], c)
result = addr(c.data)
sysAssert((cast[TAddress](result) and (MemAlign-1)) == 0, "rawAlloc 4")
else:
@ -573,7 +581,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
sysAssert(allocInv(a), "rawAlloc: before c.free < size")
if c.free < size:
sysAssert(allocInv(a), "rawAlloc: before listRemove test")
ListRemove(a.freeSmallChunks[s], c)
listRemove(a.freeSmallChunks[s], c)
sysAssert(allocInv(a), "rawAlloc: end listRemove test")
sysAssert(((cast[TAddress](result) and PageMask) - smallChunkOverhead()) %%
size == 0, "rawAlloc 21")
@ -591,6 +599,7 @@ proc rawAlloc(a: var TMemRegion, requestedSize: int): pointer =
add(a, a.root, cast[TAddress](result), cast[TAddress](result)+%size)
sysAssert(isAccessible(a, result), "rawAlloc 14")
sysAssert(allocInv(a), "rawAlloc: end")
when logAlloc: cprintf("rawAlloc: %ld %p\n", requestedSize, result)
proc rawAlloc0(a: var TMemRegion, requestedSize: int): pointer =
result = rawAlloc(a, requestedSize)
@ -619,12 +628,12 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
# check if it is not in the freeSmallChunks[s] list:
if c.free < s:
# add it to the freeSmallChunks[s] array:
ListAdd(a.freeSmallChunks[s div memAlign], c)
listAdd(a.freeSmallChunks[s div MemAlign], c)
inc(c.free, s)
else:
inc(c.free, s)
if c.free == SmallChunkSize-smallChunkOverhead():
ListRemove(a.freeSmallChunks[s div memAlign], c)
listRemove(a.freeSmallChunks[s div MemAlign], c)
c.size = SmallChunkSize
freeBigChunk(a, cast[PBigChunk](c))
sysAssert(((cast[TAddress](p) and PageMask) - smallChunkOverhead()) %%
@ -638,6 +647,7 @@ proc rawDealloc(a: var TMemRegion, p: pointer) =
del(a, a.root, cast[int](addr(c.data)))
freeBigChunk(a, c)
sysAssert(allocInv(a), "rawDealloc: end")
when logAlloc: cprintf("rawDealloc: %p\n", p)
proc isAllocatedPtr(a: TMemRegion, p: pointer): bool =
if isAccessible(a, p):
@ -729,7 +739,7 @@ proc realloc(allocator: var TMemRegion, p: pointer, newsize: int): pointer =
proc deallocOsPages(a: var TMemRegion) =
# we free every 'ordinarily' allocated page by iterating over the page bits:
for p in elements(a.chunkStarts):
var page = cast[PChunk](p shl pageShift)
var page = cast[PChunk](p shl PageShift)
when not weirdUnmap:
var size = if page.size < PageSize: PageSize else: page.size
osDeallocPages(page, size)
@ -750,8 +760,8 @@ proc getOccupiedMem(a: TMemRegion): int {.inline.} =
# ---------------------- thread memory region -------------------------------
template InstantiateForRegion(allocator: expr) =
when false:
template instantiateForRegion(allocator: expr) =
when defined(fulldebug):
proc interiorAllocatedPtr*(p: pointer): pointer =
result = interiorAllocatedPtr(allocator, p)
@ -792,13 +802,13 @@ template InstantiateForRegion(allocator: expr) =
when hasThreadSupport:
var sharedHeap: TMemRegion
var heapLock: TSysLock
InitSysLock(HeapLock)
initSysLock(heapLock)
proc allocShared(size: int): pointer =
when hasThreadSupport:
AcquireSys(HeapLock)
acquireSys(heapLock)
result = alloc(sharedHeap, size)
ReleaseSys(HeapLock)
releaseSys(heapLock)
else:
result = alloc(size)
@ -808,17 +818,17 @@ template InstantiateForRegion(allocator: expr) =
proc deallocShared(p: pointer) =
when hasThreadSupport:
AcquireSys(HeapLock)
acquireSys(heapLock)
dealloc(sharedHeap, p)
ReleaseSys(HeapLock)
releaseSys(heapLock)
else:
dealloc(p)
proc reallocShared(p: pointer, newsize: int): pointer =
when hasThreadSupport:
AcquireSys(HeapLock)
acquireSys(heapLock)
result = realloc(sharedHeap, p, newsize)
ReleaseSys(HeapLock)
releaseSys(heapLock)
else:
result = realloc(p, newsize)

View file

@ -13,12 +13,12 @@
{.push hints:off}
proc c_strcmp(a, b: CString): cint {.header: "<string.h>",
proc c_strcmp(a, b: cstring): cint {.header: "<string.h>",
noSideEffect, importc: "strcmp".}
proc c_memcmp(a, b: CString, size: int): cint {.header: "<string.h>",
proc c_memcmp(a, b: cstring, size: int): cint {.header: "<string.h>",
noSideEffect, importc: "memcmp".}
proc c_memcpy(a, b: CString, size: int) {.header: "<string.h>", importc: "memcpy".}
proc c_strlen(a: CString): int {.header: "<string.h>",
proc c_memcpy(a, b: cstring, size: int) {.header: "<string.h>", importc: "memcpy".}
proc c_strlen(a: cstring): int {.header: "<string.h>",
noSideEffect, importc: "strlen".}
proc c_memset(p: pointer, value: cint, size: int) {.
header: "<string.h>", importc: "memset".}
@ -28,8 +28,8 @@ type
final, incompleteStruct.} = object
C_BinaryFile {.importc: "FILE", header: "<stdio.h>",
final, incompleteStruct.} = object
C_TextFileStar = ptr CTextFile
C_BinaryFileStar = ptr CBinaryFile
C_TextFileStar = ptr C_TextFile
C_BinaryFileStar = ptr C_BinaryFile
C_JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = object
@ -40,21 +40,40 @@ var
# constants faked as variables:
when not defined(SIGINT):
var
SIGINT {.importc: "SIGINT", nodecl.}: cint
SIGSEGV {.importc: "SIGSEGV", nodecl.}: cint
SIGABRT {.importc: "SIGABRT", nodecl.}: cint
SIGFPE {.importc: "SIGFPE", nodecl.}: cint
SIGILL {.importc: "SIGILL", nodecl.}: cint
when NoFakeVars:
when defined(windows):
const
SIGABRT = cint(22)
SIGFPE = cint(8)
SIGILL = cint(4)
SIGINT = cint(2)
SIGSEGV = cint(11)
SIGTERM = cint(15)
elif defined(macosx) or defined(linux):
const
SIGABRT = cint(6)
SIGFPE = cint(8)
SIGILL = cint(4)
SIGINT = cint(2)
SIGSEGV = cint(11)
SIGTERM = cint(15)
else:
{.error: "SIGABRT not ported to your platform".}
else:
var
SIGINT {.importc: "SIGINT", nodecl.}: cint
SIGSEGV {.importc: "SIGSEGV", nodecl.}: cint
SIGABRT {.importc: "SIGABRT", nodecl.}: cint
SIGFPE {.importc: "SIGFPE", nodecl.}: cint
SIGILL {.importc: "SIGILL", nodecl.}: cint
when defined(macosx):
var
SIGBUS {.importc: "SIGBUS", nodecl.}: cint
# hopefully this does not lead to new bugs
when NoFakeVars:
const SIGBUS = cint(10)
else:
var SIGBUS {.importc: "SIGBUS", nodecl.}: cint
else:
var
SIGBUS {.importc: "SIGSEGV", nodecl.}: cint
# only Mac OS X has this shit
template SIGBUS: expr = SIGSEGV
proc c_longjmp(jmpb: C_JmpBuf, retval: cint) {.
header: "<setjmp.h>", importc: "longjmp".}
@ -73,27 +92,27 @@ proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc",
header: "<stdio.h>".}
proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc",
header: "<stdio.h>".}
proc c_putc(c: Char, stream: C_TextFileStar) {.importc: "putc",
proc c_putc(c: char, stream: C_TextFileStar) {.importc: "putc",
header: "<stdio.h>".}
proc c_fprintf(f: C_TextFileStar, frmt: CString) {.
proc c_fprintf(f: C_TextFileStar, frmt: cstring) {.
importc: "fprintf", header: "<stdio.h>", varargs.}
proc c_printf(frmt: CString) {.
proc c_printf(frmt: cstring) {.
importc: "printf", header: "<stdio.h>", varargs.}
proc c_fopen(filename, mode: cstring): C_TextFileStar {.
importc: "fopen", header: "<stdio.h>".}
proc c_fclose(f: C_TextFileStar) {.importc: "fclose", header: "<stdio.h>".}
proc c_sprintf(buf, frmt: CString) {.header: "<stdio.h>",
proc c_sprintf(buf, frmt: cstring) {.header: "<stdio.h>",
importc: "sprintf", varargs, noSideEffect.}
# we use it only in a way that cannot lead to security issues
proc c_fread(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {.
proc c_fread(buf: pointer, size, n: int, f: C_BinaryFileStar): int {.
importc: "fread", header: "<stdio.h>".}
proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {.
importc: "fseek", header: "<stdio.h>".}
proc c_fwrite(buf: Pointer, size, n: int, f: C_BinaryFileStar): int {.
proc c_fwrite(buf: pointer, size, n: int, f: C_BinaryFileStar): int {.
importc: "fwrite", header: "<stdio.h>".}
proc c_exit(errorcode: cint) {.importc: "exit", header: "<stdlib.h>".}
@ -111,16 +130,22 @@ proc c_realloc(p: pointer, newsize: int): pointer {.
when hostOS != "standalone":
when not defined(errno):
var errno {.importc, header: "<errno.h>".}: cint ## error variable
when defined(NimrodVM):
var vmErrnoWrapper {.importc.}: ptr cint
template errno: expr =
bind vmErrnoWrapper
vmErrnoWrapper[]
else:
var errno {.importc, header: "<errno.h>".}: cint ## error variable
proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
proc c_remove(filename: CString): cint {.
proc c_remove(filename: cstring): cint {.
importc: "remove", header: "<stdio.h>".}
proc c_rename(oldname, newname: CString): cint {.
proc c_rename(oldname, newname: cstring): cint {.
importc: "rename", header: "<stdio.h>".}
proc c_system(cmd: CString): cint {.importc: "system", header: "<stdlib.h>".}
proc c_getenv(env: CString): CString {.importc: "getenv", header: "<stdlib.h>".}
proc c_putenv(env: CString): cint {.importc: "putenv", header: "<stdlib.h>".}
proc c_system(cmd: cstring): cint {.importc: "system", header: "<stdlib.h>".}
proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
proc c_putenv(env: cstring): cint {.importc: "putenv", header: "<stdlib.h>".}
{.pop}

View file

@ -7,10 +7,10 @@
# distribution, for details about the copyright.
#
proc genericResetAux(dest: Pointer, n: ptr TNimNode)
proc genericResetAux(dest: pointer, n: ptr TNimNode)
proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool)
proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool)
proc genericAssignAux(dest, src: pointer, n: ptr TNimNode, shallow: bool) =
var
d = cast[TAddress](dest)
s = cast[TAddress](src)
@ -37,37 +37,37 @@ proc genericAssignAux(dest, src: Pointer, n: ptr TNimNode, shallow: bool) =
# echo "ugh memory corruption! ", n.kind
# quit 1
proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool) =
proc genericAssignAux(dest, src: pointer, mt: PNimType, shallow: bool) =
var
d = cast[TAddress](dest)
s = cast[TAddress](src)
sysAssert(mt != nil, "genericAssignAux 2")
case mt.Kind
case mt.kind
of tyString:
var x = cast[ppointer](dest)
var s2 = cast[ppointer](s)[]
var x = cast[PPointer](dest)
var s2 = cast[PPointer](s)[]
if s2 == nil or shallow or (
cast[PGenericSeq](s2).reserved and seqShallowFlag) != 0:
unsureAsgnRef(x, s2)
else:
unsureAsgnRef(x, copyString(cast[NimString](s2)))
of tySequence:
var s2 = cast[ppointer](src)[]
var s2 = cast[PPointer](src)[]
var seq = cast[PGenericSeq](s2)
var x = cast[ppointer](dest)
var x = cast[PPointer](dest)
if s2 == nil or shallow or (seq.reserved and seqShallowFlag) != 0:
# this can happen! nil sequences are allowed
unsureAsgnRef(x, s2)
return
sysAssert(dest != nil, "genericAssignAux 3")
unsureAsgnRef(x, newSeq(mt, seq.len))
var dst = cast[taddress](cast[ppointer](dest)[])
var dst = cast[TAddress](cast[PPointer](dest)[])
for i in 0..seq.len-1:
genericAssignAux(
cast[pointer](dst +% i*% mt.base.size +% GenericSeqSize),
cast[pointer](cast[taddress](s2) +% i *% mt.base.size +%
cast[pointer](cast[TAddress](s2) +% i *% mt.base.size +%
GenericSeqSize),
mt.Base, shallow)
mt.base, shallow)
of tyObject:
# we need to copy m_type field for tyObject, as it could be empty for
# sequence reallocations:
@ -83,16 +83,16 @@ proc genericAssignAux(dest, src: Pointer, mt: PNimType, shallow: bool) =
genericAssignAux(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base, shallow)
of tyRef:
unsureAsgnRef(cast[ppointer](dest), cast[ppointer](s)[])
unsureAsgnRef(cast[PPointer](dest), cast[PPointer](s)[])
else:
copyMem(dest, src, mt.size) # copy raw bits
proc genericAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
proc genericAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
GC_disable()
genericAssignAux(dest, src, mt, false)
GC_enable()
proc genericShallowAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
proc genericShallowAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
GC_disable()
genericAssignAux(dest, src, mt, true)
GC_enable()
@ -126,7 +126,7 @@ when false:
cprintf("%s %ld\n", k, t.size)
debugNimType(t.base)
proc genericSeqAssign(dest, src: Pointer, mt: PNimType) {.compilerProc.} =
proc genericSeqAssign(dest, src: pointer, mt: PNimType) {.compilerProc.} =
var src = src # ugly, but I like to stress the parser sometimes :-)
genericAssign(dest, addr(src), mt)
@ -139,12 +139,12 @@ proc genericAssignOpenArray(dest, src: pointer, len: int,
genericAssign(cast[pointer](d +% i*% mt.base.size),
cast[pointer](s +% i*% mt.base.size), mt.base)
proc objectInit(dest: Pointer, typ: PNimType) {.compilerProc.}
proc objectInitAux(dest: Pointer, n: ptr TNimNode) =
proc objectInit(dest: pointer, typ: PNimType) {.compilerProc.}
proc objectInitAux(dest: pointer, n: ptr TNimNode) =
var d = cast[TAddress](dest)
case n.kind
of nkNone: sysAssert(false, "objectInitAux")
of nkSLot: objectInit(cast[pointer](d +% n.offset), n.typ)
of nkSlot: objectInit(cast[pointer](d +% n.offset), n.typ)
of nkList:
for i in 0..n.len-1:
objectInitAux(dest, n.sons[i])
@ -152,7 +152,7 @@ proc objectInitAux(dest: Pointer, n: ptr TNimNode) =
var m = selectBranch(dest, n)
if m != nil: objectInitAux(dest, m)
proc objectInit(dest: Pointer, typ: PNimType) =
proc objectInit(dest: pointer, typ: PNimType) =
# the generic init proc that takes care of initialization of complex
# objects on the stack or heap
var d = cast[TAddress](dest)
@ -168,12 +168,12 @@ proc objectInit(dest: Pointer, typ: PNimType) =
of tyArray, tyArrayConstr:
for i in 0..(typ.size div typ.base.size)-1:
objectInit(cast[pointer](d +% i * typ.base.size), typ.base)
else: nil # nothing to do
else: discard # nothing to do
# ---------------------- assign zero -----------------------------------------
when not defined(nimmixin):
proc destroy(x: int) = nil
proc destroy(x: int) = discard
proc nimDestroyRange*[T](r: T) =
# internal proc used for destroying sequences and arrays
for i in countup(0, r.len - 1): destroy(r[i])
@ -184,8 +184,8 @@ else:
mixin destroy
for i in countup(0, r.len - 1): destroy(r[i])
proc genericReset(dest: Pointer, mt: PNimType) {.compilerProc.}
proc genericResetAux(dest: Pointer, n: ptr TNimNode) =
proc genericReset(dest: pointer, mt: PNimType) {.compilerProc.}
proc genericResetAux(dest: pointer, n: ptr TNimNode) =
var d = cast[TAddress](dest)
case n.kind
of nkNone: sysAssert(false, "genericResetAux")
@ -197,12 +197,12 @@ proc genericResetAux(dest: Pointer, n: ptr TNimNode) =
if m != nil: genericResetAux(dest, m)
zeroMem(cast[pointer](d +% n.offset), n.typ.size)
proc genericReset(dest: Pointer, mt: PNimType) =
proc genericReset(dest: pointer, mt: PNimType) =
var d = cast[TAddress](dest)
sysAssert(mt != nil, "genericReset 2")
case mt.Kind
case mt.kind
of tyString, tyRef, tySequence:
unsureAsgnRef(cast[ppointer](dest), nil)
unsureAsgnRef(cast[PPointer](dest), nil)
of tyObject, tyTuple:
# we don't need to reset m_type field for tyObject
genericResetAux(dest, mt.node)

View file

@ -7,70 +7,199 @@
# distribution, for details about the copyright.
#
# Atomic operations for Nimrod.
## Atomic operations for Nimrod.
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
type
AtomMemModel* = enum
ATOMIC_RELAXED, ## No barriers or synchronization.
ATOMIC_CONSUME, ## Data dependency only for both barrier and
## synchronization with another thread.
ATOMIC_ACQUIRE, ## Barrier to hoisting of code and synchronizes with
## release (or stronger)
## semantic stores from another thread.
ATOMIC_RELEASE, ## Barrier to sinking of code and synchronizes with
## acquire (or stronger)
## semantic loads from another thread.
ATOMIC_ACQ_REL, ## Full barrier in both directions and synchronizes
## with acquire loads
## and release stores in another thread.
ATOMIC_SEQ_CST ## Full barrier in both directions and synchronizes
## with acquire loads
## and release stores in all threads.
TAtomType* = TNumber|pointer|ptr|char
## Type Class representing valid types for use with atomic procs
proc atomicLoadN*[T: TAtomType](p: ptr T, mem: AtomMemModel): T {.
importc: "__atomic_load_n", nodecl.}
## This proc implements an atomic load operation. It returns the contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_CONSUME.
proc atomicLoad*[T: TAtomType](p, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_load", nodecl.}
## This is the generic version of an atomic load. It returns the contents at p in ret.
proc atomicStoreN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel) {.
importc: "__atomic_store_n", nodecl.}
## This proc implements an atomic store operation. It writes val at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, and ATOMIC_RELEASE.
proc atomicStore*[T: TAtomType](p, val: ptr T, mem: AtomMemModel) {.
importc: "__atomic_store", nodecl.}
## This is the generic version of an atomic store. It stores the value of val at p
proc atomicExchangeN*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_exchange_n", nodecl.}
## This proc implements an atomic exchange operation. It writes val at p,
## and returns the previous contents at p.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_ACQUIRE, ATOMIC_RELEASE, ATOMIC_ACQ_REL
proc atomicExchange*[T: TAtomType](p, val, ret: ptr T, mem: AtomMemModel) {.
importc: "__atomic_exchange", nodecl.}
## This is the generic version of an atomic exchange. It stores the contents at val at p.
## The original value at p is copied into ret.
proc atomicCompareExchangeN*[T: TAtomType](p, expected: ptr T, desired: T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange_n ", nodecl.}
## This proc implements an atomic compare and exchange operation. This compares the
## contents at p with the contents at expected and if equal, writes desired at p.
## If they are not equal, the current contents at p is written into expected.
## Weak is true for weak compare_exchange, and false for the strong variation.
## Many targets only offer the strong variation and ignore the parameter.
## When in doubt, use the strong variation.
## True is returned if desired is written at p and the execution is considered
## to conform to the memory model specified by success_memmodel. There are no
## restrictions on what memory model can be used here. False is returned otherwise,
## and the execution is considered to conform to failure_memmodel. This memory model
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
## than that specified by success_memmodel.
proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
importc: "__atomic_compare_exchange_n ", nodecl.}
## This proc implements the generic version of atomic_compare_exchange.
## The proc is virtually identical to atomic_compare_exchange_n, except the desired
## value is also a pointer.
## Perform the operation return the new value, all memory models are valid
proc atomicAddFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_add_fetch", nodecl.}
proc atomicSubFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_sub_fetch", nodecl.}
proc atomicOrFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_or_fetch ", nodecl.}
proc atomicAndFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_and_fetch", nodecl.}
proc atomicXorFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_xor_fetch", nodecl.}
proc atomicNandFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_nand_fetch ", nodecl.}
## Perform the operation return the old value, all memory models are valid
proc atomicFetchAdd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_add", nodecl.}
proc atomicFetchSub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_sub", nodecl.}
proc atomicFetchOr*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_or", nodecl.}
proc atomicFetchAnd*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_and", nodecl.}
proc atomicFetchXor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_xor", nodecl.}
proc atomicFetchNand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_nand", nodecl.}
proc atomicTestAndSet*(p: pointer, mem: AtomMemModel): bool {.
importc: "__atomic_test_and_set", nodecl.}
## This built-in function performs an atomic test-and-set operation on the byte at p.
## The byte is set to some implementation defined nonzero “set” value and the return
## value is true if and only if the previous contents were “set”.
## All memory models are valid.
proc atomicClear*(p: pointer, mem: AtomMemModel) {.
importc: "__atomic_clear", nodecl.}
## This built-in function performs an atomic clear operation at p.
## After the operation, at p contains 0.
## ATOMIC_RELAXED, ATOMIC_SEQ_CST, ATOMIC_RELEASE
proc atomicThreadFence*(mem: AtomMemModel) {.
importc: "__atomic_thread_fence", nodecl.}
## This built-in function acts as a synchronization fence between threads based
## on the specified memory model. All memory orders are valid.
proc atomicSignalFence*(mem: AtomMemModel) {.
importc: "__atomic_signal_fence", nodecl.}
## This built-in function acts as a synchronization fence between a thread and
## signal handlers based in the same thread. All memory orders are valid.
proc atomicAlwaysLockFree*(size: int, p: pointer): bool {.
importc: "__atomic_always_lock_free", nodecl.}
## This built-in function returns true if objects of size bytes always generate
## lock free atomic instructions for the target architecture. size must resolve
## to a compile-time constant and the result also resolves to a compile-time constant.
## ptr is an optional pointer to the object that may be used to determine alignment.
## A value of 0 indicates typical alignment should be used. The compiler may also
## ignore this parameter.
proc atomicIsLockFree*(size: int, p: pointer): bool {.
importc: "__atomic_is_lock_free", nodecl.}
## This built-in function returns true if objects of size bytes always generate
## lock free atomic instructions for the target architecture. If it is not known
## to be lock free a call is made to a runtime routine named __atomic_is_lock_free.
## ptr is an optional pointer to the object that may be used to determine alignment.
## A value of 0 indicates typical alignment should be used. The compiler may also
## ignore this parameter.
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport and
not defined(windows):
proc sync_add_and_fetch(p: var int, val: int): int {.
importc: "__sync_add_and_fetch", nodecl.}
proc sync_sub_and_fetch(p: var int, val: int): int {.
importc: "__sync_sub_and_fetch", nodecl.}
elif defined(vcc) and hasThreadSupport:
proc sync_add_and_fetch(p: var int, val: int): int {.
proc addAndFetch*(p: ptr int, val: int): int {.
importc: "NimXadd", nodecl.}
else:
proc sync_add_and_fetch(p: var int, val: int): int {.inline.} =
inc(p, val)
result = p
proc addAndFetch*(p: ptr int, val: int): int {.inline.} =
inc(p[], val)
result = p[]
proc atomicInc(memLoc: var int, x: int = 1): int =
when hasThreadSupport:
result = sync_add_and_fetch(memLoc, x)
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
#if defined(windows) and not defined(gcc) and hasThreadSupport:
# proc InterlockedCompareExchangePointer(mem: ptr pointer,
# newValue: pointer, comparand: pointer) : pointer {.nodecl,
# importc: "InterlockedCompareExchangePointer", header:"windows.h".}
# proc compareAndSwap*[T](mem: ptr T,
# expected: T, newValue: T): bool {.inline.}=
# ## Returns true if successfully set value at mem to newValue when value
# ## at mem == expected
# return InterlockedCompareExchangePointer(addr(mem),
# addr(newValue), addr(expected))[] == expected
#elif not hasThreadSupport:
# proc compareAndSwap*[T](mem: ptr T,
# expected: T, newValue: T): bool {.inline.} =
# ## Returns true if successfully set value at mem to newValue when value
# ## at mem == expected
# var oldval = mem[]
# if oldval == expected:
# mem[] = newValue
# return true
# return false
# Some convenient functions
proc atomicInc*(memLoc: var int, x: int = 1): int =
when defined(gcc) and hasThreadSupport:
result = atomic_add_fetch(memLoc.addr, x, ATOMIC_RELAXED)
else:
inc(memLoc, x)
result = memLoc
proc atomicDec(memLoc: var int, x: int = 1): int =
when hasThreadSupport:
when defined(sync_sub_and_fetch):
result = sync_sub_and_fetch(memLoc, x)
proc atomicDec*(memLoc: var int, x: int = 1): int =
when defined(gcc) and hasThreadSupport:
when defined(atomic_sub_fetch):
result = atomic_sub_fetch(memLoc.addr, x, ATOMIC_RELAXED)
else:
result = sync_add_and_fetch(memLoc, -x)
result = atomic_add_fetch(memLoc.addr, -x, ATOMIC_RELAXED)
else:
dec(memLoc, x)
result = memLoc
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T, expected: T, newValue: T): bool {.nodecl,
importc: " __sync_bool_compare_and_swap".}
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
elif defined(windows) and hasThreadSupport:
proc InterlockedCompareExchangePointer(mem: ptr pointer,
newValue: pointer, comparand: pointer) : pointer {.nodecl,
importc: "InterlockedCompareExchangePointer", header:"windows.h".}
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T,
expected: T, newValue: T): bool {.inline.}=
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
return InterlockedCompareExchangePointer(addr(mem),
newValue, expected) == expected
elif not hasThreadSupport:
proc compareAndSwap*[T: ptr|ref|pointer](mem: var T,
expected: T, newValue: T): bool {.inline.} =
## Returns true if successfully set value at mem to newValue when value
## at mem == expected
var oldval = mem
if oldval == expected:
mem = newValue
return true
return false
result = memLoc

View file

@ -9,30 +9,30 @@
# not really an AVL tree anymore, but still balanced ...
template IsBottom(n: PAvlNode): bool = n == bottom
template isBottom(n: PAvlNode): bool = n == bottom
proc lowGauge(n: PAvlNode): int =
var it = n
while not IsBottom(it):
while not isBottom(it):
result = it.key
it = it.link[0]
proc highGauge(n: PAvlNode): int =
result = -1
var it = n
while not IsBottom(it):
while not isBottom(it):
result = it.upperBound
it = it.link[1]
proc find(root: PAvlNode, key: int): PAvlNode =
var it = root
while not IsBottom(it):
while not isBottom(it):
if it.key == key: return it
it = it.link[ord(it.key <% key)]
proc inRange(root: PAvlNode, key: int): PAvlNode =
var it = root
while not IsBottom(it):
while not isBottom(it):
if it.key <=% key and key <% it.upperBound: return it
it = it.link[ord(it.key <% key)]

View file

@ -43,15 +43,15 @@ type
proc contains(s: TCellSeq, c: PCell): bool {.inline.} =
for i in 0 .. s.len-1:
if s.d[i] == c: return True
return False
if s.d[i] == c: return true
return false
proc add(s: var TCellSeq, c: PCell) {.inline.} =
if s.len >= s.cap:
s.cap = s.cap * 3 div 2
var d = cast[PCellArray](Alloc(s.cap * sizeof(PCell)))
var d = cast[PCellArray](alloc(s.cap * sizeof(PCell)))
copyMem(d, s.d, s.len * sizeof(PCell))
Dealloc(s.d)
dealloc(s.d)
s.d = d
# XXX: realloc?
s.d[s.len] = c
@ -60,10 +60,10 @@ proc add(s: var TCellSeq, c: PCell) {.inline.} =
proc init(s: var TCellSeq, cap: int = 1024) =
s.len = 0
s.cap = cap
s.d = cast[PCellArray](Alloc0(cap * sizeof(PCell)))
s.d = cast[PCellArray](alloc0(cap * sizeof(PCell)))
proc deinit(s: var TCellSeq) =
Dealloc(s.d)
dealloc(s.d)
s.d = nil
s.len = 0
s.cap = 0
@ -73,20 +73,20 @@ proc deinit(s: var TCellSeq) =
const
InitCellSetSize = 1024 # must be a power of two!
proc Init(s: var TCellSet) =
s.data = cast[PPageDescArray](Alloc0(InitCellSetSize * sizeof(PPageDesc)))
proc init(s: var TCellSet) =
s.data = cast[PPageDescArray](alloc0(InitCellSetSize * sizeof(PPageDesc)))
s.max = InitCellSetSize-1
s.counter = 0
s.head = nil
proc Deinit(s: var TCellSet) =
proc deinit(s: var TCellSet) =
var it = s.head
while it != nil:
var n = it.next
Dealloc(it)
dealloc(it)
it = n
s.head = nil # play it safe here
Dealloc(s.data)
dealloc(s.data)
s.data = nil
s.counter = 0
@ -96,14 +96,14 @@ proc nextTry(h, maxHash: int): int {.inline.} =
# generates each int in range(maxHash) exactly once (see any text on
# random-number generation for proof).
proc CellSetGet(t: TCellSet, key: TAddress): PPageDesc =
proc cellSetGet(t: TCellSet, key: TAddress): PPageDesc =
var h = cast[int](key) and t.max
while t.data[h] != nil:
if t.data[h].key == key: return t.data[h]
h = nextTry(h, t.max)
return nil
proc CellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
proc cellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
var h = cast[int](desc.key) and t.max
while data[h] != nil:
sysAssert(data[h] != desc, "CellSetRawInsert 1")
@ -111,17 +111,17 @@ proc CellSetRawInsert(t: TCellSet, data: PPageDescArray, desc: PPageDesc) =
sysAssert(data[h] == nil, "CellSetRawInsert 2")
data[h] = desc
proc CellSetEnlarge(t: var TCellSet) =
proc cellSetEnlarge(t: var TCellSet) =
var oldMax = t.max
t.max = ((t.max+1)*2)-1
var n = cast[PPageDescArray](Alloc0((t.max + 1) * sizeof(PPageDesc)))
for i in 0 .. oldmax:
var n = cast[PPageDescArray](alloc0((t.max + 1) * sizeof(PPageDesc)))
for i in 0 .. oldMax:
if t.data[i] != nil:
CellSetRawInsert(t, n, t.data[i])
Dealloc(t.data)
cellSetRawInsert(t, n, t.data[i])
dealloc(t.data)
t.data = n
proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
proc cellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
var h = cast[int](key) and t.max
while true:
var x = t.data[h]
@ -130,13 +130,13 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
h = nextTry(h, t.max)
if ((t.max+1)*2 < t.counter*3) or ((t.max+1)-t.counter < 4):
CellSetEnlarge(t)
cellSetEnlarge(t)
inc(t.counter)
h = cast[int](key) and t.max
while t.data[h] != nil: h = nextTry(h, t.max)
sysAssert(t.data[h] == nil, "CellSetPut")
# the new page descriptor goes into result
result = cast[PPageDesc](Alloc0(sizeof(TPageDesc)))
result = cast[PPageDesc](alloc0(sizeof(TPageDesc)))
result.next = t.head
result.key = key
t.head = result
@ -146,7 +146,7 @@ proc CellSetPut(t: var TCellSet, key: TAddress): PPageDesc =
proc contains(s: TCellSet, cell: PCell): bool =
var u = cast[TAddress](cell)
var t = CellSetGet(s, u shr PageShift)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
u = (u %% PageSize) /% MemAlign
result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
@ -155,13 +155,13 @@ proc contains(s: TCellSet, cell: PCell): bool =
proc incl(s: var TCellSet, cell: PCell) {.noinline.} =
var u = cast[TAddress](cell)
var t = CellSetPut(s, u shr PageShift)
var t = cellSetPut(s, u shr PageShift)
u = (u %% PageSize) /% MemAlign
t.bits[u shr IntShift] = t.bits[u shr IntShift] or (1 shl (u and IntMask))
proc excl(s: var TCellSet, cell: PCell) =
var u = cast[TAddress](cell)
var t = CellSetGet(s, u shr PageShift)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
u = (u %% PageSize) /% MemAlign
t.bits[u shr IntShift] = (t.bits[u shr IntShift] and
@ -169,7 +169,7 @@ proc excl(s: var TCellSet, cell: PCell) =
proc containsOrIncl(s: var TCellSet, cell: PCell): bool =
var u = cast[TAddress](cell)
var t = CellSetGet(s, u shr PageShift)
var t = cellSetGet(s, u shr PageShift)
if t != nil:
u = (u %% PageSize) /% MemAlign
result = (t.bits[u shr IntShift] and (1 shl (u and IntMask))) != 0
@ -177,7 +177,7 @@ proc containsOrIncl(s: var TCellSet, cell: PCell): bool =
t.bits[u shr IntShift] = t.bits[u shr IntShift] or
(1 shl (u and IntMask))
else:
Incl(s, cell)
incl(s, cell)
result = false
iterator elements(t: TCellSet): PCell {.inline.} =
@ -201,7 +201,7 @@ iterator elements(t: TCellSet): PCell {.inline.} =
iterator elementsExcept(t, s: TCellSet): PCell {.inline.} =
var r = t.head
while r != nil:
let ss = CellSetGet(s, r.key)
let ss = cellSetGet(s, r.key)
var i = 0
while i <= high(r.bits):
var w = r.bits[i]

View file

@ -13,6 +13,9 @@
##
## **Note:** The current implementation of message passing is slow and does
## not work with cyclic data structures.
when not defined(NimString):
{.error: "You must not import this module explicitly".}
type
pbytes = ptr array[0.. 0xffff, byte]
@ -45,9 +48,9 @@ proc deinitRawChannel(p: pointer) =
deinitSys(c.lock)
deinitSysCond(c.cond)
proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode)
proc storeAux(dest, src: Pointer, n: ptr TNimNode, t: PRawChannel,
proc storeAux(dest, src: pointer, n: ptr TNimNode, t: PRawChannel,
mode: TLoadStoreMode) =
var
d = cast[TAddress](dest)
@ -64,7 +67,7 @@ proc storeAux(dest, src: Pointer, n: ptr TNimNode, t: PRawChannel,
if m != nil: storeAux(dest, src, m, t, mode)
of nkNone: sysAssert(false, "storeAux")
proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
proc storeAux(dest, src: pointer, mt: PNimType, t: PRawChannel,
mode: TLoadStoreMode) =
var
d = cast[TAddress](dest)
@ -79,7 +82,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
x[] = nil
else:
var ss = cast[NimString](s2)
var ns = cast[NimString](Alloc(t.region, ss.len+1 + GenericSeqSize))
var ns = cast[NimString](alloc(t.region, ss.len+1 + GenericSeqSize))
copyMem(ns, ss, ss.len+1 + GenericSeqSize)
x[] = ns
else:
@ -89,7 +92,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
unsureAsgnRef(x, s2)
else:
unsureAsgnRef(x, copyString(cast[NimString](s2)))
Dealloc(t.region, s2)
dealloc(t.region, s2)
of tySequence:
var s2 = cast[ppointer](src)[]
var seq = cast[PGenericSeq](s2)
@ -102,7 +105,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
else:
sysAssert(dest != nil, "dest == nil")
if mode == mStore:
x[] = Alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize)
x[] = alloc(t.region, seq.len *% mt.base.size +% GenericSeqSize)
else:
unsureAsgnRef(x, newObj(mt, seq.len * mt.base.size + GenericSeqSize))
var dst = cast[taddress](cast[ppointer](dest)[])
@ -115,7 +118,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
var dstseq = cast[PGenericSeq](dst)
dstseq.len = seq.len
dstseq.reserved = seq.len
if mode != mStore: Dealloc(t.region, s2)
if mode != mStore: dealloc(t.region, s2)
of tyObject:
# copy type field:
var pint = cast[ptr PNimType](dest)
@ -140,7 +143,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
unsureAsgnRef(x, nil)
else:
if mode == mStore:
x[] = Alloc(t.region, mt.base.size)
x[] = alloc(t.region, mt.base.size)
else:
# XXX we should use the dynamic type here too, but that is not stored
# in the inbox at all --> use source[]'s object type? but how? we need
@ -148,7 +151,7 @@ proc storeAux(dest, src: Pointer, mt: PNimType, t: PRawChannel,
var obj = newObj(mt, mt.base.size)
unsureAsgnRef(x, obj)
storeAux(x[], s, mt.base, t, mode)
if mode != mStore: Dealloc(t.region, s)
if mode != mStore: dealloc(t.region, s)
else:
copyMem(dest, src, mt.size) # copy raw bits
@ -158,7 +161,7 @@ proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =
if q.count >= cap:
# start with capacity for 2 entries in the queue:
if cap == 0: cap = 1
var n = cast[pbytes](Alloc0(q.region, cap*2*typ.size))
var n = cast[pbytes](alloc0(q.region, cap*2*typ.size))
var z = 0
var i = q.rd
var c = q.count
@ -167,7 +170,7 @@ proc rawSend(q: PRawChannel, data: pointer, typ: PNimType) =
copyMem(addr(n[z*typ.size]), addr(q.data[i*typ.size]), typ.size)
i = (i + 1) and q.mask
inc z
if q.data != nil: Dealloc(q.region, q.data)
if q.data != nil: dealloc(q.region, q.data)
q.data = n
q.mask = cap*2 - 1
q.wr = q.count
@ -197,7 +200,7 @@ template sendImpl(q: expr) {.immediate.} =
rawSend(q, addr(m), typ)
q.elemType = typ
releaseSys(q.lock)
SignalSysCond(q.cond)
signalSysCond(q.cond)
proc send*[TMsg](c: var TChannel[TMsg], msg: TMsg) =
## sends a message to a thread. `msg` is deeply copied.
@ -209,7 +212,7 @@ proc llRecv(q: PRawChannel, res: pointer, typ: PNimType) =
acquireSys(q.lock)
q.ready = true
while q.count <= 0:
WaitSysCond(q.cond, q.lock)
waitSysCond(q.cond, q.lock)
q.ready = false
if typ != q.elemType:
releaseSys(q.lock)

View file

@ -9,8 +9,8 @@
# Implementation of some runtime checks.
proc raiseRangeError(val: biggestInt) {.compilerproc, noreturn, noinline.} =
when hostOs == "standalone":
proc raiseRangeError(val: BiggestInt) {.compilerproc, noreturn, noinline.} =
when hostOS == "standalone":
sysFatal(EOutOfRange, "value out of range")
else:
sysFatal(EOutOfRange, "value out of range: ", $val)

View file

@ -28,7 +28,7 @@ proc nimLoadLibraryError(path: string) =
stdout.rawWrite("\n")
quit(1)
proc ProcAddrError(name: cstring) {.noinline.} =
proc procAddrError(name: cstring) {.noinline.} =
# carefully written to avoid memory allocation:
stdout.rawWrite("could not import: ")
stdout.write(name)
@ -56,7 +56,7 @@ when defined(posix):
RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int
proc dlclose(lib: TLibHandle) {.importc, header: "<dlfcn.h>".}
proc dlopen(path: CString, mode: int): TLibHandle {.
proc dlopen(path: cstring, mode: int): TLibHandle {.
importc, header: "<dlfcn.h>".}
proc dlsym(lib: TLibHandle, name: cstring): TProcAddr {.
importc, header: "<dlfcn.h>".}
@ -72,7 +72,7 @@ when defined(posix):
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
result = dlsym(lib, name)
if result == nil: ProcAddrError(name)
if result == nil: procAddrError(name)
elif defined(windows) or defined(dos):
#
@ -83,21 +83,22 @@ elif defined(windows) or defined(dos):
type
THINSTANCE {.importc: "HINSTANCE".} = pointer
proc FreeLibrary(lib: THINSTANCE) {.importc, header: "<windows.h>", stdcall.}
proc freeLibrary(lib: THINSTANCE) {.
importc: "FreeLibrary", header: "<windows.h>", stdcall.}
proc winLoadLibrary(path: cstring): THINSTANCE {.
importc: "LoadLibraryA", header: "<windows.h>", stdcall.}
proc GetProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
proc getProcAddress(lib: THINSTANCE, name: cstring): TProcAddr {.
importc: "GetProcAddress", header: "<windows.h>", stdcall.}
proc nimUnloadLibrary(lib: TLibHandle) =
FreeLibrary(cast[THINSTANCE](lib))
freeLibrary(cast[THINSTANCE](lib))
proc nimLoadLibrary(path: string): TLibHandle =
result = cast[TLibHandle](winLoadLibrary(path))
proc nimGetProcAddr(lib: TLibHandle, name: cstring): TProcAddr =
result = GetProcAddress(cast[THINSTANCE](lib), name)
if result == nil: ProcAddrError(name)
result = getProcAddress(cast[THINSTANCE](lib), name)
if result == nil: procAddrError(name)
elif defined(mac):
#

View file

@ -11,22 +11,27 @@
# use the heap (and nor exceptions) do not include the GC or memory allocator.
var
stackTraceNewLine*: string ## undocumented feature; it is replaced by ``<br>``
## for CGI applications
template stackTraceNL: expr =
(if IsNil(stackTraceNewLine): "\n" else: stackTraceNewLine)
errorMessageWriter*: (proc(msg: string) {.tags: [FWriteIO].})
## Function that will be called
## instead of stdmsg.write when printing stacktrace.
## Unstable API.
when not defined(windows) or not defined(guiapp):
proc writeToStdErr(msg: CString) = write(stdout, msg)
proc writeToStdErr(msg: cstring) = write(stdmsg, msg)
else:
proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
header: "<windows.h>", nodecl.}
proc writeToStdErr(msg: CString) =
proc writeToStdErr(msg: cstring) =
discard MessageBoxA(0, msg, nil, 0)
proc showErrorMessage(data: cstring) =
if errorMessageWriter != nil:
errorMessageWriter($data)
else:
writeToStdErr(data)
proc chckIndx(i, a, b: int): int {.inline, compilerproc.}
proc chckRange(i, a, b: int): int {.inline, compilerproc.}
proc chckRangeF(x, a, b: float): float {.inline, compilerproc.}
@ -75,9 +80,9 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
type
TDl_info {.importc: "Dl_info", header: "<dlfcn.h>",
final, pure.} = object
dli_fname: CString
dli_fname: cstring
dli_fbase: pointer
dli_sname: CString
dli_sname: cstring
dli_saddr: pointer
proc backtrace(symbols: ptr pointer, size: int): int {.
@ -111,7 +116,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
add(s, tempDlInfo.dli_sname)
else:
add(s, '?')
add(s, stackTraceNL)
add(s, "\n")
else:
if dlresult != 0 and tempDlInfo.dli_sname != nil and
c_strcmp(tempDlInfo.dli_sname, "signalHandler") == 0'i32:
@ -172,21 +177,18 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
add(s, ')')
for k in 1..max(1, 25-(s.len-oldLen)): add(s, ' ')
add(s, tempFrames[j].procname)
add(s, stackTraceNL)
add(s, "\n")
when hasSomeStackTrace:
proc rawWriteStackTrace(s: var string) =
when nimrodStackTrace:
if framePtr == nil:
add(s, "No stack traceback available")
add(s, stackTraceNL)
add(s, "No stack traceback available\n")
else:
add(s, "Traceback (most recent call last)")
add(s, stackTraceNL)
add(s, "Traceback (most recent call last)\n")
auxWriteStackTrace(framePtr, s)
elif defined(nativeStackTrace) and nativeStackTraceSupported:
add(s, "Traceback from system (most recent call last)")
add(s, stackTraceNL)
add(s, "Traceback from system (most recent call last)\n")
auxWriteStackTraceWithBacktrace(s)
else:
add(s, "No stack traceback available\n")
@ -207,7 +209,7 @@ proc raiseExceptionAux(e: ref E_Base) =
pushCurrentException(e)
c_longjmp(excHandler.context, 1)
elif e[] of EOutOfMemory:
writeToStdErr(e.name)
showErrorMessage(e.name)
quitOrDebug()
else:
when hasSomeStackTrace:
@ -219,7 +221,7 @@ proc raiseExceptionAux(e: ref E_Base) =
add(buf, " [")
add(buf, $e.name)
add(buf, "]\n")
writeToStdErr(buf)
showErrorMessage(buf)
else:
# ugly, but avoids heap allocations :-)
template xadd(buf, s, slen: expr) =
@ -235,10 +237,10 @@ proc raiseExceptionAux(e: ref E_Base) =
add(buf, " [")
xadd(buf, e.name, c_strlen(e.name))
add(buf, "]\n")
writeToStdErr(buf)
showErrorMessage(buf)
quitOrDebug()
proc raiseException(e: ref E_Base, ename: CString) {.compilerRtl.} =
proc raiseException(e: ref E_Base, ename: cstring) {.compilerRtl.} =
e.name = ename
when hasSomeStackTrace:
e.trace = ""
@ -251,13 +253,13 @@ proc reraiseException() {.compilerRtl.} =
else:
raiseExceptionAux(currException)
proc WriteStackTrace() =
proc writeStackTrace() =
when hasSomeStackTrace:
var s = ""
rawWriteStackTrace(s)
writeToStdErr(s)
showErrorMessage(s)
else:
writeToStdErr("No stack traceback available\n")
showErrorMessage("No stack traceback available\n")
proc getStackTrace(): string =
when hasSomeStackTrace:
@ -278,7 +280,7 @@ when defined(endb):
when not defined(noSignalHandler):
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
template processSignal(s, action: expr) {.immediate.} =
template processSignal(s, action: expr) {.immediate, dirty.} =
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
elif s == SIGSEGV:
action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
@ -298,13 +300,13 @@ when not defined(noSignalHandler):
var buf = newStringOfCap(2000)
rawWriteStackTrace(buf)
processSignal(sig, buf.add) # nice hu? currying a la nimrod :-)
writeToStdErr(buf)
showErrorMessage(buf)
GC_enable()
else:
var msg: cstring
template asgn(y: expr) = msg = y
processSignal(sig, asgn)
writeToStdErr(msg)
showErrorMessage(msg)
when defined(endb): dbgAborting = True
quit(1) # always quit when SIGABRT

View file

@ -9,7 +9,7 @@
# Garbage Collector
#
# The basic algorithm is *Deferrent Reference Counting* with cycle detection.
# The basic algorithm is *Deferred Reference Counting* with cycle detection.
# This is achieved by combining a Deutsch-Bobrow garbage collector
# together with Christoper's partial mark-sweep garbage collector.
#
@ -84,7 +84,7 @@ var
gch {.rtlThreadVar.}: TGcHeap
when not defined(useNimRtl):
InstantiateForRegion(gch.region)
instantiateForRegion(gch.region)
template acquire(gch: TGcHeap) =
when hasThreadSupport and hasSharedHeap:
@ -132,9 +132,9 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
template color(c): expr = c.refCount and colorMask
template setColor(c, col) =
when col == rcBlack:
c.refcount = c.refCount and not colorMask
c.refcount = c.refcount and not colorMask
else:
c.refcount = c.refCount and not colorMask or col
c.refcount = c.refcount and not colorMask or col
proc writeCell(msg: cstring, c: PCell) =
var kind = -1
@ -151,10 +151,10 @@ template gcTrace(cell, state: expr): stmt {.immediate.} =
# forward declarations:
proc collectCT(gch: var TGcHeap)
proc IsOnStack*(p: pointer): bool {.noinline.}
proc isOnStack*(p: pointer): bool {.noinline.}
proc forAllChildren(cell: PCell, op: TWalkOp)
proc doOperation(p: pointer, op: TWalkOp)
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp)
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
# we need the prototype here for debugging purposes
when hasThreadSupport and hasSharedHeap:
@ -162,9 +162,9 @@ when hasThreadSupport and hasSharedHeap:
template `++`(x: expr): stmt = discard atomicInc(x, rcIncrement)
else:
template `--`(x: expr): expr =
Dec(x, rcIncrement)
dec(x, rcIncrement)
x <% rcIncrement
template `++`(x: expr): stmt = Inc(x, rcIncrement)
template `++`(x: expr): stmt = inc(x, rcIncrement)
proc prepareDealloc(cell: PCell) =
when useMarkForDebug:
@ -203,7 +203,7 @@ proc decRef(c: PCell) {.inline.} =
gcAssert(c.refcount >=% rcIncrement, "decRef")
if --c.refcount:
rtlAddZCT(c)
elif canBeCycleRoot(c):
elif canbeCycleRoot(c):
# unfortunately this is necessary here too, because a cycle might just
# have been broken up and we could recycle it.
rtlAddCycleRoot(c)
@ -211,10 +211,10 @@ proc decRef(c: PCell) {.inline.} =
proc incRef(c: PCell) {.inline.} =
gcAssert(isAllocatedPtr(gch.region, c), "incRef: interiorPtr")
c.refcount = c.refCount +% rcIncrement
c.refcount = c.refcount +% rcIncrement
# and not colorMask
#writeCell("incRef", c)
if canBeCycleRoot(c):
if canbeCycleRoot(c):
rtlAddCycleRoot(c)
proc nimGCref(p: pointer) {.compilerProc, inline.} = incRef(usrToCell(p))
@ -235,7 +235,7 @@ proc nimGCunrefNoCycle(p: pointer) {.compilerProc, inline.} =
sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 2")
sysAssert(allocInv(gch.region), "end nimGCunrefNoCycle 5")
proc asgnRef(dest: ppointer, src: pointer) {.compilerProc, inline.} =
proc asgnRef(dest: PPointer, src: pointer) {.compilerProc, inline.} =
# the code generator calls this proc!
gcAssert(not isOnStack(dest), "asgnRef")
# BUGFIX: first incRef then decRef!
@ -243,7 +243,7 @@ proc asgnRef(dest: ppointer, src: pointer) {.compilerProc, inline.} =
if dest[] != nil: decRef(usrToCell(dest[]))
dest[] = src
proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} =
proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerProc, inline.} =
# the code generator calls this proc if it is known at compile time that no
# cycle is possible.
if src != nil:
@ -255,7 +255,7 @@ proc asgnRefNoCycle(dest: ppointer, src: pointer) {.compilerProc, inline.} =
rtlAddZCT(c)
dest[] = src
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerProc.} =
proc unsureAsgnRef(dest: PPointer, src: pointer) {.compilerProc.} =
# unsureAsgnRef updates the reference counters only if dest is not on the
# stack. It is used by the code generator if it cannot decide wether a
# reference is in the stack or not (this can happen for var parameters).
@ -318,7 +318,7 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
# inlined for speed
if n.sons[i].kind == nkSlot:
if n.sons[i].typ.kind in {tyRef, tyString, tySequence}:
doOperation(cast[ppointer](d +% n.sons[i].offset)[], op)
doOperation(cast[PPointer](d +% n.sons[i].offset)[], op)
else:
forAllChildrenAux(cast[pointer](d +% n.sons[i].offset),
n.sons[i].typ, op)
@ -329,29 +329,30 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: sysAssert(false, "forAllSlotsAux")
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
var d = cast[TAddress](dest)
if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags:
case mt.Kind
case mt.kind
of tyRef, tyString, tySequence: # leaf:
doOperation(cast[ppointer](d)[], op)
doOperation(cast[PPointer](d)[], op)
of tyObject, tyTuple:
forAllSlotsAux(dest, mt.node, op)
of tyArray, tyArrayConstr, tyOpenArray:
for i in 0..(mt.size div mt.base.size)-1:
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: nil
else: discard
proc forAllChildren(cell: PCell, op: TWalkOp) =
gcAssert(cell != nil, "forAllChildren: 1")
gcAssert(cell.typ != nil, "forAllChildren: 2")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 3"
gcAssert(isAllocatedPtr(gch.region, cell), "forAllChildren: 2")
gcAssert(cell.typ != nil, "forAllChildren: 3")
gcAssert cell.typ.kind in {tyRef, tySequence, tyString}, "forAllChildren: 4"
let marker = cell.typ.marker
if marker != nil:
marker(cellToUsr(cell), op.int)
else:
case cell.typ.Kind
case cell.typ.kind
of tyRef: # common case
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
of tySequence:
@ -361,7 +362,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
for i in 0..s.len-1:
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
GenericSeqSize), cell.typ.base, op)
else: nil
else: discard
proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
# we check the last 8 entries (cache line) for a slot that could be reused.
@ -407,12 +408,19 @@ proc addNewObjToZCT(res: PCell, gch: var TGcHeap) {.inline.} =
return
add(gch.zct, res)
{.push stackTrace: off, profiler:off.}
proc gcInvariant*() =
sysAssert(allocInv(gch.region), "injected")
when defined(markForDebug):
markForDebug(gch)
{.pop.}
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
# generates a new object and sets its reference counter to 0
sysAssert(allocInv(gch.region), "rawNewObj begin")
acquire(gch)
gcAssert(typ.kind in {tyRef, tyString, tySequence}, "newObj: 1")
collectCT(gch)
sysAssert(allocInv(gch.region), "rawNewObj begin")
var res = cast[PCell](rawAlloc(gch.region, size + sizeof(TCell)))
gcAssert((cast[TAddress](res) and (MemAlign-1)) == 0, "newObj: 2")
# now it is buffered in the ZCT
@ -511,13 +519,15 @@ proc growObj(old: pointer, newsize: int, gch: var TGcHeap): pointer =
d[j] = res
break
dec(j)
if canBeCycleRoot(ol): excl(gch.cycleRoots, ol)
if canbeCycleRoot(ol): excl(gch.cycleRoots, ol)
when logGC:
writeCell("growObj old cell", ol)
writeCell("growObj new cell", res)
gcTrace(ol, csZctFreed)
gcTrace(res, csAllocated)
when reallyDealloc: rawDealloc(gch.region, ol)
when reallyDealloc:
sysAssert(allocInv(gch.region), "growObj before dealloc")
rawDealloc(gch.region, ol)
else:
sysAssert(ol.typ != nil, "growObj: 5")
zeroMem(ol, sizeof(TCell))
@ -537,7 +547,9 @@ proc freeCyclicCell(gch: var TGcHeap, c: PCell) =
prepareDealloc(c)
gcTrace(c, csCycFreed)
when logGC: writeCell("cycle collector dealloc cell", c)
when reallyDealloc: rawDealloc(gch.region, c)
when reallyDealloc:
sysAssert(allocInv(gch.region), "free cyclic cell")
rawDealloc(gch.region, c)
else:
gcAssert(c.typ != nil, "freeCyclicCell")
zeroMem(c, sizeof(TCell))
@ -561,7 +573,7 @@ proc scan(s: PCell) =
proc collectWhite(s: PCell) =
if s.color == rcWhite and s notin gch.cycleRoots:
s.setcolor(rcBlack)
s.setColor(rcBlack)
forAllChildren(s, waCollectWhite)
freeCyclicCell(gch, s)
@ -570,7 +582,7 @@ proc markRoots(gch: var TGcHeap) =
for s in elements(gch.cycleRoots):
#writeCell("markRoot", s)
inc tabSize
if s.color == rcPurple and s.refCount >=% rcIncrement:
if s.color == rcPurple and s.refcount >=% rcIncrement:
markGray(s)
else:
excl(gch.cycleRoots, s)
@ -620,8 +632,7 @@ proc doOperation(p: pointer, op: TWalkOp) =
case op
of waZctDecRef:
#if not isAllocatedPtr(gch.region, c):
# return
# c_fprintf(c_stdout, "[GC] decref bug: %p", c)
# c_fprintf(c_stdout, "[GC] decref bug: %p", c)
gcAssert(isAllocatedPtr(gch.region, c), "decRef: waZctDecRef")
gcAssert(c.refcount >=% rcIncrement, "doOperation 2")
#c.refcount = c.refcount -% rcIncrement
@ -658,7 +669,7 @@ proc doOperation(p: pointer, op: TWalkOp) =
proc nimGCvisit(d: pointer, op: int) {.compilerRtl.} =
doOperation(d, TWalkOp(op))
proc CollectZCT(gch: var TGcHeap): bool
proc collectZCT(gch: var TGcHeap): bool
when useMarkForDebug or useBackupGc:
proc markStackAndRegistersForSweep(gch: var TGcHeap) {.noinline, cdecl.}
@ -858,7 +869,7 @@ else:
sp = sp +% sizeof(pointer)*8
# last few entries:
while sp <=% max:
gcMark(gch, cast[ppointer](sp)[])
gcMark(gch, cast[PPointer](sp)[])
sp = sp +% sizeof(pointer)
proc markStackAndRegisters(gch: var TGcHeap) {.noinline, cdecl.} =
@ -880,7 +891,7 @@ proc collectZCT(gch: var TGcHeap): bool =
const workPackage = 100
var L = addr(gch.zct.len)
when withRealtime:
when withRealTime:
var steps = workPackage
var t0: TTicks
if gch.maxPause > 0: t0 = getticks()
@ -893,7 +904,7 @@ proc collectZCT(gch: var TGcHeap): bool =
c.refcount = c.refcount and not ZctFlag
gch.zct.d[0] = gch.zct.d[L[] - 1]
dec(L[])
when withRealtime: dec steps
when withRealTime: dec steps
if c.refcount <% rcIncrement:
# It may have a RC > 0, if it is in the hardware stack or
# it has not been removed yet from the ZCT. This is because
@ -902,7 +913,7 @@ proc collectZCT(gch: var TGcHeap): bool =
# In any case, it should be removed from the ZCT. But not
# freed. **KEEP THIS IN MIND WHEN MAKING THIS INCREMENTAL!**
when cycleGC:
if canBeCycleRoot(c): excl(gch.cycleRoots, c)
if canbeCycleRoot(c): excl(gch.cycleRoots, c)
when logGC: writeCell("zct dealloc cell", c)
gcTrace(c, csZctFreed)
# We are about to free the object, call the finalizer BEFORE its
@ -910,11 +921,13 @@ proc collectZCT(gch: var TGcHeap): bool =
# access invalid memory. This is done by prepareDealloc():
prepareDealloc(c)
forAllChildren(c, waZctDecRef)
when reallyDealloc: rawDealloc(gch.region, c)
when reallyDealloc:
sysAssert(allocInv(gch.region), "collectZCT: rawDealloc")
rawDealloc(gch.region, c)
else:
sysAssert(c.typ != nil, "collectZCT 2")
zeroMem(c, sizeof(TCell))
when withRealtime:
when withRealTime:
if steps == 0:
steps = workPackage
if gch.maxPause > 0:
@ -939,7 +952,7 @@ proc unmarkStackAndRegisters(gch: var TGcHeap) =
gch.decStack.len = 0
proc collectCTBody(gch: var TGcHeap) =
when withRealtime:
when withRealTime:
let t0 = getticks()
sysAssert(allocInv(gch.region), "collectCT: begin")
@ -957,12 +970,12 @@ proc collectCTBody(gch: var TGcHeap) =
#discard collectZCT(gch)
inc(gch.stat.cycleCollections)
gch.cycleThreshold = max(InitialCycleThreshold, getOccupiedMem() *
cycleIncrease)
CycleIncrease)
gch.stat.maxThreshold = max(gch.stat.maxThreshold, gch.cycleThreshold)
unmarkStackAndRegisters(gch)
sysAssert(allocInv(gch.region), "collectCT: end")
when withRealtime:
when withRealTime:
let duration = getticks() - t0
gch.stat.maxPause = max(gch.stat.maxPause, duration)
when defined(reportMissedDeadlines):
@ -984,7 +997,7 @@ proc collectCT(gch: var TGcHeap) =
markForDebug(gch)
collectCTBody(gch)
when withRealtime:
when withRealTime:
proc toNano(x: int): TNanos {.inline.} =
result = x * 1000
@ -1016,11 +1029,7 @@ when not defined(useNimRtl):
dec(gch.recGcLock)
proc GC_setStrategy(strategy: TGC_Strategy) =
case strategy
of gcThroughput: nil
of gcResponsiveness: nil
of gcOptimizeSpace: nil
of gcOptimizeTime: nil
discard
proc GC_enableMarkAndSweep() =
gch.cycleThreshold = InitialCycleThreshold

View file

@ -387,8 +387,7 @@ template `--`(rc: TRefCount): expr =
rc <% rcIncrement
template `--` (rc: TRefCount, heapType: THeapType): expr =
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement
else: --rc)
(when heapType == SharedHeap: atomicDec(rc, rcIncrement) <% rcIncrement else: --rc)
template doDecRef(cc: PCell,
heapType = LocalHeap,

View file

@ -1,7 +1,7 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2013 Andreas Rumpf
# (c) Copyright 2014 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
@ -59,11 +59,11 @@ var
gch {.rtlThreadVar.}: TGcHeap
when not defined(useNimRtl):
InstantiateForRegion(gch.region)
instantiateForRegion(gch.region)
template acquire(gch: TGcHeap) =
when hasThreadSupport and hasSharedHeap:
AcquireSys(HeapLock)
acquireSys(HeapLock)
template release(gch: TGcHeap) =
when hasThreadSupport and hasSharedHeap:
@ -90,7 +90,7 @@ proc extGetCellType(c: pointer): PNimType {.compilerproc.} =
# used for code generation concerning debugging
result = usrToCell(c).typ
proc unsureAsgnRef(dest: ppointer, src: pointer) {.inline.} =
proc unsureAsgnRef(dest: PPointer, src: pointer) {.inline.} =
dest[] = src
proc internRefcount(p: pointer): int {.exportc: "getRefcount".} =
@ -114,10 +114,10 @@ when BitsPerPage mod (sizeof(int)*8) != 0:
# forward declarations:
proc collectCT(gch: var TGcHeap)
proc IsOnStack*(p: pointer): bool {.noinline.}
proc isOnStack*(p: pointer): bool {.noinline.}
proc forAllChildren(cell: PCell, op: TWalkOp)
proc doOperation(p: pointer, op: TWalkOp)
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp)
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp)
# we need the prototype here for debugging purposes
proc prepareDealloc(cell: PCell) =
@ -162,19 +162,19 @@ proc forAllSlotsAux(dest: pointer, n: ptr TNimNode, op: TWalkOp) =
if m != nil: forAllSlotsAux(dest, m, op)
of nkNone: sysAssert(false, "forAllSlotsAux")
proc forAllChildrenAux(dest: Pointer, mt: PNimType, op: TWalkOp) =
proc forAllChildrenAux(dest: pointer, mt: PNimType, op: TWalkOp) =
var d = cast[TAddress](dest)
if dest == nil: return # nothing to do
if ntfNoRefs notin mt.flags:
case mt.Kind
case mt.kind
of tyRef, tyString, tySequence: # leaf:
doOperation(cast[ppointer](d)[], op)
doOperation(cast[PPointer](d)[], op)
of tyObject, tyTuple:
forAllSlotsAux(dest, mt.node, op)
of tyArray, tyArrayConstr, tyOpenArray:
for i in 0..(mt.size div mt.base.size)-1:
forAllChildrenAux(cast[pointer](d +% i *% mt.base.size), mt.base, op)
else: nil
else: discard
proc forAllChildren(cell: PCell, op: TWalkOp) =
gcAssert(cell != nil, "forAllChildren: 1")
@ -184,7 +184,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
if marker != nil:
marker(cellToUsr(cell), op.int)
else:
case cell.typ.Kind
case cell.typ.kind
of tyRef: # common case
forAllChildrenAux(cellToUsr(cell), cell.typ.base, op)
of tySequence:
@ -194,7 +194,7 @@ proc forAllChildren(cell: PCell, op: TWalkOp) =
for i in 0..s.len-1:
forAllChildrenAux(cast[pointer](d +% i *% cell.typ.base.size +%
GenericSeqSize), cell.typ.base, op)
else: nil
else: discard
proc rawNewObj(typ: PNimType, size: int, gch: var TGcHeap): pointer =
# generates a new object and sets its reference counter to 0
@ -466,7 +466,7 @@ else:
sp = sp +% sizeof(pointer)*8
# last few entries:
while sp <=% max:
gcMark(gch, cast[ppointer](sp)[])
gcMark(gch, cast[PPointer](sp)[])
sp = sp +% sizeof(pointer)
# ----------------------------------------------------------------------------
@ -505,7 +505,7 @@ when not defined(useNimRtl):
else:
dec(gch.recGcLock)
proc GC_setStrategy(strategy: TGC_Strategy) = nil
proc GC_setStrategy(strategy: TGC_Strategy) = discard
proc GC_enableMarkAndSweep() =
gch.cycleThreshold = InitialThreshold

View file

@ -69,7 +69,7 @@ type
kind: TNimNodeKind
offset: int
typ: ptr TNimType
name: Cstring
name: cstring
len: int
sons: ptr array [0..0x7fff, ptr TNimNode]

View file

@ -472,17 +472,17 @@ proc Ze(a: int): int {.compilerproc.} =
proc Ze64(a: int64): int64 {.compilerproc.} =
result = a
proc toU8(a: int): int8 {.noStackFrame, compilerproc.} =
proc ToU8(a: int): int8 {.noStackFrame, compilerproc.} =
asm """
return `a`;
"""
proc toU16(a: int): int16 {.noStackFrame, compilerproc.} =
proc ToU16(a: int): int16 {.noStackFrame, compilerproc.} =
asm """
return `a`;
"""
proc toU32(a: int): int32 {.noStackFrame, compilerproc.} =
proc ToU32(a: int): int32 {.noStackFrame, compilerproc.} =
asm """
return `a`;
"""

View file

@ -18,7 +18,8 @@ const
logGC = false
traceGC = false # extensive debugging
alwaysCycleGC = false
alwaysGC = false # collect after every memory allocation (for debugging)
alwaysGC = defined(fulldebug) # collect after every memory
# allocation (for debugging)
leakDetector = false
overwriteFree = false
trackAllocationSource = leakDetector
@ -28,10 +29,11 @@ const
reallyOsDealloc = true
coalescRight = true
coalescLeft = true
logAlloc = false
type
PPointer = ptr pointer
TByteArray = array[0..1000_0000, byte]
TByteArray = array[0..1000_0000, Byte]
PByte = ptr TByteArray
PString = ptr string
@ -112,10 +114,10 @@ when defined(boehmgc):
proc alloc0(size: int): pointer =
result = alloc(size)
zeroMem(result, size)
proc realloc(p: Pointer, newsize: int): pointer =
proc realloc(p: pointer, newsize: int): pointer =
result = boehmRealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc dealloc(p: Pointer) = boehmDealloc(p)
proc dealloc(p: pointer) = boehmDealloc(p)
proc allocShared(size: int): pointer =
result = boehmAlloc(size)
@ -123,26 +125,26 @@ when defined(boehmgc):
proc allocShared0(size: int): pointer =
result = alloc(size)
zeroMem(result, size)
proc reallocShared(p: Pointer, newsize: int): pointer =
proc reallocShared(p: pointer, newsize: int): pointer =
result = boehmRealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc deallocShared(p: Pointer) = boehmDealloc(p)
proc deallocShared(p: pointer) = boehmDealloc(p)
#boehmGCincremental()
proc GC_disable() = boehmGC_disable()
proc GC_enable() = boehmGC_enable()
proc GC_fullCollect() = boehmGCfullCollect()
proc GC_setStrategy(strategy: TGC_Strategy) = nil
proc GC_enableMarkAndSweep() = nil
proc GC_disableMarkAndSweep() = nil
proc GC_setStrategy(strategy: TGC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard
proc GC_getStatistics(): string = return ""
proc getOccupiedMem(): int = return boehmGetHeapSize()-boehmGetFreeBytes()
proc getFreeMem(): int = return boehmGetFreeBytes()
proc getTotalMem(): int = return boehmGetHeapSize()
proc setStackBottom(theStackBottom: pointer) = nil
proc setStackBottom(theStackBottom: pointer) = discard
proc initGC() =
when defined(macosx): boehmGCinit()
@ -158,8 +160,8 @@ when defined(boehmgc):
proc growObj(old: pointer, newsize: int): pointer =
result = realloc(old, newsize)
proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
@ -171,15 +173,15 @@ when defined(boehmgc):
type
TMemRegion = object {.final, pure.}
proc Alloc(r: var TMemRegion, size: int): pointer =
proc alloc(r: var TMemRegion, size: int): pointer =
result = boehmAlloc(size)
if result == nil: raiseOutOfMem()
proc Alloc0(r: var TMemRegion, size: int): pointer =
proc alloc0(r: var TMemRegion, size: int): pointer =
result = alloc(size)
zeroMem(result, size)
proc Dealloc(r: var TMemRegion, p: Pointer) = boehmDealloc(p)
proc deallocOsPages(r: var TMemRegion) {.inline.} = nil
proc deallocOsPages() {.inline.} = nil
proc dealloc(r: var TMemRegion, p: Pointer) = boehmDealloc(p)
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
proc deallocOsPages() {.inline.} = discard
include "system/cellsets"
elif defined(nogc) and defined(useMalloc):
@ -191,10 +193,10 @@ elif defined(nogc) and defined(useMalloc):
proc alloc0(size: int): pointer =
result = alloc(size)
zeroMem(result, size)
proc realloc(p: Pointer, newsize: int): pointer =
proc realloc(p: pointer, newsize: int): pointer =
result = crealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc dealloc(p: Pointer) = cfree(p)
proc dealloc(p: pointer) = cfree(p)
proc allocShared(size: int): pointer =
result = cmalloc(size)
@ -202,26 +204,26 @@ elif defined(nogc) and defined(useMalloc):
proc allocShared0(size: int): pointer =
result = alloc(size)
zeroMem(result, size)
proc reallocShared(p: Pointer, newsize: int): pointer =
proc reallocShared(p: pointer, newsize: int): pointer =
result = crealloc(p, newsize)
if result == nil: raiseOutOfMem()
proc deallocShared(p: Pointer) = cfree(p)
proc deallocShared(p: pointer) = cfree(p)
proc GC_disable() = nil
proc GC_enable() = nil
proc GC_fullCollect() = nil
proc GC_setStrategy(strategy: TGC_Strategy) = nil
proc GC_enableMarkAndSweep() = nil
proc GC_disableMarkAndSweep() = nil
proc GC_disable() = discard
proc GC_enable() = discard
proc GC_fullCollect() = discard
proc GC_setStrategy(strategy: TGC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard
proc GC_getStatistics(): string = return ""
proc getOccupiedMem(): int = nil
proc getFreeMem(): int = nil
proc getTotalMem(): int = nil
proc getOccupiedMem(): int = discard
proc getFreeMem(): int = discard
proc getTotalMem(): int = discard
proc setStackBottom(theStackBottom: pointer) = nil
proc setStackBottom(theStackBottom: pointer) = discard
proc initGC() = nil
proc initGC() = discard
proc newObj(typ: PNimType, size: int): pointer {.compilerproc.} =
result = alloc(size)
@ -233,8 +235,8 @@ elif defined(nogc) and defined(useMalloc):
proc growObj(old: pointer, newsize: int): pointer =
result = realloc(old, newsize)
proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
dest[] = src
@ -246,13 +248,13 @@ elif defined(nogc) and defined(useMalloc):
type
TMemRegion = object {.final, pure.}
proc Alloc(r: var TMemRegion, size: int): pointer =
proc alloc(r: var TMemRegion, size: int): pointer =
result = alloc(size)
proc Alloc0(r: var TMemRegion, size: int): pointer =
proc alloc0(r: var TMemRegion, size: int): pointer =
result = alloc0(size)
proc Dealloc(r: var TMemRegion, p: Pointer) = Dealloc(p)
proc deallocOsPages(r: var TMemRegion) {.inline.} = nil
proc deallocOsPages() {.inline.} = nil
proc dealloc(r: var TMemRegion, p: pointer) = dealloc(p)
proc deallocOsPages(r: var TMemRegion) {.inline.} = discard
proc deallocOsPages() {.inline.} = discard
elif defined(nogc):
# Even though we don't want the GC, we cannot simply use C's memory manager
@ -266,13 +268,13 @@ elif defined(nogc):
include "system/alloc"
proc initGC() = nil
proc GC_disable() = nil
proc GC_enable() = nil
proc GC_fullCollect() = nil
proc GC_setStrategy(strategy: TGC_Strategy) = nil
proc GC_enableMarkAndSweep() = nil
proc GC_disableMarkAndSweep() = nil
proc initGC() = discard
proc GC_disable() = discard
proc GC_enable() = discard
proc GC_fullCollect() = discard
proc GC_setStrategy(strategy: TGC_Strategy) = discard
proc GC_enableMarkAndSweep() = discard
proc GC_disableMarkAndSweep() = discard
proc GC_getStatistics(): string = return ""
@ -285,9 +287,9 @@ elif defined(nogc):
proc growObj(old: pointer, newsize: int): pointer =
result = realloc(old, newsize)
proc setStackBottom(theStackBottom: pointer) = nil
proc nimGCref(p: pointer) {.compilerproc, inline.} = nil
proc nimGCunref(p: pointer) {.compilerproc, inline.} = nil
proc setStackBottom(theStackBottom: pointer) = discard
proc nimGCref(p: pointer) {.compilerproc, inline.} = discard
proc nimGCunref(p: pointer) {.compilerproc, inline.} = discard
proc unsureAsgnRef(dest: ppointer, src: pointer) {.compilerproc, inline.} =
dest[] = src

View file

@ -72,7 +72,7 @@ proc reprEnum(e: int, typ: PNimType): string {.compilerRtl.} =
result = $e & " (invalid data!)"
type
pbyteArray = ptr array[0.. 0xffff, int8]
PByteArray = ptr array[0.. 0xffff, int8]
proc addSetElem(result: var string, elem: int, typ: PNimType) =
case typ.kind
@ -96,7 +96,7 @@ proc reprSetAux(result: var string, p: pointer, typ: PNimType) =
of 4: u = ze64(cast[ptr int32](p)[])
of 8: u = cast[ptr int64](p)[]
else:
var a = cast[pbyteArray](p)
var a = cast[PByteArray](p)
for i in 0 .. typ.size*8-1:
if (ze(a[i div 8]) and (1 shl (i mod 8))) != 0:
if elemCounter > 0: add result, ", "
@ -129,12 +129,12 @@ when not defined(useNimRtl):
when hasThreadSupport and hasSharedHeap and defined(heapLock):
AcquireSys(HeapLock)
when defined(TCellSet):
Init(cl.marked)
init(cl.marked)
cl.recdepth = -1 # default is to display everything!
cl.indent = 0
proc deinitReprClosure(cl: var TReprClosure) =
when defined(TCellSet): Deinit(cl.marked)
when defined(TCellSet): deinit(cl.marked)
when hasThreadSupport and hasSharedHeap and defined(heapLock):
ReleaseSys(HeapLock)
@ -164,7 +164,7 @@ when not defined(useNimRtl):
for i in 0..cast[PGenericSeq](p).len-1:
if i > 0: add result, ", "
reprAux(result, cast[pointer](cast[TAddress](p) + GenericSeqSize + i*bs),
typ.Base, cl)
typ.base, cl)
add result, "]"
proc reprRecordAux(result: var string, p: pointer, n: ptr TNimNode,
@ -224,17 +224,17 @@ when not defined(useNimRtl):
reprRecord(result, p, t, cl)
of tyRef, tyPtr:
sysAssert(p != nil, "reprAux")
if cast[ppointer](p)[] == nil: add result, "nil"
else: reprRef(result, cast[ppointer](p)[], typ, cl)
if cast[PPointer](p)[] == nil: add result, "nil"
else: reprRef(result, cast[PPointer](p)[], typ, cl)
of tySequence:
reprSequence(result, cast[ppointer](p)[], typ, cl)
reprSequence(result, cast[PPointer](p)[], typ, cl)
of tyInt: add result, $(cast[ptr int](p)[])
of tyInt8: add result, $int(cast[ptr Int8](p)[])
of tyInt16: add result, $int(cast[ptr Int16](p)[])
of tyInt32: add result, $int(cast[ptr Int32](p)[])
of tyInt64: add result, $(cast[ptr Int64](p)[])
of tyUInt8: add result, $ze(cast[ptr Int8](p)[])
of tyUInt16: add result, $ze(cast[ptr Int16](p)[])
of tyInt8: add result, $int(cast[ptr int8](p)[])
of tyInt16: add result, $int(cast[ptr int16](p)[])
of tyInt32: add result, $int(cast[ptr int32](p)[])
of tyInt64: add result, $(cast[ptr int64](p)[])
of tyUInt8: add result, $ze(cast[ptr int8](p)[])
of tyUInt16: add result, $ze(cast[ptr int16](p)[])
of tyFloat: add result, $(cast[ptr float](p)[])
of tyFloat32: add result, $(cast[ptr float32](p)[])
@ -246,8 +246,8 @@ when not defined(useNimRtl):
of tyCString: reprStrAux(result, $(cast[ptr cstring](p)[]))
of tyRange: reprAux(result, p, typ.base, cl)
of tyProc, tyPointer:
if cast[ppointer](p)[] == nil: add result, "nil"
else: add result, reprPointer(cast[ppointer](p)[])
if cast[PPointer](p)[] == nil: add result, "nil"
else: add result, reprPointer(cast[PPointer](p)[])
else:
add result, "(invalid data!)"
inc(cl.recdepth)

View file

@ -24,16 +24,16 @@ proc fgetc(stream: TFile): cint {.importc: "fgetc", header: "<stdio.h>",
tags: [FReadIO].}
proc ungetc(c: cint, f: TFile) {.importc: "ungetc", header: "<stdio.h>",
tags: [].}
proc putc(c: Char, stream: TFile) {.importc: "putc", header: "<stdio.h>",
proc putc(c: char, stream: TFile) {.importc: "putc", header: "<stdio.h>",
tags: [FWriteIO].}
proc fprintf(f: TFile, frmt: CString) {.importc: "fprintf",
proc fprintf(f: TFile, frmt: cstring) {.importc: "fprintf",
header: "<stdio.h>", varargs, tags: [FWriteIO].}
proc strlen(c: cstring): int {.
importc: "strlen", header: "<string.h>", tags: [].}
# C routine that is used here:
proc fread(buf: Pointer, size, n: int, f: TFile): int {.
proc fread(buf: pointer, size, n: int, f: TFile): int {.
importc: "fread", header: "<stdio.h>", tags: [FReadIO].}
proc fseek(f: TFile, offset: clong, whence: int): int {.
importc: "fseek", header: "<stdio.h>", tags: [].}
@ -45,12 +45,24 @@ proc setvbuf(stream: TFile, buf: pointer, typ, size: cint): cint {.
proc write(f: TFile, c: cstring) = fputs(c, f)
{.pop.}
var
IOFBF {.importc: "_IOFBF", nodecl.}: cint
IONBF {.importc: "_IONBF", nodecl.}: cint
when NoFakeVars:
when defined(windows):
const
IOFBF = cint(0)
IONBF = cint(4)
elif defined(macosx) or defined(linux):
const
IOFBF = cint(0)
IONBF = cint(2)
else:
{.error: "IOFBF not ported to your platform".}
else:
var
IOFBF {.importc: "_IOFBF", nodecl.}: cint
IONBF {.importc: "_IONBF", nodecl.}: cint
const
buf_size = 4000
BufSize = 4000
proc raiseEIO(msg: string) {.noinline, noreturn.} =
sysFatal(EIO, msg)
@ -59,7 +71,7 @@ proc readLine(f: TFile, line: var TaintedString): bool =
# of course this could be optimized a bit; but IO is slow anyway...
# and it was difficult to get this CORRECT with Ansi C's methods
setLen(line.string, 0) # reuse the buffer!
while True:
while true:
var c = fgetc(f)
if c < 0'i32:
if line.len > 0: break
@ -82,8 +94,8 @@ proc write(f: TFile, i: int) =
else:
fprintf(f, "%ld", i)
proc write(f: TFile, i: biggestInt) =
when sizeof(biggestint) == 8:
proc write(f: TFile, i: BiggestInt) =
when sizeof(BiggestInt) == 8:
fprintf(f, "%lld", i)
else:
fprintf(f, "%ld", i)
@ -92,9 +104,9 @@ proc write(f: TFile, b: bool) =
if b: write(f, "true")
else: write(f, "false")
proc write(f: TFile, r: float32) = fprintf(f, "%g", r)
proc write(f: TFile, r: biggestFloat) = fprintf(f, "%g", r)
proc write(f: TFile, r: BiggestFloat) = fprintf(f, "%g", r)
proc write(f: TFile, c: Char) = putc(c, f)
proc write(f: TFile, c: char) = putc(c, f)
proc write(f: TFile, a: varargs[string, `$`]) =
for x in items(a): write(f, x)
@ -102,10 +114,10 @@ proc readAllBuffer(file: TFile): string =
# This proc is for TFile we want to read but don't know how many
# bytes we need to read before the buffer is empty.
result = ""
var buffer = newString(buf_size)
var bytesRead = buf_size
while bytesRead == buf_size:
bytesRead = readBuffer(file, addr(buffer[0]), buf_size)
var buffer = newString(BufSize)
var bytesRead = BufSize
while bytesRead == BufSize:
bytesRead = readBuffer(file, addr(buffer[0]), BufSize)
result.add(buffer)
proc rawFileSize(file: TFile): int =
@ -149,7 +161,7 @@ proc writeFile(filename, content: string) =
finally:
close(f)
proc EndOfFile(f: TFile): bool =
proc endOfFile(f: TFile): bool =
# do not blame me; blame the ANSI C standard this is so brain-damaged
var c = fgetc(f)
ungetc(c, f)
@ -167,12 +179,12 @@ proc rawEchoNL() {.inline, compilerproc.} = write(stdout, "\n")
when defined(windows) and not defined(useWinAnsi):
include "system/widestrs"
proc wfopen(filename, mode: widecstring): pointer {.
proc wfopen(filename, mode: WideCString): pointer {.
importc: "_wfopen", nodecl.}
proc wfreopen(filename, mode: widecstring, stream: TFile): TFile {.
proc wfreopen(filename, mode: WideCString, stream: TFile): TFile {.
importc: "_wfreopen", nodecl.}
proc fopen(filename, mode: CString): pointer =
proc fopen(filename, mode: cstring): pointer =
var f = newWideCString(filename)
var m = newWideCString(mode)
result = wfopen(f, m)
@ -183,7 +195,7 @@ when defined(windows) and not defined(useWinAnsi):
result = wfreopen(f, m, stream)
else:
proc fopen(filename, mode: CString): pointer {.importc: "fopen", noDecl.}
proc fopen(filename, mode: cstring): pointer {.importc: "fopen", noDecl.}
proc freopen(filename, mode: cstring, stream: TFile): TFile {.
importc: "freopen", nodecl.}
@ -194,9 +206,9 @@ const
# should not be translated.
proc Open(f: var TFile, filename: string,
proc open(f: var TFile, filename: string,
mode: TFileMode = fmRead,
bufSize: int = -1): Bool =
bufSize: int = -1): bool =
var p: pointer = fopen(filename, FormatOpen[mode])
result = (p != nil)
f = cast[TFile](p)
@ -217,23 +229,23 @@ proc open(f: var TFile, filehandle: TFileHandle, mode: TFileMode): bool =
f = fdopen(filehandle, FormatOpen[mode])
result = f != nil
proc fwrite(buf: Pointer, size, n: int, f: TFile): int {.
proc fwrite(buf: pointer, size, n: int, f: TFile): int {.
importc: "fwrite", noDecl.}
proc readBuffer(f: TFile, buffer: pointer, len: int): int =
result = fread(buffer, 1, len, f)
proc ReadBytes(f: TFile, a: var openarray[int8], start, len: int): int =
proc readBytes(f: TFile, a: var openArray[int8], start, len: int): int =
result = readBuffer(f, addr(a[start]), len)
proc ReadChars(f: TFile, a: var openarray[char], start, len: int): int =
proc readChars(f: TFile, a: var openArray[char], start, len: int): int =
result = readBuffer(f, addr(a[start]), len)
{.push stackTrace:off, profiler:off.}
proc writeBytes(f: TFile, a: openarray[int8], start, len: int): int =
proc writeBytes(f: TFile, a: openArray[int8], start, len: int): int =
var x = cast[ptr array[0..1000_000_000, int8]](a)
result = writeBuffer(f, addr(x[start]), len)
proc writeChars(f: TFile, a: openarray[char], start, len: int): int =
proc writeChars(f: TFile, a: openArray[char], start, len: int): int =
var x = cast[ptr array[0..1000_000_000, int8]](a)
result = writeBuffer(f, addr(x[start]), len)
proc writeBuffer(f: TFile, buffer: pointer, len: int): int =

View file

@ -22,50 +22,53 @@ when defined(Windows):
TSysCond = THandle
proc InitSysLock(L: var TSysLock) {.stdcall, noSideEffect,
proc initSysLock(L: var TSysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "InitializeCriticalSection".}
## Initializes the lock `L`.
proc TryAcquireSysAux(L: var TSysLock): int32 {.stdcall, noSideEffect,
proc tryAcquireSysAux(L: var TSysLock): int32 {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "TryEnterCriticalSection".}
## Tries to acquire the lock `L`.
proc TryAcquireSys(L: var TSysLock): bool {.inline.} =
proc tryAcquireSys(L: var TSysLock): bool {.inline.} =
result = TryAcquireSysAux(L) != 0'i32
proc AcquireSys(L: var TSysLock) {.stdcall, noSideEffect,
proc acquireSys(L: var TSysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "EnterCriticalSection".}
## Acquires the lock `L`.
proc ReleaseSys(L: var TSysLock) {.stdcall, noSideEffect,
proc releaseSys(L: var TSysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "LeaveCriticalSection".}
## Releases the lock `L`.
proc DeinitSys(L: var TSysLock) {.stdcall, noSideEffect,
proc deinitSys(L: var TSysLock) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "DeleteCriticalSection".}
proc CreateEvent(lpEventAttributes: pointer,
proc createEvent(lpEventAttributes: pointer,
bManualReset, bInitialState: int32,
lpName: cstring): TSysCond {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "CreateEventA".}
proc CloseHandle(hObject: THandle) {.stdcall, noSideEffect,
proc closeHandle(hObject: THandle) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "CloseHandle".}
proc WaitForSingleObject(hHandle: THandle, dwMilliseconds: int32): int32 {.
proc waitForSingleObject(hHandle: THandle, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
proc SignalSysCond(hEvent: TSysCond) {.stdcall, noSideEffect,
proc signalSysCond(hEvent: TSysCond) {.stdcall, noSideEffect,
dynlib: "kernel32", importc: "SetEvent".}
proc InitSysCond(cond: var TSysCond) {.inline.} =
cond = CreateEvent(nil, 0'i32, 0'i32, nil)
proc DeinitSysCond(cond: var TSysCond) {.inline.} =
CloseHandle(cond)
proc WaitSysCond(cond: var TSysCond, lock: var TSysLock) =
proc initSysCond(cond: var TSysCond) {.inline.} =
cond = createEvent(nil, 0'i32, 0'i32, nil)
proc deinitSysCond(cond: var TSysCond) {.inline.} =
closeHandle(cond)
proc waitSysCond(cond: var TSysCond, lock: var TSysLock) =
releaseSys(lock)
discard WaitForSingleObject(cond, -1'i32)
discard waitForSingleObject(cond, -1'i32)
acquireSys(lock)
proc waitSysCondWindows(cond: var TSysCond) =
discard waitForSingleObject(cond, -1'i32)
else:
type
TSysLock {.importc: "pthread_mutex_t", pure, final,
@ -73,29 +76,29 @@ else:
TSysCond {.importc: "pthread_cond_t", pure, final,
header: "<sys/types.h>".} = object
proc InitSysLock(L: var TSysLock, attr: pointer = nil) {.
proc initSysLock(L: var TSysLock, attr: pointer = nil) {.
importc: "pthread_mutex_init", header: "<pthread.h>", noSideEffect.}
proc AcquireSys(L: var TSysLock) {.noSideEffect,
proc acquireSys(L: var TSysLock) {.noSideEffect,
importc: "pthread_mutex_lock", header: "<pthread.h>".}
proc TryAcquireSysAux(L: var TSysLock): cint {.noSideEffect,
proc tryAcquireSysAux(L: var TSysLock): cint {.noSideEffect,
importc: "pthread_mutex_trylock", header: "<pthread.h>".}
proc TryAcquireSys(L: var TSysLock): bool {.inline.} =
result = TryAcquireSysAux(L) == 0'i32
proc tryAcquireSys(L: var TSysLock): bool {.inline.} =
result = tryAcquireSysAux(L) == 0'i32
proc ReleaseSys(L: var TSysLock) {.noSideEffect,
proc releaseSys(L: var TSysLock) {.noSideEffect,
importc: "pthread_mutex_unlock", header: "<pthread.h>".}
proc DeinitSys(L: var TSysLock) {.
proc deinitSys(L: var TSysLock) {.
importc: "pthread_mutex_destroy", header: "<pthread.h>".}
proc InitSysCond(cond: var TSysCond, cond_attr: pointer = nil) {.
proc initSysCond(cond: var TSysCond, cond_attr: pointer = nil) {.
importc: "pthread_cond_init", header: "<pthread.h>".}
proc WaitSysCond(cond: var TSysCond, lock: var TSysLock) {.
proc waitSysCond(cond: var TSysCond, lock: var TSysLock) {.
importc: "pthread_cond_wait", header: "<pthread.h>".}
proc SignalSysCond(cond: var TSysCond) {.
proc signalSysCond(cond: var TSysCond) {.
importc: "pthread_cond_signal", header: "<pthread.h>".}
proc DeinitSysCond(cond: var TSysCond) {.
proc deinitSysCond(cond: var TSysCond) {.
importc: "pthread_cond_destroy", header: "<pthread.h>".}

View file

@ -55,7 +55,7 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
if len > 0:
result = rawNewString(len)
result.len = len
c_memcpy(result.data, addr(s.data[start]), len * sizeof(Char))
c_memcpy(result.data, addr(s.data[start]), len * sizeof(char))
#result.data[len] = '\0'
else:
result = rawNewString(len)
@ -63,14 +63,14 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
result = copyStrLast(s, start, s.len-1)
proc toNimStr(str: CString, len: int): NimString {.compilerProc.} =
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
result = rawNewString(len)
result.len = len
c_memcpy(result.data, str, (len+1) * sizeof(Char))
c_memcpy(result.data, str, (len+1) * sizeof(char))
#result.data[len] = '\0' # readline relies on this!
proc cstrToNimstr(str: CString): NimString {.compilerRtl.} =
result = toNimstr(str, c_strlen(str))
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
result = toNimStr(str, c_strlen(str))
proc copyString(src: NimString): NimString {.compilerRtl.} =
if src != nil:
@ -79,7 +79,7 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
else:
result = rawNewString(src.space)
result.len = src.len
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(Char))
c_memcpy(result.data, src.data, (src.len + 1) * sizeof(char))
proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
if src != nil:
@ -98,8 +98,8 @@ proc hashString(s: string): int {.compilerproc.} =
# the compiler needs exactly the same hash function!
# this used to be used for efficient generation of string case statements
var h = 0
for i in 0..Len(s)-1:
h = h +% Ord(s[i])
for i in 0..len(s)-1:
h = h +% ord(s[i])
h = h +% h shl 10
h = h xor (h shr 6)
h = h +% h shl 3
@ -150,10 +150,10 @@ proc addChar(s: NimString, c: char): NimString =
# s = rawNewString(0);
proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
if dest.len + addLen <= dest.space:
if dest.len + addlen <= dest.space:
result = dest
else: # slow path:
var sp = max(resize(dest.space), dest.len + addLen)
var sp = max(resize(dest.space), dest.len + addlen)
result = cast[NimString](growObj(dest, sizeof(TGenericSeq) + sp + 1))
result.reserved = sp
#result = rawNewString(sp)
@ -236,7 +236,7 @@ proc nimIntToStr(x: int): string {.compilerRtl.} =
result = newString(sizeof(x)*4)
var i = 0
var y = x
while True:
while true:
var d = y div 10
result[i] = chr(abs(int(y - d*10)) + ord('0'))
inc(i)
@ -259,7 +259,7 @@ proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
result = newString(sizeof(x)*4)
var i = 0
var y = x
while True:
while true:
var d = y div 10
result[i] = chr(abs(int(y - d*10)) + ord('0'))
inc(i)
@ -280,7 +280,7 @@ proc nimCharToStr(x: char): string {.compilerRtl.} =
result = newString(1)
result[0] = x
proc binaryStrSearch(x: openarray[string], y: string): int {.compilerproc.} =
proc binaryStrSearch(x: openArray[string], y: string): int {.compilerproc.} =
var
a = 0
b = len(x)

View file

@ -29,16 +29,19 @@
##
## proc threadFunc(interval: tuple[a,b: int]) {.thread.} =
## for i in interval.a..interval.b:
## Acquire(L) # lock stdout
## acquire(L) # lock stdout
## echo i
## Release(L)
## release(L)
##
## InitLock(L)
## initLock(L)
##
## for i in 0..high(thr):
## createThread(thr[i], threadFunc, (i*10, i*10+5))
## joinThreads(thr)
when not defined(NimString):
{.error: "You must not import this module explicitly".}
const
maxRegisters = 256 # don't think there is an arch with more registers
useStackMaskHack = false ## use the stack mask hack for better performance
@ -51,9 +54,9 @@ when defined(windows):
TSysThread = THandle
TWinThreadProc = proc (x: pointer): int32 {.stdcall.}
proc CreateThread(lpThreadAttributes: Pointer, dwStackSize: int32,
proc createThread(lpThreadAttributes: pointer, dwStackSize: int32,
lpStartAddress: TWinThreadProc,
lpParameter: Pointer,
lpParameter: pointer,
dwCreationFlags: int32,
lpThreadId: var int32): TSysThread {.
stdcall, dynlib: "kernel32", importc: "CreateThread".}
@ -64,23 +67,23 @@ when defined(windows):
proc winResumeThread(hThread: TSysThread): int32 {.
stdcall, dynlib: "kernel32", importc: "ResumeThread".}
proc WaitForMultipleObjects(nCount: int32,
proc waitForMultipleObjects(nCount: int32,
lpHandles: ptr TSysThread,
bWaitAll: int32,
dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
proc TerminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
proc terminateThread(hThread: TSysThread, dwExitCode: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "TerminateThread".}
type
TThreadVarSlot = distinct int32
proc ThreadVarAlloc(): TThreadVarSlot {.
proc threadVarAlloc(): TThreadVarSlot {.
importc: "TlsAlloc", stdcall, dynlib: "kernel32".}
proc ThreadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
proc threadVarSetValue(dwTlsIndex: TThreadVarSlot, lpTlsValue: pointer) {.
importc: "TlsSetValue", stdcall, dynlib: "kernel32".}
proc ThreadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
proc threadVarGetValue(dwTlsIndex: TThreadVarSlot): pointer {.
importc: "TlsGetValue", stdcall, dynlib: "kernel32".}
else:
@ -113,14 +116,14 @@ else:
proc pthread_cancel(a1: TSysThread): cint {.
importc: "pthread_cancel", header: "<pthread.h>".}
proc AcquireSysTimeoutAux(L: var TSysLock, timeout: var Ttimespec): cint {.
proc acquireSysTimeoutAux(L: var TSysLock, timeout: var Ttimespec): cint {.
importc: "pthread_mutex_timedlock", header: "<time.h>".}
proc AcquireSysTimeout(L: var TSysLock, msTimeout: int) {.inline.} =
proc acquireSysTimeout(L: var TSysLock, msTimeout: int) {.inline.} =
var a: Ttimespec
a.tv_sec = msTimeout div 1000
a.tv_nsec = (msTimeout mod 1000) * 1000
var res = AcquireSysTimeoutAux(L, a)
var res = acquireSysTimeoutAux(L, a)
if res != 0'i32: raise newException(EResourceExhausted, $strerror(res))
type
@ -138,11 +141,11 @@ else:
proc pthread_setspecific(a1: TThreadVarSlot, a2: pointer): int32 {.
importc: "pthread_setspecific", header: "<pthread.h>".}
proc ThreadVarAlloc(): TThreadVarSlot {.inline.} =
proc threadVarAlloc(): TThreadVarSlot {.inline.} =
discard pthread_key_create(addr(result), nil)
proc ThreadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
proc threadVarSetValue(s: TThreadVarSlot, value: pointer) {.inline.} =
discard pthread_setspecific(s, value)
proc ThreadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
proc threadVarGetValue(s: TThreadVarSlot): pointer {.inline.} =
result = pthread_getspecific(s)
when useStackMaskHack:
@ -156,7 +159,7 @@ const
when emulatedThreadVars:
# the compiler generates this proc for us, so that we can get the size of
# the thread local var block; we use this only for sanity checking though
proc NimThreadVarsSize(): int {.noconv, importc: "NimThreadVarsSize".}
proc nimThreadVarsSize(): int {.noconv, importc: "NimThreadVarsSize".}
# we preallocate a fixed size for thread local storage, so that no heap
# allocations are needed. Currently less than 7K are used on a 64bit machine.
@ -181,7 +184,7 @@ type
# XXX it'd be more efficient to not use a global variable for the
# thread storage slot, but to rely on the implementation to assign slot X
# for us... ;-)
var globalsSlot = ThreadVarAlloc()
var globalsSlot = threadVarAlloc()
#const globalsSlot = TThreadVarSlot(0)
#sysAssert checkSlot.int == globalsSlot.int
@ -190,7 +193,7 @@ when emulatedThreadVars:
result = addr(cast[PGcThread](ThreadVarGetValue(globalsSlot)).tls)
when useStackMaskHack:
proc MaskStackPointer(offset: int): pointer {.compilerRtl, inl.} =
proc maskStackPointer(offset: int): pointer {.compilerRtl, inl.} =
var x {.volatile.}: pointer
x = addr(x)
result = cast[pointer]((cast[int](x) and not ThreadStackMask) +%
@ -202,7 +205,7 @@ when not defined(useNimRtl):
when not useStackMaskHack:
var mainThread: TGcThread
ThreadVarSetValue(globalsSlot, addr(mainThread))
threadVarSetValue(globalsSlot, addr(mainThread))
when not defined(createNimRtl): initStackBottom()
initGC()
@ -217,18 +220,18 @@ when not defined(useNimRtl):
proc registerThread(t: PGcThread) =
# we need to use the GC global lock here!
AcquireSys(HeapLock)
acquireSys(HeapLock)
t.prev = nil
t.next = threadList
if threadList != nil:
sysAssert(threadList.prev == nil, "threadList.prev == nil")
threadList.prev = t
threadList = t
ReleaseSys(HeapLock)
releaseSys(HeapLock)
proc unregisterThread(t: PGcThread) =
# we need to use the GC global lock here!
AcquireSys(HeapLock)
acquireSys(HeapLock)
if t == threadList: threadList = t.next
if t.next != nil: t.next.prev = t.prev
if t.prev != nil: t.prev.next = t.next
@ -236,7 +239,7 @@ when not defined(useNimRtl):
# code executes `destroyThread`:
t.next = nil
t.prev = nil
ReleaseSys(HeapLock)
releaseSys(HeapLock)
# on UNIX, the GC uses ``SIGFREEZE`` to tell every thread to stop so that
# the GC can examine the stacks?
@ -263,7 +266,7 @@ type
when not defined(boehmgc) and not hasSharedHeap:
proc deallocOsPages()
template ThreadProcWrapperBody(closure: expr) {.immediate.} =
template threadProcWrapperBody(closure: expr) {.immediate.} =
when defined(globalsSlot): ThreadVarSetValue(globalsSlot, closure)
var t = cast[ptr TThread[TArg]](closure)
when useStackMaskHack:
@ -291,11 +294,11 @@ template ThreadProcWrapperBody(closure: expr) {.immediate.} =
{.push stack_trace:off.}
when defined(windows):
proc threadProcWrapper[TArg](closure: pointer): int32 {.stdcall.} =
ThreadProcWrapperBody(closure)
# implicitely return 0
threadProcWrapperBody(closure)
# implicitly return 0
else:
proc threadProcWrapper[TArg](closure: pointer) {.noconv.} =
ThreadProcWrapperBody(closure)
threadProcWrapperBody(closure)
{.pop.}
proc running*[TArg](t: TThread[TArg]): bool {.inline.} =
@ -305,7 +308,7 @@ proc running*[TArg](t: TThread[TArg]): bool {.inline.} =
proc joinThread*[TArg](t: TThread[TArg]) {.inline.} =
## waits for the thread `t` to finish.
when hostOS == "windows":
discard WaitForSingleObject(t.sys, -1'i32)
discard waitForSingleObject(t.sys, -1'i32)
else:
discard pthread_join(t.sys, nil)
@ -315,7 +318,7 @@ proc joinThreads*[TArg](t: varargs[TThread[TArg]]) =
var a: array[0..255, TSysThread]
sysAssert a.len >= t.len, "a.len >= t.len"
for i in 0..t.high: a[i] = t[i].sys
discard WaitForMultipleObjects(t.len.int32,
discard waitForMultipleObjects(t.len.int32,
cast[ptr TSysThread](addr(a)), 1, -1)
else:
for i in 0..t.high: joinThread(t[i])
@ -343,7 +346,7 @@ proc createThread*[TArg](t: var TThread[TArg],
when hasSharedHeap: t.stackSize = ThreadStackSize
when hostOS == "windows":
var dummyThreadId: int32
t.sys = CreateThread(nil, ThreadStackSize, threadProcWrapper[TArg],
t.sys = createThread(nil, ThreadStackSize, threadProcWrapper[TArg],
addr(t), 0'i32, dummyThreadId)
if t.sys <= 0:
raise newException(EResourceExhausted, "cannot create thread")

View file

@ -1,149 +1,153 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nimrod support for C/C++'s `wide strings`:idx:. This is part of the system
## module! Do not import it directly!
type
TUtf16Char* = distinct int16
WideCString* = ref array[0.. 1_000_000, TUtf16Char]
proc len*(w: WideCString): int =
## returns the length of a widestring. This traverses the whole string to
## find the binary zero end marker!
while int16(w[result]) != 0'i16: inc result
const
UNI_REPLACEMENT_CHAR = TUtf16Char(0xFFFD'i16)
UNI_MAX_BMP = 0x0000FFFF
UNI_MAX_UTF16 = 0x0010FFFF
UNI_MAX_UTF32 = 0x7FFFFFFF
UNI_MAX_LEGAL_UTF32 = 0x0010FFFF
halfShift = 10
halfBase = 0x0010000
halfMask = 0x3FF
UNI_SUR_HIGH_START = 0xD800
UNI_SUR_HIGH_END = 0xDBFF
UNI_SUR_LOW_START = 0xDC00
UNI_SUR_LOW_END = 0xDFFF
template ones(n: expr): expr = ((1 shl n)-1)
template fastRuneAt(s: cstring, i: int, result: expr, doInc = true) =
## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
## `i` is incremented by the number of bytes that have been processed.
bind ones
if ord(s[i]) <=% 127:
result = ord(s[i])
when doInc: inc(i)
elif ord(s[i]) shr 5 == 0b110:
#assert(ord(s[i+1]) shr 6 == 0b10)
result = (ord(s[i]) and (ones(5))) shl 6 or (ord(s[i+1]) and ones(6))
when doInc: inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110:
#assert(ord(s[i+1]) shr 6 == 0b10)
#assert(ord(s[i+2]) shr 6 == 0b10)
result = (ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6))
when doInc: inc(i, 3)
elif ord(s[i]) shr 3 == 0b11110:
#assert(ord(s[i+1]) shr 6 == 0b10)
#assert(ord(s[i+2]) shr 6 == 0b10)
#assert(ord(s[i+3]) shr 6 == 0b10)
result = (ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6))
when doInc: inc(i, 4)
else:
result = 0xFFFD
when doInc: inc(i)
iterator runes(s: cstring): int =
var
i = 0
result: int
while s[i] != '\0':
fastRuneAt(s, i, result, true)
yield result
proc newWideCString*(source: cstring, L: int): WideCString =
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## Nimrod support for C/C++'s `wide strings`:idx:. This is part of the system
## module! Do not import it directly!
when not defined(NimString):
{.error: "You must not import this module explicitly".}
type
TUtf16Char* = distinct int16
WideCString* = ref array[0.. 1_000_000, TUtf16Char]
proc len*(w: WideCString): int =
## returns the length of a widestring. This traverses the whole string to
## find the binary zero end marker!
while int16(w[result]) != 0'i16: inc result
const
UNI_REPLACEMENT_CHAR = TUtf16Char(0xFFFD'i16)
UNI_MAX_BMP = 0x0000FFFF
UNI_MAX_UTF16 = 0x0010FFFF
UNI_MAX_UTF32 = 0x7FFFFFFF
UNI_MAX_LEGAL_UTF32 = 0x0010FFFF
halfShift = 10
halfBase = 0x0010000
halfMask = 0x3FF
UNI_SUR_HIGH_START = 0xD800
UNI_SUR_HIGH_END = 0xDBFF
UNI_SUR_LOW_START = 0xDC00
UNI_SUR_LOW_END = 0xDFFF
template ones(n: expr): expr = ((1 shl n)-1)
template fastRuneAt(s: cstring, i: int, result: expr, doInc = true) =
## Returns the unicode character ``s[i]`` in `result`. If ``doInc == true``
## `i` is incremented by the number of bytes that have been processed.
bind ones
if ord(s[i]) <=% 127:
result = ord(s[i])
when doInc: inc(i)
elif ord(s[i]) shr 5 == 0b110:
#assert(ord(s[i+1]) shr 6 == 0b10)
result = (ord(s[i]) and (ones(5))) shl 6 or (ord(s[i+1]) and ones(6))
when doInc: inc(i, 2)
elif ord(s[i]) shr 4 == 0b1110:
#assert(ord(s[i+1]) shr 6 == 0b10)
#assert(ord(s[i+2]) shr 6 == 0b10)
result = (ord(s[i]) and ones(4)) shl 12 or
(ord(s[i+1]) and ones(6)) shl 6 or
(ord(s[i+2]) and ones(6))
when doInc: inc(i, 3)
elif ord(s[i]) shr 3 == 0b11110:
#assert(ord(s[i+1]) shr 6 == 0b10)
#assert(ord(s[i+2]) shr 6 == 0b10)
#assert(ord(s[i+3]) shr 6 == 0b10)
result = (ord(s[i]) and ones(3)) shl 18 or
(ord(s[i+1]) and ones(6)) shl 12 or
(ord(s[i+2]) and ones(6)) shl 6 or
(ord(s[i+3]) and ones(6))
when doInc: inc(i, 4)
else:
result = 0xFFFD
when doInc: inc(i)
iterator runes(s: cstring): int =
var
i = 0
result: int
while s[i] != '\0':
fastRuneAt(s, i, result, true)
yield result
proc newWideCString*(source: cstring, L: int): WideCString =
unsafeNew(result, L * 4 + 2)
#result = cast[wideCString](alloc(L * 4 + 2))
var d = 0
for ch in runes(source):
if ch <=% UNI_MAX_BMP:
if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_LOW_END:
result[d] = UNI_REPLACEMENT_CHAR
else:
result[d] = TUtf16Char(toU16(ch))
elif ch >% UNI_MAX_UTF16:
result[d] = UNI_REPLACEMENT_CHAR
else:
let ch = ch -% halfBase
result[d] = TUtf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
inc d
result[d] = TUtf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
inc d
result[d] = TUtf16Char(0'i16)
proc newWideCString*(s: cstring): WideCString =
if s.isNil: return nil
when not defined(c_strlen):
proc c_strlen(a: CString): int {.nodecl, noSideEffect, importc: "strlen".}
let L = cstrlen(s)
result = newWideCString(s, L)
proc newWideCString*(s: string): WideCString =
result = newWideCString(s, s.len)
proc `$`*(w: wideCString, estimate: int): string =
result = newStringOfCap(estimate + estimate shr 2)
var i = 0
while w[i].int16 != 0'i16:
var ch = w[i].int
inc i
if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_HIGH_END:
# If the 16 bits following the high surrogate are in the source buffer...
let ch2 = w[i].int
# If it's a low surrogate, convert to UTF32:
if ch2 >=% UNI_SUR_LOW_START and ch2 <=% UNI_SUR_LOW_END:
ch = ((ch -% UNI_SUR_HIGH_START) shr halfShift) +%
(ch2 -% UNI_SUR_LOW_START) +% halfBase
inc i
if ch <=% 127:
result.add chr(ch)
elif ch <=% 0x07FF:
result.add chr((ch shr 6) or 0b110_00000)
result.add chr((ch and ones(6)) or 0b10_000000)
elif ch <=% 0xFFFF:
result.add chr(ch shr 12 or 0b1110_0000)
result.add chr(ch shr 6 and ones(6) or 0b10_0000_00)
result.add chr(ch and ones(6) or 0b10_0000_00)
elif ch <=% 0x0010FFFF:
result.add chr(ch shr 18 or 0b1111_0000)
result.add chr(ch shr 12 and ones(6) or 0b10_0000_00)
result.add chr(ch shr 6 and ones(6) or 0b10_0000_00)
result.add chr(ch and ones(6) or 0b10_0000_00)
else:
# replacement char:
result.add chr(0xFFFD shr 12 or 0b1110_0000)
result.add chr(0xFFFD shr 6 and ones(6) or 0b10_0000_00)
result.add chr(0xFFFD and ones(6) or 0b10_0000_00)
proc `$`*(s: WideCString): string =
result = s $ 80
#result = cast[wideCString](alloc(L * 4 + 2))
var d = 0
for ch in runes(source):
if ch <=% UNI_MAX_BMP:
if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_LOW_END:
result[d] = UNI_REPLACEMENT_CHAR
else:
result[d] = TUtf16Char(toU16(ch))
elif ch >% UNI_MAX_UTF16:
result[d] = UNI_REPLACEMENT_CHAR
else:
let ch = ch -% halfBase
result[d] = TUtf16Char(toU16((ch shr halfShift) +% UNI_SUR_HIGH_START))
inc d
result[d] = TUtf16Char(toU16((ch and halfMask) +% UNI_SUR_LOW_START))
inc d
result[d] = TUtf16Char(0'i16)
proc newWideCString*(s: cstring): WideCString =
if s.isNil: return nil
when not defined(c_strlen):
proc c_strlen(a: cstring): int {.
header: "<string.h>", noSideEffect, importc: "strlen".}
let L = c_strlen(s)
result = newWideCString(s, L)
proc newWideCString*(s: string): WideCString =
result = newWideCString(s, s.len)
proc `$`*(w: WideCString, estimate: int): string =
result = newStringOfCap(estimate + estimate shr 2)
var i = 0
while w[i].int16 != 0'i16:
var ch = w[i].int
inc i
if ch >=% UNI_SUR_HIGH_START and ch <=% UNI_SUR_HIGH_END:
# If the 16 bits following the high surrogate are in the source buffer...
let ch2 = w[i].int
# If it's a low surrogate, convert to UTF32:
if ch2 >=% UNI_SUR_LOW_START and ch2 <=% UNI_SUR_LOW_END:
ch = ((ch -% UNI_SUR_HIGH_START) shr halfShift) +%
(ch2 -% UNI_SUR_LOW_START) +% halfBase
inc i
if ch <=% 127:
result.add chr(ch)
elif ch <=% 0x07FF:
result.add chr((ch shr 6) or 0b110_00000)
result.add chr((ch and ones(6)) or 0b10_000000)
elif ch <=% 0xFFFF:
result.add chr(ch shr 12 or 0b1110_0000)
result.add chr(ch shr 6 and ones(6) or 0b10_0000_00)
result.add chr(ch and ones(6) or 0b10_0000_00)
elif ch <=% 0x0010FFFF:
result.add chr(ch shr 18 or 0b1111_0000)
result.add chr(ch shr 12 and ones(6) or 0b10_0000_00)
result.add chr(ch shr 6 and ones(6) or 0b10_0000_00)
result.add chr(ch and ones(6) or 0b10_0000_00)
else:
# replacement char:
result.add chr(0xFFFD shr 12 or 0b1110_0000)
result.add chr(0xFFFD shr 6 and ones(6) or 0b10_0000_00)
result.add chr(0xFFFD and ones(6) or 0b10_0000_00)
proc `$`*(s: WideCString): string =
result = s $ 80

View file

@ -21856,15 +21856,9 @@ proc InflateRect*(lprc: var TRect, dx, dy: int): WINBOOL{.stdcall,
dynlib: "user32", importc: "InflateRect".}
proc InitializeAcl*(pAcl: var TACL, nAclLength, dwAclRevision: DWORD): WINBOOL{.
stdcall, dynlib: "advapi32", importc: "InitializeAcl".}
proc InitializeCriticalSectionAndSpinCount*(
lpCriticalSection: var TRTLCriticalSection, dwSpinCount: DWORD): WINBOOL{.
stdcall, dynlib: "kernel32",
importc: "InitializeCriticalSectionAndSpinCount".}
proc InitializeSid*(Sid: Pointer, pIdentifierAuthority: TSIDIdentifierAuthority,
nSubAuthorityCount: int8): WINBOOL{.stdcall,
dynlib: "advapi32", importc: "InitializeSid".}
proc InsertMenuItem*(p1: HMENU, p2: UINT, p3: WINBOOL, p4: TMenuItemInfo): WINBOOL{.
stdcall, dynlib: "user32", importc: "InsertMenuItemA".}
proc InsertMenuItemA*(p1: HMENU, p2: UINT, p3: WINBOOL, p4: TMenuItemInfoA): WINBOOL{.
stdcall, dynlib: "user32", importc: "InsertMenuItemA".}
#function InsertMenuItemW(p1: HMENU; p2: UINT; p3: WINBOOL; const p4: TMenuItemInfoW): WINBOOL; stdcall; external 'user32' name 'InsertMenuItemW';
@ -22362,11 +22356,6 @@ proc SetConsoleCursorInfo*(hConsoleOutput: THandle,
lpConsoleCursorInfo: TConsoleCursorInfo): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "SetConsoleCursorInfo".}
#function SetConsoleWindowInfo(hConsoleOutput: THandle; bAbsolute: WINBOOL; const lpConsoleWindow: TSmallRect): WINBOOL; stdcall; external 'kernel32' name 'SetConsoleWindowInfo';
proc SetCriticalSectionSpinCount*(lpCriticalSection: var TRTLCriticalSection,
dwSpinCount: DWORD): DWORD{.stdcall,
dynlib: "kernel32", importc: "SetCriticalSectionSpinCount".}
proc SetDeviceGammaRamp*(DC: HDC, Ramp: pointer): WINBOOL{.stdcall,
dynlib: "gdi32", importc: "SetDeviceGammaRamp".}
proc SetDIBColorTable*(DC: HDC, p2, p3: UINT, RGBQuadSTructs: pointer): UINT{.
stdcall, dynlib: "gdi32", importc: "SetDIBColorTable".}
proc SetDIBits*(DC: HDC, Bitmap: HBITMAP, StartScan, NumScans: UINT,
@ -22476,8 +22465,6 @@ proc TranslateMDISysAccel*(hWndClient: HWND, lpMsg: TMsg): WINBOOL{.stdcall,
proc TranslateMessage*(lpMsg: TMsg): WINBOOL{.stdcall, dynlib: "user32",
importc: "TranslateMessage".}
#function TransparentDIBits(DC: HDC; p2, p3, p4, p5: Integer; const p6: Pointer; const p7: PBitmapInfo; p8: UINT; p9, p10, p11, p12: Integer; p13: UINT): WINBOOL;stdcall; external 'gdi32' name 'TransparentDIBits';
proc TryEnterCriticalSection*(lpCriticalSection: var TRTLCriticalSection): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "TryEnterCriticalSection".}
proc UnhandledExceptionFilter*(ExceptionInfo: TExceptionPointers): int32{.
stdcall, dynlib: "kernel32", importc: "UnhandledExceptionFilter".}
proc UnionRect*(lprcDst: var TRect, lprcSrc1, lprcSrc2: TRect): WINBOOL{.
@ -22847,12 +22834,6 @@ proc SUBLANGID*(lgid: int32): int32 =
# return type might be wrong
result = toU16(lgid) shr 10'i16
proc LANGIDFROMLCID*(lcid: int32): int16 =
result = toU16(lcid)
proc SORTIDFROMLCID*(lcid: int32): int16 =
result = toU16((lcid and 0x000FFFFF'i32) shr 16'i32)
proc MAKELCID*(lgid, srtid: int32): DWORD =
result = toU32(srtid shl 16'i32 or lgid and 0xffff'i32)

View file

@ -42,13 +42,13 @@ type
wShowWindow*: int16
cbReserved2*: int16
lpReserved2*: pointer
hStdInput*: THANDLE
hStdOutput*: THANDLE
hStdError*: THANDLE
hStdInput*: THandle
hStdOutput*: THandle
hStdError*: THandle
TPROCESS_INFORMATION* {.final, pure.} = object
hProcess*: THANDLE
hThread*: THANDLE
hProcess*: THandle
hThread*: THandle
dwProcessId*: int32
dwThreadId*: int32
@ -92,39 +92,39 @@ const
DETACHED_PROCESS* = 8'i32
SW_SHOWNORMAL* = 1'i32
INVALID_HANDLE_VALUE* = THANDLE(-1)
INVALID_HANDLE_VALUE* = THandle(-1)
CREATE_UNICODE_ENVIRONMENT* = 1024'i32
proc CloseHandle*(hObject: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "CloseHandle".}
proc ReadFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
lpNumberOfBytesRead: var int32, lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "ReadFile".}
proc WriteFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
lpNumberOfBytesWritten: var int32,
lpOverlapped: pointer): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "WriteFile".}
proc CreatePipe*(hReadPipe, hWritePipe: var THandle,
proc createPipe*(hReadPipe, hWritePipe: var THandle,
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
nSize: int32): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
when useWinUnicode:
proc CreateProcessW*(lpApplicationName, lpCommandLine: widecstring,
proc createProcessW*(lpApplicationName, lpCommandLine: WideCString,
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
bInheritHandles: WINBOOL, dwCreationFlags: int32,
lpEnvironment, lpCurrentDirectory: widecstring,
lpEnvironment, lpCurrentDirectory: WideCString,
lpStartupInfo: var TSTARTUPINFO,
lpProcessInformation: var TPROCESS_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "CreateProcessW".}
else:
proc CreateProcessA*(lpApplicationName, lpCommandLine: cstring,
proc createProcessA*(lpApplicationName, lpCommandLine: cstring,
lpProcessAttributes: ptr TSECURITY_ATTRIBUTES,
lpThreadAttributes: ptr TSECURITY_ATTRIBUTES,
bInheritHandles: WINBOOL, dwCreationFlags: int32,
@ -134,75 +134,92 @@ else:
stdcall, dynlib: "kernel32", importc: "CreateProcessA".}
proc SuspendThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
proc suspendThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32",
importc: "SuspendThread".}
proc ResumeThread*(hThread: THANDLE): int32 {.stdcall, dynlib: "kernel32",
proc resumeThread*(hThread: THandle): int32 {.stdcall, dynlib: "kernel32",
importc: "ResumeThread".}
proc WaitForSingleObject*(hHandle: THANDLE, dwMilliseconds: int32): int32 {.
proc waitForSingleObject*(hHandle: THandle, dwMilliseconds: int32): int32 {.
stdcall, dynlib: "kernel32", importc: "WaitForSingleObject".}
proc TerminateProcess*(hProcess: THANDLE, uExitCode: int): WINBOOL {.stdcall,
proc terminateProcess*(hProcess: THandle, uExitCode: int): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "TerminateProcess".}
proc GetExitCodeProcess*(hProcess: THANDLE, lpExitCode: var int32): WINBOOL {.
proc getExitCodeProcess*(hProcess: THandle, lpExitCode: var int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "GetExitCodeProcess".}
proc GetStdHandle*(nStdHandle: int32): THANDLE {.stdcall, dynlib: "kernel32",
proc getStdHandle*(nStdHandle: int32): THandle {.stdcall, dynlib: "kernel32",
importc: "GetStdHandle".}
proc SetStdHandle*(nStdHandle: int32, hHandle: THANDLE): WINBOOL {.stdcall,
proc setStdHandle*(nStdHandle: int32, hHandle: THandle): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "SetStdHandle".}
proc FlushFileBuffers*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
proc flushFileBuffers*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "FlushFileBuffers".}
proc GetLastError*(): int32 {.importc, stdcall, dynlib: "kernel32".}
proc getLastError*(): int32 {.importc: "GetLastError",
stdcall, dynlib: "kernel32".}
when useWinUnicode:
proc FormatMessageW*(dwFlags: int32, lpSource: pointer,
proc formatMessageW*(dwFlags: int32, lpSource: pointer,
dwMessageId, dwLanguageId: int32,
lpBuffer: pointer, nSize: int32,
Arguments: pointer): int32 {.
importc, stdcall, dynlib: "kernel32".}
importc: "FormatMessageW", stdcall, dynlib: "kernel32".}
else:
proc FormatMessageA*(dwFlags: int32, lpSource: pointer,
proc formatMessageA*(dwFlags: int32, lpSource: pointer,
dwMessageId, dwLanguageId: int32,
lpBuffer: pointer, nSize: int32,
Arguments: pointer): int32 {.
importc, stdcall, dynlib: "kernel32".}
importc: "FormatMessageA", stdcall, dynlib: "kernel32".}
proc LocalFree*(p: pointer) {.importc, stdcall, dynlib: "kernel32".}
proc localFree*(p: pointer) {.
importc: "LocalFree", stdcall, dynlib: "kernel32".}
when useWinUnicode:
proc GetCurrentDirectoryW*(nBufferLength: int32,
lpBuffer: widecstring): int32 {.
importc, dynlib: "kernel32", stdcall.}
proc SetCurrentDirectoryW*(lpPathName: widecstring): int32 {.
importc, dynlib: "kernel32", stdcall.}
proc CreateDirectoryW*(pathName: widecstring, security: Pointer=nil): int32 {.
proc getCurrentDirectoryW*(nBufferLength: int32,
lpBuffer: WideCString): int32 {.
importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall.}
proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {.
importc: "SetCurrentDirectoryW", dynlib: "kernel32", stdcall.}
proc createDirectoryW*(pathName: WideCString, security: pointer=nil): int32 {.
importc: "CreateDirectoryW", dynlib: "kernel32", stdcall.}
proc RemoveDirectoryW*(lpPathName: widecstring): int32 {.
importc, dynlib: "kernel32", stdcall.}
proc SetEnvironmentVariableW*(lpName, lpValue: widecstring): int32 {.
stdcall, dynlib: "kernel32", importc.}
proc removeDirectoryW*(lpPathName: WideCString): int32 {.
importc: "RemoveDirectoryW", dynlib: "kernel32", stdcall.}
proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {.
stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}
proc GetModuleFileNameW*(handle: THandle, buf: wideCString,
size: int32): int32 {.importc,
proc getModuleFileNameW*(handle: THandle, buf: WideCString,
size: int32): int32 {.importc: "GetModuleFileNameW",
dynlib: "kernel32", stdcall.}
else:
proc GetCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {.
importc, dynlib: "kernel32", stdcall.}
proc SetCurrentDirectoryA*(lpPathName: cstring): int32 {.
importc, dynlib: "kernel32", stdcall.}
proc CreateDirectoryA*(pathName: cstring, security: Pointer=nil): int32 {.
proc getCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {.
importc: "GetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
proc setCurrentDirectoryA*(lpPathName: cstring): int32 {.
importc: "SetCurrentDirectoryA", dynlib: "kernel32", stdcall.}
proc createDirectoryA*(pathName: cstring, security: pointer=nil): int32 {.
importc: "CreateDirectoryA", dynlib: "kernel32", stdcall.}
proc RemoveDirectoryA*(lpPathName: cstring): int32 {.
importc, dynlib: "kernel32", stdcall.}
proc SetEnvironmentVariableA*(lpName, lpValue: cstring): int32 {.
stdcall, dynlib: "kernel32", importc.}
proc removeDirectoryA*(lpPathName: cstring): int32 {.
importc: "RemoveDirectoryA", dynlib: "kernel32", stdcall.}
proc setEnvironmentVariableA*(lpName, lpValue: cstring): int32 {.
stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableA".}
proc getModuleFileNameA*(handle: THandle, buf: cstring, size: int32): int32 {.
importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
when useWinUnicode:
proc createSymbolicLinkW*(lpSymlinkFileName, lpTargetFileName: WideCString,
flags: DWORD): int32 {.
importc:"CreateSymbolicLinkW", dynlib: "kernel32", stdcall.}
proc createHardLinkW*(lpFileName, lpExistingFileName: WideCString,
security: pointer=nil): int32 {.
importc:"CreateHardLinkW", dynlib: "kernel32", stdcall.}
else:
proc createSymbolicLinkA*(lpSymlinkFileName, lpTargetFileName: cstring,
flags: DWORD): int32 {.
importc:"CreateSymbolicLinkA", dynlib: "kernel32", stdcall.}
proc createHardLinkA*(lpFileName, lpExistingFileName: cstring,
security: pointer=nil): int32 {.
importc:"CreateHardLinkA", dynlib: "kernel32", stdcall.}
proc GetModuleFileNameA*(handle: THandle, buf: CString, size: int32): int32 {.
importc, dynlib: "kernel32", stdcall.}
const
FILE_ATTRIBUTE_ARCHIVE* = 32'i32
FILE_ATTRIBUTE_COMPRESSED* = 2048'i32
@ -210,6 +227,7 @@ const
FILE_ATTRIBUTE_DIRECTORY* = 16'i32
FILE_ATTRIBUTE_HIDDEN* = 2'i32
FILE_ATTRIBUTE_READONLY* = 1'i32
FILE_ATTRIBUTE_REPARSE_POINT* = 1024'i32
FILE_ATTRIBUTE_SYSTEM* = 4'i32
FILE_ATTRIBUTE_TEMPORARY* = 256'i32
@ -228,91 +246,97 @@ type
cAlternateFileName*: array[0..13, TWinChar]
when useWinUnicode:
proc FindFirstFileW*(lpFileName: widecstring,
lpFindFileData: var TWIN32_FIND_DATA): THANDLE {.
proc findFirstFileW*(lpFileName: WideCString,
lpFindFileData: var TWIN32_FIND_DATA): THandle {.
stdcall, dynlib: "kernel32", importc: "FindFirstFileW".}
proc FindNextFileW*(hFindFile: THANDLE,
proc findNextFileW*(hFindFile: THandle,
lpFindFileData: var TWIN32_FIND_DATA): int32 {.
stdcall, dynlib: "kernel32", importc: "FindNextFileW".}
else:
proc FindFirstFileA*(lpFileName: cstring,
proc findFirstFileA*(lpFileName: cstring,
lpFindFileData: var TWIN32_FIND_DATA): THANDLE {.
stdcall, dynlib: "kernel32", importc: "FindFirstFileA".}
proc FindNextFileA*(hFindFile: THANDLE,
proc findNextFileA*(hFindFile: THANDLE,
lpFindFileData: var TWIN32_FIND_DATA): int32 {.
stdcall, dynlib: "kernel32", importc: "FindNextFileA".}
proc FindClose*(hFindFile: THANDLE) {.stdcall, dynlib: "kernel32",
proc findClose*(hFindFile: THandle) {.stdcall, dynlib: "kernel32",
importc: "FindClose".}
when useWinUnicode:
proc GetFullPathNameW*(lpFileName: widecstring, nBufferLength: int32,
lpBuffer: widecstring,
lpFilePart: var widecstring): int32 {.
stdcall, dynlib: "kernel32", importc.}
proc GetFileAttributesW*(lpFileName: widecstring): int32 {.
stdcall, dynlib: "kernel32", importc.}
proc SetFileAttributesW*(lpFileName: widecstring,
proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32,
lpBuffer: WideCString,
lpFilePart: var WideCString): int32 {.
stdcall, dynlib: "kernel32",
importc: "GetFullPathNameW".}
proc getFileAttributesW*(lpFileName: WideCString): int32 {.
stdcall, dynlib: "kernel32",
importc: "GetFileAttributesW".}
proc setFileAttributesW*(lpFileName: WideCString,
dwFileAttributes: int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "SetFileAttributesW".}
proc CopyFileW*(lpExistingFileName, lpNewFileName: wideCString,
proc copyFileW*(lpExistingFileName, lpNewFileName: WideCString,
bFailIfExists: cint): cint {.
importc, stdcall, dynlib: "kernel32".}
importc: "CopyFileW", stdcall, dynlib: "kernel32".}
proc GetEnvironmentStringsW*(): widecstring {.
stdcall, dynlib: "kernel32", importc.}
proc FreeEnvironmentStringsW*(para1: widecstring): int32 {.
stdcall, dynlib: "kernel32", importc.}
proc getEnvironmentStringsW*(): WideCString {.
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsW".}
proc freeEnvironmentStringsW*(para1: WideCString): int32 {.
stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsW".}
proc GetCommandLineW*(): wideCString {.importc, stdcall, dynlib: "kernel32".}
proc getCommandLineW*(): WideCString {.importc: "GetCommandLineW",
stdcall, dynlib: "kernel32".}
else:
proc GetFullPathNameA*(lpFileName: cstring, nBufferLength: int32,
proc getFullPathNameA*(lpFileName: cstring, nBufferLength: int32,
lpBuffer: cstring, lpFilePart: var cstring): int32 {.
stdcall, dynlib: "kernel32", importc.}
proc GetFileAttributesA*(lpFileName: cstring): int32 {.
stdcall, dynlib: "kernel32", importc.}
proc SetFileAttributesA*(lpFileName: cstring,
stdcall, dynlib: "kernel32",
importc: "GetFullPathNameA".}
proc getFileAttributesA*(lpFileName: cstring): int32 {.
stdcall, dynlib: "kernel32",
importc: "GetFileAttributesA".}
proc setFileAttributesA*(lpFileName: cstring,
dwFileAttributes: int32): WINBOOL {.
stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}
proc CopyFileA*(lpExistingFileName, lpNewFileName: CString,
proc copyFileA*(lpExistingFileName, lpNewFileName: cstring,
bFailIfExists: cint): cint {.
importc, stdcall, dynlib: "kernel32".}
importc: "CopyFileA", stdcall, dynlib: "kernel32".}
proc GetEnvironmentStringsA*(): cstring {.
stdcall, dynlib: "kernel32", importc.}
proc FreeEnvironmentStringsA*(para1: cstring): int32 {.
stdcall, dynlib: "kernel32", importc.}
proc getEnvironmentStringsA*(): cstring {.
stdcall, dynlib: "kernel32", importc: "GetEnvironmentStringsA".}
proc freeEnvironmentStringsA*(para1: cstring): int32 {.
stdcall, dynlib: "kernel32", importc: "FreeEnvironmentStringsA".}
proc GetCommandLineA*(): CString {.importc, stdcall, dynlib: "kernel32".}
proc getCommandLineA*(): cstring {.
importc: "GetCommandLineA", stdcall, dynlib: "kernel32".}
proc rdFileTime*(f: TFILETIME): int64 =
result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32)
proc rdFileSize*(f: TWin32FindData): int64 =
proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32)
proc GetSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
importc: "GetSystemTimeAsFileTime", dynlib: "kernel32", stdcall.}
proc Sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32",
proc sleep*(dwMilliseconds: int32){.stdcall, dynlib: "kernel32",
importc: "Sleep".}
when useWinUnicode:
proc ShellExecuteW*(HWND: THandle, lpOperation, lpFile,
lpParameters, lpDirectory: widecstring,
proc shellExecuteW*(HWND: THandle, lpOperation, lpFile,
lpParameters, lpDirectory: WideCString,
nShowCmd: int32): THandle{.
stdcall, dynlib: "shell32.dll", importc: "ShellExecuteW".}
else:
proc ShellExecuteA*(HWND: THandle, lpOperation, lpFile,
proc shellExecuteA*(HWND: THandle, lpOperation, lpFile,
lpParameters, lpDirectory: cstring,
nShowCmd: int32): THandle{.
stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
proc GetFileInformationByHandle*(hFile: THandle,
proc getFileInformationByHandle*(hFile: THandle,
lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{.
stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}
@ -332,7 +356,7 @@ const
WSAEWOULDBLOCK* = 10035
WSAEINPROGRESS* = 10036
proc WSAGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
proc wsaGetLastError*(): cint {.importc: "WSAGetLastError", dynlib: ws2dll.}
type
TSocketHandle* = distinct int
@ -410,23 +434,23 @@ type
ai_addr*: ptr TSockAddr ## Socket address of socket.
ai_next*: ptr TAddrInfo ## Pointer to next in list.
Tsocklen* = cuint
TSockLen* = cuint
var
SOMAXCONN* {.importc, header: "Winsock2.h".}: cint
INVALID_SOCKET* {.importc, header: "Winsock2.h".}: TSocketHandle
SOL_SOCKET* {.importc, header: "Winsock2.h".}: cint
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse
SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive
SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses
SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs
SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible
SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present
SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line
SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
SO_DEBUG* {.importc, header: "Winsock2.h".}: cint ## turn on debugging info recording
SO_ACCEPTCONN* {.importc, header: "Winsock2.h".}: cint # socket has had listen()
SO_REUSEADDR* {.importc, header: "Winsock2.h".}: cint # allow local address reuse
SO_KEEPALIVE* {.importc, header: "Winsock2.h".}: cint # keep connections alive
SO_DONTROUTE* {.importc, header: "Winsock2.h".}: cint # just use interface addresses
SO_BROADCAST* {.importc, header: "Winsock2.h".}: cint # permit sending of broadcast msgs
SO_USELOOPBACK* {.importc, header: "Winsock2.h".}: cint # bypass hardware when possible
SO_LINGER* {.importc, header: "Winsock2.h".}: cint # linger on close if data present
SO_OOBINLINE* {.importc, header: "Winsock2.h".}: cint # leave received OOB data in line
SO_DONTLINGER* {.importc, header: "Winsock2.h".}: cint
SO_EXCLUSIVEADDRUSE* {.importc, header: "Winsock2.h".}: cint # disallow local address reuse
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
@ -437,10 +461,10 @@ proc getservbyname*(name, proto: cstring): ptr TServent {.
proc getservbyport*(port: cint, proto: cstring): ptr TServent {.
stdcall, importc: "getservbyport", dynlib: ws2dll.}
proc gethostbyaddr*(ip: ptr TInAddr, len: cuint, theType: cint): ptr THostEnt {.
proc gethostbyaddr*(ip: ptr TInAddr, len: cuint, theType: cint): ptr Thostent {.
stdcall, importc: "gethostbyaddr", dynlib: ws2dll.}
proc gethostbyname*(name: cstring): ptr THostEnt {.
proc gethostbyname*(name: cstring): ptr Thostent {.
stdcall, importc: "gethostbyname", dynlib: ws2dll.}
proc socket*(af, typ, protocol: cint): TSocketHandle {.
@ -470,7 +494,7 @@ proc listen*(s: TSocketHandle, backlog: cint): cint {.
proc recv*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
stdcall, importc: "recv", dynlib: ws2dll.}
proc recvfrom*(s: TSocketHandle, buf: cstring, len, flags: cint,
fromm: ptr TSockAddr, fromlen: ptr Tsocklen): cint {.
fromm: ptr TSockAddr, fromlen: ptr TSockLen): cint {.
stdcall, importc: "recvfrom", dynlib: ws2dll.}
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
timeout: ptr TTimeval): cint {.
@ -478,35 +502,35 @@ proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
proc send*(s: TSocketHandle, buf: pointer, len, flags: cint): cint {.
stdcall, importc: "send", dynlib: ws2dll.}
proc sendto*(s: TSocketHandle, buf: pointer, len, flags: cint,
to: ptr TSockAddr, tolen: Tsocklen): cint {.
to: ptr TSockAddr, tolen: TSockLen): cint {.
stdcall, importc: "sendto", dynlib: ws2dll.}
proc shutdown*(s: TSocketHandle, how: cint): cint {.
stdcall, importc: "shutdown", dynlib: ws2dll.}
proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
a3: cstring, a4: Tsocklen, a5: cstring,
a6: Tsocklen, a7: cint): cint {.
proc getnameinfo*(a1: ptr TSockAddr, a2: TSockLen,
a3: cstring, a4: TSockLen, a5: cstring,
a6: TSockLen, a7: cint): cint {.
stdcall, importc: "getnameinfo", dynlib: ws2dll.}
proc inet_addr*(cp: cstring): int32 {.
stdcall, importc: "inet_addr", dynlib: ws2dll.}
proc WSAFDIsSet(s: TSocketHandle, FDSet: var TFDSet): bool {.
proc WSAFDIsSet(s: TSocketHandle, FDSet: var TFdSet): bool {.
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll.}
proc FD_ISSET*(Socket: TSocketHandle, FDSet: var TFDSet): cint =
proc FD_ISSET*(Socket: TSocketHandle, FDSet: var TFdSet): cint =
result = if WSAFDIsSet(Socket, FDSet): 1'i32 else: 0'i32
proc FD_SET*(Socket: TSocketHandle, FDSet: var TFDSet) =
proc FD_SET*(Socket: TSocketHandle, FDSet: var TFdSet) =
if FDSet.fd_count < FD_SETSIZE:
FDSet.fd_array[int(FDSet.fd_count)] = Socket
inc(FDSet.fd_count)
proc FD_ZERO*(FDSet: var TFDSet) =
proc FD_ZERO*(FDSet: var TFdSet) =
FDSet.fd_count = 0
proc WSAStartup*(wVersionRequired: int16, WSData: ptr TWSAData): cint {.
proc wsaStartup*(wVersionRequired: int16, WSData: ptr TWSAData): cint {.
stdcall, importc: "WSAStartup", dynlib: ws2dll.}
proc getaddrinfo*(nodename, servname: cstring, hints: ptr TAddrInfo,
@ -523,10 +547,10 @@ const
MAXIMUM_WAIT_OBJECTS* = 0x00000040
type
TWOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, THANDLE]
TWOHandleArray* = array[0..MAXIMUM_WAIT_OBJECTS - 1, THandle]
PWOHandleArray* = ptr TWOHandleArray
proc WaitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
@ -553,50 +577,58 @@ const
FILE_FLAG_BACKUP_SEMANTICS* = 33554432'i32
# Error Constants
const
ERROR_ACCESS_DENIED* = 5
when useWinUnicode:
proc CreateFileW*(lpFileName: widecstring, dwDesiredAccess, dwShareMode: DWORD,
proc createFileW*(lpFileName: WideCString, dwDesiredAccess, dwShareMode: DWORD,
lpSecurityAttributes: pointer,
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
hTemplateFile: THANDLE): THANDLE {.
hTemplateFile: THandle): THandle {.
stdcall, dynlib: "kernel32", importc: "CreateFileW".}
proc deleteFileW*(pathName: WideCString): int32 {.
importc: "DeleteFileW", dynlib: "kernel32", stdcall.}
else:
proc CreateFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD,
proc createFileA*(lpFileName: cstring, dwDesiredAccess, dwShareMode: DWORD,
lpSecurityAttributes: pointer,
dwCreationDisposition, dwFlagsAndAttributes: DWORD,
hTemplateFile: THANDLE): THANDLE {.
stdcall, dynlib: "kernel32", importc: "CreateFileA".}
proc deleteFileA*(pathName: cstring): int32 {.
importc: "DeleteFileA", dynlib: "kernel32", stdcall.}
proc SetEndOfFile*(hFile: THANDLE): WINBOOL {.stdcall, dynlib: "kernel32",
proc setEndOfFile*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
importc: "SetEndOfFile".}
proc SetFilePointer*(hFile: THANDLE, lDistanceToMove: LONG,
proc setFilePointer*(hFile: THandle, lDistanceToMove: LONG,
lpDistanceToMoveHigh: ptr LONG,
dwMoveMethod: DWORD): DWORD {.
stdcall, dynlib: "kernel32", importc: "SetFilePointer".}
proc GetFileSize*(hFile: THANDLE, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
proc getFileSize*(hFile: THandle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
dynlib: "kernel32", importc: "GetFileSize".}
proc MapViewOfFileEx*(hFileMappingObject: THANDLE, dwDesiredAccess: DWORD,
proc mapViewOfFileEx*(hFileMappingObject: THandle, dwDesiredAccess: DWORD,
dwFileOffsetHigh, dwFileOffsetLow: DWORD,
dwNumberOfBytesToMap: DWORD,
lpBaseAddress: pointer): pointer{.
stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".}
proc CreateFileMappingW*(hFile: THANDLE,
proc createFileMappingW*(hFile: THandle,
lpFileMappingAttributes: pointer,
flProtect, dwMaximumSizeHigh: DWORD,
dwMaximumSizeLow: DWORD,
lpName: pointer): THANDLE {.
lpName: pointer): THandle {.
stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}
when not useWinUnicode:
proc CreateFileMappingA*(hFile: THANDLE,
proc createFileMappingA*(hFile: THANDLE,
lpFileMappingAttributes: pointer,
flProtect, dwMaximumSizeHigh: DWORD,
dwMaximumSizeLow: DWORD, lpName: cstring): THANDLE {.
stdcall, dynlib: "kernel32", importc: "CreateFileMappingA".}
proc UnmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall,
proc unmapViewOfFile*(lpBaseAddress: pointer): WINBOOL {.stdcall,
dynlib: "kernel32", importc: "UnmapViewOfFile".}

View file

@ -1,733 +0,0 @@
#* cairo - a vector graphics library with display and print output
# *
# * Copyright © 2002 University of Southern California
# * Copyright © 2005 Red Hat, Inc.
# *
# * This library is free software; you can redistribute it and/or
# * modify it either under the terms of the GNU Lesser General Public
# * License version 2.1 as published by the Free Software Foundation
# * (the "LGPL") or, at your option, under the terms of the Mozilla
# * Public License Version 1.1 (the "MPL"). If you do not alter this
# * notice, a recipient may use your version of this file under either
# * the MPL or the LGPL.
# *
# * You should have received a copy of the LGPL along with this library
# * in the file COPYING-LGPL-2.1; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# * You should have received a copy of the MPL along with this library
# * in the file COPYING-MPL-1.1
# *
# * The contents of this file are subject to the Mozilla Public License
# * Version 1.1 (the "License"); you may not use this file except in
# * compliance with the License. You may obtain a copy of the License at
# * http://www.mozilla.org/MPL/
# *
# * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
# * OF ANY KIND, either express or implied. See the LGPL or the MPL for
# * the specific language governing rights and limitations.
# *
# * The Original Code is the cairo graphics library.
# *
# * The Initial Developer of the Original Code is University of Southern
# * California.
# *
# * Contributor(s):
# * Carl D. Worth <cworth@cworth.org>
# #*
# * This FreePascal binding generated August 26, 2005
# * by Jeffrey Pohlmeyer <yetanothergeek@yahoo.com>
#
#
# - Updated to cairo version 1.4
# - Grouped OS specific fuctions in separated units
# - Organized the functions by group and ordered exactly as the c header
# - Cleared parameter list syntax according to pascal standard
#
# By Luiz Américo Pereira Câmara
# October 2007
#
include "cairo_pragma.nim"
type
PByte = cstring
TStatus* = enum
STATUS_SUCCESS = 0,
STATUS_NO_MEMORY,
STATUS_INVALID_RESTORE,
STATUS_INVALID_POP_GROUP,
STATUS_NO_CURRENT_POINT,
STATUS_INVALID_MATRIX,
STATUS_INVALID_STATUS,
STATUS_NULL_POINTER,
STATUS_INVALID_STRING,
STATUS_INVALID_PATH_DATA,
STATUS_READ_ERROR,
STATUS_WRITE_ERROR,
STATUS_SURFACE_FINISHED,
STATUS_SURFACE_TYPE_MISMATCH,
STATUS_PATTERN_TYPE_MISMATCH,
STATUS_INVALID_CONTENT,
STATUS_INVALID_FORMAT,
STATUS_INVALID_VISUAL,
STATUS_FILE_NOT_FOUND,
STATUS_INVALID_DASH,
STATUS_INVALID_DSC_COMMENT,
STATUS_INVALID_INDEX,
STATUS_CLIP_NOT_REPRESENTABLE,
STATUS_TEMP_FILE_ERROR,
STATUS_INVALID_STRIDE,
STATUS_FONT_TYPE_MISMATCH,
STATUS_USER_FONT_IMMUTABLE,
STATUS_USER_FONT_ERROR,
STATUS_NEGATIVE_COUNT,
STATUS_INVALID_CLUSTERS,
STATUS_INVALID_SLANT,
STATUS_INVALID_WEIGHT
TOperator* = enum
OPERATOR_CLEAR, OPERATOR_SOURCE, OPERATOR_OVER, OPERATOR_IN, OPERATOR_OUT,
OPERATOR_ATOP, OPERATOR_DEST, OPERATOR_DEST_OVER, OPERATOR_DEST_IN,
OPERATOR_DEST_OUT, OPERATOR_DEST_ATOP, OPERATOR_XOR, OPERATOR_ADD,
OPERATOR_SATURATE
TAntialias* = enum
ANTIALIAS_DEFAULT, ANTIALIAS_NONE, ANTIALIAS_GRAY, ANTIALIAS_SUBPIXEL
TFillRule* = enum
FILL_RULE_WINDING, FILL_RULE_EVEN_ODD
TLineCap* = enum
LINE_CAP_BUTT, LINE_CAP_ROUND, LINE_CAP_SQUARE
TLineJoin* = enum
LINE_JOIN_MITER, LINE_JOIN_ROUND, LINE_JOIN_BEVEL
TFontSlant* = enum
FONT_SLANT_NORMAL, FONT_SLANT_ITALIC, FONT_SLANT_OBLIQUE
TFontWeight* = enum
FONT_WEIGHT_NORMAL, FONT_WEIGHT_BOLD
TSubpixelOrder* = enum
SUBPIXEL_ORDER_DEFAULT, SUBPIXEL_ORDER_RGB, SUBPIXEL_ORDER_BGR,
SUBPIXEL_ORDER_VRGB, SUBPIXEL_ORDER_VBGR
THintStyle* = enum
HINT_STYLE_DEFAULT, HINT_STYLE_NONE, HINT_STYLE_SLIGHT, HINT_STYLE_MEDIUM,
HINT_STYLE_FULL
THintMetrics* = enum
HINT_METRICS_DEFAULT, HINT_METRICS_OFF, HINT_METRICS_ON
TPathDataType* = enum
PATH_MOVE_TO, PATH_LINE_TO, PATH_CURVE_TO, PATH_CLOSE_PATH
TContent* = enum
CONTENT_COLOR = 0x00001000, CONTENT_ALPHA = 0x00002000,
CONTENT_COLOR_ALPHA = 0x00003000
TFormat* = enum
FORMAT_ARGB32, FORMAT_RGB24, FORMAT_A8, FORMAT_A1
TExtend* = enum
EXTEND_NONE, EXTEND_REPEAT, EXTEND_REFLECT, EXTEND_PAD
TFilter* = enum
FILTER_FAST, FILTER_GOOD, FILTER_BEST, FILTER_NEAREST, FILTER_BILINEAR,
FILTER_GAUSSIAN
TFontType* = enum
FONT_TYPE_TOY, FONT_TYPE_FT, FONT_TYPE_WIN32, FONT_TYPE_ATSUI
TPatternType* = enum
PATTERN_TYPE_SOLID, PATTERN_TYPE_SURFACE, PATTERN_TYPE_LINEAR,
PATTERN_TYPE_RADIAL
TSurfaceType* = enum
SURFACE_TYPE_IMAGE, SURFACE_TYPE_PDF, SURFACE_TYPE_PS, SURFACE_TYPE_XLIB,
SURFACE_TYPE_XCB, SURFACE_TYPE_GLITZ, SURFACE_TYPE_QUARTZ,
SURFACE_TYPE_WIN32, SURFACE_TYPE_BEOS, SURFACE_TYPE_DIRECTFB,
SURFACE_TYPE_SVG, SURFACE_TYPE_OS2
TSvgVersion* = enum
SVG_VERSION_1_1, SVG_VERSION_1_2
PSurface* = ptr TSurface
PPSurface* = ptr PSurface
PContext* = ptr TContext
PPattern* = ptr TPattern
PFontOptions* = ptr TFontOptions
PFontFace* = ptr TFontFace
PScaledFont* = ptr TScaledFont
PBool* = ptr TBool
TBool* = int32
PMatrix* = ptr TMatrix
PUserDataKey* = ptr TUserDataKey
PGlyph* = ptr TGlyph
PTextExtents* = ptr TTextExtents
PFontExtents* = ptr TFontExtents
PPathDataType* = ptr TPathDataType
PPathData* = ptr TPathData
PPath* = ptr TPath
PRectangle* = ptr TRectangle
PRectangleList* = ptr TRectangleList
TDestroyFunc* = proc (data: Pointer){.cdecl.}
TWriteFunc* = proc (closure: Pointer, data: PByte, len: int32): TStatus{.cdecl.}
TReadFunc* = proc (closure: Pointer, data: PByte, len: int32): TStatus{.cdecl.}
TContext*{.final.} = object #OPAQUE
TSurface*{.final.} = object #OPAQUE
TPattern*{.final.} = object #OPAQUE
TScaledFont*{.final.} = object #OPAQUE
TFontFace*{.final.} = object #OPAQUE
TFontOptions*{.final.} = object #OPAQUE
TMatrix*{.final.} = object
xx: float64
yx: float64
xy: float64
yy: float64
x0: float64
y0: float64
TUserDataKey*{.final.} = object
unused: int32
TGlyph*{.final.} = object
index: int32
x: float64
y: float64
TTextExtents*{.final.} = object
x_bearing: float64
y_bearing: float64
width: float64
height: float64
x_advance: float64
y_advance: float64
TFontExtents*{.final.} = object
ascent: float64
descent: float64
height: float64
max_x_advance: float64
max_y_advance: float64
TPathData*{.final.} = object #* _type : TCairoPathDataType;
# length : LongInt;
# end
x: float64
y: float64
TPath*{.final.} = object
status: TStatus
data: PPathData
num_data: int32
TRectangle*{.final.} = object
x, y, width, height: float64
TRectangleList*{.final.} = object
status: TStatus
rectangles: PRectangle
num_rectangles: int32
proc version*(): int32{.cdecl, importc: "cairo_version", libcairo.}
proc version_string*(): cstring{.cdecl, importc: "cairo_version_string",
libcairo.}
#Helper function to retrieve decoded version
proc version*(major, minor, micro: var int32)
#* Functions for manipulating state objects
proc create*(target: PSurface): PContext{.cdecl, importc: "cairo_create",
libcairo.}
proc reference*(cr: PContext): PContext{.cdecl, importc: "cairo_reference", libcairo.}
proc destroy*(cr: PContext){.cdecl, importc: "cairo_destroy", libcairo.}
proc get_reference_count*(cr: PContext): int32{.cdecl,
importc: "cairo_get_reference_count", libcairo.}
proc get_user_data*(cr: PContext, key: PUserDataKey): pointer{.cdecl,
importc: "cairo_get_user_data", libcairo.}
proc set_user_data*(cr: PContext, key: PUserDataKey, user_data: Pointer,
destroy: TDestroyFunc): TStatus{.cdecl,
importc: "cairo_set_user_data", libcairo.}
proc save*(cr: PContext){.cdecl, importc: "cairo_save", libcairo.}
proc restore*(cr: PContext){.cdecl, importc: "cairo_restore", libcairo.}
proc push_group*(cr: PContext){.cdecl, importc: "cairo_push_group", libcairo.}
proc push_group_with_content*(cr: PContext, content: TContent){.cdecl,
importc: "cairo_push_group_with_content", libcairo.}
proc pop_group*(cr: PContext): PPattern{.cdecl, importc: "cairo_pop_group",
libcairo.}
proc pop_group_to_source*(cr: PContext){.cdecl, importc: "cairo_pop_group_to_source",
libcairo.}
#* Modify state
proc set_operator*(cr: PContext, op: TOperator){.cdecl, importc: "cairo_set_operator",
libcairo.}
proc set_source*(cr: PContext, source: PPattern){.cdecl, importc: "cairo_set_source",
libcairo.}
proc set_source_rgb*(cr: PContext, red, green, blue: float64){.cdecl,
importc: "cairo_set_source_rgb", libcairo.}
proc set_source_rgba*(cr: PContext, red, green, blue, alpha: float64){.cdecl,
importc: "cairo_set_source_rgba", libcairo.}
proc set_source*(cr: PContext, surface: PSurface, x, y: float64){.cdecl,
importc: "cairo_set_source_surface", libcairo.}
proc set_tolerance*(cr: PContext, tolerance: float64){.cdecl,
importc: "cairo_set_tolerance", libcairo.}
proc set_antialias*(cr: PContext, antialias: TAntialias){.cdecl,
importc: "cairo_set_antialias", libcairo.}
proc set_fill_rule*(cr: PContext, fill_rule: TFillRule){.cdecl,
importc: "cairo_set_fill_rule", libcairo.}
proc set_line_width*(cr: PContext, width: float64){.cdecl,
importc: "cairo_set_line_width", libcairo.}
proc set_line_cap*(cr: PContext, line_cap: TLineCap){.cdecl,
importc: "cairo_set_line_cap", libcairo.}
proc set_line_join*(cr: PContext, line_join: TLineJoin){.cdecl,
importc: "cairo_set_line_join", libcairo.}
proc set_dash*(cr: PContext, dashes: openarray[float64], offset: float64){.cdecl,
importc: "cairo_set_dash", libcairo.}
proc set_miter_limit*(cr: PContext, limit: float64){.cdecl,
importc: "cairo_set_miter_limit", libcairo.}
proc translate*(cr: PContext, tx, ty: float64){.cdecl, importc: "cairo_translate",
libcairo.}
proc scale*(cr: PContext, sx, sy: float64){.cdecl, importc: "cairo_scale",
libcairo.}
proc rotate*(cr: PContext, angle: float64){.cdecl, importc: "cairo_rotate",
libcairo.}
proc transform*(cr: PContext, matrix: PMatrix){.cdecl, importc: "cairo_transform",
libcairo.}
proc set_matrix*(cr: PContext, matrix: PMatrix){.cdecl, importc: "cairo_set_matrix",
libcairo.}
proc identity_matrix*(cr: PContext){.cdecl, importc: "cairo_identity_matrix",
libcairo.}
proc user_to_device*(cr: PContext, x, y: var float64){.cdecl,
importc: "cairo_user_to_device", libcairo.}
proc user_to_device_distance*(cr: PContext, dx, dy: var float64){.cdecl,
importc: "cairo_user_to_device_distance", libcairo.}
proc device_to_user*(cr: PContext, x, y: var float64){.cdecl,
importc: "cairo_device_to_user", libcairo.}
proc device_to_user_distance*(cr: PContext, dx, dy: var float64){.cdecl,
importc: "cairo_device_to_user_distance", libcairo.}
#* Path creation functions
proc new_path*(cr: PContext){.cdecl, importc: "cairo_new_path", libcairo.}
proc move_to*(cr: PContext, x, y: float64){.cdecl, importc: "cairo_move_to",
libcairo.}
proc new_sub_path*(cr: PContext){.cdecl, importc: "cairo_new_sub_path",
libcairo.}
proc line_to*(cr: PContext, x, y: float64){.cdecl, importc: "cairo_line_to",
libcairo.}
proc curve_to*(cr: PContext, x1, y1, x2, y2, x3, y3: float64){.cdecl,
importc: "cairo_curve_to", libcairo.}
proc arc*(cr: PContext, xc, yc, radius, angle1, angle2: float64){.cdecl,
importc: "cairo_arc", libcairo.}
proc arc_negative*(cr: PContext, xc, yc, radius, angle1, angle2: float64){.cdecl,
importc: "cairo_arc_negative", libcairo.}
proc rel_move_to*(cr: PContext, dx, dy: float64){.cdecl, importc: "cairo_rel_move_to",
libcairo.}
proc rel_line_to*(cr: PContext, dx, dy: float64){.cdecl, importc: "cairo_rel_line_to",
libcairo.}
proc rel_curve_to*(cr: PContext, dx1, dy1, dx2, dy2, dx3, dy3: float64){.cdecl,
importc: "cairo_rel_curve_to", libcairo.}
proc rectangle*(cr: PContext, x, y, width, height: float64){.cdecl,
importc: "cairo_rectangle", libcairo.}
proc close_path*(cr: PContext){.cdecl, importc: "cairo_close_path", libcairo.}
#* Painting functions
proc paint*(cr: PContext){.cdecl, importc: "cairo_paint", libcairo.}
proc paint_with_alpha*(cr: PContext, alpha: float64){.cdecl,
importc: "cairo_paint_with_alpha", libcairo.}
proc mask*(cr: PContext, pattern: PPattern){.cdecl, importc: "cairo_mask",
libcairo.}
proc mask*(cr: PContext, surface: PSurface, surface_x, surface_y: float64){.
cdecl, importc: "cairo_mask_surface", libcairo.}
proc stroke*(cr: PContext){.cdecl, importc: "cairo_stroke", libcairo.}
proc stroke_preserve*(cr: PContext){.cdecl, importc: "cairo_stroke_preserve",
libcairo.}
proc fill*(cr: PContext){.cdecl, importc: "cairo_fill", libcairo.}
proc fill_preserve*(cr: PContext){.cdecl, importc: "cairo_fill_preserve",
libcairo.}
proc copy_page*(cr: PContext){.cdecl, importc: "cairo_copy_page", libcairo.}
proc show_page*(cr: PContext){.cdecl, importc: "cairo_show_page", libcairo.}
#* Insideness testing
proc in_stroke*(cr: PContext, x, y: float64): TBool{.cdecl, importc: "cairo_in_stroke",
libcairo.}
proc in_fill*(cr: PContext, x, y: float64): TBool{.cdecl, importc: "cairo_in_fill",
libcairo.}
#* Rectangular extents
proc stroke_extents*(cr: PContext, x1, y1, x2, y2: var float64){.cdecl,
importc: "cairo_stroke_extents", libcairo.}
proc fill_extents*(cr: PContext, x1, y1, x2, y2: var float64){.cdecl,
importc: "cairo_fill_extents", libcairo.}
#* Clipping
proc reset_clip*(cr: PContext){.cdecl, importc: "cairo_reset_clip", libcairo.}
proc clip*(cr: PContext){.cdecl, importc: "cairo_clip", libcairo.}
proc clip_preserve*(cr: PContext){.cdecl, importc: "cairo_clip_preserve",
libcairo.}
proc clip_extents*(cr: PContext, x1, y1, x2, y2: var float64){.cdecl,
importc: "cairo_clip_extents", libcairo.}
proc copy_clip_rectangle_list*(cr: PContext): PRectangleList{.cdecl,
importc: "cairo_copy_clip_rectangle_list", libcairo.}
proc rectangle_list_destroy*(rectangle_list: PRectangleList){.cdecl,
importc: "cairo_rectangle_list_destroy", libcairo.}
#* Font/Text functions
proc font_options_create*(): PFontOptions{.cdecl,
importc: "cairo_font_options_create", libcairo.}
proc copy*(original: PFontOptions): PFontOptions{.cdecl,
importc: "cairo_font_options_copy", libcairo.}
proc destroy*(options: PFontOptions){.cdecl,
importc: "cairo_font_options_destroy", libcairo.}
proc status*(options: PFontOptions): TStatus{.cdecl,
importc: "cairo_font_options_status", libcairo.}
proc merge*(options, other: PFontOptions){.cdecl,
importc: "cairo_font_options_merge", libcairo.}
proc equal*(options, other: PFontOptions): TBool{.cdecl,
importc: "cairo_font_options_equal", libcairo.}
proc hash*(options: PFontOptions): int32{.cdecl,
importc: "cairo_font_options_hash", libcairo.}
proc set_antialias*(options: PFontOptions, antialias: TAntialias){.
cdecl, importc: "cairo_font_options_set_antialias", libcairo.}
proc get_antialias*(options: PFontOptions): TAntialias{.cdecl,
importc: "cairo_font_options_get_antialias", libcairo.}
proc set_subpixel_order*(options: PFontOptions,
subpixel_order: TSubpixelOrder){.cdecl,
importc: "cairo_font_options_set_subpixel_order", libcairo.}
proc get_subpixel_order*(options: PFontOptions): TSubpixelOrder{.
cdecl, importc: "cairo_font_options_get_subpixel_order", libcairo.}
proc set_hint_style*(options: PFontOptions, hint_style: THintStyle){.
cdecl, importc: "cairo_font_options_set_hint_style", libcairo.}
proc get_hint_style*(options: PFontOptions): THintStyle{.cdecl,
importc: "cairo_font_options_get_hint_style", libcairo.}
proc set_hint_metrics*(options: PFontOptions,
hint_metrics: THintMetrics){.cdecl,
importc: "cairo_font_options_set_hint_metrics", libcairo.}
proc get_hint_metrics*(options: PFontOptions): THintMetrics{.cdecl,
importc: "cairo_font_options_get_hint_metrics", libcairo.}
#* This interface is for dealing with text as text, not caring about the
# font object inside the the TCairo.
proc select_font_face*(cr: PContext, family: cstring, slant: TFontSlant,
weight: TFontWeight){.cdecl,
importc: "cairo_select_font_face", libcairo.}
proc set_font_size*(cr: PContext, size: float64){.cdecl,
importc: "cairo_set_font_size", libcairo.}
proc set_font_matrix*(cr: PContext, matrix: PMatrix){.cdecl,
importc: "cairo_set_font_matrix", libcairo.}
proc get_font_matrix*(cr: PContext, matrix: PMatrix){.cdecl,
importc: "cairo_get_font_matrix", libcairo.}
proc set_font_options*(cr: PContext, options: PFontOptions){.cdecl,
importc: "cairo_set_font_options", libcairo.}
proc get_font_options*(cr: PContext, options: PFontOptions){.cdecl,
importc: "cairo_get_font_options", libcairo.}
proc set_font_face*(cr: PContext, font_face: PFontFace){.cdecl,
importc: "cairo_set_font_face", libcairo.}
proc get_font_face*(cr: PContext): PFontFace{.cdecl, importc: "cairo_get_font_face",
libcairo.}
proc set_scaled_font*(cr: PContext, scaled_font: PScaledFont){.cdecl,
importc: "cairo_set_scaled_font", libcairo.}
proc get_scaled_font*(cr: PContext): PScaledFont{.cdecl,
importc: "cairo_get_scaled_font", libcairo.}
proc show_text*(cr: PContext, utf8: cstring){.cdecl, importc: "cairo_show_text",
libcairo.}
proc show_glyphs*(cr: PContext, glyphs: PGlyph, num_glyphs: int32){.cdecl,
importc: "cairo_show_glyphs", libcairo.}
proc text_path*(cr: PContext, utf8: cstring){.cdecl, importc: "cairo_text_path",
libcairo.}
proc glyph_path*(cr: PContext, glyphs: PGlyph, num_glyphs: int32){.cdecl,
importc: "cairo_glyph_path", libcairo.}
proc text_extents*(cr: PContext, utf8: cstring, extents: PTextExtents){.cdecl,
importc: "cairo_text_extents", libcairo.}
proc glyph_extents*(cr: PContext, glyphs: PGlyph, num_glyphs: int32,
extents: PTextExtents){.cdecl,
importc: "cairo_glyph_extents", libcairo.}
proc font_extents*(cr: PContext, extents: PFontExtents){.cdecl,
importc: "cairo_font_extents", libcairo.}
#* Generic identifier for a font style
proc reference*(font_face: PFontFace): PFontFace{.cdecl,
importc: "cairo_font_face_reference", libcairo.}
proc destroy*(font_face: PFontFace){.cdecl,
importc: "cairo_font_face_destroy", libcairo.}
proc get_reference_count*(font_face: PFontFace): int32{.cdecl,
importc: "cairo_font_face_get_reference_count", libcairo.}
proc status*(font_face: PFontFace): TStatus{.cdecl,
importc: "cairo_font_face_status", libcairo.}
proc get_type*(font_face: PFontFace): TFontType{.cdecl,
importc: "cairo_font_face_get_type", libcairo.}
proc get_user_data*(font_face: PFontFace, key: PUserDataKey): pointer{.
cdecl, importc: "cairo_font_face_get_user_data", libcairo.}
proc set_user_data*(font_face: PFontFace, key: PUserDataKey,
user_data: pointer, destroy: TDestroyFunc): TStatus{.
cdecl, importc: "cairo_font_face_set_user_data", libcairo.}
#* Portable interface to general font features
proc scaled_font_create*(font_face: PFontFace, font_matrix: PMatrix,
ctm: PMatrix, options: PFontOptions): PScaledFont{.
cdecl, importc: "cairo_scaled_font_create", libcairo.}
proc reference*(scaled_font: PScaledFont): PScaledFont{.cdecl,
importc: "cairo_scaled_font_reference", libcairo.}
proc destroy*(scaled_font: PScaledFont){.cdecl,
importc: "cairo_scaled_font_destroy", libcairo.}
proc get_reference_count*(scaled_font: PScaledFont): int32{.cdecl,
importc: "cairo_scaled_font_get_reference_count", libcairo.}
proc status*(scaled_font: PScaledFont): TStatus{.cdecl,
importc: "cairo_scaled_font_status", libcairo.}
proc get_type*(scaled_font: PScaledFont): TFontType{.cdecl,
importc: "cairo_scaled_font_get_type", libcairo.}
proc get_user_data*(scaled_font: PScaledFont, key: PUserDataKey): Pointer{.
cdecl, importc: "cairo_scaled_font_get_user_data", libcairo.}
proc set_user_data*(scaled_font: PScaledFont, key: PUserDataKey,
user_data: Pointer, destroy: TDestroyFunc): TStatus{.
cdecl, importc: "cairo_scaled_font_set_user_data", libcairo.}
proc extents*(scaled_font: PScaledFont, extents: PFontExtents){.
cdecl, importc: "cairo_scaled_font_extents", libcairo.}
proc text_extents*(scaled_font: PScaledFont, utf8: cstring,
extents: PTextExtents){.cdecl,
importc: "cairo_scaled_font_text_extents", libcairo.}
proc glyph_extents*(scaled_font: PScaledFont, glyphs: PGlyph,
num_glyphs: int32, extents: PTextExtents){.
cdecl, importc: "cairo_scaled_font_glyph_extents", libcairo.}
proc get_font_face*(scaled_font: PScaledFont): PFontFace{.cdecl,
importc: "cairo_scaled_font_get_font_face", libcairo.}
proc get_font_matrix*(scaled_font: PScaledFont, font_matrix: PMatrix){.
cdecl, importc: "cairo_scaled_font_get_font_matrix", libcairo.}
proc get_ctm*(scaled_font: PScaledFont, ctm: PMatrix){.cdecl,
importc: "cairo_scaled_font_get_ctm", libcairo.}
proc get_font_options*(scaled_font: PScaledFont,
options: PFontOptions){.cdecl,
importc: "cairo_scaled_font_get_font_options", libcairo.}
#* Query functions
proc get_operator*(cr: PContext): TOperator{.cdecl, importc: "cairo_get_operator",
libcairo.}
proc get_source*(cr: PContext): PPattern{.cdecl, importc: "cairo_get_source",
libcairo.}
proc get_tolerance*(cr: PContext): float64{.cdecl, importc: "cairo_get_tolerance",
libcairo.}
proc get_antialias*(cr: PContext): TAntialias{.cdecl, importc: "cairo_get_antialias",
libcairo.}
proc get_current_point*(cr: PContext, x, y: var float64){.cdecl,
importc: "cairo_get_current_point", libcairo.}
proc get_fill_rule*(cr: PContext): TFillRule{.cdecl, importc: "cairo_get_fill_rule",
libcairo.}
proc get_line_width*(cr: PContext): float64{.cdecl, importc: "cairo_get_line_width",
libcairo.}
proc get_line_cap*(cr: PContext): TLineCap{.cdecl, importc: "cairo_get_line_cap",
libcairo.}
proc get_line_join*(cr: PContext): TLineJoin{.cdecl, importc: "cairo_get_line_join",
libcairo.}
proc get_miter_limit*(cr: PContext): float64{.cdecl, importc: "cairo_get_miter_limit",
libcairo.}
proc get_dash_count*(cr: PContext): int32{.cdecl, importc: "cairo_get_dash_count",
libcairo.}
proc get_dash*(cr: PContext, dashes, offset: var float64){.cdecl,
importc: "cairo_get_dash", libcairo.}
proc get_matrix*(cr: PContext, matrix: PMatrix){.cdecl, importc: "cairo_get_matrix",
libcairo.}
proc get_target*(cr: PContext): PSurface{.cdecl, importc: "cairo_get_target",
libcairo.}
proc get_group_target*(cr: PContext): PSurface{.cdecl,
importc: "cairo_get_group_target", libcairo.}
proc copy_path*(cr: PContext): PPath{.cdecl, importc: "cairo_copy_path",
libcairo.}
proc copy_path_flat*(cr: PContext): PPath{.cdecl, importc: "cairo_copy_path_flat",
libcairo.}
proc append_path*(cr: PContext, path: PPath){.cdecl, importc: "cairo_append_path",
libcairo.}
proc destroy*(path: PPath){.cdecl, importc: "cairo_path_destroy",
libcairo.}
#* Error status queries
proc status*(cr: PContext): TStatus{.cdecl, importc: "cairo_status", libcairo.}
proc status_to_string*(status: TStatus): cstring{.cdecl,
importc: "cairo_status_to_string", libcairo.}
#* Surface manipulation
proc surface_create_similar*(other: PSurface, content: TContent,
width, height: int32): PSurface{.cdecl,
importc: "cairo_surface_create_similar", libcairo.}
proc reference*(surface: PSurface): PSurface{.cdecl,
importc: "cairo_surface_reference", libcairo.}
proc finish*(surface: PSurface){.cdecl, importc: "cairo_surface_finish",
libcairo.}
proc destroy*(surface: PSurface){.cdecl,
importc: "cairo_surface_destroy", libcairo.}
proc get_reference_count*(surface: PSurface): int32{.cdecl,
importc: "cairo_surface_get_reference_count", libcairo.}
proc status*(surface: PSurface): TStatus{.cdecl,
importc: "cairo_surface_status", libcairo.}
proc get_type*(surface: PSurface): TSurfaceType{.cdecl,
importc: "cairo_surface_get_type", libcairo.}
proc get_content*(surface: PSurface): TContent{.cdecl,
importc: "cairo_surface_get_content", libcairo.}
proc write_to_png*(surface: PSurface, filename: cstring): TStatus{.
cdecl, importc: "cairo_surface_write_to_png", libcairo.}
proc write_to_png*(surface: PSurface, write_func: TWriteFunc,
closure: pointer): TStatus{.cdecl,
importc: "cairo_surface_write_to_png_stream", libcairo.}
proc get_user_data*(surface: PSurface, key: PUserDataKey): pointer{.
cdecl, importc: "cairo_surface_get_user_data", libcairo.}
proc set_user_data*(surface: PSurface, key: PUserDataKey,
user_data: pointer, destroy: TDestroyFunc): TStatus{.
cdecl, importc: "cairo_surface_set_user_data", libcairo.}
proc get_font_options*(surface: PSurface, options: PFontOptions){.cdecl,
importc: "cairo_surface_get_font_options", libcairo.}
proc flush*(surface: PSurface){.cdecl, importc: "cairo_surface_flush",
libcairo.}
proc mark_dirty*(surface: PSurface){.cdecl,
importc: "cairo_surface_mark_dirty", libcairo.}
proc mark_dirty_rectangle*(surface: PSurface, x, y, width, height: int32){.
cdecl, importc: "cairo_surface_mark_dirty_rectangle", libcairo.}
proc set_device_offset*(surface: PSurface, x_offset, y_offset: float64){.
cdecl, importc: "cairo_surface_set_device_offset", libcairo.}
proc get_device_offset*(surface: PSurface,
x_offset, y_offset: var float64){.cdecl,
importc: "cairo_surface_get_device_offset", libcairo.}
proc set_fallback_resolution*(surface: PSurface, x_pixels_per_inch,
y_pixels_per_inch: float64){.cdecl, importc: "cairo_surface_set_fallback_resolution",
libcairo.}
#* Image-surface functions
proc image_surface_create*(format: TFormat, width, height: int32): PSurface{.
cdecl, importc: "cairo_image_surface_create", libcairo.}
proc image_surface_create*(data: Pbyte, format: TFormat,
width, height, stride: int32): PSurface{.
cdecl, importc: "cairo_image_surface_create_for_data", libcairo.}
proc get_data*(surface: PSurface): cstring{.cdecl,
importc: "cairo_image_surface_get_data", libcairo.}
proc get_format*(surface: PSurface): TFormat{.cdecl,
importc: "cairo_image_surface_get_format", libcairo.}
proc get_width*(surface: PSurface): int32{.cdecl,
importc: "cairo_image_surface_get_width", libcairo.}
proc get_height*(surface: PSurface): int32{.cdecl,
importc: "cairo_image_surface_get_height", libcairo.}
proc get_stride*(surface: PSurface): int32{.cdecl,
importc: "cairo_image_surface_get_stride", libcairo.}
proc image_surface_create_from_png*(filename: cstring): PSurface{.cdecl,
importc: "cairo_image_surface_create_from_png", libcairo.}
proc image_surface_create_from_png*(read_func: TReadFunc,
closure: pointer): PSurface{.cdecl, importc: "cairo_image_surface_create_from_png_stream",
libcairo.}
#* Pattern creation functions
proc pattern_create_rgb*(red, green, blue: float64): PPattern{.cdecl,
importc: "cairo_pattern_create_rgb", libcairo.}
proc pattern_create_rgba*(red, green, blue, alpha: float64): PPattern{.cdecl,
importc: "cairo_pattern_create_rgba", libcairo.}
proc pattern_create_for_surface*(surface: PSurface): PPattern{.cdecl,
importc: "cairo_pattern_create_for_surface", libcairo.}
proc pattern_create_linear*(x0, y0, x1, y1: float64): PPattern{.cdecl,
importc: "cairo_pattern_create_linear", libcairo.}
proc pattern_create_radial*(cx0, cy0, radius0, cx1, cy1, radius1: float64): PPattern{.
cdecl, importc: "cairo_pattern_create_radial", libcairo.}
proc reference*(pattern: PPattern): PPattern{.cdecl,
importc: "cairo_pattern_reference", libcairo.}
proc destroy*(pattern: PPattern){.cdecl,
importc: "cairo_pattern_destroy", libcairo.}
proc get_reference_count*(pattern: PPattern): int32{.cdecl,
importc: "cairo_pattern_get_reference_count", libcairo.}
proc status*(pattern: PPattern): TStatus{.cdecl,
importc: "cairo_pattern_status", libcairo.}
proc get_user_data*(pattern: PPattern, key: PUserDataKey): Pointer{.
cdecl, importc: "cairo_pattern_get_user_data", libcairo.}
proc set_user_data*(pattern: PPattern, key: PUserDataKey,
user_data: Pointer, destroy: TDestroyFunc): TStatus{.
cdecl, importc: "cairo_pattern_set_user_data", libcairo.}
proc get_type*(pattern: PPattern): TPatternType{.cdecl,
importc: "cairo_pattern_get_type", libcairo.}
proc add_color_stop_rgb*(pattern: PPattern,
offset, red, green, blue: float64){.cdecl,
importc: "cairo_pattern_add_color_stop_rgb", libcairo.}
proc add_color_stop_rgba*(pattern: PPattern,
offset, red, green, blue, alpha: float64){.
cdecl, importc: "cairo_pattern_add_color_stop_rgba", libcairo.}
proc set_matrix*(pattern: PPattern, matrix: PMatrix){.cdecl,
importc: "cairo_pattern_set_matrix", libcairo.}
proc get_matrix*(pattern: PPattern, matrix: PMatrix){.cdecl,
importc: "cairo_pattern_get_matrix", libcairo.}
proc set_extend*(pattern: PPattern, extend: TExtend){.cdecl,
importc: "cairo_pattern_set_extend", libcairo.}
proc get_extend*(pattern: PPattern): TExtend{.cdecl,
importc: "cairo_pattern_get_extend", libcairo.}
proc set_filter*(pattern: PPattern, filter: TFilter){.cdecl,
importc: "cairo_pattern_set_filter", libcairo.}
proc get_filter*(pattern: PPattern): TFilter{.cdecl,
importc: "cairo_pattern_get_filter", libcairo.}
proc get_rgba*(pattern: PPattern,
red, green, blue, alpha: var float64): TStatus{.
cdecl, importc: "cairo_pattern_get_rgba", libcairo.}
proc get_surface*(pattern: PPattern, surface: PPSurface): TStatus{.
cdecl, importc: "cairo_pattern_get_surface", libcairo.}
proc get_color_stop_rgba*(pattern: PPattern, index: int32,
offset, red, green, blue, alpha: var float64): TStatus{.
cdecl, importc: "cairo_pattern_get_color_stop_rgba", libcairo.}
proc get_color_stop_count*(pattern: PPattern, count: var int32): TStatus{.
cdecl, importc: "cairo_pattern_get_color_stop_count", libcairo.}
proc get_linear_points*(pattern: PPattern,
x0, y0, x1, y1: var float64): TStatus{.
cdecl, importc: "cairo_pattern_get_linear_points", libcairo.}
proc get_radial_circles*(pattern: PPattern,
x0, y0, r0, x1, y1, r1: var float64): TStatus{.
cdecl, importc: "cairo_pattern_get_radial_circles", libcairo.}
#* Matrix functions
proc init*(matrix: PMatrix, xx, yx, xy, yy, x0, y0: float64){.cdecl,
importc: "cairo_matrix_init", libcairo.}
proc init_identity*(matrix: PMatrix){.cdecl,
importc: "cairo_matrix_init_identity", libcairo.}
proc init_translate*(matrix: PMatrix, tx, ty: float64){.cdecl,
importc: "cairo_matrix_init_translate", libcairo.}
proc init_scale*(matrix: PMatrix, sx, sy: float64){.cdecl,
importc: "cairo_matrix_init_scale", libcairo.}
proc init_rotate*(matrix: PMatrix, radians: float64){.cdecl,
importc: "cairo_matrix_init_rotate", libcairo.}
proc translate*(matrix: PMatrix, tx, ty: float64){.cdecl,
importc: "cairo_matrix_translate", libcairo.}
proc scale*(matrix: PMatrix, sx, sy: float64){.cdecl,
importc: "cairo_matrix_scale", libcairo.}
proc rotate*(matrix: PMatrix, radians: float64){.cdecl,
importc: "cairo_matrix_rotate", libcairo.}
proc invert*(matrix: PMatrix): TStatus{.cdecl,
importc: "cairo_matrix_invert", libcairo.}
proc multiply*(result, a, b: PMatrix){.cdecl,
importc: "cairo_matrix_multiply", libcairo.}
proc transform_distance*(matrix: PMatrix, dx, dy: var float64){.cdecl,
importc: "cairo_matrix_transform_distance", libcairo.}
proc transform_point*(matrix: PMatrix, x, y: var float64){.cdecl,
importc: "cairo_matrix_transform_point", libcairo.}
#* PDF functions
proc pdf_surface_create*(filename: cstring,
width_in_points, height_in_points: float64): PSurface{.
cdecl, importc: "cairo_pdf_surface_create", libcairo.}
proc pdf_surface_create_for_stream*(write_func: TWriteFunc, closure: Pointer,
width_in_points, height_in_points: float64): PSurface{.
cdecl, importc: "cairo_pdf_surface_create_for_stream", libcairo.}
proc pdf_surface_set_size*(surface: PSurface,
width_in_points, height_in_points: float64){.cdecl,
importc: "cairo_pdf_surface_set_size", libcairo.}
#* PS functions
proc ps_surface_create*(filename: cstring,
width_in_points, height_in_points: float64): PSurface{.
cdecl, importc: "cairo_ps_surface_create", libcairo.}
proc ps_surface_create_for_stream*(write_func: TWriteFunc, closure: Pointer,
width_in_points, height_in_points: float64): PSurface{.
cdecl, importc: "cairo_ps_surface_create_for_stream", libcairo.}
proc ps_surface_set_size*(surface: PSurface,
width_in_points, height_in_points: float64){.cdecl,
importc: "cairo_ps_surface_set_size", libcairo.}
proc ps_surface_dsc_comment*(surface: PSurface, comment: cstring){.cdecl,
importc: "cairo_ps_surface_dsc_comment", libcairo.}
proc ps_surface_dsc_begin_setup*(surface: PSurface){.cdecl,
importc: "cairo_ps_surface_dsc_begin_setup", libcairo.}
proc ps_surface_dsc_begin_page_setup*(surface: PSurface){.cdecl,
importc: "cairo_ps_surface_dsc_begin_page_setup", libcairo.}
#* SVG functions
proc svg_surface_create*(filename: cstring,
width_in_points, height_in_points: float64): PSurface{.
cdecl, importc: "cairo_svg_surface_create", libcairo.}
proc svg_surface_create_for_stream*(write_func: TWriteFunc, closure: Pointer,
width_in_points, height_in_points: float64): PSurface{.
cdecl, importc: "cairo_svg_surface_create_for_stream", libcairo.}
proc svg_surface_restrict_to_version*(surface: PSurface, version: TSvgVersion){.
cdecl, importc: "cairo_svg_surface_restrict_to_version", libcairo.}
#todo: see how translate this
#procedure cairo_svg_get_versions(TCairoSvgVersion const **versions,
# int *num_versions);
proc svg_version_to_string*(version: TSvgVersion): cstring{.cdecl,
importc: "cairo_svg_version_to_string", libcairo.}
#* Functions to be used while debugging (not intended for use in production code)
proc debug_reset_static_data*(){.cdecl,
importc: "cairo_debug_reset_static_data",
libcairo.}
# implementation
proc version(major, minor, micro: var int32) =
var version: int32
version = version()
major = version div 10000'i32
minor = (version mod (major * 10000'i32)) div 100'i32
micro = (version mod ((major * 10000'i32) + (minor * 100'i32)))
proc checkStatus*(s: cairo.TStatus) {.noinline.} =
## if ``s != StatusSuccess`` the error is turned into an appropirate Nimrod
## exception and raised.
case s
of StatusSuccess: nil
of StatusNoMemory:
raise newException(EOutOfMemory, $statusToString(s))
of STATUS_READ_ERROR, STATUS_WRITE_ERROR, STATUS_FILE_NOT_FOUND,
STATUS_TEMP_FILE_ERROR:
raise newException(EIO, $statusToString(s))
else:
raise newException(EAssertionFailed, $statusToString(s))

View file

@ -1,16 +0,0 @@
# included by cairo bindings
when defined(use_pkg_config) or defined(use_pkg_config_static):
{.pragma: libcairo, cdecl.}
when defined(use_pkg_config_static):
{.passl: gorge("pkg-config cairo --libs --static").}
else:
{.passl: gorge("pkg-config cairo --libs").}
else:
when defined(windows):
const LIB_CAIRO* = "libcairo-2.dll"
elif defined(macosx):
const LIB_CAIRO* = "libcairo.dylib"
else:
const LIB_CAIRO* = "libcairo.so(|.2)"
{.pragma: libcairo, cdecl, dynlib: LIB_CAIRO.}

View file

@ -1,36 +0,0 @@
#
# Translation of cairo-ft.h
# by Jeffrey Pohlmeyer
# updated to version 1.4 by Luiz Américo Pereira Câmara 2007
#
import
cairo, freetypeh
include "cairo_pragma.nim"
#todo: properly define FcPattern:
#It will require translate FontConfig header
#*
#typedef struct _XftPattern {
# int num;
# int size;
# XftPatternElt *elts;
# } XftPattern;
# typedef FcPattern XftPattern;
#
type
FcPattern* = Pointer
PFcPattern* = ptr FcPattern
proc ft_font_face_create_for_pattern*(pattern: PFcPattern): PFontFace{.libcairo,
importc: "cairo_ft_font_face_create_for_pattern".}
proc ft_font_options_substitute*(options: PFontOptions, pattern: PFcPattern){.
libcairo, importc: "cairo_ft_font_options_substitute".}
proc ft_font_face_create_for_ft_face*(face: TFT_Face, load_flags: int32): PFontFace{.libcairo,
importc: "cairo_ft_font_face_create_for_ft_face".}
proc ft_scaled_font_lock_face*(scaled_font: PScaledFont): TFT_Face{.libcairo,
importc: "cairo_ft_scaled_font_lock_face".}
proc ft_scaled_font_unlock_face*(scaled_font: PScaledFont){.libcairo,
importc: "cairo_ft_scaled_font_unlock_face".}

View file

@ -1,37 +0,0 @@
#
# Translation of cairo-win32.h version 1.4
# by Luiz Américo Pereira Câmara 2007
#
import
cairo, windows
proc win32_surface_create*(hdc: HDC): PSurface{.cdecl,
importc: "cairo_win32_surface_create", dynlib: LIB_CAIRO.}
proc win32_surface_create_with_ddb*(hdc: HDC, format: TFormat,
width, height: int32): PSurface{.cdecl,
importc: "cairo_win32_surface_create_with_ddb", dynlib: LIB_CAIRO.}
proc win32_surface_create_with_dib*(format: TFormat, width, height: int32): PSurface{.
cdecl, importc: "cairo_win32_surface_create_with_dib", dynlib: LIB_CAIRO.}
proc win32_surface_get_dc*(surface: PSurface): HDC{.cdecl,
importc: "cairo_win32_surface_get_dc", dynlib: LIB_CAIRO.}
proc win32_surface_get_image*(surface: PSurface): PSurface{.cdecl,
importc: "cairo_win32_surface_get_image", dynlib: LIB_CAIRO.}
proc win32_font_face_create_for_logfontw*(logfont: pLOGFONTW): PFontFace{.cdecl,
importc: "cairo_win32_font_face_create_for_logfontw", dynlib: LIB_CAIRO.}
proc win32_font_face_create_for_hfont*(font: HFONT): PFontFace{.cdecl,
importc: "cairo_win32_font_face_create_for_hfont", dynlib: LIB_CAIRO.}
proc win32_scaled_font_select_font*(scaled_font: PScaledFont, hdc: HDC): TStatus{.
cdecl, importc: "cairo_win32_scaled_font_select_font", dynlib: LIB_CAIRO.}
proc win32_scaled_font_done_font*(scaled_font: PScaledFont){.cdecl,
importc: "cairo_win32_scaled_font_done_font", dynlib: LIB_CAIRO.}
proc win32_scaled_font_get_metrics_factor*(scaled_font: PScaledFont): float64{.
cdecl, importc: "cairo_win32_scaled_font_get_metrics_factor",
dynlib: LIB_CAIRO.}
proc win32_scaled_font_get_logical_to_device*(scaled_font: PScaledFont,
logical_to_device: PMatrix){.cdecl, importc: "cairo_win32_scaled_font_get_logical_to_device",
dynlib: LIB_CAIRO.}
proc win32_scaled_font_get_device_to_logical*(scaled_font: PScaledFont,
device_to_logical: PMatrix){.cdecl, importc: "cairo_win32_scaled_font_get_device_to_logical",
dynlib: LIB_CAIRO.}
# implementation

View file

@ -1,41 +0,0 @@
#
# Translation of cairo-xlib.h version 1.4
# by Jeffrey Pohlmeyer
# updated to version 1.4 by Luiz Américo Pereira Câmara 2007
#
import
cairo, x, xlib, xrender
include "cairo_pragma.nim"
proc xlib_surface_create*(dpy: PDisplay, drawable: TDrawable, visual: PVisual,
width, height: int32): PSurface{.cdecl,
importc: "cairo_xlib_surface_create", libcairo.}
proc xlib_surface_create_for_bitmap*(dpy: PDisplay, bitmap: TPixmap,
screen: PScreen, width, height: int32): PSurface{.
cdecl, importc: "cairo_xlib_surface_create_for_bitmap", libcairo.}
proc xlib_surface_create_with_xrender_format*(dpy: PDisplay,
drawable: TDrawable, screen: PScreen, format: PXRenderPictFormat,
width, height: int32): PSurface{.cdecl, importc: "cairo_xlib_surface_create_with_xrender_format",
libcairo.}
proc xlib_surface_get_depth*(surface: PSurface): int32{.cdecl,
importc: "cairo_xlib_surface_get_depth", libcairo.}
proc xlib_surface_get_display*(surface: PSurface): PDisplay{.cdecl,
importc: "cairo_xlib_surface_get_display", libcairo.}
proc xlib_surface_get_drawable*(surface: PSurface): TDrawable{.cdecl,
importc: "cairo_xlib_surface_get_drawable", libcairo.}
proc xlib_surface_get_height*(surface: PSurface): int32{.cdecl,
importc: "cairo_xlib_surface_get_height", libcairo.}
proc xlib_surface_get_screen*(surface: PSurface): PScreen{.cdecl,
importc: "cairo_xlib_surface_get_screen", libcairo.}
proc xlib_surface_get_visual*(surface: PSurface): PVisual{.cdecl,
importc: "cairo_xlib_surface_get_visual", libcairo.}
proc xlib_surface_get_width*(surface: PSurface): int32{.cdecl,
importc: "cairo_xlib_surface_get_width", libcairo.}
proc xlib_surface_set_size*(surface: PSurface, width, height: int32){.cdecl,
importc: "cairo_xlib_surface_set_size", libcairo.}
proc xlib_surface_set_drawable*(surface: PSurface, drawable: TDrawable,
width, height: int32){.cdecl,
importc: "cairo_xlib_surface_set_drawable", libcairo.}
# implementation

Some files were not shown because too many files have changed in this diff Show more