Merge branch 'devel' of git://github.com/Araq/Nimrod

This commit is contained in:
Miguel 2014-01-26 05:37:18 +04:00
commit a8b4e3c764
741 changed files with 20953 additions and 11950 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
@ -287,16 +294,18 @@ 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:
##
## .. code-block:: nimrod
##
## emit("echo " & '"' & "hello world".toUpper & '"')
##
eval: result = e.parseStmt
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 = e.parseStmt
payload()
proc expectKind*(n: PNimrodNode, k: TNimrodNodeKind) {.compileTime.} =
## checks that `n` is of kind `k`. If this is not the case,
@ -345,12 +354,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
@ -381,7 +390,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)
@ -406,7 +415,7 @@ 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)
@ -529,7 +538,7 @@ from strutils import cmpIgnoreStyle, format
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] = [newEmptyNode()];
proc newProc*(name = newEmptyNode(); params: openArray[PNimrodNode] = [newEmptyNode()];
body: PNimrodNode = newStmtList(), procType = nnkProcDef): PNimrodNode {.compileTime.} =
## shortcut for creating a new proc
##
@ -567,7 +576,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
@ -604,7 +613,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:
@ -628,7 +637,7 @@ proc `$`*(node: PNimrodNode): string {.compileTime.} =
of nnkIdent:
result = $node.ident
of nnkStrLit:
result = node.strval
result = node.strVal
else:
badNodeKind node.kind, "$"
@ -639,10 +648,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:
@ -651,7 +663,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
@ -672,14 +684,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)
@ -730,6 +742,6 @@ 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))

View file

@ -47,12 +47,12 @@ 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.
@ -113,7 +113,7 @@ 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.

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,11 +172,11 @@ 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.

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,44 @@ 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,
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.
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: dbError(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. 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 +192,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

@ -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 =
@ -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

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,13 +864,13 @@ 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:
while true:
case p.tok[p.idx].kind
of tkWhite, tkWord, tkAdornment, tkOther, tkPunct: parseInline(p, father)
of tkEof, tkIndent: break
@ -879,9 +879,9 @@ 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
@ -933,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
@ -953,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
@ -999,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
@ -1026,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
@ -1052,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:
@ -1084,7 +1084,7 @@ proc parseParagraph(p: var TRstParser, result: PRstNode) =
proc parseHeadline(p: var TRstParser): PRstNode =
result = newRstNode(rnHeadline)
parseUntilNewLine(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]
@ -1101,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)
@ -1119,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)
@ -1135,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
@ -1243,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
@ -1269,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
@ -1290,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:
@ -1335,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)
@ -1351,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)
@ -1394,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))
@ -1566,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)
@ -1624,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

@ -44,7 +44,7 @@ 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
@ -111,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;")
@ -121,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}")
@ -148,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)
@ -161,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
@ -224,6 +228,13 @@ proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
# ---------------- index handling --------------------------------------------
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)
@ -263,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
@ -320,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
@ -456,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
@ -620,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 = ""
@ -646,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:
@ -688,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) =

View file

@ -85,15 +85,15 @@ type
Tdirent* {.importc: "struct dirent",
header: "<dirent.h>", final, pure.} = object ## dirent_t struct
d_ino*: TIno ## File serial number.
d_ino*: Tino ## File serial number.
d_name*: array [0..255, char] ## Name of entry.
Tflock* {.importc: "flock", final, pure,
header: "<fcntl.h>".} = object ## flock type
l_type*: cshort ## Type of lock; F_RDLCK, F_WRLCK, F_UNLCK.
l_whence*: cshort ## Flag for starting offset.
l_start*: Toff ## Relative offset in bytes.
l_len*: Toff ## Size; if 0 then until EOF.
l_start*: TOff ## Relative offset in bytes.
l_len*: TOff ## Size; if 0 then until EOF.
l_pid*: TPid ## Process ID of the process holding the lock;
## returned with F_GETLK.
@ -172,7 +172,7 @@ type
TPasswd* {.importc: "struct passwd", header: "<pwd.h>",
final, pure.} = object ## struct passwd
pw_name*: cstring ## User's login name.
pw_uid*: TUid ## Numerical user ID.
pw_uid*: Tuid ## Numerical user ID.
pw_gid*: TGid ## Numerical group ID.
pw_dir*: cstring ## Initial working directory.
pw_shell*: cstring ## Program to use as shell.
@ -240,20 +240,20 @@ type
TSem* {.importc: "sem_t", header: "<semaphore.h>", final, pure.} = object
Tipc_perm* {.importc: "struct ipc_perm",
header: "<sys/ipc.h>", final, pure.} = object ## struct ipc_perm
uid*: tuid ## Owner's user ID.
gid*: tgid ## Owner's group ID.
uid*: Tuid ## Owner's user ID.
gid*: TGid ## Owner's group ID.
cuid*: Tuid ## Creator's user ID.
cgid*: Tgid ## Creator's group ID.
cgid*: TGid ## Creator's group ID.
mode*: TMode ## Read/write permission.
TStat* {.importc: "struct stat",
header: "<sys/stat.h>", final, pure.} = object ## struct stat
st_dev*: TDev ## Device ID of device containing file.
st_ino*: TIno ## File serial number.
st_ino*: Tino ## File serial number.
st_mode*: TMode ## Mode of file (see below).
st_nlink*: tnlink ## Number of hard links to the file.
st_uid*: tuid ## User ID of file.
st_gid*: Tgid ## Group ID of file.
st_nlink*: TNlink ## Number of hard links to the file.
st_uid*: Tuid ## User ID of file.
st_gid*: TGid ## Group ID of file.
st_rdev*: TDev ## Device ID (if file is character or block special).
st_size*: TOff ## For regular files, the file size in bytes.
## For symbolic links, the length in bytes of the
@ -262,9 +262,9 @@ type
## For a typed memory object, the length in bytes.
## For other file types, the use of this field is
## unspecified.
st_atime*: ttime ## Time of last access.
st_mtime*: ttime ## Time of last data modification.
st_ctime*: ttime ## Time of last status change.
st_atime*: TTime ## Time of last access.
st_mtime*: TTime ## Time of last data modification.
st_ctime*: TTime ## Time of last status change.
st_blksize*: Tblksize ## A file system-specific preferred I/O block size
## for this object. In some file system types, this
## may vary from file to file.
@ -305,12 +305,12 @@ type
tm_isdst*: cint ## Daylight Savings flag.
Ttimespec* {.importc: "struct timespec",
header: "<time.h>", final, pure.} = object ## struct timespec
tv_sec*: Ttime ## Seconds.
tv_sec*: TTime ## Seconds.
tv_nsec*: int ## Nanoseconds.
titimerspec* {.importc: "struct itimerspec", header: "<time.h>",
final, pure.} = object ## struct itimerspec
it_interval*: ttimespec ## Timer period.
it_value*: ttimespec ## Timer expiration.
it_interval*: Ttimespec ## Timer period.
it_value*: Ttimespec ## Timer expiration.
Tsig_atomic* {.importc: "sig_atomic_t", header: "<signal.h>".} = cint
## Possibly volatile-qualified integer type of an object that can be
@ -322,9 +322,9 @@ type
header: "<signal.h>", final, pure.} = object ## struct sigevent
sigev_notify*: cint ## Notification type.
sigev_signo*: cint ## Signal number.
sigev_value*: Tsigval ## Signal value.
sigev_notify_function*: proc (x: TSigval) {.noconv.} ## Notification func.
sigev_notify_attributes*: ptr Tpthreadattr ## Notification attributes.
sigev_value*: TsigVal ## Signal value.
sigev_notify_function*: proc (x: TsigVal) {.noconv.} ## Notification func.
sigev_notify_attributes*: ptr Tpthread_attr ## Notification attributes.
TsigVal* {.importc: "union sigval",
header: "<signal.h>", final, pure.} = object ## struct sigval
@ -335,10 +335,10 @@ type
sa_handler*: proc (x: cint) {.noconv.} ## Pointer to a signal-catching
## function or one of the macros
## SIG_IGN or SIG_DFL.
sa_mask*: TsigSet ## Set of signals to be blocked during execution of
sa_mask*: Tsigset ## Set of signals to be blocked during execution of
## the signal handling function.
sa_flags*: cint ## Special flags.
sa_sigaction*: proc (x: cint, y: var TSigInfo, z: pointer) {.noconv.}
sa_sigaction*: proc (x: cint, y: var TsigInfo, z: pointer) {.noconv.}
TStack* {.importc: "stack_t",
header: "<signal.h>", final, pure.} = object ## stack_t
@ -357,12 +357,12 @@ type
si_code*: cint ## Signal code.
si_errno*: cint ## If non-zero, an errno value associated with
## this signal, as defined in <errno.h>.
si_pid*: tpid ## Sending process ID.
si_uid*: tuid ## Real user ID of sending process.
si_pid*: TPid ## Sending process ID.
si_uid*: Tuid ## Real user ID of sending process.
si_addr*: pointer ## Address of faulting instruction.
si_status*: cint ## Exit value or signal.
si_band*: int ## Band event for SIGPOLL.
si_value*: TSigval ## Signal value.
si_value*: TsigVal ## Signal value.
Tnl_item* {.importc: "nl_item", header: "<nl_types.h>".} = cint
Tnl_catd* {.importc: "nl_catd", header: "<nl_types.h>".} = cint
@ -373,9 +373,9 @@ type
sched_priority*: cint
sched_ss_low_priority*: cint ## Low scheduling priority for
## sporadic server.
sched_ss_repl_period*: ttimespec ## Replenishment period for
sched_ss_repl_period*: Ttimespec ## Replenishment period for
## sporadic server.
sched_ss_init_budget*: ttimespec ## Initial budget for sporadic server.
sched_ss_init_budget*: Ttimespec ## Initial budget for sporadic server.
sched_ss_max_repl*: cint ## Maximum pending replenishments for
## sporadic server.
@ -383,8 +383,8 @@ type
final, pure.} = object ## struct timeval
tv_sec*: int ## Seconds.
tv_usec*: int ## Microseconds.
Tfd_set* {.importc: "fd_set", header: "<sys/select.h>",
final, pure.} = object
TFdSet* {.importc: "fd_set", header: "<sys/select.h>",
final, pure.} = object
Tmcontext* {.importc: "mcontext_t", header: "<ucontext.h>",
final, pure.} = object
Tucontext* {.importc: "ucontext_t", header: "<ucontext.h>",
@ -406,7 +406,7 @@ when hasAioH:
aio_buf*: pointer ## Location of buffer.
aio_nbytes*: int ## Length of transfer.
aio_reqprio*: cint ## Request priority offset.
aio_sigevent*: TSigEvent ## Signal number and value.
aio_sigevent*: TsigEvent ## Signal number and value.
aio_lio_opcode: cint ## Operation to be performed.
when hasSpawnH:
@ -422,13 +422,13 @@ type
TSockAddr* {.importc: "struct sockaddr", header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr
sa_family*: Tsa_family ## Address family.
sa_family*: TSa_Family ## Address family.
sa_data*: array [0..255, char] ## Socket address (variable-length data).
Tsockaddr_storage* {.importc: "struct sockaddr_storage",
header: "<sys/socket.h>",
pure, final.} = object ## struct sockaddr_storage
ss_family*: Tsa_family ## Address family.
ss_family*: TSa_Family ## Address family.
Tif_nameindex* {.importc: "struct if_nameindex", final,
pure, header: "<net/if.h>".} = object ## struct if_nameindex
@ -444,17 +444,17 @@ type
Tmsghdr* {.importc: "struct msghdr", pure, final,
header: "<sys/socket.h>".} = object ## struct msghdr
msg_name*: pointer ## Optional address.
msg_namelen*: TSockLen ## Size of address.
msg_namelen*: TSocklen ## Size of address.
msg_iov*: ptr TIOVec ## Scatter/gather array.
msg_iovlen*: cint ## Members in msg_iov.
msg_control*: pointer ## Ancillary data; see below.
msg_controllen*: TSockLen ## Ancillary data buffer len.
msg_controllen*: TSocklen ## Ancillary data buffer len.
msg_flags*: cint ## Flags on received message.
Tcmsghdr* {.importc: "struct cmsghdr", pure, final,
header: "<sys/socket.h>".} = object ## struct cmsghdr
cmsg_len*: TSockLen ## Data byte count, including the cmsghdr.
cmsg_len*: TSocklen ## Data byte count, including the cmsghdr.
cmsg_level*: cint ## Originating protocol.
cmsg_type*: cint ## Protocol-specific type.
@ -475,7 +475,7 @@ type
Tsockaddr_in* {.importc: "struct sockaddr_in", pure, final,
header: "<netinet/in.h>".} = object ## struct sockaddr_in
sin_family*: TSa_family ## AF_INET.
sin_family*: TSa_Family ## AF_INET.
sin_port*: TInPort ## Port number.
sin_addr*: TInAddr ## IP address.
@ -485,10 +485,10 @@ type
Tsockaddr_in6* {.importc: "struct sockaddr_in6", pure, final,
header: "<netinet/in.h>".} = object ## struct sockaddr_in6
sin6_family*: TSa_family ## AF_INET6.
sin6_family*: TSa_Family ## AF_INET6.
sin6_port*: TInPort ## Port number.
sin6_flowinfo*: int32 ## IPv6 traffic class and flow information.
sin6_addr*: Tin6Addr ## IPv6 address.
sin6_addr*: TIn6Addr ## IPv6 address.
sin6_scope_id*: int32 ## Set of interfaces for a scope.
Tipv6_mreq* {.importc: "struct ipv6_mreq", pure, final,
@ -543,10 +543,10 @@ type
ai_family*: cint ## Address family of socket.
ai_socktype*: cint ## Socket type.
ai_protocol*: cint ## Protocol of socket.
ai_addrlen*: TSockLen ## Length of socket address.
ai_addrlen*: TSocklen ## Length of socket address.
ai_addr*: ptr TSockAddr ## Socket address of socket.
ai_canonname*: cstring ## Canonical name of service location.
ai_next*: ptr TAddrInfo ## Pointer to next in list.
ai_next*: ptr Taddrinfo ## Pointer to next in list.
TPollfd* {.importc: "struct pollfd", pure, final,
header: "<poll.h>".} = object ## struct pollfd
@ -1616,9 +1616,9 @@ var
IPPROTO_UDP* {.importc, header: "<netinet/in.h>".}: cint
## User datagram protocol.
INADDR_ANY* {.importc, header: "<netinet/in.h>".}: TinAddrScalar
INADDR_ANY* {.importc, header: "<netinet/in.h>".}: TInAddrScalar
## IPv4 local host address.
INADDR_BROADCAST* {.importc, header: "<netinet/in.h>".}: TinAddrScalar
INADDR_BROADCAST* {.importc, header: "<netinet/in.h>".}: TInAddrScalar
## IPv4 broadcast address.
INET_ADDRSTRLEN* {.importc, header: "<netinet/in.h>".}: cint
@ -1726,7 +1726,7 @@ var
## Invalid fd member (revents only).
when hasSpawnh:
when hasSpawnH:
var
POSIX_SPAWN_RESETIDS* {.importc, header: "<spawn.h>".}: cint
POSIX_SPAWN_SETPGROUP* {.importc, header: "<spawn.h>".}: cint
@ -1750,11 +1750,11 @@ when hasAioH:
proc aio_fsync*(a1: cint, a2: ptr Taiocb): cint {.importc, header: "<aio.h>".}
proc aio_read*(a1: ptr Taiocb): cint {.importc, header: "<aio.h>".}
proc aio_return*(a1: ptr Taiocb): int {.importc, header: "<aio.h>".}
proc aio_suspend*(a1: ptr ptr Taiocb, a2: cint, a3: ptr ttimespec): cint {.
proc aio_suspend*(a1: ptr ptr Taiocb, a2: cint, a3: ptr Ttimespec): cint {.
importc, header: "<aio.h>".}
proc aio_write*(a1: ptr Taiocb): cint {.importc, header: "<aio.h>".}
proc lio_listio*(a1: cint, a2: ptr ptr Taiocb, a3: cint,
a4: ptr Tsigevent): cint {.importc, header: "<aio.h>".}
a4: ptr TsigEvent): cint {.importc, header: "<aio.h>".}
# arpa/inet.h
proc htonl*(a1: int32): int32 {.importc, header: "<arpa/inet.h>".}
@ -1778,9 +1778,9 @@ proc IN6ADDR_LOOPBACK_INIT* (): TIn6Addr {.importc, header: "<netinet/in.h>".}
# dirent.h
proc closedir*(a1: ptr TDIR): cint {.importc, header: "<dirent.h>".}
proc opendir*(a1: cstring): ptr TDir {.importc, header: "<dirent.h>".}
proc readdir*(a1: ptr TDIR): ptr TDirent {.importc, header: "<dirent.h>".}
proc readdir_r*(a1: ptr TDIR, a2: ptr Tdirent, a3: ptr ptr TDirent): cint {.
proc opendir*(a1: cstring): ptr TDIR {.importc, header: "<dirent.h>".}
proc readdir*(a1: ptr TDIR): ptr Tdirent {.importc, header: "<dirent.h>".}
proc readdir_r*(a1: ptr TDIR, a2: ptr Tdirent, a3: ptr ptr Tdirent): cint {.
importc, header: "<dirent.h>".}
proc rewinddir*(a1: ptr TDIR) {.importc, header: "<dirent.h>".}
proc seekdir*(a1: ptr TDIR, a2: int) {.importc, header: "<dirent.h>".}
@ -1792,12 +1792,12 @@ proc dlerror*(): cstring {.importc, header: "<dlfcn.h>".}
proc dlopen*(a1: cstring, a2: cint): pointer {.importc, header: "<dlfcn.h>".}
proc dlsym*(a1: pointer, a2: cstring): pointer {.importc, header: "<dlfcn.h>".}
proc creat*(a1: cstring, a2: Tmode): cint {.importc, header: "<fcntl.h>".}
proc creat*(a1: cstring, a2: TMode): cint {.importc, header: "<fcntl.h>".}
proc fcntl*(a1: cint | TSocketHandle, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc open*(a1: cstring, a2: cint): cint {.varargs, importc, header: "<fcntl.h>".}
proc posix_fadvise*(a1: cint, a2, a3: Toff, a4: cint): cint {.
proc posix_fadvise*(a1: cint, a2, a3: TOff, a4: cint): cint {.
importc, header: "<fcntl.h>".}
proc posix_fallocate*(a1: cint, a2, a3: Toff): cint {.
proc posix_fallocate*(a1: cint, a2, a3: TOff): cint {.
importc, header: "<fcntl.h>".}
proc feclearexcept*(a1: cint): cint {.importc, header: "<fenv.h>".}
@ -1812,7 +1812,7 @@ proc fesetround*(a1: cint): cint {.importc, header: "<fenv.h>".}
proc fegetenv*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
proc feholdexcept*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
proc fesetenv*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
proc feupdateenv*(a1: ptr TFenv): cint {.importc, header: "<fenv.h>".}
proc feupdateenv*(a1: ptr Tfenv): cint {.importc, header: "<fenv.h>".}
when not defined(haiku):
proc fmtmsg*(a1: int, a2: cstring, a3: cint,
@ -1830,12 +1830,12 @@ proc nftw*(a1: cstring,
proc glob*(a1: cstring, a2: cint,
a3: proc (x1: cstring, x2: cint): cint {.noconv.},
a4: ptr Tglob): cint {.importc, header: "<glob.h>".}
a4: ptr TGlob): cint {.importc, header: "<glob.h>".}
proc globfree*(a1: ptr TGlob) {.importc, header: "<glob.h>".}
proc getgrgid*(a1: TGid): ptr TGroup {.importc, header: "<grp.h>".}
proc getgrnam*(a1: cstring): ptr TGroup {.importc, header: "<grp.h>".}
proc getgrgid_r*(a1: Tgid, a2: ptr TGroup, a3: cstring, a4: int,
proc getgrgid_r*(a1: TGid, a2: ptr TGroup, a3: cstring, a4: int,
a5: ptr ptr TGroup): cint {.importc, header: "<grp.h>".}
proc getgrnam_r*(a1: cstring, a2: ptr TGroup, a3: cstring,
a4: int, a5: ptr ptr TGroup): cint {.
@ -1845,7 +1845,7 @@ proc endgrent*() {.importc, header: "<grp.h>".}
proc setgrent*() {.importc, header: "<grp.h>".}
proc iconv_open*(a1, a2: cstring): TIconv {.importc, header: "<iconv.h>".}
proc iconv_open*(a1, a2: cstring): Ticonv {.importc, header: "<iconv.h>".}
proc iconv*(a1: Ticonv, a2: var cstring, a3: var int, a4: var cstring,
a5: var int): int {.importc, header: "<iconv.h>".}
proc iconv_close*(a1: Ticonv): cint {.importc, header: "<iconv.h>".}
@ -1862,33 +1862,33 @@ proc setlocale*(a1: cint, a2: cstring): cstring {.
proc strfmon*(a1: cstring, a2: int, a3: cstring): int {.varargs,
importc, header: "<monetary.h>".}
proc mq_close*(a1: Tmqd): cint {.importc, header: "<mqueue.h>".}
proc mq_getattr*(a1: Tmqd, a2: ptr Tmq_attr): cint {.
proc mq_close*(a1: TMqd): cint {.importc, header: "<mqueue.h>".}
proc mq_getattr*(a1: TMqd, a2: ptr TMqAttr): cint {.
importc, header: "<mqueue.h>".}
proc mq_notify*(a1: Tmqd, a2: ptr Tsigevent): cint {.
proc mq_notify*(a1: TMqd, a2: ptr TsigEvent): cint {.
importc, header: "<mqueue.h>".}
proc mq_open*(a1: cstring, a2: cint): TMqd {.
varargs, importc, header: "<mqueue.h>".}
proc mq_receive*(a1: Tmqd, a2: cstring, a3: int, a4: var int): int {.
proc mq_receive*(a1: TMqd, a2: cstring, a3: int, a4: var int): int {.
importc, header: "<mqueue.h>".}
proc mq_send*(a1: Tmqd, a2: cstring, a3: int, a4: int): cint {.
proc mq_send*(a1: TMqd, a2: cstring, a3: int, a4: int): cint {.
importc, header: "<mqueue.h>".}
proc mq_setattr*(a1: Tmqd, a2, a3: ptr Tmq_attr): cint {.
proc mq_setattr*(a1: TMqd, a2, a3: ptr TMqAttr): cint {.
importc, header: "<mqueue.h>".}
proc mq_timedreceive*(a1: Tmqd, a2: cstring, a3: int, a4: int,
a5: ptr TTimespec): int {.importc, header: "<mqueue.h>".}
proc mq_timedsend*(a1: Tmqd, a2: cstring, a3: int, a4: int,
a5: ptr TTimeSpec): cint {.importc, header: "<mqueue.h>".}
proc mq_timedreceive*(a1: TMqd, a2: cstring, a3: int, a4: int,
a5: ptr Ttimespec): int {.importc, header: "<mqueue.h>".}
proc mq_timedsend*(a1: TMqd, a2: cstring, a3: int, a4: int,
a5: ptr Ttimespec): cint {.importc, header: "<mqueue.h>".}
proc mq_unlink*(a1: cstring): cint {.importc, header: "<mqueue.h>".}
proc getpwnam*(a1: cstring): ptr TPasswd {.importc, header: "<pwd.h>".}
proc getpwuid*(a1: Tuid): ptr TPasswd {.importc, header: "<pwd.h>".}
proc getpwnam_r*(a1: cstring, a2: ptr Tpasswd, a3: cstring, a4: int,
a5: ptr ptr Tpasswd): cint {.importc, header: "<pwd.h>".}
proc getpwuid_r*(a1: Tuid, a2: ptr Tpasswd, a3: cstring,
a4: int, a5: ptr ptr Tpasswd): cint {.importc, header: "<pwd.h>".}
proc getpwnam_r*(a1: cstring, a2: ptr TPasswd, a3: cstring, a4: int,
a5: ptr ptr TPasswd): cint {.importc, header: "<pwd.h>".}
proc getpwuid_r*(a1: Tuid, a2: ptr TPasswd, a3: cstring,
a4: int, a5: ptr ptr TPasswd): cint {.importc, header: "<pwd.h>".}
proc endpwent*() {.importc, header: "<pwd.h>".}
proc getpwent*(): ptr TPasswd {.importc, header: "<pwd.h>".}
proc setpwent*() {.importc, header: "<pwd.h>".}
@ -1933,9 +1933,9 @@ proc pthread_attr_setscope*(a1: ptr Tpthread_attr, a2: cint): cint {.importc,
header: "<pthread.h>".}
proc pthread_attr_setstack*(a1: ptr Tpthread_attr, a2: pointer, a3: int): cint {.
importc, header: "<pthread.h>".}
proc pthread_attr_setstackaddr*(a1: ptr TPthread_attr, a2: pointer): cint {.
proc pthread_attr_setstackaddr*(a1: ptr Tpthread_attr, a2: pointer): cint {.
importc, header: "<pthread.h>".}
proc pthread_attr_setstacksize*(a1: ptr TPthread_attr, a2: int): cint {.
proc pthread_attr_setstacksize*(a1: ptr Tpthread_attr, a2: int): cint {.
importc, header: "<pthread.h>".}
proc pthread_barrier_destroy*(a1: ptr Tpthread_barrier): cint {.
importc, header: "<pthread.h>".}
@ -1949,9 +1949,9 @@ proc pthread_barrierattr_destroy*(a1: ptr Tpthread_barrierattr): cint {.
proc pthread_barrierattr_getpshared*(
a1: ptr Tpthread_barrierattr, a2: var cint): cint {.
importc, header: "<pthread.h>".}
proc pthread_barrierattr_init*(a1: ptr TPthread_barrierattr): cint {.
proc pthread_barrierattr_init*(a1: ptr Tpthread_barrierattr): cint {.
importc, header: "<pthread.h>".}
proc pthread_barrierattr_setpshared*(a1: ptr TPthread_barrierattr,
proc pthread_barrierattr_setpshared*(a1: ptr Tpthread_barrierattr,
a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_cancel*(a1: Tpthread): cint {.importc, header: "<pthread.h>".}
proc pthread_cleanup_push*(a1: proc (x: pointer) {.noconv.}, a2: pointer) {.
@ -1970,13 +1970,13 @@ proc pthread_cond_wait*(a1: ptr Tpthread_cond,
a2: ptr Tpthread_mutex): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_destroy*(a1: ptr Tpthread_condattr): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_getclock*(a1: ptr Tpthread_condattr,
a2: var Tclockid): cint {.importc, header: "<pthread.h>".}
a2: var TClockId): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_getpshared*(a1: ptr Tpthread_condattr,
a2: var cint): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_init*(a1: ptr TPthread_condattr): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_setclock*(a1: ptr TPthread_condattr,a2: Tclockid): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_setpshared*(a1: ptr TPthread_condattr, a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_init*(a1: ptr Tpthread_condattr): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_setclock*(a1: ptr Tpthread_condattr,a2: TClockId): cint {.importc, header: "<pthread.h>".}
proc pthread_condattr_setpshared*(a1: ptr Tpthread_condattr, a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_create*(a1: ptr Tpthread, a2: ptr Tpthread_attr,
a3: proc (x: pointer): pointer {.noconv.}, a4: pointer): cint {.importc, header: "<pthread.h>".}
@ -1984,7 +1984,7 @@ proc pthread_detach*(a1: Tpthread): cint {.importc, header: "<pthread.h>".}
proc pthread_equal*(a1, a2: Tpthread): cint {.importc, header: "<pthread.h>".}
proc pthread_exit*(a1: pointer) {.importc, header: "<pthread.h>".}
proc pthread_getconcurrency*(): cint {.importc, header: "<pthread.h>".}
proc pthread_getcpuclockid*(a1: Tpthread, a2: var Tclockid): cint {.importc, header: "<pthread.h>".}
proc pthread_getcpuclockid*(a1: Tpthread, a2: var TClockId): cint {.importc, header: "<pthread.h>".}
proc pthread_getschedparam*(a1: Tpthread, a2: var cint,
a3: ptr Tsched_param): cint {.importc, header: "<pthread.h>".}
proc pthread_getspecific*(a1: Tpthread_key): pointer {.importc, header: "<pthread.h>".}
@ -2016,7 +2016,7 @@ proc pthread_mutexattr_gettype*(a1: ptr Tpthread_mutexattr,
a2: var cint): cint {.importc, header: "<pthread.h>".}
proc pthread_mutexattr_init*(a1: ptr Tpthread_mutexattr): cint {.importc, header: "<pthread.h>".}
proc pthread_mutexattr_setprioceiling*(a1: ptr tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_mutexattr_setprioceiling*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_mutexattr_setprotocol*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_mutexattr_setpshared*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
proc pthread_mutexattr_settype*(a1: ptr Tpthread_mutexattr, a2: cint): cint {.importc, header: "<pthread.h>".}
@ -2069,7 +2069,7 @@ proc pthread_testcancel*() {.importc, header: "<pthread.h>".}
proc access*(a1: cstring, a2: cint): cint {.importc, header: "<unistd.h>".}
proc alarm*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc chdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
proc chown*(a1: cstring, a2: Tuid, a3: Tgid): cint {.importc, header: "<unistd.h>".}
proc chown*(a1: cstring, a2: Tuid, a3: TGid): cint {.importc, header: "<unistd.h>".}
proc close*(a1: cint | TSocketHandle): cint {.importc, header: "<unistd.h>".}
proc confstr*(a1: cint, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
proc crypt*(a1, a2: cstring): cstring {.importc, header: "<unistd.h>".}
@ -2085,19 +2085,19 @@ proc execv*(a1: cstring, a2: cstringArray): cint {.importc, header: "<unistd.h>"
proc execve*(a1: cstring, a2, a3: cstringArray): cint {.
importc, header: "<unistd.h>".}
proc execvp*(a1: cstring, a2: cstringArray): cint {.importc, header: "<unistd.h>".}
proc fchown*(a1: cint, a2: Tuid, a3: Tgid): cint {.importc, header: "<unistd.h>".}
proc fchown*(a1: cint, a2: Tuid, a3: TGid): cint {.importc, header: "<unistd.h>".}
proc fchdir*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc fdatasync*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc fork*(): Tpid {.importc, header: "<unistd.h>".}
proc fork*(): TPid {.importc, header: "<unistd.h>".}
proc fpathconf*(a1, a2: cint): int {.importc, header: "<unistd.h>".}
proc fsync*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc ftruncate*(a1: cint, a2: Toff): cint {.importc, header: "<unistd.h>".}
proc ftruncate*(a1: cint, a2: TOff): cint {.importc, header: "<unistd.h>".}
proc getcwd*(a1: cstring, a2: int): cstring {.importc, header: "<unistd.h>".}
proc getegid*(): TGid {.importc, header: "<unistd.h>".}
proc geteuid*(): TUid {.importc, header: "<unistd.h>".}
proc geteuid*(): Tuid {.importc, header: "<unistd.h>".}
proc getgid*(): TGid {.importc, header: "<unistd.h>".}
proc getgroups*(a1: cint, a2: ptr array[0..255, Tgid]): cint {.
proc getgroups*(a1: cint, a2: ptr array[0..255, TGid]): cint {.
importc, header: "<unistd.h>".}
proc gethostid*(): int {.importc, header: "<unistd.h>".}
proc gethostname*(a1: cstring, a2: int): cint {.importc, header: "<unistd.h>".}
@ -2106,105 +2106,105 @@ proc getlogin_r*(a1: cstring, a2: int): cint {.importc, header: "<unistd.h>".}
proc getopt*(a1: cint, a2: cstringArray, a3: cstring): cint {.
importc, header: "<unistd.h>".}
proc getpgid*(a1: Tpid): Tpid {.importc, header: "<unistd.h>".}
proc getpgrp*(): Tpid {.importc, header: "<unistd.h>".}
proc getpid*(): Tpid {.importc, header: "<unistd.h>".}
proc getppid*(): Tpid {.importc, header: "<unistd.h>".}
proc getsid*(a1: Tpid): Tpid {.importc, header: "<unistd.h>".}
proc getpgid*(a1: TPid): TPid {.importc, header: "<unistd.h>".}
proc getpgrp*(): TPid {.importc, header: "<unistd.h>".}
proc getpid*(): TPid {.importc, header: "<unistd.h>".}
proc getppid*(): TPid {.importc, header: "<unistd.h>".}
proc getsid*(a1: TPid): TPid {.importc, header: "<unistd.h>".}
proc getuid*(): Tuid {.importc, header: "<unistd.h>".}
proc getwd*(a1: cstring): cstring {.importc, header: "<unistd.h>".}
proc isatty*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc lchown*(a1: cstring, a2: Tuid, a3: Tgid): cint {.importc, header: "<unistd.h>".}
proc lchown*(a1: cstring, a2: Tuid, a3: TGid): cint {.importc, header: "<unistd.h>".}
proc link*(a1, a2: cstring): cint {.importc, header: "<unistd.h>".}
proc lockf*(a1, a2: cint, a3: Toff): cint {.importc, header: "<unistd.h>".}
proc lseek*(a1: cint, a2: Toff, a3: cint): Toff {.importc, header: "<unistd.h>".}
proc lockf*(a1, a2: cint, a3: TOff): cint {.importc, header: "<unistd.h>".}
proc lseek*(a1: cint, a2: TOff, a3: cint): TOff {.importc, header: "<unistd.h>".}
proc nice*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc pathconf*(a1: cstring, a2: cint): int {.importc, header: "<unistd.h>".}
proc pause*(): cint {.importc, header: "<unistd.h>".}
proc pipe*(a: array[0..1, cint]): cint {.importc, header: "<unistd.h>".}
proc pread*(a1: cint, a2: pointer, a3: int, a4: Toff): int {.
proc pread*(a1: cint, a2: pointer, a3: int, a4: TOff): int {.
importc, header: "<unistd.h>".}
proc pwrite*(a1: cint, a2: pointer, a3: int, a4: Toff): int {.
proc pwrite*(a1: cint, a2: pointer, a3: int, a4: TOff): int {.
importc, header: "<unistd.h>".}
proc read*(a1: cint, a2: pointer, a3: int): int {.importc, header: "<unistd.h>".}
proc readlink*(a1, a2: cstring, a3: int): int {.importc, header: "<unistd.h>".}
proc rmdir*(a1: cstring): cint {.importc, header: "<unistd.h>".}
proc setegid*(a1: Tgid): cint {.importc, header: "<unistd.h>".}
proc setegid*(a1: TGid): cint {.importc, header: "<unistd.h>".}
proc seteuid*(a1: Tuid): cint {.importc, header: "<unistd.h>".}
proc setgid*(a1: Tgid): cint {.importc, header: "<unistd.h>".}
proc setgid*(a1: TGid): cint {.importc, header: "<unistd.h>".}
proc setpgid*(a1, a2: Tpid): cint {.importc, header: "<unistd.h>".}
proc setpgrp*(): Tpid {.importc, header: "<unistd.h>".}
proc setregid*(a1, a2: Tgid): cint {.importc, header: "<unistd.h>".}
proc setpgid*(a1, a2: TPid): cint {.importc, header: "<unistd.h>".}
proc setpgrp*(): TPid {.importc, header: "<unistd.h>".}
proc setregid*(a1, a2: TGid): cint {.importc, header: "<unistd.h>".}
proc setreuid*(a1, a2: Tuid): cint {.importc, header: "<unistd.h>".}
proc setsid*(): Tpid {.importc, header: "<unistd.h>".}
proc setsid*(): TPid {.importc, header: "<unistd.h>".}
proc setuid*(a1: Tuid): cint {.importc, header: "<unistd.h>".}
proc sleep*(a1: cint): cint {.importc, header: "<unistd.h>".}
proc swab*(a1, a2: pointer, a3: int) {.importc, header: "<unistd.h>".}
proc symlink*(a1, a2: cstring): cint {.importc, header: "<unistd.h>".}
proc sync*() {.importc, header: "<unistd.h>".}
proc sysconf*(a1: cint): int {.importc, header: "<unistd.h>".}
proc tcgetpgrp*(a1: cint): tpid {.importc, header: "<unistd.h>".}
proc tcsetpgrp*(a1: cint, a2: Tpid): cint {.importc, header: "<unistd.h>".}
proc truncate*(a1: cstring, a2: Toff): cint {.importc, header: "<unistd.h>".}
proc tcgetpgrp*(a1: cint): TPid {.importc, header: "<unistd.h>".}
proc tcsetpgrp*(a1: cint, a2: TPid): cint {.importc, header: "<unistd.h>".}
proc truncate*(a1: cstring, a2: TOff): cint {.importc, header: "<unistd.h>".}
proc ttyname*(a1: cint): cstring {.importc, header: "<unistd.h>".}
proc ttyname_r*(a1: cint, a2: cstring, a3: int): cint {.
importc, header: "<unistd.h>".}
proc ualarm*(a1, a2: Tuseconds): Tuseconds {.importc, header: "<unistd.h>".}
proc unlink*(a1: cstring): cint {.importc, header: "<unistd.h>".}
proc usleep*(a1: Tuseconds): cint {.importc, header: "<unistd.h>".}
proc vfork*(): tpid {.importc, header: "<unistd.h>".}
proc vfork*(): TPid {.importc, header: "<unistd.h>".}
proc write*(a1: cint, a2: pointer, a3: int): int {.importc, header: "<unistd.h>".}
proc sem_close*(a1: ptr Tsem): cint {.importc, header: "<semaphore.h>".}
proc sem_destroy*(a1: ptr Tsem): cint {.importc, header: "<semaphore.h>".}
proc sem_getvalue*(a1: ptr Tsem, a2: var cint): cint {.
proc sem_close*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
proc sem_destroy*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
proc sem_getvalue*(a1: ptr TSem, a2: var cint): cint {.
importc, header: "<semaphore.h>".}
proc sem_init*(a1: ptr Tsem, a2: cint, a3: cint): cint {.
proc sem_init*(a1: ptr TSem, a2: cint, a3: cint): cint {.
importc, header: "<semaphore.h>".}
proc sem_open*(a1: cstring, a2: cint): ptr TSem {.
varargs, importc, header: "<semaphore.h>".}
proc sem_post*(a1: ptr Tsem): cint {.importc, header: "<semaphore.h>".}
proc sem_timedwait*(a1: ptr Tsem, a2: ptr Ttimespec): cint {.
proc sem_post*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
proc sem_timedwait*(a1: ptr TSem, a2: ptr Ttimespec): cint {.
importc, header: "<semaphore.h>".}
proc sem_trywait*(a1: ptr Tsem): cint {.importc, header: "<semaphore.h>".}
proc sem_trywait*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
proc sem_unlink*(a1: cstring): cint {.importc, header: "<semaphore.h>".}
proc sem_wait*(a1: ptr Tsem): cint {.importc, header: "<semaphore.h>".}
proc sem_wait*(a1: ptr TSem): cint {.importc, header: "<semaphore.h>".}
proc ftok*(a1: cstring, a2: cint): Tkey {.importc, header: "<sys/ipc.h>".}
proc ftok*(a1: cstring, a2: cint): TKey {.importc, header: "<sys/ipc.h>".}
proc statvfs*(a1: cstring, a2: var Tstatvfs): cint {.
proc statvfs*(a1: cstring, a2: var TStatvfs): cint {.
importc, header: "<sys/statvfs.h>".}
proc fstatvfs*(a1: cint, a2: var Tstatvfs): cint {.
proc fstatvfs*(a1: cint, a2: var TStatvfs): cint {.
importc, header: "<sys/statvfs.h>".}
proc chmod*(a1: cstring, a2: TMode): cint {.importc, header: "<sys/stat.h>".}
proc fchmod*(a1: cint, a2: TMode): cint {.importc, header: "<sys/stat.h>".}
proc fstat*(a1: cint, a2: var Tstat): cint {.importc, header: "<sys/stat.h>".}
proc lstat*(a1: cstring, a2: var Tstat): cint {.importc, header: "<sys/stat.h>".}
proc fstat*(a1: cint, a2: var TStat): cint {.importc, header: "<sys/stat.h>".}
proc lstat*(a1: cstring, a2: var TStat): cint {.importc, header: "<sys/stat.h>".}
proc mkdir*(a1: cstring, a2: TMode): cint {.importc, header: "<sys/stat.h>".}
proc mkfifo*(a1: cstring, a2: TMode): cint {.importc, header: "<sys/stat.h>".}
proc mknod*(a1: cstring, a2: TMode, a3: Tdev): cint {.
proc mknod*(a1: cstring, a2: TMode, a3: TDev): cint {.
importc, header: "<sys/stat.h>".}
proc stat*(a1: cstring, a2: var Tstat): cint {.importc, header: "<sys/stat.h>".}
proc umask*(a1: Tmode): TMode {.importc, header: "<sys/stat.h>".}
proc stat*(a1: cstring, a2: var TStat): cint {.importc, header: "<sys/stat.h>".}
proc umask*(a1: TMode): TMode {.importc, header: "<sys/stat.h>".}
proc S_ISBLK*(m: Tmode): bool {.importc, header: "<sys/stat.h>".}
proc S_ISBLK*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
## Test for a block special file.
proc S_ISCHR*(m: Tmode): bool {.importc, header: "<sys/stat.h>".}
proc S_ISCHR*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
## Test for a character special file.
proc S_ISDIR*(m: Tmode): bool {.importc, header: "<sys/stat.h>".}
proc S_ISDIR*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
## Test for a directory.
proc S_ISFIFO*(m: Tmode): bool {.importc, header: "<sys/stat.h>".}
proc S_ISFIFO*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
## Test for a pipe or FIFO special file.
proc S_ISREG*(m: Tmode): bool {.importc, header: "<sys/stat.h>".}
proc S_ISREG*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
## Test for a regular file.
proc S_ISLNK*(m: Tmode): bool {.importc, header: "<sys/stat.h>".}
proc S_ISLNK*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
## Test for a symbolic link.
proc S_ISSOCK*(m: Tmode): bool {.importc, header: "<sys/stat.h>".}
proc S_ISSOCK*(m: TMode): bool {.importc, header: "<sys/stat.h>".}
## Test for a socket.
proc S_TYPEISMQ*(buf: var TStat): bool {.importc, header: "<sys/stat.h>".}
@ -2219,7 +2219,7 @@ proc S_TYPEISTMO*(buf: var TStat): bool {.importc, header: "<sys/stat.h>".}
proc mlock*(a1: pointer, a2: int): cint {.importc, header: "<sys/mman.h>".}
proc mlockall*(a1: cint): cint {.importc, header: "<sys/mman.h>".}
proc mmap*(a1: pointer, a2: int, a3, a4, a5: cint, a6: Toff): pointer {.
proc mmap*(a1: pointer, a2: int, a3, a4, a5: cint, a6: TOff): pointer {.
importc, header: "<sys/mman.h>".}
proc mprotect*(a1: pointer, a2: int, a3: cint): cint {.
importc, header: "<sys/mman.h>".}
@ -2229,75 +2229,75 @@ proc munlockall*(): cint {.importc, header: "<sys/mman.h>".}
proc munmap*(a1: pointer, a2: int): cint {.importc, header: "<sys/mman.h>".}
proc posix_madvise*(a1: pointer, a2: int, a3: cint): cint {.
importc, header: "<sys/mman.h>".}
proc posix_mem_offset*(a1: pointer, a2: int, a3: var Toff,
proc posix_mem_offset*(a1: pointer, a2: int, a3: var TOff,
a4: var int, a5: var cint): cint {.importc, header: "<sys/mman.h>".}
proc posix_typed_mem_get_info*(a1: cint,
a2: var Tposix_typed_mem_info): cint {.importc, header: "<sys/mman.h>".}
proc posix_typed_mem_open*(a1: cstring, a2, a3: cint): cint {.
importc, header: "<sys/mman.h>".}
proc shm_open*(a1: cstring, a2: cint, a3: Tmode): cint {.
proc shm_open*(a1: cstring, a2: cint, a3: TMode): cint {.
importc, header: "<sys/mman.h>".}
proc shm_unlink*(a1: cstring): cint {.importc, header: "<sys/mman.h>".}
proc asctime*(a1: var ttm): cstring{.importc, header: "<time.h>".}
proc asctime*(a1: var Ttm): cstring{.importc, header: "<time.h>".}
proc asctime_r*(a1: var ttm, a2: cstring): cstring {.importc, header: "<time.h>".}
proc clock*(): Tclock {.importc, header: "<time.h>".}
proc clock_getcpuclockid*(a1: tpid, a2: var Tclockid): cint {.
proc asctime_r*(a1: var Ttm, a2: cstring): cstring {.importc, header: "<time.h>".}
proc clock*(): TClock {.importc, header: "<time.h>".}
proc clock_getcpuclockid*(a1: TPid, a2: var TClockId): cint {.
importc, header: "<time.h>".}
proc clock_getres*(a1: Tclockid, a2: var Ttimespec): cint {.
proc clock_getres*(a1: TClockId, a2: var Ttimespec): cint {.
importc, header: "<time.h>".}
proc clock_gettime*(a1: Tclockid, a2: var Ttimespec): cint {.
proc clock_gettime*(a1: TClockId, a2: var Ttimespec): cint {.
importc, header: "<time.h>".}
proc clock_nanosleep*(a1: Tclockid, a2: cint, a3: var Ttimespec,
proc clock_nanosleep*(a1: TClockId, a2: cint, a3: var Ttimespec,
a4: var Ttimespec): cint {.importc, header: "<time.h>".}
proc clock_settime*(a1: Tclockid, a2: var Ttimespec): cint {.
proc clock_settime*(a1: TClockId, a2: var Ttimespec): cint {.
importc, header: "<time.h>".}
proc ctime*(a1: var Ttime): cstring {.importc, header: "<time.h>".}
proc ctime_r*(a1: var Ttime, a2: cstring): cstring {.importc, header: "<time.h>".}
proc difftime*(a1, a2: Ttime): cdouble {.importc, header: "<time.h>".}
proc getdate*(a1: cstring): ptr ttm {.importc, header: "<time.h>".}
proc ctime*(a1: var TTime): cstring {.importc, header: "<time.h>".}
proc ctime_r*(a1: var TTime, a2: cstring): cstring {.importc, header: "<time.h>".}
proc difftime*(a1, a2: TTime): cdouble {.importc, header: "<time.h>".}
proc getdate*(a1: cstring): ptr Ttm {.importc, header: "<time.h>".}
proc gmtime*(a1: var ttime): ptr ttm {.importc, header: "<time.h>".}
proc gmtime_r*(a1: var ttime, a2: var ttm): ptr ttm {.importc, header: "<time.h>".}
proc localtime*(a1: var ttime): ptr ttm {.importc, header: "<time.h>".}
proc localtime_r*(a1: var ttime, a2: var ttm): ptr ttm {.importc, header: "<time.h>".}
proc mktime*(a1: var ttm): ttime {.importc, header: "<time.h>".}
proc gmtime*(a1: var TTime): ptr Ttm {.importc, header: "<time.h>".}
proc gmtime_r*(a1: var TTime, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".}
proc localtime*(a1: var TTime): ptr Ttm {.importc, header: "<time.h>".}
proc localtime_r*(a1: var TTime, a2: var Ttm): ptr Ttm {.importc, header: "<time.h>".}
proc mktime*(a1: var Ttm): TTime {.importc, header: "<time.h>".}
proc nanosleep*(a1, a2: var Ttimespec): cint {.importc, header: "<time.h>".}
proc strftime*(a1: cstring, a2: int, a3: cstring,
a4: var ttm): int {.importc, header: "<time.h>".}
proc strptime*(a1, a2: cstring, a3: var ttm): cstring {.importc, header: "<time.h>".}
proc time*(a1: var Ttime): ttime {.importc, header: "<time.h>".}
proc timer_create*(a1: var Tclockid, a2: var Tsigevent,
a4: var Ttm): int {.importc, header: "<time.h>".}
proc strptime*(a1, a2: cstring, a3: var Ttm): cstring {.importc, header: "<time.h>".}
proc time*(a1: var TTime): TTime {.importc, header: "<time.h>".}
proc timer_create*(a1: var TClockId, a2: var TsigEvent,
a3: var Ttimer): cint {.importc, header: "<time.h>".}
proc timer_delete*(a1: var Ttimer): cint {.importc, header: "<time.h>".}
proc timer_gettime*(a1: Ttimer, a2: var Titimerspec): cint {.
proc timer_gettime*(a1: Ttimer, a2: var titimerspec): cint {.
importc, header: "<time.h>".}
proc timer_getoverrun*(a1: Ttimer): cint {.importc, header: "<time.h>".}
proc timer_settime*(a1: Ttimer, a2: cint, a3: var Titimerspec,
proc timer_settime*(a1: Ttimer, a2: cint, a3: var titimerspec,
a4: var titimerspec): cint {.importc, header: "<time.h>".}
proc tzset*() {.importc, header: "<time.h>".}
proc wait*(a1: var cint): tpid {.importc, header: "<sys/wait.h>".}
proc waitid*(a1: cint, a2: tid, a3: var Tsiginfo, a4: cint): cint {.
proc wait*(a1: var cint): TPid {.importc, header: "<sys/wait.h>".}
proc waitid*(a1: cint, a2: Tid, a3: var TsigInfo, a4: cint): cint {.
importc, header: "<sys/wait.h>".}
proc waitpid*(a1: tpid, a2: var cint, a3: cint): tpid {.
proc waitpid*(a1: TPid, a2: var cint, a3: cint): TPid {.
importc, header: "<sys/wait.h>".}
proc bsd_signal*(a1: cint, a2: proc (x: pointer) {.noconv.}) {.
importc, header: "<signal.h>".}
proc kill*(a1: Tpid, a2: cint): cint {.importc, header: "<signal.h>".}
proc killpg*(a1: Tpid, a2: cint): cint {.importc, header: "<signal.h>".}
proc pthread_kill*(a1: tpthread, a2: cint): cint {.importc, header: "<signal.h>".}
proc kill*(a1: TPid, a2: cint): cint {.importc, header: "<signal.h>".}
proc killpg*(a1: TPid, a2: cint): cint {.importc, header: "<signal.h>".}
proc pthread_kill*(a1: Tpthread, a2: cint): cint {.importc, header: "<signal.h>".}
proc pthread_sigmask*(a1: cint, a2, a3: var Tsigset): cint {.
importc, header: "<signal.h>".}
proc `raise`*(a1: cint): cint {.importc, header: "<signal.h>".}
proc sigaction*(a1: cint, a2, a3: var Tsigaction): cint {.
proc sigaction*(a1: cint, a2, a3: var TSigaction): cint {.
importc, header: "<signal.h>".}
proc sigaddset*(a1: var Tsigset, a2: cint): cint {.importc, header: "<signal.h>".}
proc sigaltstack*(a1, a2: var Tstack): cint {.importc, header: "<signal.h>".}
proc sigaltstack*(a1, a2: var TStack): cint {.importc, header: "<signal.h>".}
proc sigdelset*(a1: var Tsigset, a2: cint): cint {.importc, header: "<signal.h>".}
proc sigemptyset*(a1: var Tsigset): cint {.importc, header: "<signal.h>".}
proc sigfillset*(a1: var Tsigset): cint {.importc, header: "<signal.h>".}
@ -2308,20 +2308,20 @@ proc sigismember*(a1: var Tsigset, a2: cint): cint {.importc, header: "<signal.h
proc signal*(a1: cint, a2: proc (x: cint) {.noconv.}) {.
importc, header: "<signal.h>".}
proc sigpause*(a1: cint): cint {.importc, header: "<signal.h>".}
proc sigpending*(a1: var tsigset): cint {.importc, header: "<signal.h>".}
proc sigprocmask*(a1: cint, a2, a3: var tsigset): cint {.
proc sigpending*(a1: var Tsigset): cint {.importc, header: "<signal.h>".}
proc sigprocmask*(a1: cint, a2, a3: var Tsigset): cint {.
importc, header: "<signal.h>".}
proc sigqueue*(a1: tpid, a2: cint, a3: Tsigval): cint {.
proc sigqueue*(a1: TPid, a2: cint, a3: TsigVal): cint {.
importc, header: "<signal.h>".}
proc sigrelse*(a1: cint): cint {.importc, header: "<signal.h>".}
proc sigset*(a1: int, a2: proc (x: cint) {.noconv.}) {.
importc, header: "<signal.h>".}
proc sigsuspend*(a1: var Tsigset): cint {.importc, header: "<signal.h>".}
proc sigtimedwait*(a1: var Tsigset, a2: var tsiginfo,
a3: var ttimespec): cint {.importc, header: "<signal.h>".}
proc sigtimedwait*(a1: var Tsigset, a2: var TsigInfo,
a3: var Ttimespec): cint {.importc, header: "<signal.h>".}
proc sigwait*(a1: var Tsigset, a2: var cint): cint {.
importc, header: "<signal.h>".}
proc sigwaitinfo*(a1: var Tsigset, a2: var tsiginfo): cint {.
proc sigwaitinfo*(a1: var Tsigset, a2: var TsigInfo): cint {.
importc, header: "<signal.h>".}
@ -2333,81 +2333,81 @@ proc catopen*(a1: cstring, a2: cint): Tnl_catd {.
proc sched_get_priority_max*(a1: cint): cint {.importc, header: "<sched.h>".}
proc sched_get_priority_min*(a1: cint): cint {.importc, header: "<sched.h>".}
proc sched_getparam*(a1: tpid, a2: var Tsched_param): cint {.
proc sched_getparam*(a1: TPid, a2: var Tsched_param): cint {.
importc, header: "<sched.h>".}
proc sched_getscheduler*(a1: tpid): cint {.importc, header: "<sched.h>".}
proc sched_rr_get_interval*(a1: tpid, a2: var Ttimespec): cint {.
proc sched_getscheduler*(a1: TPid): cint {.importc, header: "<sched.h>".}
proc sched_rr_get_interval*(a1: TPid, a2: var Ttimespec): cint {.
importc, header: "<sched.h>".}
proc sched_setparam*(a1: tpid, a2: var Tsched_param): cint {.
proc sched_setparam*(a1: TPid, a2: var Tsched_param): cint {.
importc, header: "<sched.h>".}
proc sched_setscheduler*(a1: tpid, a2: cint, a3: var tsched_param): cint {.
proc sched_setscheduler*(a1: TPid, a2: cint, a3: var Tsched_param): cint {.
importc, header: "<sched.h>".}
proc sched_yield*(): cint {.importc, header: "<sched.h>".}
proc strerror*(errnum: cint): cstring {.importc, header: "<string.h>".}
proc hstrerror*(herrnum: cint): cstring {.importc, header: "<netdb.h>".}
proc FD_CLR*(a1: cint, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_ISSET*(a1: cint | TSocketHandle, a2: var Tfd_set): cint {.
proc FD_CLR*(a1: cint, a2: var TFdSet) {.importc, header: "<sys/select.h>".}
proc FD_ISSET*(a1: cint | TSocketHandle, a2: var TFdSet): cint {.
importc, header: "<sys/select.h>".}
proc FD_SET*(a1: cint | TSocketHandle, a2: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_ZERO*(a1: var Tfd_set) {.importc, header: "<sys/select.h>".}
proc FD_SET*(a1: cint | TSocketHandle, a2: var TFdSet) {.importc, header: "<sys/select.h>".}
proc FD_ZERO*(a1: var TFdSet) {.importc, header: "<sys/select.h>".}
proc pselect*(a1: cint, a2, a3, a4: ptr Tfd_set, a5: ptr ttimespec,
proc pselect*(a1: cint, a2, a3, a4: ptr TFdSet, a5: ptr Ttimespec,
a6: var Tsigset): cint {.importc, header: "<sys/select.h>".}
proc select*(a1: cint, a2, a3, a4: ptr Tfd_set, a5: ptr ttimeval): cint {.
proc select*(a1: cint, a2, a3, a4: ptr TFdSet, a5: ptr Ttimeval): cint {.
importc, header: "<sys/select.h>".}
when hasSpawnH:
proc posix_spawn*(a1: var tpid, a2: cstring,
proc posix_spawn*(a1: var TPid, a2: cstring,
a3: var Tposix_spawn_file_actions,
a4: var Tposix_spawnattr,
a5, a6: cstringArray): cint {.importc, header: "<spawn.h>".}
proc posix_spawn_file_actions_addclose*(a1: var tposix_spawn_file_actions,
proc posix_spawn_file_actions_addclose*(a1: var Tposix_spawn_file_actions,
a2: cint): cint {.importc, header: "<spawn.h>".}
proc posix_spawn_file_actions_adddup2*(a1: var tposix_spawn_file_actions,
proc posix_spawn_file_actions_adddup2*(a1: var Tposix_spawn_file_actions,
a2, a3: cint): cint {.importc, header: "<spawn.h>".}
proc posix_spawn_file_actions_addopen*(a1: var tposix_spawn_file_actions,
a2: cint, a3: cstring, a4: cint, a5: tmode): cint {.
proc posix_spawn_file_actions_addopen*(a1: var Tposix_spawn_file_actions,
a2: cint, a3: cstring, a4: cint, a5: TMode): cint {.
importc, header: "<spawn.h>".}
proc posix_spawn_file_actions_destroy*(
a1: var tposix_spawn_file_actions): cint {.importc, header: "<spawn.h>".}
a1: var Tposix_spawn_file_actions): cint {.importc, header: "<spawn.h>".}
proc posix_spawn_file_actions_init*(
a1: var tposix_spawn_file_actions): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_destroy*(a1: var tposix_spawnattr): cint {.
a1: var Tposix_spawn_file_actions): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_destroy*(a1: var Tposix_spawnattr): cint {.
importc, header: "<spawn.h>".}
proc posix_spawnattr_getsigdefault*(a1: var tposix_spawnattr,
proc posix_spawnattr_getsigdefault*(a1: var Tposix_spawnattr,
a2: var Tsigset): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_getflags*(a1: var tposix_spawnattr,
proc posix_spawnattr_getflags*(a1: var Tposix_spawnattr,
a2: var cshort): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_getpgroup*(a1: var tposix_spawnattr,
a2: var tpid): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_getschedparam*(a1: var tposix_spawnattr,
a2: var tsched_param): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_getschedpolicy*(a1: var tposix_spawnattr,
proc posix_spawnattr_getpgroup*(a1: var Tposix_spawnattr,
a2: var TPid): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_getschedparam*(a1: var Tposix_spawnattr,
a2: var Tsched_param): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_getschedpolicy*(a1: var Tposix_spawnattr,
a2: var cint): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_getsigmask*(a1: var tposix_spawnattr,
a2: var tsigset): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_getsigmask*(a1: var Tposix_spawnattr,
a2: var Tsigset): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_init*(a1: var tposix_spawnattr): cint {.
proc posix_spawnattr_init*(a1: var Tposix_spawnattr): cint {.
importc, header: "<spawn.h>".}
proc posix_spawnattr_setsigdefault*(a1: var tposix_spawnattr,
a2: var tsigset): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_setflags*(a1: var tposix_spawnattr, a2: cint): cint {.
proc posix_spawnattr_setsigdefault*(a1: var Tposix_spawnattr,
a2: var Tsigset): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_setflags*(a1: var Tposix_spawnattr, a2: cint): cint {.
importc, header: "<spawn.h>".}
proc posix_spawnattr_setpgroup*(a1: var tposix_spawnattr, a2: tpid): cint {.
proc posix_spawnattr_setpgroup*(a1: var Tposix_spawnattr, a2: TPid): cint {.
importc, header: "<spawn.h>".}
proc posix_spawnattr_setschedparam*(a1: var tposix_spawnattr,
a2: var tsched_param): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_setschedpolicy*(a1: var tposix_spawnattr,
proc posix_spawnattr_setschedparam*(a1: var Tposix_spawnattr,
a2: var Tsched_param): cint {.importc, header: "<spawn.h>".}
proc posix_spawnattr_setschedpolicy*(a1: var Tposix_spawnattr,
a2: cint): cint {.
importc, header: "<spawn.h>".}
proc posix_spawnattr_setsigmask*(a1: var tposix_spawnattr,
a2: var tsigset): cint {.importc, header: "<spawn.h>".}
proc posix_spawnp*(a1: var tpid, a2: cstring,
a3: var tposix_spawn_file_actions,
a4: var tposix_spawnattr,
proc posix_spawnattr_setsigmask*(a1: var Tposix_spawnattr,
a2: var Tsigset): cint {.importc, header: "<spawn.h>".}
proc posix_spawnp*(a1: var TPid, a2: cstring,
a3: var Tposix_spawn_file_actions,
a4: var Tposix_spawnattr,
a5, a6: cstringArray): cint {.importc, header: "<spawn.h>".}
proc getcontext*(a1: var Tucontext): cint {.importc, header: "<ucontext.h>".}
@ -2424,10 +2424,10 @@ proc writev*(a1: cint, a2: ptr TIOVec, a3: cint): int {.
proc CMSG_DATA*(cmsg: ptr Tcmsghdr): cstring {.
importc, header: "<sys/socket.h>".}
proc CMSG_NXTHDR*(mhdr: ptr TMsgHdr, cmsg: ptr TCMsgHdr): ptr TCmsgHdr {.
proc CMSG_NXTHDR*(mhdr: ptr Tmsghdr, cmsg: ptr Tcmsghdr): ptr Tcmsghdr {.
importc, header: "<sys/socket.h>".}
proc CMSG_FIRSTHDR*(mhdr: ptr TMsgHdr): ptr TCMsgHdr {.
proc CMSG_FIRSTHDR*(mhdr: ptr Tmsghdr): ptr Tcmsghdr {.
importc, header: "<sys/socket.h>".}
const
@ -2435,21 +2435,21 @@ const
proc `==`*(x, y: TSocketHandle): bool {.borrow.}
proc accept*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): TSocketHandle {.
proc accept*(a1: TSocketHandle, a2: ptr TSockAddr, a3: ptr TSocklen): TSocketHandle {.
importc, header: "<sys/socket.h>".}
proc bindSocket*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
proc bindSocket*(a1: TSocketHandle, a2: ptr TSockAddr, a3: TSocklen): cint {.
importc: "bind", header: "<sys/socket.h>".}
## is Posix's ``bind``, because ``bind`` is a reserved word
proc connect*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: Tsocklen): cint {.
proc connect*(a1: TSocketHandle, a2: ptr TSockAddr, a3: TSocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getpeername*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
proc getpeername*(a1: TSocketHandle, a2: ptr TSockAddr, a3: ptr TSocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getsockname*(a1: TSocketHandle, a2: ptr Tsockaddr, a3: ptr Tsocklen): cint {.
proc getsockname*(a1: TSocketHandle, a2: ptr TSockAddr, a3: ptr TSocklen): cint {.
importc, header: "<sys/socket.h>".}
proc getsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: ptr Tsocklen): cint {.
proc getsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: ptr TSocklen): cint {.
importc, header: "<sys/socket.h>".}
proc listen*(a1: TSocketHandle, a2: cint): cint {.
@ -2457,7 +2457,7 @@ proc listen*(a1: TSocketHandle, a2: cint): cint {.
proc recv*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {.
importc, header: "<sys/socket.h>".}
proc recvfrom*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint,
a5: ptr Tsockaddr, a6: ptr Tsocklen): int {.
a5: ptr TSockAddr, a6: ptr TSocklen): int {.
importc, header: "<sys/socket.h>".}
proc recvmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
importc, header: "<sys/socket.h>".}
@ -2465,10 +2465,10 @@ proc send*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint): int {.
importc, header: "<sys/socket.h>".}
proc sendmsg*(a1: TSocketHandle, a2: ptr Tmsghdr, a3: cint): int {.
importc, header: "<sys/socket.h>".}
proc sendto*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint, a5: ptr Tsockaddr,
a6: Tsocklen): int {.
proc sendto*(a1: TSocketHandle, a2: pointer, a3: int, a4: cint, a5: ptr TSockAddr,
a6: TSocklen): int {.
importc, header: "<sys/socket.h>".}
proc setsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: Tsocklen): cint {.
proc setsockopt*(a1: TSocketHandle, a2, a3: cint, a4: pointer, a5: TSocklen): cint {.
importc, header: "<sys/socket.h>".}
proc shutdown*(a1: TSocketHandle, a2: cint): cint {.
importc, header: "<sys/socket.h>".}
@ -2530,21 +2530,21 @@ proc freeaddrinfo*(a1: ptr Taddrinfo) {.importc, header: "<netdb.h>".}
proc gai_strerror*(a1: cint): cstring {.importc, header: "<netdb.h>".}
proc getaddrinfo*(a1, a2: cstring, a3: ptr TAddrInfo,
a4: var ptr TAddrInfo): cint {.importc, header: "<netdb.h>".}
proc getaddrinfo*(a1, a2: cstring, a3: ptr Taddrinfo,
a4: var ptr Taddrinfo): cint {.importc, header: "<netdb.h>".}
proc gethostbyaddr*(a1: pointer, a2: Tsocklen, a3: cint): ptr THostent {.
proc gethostbyaddr*(a1: pointer, a2: TSocklen, a3: cint): ptr Thostent {.
importc, header: "<netdb.h>".}
proc gethostbyname*(a1: cstring): ptr THostent {.importc, header: "<netdb.h>".}
proc gethostent*(): ptr THostent {.importc, header: "<netdb.h>".}
proc gethostbyname*(a1: cstring): ptr Thostent {.importc, header: "<netdb.h>".}
proc gethostent*(): ptr Thostent {.importc, header: "<netdb.h>".}
proc getnameinfo*(a1: ptr Tsockaddr, a2: Tsocklen,
a3: cstring, a4: Tsocklen, a5: cstring,
a6: Tsocklen, a7: cint): cint {.importc, header: "<netdb.h>".}
proc getnameinfo*(a1: ptr TSockAddr, a2: TSocklen,
a3: cstring, a4: TSocklen, a5: cstring,
a6: TSocklen, a7: cint): cint {.importc, header: "<netdb.h>".}
proc getnetbyaddr*(a1: int32, a2: cint): ptr TNetent {.importc, header: "<netdb.h>".}
proc getnetbyname*(a1: cstring): ptr TNetent {.importc, header: "<netdb.h>".}
proc getnetent*(): ptr TNetent {.importc, header: "<netdb.h>".}
proc getnetbyaddr*(a1: int32, a2: cint): ptr Tnetent {.importc, header: "<netdb.h>".}
proc getnetbyname*(a1: cstring): ptr Tnetent {.importc, header: "<netdb.h>".}
proc getnetent*(): ptr Tnetent {.importc, header: "<netdb.h>".}
proc getprotobyname*(a1: cstring): ptr TProtoent {.importc, header: "<netdb.h>".}
proc getprotobynumber*(a1: cint): ptr TProtoent {.importc, header: "<netdb.h>".}
@ -2560,10 +2560,10 @@ proc setnetent*(a1: cint) {.importc, header: "<netdb.h>".}
proc setprotoent*(a1: cint) {.importc, header: "<netdb.h>".}
proc setservent*(a1: cint) {.importc, header: "<netdb.h>".}
proc poll*(a1: ptr Tpollfd, a2: Tnfds, a3: int): cint {.
proc poll*(a1: ptr TPollfd, a2: Tnfds, a3: int): cint {.
importc, header: "<poll.h>".}
proc realpath*(name, resolved: CString): CString {.
proc realpath*(name, resolved: cstring): cstring {.
importc: "realpath", header: "<stdlib.h>".}

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

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 = ""

View file

@ -29,9 +29,9 @@ 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 " & quoteShell(url))
else:
@ -45,4 +45,4 @@ proc openDefaultBrowser*(url: string) =
discard startProcess(command=b, args=[url], options={poUseShell})
return
except EOS:
nil
discard

View file

@ -23,7 +23,8 @@ elif sizeof(int) == 8: # 64bit
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: echo("unsupported platform")
else:
{.error: "unsupported platform".}
type
TEntry = tuple

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

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)
@ -224,5 +224,3 @@ proc toOrderedSet*[A](keys: openarray[A]): TOrderedSet[A] =
proc `$`*[A](s: TOrderedSet[A]): string =
## The `$` operator for ordered hash sets.
dollarImpl()

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))
@ -240,7 +240,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 +248,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 +262,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 +271,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 +280,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 +290,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 +304,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 +398,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 +409,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 +423,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 +463,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 +480,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

@ -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

@ -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

@ -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

@ -346,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

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")

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)

File diff suppressed because it is too large Load diff

View file

@ -23,7 +23,7 @@ else:
type
TProcess = object of TObject
when defined(windows):
FProcessHandle: Thandle
fProcessHandle: THandle
inHandle, outHandle, errHandle: TFileHandle
id: THandle
else:
@ -108,7 +108,7 @@ proc execCmd*(command: string): int {.rtl, extern: "nosp$1", tags: [FExecIO].}
proc startProcess*(command: string,
workingDir: string = "",
args: openarray[string] = [],
args: openArray[string] = [],
env: PStringTable = nil,
options: set[TProcessOption] = {poStdErrToStdOut}):
PProcess {.rtl, extern: "nosp$1", tags: [FExecIO, FReadEnv].}
@ -219,7 +219,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
@ -329,18 +329,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
@ -348,7 +348,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)
@ -358,7 +358,7 @@ when defined(Windows) and not defined(useNimRtl):
result.readDataImpl = hsReadData
result.writeDataImpl = hsWriteData
proc buildCommandLine(a: string, args: openarray[string]): cstring =
proc buildCommandLine(a: string, args: openArray[string]): cstring =
var res = quoteShell(a)
for i in 0..high(args):
res.add(' ')
@ -383,45 +383,45 @@ 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)
@ -440,64 +440,64 @@ when defined(Windows) and not defined(useNimRtl):
var tmp = newWideCString(cmdl)
var ee = newWideCString(e)
var wwd = newWideCString(wd)
success = winlean.CreateProcessW(nil,
success = winlean.createProcessW(nil,
tmp, nil, nil, 1, NORMAL_PRIORITY_CLASS or CREATE_UNICODE_ENVIRONMENT,
ee, wwd, SI, ProcInfo)
ee, wwd, si, procInfo)
else:
success = winlean.CreateProcessA(nil,
success = winlean.createProcessA(nil,
cmdl, nil, nil, 1, NORMAL_PRIORITY_CLASS, e, wd, SI, ProcInfo)
let lastError = OSLastError()
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:
var res: int32
discard GetExitCodeProcess(p.FProcessHandle, res)
discard getExitCodeProcess(p.fProcessHandle, res)
return res
proc inputStream(p: PProcess): PStream =
@ -511,38 +511,38 @@ 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,
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 =
assert readfds.len <= MAXIMUM_WAIT_OBJECTS
var rfds: TWOHandleArray
for i in 0..readfds.len()-1:
rfds[i] = readfds[i].FProcessHandle
rfds[i] = readfds[i].fProcessHandle
var ret = waitForMultipleObjects(readfds.len.int32,
addr(rfds), 0'i32, timeout.int32)
@ -550,7 +550,7 @@ when defined(Windows) and not defined(useNimRtl):
of WAIT_TIMEOUT:
return 0
of WAIT_FAILED:
OSError(OSLastError())
osError(osLastError())
else:
var i = ret - WAIT_OBJECT_0
readfds.del(i)
@ -561,13 +561,13 @@ elif not defined(useNimRtl):
readIdx = 0
writeIdx = 1
proc addCmdArgs(command: string, args: openarray[string]): string =
proc addCmdArgs(command: string, args: openArray[string]): string =
result = quoteShell(command)
for i in 0 .. high(args):
add(result, " ")
add(result, quoteShell(args[i]))
proc toCStringArray(b, a: openarray[string]): cstringArray =
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))
@ -576,7 +576,7 @@ elif not defined(useNimRtl):
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 toCStringArray(t: PStringTable): cstringArray =
result = cast[cstringArray](alloc0((t.len + 1) * sizeof(cstring)))
var i = 0
for key, val in pairs(t):
@ -585,7 +585,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)))
@ -598,17 +598,17 @@ elif not defined(useNimRtl):
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 pid: TPid
when defined(posix_spawn) and not defined(useFork):
@ -616,7 +616,7 @@ elif not defined(useNimRtl):
var fops: Tposix_spawn_file_actions
template chck(e: expr) =
if e != 0'i32: OSError(OSLastError())
if e != 0'i32: osError(osLastError())
chck posix_spawn_file_actions_init(fops)
chck posix_spawnattr_init(attr)
@ -631,17 +631,17 @@ elif not defined(useNimRtl):
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)
chck posix_spawn_file_actions_adddup2(fops, pStderr[writeIdx], 2)
var e = if env == nil: EnvToCStringArray() else: ToCStringArray(env)
var e = if env == nil: envToCStringArray() else: toCStringArray(env)
var a: cstringArray
var res: cint
if workingDir.len > 0: os.setCurrentDir(workingDir)
@ -660,21 +660,21 @@ elif not defined(useNimRtl):
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))
@ -685,14 +685,14 @@ elif not defined(useNimRtl):
if env == nil:
discard execv(command, a)
else:
discard execve(command, a, ToCStringArray(env))
discard execve(command, a, toCStringArray(env))
else:
var x = addCmdArgs(command, args)
var a = toCStringArray(["sh", "-c"], [x])
if env == nil:
discard execv("/bin/sh", a)
else:
discard execve("/bin/sh", a, ToCStringArray(env))
discard execve("/bin/sh", a, toCStringArray(env))
# too risky to raise an exception here:
quit("execve call failed: " & $strerror(errno))
# Parent process. Copy process information.
@ -709,16 +709,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)
@ -729,21 +729,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):
@ -751,14 +751,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
@ -767,7 +767,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 =
@ -800,7 +800,7 @@ elif not defined(useNimRtl):
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:
@ -808,7 +808,7 @@ elif not defined(useNimRtl):
setLen(s, L)
proc select(readfds: var seq[PProcess], timeout = 500): int =
var tv: TTimeVal
var tv: Ttimeval
tv.tv_sec = 0
tv.tv_usec = timeout * 1000

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

@ -11,8 +11,8 @@
## It supports one convenience iterator over all command line options and some
## lower-level features.
##
## DEPRECATED. Use parseopt2 instead as this version has issues with spaces
## in arguments.
## **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.}
@ -37,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!
@ -50,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""
@ -94,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
@ -105,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)

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

@ -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
@ -187,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
@ -210,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,
@ -230,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()
@ -333,7 +333,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
@ -362,28 +362,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:.
@ -410,14 +410,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))
@ -436,17 +436,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.
@ -457,40 +457,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
@ -628,7 +628,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.
@ -669,7 +669,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)
@ -677,43 +677,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)
@ -723,10 +723,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) {.
@ -734,8 +734,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
@ -751,10 +751,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) {.
@ -762,8 +762,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].} =
@ -773,8 +773,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)
@ -784,14 +784,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:
@ -836,8 +836,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)
@ -847,12 +847,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:
@ -866,7 +866,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
@ -912,7 +912,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
@ -928,7 +928,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:
@ -970,7 +970,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
@ -993,7 +993,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
@ -1017,7 +1017,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
@ -1035,7 +1035,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
@ -1058,7 +1058,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
@ -1142,7 +1142,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)
@ -1180,7 +1180,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 =
@ -1194,7 +1194,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)
@ -1258,10 +1258,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)
@ -1291,18 +1291,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: osError(osLastError())
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: osError(osLastError())
addNLIfEmpty()
return
elif c == '\L':
addNlIfEmpty()
addNLIfEmpty()
return
add(line.string, c)
@ -1352,7 +1352,7 @@ proc readLineAsync*(socket: TSocket,
setLen(line.string, 0)
template errorOrNone =
socket.SocketError(async = true)
socket.socketError(async = true)
return ReadNone
while true:
@ -1385,7 +1385,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:
@ -1454,22 +1454,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 {.
@ -1488,8 +1488,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:
@ -1497,7 +1497,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``,
@ -1507,15 +1507,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
@ -1523,7 +1523,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) =
@ -1565,7 +1565,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.")
@ -1598,15 +1598,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].} =
@ -1622,8 +1622,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)
@ -1633,8 +1633,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
@ -1661,16 +1661,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) =
@ -1709,7 +1709,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
@ -256,7 +256,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))
@ -268,7 +268,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))
@ -297,7 +297,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".},
@ -308,7 +308,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
@ -319,11 +319,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>".}
@ -335,7 +335,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]
@ -345,11 +345,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
@ -358,7 +358,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
@ -367,7 +367,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
@ -401,7 +401,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))
@ -453,7 +453,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
@ -498,7 +498,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)
@ -532,7 +532,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``.
@ -593,7 +593,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
@ -698,7 +698,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)
@ -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
@ -126,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]))
@ -146,7 +146,8 @@ 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)
@ -176,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

@ -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)``.
@ -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.}
@ -933,7 +945,6 @@ template sysAssert(cond: bool, msg: string) =
if not cond:
echo "[SYSASSERT] ", msg
quit 1
nil
include "system/inclrtl"
@ -1061,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
@ -1073,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
@ -1115,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
@ -1135,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
@ -1157,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**
@ -1165,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
@ -1186,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
@ -1237,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.
@ -1259,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
@ -1319,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.} =
@ -1372,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):
@ -1425,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):
@ -1959,20 +1970,20 @@ when not defined(JS): #and not defined(NimrodVM):
## 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: [].}
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`.
##
@ -1989,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.
@ -2018,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].}
@ -2047,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
@ -2064,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
@ -2192,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)
@ -2203,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]
@ -2225,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
@ -2234,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
@ -2547,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,
@ -2560,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
@ -2577,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
@ -2596,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.} =
@ -2643,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:
@ -2651,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()
@ -2675,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
@ -530,7 +531,7 @@ proc allocInv(a: TMemRegion): bool =
while it != nil:
if it.zeroField != 0:
echo "[SYSASSERT] it.zeroField != 0"
cprintf("%ld %p\n", it.zeroField, it)
c_printf("%ld %p\n", it.zeroField, it)
return false
it = it.next
c = c.next
@ -556,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:
@ -580,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")
@ -627,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()) %%
@ -738,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)
@ -759,7 +760,7 @@ proc getOccupiedMem(a: TMemRegion): int {.inline.} =
# ---------------------- thread memory region -------------------------------
template InstantiateForRegion(allocator: expr) =
template instantiateForRegion(allocator: expr) =
when defined(fulldebug):
proc interiorAllocatedPtr*(p: pointer): pointer =
result = interiorAllocatedPtr(allocator, p)
@ -801,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)
@ -817,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,62 +7,60 @@
# distribution, for details about the copyright.
#
# Atomic operations for Nimrod.
## Atomic operations for Nimrod.
when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
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.
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
## Type Class representing valid types for use with atomic procs
proc atomic_load_n*[T: TAtomType](p: ptr T, mem: AtomMemModel): T {.
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 atomic_load*[T: TAtomType](p: ptr T, ret: ptr T, mem: AtomMemModel) {.
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 atomic_store_n*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel) {.
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 atomic_store*[T: TAtomType](p: ptr T, val: ptr T, mem: AtomMemModel) {.
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 atomic_exchange_n*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
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 atomic_exchange*[T: TAtomType](p: ptr T, val: ptr T, ret: ptr T, mem: AtomMemModel) {.
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 atomic_compare_exchange_n*[T: TAtomType](p: ptr T, expected: ptr T, desired: T,
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
@ -78,7 +76,7 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
## cannot be __ATOMIC_RELEASE nor __ATOMIC_ACQ_REL. It also cannot be a stronger model
## than that specified by success_memmodel.
proc atomic_compare_exchange*[T: TAtomType](p: ptr T, expected: ptr T, desired: ptr T,
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.
@ -86,58 +84,58 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
## value is also a pointer.
## Perform the operation return the new value, all memory models are valid
proc atomic_add_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicAddFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_add_fetch", nodecl.}
proc atomic_sub_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicSubFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_sub_fetch", nodecl.}
proc atomic_or_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicOrFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_or_fetch ", nodecl.}
proc atomic_and_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicAndFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_and_fetch", nodecl.}
proc atomic_xor_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
proc atomicXorFetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_xor_fetch", nodecl.}
proc atomic_nand_fetch*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
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 atomic_fetch_add*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_add ", nodecl.}
proc atomic_fetch_sub*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_sub ", nodecl.}
proc atomic_fetch_or*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_or ", nodecl.}
proc atomic_fetch_and*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_and ", nodecl.}
proc atomic_fetch_xor*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
importc: "__atomic_fetch_xor ", nodecl.}
proc atomic_fetch_nand*[T: TAtomType](p: ptr T, val: T, mem: AtomMemModel): T {.
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 atomic_test_and_set*(p: pointer, mem: AtomMemModel): bool {.
importc: "__atomic_test_and_set ", 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 atomic_clear*(p: pointer, mem: AtomMemModel) {.
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 atomic_thread_fence*(mem: AtomMemModel) {.
importc: "__atomic_thread_fence ", nodecl.}
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 atomic_signal_fence*(mem: AtomMemModel) {.
importc: "__atomic_signal_fence ", nodecl.}
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 atomic_always_lock_free*(size: int, p: pointer): bool {.
importc: "__atomic_always_lock_free ", nodecl.}
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.
@ -145,8 +143,8 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
## A value of 0 indicates typical alignment should be used. The compiler may also
## ignore this parameter.
proc atomic_is_lock_free*(size: int, p: pointer): bool {.
importc: "__atomic_is_lock_free ", nodecl.}
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.
@ -154,19 +152,14 @@ when (defined(gcc) or defined(llvm_gcc)) and hasThreadSupport:
## A value of 0 indicates typical alignment should be used. The compiler may also
## ignore this parameter.
elif defined(vcc) and hasThreadSupport:
proc add_and_fetch*(p: ptr int, val: int): int {.
proc addAndFetch*(p: ptr int, val: int): int {.
importc: "NimXadd", nodecl.}
else:
proc add_and_fetch*(p: ptr int, val: int): int {.inline.} =
proc addAndFetch*(p: ptr int, val: int): int {.inline.} =
inc(p[], val)
result = p[]
# atomic compare and swap (CAS) funcitons to implement lock-free algorithms
#if defined(windows) and not defined(gcc) and hasThreadSupport:
@ -183,7 +176,7 @@ else:
#elif not hasThreadSupport:
# proc compareAndSwap*[T](mem: ptr T,
# expected: T, newValue: T): bool {.inline.} =
# expected: T, newValue: T): bool {.inline.} =
# ## Returns true if successfully set value at mem to newValue when value
# ## at mem == expected
# var oldval = mem[]
@ -209,7 +202,4 @@ proc atomicDec*(memLoc: var int, x: int = 1): int =
result = atomic_add_fetch(memLoc.addr, -x, ATOMIC_RELAXED)
else:
dec(memLoc, x)
result = memLoc
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

@ -48,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)
@ -67,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)
@ -82,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:
@ -92,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)
@ -105,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)[])
@ -118,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)
@ -143,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
@ -151,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
@ -161,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
@ -170,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
@ -200,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.
@ -212,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,13 +11,13 @@
# use the heap (and nor exceptions) do not include the GC or memory allocator.
var
errorMessageWriter*: (proc(msg: string): void {.tags: [FWriteIO].})
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(stdmsg, msg)
proc writeToStdErr(msg: cstring) = write(stdmsg, msg)
else:
proc MessageBoxA(hWnd: cint, lpText, lpCaption: cstring, uType: int): int32 {.
@ -80,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 {.
@ -240,7 +240,7 @@ proc raiseExceptionAux(e: ref E_Base) =
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 = ""
@ -253,7 +253,7 @@ proc reraiseException() {.compilerRtl.} =
else:
raiseExceptionAux(currException)
proc WriteStackTrace() =
proc writeStackTrace() =
when hasSomeStackTrace:
var s = ""
rawWriteStackTrace(s)
@ -280,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")

View file

@ -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,19 +329,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")
@ -352,7 +352,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:
@ -519,7 +519,7 @@ 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)
@ -573,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)
@ -582,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)
@ -669,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.}
@ -869,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.} =
@ -891,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()
@ -904,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
@ -913,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
@ -927,7 +927,7 @@ proc collectZCT(gch: var TGcHeap): bool =
else:
sysAssert(c.typ != nil, "collectZCT 2")
zeroMem(c, sizeof(TCell))
when withRealtime:
when withRealTime:
if steps == 0:
steps = workPackage
if gch.maxPause > 0:
@ -952,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")
@ -970,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):
@ -997,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
@ -1029,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

@ -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

@ -33,7 +33,7 @@ const
type
PPointer = ptr pointer
TByteArray = array[0..1000_0000, byte]
TByteArray = array[0..1000_0000, Byte]
PByte = ptr TByteArray
PString = ptr string
@ -114,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)
@ -125,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()
@ -160,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
@ -173,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):
@ -193,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)
@ -204,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)
@ -235,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
@ -248,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
@ -268,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 ""
@ -287,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,11 +29,11 @@
##
## 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))
@ -54,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".}
@ -67,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:
@ -116,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
@ -141,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:
@ -159,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.
@ -184,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
@ -193,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) +%
@ -205,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()
@ -220,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
@ -239,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?
@ -266,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:
@ -294,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.} =
@ -308,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)
@ -318,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])
@ -346,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,74 +134,76 @@ 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, dynlib: "kernel32", stdcall.}
proc getModuleFileNameA*(handle: THandle, buf: CString, size: int32): int32 {.
importc: "GetModuleFileNameA", dynlib: "kernel32", stdcall.}
const
FILE_ATTRIBUTE_ARCHIVE* = 32'i32
@ -228,91 +230,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 +340,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,7 +418,7 @@ 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
@ -437,10 +445,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 +478,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 +486,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 +531,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".}
@ -558,53 +566,53 @@ 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 {.
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 {.
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

@ -0,0 +1,331 @@
/* -----------------------------------------------------------------*-C-*-
libffi 2.00-beta - Copyright (c) 1996-2003 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
/* -------------------------------------------------------------------
The basic API is described in the README file.
The raw API is designed to bypass some of the argument packing
and unpacking on architectures for which it can be avoided.
The closure API allows interpreted functions to be packaged up
inside a C function pointer, so that they can be called as C functions,
with no understanding on the client side that they are interpreted.
It can also be used in other cases in which it is necessary to package
up a user specified parameter and a function pointer as a single
function pointer.
The closure API must be implemented in order to get its functionality,
e.g. for use by gij. Routines are provided to emulate the raw API
if the underlying platform doesn't allow faster implementation.
More details on the raw and cloure API can be found in:
http://gcc.gnu.org/ml/java/1999-q3/msg00138.html
and
http://gcc.gnu.org/ml/java/1999-q3/msg00174.html
-------------------------------------------------------------------- */
#ifndef LIBFFI_H
#define LIBFFI_H
#ifdef __cplusplus
extern "C" {
#endif
/* Specify which architecture libffi is configured for. */
//XXX #define X86
/* ---- System configuration information --------------------------------- */
#include <ffitarget.h>
#ifndef LIBFFI_ASM
#include <stddef.h>
#include <limits.h>
/* LONG_LONG_MAX is not always defined (not if STRICT_ANSI, for example).
But we can find it either under the correct ANSI name, or under GNU
C's internal name. */
#ifdef LONG_LONG_MAX
# define FFI_LONG_LONG_MAX LONG_LONG_MAX
#else
# ifdef LLONG_MAX
# define FFI_LONG_LONG_MAX LLONG_MAX
# else
# ifdef __GNUC__
# define FFI_LONG_LONG_MAX __LONG_LONG_MAX__
# endif
# ifdef _MSC_VER
# define FFI_LONG_LONG_MAX _I64_MAX
# endif
# endif
#endif
#if SCHAR_MAX == 127
# define ffi_type_uchar ffi_type_uint8
# define ffi_type_schar ffi_type_sint8
#else
#error "char size not supported"
#endif
#if SHRT_MAX == 32767
# define ffi_type_ushort ffi_type_uint16
# define ffi_type_sshort ffi_type_sint16
#elif SHRT_MAX == 2147483647
# define ffi_type_ushort ffi_type_uint32
# define ffi_type_sshort ffi_type_sint32
#else
#error "short size not supported"
#endif
#if INT_MAX == 32767
# define ffi_type_uint ffi_type_uint16
# define ffi_type_sint ffi_type_sint16
#elif INT_MAX == 2147483647
# define ffi_type_uint ffi_type_uint32
# define ffi_type_sint ffi_type_sint32
#elif INT_MAX == 9223372036854775807
# define ffi_type_uint ffi_type_uint64
# define ffi_type_sint ffi_type_sint64
#else
#error "int size not supported"
#endif
#define ffi_type_ulong ffi_type_uint64
#define ffi_type_slong ffi_type_sint64
#if LONG_MAX == 2147483647
# if FFI_LONG_LONG_MAX != 9223372036854775807
#error "no 64-bit data type supported"
# endif
#elif LONG_MAX != 9223372036854775807
#error "long size not supported"
#endif
/* The closure code assumes that this works on pointers, i.e. a size_t */
/* can hold a pointer. */
typedef struct _ffi_type
{
size_t size;
unsigned short alignment;
unsigned short type;
/*@null@*/ struct _ffi_type **elements;
} ffi_type;
/* These are defined in types.c */
extern const ffi_type ffi_type_void;
extern const ffi_type ffi_type_uint8;
extern const ffi_type ffi_type_sint8;
extern const ffi_type ffi_type_uint16;
extern const ffi_type ffi_type_sint16;
extern const ffi_type ffi_type_uint32;
extern const ffi_type ffi_type_sint32;
extern const ffi_type ffi_type_uint64;
extern const ffi_type ffi_type_sint64;
extern const ffi_type ffi_type_float;
extern const ffi_type ffi_type_double;
extern const ffi_type ffi_type_longdouble;
extern const ffi_type ffi_type_pointer;
typedef enum {
FFI_OK = 0,
FFI_BAD_TYPEDEF,
FFI_BAD_ABI
} ffi_status;
typedef unsigned FFI_TYPE;
typedef struct {
ffi_abi abi;
unsigned nargs;
/*@dependent@*/ ffi_type **arg_types;
/*@dependent@*/ ffi_type *rtype;
unsigned bytes;
unsigned flags;
#ifdef FFI_EXTRA_CIF_FIELDS
FFI_EXTRA_CIF_FIELDS;
#endif
} ffi_cif;
/* ---- Definitions for the raw API -------------------------------------- */
#ifdef _WIN64
#define FFI_SIZEOF_ARG 8
#else
#define FFI_SIZEOF_ARG 4
#endif
typedef union {
ffi_sarg sint;
ffi_arg uint;
float flt;
char data[FFI_SIZEOF_ARG];
void* ptr;
} ffi_raw;
void ffi_raw_call (/*@dependent@*/ ffi_cif *cif,
void (*fn)(),
/*@out@*/ void *rvalue,
/*@dependent@*/ ffi_raw *avalue);
void ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
void ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
size_t ffi_raw_size (ffi_cif *cif);
/* This is analogous to the raw API, except it uses Java parameter */
/* packing, even on 64-bit machines. I.e. on 64-bit machines */
/* longs and doubles are followed by an empty 64-bit word. */
void ffi_java_raw_call (/*@dependent@*/ ffi_cif *cif,
void (*fn)(),
/*@out@*/ void *rvalue,
/*@dependent@*/ ffi_raw *avalue);
void ffi_java_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw);
void ffi_java_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args);
size_t ffi_java_raw_size (ffi_cif *cif);
/* ---- Definitions for closures ----------------------------------------- */
#if FFI_CLOSURES
typedef struct {
char tramp[FFI_TRAMPOLINE_SIZE];
ffi_cif *cif;
void (*fun)(ffi_cif*,void*,void**,void*);
void *user_data;
} ffi_closure;
void ffi_closure_free(void *);
void *ffi_closure_alloc (size_t size, void **code);
ffi_status
ffi_prep_closure_loc (ffi_closure*,
ffi_cif *,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc);
typedef struct {
char tramp[FFI_TRAMPOLINE_SIZE];
ffi_cif *cif;
#if !FFI_NATIVE_RAW_API
/* if this is enabled, then a raw closure has the same layout
as a regular closure. We use this to install an intermediate
handler to do the transaltion, void** -> ffi_raw*. */
void (*translate_args)(ffi_cif*,void*,void**,void*);
void *this_closure;
#endif
void (*fun)(ffi_cif*,void*,ffi_raw*,void*);
void *user_data;
} ffi_raw_closure;
ffi_status
ffi_prep_raw_closure (ffi_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data);
ffi_status
ffi_prep_java_raw_closure (ffi_raw_closure*,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data);
#endif /* FFI_CLOSURES */
/* ---- Public interface definition -------------------------------------- */
ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
ffi_abi abi,
unsigned int nargs,
/*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype,
/*@dependent@*/ ffi_type **atypes);
void
ffi_call(/*@dependent@*/ ffi_cif *cif,
void (*fn)(),
/*@out@*/ void *rvalue,
/*@dependent@*/ void **avalue);
/* Useful for eliminating compiler warnings */
#define FFI_FN(f) ((void (*)())f)
/* ---- Definitions shared with assembly code ---------------------------- */
#endif
/* If these change, update src/mips/ffitarget.h. */
#define FFI_TYPE_VOID 0
#define FFI_TYPE_INT 1
#define FFI_TYPE_FLOAT 2
#define FFI_TYPE_DOUBLE 3
#if 1
#define FFI_TYPE_LONGDOUBLE 4
#else
#define FFI_TYPE_LONGDOUBLE FFI_TYPE_DOUBLE
#endif
#define FFI_TYPE_UINT8 5
#define FFI_TYPE_SINT8 6
#define FFI_TYPE_UINT16 7
#define FFI_TYPE_SINT16 8
#define FFI_TYPE_UINT32 9
#define FFI_TYPE_SINT32 10
#define FFI_TYPE_UINT64 11
#define FFI_TYPE_SINT64 12
#define FFI_TYPE_STRUCT 13
#define FFI_TYPE_POINTER 14
/* This should always refer to the last type code (for sanity checks) */
#define FFI_TYPE_LAST FFI_TYPE_POINTER
#define FFI_HIDDEN /* no idea what the origial definition looks like ... */
#ifdef __GNUC__
# define LIKELY(x) __builtin_expect(x, 1)
# define UNLIKELY(x) __builtin_expect(x, 0)
#else
# define LIKELY(x) (x)
# define UNLIKELY(x) (x)
#endif
#define MAYBE_UNUSED
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,77 @@
/* -----------------------------------------------------------------------
ffi_common.h - Copyright (c) 1996 Red Hat, Inc.
Common internal definitions and macros. Only necessary for building
libffi.
----------------------------------------------------------------------- */
#ifndef FFI_COMMON_H
#define FFI_COMMON_H
#ifdef __cplusplus
extern "C" {
#endif
#include <fficonfig.h>
#include <malloc.h>
/* Check for the existence of memcpy. */
#if STDC_HEADERS
# include <string.h>
#else
# ifndef HAVE_MEMCPY
# define memcpy(d, s, n) bcopy ((s), (d), (n))
# endif
#endif
#if defined(FFI_DEBUG)
#include <stdio.h>
#endif
#ifdef FFI_DEBUG
/*@exits@*/ void ffi_assert(/*@temp@*/ char *expr, /*@temp@*/ char *file, int line);
void ffi_stop_here(void);
void ffi_type_test(/*@temp@*/ /*@out@*/ ffi_type *a, /*@temp@*/ char *file, int line);
#define FFI_ASSERT(x) ((x) ? (void)0 : ffi_assert(#x, __FILE__,__LINE__))
#define FFI_ASSERT_AT(x, f, l) ((x) ? 0 : ffi_assert(#x, (f), (l)))
#define FFI_ASSERT_VALID_TYPE(x) ffi_type_test (x, __FILE__, __LINE__)
#else
#define FFI_ASSERT(x)
#define FFI_ASSERT_AT(x, f, l)
#define FFI_ASSERT_VALID_TYPE(x)
#endif
#define ALIGN(v, a) (((((size_t) (v))-1) | ((a)-1))+1)
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif);
/* Extended cif, used in callback from assembly routine */
typedef struct
{
/*@dependent@*/ ffi_cif *cif;
/*@dependent@*/ void *rvalue;
/*@dependent@*/ void **avalue;
} extended_cif;
/* Terse sized type definitions. */
typedef unsigned int UINT8 __attribute__((__mode__(__QI__)));
typedef signed int SINT8 __attribute__((__mode__(__QI__)));
typedef unsigned int UINT16 __attribute__((__mode__(__HI__)));
typedef signed int SINT16 __attribute__((__mode__(__HI__)));
typedef unsigned int UINT32 __attribute__((__mode__(__SI__)));
typedef signed int SINT32 __attribute__((__mode__(__SI__)));
typedef unsigned int UINT64 __attribute__((__mode__(__DI__)));
typedef signed int SINT64 __attribute__((__mode__(__DI__)));
typedef float FLOAT32;
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,96 @@
/* fficonfig.h. Originally created by configure, now hand_maintained for MSVC. */
/* fficonfig.h. Generated automatically by configure. */
/* fficonfig.h.in. Generated automatically from configure.in by autoheader. */
/* Define this for MSVC, but not for mingw32! */
#ifdef _MSC_VER
#define __attribute__(x) /* */
#endif
#define alloca _alloca
/*----------------------------------------------------------------*/
/* Define if using alloca.c. */
/* #undef C_ALLOCA */
/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
This function is required for alloca.c support on those systems. */
/* #undef CRAY_STACKSEG_END */
/* Define if you have alloca, as a function or macro. */
#define HAVE_ALLOCA 1
/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
/* #define HAVE_ALLOCA_H 1 */
/* If using the C implementation of alloca, define if you know the
direction of stack growth for your system; otherwise it will be
automatically deduced at run-time.
STACK_DIRECTION > 0 => grows toward higher addresses
STACK_DIRECTION < 0 => grows toward lower addresses
STACK_DIRECTION = 0 => direction of growth unknown
*/
/* #undef STACK_DIRECTION */
/* Define if you have the ANSI C header files. */
#define STDC_HEADERS 1
/* Define if you have the memcpy function. */
#define HAVE_MEMCPY 1
/* Define if read-only mmap of a plain file works. */
//#define HAVE_MMAP_FILE 1
/* Define if mmap of /dev/zero works. */
//#define HAVE_MMAP_DEV_ZERO 1
/* Define if mmap with MAP_ANON(YMOUS) works. */
//#define HAVE_MMAP_ANON 1
/* The number of bytes in type double */
#define SIZEOF_DOUBLE 8
/* The number of bytes in type long double */
#define SIZEOF_LONG_DOUBLE 12
/* Define if you have the long double type and it is bigger than a double */
#define HAVE_LONG_DOUBLE 1
/* whether byteorder is bigendian */
/* #undef WORDS_BIGENDIAN */
/* Define if the host machine stores words of multi-word integers in
big-endian order. */
/* #undef HOST_WORDS_BIG_ENDIAN */
/* 1234 = LIL_ENDIAN, 4321 = BIGENDIAN */
#define BYTEORDER 1234
/* Define if your assembler and linker support unaligned PC relative relocs. */
/* #undef HAVE_AS_SPARC_UA_PCREL */
/* Define if your assembler supports .register. */
/* #undef HAVE_AS_REGISTER_PSEUDO_OP */
/* Define if .eh_frame sections should be read-only. */
/* #undef HAVE_RO_EH_FRAME */
/* Define to the flags needed for the .section .eh_frame directive. */
/* #define EH_FRAME_FLAGS "aw" */
/* Define to the flags needed for the .section .eh_frame directive. */
/* #define EH_FRAME_FLAGS "aw" */
/* Define this if you want extra debugging. */
/* #undef FFI_DEBUG */
/* Define this is you do not want support for aggregate types. */
/* #undef FFI_NO_STRUCTS */
/* Define this is you do not want support for the raw API. */
/* #undef FFI_NO_RAW_API */
/* Define this if you are using Purify and want to suppress spurious messages. */
/* #undef USING_PURIFY */

View file

@ -0,0 +1,150 @@
/* -----------------------------------------------------------------*-C-*-
ffitarget.h - Copyright (c) 2012 Anthony Green
Copyright (c) 1996-2003, 2010 Red Hat, Inc.
Copyright (C) 2008 Free Software Foundation, Inc.
Target configuration macros for x86 and x86-64.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#ifndef LIBFFI_TARGET_H
#define LIBFFI_TARGET_H
#ifndef LIBFFI_H
#error "Please do not include ffitarget.h directly into your source. Use ffi.h instead."
#endif
/* ---- System specific configurations ----------------------------------- */
/* For code common to all platforms on x86 and x86_64. */
#define X86_ANY
#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
# if defined(__x86_64__) || defined(__x86_64) || defined(_M_X64)
# define X86_64
# define X86_WIN64
# else
# define X86_32
# define X86_WIN32
# endif
#endif
#if defined (X86_64) && defined (__i386__)
#undef X86_64
#define X86
#endif
#ifdef X86_WIN64
#define FFI_SIZEOF_ARG 8
#define USE_BUILTIN_FFS 0 /* not yet implemented in mingw-64 */
#endif
/* ---- Generic type definitions ----------------------------------------- */
#ifndef LIBFFI_ASM
#ifdef X86_WIN64
#ifdef _MSC_VER
typedef unsigned __int64 ffi_arg;
typedef __int64 ffi_sarg;
#else
typedef unsigned long long ffi_arg;
typedef long long ffi_sarg;
#endif
#else
#if defined __x86_64__ && defined __ILP32__
#define FFI_SIZEOF_ARG 8
#define FFI_SIZEOF_JAVA_RAW 4
typedef unsigned long long ffi_arg;
typedef long long ffi_sarg;
#else
typedef unsigned long ffi_arg;
typedef signed long ffi_sarg;
#endif
#endif
typedef enum ffi_abi {
FFI_FIRST_ABI = 0,
/* ---- Intel x86 Win32 ---------- */
#ifdef X86_WIN32
FFI_SYSV,
FFI_STDCALL,
FFI_THISCALL,
FFI_FASTCALL,
FFI_MS_CDECL,
FFI_LAST_ABI,
#ifdef _MSC_VER
FFI_DEFAULT_ABI = FFI_MS_CDECL
#else
FFI_DEFAULT_ABI = FFI_SYSV
#endif
#elif defined(X86_WIN64)
FFI_WIN64,
FFI_LAST_ABI,
FFI_DEFAULT_ABI = FFI_WIN64
#else
/* ---- Intel x86 and AMD x86-64 - */
FFI_SYSV,
FFI_UNIX64, /* Unix variants all use the same ABI for x86-64 */
FFI_LAST_ABI,
#if defined(__i386__) || defined(__i386)
FFI_DEFAULT_ABI = FFI_SYSV
#else
FFI_DEFAULT_ABI = FFI_UNIX64
#endif
#endif
} ffi_abi;
#endif
/* ---- Definitions for closures ----------------------------------------- */
#define FFI_CLOSURES 1
#define FFI_TYPE_SMALL_STRUCT_1B (FFI_TYPE_LAST + 1)
#define FFI_TYPE_SMALL_STRUCT_2B (FFI_TYPE_LAST + 2)
#define FFI_TYPE_SMALL_STRUCT_4B (FFI_TYPE_LAST + 3)
#define FFI_TYPE_MS_STRUCT (FFI_TYPE_LAST + 4)
#if defined (X86_64) || (defined (__x86_64__) && defined (X86_DARWIN))
#define FFI_TRAMPOLINE_SIZE 24
#define FFI_NATIVE_RAW_API 0
#else
#ifdef X86_WIN32
#define FFI_TRAMPOLINE_SIZE 52
#else
#ifdef X86_WIN64
#define FFI_TRAMPOLINE_SIZE 29
#define FFI_NATIVE_RAW_API 0
#define FFI_NO_RAW_API 1
#else
#define FFI_TRAMPOLINE_SIZE 10
#endif
#endif
#ifndef X86_WIN64
#define FFI_NATIVE_RAW_API 1 /* x86 has native raw api support */
#endif
#endif
#endif

View file

@ -0,0 +1,110 @@
#include <ffi.h>
#ifdef MS_WIN32
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
# if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
# define MAP_ANONYMOUS MAP_ANON
# endif
#endif
#include "ctypes.h"
/* BLOCKSIZE can be adjusted. Larger blocksize will take a larger memory
overhead, but allocate less blocks from the system. It may be that some
systems have a limit of how many mmap'd blocks can be open.
*/
#define BLOCKSIZE _pagesize
/* #define MALLOC_CLOSURE_DEBUG */ /* enable for some debugging output */
/******************************************************************/
typedef union _tagITEM {
ffi_closure closure;
union _tagITEM *next;
} ITEM;
static ITEM *free_list;
static int _pagesize;
static void more_core(void)
{
ITEM *item;
int count, i;
/* determine the pagesize */
#ifdef MS_WIN32
if (!_pagesize) {
SYSTEM_INFO systeminfo;
GetSystemInfo(&systeminfo);
_pagesize = systeminfo.dwPageSize;
}
#else
if (!_pagesize) {
#ifdef _SC_PAGESIZE
_pagesize = sysconf(_SC_PAGESIZE);
#else
_pagesize = getpagesize();
#endif
}
#endif
/* calculate the number of nodes to allocate */
count = BLOCKSIZE / sizeof(ITEM);
/* allocate a memory block */
#ifdef MS_WIN32
item = (ITEM *)VirtualAlloc(NULL,
count * sizeof(ITEM),
MEM_COMMIT,
PAGE_EXECUTE_READWRITE);
if (item == NULL)
return;
#else
item = (ITEM *)mmap(NULL,
count * sizeof(ITEM),
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS,
-1,
0);
if (item == (void *)MAP_FAILED)
return;
#endif
#ifdef MALLOC_CLOSURE_DEBUG
printf("block at %p allocated (%d bytes), %d ITEMs\n",
item, count * sizeof(ITEM), count);
#endif
/* put them into the free list */
for (i = 0; i < count; ++i) {
item->next = free_list;
free_list = item;
++item;
}
}
/******************************************************************/
/* put the item back into the free list */
void ffi_closure_free(void *p)
{
ITEM *item = (ITEM *)p;
item->next = free_list;
free_list = item;
}
/* return one item from the free list, allocating more if needed */
void *ffi_closure_alloc(size_t ignored, void** codeloc)
{
ITEM *item;
if (!free_list)
more_core();
if (!free_list)
return NULL;
item = free_list;
free_list = item->next;
*codeloc = (void *)item;
return (void *)item;
}

View file

@ -0,0 +1,254 @@
/* -----------------------------------------------------------------------
raw_api.c - Copyright (c) 1999, 2008 Red Hat, Inc.
Author: Kresten Krab Thorup <krab@gnu.org>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
/* This file defines generic functions for use with the raw api. */
#include <ffi.h>
#include <ffi_common.h>
#if !FFI_NO_RAW_API
size_t
ffi_raw_size (ffi_cif *cif)
{
size_t result = 0;
int i;
ffi_type **at = cif->arg_types;
for (i = cif->nargs-1; i >= 0; i--, at++)
{
#if !FFI_NO_STRUCTS
if ((*at)->type == FFI_TYPE_STRUCT)
result += ALIGN (sizeof (void*), FFI_SIZEOF_ARG);
else
#endif
result += ALIGN ((*at)->size, FFI_SIZEOF_ARG);
}
return result;
}
void
ffi_raw_to_ptrarray (ffi_cif *cif, ffi_raw *raw, void **args)
{
unsigned i;
ffi_type **tp = cif->arg_types;
#if WORDS_BIGENDIAN
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
switch ((*tp)->type)
{
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
*args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 1);
break;
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
*args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 2);
break;
#if FFI_SIZEOF_ARG >= 4
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
*args = (void*) ((char*)(raw++) + FFI_SIZEOF_ARG - 4);
break;
#endif
#if !FFI_NO_STRUCTS
case FFI_TYPE_STRUCT:
*args = (raw++)->ptr;
break;
#endif
case FFI_TYPE_POINTER:
*args = (void*) &(raw++)->ptr;
break;
default:
*args = raw;
raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
#else /* WORDS_BIGENDIAN */
#if !PDP
/* then assume little endian */
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
#if !FFI_NO_STRUCTS
if ((*tp)->type == FFI_TYPE_STRUCT)
{
*args = (raw++)->ptr;
}
else
#endif
{
*args = (void*) raw;
raw += ALIGN ((*tp)->size, sizeof (void*)) / sizeof (void*);
}
}
#else
#error "pdp endian not supported"
#endif /* ! PDP */
#endif /* WORDS_BIGENDIAN */
}
void
ffi_ptrarray_to_raw (ffi_cif *cif, void **args, ffi_raw *raw)
{
unsigned i;
ffi_type **tp = cif->arg_types;
for (i = 0; i < cif->nargs; i++, tp++, args++)
{
switch ((*tp)->type)
{
case FFI_TYPE_UINT8:
(raw++)->uint = *(UINT8*) (*args);
break;
case FFI_TYPE_SINT8:
(raw++)->sint = *(SINT8*) (*args);
break;
case FFI_TYPE_UINT16:
(raw++)->uint = *(UINT16*) (*args);
break;
case FFI_TYPE_SINT16:
(raw++)->sint = *(SINT16*) (*args);
break;
#if FFI_SIZEOF_ARG >= 4
case FFI_TYPE_UINT32:
(raw++)->uint = *(UINT32*) (*args);
break;
case FFI_TYPE_SINT32:
(raw++)->sint = *(SINT32*) (*args);
break;
#endif
#if !FFI_NO_STRUCTS
case FFI_TYPE_STRUCT:
(raw++)->ptr = *args;
break;
#endif
case FFI_TYPE_POINTER:
(raw++)->ptr = **(void***) args;
break;
default:
memcpy ((void*) raw->data, (void*)*args, (*tp)->size);
raw += ALIGN ((*tp)->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
}
}
}
#if !FFI_NATIVE_RAW_API
/* This is a generic definition of ffi_raw_call, to be used if the
* native system does not provide a machine-specific implementation.
* Having this, allows code to be written for the raw API, without
* the need for system-specific code to handle input in that format;
* these following couple of functions will handle the translation forth
* and back automatically. */
void ffi_raw_call (ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *raw)
{
void **avalue = (void**) alloca (cif->nargs * sizeof (void*));
ffi_raw_to_ptrarray (cif, raw, avalue);
ffi_call (cif, fn, rvalue, avalue);
}
#if FFI_CLOSURES /* base system provides closures */
static void
ffi_translate_args (ffi_cif *cif, void *rvalue,
void **avalue, void *user_data)
{
ffi_raw *raw = (ffi_raw*)alloca (ffi_raw_size (cif));
ffi_raw_closure *cl = (ffi_raw_closure*)user_data;
ffi_ptrarray_to_raw (cif, avalue, raw);
(*cl->fun) (cif, rvalue, raw, cl->user_data);
}
ffi_status
ffi_prep_raw_closure_loc (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc)
{
ffi_status status;
status = ffi_prep_closure_loc ((ffi_closure*) cl,
cif,
&ffi_translate_args,
codeloc,
codeloc);
if (status == FFI_OK)
{
cl->fun = fun;
cl->user_data = user_data;
}
return status;
}
#endif /* FFI_CLOSURES */
#endif /* !FFI_NATIVE_RAW_API */
#if FFI_CLOSURES
/* Again, here is the generic version of ffi_prep_raw_closure, which
* will install an intermediate "hub" for translation of arguments from
* the pointer-array format, to the raw format */
ffi_status
ffi_prep_raw_closure (ffi_raw_closure* cl,
ffi_cif *cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data)
{
return ffi_prep_raw_closure_loc (cl, cif, fun, user_data, cl);
}
#endif /* FFI_CLOSURES */
#endif /* !FFI_NO_RAW_API */

View file

@ -0,0 +1,627 @@
/* -----------------------------------------------------------------------
closures.c - Copyright (c) 2007, 2009, 2010 Red Hat, Inc.
Copyright (C) 2007, 2009, 2010 Free Software Foundation, Inc
Copyright (c) 2011 Plausible Labs Cooperative, Inc.
Code to allocate and deallocate memory for closures.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#if defined __linux__ && !defined _GNU_SOURCE
#define _GNU_SOURCE 1
#endif
#include <ffi.h>
#include <ffi_common.h>
#if !FFI_MMAP_EXEC_WRIT && !FFI_EXEC_TRAMPOLINE_TABLE
# if __gnu_linux__
/* This macro indicates it may be forbidden to map anonymous memory
with both write and execute permission. Code compiled when this
option is defined will attempt to map such pages once, but if it
fails, it falls back to creating a temporary file in a writable and
executable filesystem and mapping pages from it into separate
locations in the virtual memory space, one location writable and
another executable. */
# define FFI_MMAP_EXEC_WRIT 1
# define HAVE_MNTENT 1
# endif
# if defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)
/* Windows systems may have Data Execution Protection (DEP) enabled,
which requires the use of VirtualMalloc/VirtualFree to alloc/free
executable memory. */
# define FFI_MMAP_EXEC_WRIT 1
# endif
#endif
#if FFI_MMAP_EXEC_WRIT && !defined FFI_MMAP_EXEC_SELINUX
# ifdef __linux__
/* When defined to 1 check for SELinux and if SELinux is active,
don't attempt PROT_EXEC|PROT_WRITE mapping at all, as that
might cause audit messages. */
# define FFI_MMAP_EXEC_SELINUX 1
# endif
#endif
#if FFI_CLOSURES
# if FFI_EXEC_TRAMPOLINE_TABLE
// Per-target implementation; It's unclear what can reasonable be shared
// between two OS/architecture implementations.
# elif FFI_MMAP_EXEC_WRIT /* !FFI_EXEC_TRAMPOLINE_TABLE */
#define USE_LOCKS 1
#define USE_DL_PREFIX 1
#ifdef __GNUC__
#ifndef USE_BUILTIN_FFS
#define USE_BUILTIN_FFS 1
#endif
#endif
/* We need to use mmap, not sbrk. */
#define HAVE_MORECORE 0
/* We could, in theory, support mremap, but it wouldn't buy us anything. */
#define HAVE_MREMAP 0
/* We have no use for this, so save some code and data. */
#define NO_MALLINFO 1
/* We need all allocations to be in regular segments, otherwise we
lose track of the corresponding code address. */
#define DEFAULT_MMAP_THRESHOLD MAX_SIZE_T
/* Don't allocate more than a page unless needed. */
#define DEFAULT_GRANULARITY ((size_t)malloc_getpagesize)
#if FFI_CLOSURE_TEST
/* Don't release single pages, to avoid a worst-case scenario of
continuously allocating and releasing single pages, but release
pairs of pages, which should do just as well given that allocations
are likely to be small. */
#define DEFAULT_TRIM_THRESHOLD ((size_t)malloc_getpagesize)
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <string.h>
#include <stdio.h>
#if !defined(X86_WIN32) && !defined(X86_WIN64)
#ifdef HAVE_MNTENT
#include <mntent.h>
#endif /* HAVE_MNTENT */
#include <sys/param.h>
#include <pthread.h>
/* We don't want sys/mman.h to be included after we redefine mmap and
dlmunmap. */
#include <sys/mman.h>
#define LACKS_SYS_MMAN_H 1
#if FFI_MMAP_EXEC_SELINUX
#include <sys/statfs.h>
#include <stdlib.h>
static int selinux_enabled = -1;
static int
selinux_enabled_check (void)
{
struct statfs sfs;
FILE *f;
char *buf = NULL;
size_t len = 0;
if (statfs ("/selinux", &sfs) >= 0
&& (unsigned int) sfs.f_type == 0xf97cff8cU)
return 1;
f = fopen ("/proc/mounts", "r");
if (f == NULL)
return 0;
while (getline (&buf, &len, f) >= 0)
{
char *p = strchr (buf, ' ');
if (p == NULL)
break;
p = strchr (p + 1, ' ');
if (p == NULL)
break;
if (strncmp (p + 1, "selinuxfs ", 10) == 0)
{
free (buf);
fclose (f);
return 1;
}
}
free (buf);
fclose (f);
return 0;
}
#define is_selinux_enabled() (selinux_enabled >= 0 ? selinux_enabled \
: (selinux_enabled = selinux_enabled_check ()))
#else
#define is_selinux_enabled() 0
#endif /* !FFI_MMAP_EXEC_SELINUX */
/* On PaX enable kernels that have MPROTECT enable we can't use PROT_EXEC. */
#ifdef FFI_MMAP_EXEC_EMUTRAMP_PAX
#include <stdlib.h>
static int emutramp_enabled = -1;
static int
emutramp_enabled_check (void)
{
if (getenv ("FFI_DISABLE_EMUTRAMP") == NULL)
return 1;
else
return 0;
}
#define is_emutramp_enabled() (emutramp_enabled >= 0 ? emutramp_enabled \
: (emutramp_enabled = emutramp_enabled_check ()))
#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
#elif defined (__CYGWIN__) || defined(__INTERIX)
#include <sys/mman.h>
/* Cygwin is Linux-like, but not quite that Linux-like. */
#define is_selinux_enabled() 0
#endif /* !defined(X86_WIN32) && !defined(X86_WIN64) */
#ifndef FFI_MMAP_EXEC_EMUTRAMP_PAX
#define is_emutramp_enabled() 0
#endif /* FFI_MMAP_EXEC_EMUTRAMP_PAX */
#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
/* Use these for mmap and munmap within dlmalloc.c. */
static void *dlmmap(void *, size_t, int, int, int, off_t);
static int dlmunmap(void *, size_t);
#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
#if !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX)
/* A mutex used to synchronize access to *exec* variables in this file. */
static pthread_mutex_t open_temp_exec_file_mutex = PTHREAD_MUTEX_INITIALIZER;
/* A file descriptor of a temporary file from which we'll map
executable pages. */
static int execfd = -1;
/* The amount of space already allocated from the temporary file. */
static size_t execsize = 0;
/* Open a temporary file name, and immediately unlink it. */
static int
open_temp_exec_file_name (char *name)
{
int fd = mkstemp (name);
if (fd != -1)
unlink (name);
return fd;
}
/* Open a temporary file in the named directory. */
static int
open_temp_exec_file_dir (const char *dir)
{
static const char suffix[] = "/ffiXXXXXX";
int lendir = strlen (dir);
char *tempname = __builtin_alloca (lendir + sizeof (suffix));
if (!tempname)
return -1;
memcpy (tempname, dir, lendir);
memcpy (tempname + lendir, suffix, sizeof (suffix));
return open_temp_exec_file_name (tempname);
}
/* Open a temporary file in the directory in the named environment
variable. */
static int
open_temp_exec_file_env (const char *envvar)
{
const char *value = getenv (envvar);
if (!value)
return -1;
return open_temp_exec_file_dir (value);
}
#ifdef HAVE_MNTENT
/* Open a temporary file in an executable and writable mount point
listed in the mounts file. Subsequent calls with the same mounts
keep searching for mount points in the same file. Providing NULL
as the mounts file closes the file. */
static int
open_temp_exec_file_mnt (const char *mounts)
{
static const char *last_mounts;
static FILE *last_mntent;
if (mounts != last_mounts)
{
if (last_mntent)
endmntent (last_mntent);
last_mounts = mounts;
if (mounts)
last_mntent = setmntent (mounts, "r");
else
last_mntent = NULL;
}
if (!last_mntent)
return -1;
for (;;)
{
int fd;
struct mntent mnt;
char buf[MAXPATHLEN * 3];
if (getmntent_r (last_mntent, &mnt, buf, sizeof (buf)) == NULL)
return -1;
if (hasmntopt (&mnt, "ro")
|| hasmntopt (&mnt, "noexec")
|| access (mnt.mnt_dir, W_OK))
continue;
fd = open_temp_exec_file_dir (mnt.mnt_dir);
if (fd != -1)
return fd;
}
}
#endif /* HAVE_MNTENT */
/* Instructions to look for a location to hold a temporary file that
can be mapped in for execution. */
static struct
{
int (*func)(const char *);
const char *arg;
int repeat;
} open_temp_exec_file_opts[] = {
{ open_temp_exec_file_env, "TMPDIR", 0 },
{ open_temp_exec_file_dir, "/tmp", 0 },
{ open_temp_exec_file_dir, "/var/tmp", 0 },
{ open_temp_exec_file_dir, "/dev/shm", 0 },
{ open_temp_exec_file_env, "HOME", 0 },
#ifdef HAVE_MNTENT
{ open_temp_exec_file_mnt, "/etc/mtab", 1 },
{ open_temp_exec_file_mnt, "/proc/mounts", 1 },
#endif /* HAVE_MNTENT */
};
/* Current index into open_temp_exec_file_opts. */
static int open_temp_exec_file_opts_idx = 0;
/* Reset a current multi-call func, then advances to the next entry.
If we're at the last, go back to the first and return nonzero,
otherwise return zero. */
static int
open_temp_exec_file_opts_next (void)
{
if (open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func (NULL);
open_temp_exec_file_opts_idx++;
if (open_temp_exec_file_opts_idx
== (sizeof (open_temp_exec_file_opts)
/ sizeof (*open_temp_exec_file_opts)))
{
open_temp_exec_file_opts_idx = 0;
return 1;
}
return 0;
}
/* Return a file descriptor of a temporary zero-sized file in a
writable and exexutable filesystem. */
static int
open_temp_exec_file (void)
{
int fd;
do
{
fd = open_temp_exec_file_opts[open_temp_exec_file_opts_idx].func
(open_temp_exec_file_opts[open_temp_exec_file_opts_idx].arg);
if (!open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat
|| fd == -1)
{
if (open_temp_exec_file_opts_next ())
break;
}
}
while (fd == -1);
return fd;
}
/* Map in a chunk of memory from the temporary exec file into separate
locations in the virtual memory address space, one writable and one
executable. Returns the address of the writable portion, after
storing an offset to the corresponding executable portion at the
last word of the requested chunk. */
static void *
dlmmap_locked (void *start, size_t length, int prot, int flags, off_t offset)
{
void *ptr;
if (execfd == -1)
{
open_temp_exec_file_opts_idx = 0;
retry_open:
execfd = open_temp_exec_file ();
if (execfd == -1)
return MFAIL;
}
offset = execsize;
if (ftruncate (execfd, offset + length))
return MFAIL;
flags &= ~(MAP_PRIVATE | MAP_ANONYMOUS);
flags |= MAP_SHARED;
ptr = mmap (NULL, length, (prot & ~PROT_WRITE) | PROT_EXEC,
flags, execfd, offset);
if (ptr == MFAIL)
{
if (!offset)
{
close (execfd);
goto retry_open;
}
ftruncate (execfd, offset);
return MFAIL;
}
else if (!offset
&& open_temp_exec_file_opts[open_temp_exec_file_opts_idx].repeat)
open_temp_exec_file_opts_next ();
start = mmap (start, length, prot, flags, execfd, offset);
if (start == MFAIL)
{
munmap (ptr, length);
ftruncate (execfd, offset);
return start;
}
mmap_exec_offset ((char *)start, length) = (char*)ptr - (char*)start;
execsize += length;
return start;
}
/* Map in a writable and executable chunk of memory if possible.
Failing that, fall back to dlmmap_locked. */
static void *
dlmmap (void *start, size_t length, int prot,
int flags, int fd, off_t offset)
{
void *ptr;
assert (start == NULL && length % malloc_getpagesize == 0
&& prot == (PROT_READ | PROT_WRITE)
&& flags == (MAP_PRIVATE | MAP_ANONYMOUS)
&& fd == -1 && offset == 0);
#if FFI_CLOSURE_TEST
printf ("mapping in %zi\n", length);
#endif
if (execfd == -1 && is_emutramp_enabled ())
{
ptr = mmap (start, length, prot & ~PROT_EXEC, flags, fd, offset);
return ptr;
}
if (execfd == -1 && !is_selinux_enabled ())
{
ptr = mmap (start, length, prot | PROT_EXEC, flags, fd, offset);
if (ptr != MFAIL || (errno != EPERM && errno != EACCES))
/* Cool, no need to mess with separate segments. */
return ptr;
/* If MREMAP_DUP is ever introduced and implemented, try mmap
with ((prot & ~PROT_WRITE) | PROT_EXEC) and mremap with
MREMAP_DUP and prot at this point. */
}
if (execsize == 0 || execfd == -1)
{
pthread_mutex_lock (&open_temp_exec_file_mutex);
ptr = dlmmap_locked (start, length, prot, flags, offset);
pthread_mutex_unlock (&open_temp_exec_file_mutex);
return ptr;
}
return dlmmap_locked (start, length, prot, flags, offset);
}
/* Release memory at the given address, as well as the corresponding
executable page if it's separate. */
static int
dlmunmap (void *start, size_t length)
{
/* We don't bother decreasing execsize or truncating the file, since
we can't quite tell whether we're unmapping the end of the file.
We don't expect frequent deallocation anyway. If we did, we
could locate pages in the file by writing to the pages being
deallocated and checking that the file contents change.
Yuck. */
msegmentptr seg = segment_holding (gm, start);
void *code;
#if FFI_CLOSURE_TEST
printf ("unmapping %zi\n", length);
#endif
if (seg && (code = add_segment_exec_offset (start, seg)) != start)
{
int ret = munmap (code, length);
if (ret)
return ret;
}
return munmap (start, length);
}
#if FFI_CLOSURE_FREE_CODE
/* Return segment holding given code address. */
static msegmentptr
segment_holding_code (mstate m, char* addr)
{
msegmentptr sp = &m->seg;
for (;;) {
if (addr >= add_segment_exec_offset (sp->base, sp)
&& addr < add_segment_exec_offset (sp->base, sp) + sp->size)
return sp;
if ((sp = sp->next) == 0)
return 0;
}
}
#endif
#endif /* !(defined(X86_WIN32) || defined(X86_WIN64) || defined(__OS2__)) || defined (__CYGWIN__) || defined(__INTERIX) */
/* Allocate a chunk of memory with the given size. Returns a pointer
to the writable address, and sets *CODE to the executable
corresponding virtual address. */
void *
ffi_closure_alloc (size_t size, void **code)
{
*code = malloc(size);
return *code;
#if 0
void *ptr;
if (!code)
return NULL;
ptr = dlmalloc (size);
if (ptr)
{
msegmentptr seg = segment_holding (gm, ptr);
*code = add_segment_exec_offset (ptr, seg);
}
return ptr;
#endif
}
/* Release a chunk of memory allocated with ffi_closure_alloc. If
FFI_CLOSURE_FREE_CODE is nonzero, the given address can be the
writable or the executable address given. Otherwise, only the
writable address can be provided here. */
void
ffi_closure_free (void *ptr)
{
#if 0
#if FFI_CLOSURE_FREE_CODE
msegmentptr seg = segment_holding_code(gm, ptr);
if (seg)
ptr = sub_segment_exec_offset(ptr, seg);
#endif
dlfree(ptr);
#endif
free(ptr);
}
#if FFI_CLOSURE_TEST
/* Do some internal sanity testing to make sure allocation and
deallocation of pages are working as intended. */
int main ()
{
void *p[3];
#define GET(idx, len) do { p[idx] = dlmalloc (len); printf ("allocated %zi for p[%i]\n", (len), (idx)); } while (0)
#define PUT(idx) do { printf ("freeing p[%i]\n", (idx)); dlfree (p[idx]); } while (0)
GET (0, malloc_getpagesize / 2);
GET (1, 2 * malloc_getpagesize - 64 * sizeof (void*));
PUT (1);
GET (1, 2 * malloc_getpagesize);
GET (2, malloc_getpagesize / 2);
PUT (1);
PUT (0);
PUT (2);
return 0;
}
#endif /* FFI_CLOSURE_TEST */
# else /* ! FFI_MMAP_EXEC_WRIT */
/* On many systems, memory returned by malloc is writable and
executable, so just use it. */
#include <stdlib.h>
void *
ffi_closure_alloc (size_t size, void **code)
{
if (!code)
return NULL;
return *code = malloc (size);
}
void
ffi_closure_free (void *ptr)
{
free (ptr);
}
# endif /* ! FFI_MMAP_EXEC_WRIT */
#endif /* FFI_CLOSURES */

View file

@ -0,0 +1,841 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996, 1998, 1999, 2001, 2007, 2008 Red Hat, Inc.
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2002 Bo Thorsen
Copyright (c) 2002 Roger Sayle
Copyright (C) 2008, 2010 Free Software Foundation, Inc.
x86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#if !defined(__x86_64__) || defined(_WIN64)
#ifdef _WIN64
#include <windows.h>
#endif
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
void ffi_prep_args(char *stack, extended_cif *ecif)
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
#ifdef X86_WIN32
size_t p_stack_args[2];
void *p_stack_data[2];
char *argp2 = stack;
int stack_args_count = 0;
int cabi = ecif->cif->abi;
#endif
argp = stack;
if ((ecif->cif->flags == FFI_TYPE_STRUCT
|| ecif->cif->flags == FFI_TYPE_MS_STRUCT)
#ifdef X86_WIN64
&& (ecif->cif->rtype->size != 1 && ecif->cif->rtype->size != 2
&& ecif->cif->rtype->size != 4 && ecif->cif->rtype->size != 8)
#endif
)
{
*(void **) argp = ecif->rvalue;
#ifdef X86_WIN32
/* For fastcall/thiscall this is first register-passed
argument. */
if (cabi == FFI_THISCALL || cabi == FFI_FASTCALL)
{
p_stack_args[stack_args_count] = sizeof (void*);
p_stack_data[stack_args_count] = argp;
++stack_args_count;
}
#endif
argp += sizeof(void*);
}
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
i != 0;
i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(void*) - 1) & (size_t) argp)
argp = (char *) ALIGN(argp, sizeof(void*));
z = (*p_arg)->size;
#ifdef X86_WIN64
if (z > sizeof(ffi_arg)
|| ((*p_arg)->type == FFI_TYPE_STRUCT
&& (z != 1 && z != 2 && z != 4 && z != 8))
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
|| ((*p_arg)->type == FFI_TYPE_LONGDOUBLE)
#endif
)
{
z = sizeof(ffi_arg);
*(void **)argp = *p_argv;
}
else if ((*p_arg)->type == FFI_TYPE_FLOAT)
{
memcpy(argp, *p_argv, z);
}
else
#endif
if (z < sizeof(ffi_arg))
{
z = sizeof(ffi_arg);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(ffi_sarg *) argp = (ffi_sarg)*(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(ffi_arg *) argp = (ffi_arg)*(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(ffi_sarg *) argp = (ffi_sarg)*(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(ffi_arg *) argp = (ffi_arg)*(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
*(ffi_sarg *) argp = (ffi_sarg)*(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(ffi_arg *) argp = (ffi_arg)*(UINT32 *)(* p_argv);
break;
case FFI_TYPE_STRUCT:
*(ffi_arg *) argp = *(ffi_arg *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
}
else
{
memcpy(argp, *p_argv, z);
}
#ifdef X86_WIN32
/* For thiscall/fastcall convention register-passed arguments
are the first two none-floating-point arguments with a size
smaller or equal to sizeof (void*). */
if ((cabi == FFI_THISCALL && stack_args_count < 1)
|| (cabi == FFI_FASTCALL && stack_args_count < 2))
{
if (z <= 4
&& ((*p_arg)->type != FFI_TYPE_FLOAT
&& (*p_arg)->type != FFI_TYPE_STRUCT))
{
p_stack_args[stack_args_count] = z;
p_stack_data[stack_args_count] = argp;
++stack_args_count;
}
}
#endif
p_argv++;
#ifdef X86_WIN64
argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
#else
argp += z;
#endif
}
#ifdef X86_WIN32
/* We need to move the register-passed arguments for thiscall/fastcall
on top of stack, so that those can be moved to registers ecx/edx by
call-handler. */
if (stack_args_count > 0)
{
size_t zz = (p_stack_args[0] + 3) & ~3;
char *h;
/* Move first argument to top-stack position. */
if (p_stack_data[0] != argp2)
{
h = alloca (zz + 1);
memcpy (h, p_stack_data[0], zz);
memmove (argp2 + zz, argp2,
(size_t) ((char *) p_stack_data[0] - (char*)argp2));
memcpy (argp2, h, zz);
}
argp2 += zz;
--stack_args_count;
if (zz > 4)
stack_args_count = 0;
/* If we have a second argument, then move it on top
after the first one. */
if (stack_args_count > 0 && p_stack_data[1] != argp2)
{
zz = p_stack_args[1];
zz = (zz + 3) & ~3;
h = alloca (zz + 1);
h = alloca (zz + 1);
memcpy (h, p_stack_data[1], zz);
memmove (argp2 + zz, argp2, (size_t) ((char*) p_stack_data[1] - (char*)argp2));
memcpy (argp2, h, zz);
}
}
#endif
return;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
unsigned int i;
ffi_type **ptr;
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_UINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT8:
case FFI_TYPE_SINT16:
#ifdef X86_WIN64
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
#endif
case FFI_TYPE_SINT64:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
#ifndef X86_WIN64
#if FFI_TYPE_DOUBLE != FFI_TYPE_LONGDOUBLE
case FFI_TYPE_LONGDOUBLE:
#endif
#endif
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_UINT64:
#ifdef X86_WIN64
case FFI_TYPE_POINTER:
#endif
cif->flags = FFI_TYPE_SINT64;
break;
case FFI_TYPE_STRUCT:
#ifndef X86
if (cif->rtype->size == 1)
{
cif->flags = FFI_TYPE_SMALL_STRUCT_1B; /* same as char size */
}
else if (cif->rtype->size == 2)
{
cif->flags = FFI_TYPE_SMALL_STRUCT_2B; /* same as short size */
}
else if (cif->rtype->size == 4)
{
#ifdef X86_WIN64
cif->flags = FFI_TYPE_SMALL_STRUCT_4B;
#else
cif->flags = FFI_TYPE_INT; /* same as int type */
#endif
}
else if (cif->rtype->size == 8)
{
cif->flags = FFI_TYPE_SINT64; /* same as int64 type */
}
else
#endif
{
#ifdef X86_WIN32
if (cif->abi == FFI_MS_CDECL)
cif->flags = FFI_TYPE_MS_STRUCT;
else
#endif
cif->flags = FFI_TYPE_STRUCT;
/* allocate space for return value pointer */
cif->bytes += ALIGN(sizeof(void*), FFI_SIZEOF_ARG);
}
break;
default:
#ifdef X86_WIN64
cif->flags = FFI_TYPE_SINT64;
break;
case FFI_TYPE_INT:
cif->flags = FFI_TYPE_SINT32;
#else
cif->flags = FFI_TYPE_INT;
#endif
break;
}
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
if (((*ptr)->alignment - 1) & cif->bytes)
cif->bytes = ALIGN(cif->bytes, (*ptr)->alignment);
cif->bytes += ALIGN((*ptr)->size, FFI_SIZEOF_ARG);
}
#ifdef X86_WIN64
/* ensure space for storing four registers */
cif->bytes += 4 * sizeof(ffi_arg);
#endif
cif->bytes = (cif->bytes + 15) & ~0xF;
return FFI_OK;
}
#ifdef X86_WIN64
extern int
ffi_call_win64(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)(void));
#elif defined(X86_WIN32)
extern void
ffi_call_win32(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned, unsigned *, void (*fn)(void));
#else
extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
unsigned, unsigned, unsigned *, void (*fn)(void));
#endif
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
extended_cif ecif;
ecif.cif = cif;
ecif.avalue = avalue;
/* If the return value is a struct and we don't have a return */
/* value address then we need to make one */
#ifdef X86_WIN64
if (rvalue == NULL
&& cif->flags == FFI_TYPE_STRUCT
&& cif->rtype->size != 1 && cif->rtype->size != 2
&& cif->rtype->size != 4 && cif->rtype->size != 8)
{
ecif.rvalue = alloca((cif->rtype->size + 0xF) & ~0xF);
}
#else
if (rvalue == NULL
&& (cif->flags == FFI_TYPE_STRUCT
|| cif->flags == FFI_TYPE_MS_STRUCT))
{
ecif.rvalue = alloca(cif->rtype->size);
}
#endif
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
#ifdef X86_WIN64
case FFI_WIN64:
ffi_call_win64(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
#elif defined(X86_WIN32)
case FFI_SYSV:
case FFI_STDCALL:
case FFI_MS_CDECL:
ffi_call_win32(ffi_prep_args, &ecif, cif->abi, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
case FFI_THISCALL:
case FFI_FASTCALL:
{
unsigned int abi = cif->abi;
unsigned int i, passed_regs = 0;
if (cif->flags == FFI_TYPE_STRUCT)
++passed_regs;
for (i=0; i < cif->nargs && passed_regs < 2;i++)
{
size_t sz;
if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
|| cif->arg_types[i]->type == FFI_TYPE_STRUCT)
continue;
sz = (cif->arg_types[i]->size + 3) & ~3;
if (sz == 0 || sz > 4)
continue;
++passed_regs;
}
if (passed_regs < 2 && abi == FFI_FASTCALL)
abi = FFI_THISCALL;
if (passed_regs < 1 && abi == FFI_THISCALL)
abi = FFI_STDCALL;
ffi_call_win32(ffi_prep_args, &ecif, abi, cif->bytes, cif->flags,
ecif.rvalue, fn);
}
break;
#else
case FFI_SYSV:
ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, ecif.rvalue,
fn);
break;
#endif
default:
FFI_ASSERT(0);
break;
}
}
/** private members **/
/* The following __attribute__((regparm(1))) decorations will have no effect
on MSVC or SUNPRO_C -- standard conventions apply. */
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
void** args, ffi_cif* cif);
void FFI_HIDDEN ffi_closure_SYSV (ffi_closure *)
__attribute__ ((regparm(1)));
unsigned int FFI_HIDDEN ffi_closure_SYSV_inner (ffi_closure *, void **, void *)
__attribute__ ((regparm(1)));
void FFI_HIDDEN ffi_closure_raw_SYSV (ffi_raw_closure *)
__attribute__ ((regparm(1)));
#ifdef X86_WIN32
void FFI_HIDDEN ffi_closure_raw_THISCALL (ffi_raw_closure *)
__attribute__ ((regparm(1)));
void FFI_HIDDEN ffi_closure_STDCALL (ffi_closure *)
__attribute__ ((regparm(1)));
void FFI_HIDDEN ffi_closure_THISCALL (ffi_closure *)
__attribute__ ((regparm(1)));
#endif
#ifdef X86_WIN64
void FFI_HIDDEN ffi_closure_win64 (ffi_closure *);
#endif
/* This function is jumped to by the trampoline */
#ifdef X86_WIN64
void * FFI_HIDDEN
ffi_closure_win64_inner (ffi_closure *closure, void *args) {
ffi_cif *cif;
void **arg_area;
void *result;
void *resp = &result;
cif = closure->cif;
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
/* this call will initialize ARG_AREA, such that each
* element in that array points to the corresponding
* value on the stack; and if the function returns
* a structure, it will change RESP to point to the
* structure return address. */
ffi_prep_incoming_args_SYSV(args, &resp, arg_area, cif);
(closure->fun) (cif, resp, arg_area, closure->user_data);
/* The result is returned in rax. This does the right thing for
result types except for floats; we have to 'mov xmm0, rax' in the
caller to correct this.
TODO: structure sizes of 3 5 6 7 are returned by reference, too!!!
*/
return cif->rtype->size > sizeof(void *) ? resp : *(void **)resp;
}
#else
unsigned int FFI_HIDDEN __attribute__ ((regparm(1)))
ffi_closure_SYSV_inner (ffi_closure *closure, void **respp, void *args)
{
/* our various things... */
ffi_cif *cif;
void **arg_area;
cif = closure->cif;
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
/* this call will initialize ARG_AREA, such that each
* element in that array points to the corresponding
* value on the stack; and if the function returns
* a structure, it will change RESP to point to the
* structure return address. */
ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
(closure->fun) (cif, *respp, arg_area, closure->user_data);
return cif->flags;
}
#endif /* !X86_WIN64 */
static void
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue, void **avalue,
ffi_cif *cif)
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
#ifdef X86_WIN64
if (cif->rtype->size > sizeof(ffi_arg)
|| (cif->flags == FFI_TYPE_STRUCT
&& (cif->rtype->size != 1 && cif->rtype->size != 2
&& cif->rtype->size != 4 && cif->rtype->size != 8))) {
*rvalue = *(void **) argp;
argp += sizeof(void *);
}
#else
if ( cif->flags == FFI_TYPE_STRUCT
|| cif->flags == FFI_TYPE_MS_STRUCT ) {
*rvalue = *(void **) argp;
argp += sizeof(void *);
}
#endif
p_argv = avalue;
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(void*) - 1) & (size_t) argp) {
argp = (char *) ALIGN(argp, sizeof(void*));
}
#ifdef X86_WIN64
if ((*p_arg)->size > sizeof(ffi_arg)
|| ((*p_arg)->type == FFI_TYPE_STRUCT
&& ((*p_arg)->size != 1 && (*p_arg)->size != 2
&& (*p_arg)->size != 4 && (*p_arg)->size != 8)))
{
z = sizeof(void *);
*p_argv = *(void **)argp;
}
else
#endif
{
z = (*p_arg)->size;
/* because we're little endian, this is what it turns into. */
*p_argv = (void*) argp;
}
p_argv++;
#ifdef X86_WIN64
argp += (z + sizeof(void*) - 1) & ~(sizeof(void*) - 1);
#else
argp += z;
#endif
}
return;
}
#define FFI_INIT_TRAMPOLINE_WIN64(TRAMP,FUN,CTX,MASK) \
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
void* __fun = (void*)(FUN); \
void* __ctx = (void*)(CTX); \
*(unsigned char*) &__tramp[0] = 0x41; \
*(unsigned char*) &__tramp[1] = 0xbb; \
*(unsigned int*) &__tramp[2] = MASK; /* mov $mask, %r11 */ \
*(unsigned char*) &__tramp[6] = 0x48; \
*(unsigned char*) &__tramp[7] = 0xb8; \
*(void**) &__tramp[8] = __ctx; /* mov __ctx, %rax */ \
*(unsigned char *) &__tramp[16] = 0x49; \
*(unsigned char *) &__tramp[17] = 0xba; \
*(void**) &__tramp[18] = __fun; /* mov __fun, %r10 */ \
*(unsigned char *) &__tramp[26] = 0x41; \
*(unsigned char *) &__tramp[27] = 0xff; \
*(unsigned char *) &__tramp[28] = 0xe2; /* jmp %r10 */ \
}
/* How to make a trampoline. Derived from gcc/config/i386/i386.c. */
#define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
unsigned int __fun = (unsigned int)(FUN); \
unsigned int __ctx = (unsigned int)(CTX); \
unsigned int __dis = __fun - (__ctx + 10); \
*(unsigned char*) &__tramp[0] = 0xb8; \
*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
*(unsigned char *) &__tramp[5] = 0xe9; \
*(unsigned int*) &__tramp[6] = __dis; /* jmp __fun */ \
}
#define FFI_INIT_TRAMPOLINE_THISCALL(TRAMP,FUN,CTX,SIZE) \
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
unsigned int __fun = (unsigned int)(FUN); \
unsigned int __ctx = (unsigned int)(CTX); \
unsigned int __dis = __fun - (__ctx + 49); \
unsigned short __size = (unsigned short)(SIZE); \
*(unsigned int *) &__tramp[0] = 0x8324048b; /* mov (%esp), %eax */ \
*(unsigned int *) &__tramp[4] = 0x4c890cec; /* sub $12, %esp */ \
*(unsigned int *) &__tramp[8] = 0x04890424; /* mov %ecx, 4(%esp) */ \
*(unsigned char*) &__tramp[12] = 0x24; /* mov %eax, (%esp) */ \
*(unsigned char*) &__tramp[13] = 0xb8; \
*(unsigned int *) &__tramp[14] = __size; /* mov __size, %eax */ \
*(unsigned int *) &__tramp[18] = 0x08244c8d; /* lea 8(%esp), %ecx */ \
*(unsigned int *) &__tramp[22] = 0x4802e8c1; /* shr $2, %eax ; dec %eax */ \
*(unsigned short*) &__tramp[26] = 0x0b74; /* jz 1f */ \
*(unsigned int *) &__tramp[28] = 0x8908518b; /* 2b: mov 8(%ecx), %edx */ \
*(unsigned int *) &__tramp[32] = 0x04c18311; /* mov %edx, (%ecx) ; add $4, %ecx */ \
*(unsigned char*) &__tramp[36] = 0x48; /* dec %eax */ \
*(unsigned short*) &__tramp[37] = 0xf575; /* jnz 2b ; 1f: */ \
*(unsigned char*) &__tramp[39] = 0xb8; \
*(unsigned int*) &__tramp[40] = __ctx; /* movl __ctx, %eax */ \
*(unsigned char *) &__tramp[44] = 0xe8; \
*(unsigned int*) &__tramp[45] = __dis; /* call __fun */ \
*(unsigned char*) &__tramp[49] = 0xc2; /* ret */ \
*(unsigned short*) &__tramp[50] = (__size + 8); /* ret (__size + 8) */ \
}
#define FFI_INIT_TRAMPOLINE_STDCALL(TRAMP,FUN,CTX,SIZE) \
{ unsigned char *__tramp = (unsigned char*)(TRAMP); \
unsigned int __fun = (unsigned int)(FUN); \
unsigned int __ctx = (unsigned int)(CTX); \
unsigned int __dis = __fun - (__ctx + 10); \
unsigned short __size = (unsigned short)(SIZE); \
*(unsigned char*) &__tramp[0] = 0xb8; \
*(unsigned int*) &__tramp[1] = __ctx; /* movl __ctx, %eax */ \
*(unsigned char *) &__tramp[5] = 0xe8; \
*(unsigned int*) &__tramp[6] = __dis; /* call __fun */ \
*(unsigned char *) &__tramp[10] = 0xc2; \
*(unsigned short*) &__tramp[11] = __size; /* ret __size */ \
}
/* the cif must already be prep'ed */
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc)
{
#ifdef X86_WIN64
#define ISFLOAT(IDX) (cif->arg_types[IDX]->type == FFI_TYPE_FLOAT || cif->arg_types[IDX]->type == FFI_TYPE_DOUBLE)
#define FLAG(IDX) (cif->nargs>(IDX)&&ISFLOAT(IDX)?(1<<(IDX)):0)
if (cif->abi == FFI_WIN64)
{
int mask = FLAG(0)|FLAG(1)|FLAG(2)|FLAG(3);
FFI_INIT_TRAMPOLINE_WIN64 (&closure->tramp[0],
&ffi_closure_win64,
codeloc, mask);
/* make sure we can execute here */
}
#else
if (cif->abi == FFI_SYSV)
{
FFI_INIT_TRAMPOLINE (&closure->tramp[0],
&ffi_closure_SYSV,
(void*)codeloc);
}
#ifdef X86_WIN32
else if (cif->abi == FFI_THISCALL)
{
FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0],
&ffi_closure_THISCALL,
(void*)codeloc,
cif->bytes);
}
else if (cif->abi == FFI_STDCALL)
{
FFI_INIT_TRAMPOLINE_STDCALL (&closure->tramp[0],
&ffi_closure_STDCALL,
(void*)codeloc, cif->bytes);
}
else if (cif->abi == FFI_MS_CDECL)
{
FFI_INIT_TRAMPOLINE (&closure->tramp[0],
&ffi_closure_SYSV,
(void*)codeloc);
}
#endif /* X86_WIN32 */
#endif /* !X86_WIN64 */
else
{
return FFI_BAD_ABI;
}
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}
/* ------- Native raw API support -------------------------------- */
#if !FFI_NO_RAW_API
ffi_status
ffi_prep_raw_closure_loc (ffi_raw_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,ffi_raw*,void*),
void *user_data,
void *codeloc)
{
int i;
if (cif->abi != FFI_SYSV) {
#ifdef X86_WIN32
if (cif->abi != FFI_THISCALL)
#endif
return FFI_BAD_ABI;
}
/* we currently don't support certain kinds of arguments for raw
closures. This should be implemented by a separate assembly
language routine, since it would require argument processing,
something we don't do now for performance. */
for (i = cif->nargs-1; i >= 0; i--)
{
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_STRUCT);
FFI_ASSERT (cif->arg_types[i]->type != FFI_TYPE_LONGDOUBLE);
}
#ifdef X86_WIN32
if (cif->abi == FFI_SYSV)
{
#endif
FFI_INIT_TRAMPOLINE (&closure->tramp[0], &ffi_closure_raw_SYSV,
codeloc);
#ifdef X86_WIN32
}
else if (cif->abi == FFI_THISCALL)
{
FFI_INIT_TRAMPOLINE_THISCALL (&closure->tramp[0], &ffi_closure_raw_THISCALL,
codeloc, cif->bytes);
}
#endif
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}
static void
ffi_prep_args_raw(char *stack, extended_cif *ecif)
{
memcpy (stack, ecif->avalue, ecif->cif->bytes);
}
/* we borrow this routine from libffi (it must be changed, though, to
* actually call the function passed in the first argument. as of
* libffi-1.20, this is not the case.)
*/
void
ffi_raw_call(ffi_cif *cif, void (*fn)(void), void *rvalue, ffi_raw *fake_avalue)
{
extended_cif ecif;
void **avalue = (void **)fake_avalue;
ecif.cif = cif;
ecif.avalue = avalue;
/* If the return value is a struct and we don't have a return */
/* value address then we need to make one */
if (rvalue == NULL
&& (cif->flags == FFI_TYPE_STRUCT
|| cif->flags == FFI_TYPE_MS_STRUCT))
{
ecif.rvalue = alloca(cif->rtype->size);
}
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
#ifdef X86_WIN32
case FFI_SYSV:
case FFI_STDCALL:
case FFI_MS_CDECL:
ffi_call_win32(ffi_prep_args_raw, &ecif, cif->abi, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
case FFI_THISCALL:
case FFI_FASTCALL:
{
unsigned int abi = cif->abi;
unsigned int i, passed_regs = 0;
if (cif->flags == FFI_TYPE_STRUCT)
++passed_regs;
for (i=0; i < cif->nargs && passed_regs < 2;i++)
{
size_t sz;
if (cif->arg_types[i]->type == FFI_TYPE_FLOAT
|| cif->arg_types[i]->type == FFI_TYPE_STRUCT)
continue;
sz = (cif->arg_types[i]->size + 3) & ~3;
if (sz == 0 || sz > 4)
continue;
++passed_regs;
}
if (passed_regs < 2 && abi == FFI_FASTCALL)
cif->abi = abi = FFI_THISCALL;
if (passed_regs < 1 && abi == FFI_THISCALL)
cif->abi = abi = FFI_STDCALL;
ffi_call_win32(ffi_prep_args_raw, &ecif, abi, cif->bytes, cif->flags,
ecif.rvalue, fn);
}
break;
#else
case FFI_SYSV:
ffi_call_SYSV(ffi_prep_args_raw, &ecif, cif->bytes, cif->flags,
ecif.rvalue, fn);
break;
#endif
default:
FFI_ASSERT(0);
break;
}
}
#endif
#endif /* !__x86_64__ || X86_WIN64 */

View file

@ -0,0 +1,673 @@
/* -----------------------------------------------------------------------
ffi64.c - Copyright (c) 2013 The Written Word, Inc.
Copyright (c) 2011 Anthony Green
Copyright (c) 2008, 2010 Red Hat, Inc.
Copyright (c) 2002, 2007 Bo Thorsen <bo@suse.de>
x86-64 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
#include <stdarg.h>
#ifdef __x86_64__
#define MAX_GPR_REGS 6
#define MAX_SSE_REGS 8
#if defined(__INTEL_COMPILER)
#define UINT128 __m128
#else
#if defined(__SUNPRO_C)
#include <sunmedia_types.h>
#define UINT128 __m128i
#else
#define UINT128 __int128_t
#endif
#endif
union big_int_union
{
UINT32 i32;
UINT64 i64;
UINT128 i128;
};
struct register_args
{
/* Registers for argument passing. */
UINT64 gpr[MAX_GPR_REGS];
union big_int_union sse[MAX_SSE_REGS];
};
extern void ffi_call_unix64 (void *args, unsigned long bytes, unsigned flags,
void *raddr, void (*fnaddr)(void), unsigned ssecount);
/* All reference to register classes here is identical to the code in
gcc/config/i386/i386.c. Do *not* change one without the other. */
/* Register class used for passing given 64bit part of the argument.
These represent classes as documented by the PS ABI, with the
exception of SSESF, SSEDF classes, that are basically SSE class,
just gcc will use SF or DFmode move instead of DImode to avoid
reformatting penalties.
Similary we play games with INTEGERSI_CLASS to use cheaper SImode moves
whenever possible (upper half does contain padding). */
enum x86_64_reg_class
{
X86_64_NO_CLASS,
X86_64_INTEGER_CLASS,
X86_64_INTEGERSI_CLASS,
X86_64_SSE_CLASS,
X86_64_SSESF_CLASS,
X86_64_SSEDF_CLASS,
X86_64_SSEUP_CLASS,
X86_64_X87_CLASS,
X86_64_X87UP_CLASS,
X86_64_COMPLEX_X87_CLASS,
X86_64_MEMORY_CLASS
};
#define MAX_CLASSES 4
#define SSE_CLASS_P(X) ((X) >= X86_64_SSE_CLASS && X <= X86_64_SSEUP_CLASS)
/* x86-64 register passing implementation. See x86-64 ABI for details. Goal
of this code is to classify each 8bytes of incoming argument by the register
class and assign registers accordingly. */
/* Return the union class of CLASS1 and CLASS2.
See the x86-64 PS ABI for details. */
static enum x86_64_reg_class
merge_classes (enum x86_64_reg_class class1, enum x86_64_reg_class class2)
{
/* Rule #1: If both classes are equal, this is the resulting class. */
if (class1 == class2)
return class1;
/* Rule #2: If one of the classes is NO_CLASS, the resulting class is
the other class. */
if (class1 == X86_64_NO_CLASS)
return class2;
if (class2 == X86_64_NO_CLASS)
return class1;
/* Rule #3: If one of the classes is MEMORY, the result is MEMORY. */
if (class1 == X86_64_MEMORY_CLASS || class2 == X86_64_MEMORY_CLASS)
return X86_64_MEMORY_CLASS;
/* Rule #4: If one of the classes is INTEGER, the result is INTEGER. */
if ((class1 == X86_64_INTEGERSI_CLASS && class2 == X86_64_SSESF_CLASS)
|| (class2 == X86_64_INTEGERSI_CLASS && class1 == X86_64_SSESF_CLASS))
return X86_64_INTEGERSI_CLASS;
if (class1 == X86_64_INTEGER_CLASS || class1 == X86_64_INTEGERSI_CLASS
|| class2 == X86_64_INTEGER_CLASS || class2 == X86_64_INTEGERSI_CLASS)
return X86_64_INTEGER_CLASS;
/* Rule #5: If one of the classes is X87, X87UP, or COMPLEX_X87 class,
MEMORY is used. */
if (class1 == X86_64_X87_CLASS
|| class1 == X86_64_X87UP_CLASS
|| class1 == X86_64_COMPLEX_X87_CLASS
|| class2 == X86_64_X87_CLASS
|| class2 == X86_64_X87UP_CLASS
|| class2 == X86_64_COMPLEX_X87_CLASS)
return X86_64_MEMORY_CLASS;
/* Rule #6: Otherwise class SSE is used. */
return X86_64_SSE_CLASS;
}
/* Classify the argument of type TYPE and mode MODE.
CLASSES will be filled by the register class used to pass each word
of the operand. The number of words is returned. In case the parameter
should be passed in memory, 0 is returned. As a special case for zero
sized containers, classes[0] will be NO_CLASS and 1 is returned.
See the x86-64 PS ABI for details.
*/
static int
classify_argument (ffi_type *type, enum x86_64_reg_class classes[],
size_t byte_offset)
{
switch (type->type)
{
case FFI_TYPE_UINT8:
case FFI_TYPE_SINT8:
case FFI_TYPE_UINT16:
case FFI_TYPE_SINT16:
case FFI_TYPE_UINT32:
case FFI_TYPE_SINT32:
case FFI_TYPE_UINT64:
case FFI_TYPE_SINT64:
case FFI_TYPE_POINTER:
{
int size = byte_offset + type->size;
if (size <= 4)
{
classes[0] = X86_64_INTEGERSI_CLASS;
return 1;
}
else if (size <= 8)
{
classes[0] = X86_64_INTEGER_CLASS;
return 1;
}
else if (size <= 12)
{
classes[0] = X86_64_INTEGER_CLASS;
classes[1] = X86_64_INTEGERSI_CLASS;
return 2;
}
else if (size <= 16)
{
classes[0] = classes[1] = X86_64_INTEGERSI_CLASS;
return 2;
}
else
FFI_ASSERT (0);
}
case FFI_TYPE_FLOAT:
if (!(byte_offset % 8))
classes[0] = X86_64_SSESF_CLASS;
else
classes[0] = X86_64_SSE_CLASS;
return 1;
case FFI_TYPE_DOUBLE:
classes[0] = X86_64_SSEDF_CLASS;
return 1;
case FFI_TYPE_LONGDOUBLE:
classes[0] = X86_64_X87_CLASS;
classes[1] = X86_64_X87UP_CLASS;
return 2;
case FFI_TYPE_STRUCT:
{
const int UNITS_PER_WORD = 8;
int words = (type->size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
ffi_type **ptr;
int i;
enum x86_64_reg_class subclasses[MAX_CLASSES];
/* If the struct is larger than 32 bytes, pass it on the stack. */
if (type->size > 32)
return 0;
for (i = 0; i < words; i++)
classes[i] = X86_64_NO_CLASS;
/* Zero sized arrays or structures are NO_CLASS. We return 0 to
signalize memory class, so handle it as special case. */
if (!words)
{
classes[0] = X86_64_NO_CLASS;
return 1;
}
/* Merge the fields of structure. */
for (ptr = type->elements; *ptr != NULL; ptr++)
{
int num;
byte_offset = ALIGN (byte_offset, (*ptr)->alignment);
num = classify_argument (*ptr, subclasses, byte_offset % 8);
if (num == 0)
return 0;
for (i = 0; i < num; i++)
{
int pos = byte_offset / 8;
classes[i + pos] =
merge_classes (subclasses[i], classes[i + pos]);
}
byte_offset += (*ptr)->size;
}
if (words > 2)
{
/* When size > 16 bytes, if the first one isn't
X86_64_SSE_CLASS or any other ones aren't
X86_64_SSEUP_CLASS, everything should be passed in
memory. */
if (classes[0] != X86_64_SSE_CLASS)
return 0;
for (i = 1; i < words; i++)
if (classes[i] != X86_64_SSEUP_CLASS)
return 0;
}
/* Final merger cleanup. */
for (i = 0; i < words; i++)
{
/* If one class is MEMORY, everything should be passed in
memory. */
if (classes[i] == X86_64_MEMORY_CLASS)
return 0;
/* The X86_64_SSEUP_CLASS should be always preceded by
X86_64_SSE_CLASS or X86_64_SSEUP_CLASS. */
if (classes[i] == X86_64_SSEUP_CLASS
&& classes[i - 1] != X86_64_SSE_CLASS
&& classes[i - 1] != X86_64_SSEUP_CLASS)
{
/* The first one should never be X86_64_SSEUP_CLASS. */
FFI_ASSERT (i != 0);
classes[i] = X86_64_SSE_CLASS;
}
/* If X86_64_X87UP_CLASS isn't preceded by X86_64_X87_CLASS,
everything should be passed in memory. */
if (classes[i] == X86_64_X87UP_CLASS
&& (classes[i - 1] != X86_64_X87_CLASS))
{
/* The first one should never be X86_64_X87UP_CLASS. */
FFI_ASSERT (i != 0);
return 0;
}
}
return words;
}
default:
FFI_ASSERT(0);
}
return 0; /* Never reached. */
}
/* Examine the argument and return set number of register required in each
class. Return zero iff parameter should be passed in memory, otherwise
the number of registers. */
static int
examine_argument (ffi_type *type, enum x86_64_reg_class classes[MAX_CLASSES],
_Bool in_return, int *pngpr, int *pnsse)
{
int i, n, ngpr, nsse;
n = classify_argument (type, classes, 0);
if (n == 0)
return 0;
ngpr = nsse = 0;
for (i = 0; i < n; ++i)
switch (classes[i])
{
case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS:
ngpr++;
break;
case X86_64_SSE_CLASS:
case X86_64_SSESF_CLASS:
case X86_64_SSEDF_CLASS:
nsse++;
break;
case X86_64_NO_CLASS:
case X86_64_SSEUP_CLASS:
break;
case X86_64_X87_CLASS:
case X86_64_X87UP_CLASS:
case X86_64_COMPLEX_X87_CLASS:
return in_return != 0;
default:
abort ();
}
*pngpr = ngpr;
*pnsse = nsse;
return n;
}
/* Perform machine dependent cif processing. */
ffi_status
ffi_prep_cif_machdep (ffi_cif *cif)
{
int gprcount, ssecount, i, avn, n, ngpr, nsse, flags;
enum x86_64_reg_class classes[MAX_CLASSES];
size_t bytes;
gprcount = ssecount = 0;
flags = cif->rtype->type;
if (flags != FFI_TYPE_VOID)
{
n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
if (n == 0)
{
/* The return value is passed in memory. A pointer to that
memory is the first argument. Allocate a register for it. */
gprcount++;
/* We don't have to do anything in asm for the return. */
flags = FFI_TYPE_VOID;
}
else if (flags == FFI_TYPE_STRUCT)
{
/* Mark which registers the result appears in. */
_Bool sse0 = SSE_CLASS_P (classes[0]);
_Bool sse1 = n == 2 && SSE_CLASS_P (classes[1]);
if (sse0 && !sse1)
flags |= 1 << 8;
else if (!sse0 && sse1)
flags |= 1 << 9;
else if (sse0 && sse1)
flags |= 1 << 10;
/* Mark the true size of the structure. */
flags |= cif->rtype->size << 12;
}
}
/* Go over all arguments and determine the way they should be passed.
If it's in a register and there is space for it, let that be so. If
not, add it's size to the stack byte count. */
for (bytes = 0, i = 0, avn = cif->nargs; i < avn; i++)
{
if (examine_argument (cif->arg_types[i], classes, 0, &ngpr, &nsse) == 0
|| gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{
long align = cif->arg_types[i]->alignment;
if (align < 8)
align = 8;
bytes = ALIGN (bytes, align);
bytes += cif->arg_types[i]->size;
}
else
{
gprcount += ngpr;
ssecount += nsse;
}
}
if (ssecount)
flags |= 1 << 11;
cif->flags = flags;
cif->bytes = ALIGN (bytes, 8);
return FFI_OK;
}
void
ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
{
enum x86_64_reg_class classes[MAX_CLASSES];
char *stack, *argp;
ffi_type **arg_types;
int gprcount, ssecount, ngpr, nsse, i, avn;
_Bool ret_in_memory;
struct register_args *reg_args;
/* Can't call 32-bit mode from 64-bit mode. */
FFI_ASSERT (cif->abi == FFI_UNIX64);
/* If the return value is a struct and we don't have a return value
address then we need to make one. Note the setting of flags to
VOID above in ffi_prep_cif_machdep. */
ret_in_memory = (cif->rtype->type == FFI_TYPE_STRUCT
&& (cif->flags & 0xff) == FFI_TYPE_VOID);
if (rvalue == NULL && ret_in_memory)
rvalue = alloca (cif->rtype->size);
/* Allocate the space for the arguments, plus 4 words of temp space. */
stack = alloca (sizeof (struct register_args) + cif->bytes + 4*8);
reg_args = (struct register_args *) stack;
argp = stack + sizeof (struct register_args);
gprcount = ssecount = 0;
/* If the return value is passed in memory, add the pointer as the
first integer argument. */
if (ret_in_memory)
reg_args->gpr[gprcount++] = (unsigned long) rvalue;
avn = cif->nargs;
arg_types = cif->arg_types;
for (i = 0; i < avn; ++i)
{
size_t size = arg_types[i]->size;
int n;
n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
if (n == 0
|| gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{
long align = arg_types[i]->alignment;
/* Stack arguments are *always* at least 8 byte aligned. */
if (align < 8)
align = 8;
/* Pass this argument in memory. */
argp = (void *) ALIGN (argp, align);
memcpy (argp, avalue[i], size);
argp += size;
}
else
{
/* The argument is passed entirely in registers. */
char *a = (char *) avalue[i];
int j;
for (j = 0; j < n; j++, a += 8, size -= 8)
{
switch (classes[j])
{
case X86_64_INTEGER_CLASS:
case X86_64_INTEGERSI_CLASS:
/* Sign-extend integer arguments passed in general
purpose registers, to cope with the fact that
LLVM incorrectly assumes that this will be done
(the x86-64 PS ABI does not specify this). */
switch (arg_types[i]->type)
{
case FFI_TYPE_SINT8:
*(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT8 *) a);
break;
case FFI_TYPE_SINT16:
*(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT16 *) a);
break;
case FFI_TYPE_SINT32:
*(SINT64 *)&reg_args->gpr[gprcount] = (SINT64) *((SINT32 *) a);
break;
default:
reg_args->gpr[gprcount] = 0;
memcpy (&reg_args->gpr[gprcount], a, size < 8 ? size : 8);
}
gprcount++;
break;
case X86_64_SSE_CLASS:
case X86_64_SSEDF_CLASS:
reg_args->sse[ssecount++].i64 = *(UINT64 *) a;
break;
case X86_64_SSESF_CLASS:
reg_args->sse[ssecount++].i32 = *(UINT32 *) a;
break;
default:
abort();
}
}
}
}
ffi_call_unix64 (stack, cif->bytes + sizeof (struct register_args),
cif->flags, rvalue, fn, ssecount);
}
extern void ffi_closure_unix64(void);
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*, void*, void**, void*),
void *user_data,
void *codeloc)
{
volatile unsigned short *tramp;
/* Sanity check on the cif ABI. */
{
int abi = cif->abi;
if (UNLIKELY (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI)))
return FFI_BAD_ABI;
}
tramp = (volatile unsigned short *) &closure->tramp[0];
tramp[0] = 0xbb49; /* mov <code>, %r11 */
*((unsigned long long * volatile) &tramp[1])
= (unsigned long) ffi_closure_unix64;
tramp[5] = 0xba49; /* mov <data>, %r10 */
*((unsigned long long * volatile) &tramp[6])
= (unsigned long) codeloc;
/* Set the carry bit iff the function uses any sse registers.
This is clc or stc, together with the first byte of the jmp. */
tramp[10] = cif->flags & (1 << 11) ? 0x49f9 : 0x49f8;
tramp[11] = 0xe3ff; /* jmp *%r11 */
closure->cif = cif;
closure->fun = fun;
closure->user_data = user_data;
return FFI_OK;
}
int
ffi_closure_unix64_inner(ffi_closure *closure, void *rvalue,
struct register_args *reg_args, char *argp)
{
ffi_cif *cif;
void **avalue;
ffi_type **arg_types;
long i, avn;
int gprcount, ssecount, ngpr, nsse;
int ret;
cif = closure->cif;
avalue = alloca(cif->nargs * sizeof(void *));
gprcount = ssecount = 0;
ret = cif->rtype->type;
if (ret != FFI_TYPE_VOID)
{
enum x86_64_reg_class classes[MAX_CLASSES];
int n = examine_argument (cif->rtype, classes, 1, &ngpr, &nsse);
if (n == 0)
{
/* The return value goes in memory. Arrange for the closure
return value to go directly back to the original caller. */
rvalue = (void *) (unsigned long) reg_args->gpr[gprcount++];
/* We don't have to do anything in asm for the return. */
ret = FFI_TYPE_VOID;
}
else if (ret == FFI_TYPE_STRUCT && n == 2)
{
/* Mark which register the second word of the structure goes in. */
_Bool sse0 = SSE_CLASS_P (classes[0]);
_Bool sse1 = SSE_CLASS_P (classes[1]);
if (!sse0 && sse1)
ret |= 1 << 8;
else if (sse0 && !sse1)
ret |= 1 << 9;
}
}
avn = cif->nargs;
arg_types = cif->arg_types;
for (i = 0; i < avn; ++i)
{
enum x86_64_reg_class classes[MAX_CLASSES];
int n;
n = examine_argument (arg_types[i], classes, 0, &ngpr, &nsse);
if (n == 0
|| gprcount + ngpr > MAX_GPR_REGS
|| ssecount + nsse > MAX_SSE_REGS)
{
long align = arg_types[i]->alignment;
/* Stack arguments are *always* at least 8 byte aligned. */
if (align < 8)
align = 8;
/* Pass this argument in memory. */
argp = (void *) ALIGN (argp, align);
avalue[i] = argp;
argp += arg_types[i]->size;
}
/* If the argument is in a single register, or two consecutive
integer registers, then we can use that address directly. */
else if (n == 1
|| (n == 2 && !(SSE_CLASS_P (classes[0])
|| SSE_CLASS_P (classes[1]))))
{
/* The argument is in a single register. */
if (SSE_CLASS_P (classes[0]))
{
avalue[i] = &reg_args->sse[ssecount];
ssecount += n;
}
else
{
avalue[i] = &reg_args->gpr[gprcount];
gprcount += n;
}
}
/* Otherwise, allocate space to make them consecutive. */
else
{
char *a = alloca (16);
int j;
avalue[i] = a;
for (j = 0; j < n; j++, a += 8)
{
if (SSE_CLASS_P (classes[j]))
memcpy (a, &reg_args->sse[ssecount++], 8);
else
memcpy (a, &reg_args->gpr[gprcount++], 8);
}
}
}
/* Invoke the closure. */
closure->fun (cif, rvalue, avalue, closure->user_data);
/* Tell assembly how to perform return type promotions. */
return ret;
}
#endif /* __x86_64__ */

View file

@ -0,0 +1,237 @@
/* -----------------------------------------------------------------------
prep_cif.c - Copyright (c) 2011, 2012 Anthony Green
Copyright (c) 1996, 1998, 2007 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* Round up to FFI_SIZEOF_ARG. */
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
/* Perform machine independent initialization of aggregate type
specifications. */
static ffi_status initialize_aggregate(ffi_type *arg)
{
ffi_type **ptr;
if (UNLIKELY(arg == NULL || arg->elements == NULL))
return FFI_BAD_TYPEDEF;
arg->size = 0;
arg->alignment = 0;
ptr = &(arg->elements[0]);
if (UNLIKELY(ptr == 0))
return FFI_BAD_TYPEDEF;
while ((*ptr) != NULL)
{
if (UNLIKELY(((*ptr)->size == 0)
&& (initialize_aggregate((*ptr)) != FFI_OK)))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type */
FFI_ASSERT_VALID_TYPE(*ptr);
arg->size = ALIGN(arg->size, (*ptr)->alignment);
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
arg->alignment : (*ptr)->alignment;
ptr++;
}
/* Structure size includes tail padding. This is important for
structures that fit in one register on ABIs like the PowerPC64
Linux ABI that right justify small structs in a register.
It's also needed for nested structure layout, for example
struct A { long a; char b; }; struct B { struct A x; char y; };
should find y at an offset of 2*sizeof(long) and result in a
total size of 3*sizeof(long). */
arg->size = ALIGN (arg->size, arg->alignment);
if (arg->size == 0)
return FFI_BAD_TYPEDEF;
else
return FFI_OK;
}
#ifndef __CRIS__
/* The CRIS ABI specifies structure elements to have byte
alignment only, so it completely overrides this functions,
which assumes "natural" alignment and padding. */
/* Perform machine independent ffi_cif preparation, then call
machine dependent routine. */
/* For non variadic functions isvariadic should be 0 and
nfixedargs==ntotalargs.
For variadic calls, isvariadic should be 1 and nfixedargs
and ntotalargs set as appropriate. nfixedargs must always be >=1 */
ffi_status FFI_HIDDEN ffi_prep_cif_core(ffi_cif *cif, ffi_abi abi,
unsigned int isvariadic,
unsigned int nfixedargs,
unsigned int ntotalargs,
ffi_type *rtype, ffi_type **atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT(cif != NULL);
FFI_ASSERT((!isvariadic) || (nfixedargs >= 1));
FFI_ASSERT(nfixedargs <= ntotalargs);
#ifndef X86_WIN32
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI))
return FFI_BAD_ABI;
#else
if (! (abi > FFI_FIRST_ABI && abi < FFI_LAST_ABI || abi == FFI_THISCALL))
return FFI_BAD_ABI;
#endif
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = ntotalargs;
cif->rtype = rtype;
cif->flags = 0;
/* Initialize the return type if necessary */
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the return type */
FFI_ASSERT_VALID_TYPE(cif->rtype);
/* x86, x86-64 and s390 stack space allocation is handled in prep_machdep. */
#if !defined M68K && !defined X86_ANY && !defined S390 && !defined PA
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
#ifdef SPARC
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
#endif
#ifdef TILE
&& (cif->rtype->size > 10 * FFI_SIZEOF_ARG)
#endif
#ifdef XTENSA
&& (cif->rtype->size > 16)
#endif
)
bytes = STACK_ARG_SIZE(sizeof(void*));
#endif
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
/* Initialize any uninitialized aggregate type definitions */
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type, do this
check after the initialization. */
FFI_ASSERT_VALID_TYPE(*ptr);
#if !defined X86_ANY && !defined S390 && !defined PA
#ifdef SPARC
if (((*ptr)->type == FFI_TYPE_STRUCT
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
|| ((*ptr)->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_V9))
bytes += sizeof(void*);
else
#endif
{
/* Add any padding if necessary */
if (((*ptr)->alignment - 1) & bytes)
bytes = ALIGN(bytes, (*ptr)->alignment);
#ifdef TILE
if (bytes < 10 * FFI_SIZEOF_ARG &&
bytes + STACK_ARG_SIZE((*ptr)->size) > 10 * FFI_SIZEOF_ARG)
{
/* An argument is never split between the 10 parameter
registers and the stack. */
bytes = 10 * FFI_SIZEOF_ARG;
}
#endif
#ifdef XTENSA
if (bytes <= 6*4 && bytes + STACK_ARG_SIZE((*ptr)->size) > 6*4)
bytes = 6*4;
#endif
bytes += STACK_ARG_SIZE((*ptr)->size);
}
#endif
}
cif->bytes = bytes;
/* Perform machine dependent cif processing */
#ifdef FFI_TARGET_SPECIFIC_VARIADIC
if (isvariadic)
return ffi_prep_cif_machdep_var(cif, nfixedargs, ntotalargs);
#endif
return ffi_prep_cif_machdep(cif);
}
#endif /* not __CRIS__ */
ffi_status ffi_prep_cif(ffi_cif *cif, ffi_abi abi, unsigned int nargs,
ffi_type *rtype, ffi_type **atypes)
{
return ffi_prep_cif_core(cif, abi, 0, nargs, nargs, rtype, atypes);
}
ffi_status ffi_prep_cif_var(ffi_cif *cif,
ffi_abi abi,
unsigned int nfixedargs,
unsigned int ntotalargs,
ffi_type *rtype,
ffi_type **atypes)
{
return ffi_prep_cif_core(cif, abi, 1, nfixedargs, ntotalargs, rtype, atypes);
}
#if FFI_CLOSURES
ffi_status
ffi_prep_closure (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data)
{
return ffi_prep_closure_loc (closure, cif, fun, user_data, closure);
}
#endif

View file

@ -0,0 +1,77 @@
/* -----------------------------------------------------------------------
types.c - Copyright (c) 1996, 1998 Red Hat, Inc.
Predefined ffi_types needed by libffi.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
/* Hide the basic type definitions from the header file, so that we
can redefine them here as "const". */
#define LIBFFI_HIDE_BASIC_TYPES
#include <ffi.h>
#include <ffi_common.h>
/* Type definitions */
#define FFI_TYPEDEF(name, type, id) \
struct struct_align_##name { \
char c; \
type x; \
}; \
const ffi_type ffi_type_##name = { \
sizeof(type), \
offsetof(struct struct_align_##name, x), \
id, NULL \
}
/* Size and alignment are fake here. They must not be 0. */
const ffi_type ffi_type_void = {
1, 1, FFI_TYPE_VOID, NULL
};
FFI_TYPEDEF(uint8, UINT8, FFI_TYPE_UINT8);
FFI_TYPEDEF(sint8, SINT8, FFI_TYPE_SINT8);
FFI_TYPEDEF(uint16, UINT16, FFI_TYPE_UINT16);
FFI_TYPEDEF(sint16, SINT16, FFI_TYPE_SINT16);
FFI_TYPEDEF(uint32, UINT32, FFI_TYPE_UINT32);
FFI_TYPEDEF(sint32, SINT32, FFI_TYPE_SINT32);
FFI_TYPEDEF(uint64, UINT64, FFI_TYPE_UINT64);
FFI_TYPEDEF(sint64, SINT64, FFI_TYPE_SINT64);
FFI_TYPEDEF(pointer, void*, FFI_TYPE_POINTER);
FFI_TYPEDEF(float, float, FFI_TYPE_FLOAT);
FFI_TYPEDEF(double, double, FFI_TYPE_DOUBLE);
#ifdef __alpha__
/* Even if we're not configured to default to 128-bit long double,
maintain binary compatibility, as -mlong-double-128 can be used
at any time. */
/* Validate the hard-coded number below. */
# if defined(__LONG_DOUBLE_128__) && FFI_TYPE_LONGDOUBLE != 4
# error FFI_TYPE_LONGDOUBLE out of date
# endif
const ffi_type ffi_type_longdouble = { 16, 16, 4, NULL };
#elif FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
FFI_TYPEDEF(longdouble, long double, FFI_TYPE_LONGDOUBLE);
#endif

View file

@ -0,0 +1,759 @@
/* -----------------------------------------------------------------------
win32.S - Copyright (c) 1996, 1998, 2001, 2002, 2009 Red Hat, Inc.
Copyright (c) 2001 John Beniton
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2009 Daniel Witte
X86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------
*/
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
#include <ffitarget.h>
.text
// This assumes we are using gas.
.balign 16
.globl _ffi_call_win32
#ifndef __OS2__
.def _ffi_call_win32; .scl 2; .type 32; .endef
#endif
_ffi_call_win32:
.LFB1:
pushl %ebp
.LCFI0:
movl %esp,%ebp
.LCFI1:
// Make room for all of the new args.
movl 20(%ebp),%ecx
subl %ecx,%esp
movl %esp,%eax
// Place all of the ffi_prep_args in position
pushl 12(%ebp)
pushl %eax
call *8(%ebp)
// Return stack to previous state and call the function
addl $8,%esp
// Handle fastcall and thiscall
cmpl $3, 16(%ebp) // FFI_THISCALL
jz .do_thiscall
cmpl $4, 16(%ebp) // FFI_FASTCALL
jnz .do_fncall
movl (%esp), %ecx
movl 4(%esp), %edx
addl $8, %esp
jmp .do_fncall
.do_thiscall:
movl (%esp), %ecx
addl $4, %esp
.do_fncall:
// FIXME: Align the stack to a 128-bit boundary to avoid
// potential performance hits.
call *32(%ebp)
// stdcall functions pop arguments off the stack themselves
// Load %ecx with the return type code
movl 24(%ebp),%ecx
// If the return value pointer is NULL, assume no return value.
cmpl $0,28(%ebp)
jne 0f
// Even if there is no space for the return value, we are
// obliged to handle floating-point values.
cmpl $FFI_TYPE_FLOAT,%ecx
jne .Lnoretval
fstp %st(0)
jmp .Lepilogue
0:
call 1f
// Do not insert anything here between the call and the jump table.
.Lstore_table:
.long .Lnoretval /* FFI_TYPE_VOID */
.long .Lretint /* FFI_TYPE_INT */
.long .Lretfloat /* FFI_TYPE_FLOAT */
.long .Lretdouble /* FFI_TYPE_DOUBLE */
.long .Lretlongdouble /* FFI_TYPE_LONGDOUBLE */
.long .Lretuint8 /* FFI_TYPE_UINT8 */
.long .Lretsint8 /* FFI_TYPE_SINT8 */
.long .Lretuint16 /* FFI_TYPE_UINT16 */
.long .Lretsint16 /* FFI_TYPE_SINT16 */
.long .Lretint /* FFI_TYPE_UINT32 */
.long .Lretint /* FFI_TYPE_SINT32 */
.long .Lretint64 /* FFI_TYPE_UINT64 */
.long .Lretint64 /* FFI_TYPE_SINT64 */
.long .Lretstruct /* FFI_TYPE_STRUCT */
.long .Lretint /* FFI_TYPE_POINTER */
.long .Lretstruct1b /* FFI_TYPE_SMALL_STRUCT_1B */
.long .Lretstruct2b /* FFI_TYPE_SMALL_STRUCT_2B */
.long .Lretstruct4b /* FFI_TYPE_SMALL_STRUCT_4B */
.long .Lretstruct /* FFI_TYPE_MS_STRUCT */
1:
add %ecx, %ecx
add %ecx, %ecx
add (%esp),%ecx
add $4, %esp
jmp *(%ecx)
/* Sign/zero extend as appropriate. */
.Lretsint8:
movsbl %al, %eax
jmp .Lretint
.Lretsint16:
movswl %ax, %eax
jmp .Lretint
.Lretuint8:
movzbl %al, %eax
jmp .Lretint
.Lretuint16:
movzwl %ax, %eax
jmp .Lretint
.Lretint:
// Load %ecx with the pointer to storage for the return value
movl 28(%ebp),%ecx
movl %eax,0(%ecx)
jmp .Lepilogue
.Lretfloat:
// Load %ecx with the pointer to storage for the return value
movl 28(%ebp),%ecx
fstps (%ecx)
jmp .Lepilogue
.Lretdouble:
// Load %ecx with the pointer to storage for the return value
movl 28(%ebp),%ecx
fstpl (%ecx)
jmp .Lepilogue
.Lretlongdouble:
// Load %ecx with the pointer to storage for the return value
movl 28(%ebp),%ecx
fstpt (%ecx)
jmp .Lepilogue
.Lretint64:
// Load %ecx with the pointer to storage for the return value
movl 28(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
jmp .Lepilogue
.Lretstruct1b:
// Load %ecx with the pointer to storage for the return value
movl 28(%ebp),%ecx
movb %al,0(%ecx)
jmp .Lepilogue
.Lretstruct2b:
// Load %ecx with the pointer to storage for the return value
movl 28(%ebp),%ecx
movw %ax,0(%ecx)
jmp .Lepilogue
.Lretstruct4b:
// Load %ecx with the pointer to storage for the return value
movl 28(%ebp),%ecx
movl %eax,0(%ecx)
jmp .Lepilogue
.Lretstruct:
// Nothing to do!
.Lnoretval:
.Lepilogue:
movl %ebp,%esp
popl %ebp
ret
.ffi_call_win32_end:
.balign 16
.globl _ffi_closure_THISCALL
#ifndef __OS2__
.def _ffi_closure_THISCALL; .scl 2; .type 32; .endef
#endif
_ffi_closure_THISCALL:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp) /* resp */
leal 12(%ebp), %edx /* account for stub return address on stack */
jmp .stub
.LFE1:
// This assumes we are using gas.
.balign 16
.globl _ffi_closure_SYSV
#ifndef __OS2__
.def _ffi_closure_SYSV; .scl 2; .type 32; .endef
#endif
_ffi_closure_SYSV:
.LFB3:
pushl %ebp
.LCFI4:
movl %esp, %ebp
.LCFI5:
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp) /* resp */
leal 8(%ebp), %edx
.stub:
movl %edx, 4(%esp) /* args = __builtin_dwarf_cfa () */
leal -12(%ebp), %edx
movl %edx, (%esp) /* &resp */
call _ffi_closure_SYSV_inner
movl -12(%ebp), %ecx
0:
call 1f
// Do not insert anything here between the call and the jump table.
.Lcls_store_table:
.long .Lcls_noretval /* FFI_TYPE_VOID */
.long .Lcls_retint /* FFI_TYPE_INT */
.long .Lcls_retfloat /* FFI_TYPE_FLOAT */
.long .Lcls_retdouble /* FFI_TYPE_DOUBLE */
.long .Lcls_retldouble /* FFI_TYPE_LONGDOUBLE */
.long .Lcls_retuint8 /* FFI_TYPE_UINT8 */
.long .Lcls_retsint8 /* FFI_TYPE_SINT8 */
.long .Lcls_retuint16 /* FFI_TYPE_UINT16 */
.long .Lcls_retsint16 /* FFI_TYPE_SINT16 */
.long .Lcls_retint /* FFI_TYPE_UINT32 */
.long .Lcls_retint /* FFI_TYPE_SINT32 */
.long .Lcls_retllong /* FFI_TYPE_UINT64 */
.long .Lcls_retllong /* FFI_TYPE_SINT64 */
.long .Lcls_retstruct /* FFI_TYPE_STRUCT */
.long .Lcls_retint /* FFI_TYPE_POINTER */
.long .Lcls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */
.long .Lcls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */
.long .Lcls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */
.long .Lcls_retmsstruct /* FFI_TYPE_MS_STRUCT */
1:
add %eax, %eax
add %eax, %eax
add (%esp),%eax
add $4, %esp
jmp *(%eax)
/* Sign/zero extend as appropriate. */
.Lcls_retsint8:
movsbl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retsint16:
movswl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retuint8:
movzbl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retuint16:
movzwl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retint:
movl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retfloat:
flds (%ecx)
jmp .Lcls_epilogue
.Lcls_retdouble:
fldl (%ecx)
jmp .Lcls_epilogue
.Lcls_retldouble:
fldt (%ecx)
jmp .Lcls_epilogue
.Lcls_retllong:
movl (%ecx), %eax
movl 4(%ecx), %edx
jmp .Lcls_epilogue
.Lcls_retstruct1:
movsbl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct2:
movswl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct4:
movl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct:
// Caller expects us to pop struct return value pointer hidden arg.
movl %ebp, %esp
popl %ebp
ret $0x4
.Lcls_retmsstruct:
// Caller expects us to return a pointer to the real return value.
mov %ecx, %eax
// Caller doesn't expects us to pop struct return value pointer hidden arg.
jmp .Lcls_epilogue
.Lcls_noretval:
.Lcls_epilogue:
movl %ebp, %esp
popl %ebp
ret
.ffi_closure_SYSV_end:
.LFE3:
#if !FFI_NO_RAW_API
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) & ~3)
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
#define CIF_FLAGS_OFFSET 20
.balign 16
.globl _ffi_closure_raw_THISCALL
#ifndef __OS2__
.def _ffi_closure_raw_THISCALL; .scl 2; .type 32; .endef
#endif
_ffi_closure_raw_THISCALL:
pushl %ebp
movl %esp, %ebp
pushl %esi
subl $36, %esp
movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
movl %edx, 12(%esp) /* user_data */
leal 12(%ebp), %edx /* __builtin_dwarf_cfa () */
jmp .stubraw
// This assumes we are using gas.
.balign 16
.globl _ffi_closure_raw_SYSV
#ifndef __OS2__
.def _ffi_closure_raw_SYSV; .scl 2; .type 32; .endef
#endif
_ffi_closure_raw_SYSV:
.LFB4:
pushl %ebp
.LCFI6:
movl %esp, %ebp
.LCFI7:
pushl %esi
.LCFI8:
subl $36, %esp
movl RAW_CLOSURE_CIF_OFFSET(%eax), %esi /* closure->cif */
movl RAW_CLOSURE_USER_DATA_OFFSET(%eax), %edx /* closure->user_data */
movl %edx, 12(%esp) /* user_data */
leal 8(%ebp), %edx /* __builtin_dwarf_cfa () */
.stubraw:
movl %edx, 8(%esp) /* raw_args */
leal -24(%ebp), %edx
movl %edx, 4(%esp) /* &res */
movl %esi, (%esp) /* cif */
call *RAW_CLOSURE_FUN_OFFSET(%eax) /* closure->fun */
movl CIF_FLAGS_OFFSET(%esi), %eax /* rtype */
0:
call 1f
// Do not insert anything here between the call and the jump table.
.Lrcls_store_table:
.long .Lrcls_noretval /* FFI_TYPE_VOID */
.long .Lrcls_retint /* FFI_TYPE_INT */
.long .Lrcls_retfloat /* FFI_TYPE_FLOAT */
.long .Lrcls_retdouble /* FFI_TYPE_DOUBLE */
.long .Lrcls_retldouble /* FFI_TYPE_LONGDOUBLE */
.long .Lrcls_retuint8 /* FFI_TYPE_UINT8 */
.long .Lrcls_retsint8 /* FFI_TYPE_SINT8 */
.long .Lrcls_retuint16 /* FFI_TYPE_UINT16 */
.long .Lrcls_retsint16 /* FFI_TYPE_SINT16 */
.long .Lrcls_retint /* FFI_TYPE_UINT32 */
.long .Lrcls_retint /* FFI_TYPE_SINT32 */
.long .Lrcls_retllong /* FFI_TYPE_UINT64 */
.long .Lrcls_retllong /* FFI_TYPE_SINT64 */
.long .Lrcls_retstruct /* FFI_TYPE_STRUCT */
.long .Lrcls_retint /* FFI_TYPE_POINTER */
.long .Lrcls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */
.long .Lrcls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */
.long .Lrcls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */
.long .Lrcls_retstruct /* FFI_TYPE_MS_STRUCT */
1:
add %eax, %eax
add %eax, %eax
add (%esp),%eax
add $4, %esp
jmp *(%eax)
/* Sign/zero extend as appropriate. */
.Lrcls_retsint8:
movsbl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retsint16:
movswl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retuint8:
movzbl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retuint16:
movzwl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retint:
movl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retfloat:
flds -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retdouble:
fldl -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retldouble:
fldt -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retllong:
movl -24(%ebp), %eax
movl -20(%ebp), %edx
jmp .Lrcls_epilogue
.Lrcls_retstruct1:
movsbl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retstruct2:
movswl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retstruct4:
movl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retstruct:
// Nothing to do!
.Lrcls_noretval:
.Lrcls_epilogue:
addl $36, %esp
popl %esi
popl %ebp
ret
.ffi_closure_raw_SYSV_end:
.LFE4:
#endif /* !FFI_NO_RAW_API */
// This assumes we are using gas.
.balign 16
.globl _ffi_closure_STDCALL
#ifndef __OS2__
.def _ffi_closure_STDCALL; .scl 2; .type 32; .endef
#endif
_ffi_closure_STDCALL:
.LFB5:
pushl %ebp
.LCFI9:
movl %esp, %ebp
.LCFI10:
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp) /* resp */
leal 12(%ebp), %edx /* account for stub return address on stack */
movl %edx, 4(%esp) /* args */
leal -12(%ebp), %edx
movl %edx, (%esp) /* &resp */
call _ffi_closure_SYSV_inner
movl -12(%ebp), %ecx
0:
call 1f
// Do not insert anything here between the call and the jump table.
.Lscls_store_table:
.long .Lscls_noretval /* FFI_TYPE_VOID */
.long .Lscls_retint /* FFI_TYPE_INT */
.long .Lscls_retfloat /* FFI_TYPE_FLOAT */
.long .Lscls_retdouble /* FFI_TYPE_DOUBLE */
.long .Lscls_retldouble /* FFI_TYPE_LONGDOUBLE */
.long .Lscls_retuint8 /* FFI_TYPE_UINT8 */
.long .Lscls_retsint8 /* FFI_TYPE_SINT8 */
.long .Lscls_retuint16 /* FFI_TYPE_UINT16 */
.long .Lscls_retsint16 /* FFI_TYPE_SINT16 */
.long .Lscls_retint /* FFI_TYPE_UINT32 */
.long .Lscls_retint /* FFI_TYPE_SINT32 */
.long .Lscls_retllong /* FFI_TYPE_UINT64 */
.long .Lscls_retllong /* FFI_TYPE_SINT64 */
.long .Lscls_retstruct /* FFI_TYPE_STRUCT */
.long .Lscls_retint /* FFI_TYPE_POINTER */
.long .Lscls_retstruct1 /* FFI_TYPE_SMALL_STRUCT_1B */
.long .Lscls_retstruct2 /* FFI_TYPE_SMALL_STRUCT_2B */
.long .Lscls_retstruct4 /* FFI_TYPE_SMALL_STRUCT_4B */
1:
add %eax, %eax
add %eax, %eax
add (%esp),%eax
add $4, %esp
jmp *(%eax)
/* Sign/zero extend as appropriate. */
.Lscls_retsint8:
movsbl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retsint16:
movswl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retuint8:
movzbl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retuint16:
movzwl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retint:
movl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retfloat:
flds (%ecx)
jmp .Lscls_epilogue
.Lscls_retdouble:
fldl (%ecx)
jmp .Lscls_epilogue
.Lscls_retldouble:
fldt (%ecx)
jmp .Lscls_epilogue
.Lscls_retllong:
movl (%ecx), %eax
movl 4(%ecx), %edx
jmp .Lscls_epilogue
.Lscls_retstruct1:
movsbl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retstruct2:
movswl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retstruct4:
movl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retstruct:
// Nothing to do!
.Lscls_noretval:
.Lscls_epilogue:
movl %ebp, %esp
popl %ebp
ret
.ffi_closure_STDCALL_end:
.LFE5:
#ifndef __OS2__
.section .eh_frame,"w"
#endif
.Lframe1:
.LSCIE1:
.long .LECIE1-.LASCIE1 /* Length of Common Information Entry */
.LASCIE1:
.long 0x0 /* CIE Identifier Tag */
.byte 0x1 /* CIE Version */
#ifdef __PIC__
.ascii "zR\0" /* CIE Augmentation */
#else
.ascii "\0" /* CIE Augmentation */
#endif
.byte 0x1 /* .uleb128 0x1; CIE Code Alignment Factor */
.byte 0x7c /* .sleb128 -4; CIE Data Alignment Factor */
.byte 0x8 /* CIE RA Column */
#ifdef __PIC__
.byte 0x1 /* .uleb128 0x1; Augmentation size */
.byte 0x1b /* FDE Encoding (pcrel sdata4) */
#endif
.byte 0xc /* DW_CFA_def_cfa CFA = r4 + 4 = 4(%esp) */
.byte 0x4 /* .uleb128 0x4 */
.byte 0x4 /* .uleb128 0x4 */
.byte 0x88 /* DW_CFA_offset, column 0x8 %eip at CFA + 1 * -4 */
.byte 0x1 /* .uleb128 0x1 */
.align 4
.LECIE1:
.LSFDE1:
.long .LEFDE1-.LASFDE1 /* FDE Length */
.LASFDE1:
.long .LASFDE1-.Lframe1 /* FDE CIE offset */
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
.long .LFB1-. /* FDE initial location */
#else
.long .LFB1
#endif
.long .LFE1-.LFB1 /* FDE address range */
#ifdef __PIC__
.byte 0x0 /* .uleb128 0x0; Augmentation size */
#endif
/* DW_CFA_xxx CFI instructions go here. */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI0-.LFB1
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
.byte 0x8 /* .uleb128 0x8 */
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
.byte 0x2 /* .uleb128 0x2 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI1-.LCFI0
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
.byte 0x5 /* .uleb128 0x5 */
/* End of DW_CFA_xxx CFI instructions. */
.align 4
.LEFDE1:
.LSFDE3:
.long .LEFDE3-.LASFDE3 /* FDE Length */
.LASFDE3:
.long .LASFDE3-.Lframe1 /* FDE CIE offset */
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
.long .LFB3-. /* FDE initial location */
#else
.long .LFB3
#endif
.long .LFE3-.LFB3 /* FDE address range */
#ifdef __PIC__
.byte 0x0 /* .uleb128 0x0; Augmentation size */
#endif
/* DW_CFA_xxx CFI instructions go here. */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI4-.LFB3
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
.byte 0x8 /* .uleb128 0x8 */
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
.byte 0x2 /* .uleb128 0x2 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI5-.LCFI4
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
.byte 0x5 /* .uleb128 0x5 */
/* End of DW_CFA_xxx CFI instructions. */
.align 4
.LEFDE3:
#if !FFI_NO_RAW_API
.LSFDE4:
.long .LEFDE4-.LASFDE4 /* FDE Length */
.LASFDE4:
.long .LASFDE4-.Lframe1 /* FDE CIE offset */
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
.long .LFB4-. /* FDE initial location */
#else
.long .LFB4
#endif
.long .LFE4-.LFB4 /* FDE address range */
#ifdef __PIC__
.byte 0x0 /* .uleb128 0x0; Augmentation size */
#endif
/* DW_CFA_xxx CFI instructions go here. */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI6-.LFB4
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
.byte 0x8 /* .uleb128 0x8 */
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
.byte 0x2 /* .uleb128 0x2 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI7-.LCFI6
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
.byte 0x5 /* .uleb128 0x5 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI8-.LCFI7
.byte 0x86 /* DW_CFA_offset, column 0x6 %esi at CFA + 3 * -4 */
.byte 0x3 /* .uleb128 0x3 */
/* End of DW_CFA_xxx CFI instructions. */
.align 4
.LEFDE4:
#endif /* !FFI_NO_RAW_API */
.LSFDE5:
.long .LEFDE5-.LASFDE5 /* FDE Length */
.LASFDE5:
.long .LASFDE5-.Lframe1 /* FDE CIE offset */
#if defined __PIC__ && defined HAVE_AS_X86_PCREL
.long .LFB5-. /* FDE initial location */
#else
.long .LFB5
#endif
.long .LFE5-.LFB5 /* FDE address range */
#ifdef __PIC__
.byte 0x0 /* .uleb128 0x0; Augmentation size */
#endif
/* DW_CFA_xxx CFI instructions go here. */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI9-.LFB5
.byte 0xe /* DW_CFA_def_cfa_offset CFA = r4 + 8 = 8(%esp) */
.byte 0x8 /* .uleb128 0x8 */
.byte 0x85 /* DW_CFA_offset, column 0x5 %ebp at CFA + 2 * -4 */
.byte 0x2 /* .uleb128 0x2 */
.byte 0x4 /* DW_CFA_advance_loc4 */
.long .LCFI10-.LCFI9
.byte 0xd /* DW_CFA_def_cfa_register CFA = r5 = %ebp */
.byte 0x5 /* .uleb128 0x5 */
/* End of DW_CFA_xxx CFI instructions. */
.align 4
.LEFDE5:

View file

@ -0,0 +1,736 @@
# 1 "gcc\\win32_asm.asm"
# 1 "<command-line>"
# 1 "gcc\\win32_asm.asm"
# 33 "gcc\\win32_asm.asm"
# 1 "common/fficonfig.h" 1
# 34 "gcc\\win32_asm.asm" 2
# 1 "common/ffi.h" 1
# 63 "common/ffi.h"
# 1 "common/ffitarget.h" 1
# 64 "common/ffi.h" 2
# 35 "gcc\\win32_asm.asm" 2
.text
.balign 16
.globl _ffi_call_win32
.def _ffi_call_win32; .scl 2; .type 32; .endef
_ffi_call_win32:
.LFB1:
pushl %ebp
.LCFI0:
movl %esp,%ebp
.LCFI1:
movl 20(%ebp),%ecx
subl %ecx,%esp
movl %esp,%eax
pushl 12(%ebp)
pushl %eax
call *8(%ebp)
addl $8,%esp
cmpl $3, 16(%ebp)
jz .do_thiscall
cmpl $4, 16(%ebp)
jnz .do_fncall
movl (%esp), %ecx
movl 4(%esp), %edx
addl $8, %esp
jmp .do_fncall
.do_thiscall:
movl (%esp), %ecx
addl $4, %esp
.do_fncall:
call *32(%ebp)
movl 24(%ebp),%ecx
cmpl $0,28(%ebp)
jne 0f
cmpl $2,%ecx
jne .Lnoretval
fstp %st(0)
jmp .Lepilogue
0:
call 1f
.Lstore_table:
.long .Lnoretval
.long .Lretint
.long .Lretfloat
.long .Lretdouble
.long .Lretlongdouble
.long .Lretuint8
.long .Lretsint8
.long .Lretuint16
.long .Lretsint16
.long .Lretint
.long .Lretint
.long .Lretint64
.long .Lretint64
.long .Lretstruct
.long .Lretint
.long .Lretstruct1b
.long .Lretstruct2b
.long .Lretstruct4b
.long .Lretstruct
1:
add %ecx, %ecx
add %ecx, %ecx
add (%esp),%ecx
add $4, %esp
jmp *(%ecx)
.Lretsint8:
movsbl %al, %eax
jmp .Lretint
.Lretsint16:
movswl %ax, %eax
jmp .Lretint
.Lretuint8:
movzbl %al, %eax
jmp .Lretint
.Lretuint16:
movzwl %ax, %eax
jmp .Lretint
.Lretint:
movl 28(%ebp),%ecx
movl %eax,0(%ecx)
jmp .Lepilogue
.Lretfloat:
movl 28(%ebp),%ecx
fstps (%ecx)
jmp .Lepilogue
.Lretdouble:
movl 28(%ebp),%ecx
fstpl (%ecx)
jmp .Lepilogue
.Lretlongdouble:
movl 28(%ebp),%ecx
fstpt (%ecx)
jmp .Lepilogue
.Lretint64:
movl 28(%ebp),%ecx
movl %eax,0(%ecx)
movl %edx,4(%ecx)
jmp .Lepilogue
.Lretstruct1b:
movl 28(%ebp),%ecx
movb %al,0(%ecx)
jmp .Lepilogue
.Lretstruct2b:
movl 28(%ebp),%ecx
movw %ax,0(%ecx)
jmp .Lepilogue
.Lretstruct4b:
movl 28(%ebp),%ecx
movl %eax,0(%ecx)
jmp .Lepilogue
.Lretstruct:
.Lnoretval:
.Lepilogue:
movl %ebp,%esp
popl %ebp
ret
.ffi_call_win32_end:
.balign 16
.globl _ffi_closure_THISCALL
.def _ffi_closure_THISCALL; .scl 2; .type 32; .endef
_ffi_closure_THISCALL:
pushl %ebp
movl %esp, %ebp
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp)
leal 12(%ebp), %edx
jmp .stub
.LFE1:
.balign 16
.globl _ffi_closure_SYSV
.def _ffi_closure_SYSV; .scl 2; .type 32; .endef
_ffi_closure_SYSV:
.LFB3:
pushl %ebp
.LCFI4:
movl %esp, %ebp
.LCFI5:
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp)
leal 8(%ebp), %edx
.stub:
movl %edx, 4(%esp)
leal -12(%ebp), %edx
movl %edx, (%esp)
call _ffi_closure_SYSV_inner
movl -12(%ebp), %ecx
0:
call 1f
.Lcls_store_table:
.long .Lcls_noretval
.long .Lcls_retint
.long .Lcls_retfloat
.long .Lcls_retdouble
.long .Lcls_retldouble
.long .Lcls_retuint8
.long .Lcls_retsint8
.long .Lcls_retuint16
.long .Lcls_retsint16
.long .Lcls_retint
.long .Lcls_retint
.long .Lcls_retllong
.long .Lcls_retllong
.long .Lcls_retstruct
.long .Lcls_retint
.long .Lcls_retstruct1
.long .Lcls_retstruct2
.long .Lcls_retstruct4
.long .Lcls_retmsstruct
1:
add %eax, %eax
add %eax, %eax
add (%esp),%eax
add $4, %esp
jmp *(%eax)
.Lcls_retsint8:
movsbl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retsint16:
movswl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retuint8:
movzbl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retuint16:
movzwl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retint:
movl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retfloat:
flds (%ecx)
jmp .Lcls_epilogue
.Lcls_retdouble:
fldl (%ecx)
jmp .Lcls_epilogue
.Lcls_retldouble:
fldt (%ecx)
jmp .Lcls_epilogue
.Lcls_retllong:
movl (%ecx), %eax
movl 4(%ecx), %edx
jmp .Lcls_epilogue
.Lcls_retstruct1:
movsbl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct2:
movswl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct4:
movl (%ecx), %eax
jmp .Lcls_epilogue
.Lcls_retstruct:
movl %ebp, %esp
popl %ebp
ret $0x4
.Lcls_retmsstruct:
mov %ecx, %eax
jmp .Lcls_epilogue
.Lcls_noretval:
.Lcls_epilogue:
movl %ebp, %esp
popl %ebp
ret
.ffi_closure_SYSV_end:
.LFE3:
.balign 16
.globl _ffi_closure_raw_THISCALL
.def _ffi_closure_raw_THISCALL; .scl 2; .type 32; .endef
_ffi_closure_raw_THISCALL:
pushl %ebp
movl %esp, %ebp
pushl %esi
subl $36, %esp
movl ((52 + 3) & ~3)(%eax), %esi
movl ((((52 + 3) & ~3) + 4) + 4)(%eax), %edx
movl %edx, 12(%esp)
leal 12(%ebp), %edx
jmp .stubraw
.balign 16
.globl _ffi_closure_raw_SYSV
.def _ffi_closure_raw_SYSV; .scl 2; .type 32; .endef
_ffi_closure_raw_SYSV:
.LFB4:
pushl %ebp
.LCFI6:
movl %esp, %ebp
.LCFI7:
pushl %esi
.LCFI8:
subl $36, %esp
movl ((52 + 3) & ~3)(%eax), %esi
movl ((((52 + 3) & ~3) + 4) + 4)(%eax), %edx
movl %edx, 12(%esp)
leal 8(%ebp), %edx
.stubraw:
movl %edx, 8(%esp)
leal -24(%ebp), %edx
movl %edx, 4(%esp)
movl %esi, (%esp)
call *(((52 + 3) & ~3) + 4)(%eax)
movl 20(%esi), %eax
0:
call 1f
.Lrcls_store_table:
.long .Lrcls_noretval
.long .Lrcls_retint
.long .Lrcls_retfloat
.long .Lrcls_retdouble
.long .Lrcls_retldouble
.long .Lrcls_retuint8
.long .Lrcls_retsint8
.long .Lrcls_retuint16
.long .Lrcls_retsint16
.long .Lrcls_retint
.long .Lrcls_retint
.long .Lrcls_retllong
.long .Lrcls_retllong
.long .Lrcls_retstruct
.long .Lrcls_retint
.long .Lrcls_retstruct1
.long .Lrcls_retstruct2
.long .Lrcls_retstruct4
.long .Lrcls_retstruct
1:
add %eax, %eax
add %eax, %eax
add (%esp),%eax
add $4, %esp
jmp *(%eax)
.Lrcls_retsint8:
movsbl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retsint16:
movswl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retuint8:
movzbl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retuint16:
movzwl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retint:
movl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retfloat:
flds -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retdouble:
fldl -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retldouble:
fldt -24(%ebp)
jmp .Lrcls_epilogue
.Lrcls_retllong:
movl -24(%ebp), %eax
movl -20(%ebp), %edx
jmp .Lrcls_epilogue
.Lrcls_retstruct1:
movsbl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retstruct2:
movswl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retstruct4:
movl -24(%ebp), %eax
jmp .Lrcls_epilogue
.Lrcls_retstruct:
.Lrcls_noretval:
.Lrcls_epilogue:
addl $36, %esp
popl %esi
popl %ebp
ret
.ffi_closure_raw_SYSV_end:
.LFE4:
.balign 16
.globl _ffi_closure_STDCALL
.def _ffi_closure_STDCALL; .scl 2; .type 32; .endef
_ffi_closure_STDCALL:
.LFB5:
pushl %ebp
.LCFI9:
movl %esp, %ebp
.LCFI10:
subl $40, %esp
leal -24(%ebp), %edx
movl %edx, -12(%ebp)
leal 12(%ebp), %edx
movl %edx, 4(%esp)
leal -12(%ebp), %edx
movl %edx, (%esp)
call _ffi_closure_SYSV_inner
movl -12(%ebp), %ecx
0:
call 1f
.Lscls_store_table:
.long .Lscls_noretval
.long .Lscls_retint
.long .Lscls_retfloat
.long .Lscls_retdouble
.long .Lscls_retldouble
.long .Lscls_retuint8
.long .Lscls_retsint8
.long .Lscls_retuint16
.long .Lscls_retsint16
.long .Lscls_retint
.long .Lscls_retint
.long .Lscls_retllong
.long .Lscls_retllong
.long .Lscls_retstruct
.long .Lscls_retint
.long .Lscls_retstruct1
.long .Lscls_retstruct2
.long .Lscls_retstruct4
1:
add %eax, %eax
add %eax, %eax
add (%esp),%eax
add $4, %esp
jmp *(%eax)
.Lscls_retsint8:
movsbl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retsint16:
movswl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retuint8:
movzbl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retuint16:
movzwl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retint:
movl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retfloat:
flds (%ecx)
jmp .Lscls_epilogue
.Lscls_retdouble:
fldl (%ecx)
jmp .Lscls_epilogue
.Lscls_retldouble:
fldt (%ecx)
jmp .Lscls_epilogue
.Lscls_retllong:
movl (%ecx), %eax
movl 4(%ecx), %edx
jmp .Lscls_epilogue
.Lscls_retstruct1:
movsbl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retstruct2:
movswl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retstruct4:
movl (%ecx), %eax
jmp .Lscls_epilogue
.Lscls_retstruct:
.Lscls_noretval:
.Lscls_epilogue:
movl %ebp, %esp
popl %ebp
ret
.ffi_closure_STDCALL_end:
.LFE5:
.section .eh_frame,"w"
.Lframe1:
.LSCIE1:
.long .LECIE1-.LASCIE1
.LASCIE1:
.long 0x0
.byte 0x1
.ascii "\0"
.byte 0x1
.byte 0x7c
.byte 0x8
.byte 0xc
.byte 0x4
.byte 0x4
.byte 0x88
.byte 0x1
.align 4
.LECIE1:
.LSFDE1:
.long .LEFDE1-.LASFDE1
.LASFDE1:
.long .LASFDE1-.Lframe1
.long .LFB1
.long .LFE1-.LFB1
.byte 0x4
.long .LCFI0-.LFB1
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.long .LCFI1-.LCFI0
.byte 0xd
.byte 0x5
.align 4
.LEFDE1:
.LSFDE3:
.long .LEFDE3-.LASFDE3
.LASFDE3:
.long .LASFDE3-.Lframe1
.long .LFB3
.long .LFE3-.LFB3
.byte 0x4
.long .LCFI4-.LFB3
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.long .LCFI5-.LCFI4
.byte 0xd
.byte 0x5
.align 4
.LEFDE3:
.LSFDE4:
.long .LEFDE4-.LASFDE4
.LASFDE4:
.long .LASFDE4-.Lframe1
.long .LFB4
.long .LFE4-.LFB4
.byte 0x4
.long .LCFI6-.LFB4
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.long .LCFI7-.LCFI6
.byte 0xd
.byte 0x5
.byte 0x4
.long .LCFI8-.LCFI7
.byte 0x86
.byte 0x3
.align 4
.LEFDE4:
.LSFDE5:
.long .LEFDE5-.LASFDE5
.LASFDE5:
.long .LASFDE5-.Lframe1
.long .LFB5
.long .LFE5-.LFB5
.byte 0x4
.long .LCFI9-.LFB5
.byte 0xe
.byte 0x8
.byte 0x85
.byte 0x2
.byte 0x4
.long .LCFI10-.LCFI9
.byte 0xd
.byte 0x5
.align 4
.LEFDE5:

View file

@ -0,0 +1,467 @@
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
/* Constants for ffi_call_win64 */
#define STACK 0
#define PREP_ARGS_FN 32
#define ECIF 40
#define CIF_BYTES 48
#define CIF_FLAGS 56
#define RVALUE 64
#define FN 72
/* ffi_call_win64 (void (*prep_args_fn)(char *, extended_cif *),
extended_cif *ecif, unsigned bytes, unsigned flags,
unsigned *rvalue, void (*fn)());
*/
#ifdef _MSC_VER
PUBLIC ffi_call_win64
EXTRN __chkstk:NEAR
EXTRN ffi_closure_win64_inner:NEAR
_TEXT SEGMENT
;;; ffi_closure_win64 will be called with these registers set:
;;; rax points to 'closure'
;;; r11 contains a bit mask that specifies which of the
;;; first four parameters are float or double
;;;
;;; It must move the parameters passed in registers to their stack location,
;;; call ffi_closure_win64_inner for the actual work, then return the result.
;;;
ffi_closure_win64 PROC FRAME
;; copy register arguments onto stack
test r11, 1
jne first_is_float
mov QWORD PTR [rsp+8], rcx
jmp second
first_is_float:
movlpd QWORD PTR [rsp+8], xmm0
second:
test r11, 2
jne second_is_float
mov QWORD PTR [rsp+16], rdx
jmp third
second_is_float:
movlpd QWORD PTR [rsp+16], xmm1
third:
test r11, 4
jne third_is_float
mov QWORD PTR [rsp+24], r8
jmp fourth
third_is_float:
movlpd QWORD PTR [rsp+24], xmm2
fourth:
test r11, 8
jne fourth_is_float
mov QWORD PTR [rsp+32], r9
jmp done
fourth_is_float:
movlpd QWORD PTR [rsp+32], xmm3
done:
.ALLOCSTACK 40
sub rsp, 40
.ENDPROLOG
mov rcx, rax ; context is first parameter
mov rdx, rsp ; stack is second parameter
add rdx, 48 ; point to start of arguments
mov rax, ffi_closure_win64_inner
call rax ; call the real closure function
add rsp, 40
movd xmm0, rax ; If the closure returned a float,
; ffi_closure_win64_inner wrote it to rax
ret 0
ffi_closure_win64 ENDP
ffi_call_win64 PROC FRAME
;; copy registers onto stack
mov QWORD PTR [rsp+32], r9
mov QWORD PTR [rsp+24], r8
mov QWORD PTR [rsp+16], rdx
mov QWORD PTR [rsp+8], rcx
.PUSHREG rbp
push rbp
.ALLOCSTACK 48
sub rsp, 48 ; 00000030H
.SETFRAME rbp, 32
lea rbp, QWORD PTR [rsp+32]
.ENDPROLOG
mov eax, DWORD PTR CIF_BYTES[rbp]
add rax, 15
and rax, -16
call __chkstk
sub rsp, rax
lea rax, QWORD PTR [rsp+32]
mov QWORD PTR STACK[rbp], rax
mov rdx, QWORD PTR ECIF[rbp]
mov rcx, QWORD PTR STACK[rbp]
call QWORD PTR PREP_ARGS_FN[rbp]
mov rsp, QWORD PTR STACK[rbp]
movlpd xmm3, QWORD PTR [rsp+24]
movd r9, xmm3
movlpd xmm2, QWORD PTR [rsp+16]
movd r8, xmm2
movlpd xmm1, QWORD PTR [rsp+8]
movd rdx, xmm1
movlpd xmm0, QWORD PTR [rsp]
movd rcx, xmm0
call QWORD PTR FN[rbp]
ret_struct4b$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_4B
jne ret_struct2b$
mov rcx, QWORD PTR RVALUE[rbp]
mov DWORD PTR [rcx], eax
jmp ret_void$
ret_struct2b$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_2B
jne ret_struct1b$
mov rcx, QWORD PTR RVALUE[rbp]
mov WORD PTR [rcx], ax
jmp ret_void$
ret_struct1b$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SMALL_STRUCT_1B
jne ret_uint8$
mov rcx, QWORD PTR RVALUE[rbp]
mov BYTE PTR [rcx], al
jmp ret_void$
ret_uint8$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT8
jne ret_sint8$
mov rcx, QWORD PTR RVALUE[rbp]
movzx rax, al
mov QWORD PTR [rcx], rax
jmp ret_void$
ret_sint8$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT8
jne ret_uint16$
mov rcx, QWORD PTR RVALUE[rbp]
movsx rax, al
mov QWORD PTR [rcx], rax
jmp ret_void$
ret_uint16$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT16
jne ret_sint16$
mov rcx, QWORD PTR RVALUE[rbp]
movzx rax, ax
mov QWORD PTR [rcx], rax
jmp SHORT ret_void$
ret_sint16$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT16
jne ret_uint32$
mov rcx, QWORD PTR RVALUE[rbp]
movsx rax, ax
mov QWORD PTR [rcx], rax
jmp SHORT ret_void$
ret_uint32$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_UINT32
jne ret_sint32$
mov rcx, QWORD PTR RVALUE[rbp]
mov eax, eax
mov QWORD PTR [rcx], rax
jmp SHORT ret_void$
ret_sint32$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT32
jne ret_float$
mov rcx, QWORD PTR RVALUE[rbp]
cdqe
mov QWORD PTR [rcx], rax
jmp SHORT ret_void$
ret_float$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_FLOAT
jne SHORT ret_double$
mov rax, QWORD PTR RVALUE[rbp]
movss DWORD PTR [rax], xmm0
jmp SHORT ret_void$
ret_double$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_DOUBLE
jne SHORT ret_sint64$
mov rax, QWORD PTR RVALUE[rbp]
movlpd QWORD PTR [rax], xmm0
jmp SHORT ret_void$
ret_sint64$:
cmp DWORD PTR CIF_FLAGS[rbp], FFI_TYPE_SINT64
jne ret_void$
mov rcx, QWORD PTR RVALUE[rbp]
mov QWORD PTR [rcx], rax
jmp SHORT ret_void$
ret_void$:
xor rax, rax
lea rsp, QWORD PTR [rbp+16]
pop rbp
ret 0
ffi_call_win64 ENDP
_TEXT ENDS
END
#else
#ifdef SYMBOL_UNDERSCORE
#define SYMBOL_NAME(name) _##name
#else
#define SYMBOL_NAME(name) name
#endif
.text
.extern SYMBOL_NAME(ffi_closure_win64_inner)
// ffi_closure_win64 will be called with these registers set:
// rax points to 'closure'
// r11 contains a bit mask that specifies which of the
// first four parameters are float or double
// // It must move the parameters passed in registers to their stack location,
// call ffi_closure_win64_inner for the actual work, then return the result.
//
.balign 16
.globl SYMBOL_NAME(ffi_closure_win64)
SYMBOL_NAME(ffi_closure_win64):
// copy register arguments onto stack
test $1,%r11
jne .Lfirst_is_float
mov %rcx, 8(%rsp)
jmp .Lsecond
.Lfirst_is_float:
movlpd %xmm0, 8(%rsp)
.Lsecond:
test $2, %r11
jne .Lsecond_is_float
mov %rdx, 16(%rsp)
jmp .Lthird
.Lsecond_is_float:
movlpd %xmm1, 16(%rsp)
.Lthird:
test $4, %r11
jne .Lthird_is_float
mov %r8,24(%rsp)
jmp .Lfourth
.Lthird_is_float:
movlpd %xmm2, 24(%rsp)
.Lfourth:
test $8, %r11
jne .Lfourth_is_float
mov %r9, 32(%rsp)
jmp .Ldone
.Lfourth_is_float:
movlpd %xmm3, 32(%rsp)
.Ldone:
// ALLOCSTACK 40
sub $40, %rsp
// ENDPROLOG
mov %rax, %rcx // context is first parameter
mov %rsp, %rdx // stack is second parameter
add $48, %rdx // point to start of arguments
mov $SYMBOL_NAME(ffi_closure_win64_inner), %rax
callq *%rax // call the real closure function
add $40, %rsp
movq %rax, %xmm0 // If the closure returned a float,
// ffi_closure_win64_inner wrote it to rax
retq
.ffi_closure_win64_end:
.balign 16
.globl SYMBOL_NAME(ffi_call_win64)
SYMBOL_NAME(ffi_call_win64):
// copy registers onto stack
mov %r9,32(%rsp)
mov %r8,24(%rsp)
mov %rdx,16(%rsp)
mov %rcx,8(%rsp)
// PUSHREG rbp
push %rbp
// ALLOCSTACK 48
sub $48,%rsp
// SETFRAME rbp, 32
lea 32(%rsp),%rbp
// ENDPROLOG
mov CIF_BYTES(%rbp),%eax
add $15, %rax
and $-16, %rax
cmpq $0x1000, %rax
jb Lch_done
Lch_probe:
subq $0x1000,%rsp
orl $0x0, (%rsp)
subq $0x1000,%rax
cmpq $0x1000,%rax
ja Lch_probe
Lch_done:
subq %rax, %rsp
orl $0x0, (%rsp)
lea 32(%rsp), %rax
mov %rax, STACK(%rbp)
mov ECIF(%rbp), %rdx
mov STACK(%rbp), %rcx
callq *PREP_ARGS_FN(%rbp)
mov STACK(%rbp), %rsp
movlpd 24(%rsp), %xmm3
movd %xmm3, %r9
movlpd 16(%rsp), %xmm2
movd %xmm2, %r8
movlpd 8(%rsp), %xmm1
movd %xmm1, %rdx
movlpd (%rsp), %xmm0
movd %xmm0, %rcx
callq *FN(%rbp)
.Lret_struct4b:
cmpl $FFI_TYPE_SMALL_STRUCT_4B, CIF_FLAGS(%rbp)
jne .Lret_struct2b
mov RVALUE(%rbp), %rcx
mov %eax, (%rcx)
jmp .Lret_void
.Lret_struct2b:
cmpl $FFI_TYPE_SMALL_STRUCT_2B, CIF_FLAGS(%rbp)
jne .Lret_struct1b
mov RVALUE(%rbp), %rcx
mov %ax, (%rcx)
jmp .Lret_void
.Lret_struct1b:
cmpl $FFI_TYPE_SMALL_STRUCT_1B, CIF_FLAGS(%rbp)
jne .Lret_uint8
mov RVALUE(%rbp), %rcx
mov %al, (%rcx)
jmp .Lret_void
.Lret_uint8:
cmpl $FFI_TYPE_UINT8, CIF_FLAGS(%rbp)
jne .Lret_sint8
mov RVALUE(%rbp), %rcx
movzbq %al, %rax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_sint8:
cmpl $FFI_TYPE_SINT8, CIF_FLAGS(%rbp)
jne .Lret_uint16
mov RVALUE(%rbp), %rcx
movsbq %al, %rax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_uint16:
cmpl $FFI_TYPE_UINT16, CIF_FLAGS(%rbp)
jne .Lret_sint16
mov RVALUE(%rbp), %rcx
movzwq %ax, %rax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_sint16:
cmpl $FFI_TYPE_SINT16, CIF_FLAGS(%rbp)
jne .Lret_uint32
mov RVALUE(%rbp), %rcx
movswq %ax, %rax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_uint32:
cmpl $FFI_TYPE_UINT32, CIF_FLAGS(%rbp)
jne .Lret_sint32
mov RVALUE(%rbp), %rcx
movl %eax, %eax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_sint32:
cmpl $FFI_TYPE_SINT32, CIF_FLAGS(%rbp)
jne .Lret_float
mov RVALUE(%rbp), %rcx
cltq
movq %rax, (%rcx)
jmp .Lret_void
.Lret_float:
cmpl $FFI_TYPE_FLOAT, CIF_FLAGS(%rbp)
jne .Lret_double
mov RVALUE(%rbp), %rax
movss %xmm0, (%rax)
jmp .Lret_void
.Lret_double:
cmpl $FFI_TYPE_DOUBLE, CIF_FLAGS(%rbp)
jne .Lret_sint64
mov RVALUE(%rbp), %rax
movlpd %xmm0, (%rax)
jmp .Lret_void
.Lret_sint64:
cmpl $FFI_TYPE_SINT64, CIF_FLAGS(%rbp)
jne .Lret_void
mov RVALUE(%rbp), %rcx
mov %rax, (%rcx)
jmp .Lret_void
.Lret_void:
xor %rax, %rax
lea 16(%rbp), %rsp
pop %rbp
retq
.ffi_call_win64_end:
#endif /* !_MSC_VER */

View file

@ -0,0 +1,227 @@
# 1 "gcc\\win64_asm.asm"
# 1 "<command-line>"
# 1 "gcc\\win64_asm.asm"
# 1 "common/fficonfig.h" 1
# 3 "gcc\\win64_asm.asm" 2
# 1 "common/ffi.h" 1
# 63 "common/ffi.h"
# 1 "common/ffitarget.h" 1
# 64 "common/ffi.h" 2
# 4 "gcc\\win64_asm.asm" 2
# 244 "gcc\\win64_asm.asm"
.text
.extern ffi_closure_win64_inner
# 255 "gcc\\win64_asm.asm"
.balign 16
.globl ffi_closure_win64
ffi_closure_win64:
test $1,%r11
jne .Lfirst_is_float
mov %rcx, 8(%rsp)
jmp .Lsecond
.Lfirst_is_float:
movlpd %xmm0, 8(%rsp)
.Lsecond:
test $2, %r11
jne .Lsecond_is_float
mov %rdx, 16(%rsp)
jmp .Lthird
.Lsecond_is_float:
movlpd %xmm1, 16(%rsp)
.Lthird:
test $4, %r11
jne .Lthird_is_float
mov %r8,24(%rsp)
jmp .Lfourth
.Lthird_is_float:
movlpd %xmm2, 24(%rsp)
.Lfourth:
test $8, %r11
jne .Lfourth_is_float
mov %r9, 32(%rsp)
jmp .Ldone
.Lfourth_is_float:
movlpd %xmm3, 32(%rsp)
.Ldone:
sub $40, %rsp
mov %rax, %rcx
mov %rsp, %rdx
add $48, %rdx
mov $SYMBOL_NAME(ffi_closure_win64_inner), %rax
callq *%rax
add $40, %rsp
movq %rax, %xmm0
retq
.ffi_closure_win64_end:
.balign 16
.globl ffi_call_win64
ffi_call_win64:
mov %r9,32(%rsp)
mov %r8,24(%rsp)
mov %rdx,16(%rsp)
mov %rcx,8(%rsp)
push %rbp
sub $48,%rsp
lea 32(%rsp),%rbp
mov 48(%rbp),%eax
add $15, %rax
and $-16, %rax
cmpq $0x1000, %rax
jb Lch_done
Lch_probe:
subq $0x1000,%rsp
orl $0x0, (%rsp)
subq $0x1000,%rax
cmpq $0x1000,%rax
ja Lch_probe
Lch_done:
subq %rax, %rsp
orl $0x0, (%rsp)
lea 32(%rsp), %rax
mov %rax, 0(%rbp)
mov 40(%rbp), %rdx
mov 0(%rbp), %rcx
callq *32(%rbp)
mov 0(%rbp), %rsp
movlpd 24(%rsp), %xmm3
movd %xmm3, %r9
movlpd 16(%rsp), %xmm2
movd %xmm2, %r8
movlpd 8(%rsp), %xmm1
movd %xmm1, %rdx
movlpd (%rsp), %xmm0
movd %xmm0, %rcx
callq *72(%rbp)
.Lret_struct4b:
cmpl $FFI_TYPE_SMALL_STRUCT_4B, 56(%rbp)
jne .Lret_struct2b
mov 64(%rbp), %rcx
mov %eax, (%rcx)
jmp .Lret_void
.Lret_struct2b:
cmpl $FFI_TYPE_SMALL_STRUCT_2B, 56(%rbp)
jne .Lret_struct1b
mov 64(%rbp), %rcx
mov %ax, (%rcx)
jmp .Lret_void
.Lret_struct1b:
cmpl $FFI_TYPE_SMALL_STRUCT_1B, 56(%rbp)
jne .Lret_uint8
mov 64(%rbp), %rcx
mov %al, (%rcx)
jmp .Lret_void
.Lret_uint8:
cmpl $FFI_TYPE_UINT8, 56(%rbp)
jne .Lret_sint8
mov 64(%rbp), %rcx
movzbq %al, %rax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_sint8:
cmpl $FFI_TYPE_SINT8, 56(%rbp)
jne .Lret_uint16
mov 64(%rbp), %rcx
movsbq %al, %rax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_uint16:
cmpl $FFI_TYPE_UINT16, 56(%rbp)
jne .Lret_sint16
mov 64(%rbp), %rcx
movzwq %ax, %rax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_sint16:
cmpl $FFI_TYPE_SINT16, 56(%rbp)
jne .Lret_uint32
mov 64(%rbp), %rcx
movswq %ax, %rax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_uint32:
cmpl $9, 56(%rbp)
jne .Lret_sint32
mov 64(%rbp), %rcx
movl %eax, %eax
movq %rax, (%rcx)
jmp .Lret_void
.Lret_sint32:
cmpl $10, 56(%rbp)
jne .Lret_float
mov 64(%rbp), %rcx
cltq
movq %rax, (%rcx)
jmp .Lret_void
.Lret_float:
cmpl $2, 56(%rbp)
jne .Lret_double
mov 64(%rbp), %rax
movss %xmm0, (%rax)
jmp .Lret_void
.Lret_double:
cmpl $3, 56(%rbp)
jne .Lret_sint64
mov 64(%rbp), %rax
movlpd %xmm0, (%rax)
jmp .Lret_void
.Lret_sint64:
cmpl $12, 56(%rbp)
jne .Lret_void
mov 64(%rbp), %rcx
mov %rax, (%rcx)
jmp .Lret_void
.Lret_void:
xor %rax, %rax
lea 16(%rbp), %rsp
pop %rbp
retq
.ffi_call_win64_end:

View file

@ -26,12 +26,36 @@
{.deadCodeElim: on.}
when defined(windows):
const libffidll* = "libffi.dll"
elif defined(macosx):
const libffidll* = "libffi.dylib"
else:
const libffidll* = "libffi.so"
when defined(windows):
# on Windows we don't use a DLL but instead embed libffi directly:
{.pragma: mylib, header: r"ffi.h".}
#{.compile: r"common\malloc_closure.c".}
{.compile: r"common\raw_api.c".}
when defined(vcc):
{.compile: r"msvc\ffi.c".}
{.compile: r"msvc\prep_cif.c".}
{.compile: r"msvc\win32.c".}
{.compile: r"msvc\types.c".}
when defined(cpu64):
{.compile: r"msvc\win64_asm.asm".}
else:
{.compile: r"msvc\win32_asm.asm".}
else:
{.compile: r"gcc\ffi.c".}
{.compile: r"gcc\prep_cif.c".}
{.compile: r"gcc\types.c".}
{.compile: r"gcc\closures.c".}
when defined(cpu64):
{.compile: r"gcc\ffi64.c".}
{.compile: r"gcc\win64_asm.S".}
else:
{.compile: r"gcc\win32_asm.S".}
elif defined(macosx):
{.pragma: mylib, dynlib: "libffi.dylib".}
else:
{.pragma: mylib, dynlib: "libffi.so".}
type
TArg* = int
@ -88,19 +112,19 @@ type
elements*: ptr ptr TType
var
type_void* {.importc: "ffi_type_void", dynlib: libffidll.}: TType
type_uint8* {.importc: "ffi_type_uint8", dynlib: libffidll.}: TType
type_sint8* {.importc: "ffi_type_sint8", dynlib: libffidll.}: TType
type_uint16* {.importc: "ffi_type_uint16", dynlib: libffidll.}: TType
type_sint16* {.importc: "ffi_type_sint16", dynlib: libffidll.}: TType
type_uint32* {.importc: "ffi_type_uint32", dynlib: libffidll.}: TType
type_sint32* {.importc: "ffi_type_sint32", dynlib: libffidll.}: TType
type_uint64* {.importc: "ffi_type_uint64", dynlib: libffidll.}: TType
type_sint64* {.importc: "ffi_type_sint64", dynlib: libffidll.}: TType
type_float* {.importc: "ffi_type_float", dynlib: libffidll.}: TType
type_double* {.importc: "ffi_type_double", dynlib: libffidll.}: TType
type_pointer* {.importc: "ffi_type_pointer", dynlib: libffidll.}: TType
type_longdouble* {.importc: "ffi_type_longdouble", dynlib: libffidll.}: TType
type_void* {.importc: "ffi_type_void", mylib.}: TType
type_uint8* {.importc: "ffi_type_uint8", mylib.}: TType
type_sint8* {.importc: "ffi_type_sint8", mylib.}: TType
type_uint16* {.importc: "ffi_type_uint16", mylib.}: TType
type_sint16* {.importc: "ffi_type_sint16", mylib.}: TType
type_uint32* {.importc: "ffi_type_uint32", mylib.}: TType
type_sint32* {.importc: "ffi_type_sint32", mylib.}: TType
type_uint64* {.importc: "ffi_type_uint64", mylib.}: TType
type_sint64* {.importc: "ffi_type_sint64", mylib.}: TType
type_float* {.importc: "ffi_type_float", mylib.}: TType
type_double* {.importc: "ffi_type_double", mylib.}: TType
type_pointer* {.importc: "ffi_type_pointer", mylib.}: TType
type_longdouble* {.importc: "ffi_type_longdouble", mylib.}: TType
type
Tstatus* {.size: sizeof(cint).} = enum
@ -119,20 +143,18 @@ type
sint*: TSArg
proc raw_call*(cif: var Tcif; fn: proc () {.cdecl.}; rvalue: pointer;
avalue: ptr TRaw) {.cdecl, importc: "ffi_raw_call",
dynlib: libffidll.}
avalue: ptr TRaw) {.cdecl, importc: "ffi_raw_call", mylib.}
proc ptrarray_to_raw*(cif: var Tcif; args: ptr pointer; raw: ptr TRaw) {.cdecl,
importc: "ffi_ptrarray_to_raw", dynlib: libffidll.}
importc: "ffi_ptrarray_to_raw", mylib.}
proc raw_to_ptrarray*(cif: var Tcif; raw: ptr TRaw; args: ptr pointer) {.cdecl,
importc: "ffi_raw_to_ptrarray", dynlib: libffidll.}
proc raw_size*(cif: var Tcif): int {.cdecl, importc: "ffi_raw_size",
dynlib: libffidll.}
importc: "ffi_raw_to_ptrarray", mylib.}
proc raw_size*(cif: var Tcif): int {.cdecl, importc: "ffi_raw_size", mylib.}
proc prep_cif*(cif: var Tcif; abi: TABI; nargs: cuint; rtype: ptr TType;
atypes: ptr ptr TType): TStatus {.cdecl, importc: "ffi_prep_cif",
dynlib: libffidll.}
mylib.}
proc call*(cif: var Tcif; fn: proc () {.cdecl.}; rvalue: pointer;
avalue: ptr pointer) {.cdecl, importc: "ffi_call", dynlib: libffidll.}
avalue: ptr pointer) {.cdecl, importc: "ffi_call", mylib.}
# the same with an easier interface:
type
@ -141,9 +163,9 @@ type
proc prep_cif*(cif: var Tcif; abi: TABI; nargs: cuint; rtype: ptr TType;
atypes: TParamList): TStatus {.cdecl, importc: "ffi_prep_cif",
dynlib: libffidll.}
mylib.}
proc call*(cif: var Tcif; fn, rvalue: pointer;
avalue: TArgList) {.cdecl, importc: "ffi_call", dynlib: libffidll.}
avalue: TArgList) {.cdecl, importc: "ffi_call", mylib.}
# Useful for eliminating compiler warnings
##define FFI_FN(f) ((void (*)(void))f)

View file

@ -0,0 +1,457 @@
/* -----------------------------------------------------------------------
ffi.c - Copyright (c) 1996, 1998, 1999, 2001 Red Hat, Inc.
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2002 Bo Thorsen
Copyright (c) 2002 Roger Sayle
x86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* ffi_prep_args is called by the assembly routine once stack space
has been allocated for the function's arguments */
extern void Py_FatalError(const char *msg);
/*@-exportheader@*/
void ffi_prep_args(char *stack, extended_cif *ecif)
/*@=exportheader@*/
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
{
*(void **) argp = ecif->rvalue;
argp += sizeof(void *);
}
p_argv = ecif->avalue;
for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
i != 0;
i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(void *) - 1) & (size_t) argp)
argp = (char *) ALIGN(argp, sizeof(void *));
z = (*p_arg)->size;
if (z < sizeof(int))
{
z = sizeof(int);
switch ((*p_arg)->type)
{
case FFI_TYPE_SINT8:
*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
break;
case FFI_TYPE_UINT8:
*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
break;
case FFI_TYPE_SINT16:
*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
break;
case FFI_TYPE_UINT16:
*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
break;
case FFI_TYPE_SINT32:
*(signed int *) argp = (signed int)*(SINT32 *)(* p_argv);
break;
case FFI_TYPE_UINT32:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
case FFI_TYPE_STRUCT:
*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
break;
default:
FFI_ASSERT(0);
}
}
else
{
memcpy(argp, *p_argv, z);
}
p_argv++;
argp += z;
}
if (argp >= stack && (unsigned)(argp - stack) > ecif->cif->bytes)
{
Py_FatalError("FFI BUG: not enough stack space for arguments");
}
return;
}
/* Perform machine dependent cif processing */
ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
{
/* Set the return type flag */
switch (cif->rtype->type)
{
case FFI_TYPE_VOID:
case FFI_TYPE_STRUCT:
case FFI_TYPE_SINT64:
case FFI_TYPE_FLOAT:
case FFI_TYPE_DOUBLE:
case FFI_TYPE_LONGDOUBLE:
cif->flags = (unsigned) cif->rtype->type;
break;
case FFI_TYPE_UINT64:
#ifdef _WIN64
case FFI_TYPE_POINTER:
#endif
cif->flags = FFI_TYPE_SINT64;
break;
default:
cif->flags = FFI_TYPE_INT;
break;
}
return FFI_OK;
}
#ifdef _WIN32
extern int
ffi_call_x86(void (*)(char *, extended_cif *),
/*@out@*/ extended_cif *,
unsigned, unsigned,
/*@out@*/ unsigned *,
void (*fn)());
#endif
#ifdef _WIN64
extern int
ffi_call_AMD64(void (*)(char *, extended_cif *),
/*@out@*/ extended_cif *,
unsigned, unsigned,
/*@out@*/ unsigned *,
void (*fn)());
#endif
int
ffi_call(/*@dependent@*/ ffi_cif *cif,
void (*fn)(),
/*@out@*/ void *rvalue,
/*@dependent@*/ void **avalue)
{
extended_cif ecif;
ecif.cif = cif;
ecif.avalue = avalue;
/* If the return value is a struct and we don't have a return */
/* value address then we need to make one */
if ((rvalue == NULL) &&
(cif->rtype->type == FFI_TYPE_STRUCT))
{
/*@-sysunrecog@*/
ecif.rvalue = alloca(cif->rtype->size);
/*@=sysunrecog@*/
}
else
ecif.rvalue = rvalue;
switch (cif->abi)
{
#if !defined(_WIN64)
case FFI_SYSV:
case FFI_STDCALL:
return ffi_call_x86(ffi_prep_args, &ecif, cif->bytes,
cif->flags, ecif.rvalue, fn);
break;
#else
case FFI_SYSV:
/*@-usedef@*/
/* Function call needs at least 40 bytes stack size, on win64 AMD64 */
return ffi_call_AMD64(ffi_prep_args, &ecif, cif->bytes ? cif->bytes : 40,
cif->flags, ecif.rvalue, fn);
/*@=usedef@*/
break;
#endif
default:
FFI_ASSERT(0);
break;
}
return -1; /* theller: Hrm. */
}
/** private members **/
static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
void** args, ffi_cif* cif);
/* This function is jumped to by the trampoline */
#ifdef _WIN64
void *
#else
static void __fastcall
#endif
ffi_closure_SYSV (ffi_closure *closure, int *argp)
{
// this is our return value storage
long double res;
// our various things...
ffi_cif *cif;
void **arg_area;
unsigned short rtype;
void *resp = (void*)&res;
void *args = &argp[1];
cif = closure->cif;
arg_area = (void**) alloca (cif->nargs * sizeof (void*));
/* this call will initialize ARG_AREA, such that each
* element in that array points to the corresponding
* value on the stack; and if the function returns
* a structure, it will re-set RESP to point to the
* structure return address. */
ffi_prep_incoming_args_SYSV(args, (void**)&resp, arg_area, cif);
(closure->fun) (cif, resp, arg_area, closure->user_data);
rtype = cif->flags;
#if defined(_WIN32) && !defined(_WIN64)
#ifdef _MSC_VER
/* now, do a generic return based on the value of rtype */
if (rtype == FFI_TYPE_INT)
{
_asm mov eax, resp ;
_asm mov eax, [eax] ;
}
else if (rtype == FFI_TYPE_FLOAT)
{
_asm mov eax, resp ;
_asm fld DWORD PTR [eax] ;
// asm ("flds (%0)" : : "r" (resp) : "st" );
}
else if (rtype == FFI_TYPE_DOUBLE)
{
_asm mov eax, resp ;
_asm fld QWORD PTR [eax] ;
// asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_LONGDOUBLE)
{
// asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_SINT64)
{
_asm mov edx, resp ;
_asm mov eax, [edx] ;
_asm mov edx, [edx + 4] ;
// asm ("movl 0(%0),%%eax;"
// "movl 4(%0),%%edx"
// : : "r"(resp)
// : "eax", "edx");
}
#else
/* now, do a generic return based on the value of rtype */
if (rtype == FFI_TYPE_INT)
{
asm ("movl (%0),%%eax" : : "r" (resp) : "eax");
}
else if (rtype == FFI_TYPE_FLOAT)
{
asm ("flds (%0)" : : "r" (resp) : "st" );
}
else if (rtype == FFI_TYPE_DOUBLE)
{
asm ("fldl (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_LONGDOUBLE)
{
asm ("fldt (%0)" : : "r" (resp) : "st", "st(1)" );
}
else if (rtype == FFI_TYPE_SINT64)
{
asm ("movl 0(%0),%%eax;"
"movl 4(%0),%%edx"
: : "r"(resp)
: "eax", "edx");
}
#endif
#endif
#ifdef _WIN64
/* The result is returned in rax. This does the right thing for
result types except for floats; we have to 'mov xmm0, rax' in the
caller to correct this.
*/
return *(void **)resp;
#endif
}
/*@-exportheader@*/
static void
ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
void **avalue, ffi_cif *cif)
/*@=exportheader@*/
{
register unsigned int i;
register void **p_argv;
register char *argp;
register ffi_type **p_arg;
argp = stack;
if ( cif->rtype->type == FFI_TYPE_STRUCT ) {
*rvalue = *(void **) argp;
argp += 4;
}
p_argv = avalue;
for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
{
size_t z;
/* Align if necessary */
if ((sizeof(char *) - 1) & (size_t) argp) {
argp = (char *) ALIGN(argp, sizeof(char*));
}
z = (*p_arg)->size;
/* because we're little endian, this is what it turns into. */
*p_argv = (void*) argp;
p_argv++;
argp += z;
}
return;
}
/* the cif must already be prep'ed */
extern void ffi_closure_OUTER();
ffi_status
ffi_prep_closure_loc (ffi_closure* closure,
ffi_cif* cif,
void (*fun)(ffi_cif*,void*,void**,void*),
void *user_data,
void *codeloc)
{
short bytes;
char *tramp;
#ifdef _WIN64
int mask = 0;
#endif
FFI_ASSERT (cif->abi == FFI_SYSV);
if (cif->abi == FFI_SYSV)
bytes = 0;
#if !defined(_WIN64)
else if (cif->abi == FFI_STDCALL)
bytes = cif->bytes;
#endif
else
return FFI_BAD_ABI;
tramp = &closure->tramp[0];
#define BYTES(text) memcpy(tramp, text, sizeof(text)), tramp += sizeof(text)-1
#define POINTER(x) *(void**)tramp = (void*)(x), tramp += sizeof(void*)
#define SHORT(x) *(short*)tramp = x, tramp += sizeof(short)
#define INT(x) *(int*)tramp = x, tramp += sizeof(int)
#ifdef _WIN64
if (cif->nargs >= 1 &&
(cif->arg_types[0]->type == FFI_TYPE_FLOAT
|| cif->arg_types[0]->type == FFI_TYPE_DOUBLE))
mask |= 1;
if (cif->nargs >= 2 &&
(cif->arg_types[1]->type == FFI_TYPE_FLOAT
|| cif->arg_types[1]->type == FFI_TYPE_DOUBLE))
mask |= 2;
if (cif->nargs >= 3 &&
(cif->arg_types[2]->type == FFI_TYPE_FLOAT
|| cif->arg_types[2]->type == FFI_TYPE_DOUBLE))
mask |= 4;
if (cif->nargs >= 4 &&
(cif->arg_types[3]->type == FFI_TYPE_FLOAT
|| cif->arg_types[3]->type == FFI_TYPE_DOUBLE))
mask |= 8;
/* 41 BB ---- mov r11d,mask */
BYTES("\x41\xBB"); INT(mask);
/* 48 B8 -------- mov rax, closure */
BYTES("\x48\xB8"); POINTER(closure);
/* 49 BA -------- mov r10, ffi_closure_OUTER */
BYTES("\x49\xBA"); POINTER(ffi_closure_OUTER);
/* 41 FF E2 jmp r10 */
BYTES("\x41\xFF\xE2");
#else
/* mov ecx, closure */
BYTES("\xb9"); POINTER(closure);
/* mov edx, esp */
BYTES("\x8b\xd4");
/* call ffi_closure_SYSV */
BYTES("\xe8"); POINTER((char*)&ffi_closure_SYSV - (tramp + 4));
/* ret bytes */
BYTES("\xc2");
SHORT(bytes);
#endif
if (tramp - &closure->tramp[0] > FFI_TRAMPOLINE_SIZE)
Py_FatalError("FFI_TRAMPOLINE_SIZE too small in " __FILE__);
closure->cif = cif;
closure->user_data = user_data;
closure->fun = fun;
return FFI_OK;
}

View file

@ -0,0 +1,175 @@
/* -----------------------------------------------------------------------
prep_cif.c - Copyright (c) 1996, 1998 Red Hat, Inc.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
#include <stdlib.h>
/* Round up to FFI_SIZEOF_ARG. */
#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
/* Perform machine independent initialization of aggregate type
specifications. */
static ffi_status initialize_aggregate(/*@out@*/ ffi_type *arg)
{
ffi_type **ptr;
FFI_ASSERT(arg != NULL);
/*@-usedef@*/
FFI_ASSERT(arg->elements != NULL);
FFI_ASSERT(arg->size == 0);
FFI_ASSERT(arg->alignment == 0);
ptr = &(arg->elements[0]);
while ((*ptr) != NULL)
{
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type */
FFI_ASSERT_VALID_TYPE(*ptr);
arg->size = ALIGN(arg->size, (*ptr)->alignment);
arg->size += (*ptr)->size;
arg->alignment = (arg->alignment > (*ptr)->alignment) ?
arg->alignment : (*ptr)->alignment;
ptr++;
}
/* Structure size includes tail padding. This is important for
structures that fit in one register on ABIs like the PowerPC64
Linux ABI that right justify small structs in a register.
It's also needed for nested structure layout, for example
struct A { long a; char b; }; struct B { struct A x; char y; };
should find y at an offset of 2*sizeof(long) and result in a
total size of 3*sizeof(long). */
arg->size = ALIGN (arg->size, arg->alignment);
if (arg->size == 0)
return FFI_BAD_TYPEDEF;
else
return FFI_OK;
/*@=usedef@*/
}
/* Perform machine independent ffi_cif preparation, then call
machine dependent routine. */
ffi_status ffi_prep_cif(/*@out@*/ /*@partial@*/ ffi_cif *cif,
ffi_abi abi, unsigned int nargs,
/*@dependent@*/ /*@out@*/ /*@partial@*/ ffi_type *rtype,
/*@dependent@*/ ffi_type **atypes)
{
unsigned bytes = 0;
unsigned int i;
ffi_type **ptr;
FFI_ASSERT(cif != NULL);
FFI_ASSERT((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
cif->abi = abi;
cif->arg_types = atypes;
cif->nargs = nargs;
cif->rtype = rtype;
cif->flags = 0;
/* Initialize the return type if necessary */
/*@-usedef@*/
if ((cif->rtype->size == 0) && (initialize_aggregate(cif->rtype) != FFI_OK))
return FFI_BAD_TYPEDEF;
/*@=usedef@*/
/* Perform a sanity check on the return type */
FFI_ASSERT_VALID_TYPE(cif->rtype);
/* x86-64 and s390 stack space allocation is handled in prep_machdep. */
#if !defined M68K && !defined __x86_64__ && !defined S390
/* Make space for the return structure pointer */
if (cif->rtype->type == FFI_TYPE_STRUCT
/* MSVC returns small structures in registers. But we have a different
workaround: pretend int32 or int64 return type, and converting to
structure afterwards. */
#ifdef SPARC
&& (cif->abi != FFI_V9 || cif->rtype->size > 32)
#endif
)
bytes = STACK_ARG_SIZE(sizeof(void*));
#endif
for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
{
/* Initialize any uninitialized aggregate type definitions */
if (((*ptr)->size == 0) && (initialize_aggregate((*ptr)) != FFI_OK))
return FFI_BAD_TYPEDEF;
/* Perform a sanity check on the argument type, do this
check after the initialization. */
FFI_ASSERT_VALID_TYPE(*ptr);
#if !defined __x86_64__ && !defined S390
#ifdef SPARC
if (((*ptr)->type == FFI_TYPE_STRUCT
&& ((*ptr)->size > 16 || cif->abi != FFI_V9))
|| ((*ptr)->type == FFI_TYPE_LONGDOUBLE
&& cif->abi != FFI_V9))
bytes += sizeof(void*);
else
#endif
{
#if !defined(_MSC_VER) && !defined(__MINGW32__)
/* Don't know if this is a libffi bug or not. At least on
Windows with MSVC, function call parameters are *not*
aligned in the same way as structure fields are, they are
only aligned in integer boundaries.
This doesn't do any harm for cdecl functions and closures,
since the caller cleans up the stack, but it is wrong for
stdcall functions where the callee cleans.
*/
/* Add any padding if necessary */
if (((*ptr)->alignment - 1) & bytes)
bytes = ALIGN(bytes, (*ptr)->alignment);
#endif
bytes += STACK_ARG_SIZE((*ptr)->size);
}
#endif
}
cif->bytes = bytes;
/* Perform machine dependent cif processing */
return ffi_prep_cif_machdep(cif);
}

View file

@ -0,0 +1,104 @@
/* -----------------------------------------------------------------------
types.c - Copyright (c) 1996, 1998 Red Hat, Inc.
Predefined ffi_types needed by libffi.
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
#include <ffi.h>
#include <ffi_common.h>
/* Type definitions */
#define FFI_INTEGRAL_TYPEDEF(n, s, a, t) ffi_type ffi_type_##n = { s, a, t, NULL }
#define FFI_AGGREGATE_TYPEDEF(n, e) ffi_type ffi_type_##n = { 0, 0, FFI_TYPE_STRUCT, e }
/* Size and alignment are fake here. They must not be 0. */
FFI_INTEGRAL_TYPEDEF(void, 1, 1, FFI_TYPE_VOID);
FFI_INTEGRAL_TYPEDEF(uint8, 1, 1, FFI_TYPE_UINT8);
FFI_INTEGRAL_TYPEDEF(sint8, 1, 1, FFI_TYPE_SINT8);
FFI_INTEGRAL_TYPEDEF(uint16, 2, 2, FFI_TYPE_UINT16);
FFI_INTEGRAL_TYPEDEF(sint16, 2, 2, FFI_TYPE_SINT16);
FFI_INTEGRAL_TYPEDEF(uint32, 4, 4, FFI_TYPE_UINT32);
FFI_INTEGRAL_TYPEDEF(sint32, 4, 4, FFI_TYPE_SINT32);
FFI_INTEGRAL_TYPEDEF(float, 4, 4, FFI_TYPE_FLOAT);
#if defined ALPHA || defined SPARC64 || defined X86_64 || defined S390X \
|| defined IA64
FFI_INTEGRAL_TYPEDEF(pointer, 8, 8, FFI_TYPE_POINTER);
#else
FFI_INTEGRAL_TYPEDEF(pointer, 4, 4, FFI_TYPE_POINTER);
#endif
#if defined X86 || defined X86_WIN32 || defined ARM || defined M68K
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
#elif defined SH
FFI_INTEGRAL_TYPEDEF(uint64, 8, 4, FFI_TYPE_UINT64);
FFI_INTEGRAL_TYPEDEF(sint64, 8, 4, FFI_TYPE_SINT64);
#else
FFI_INTEGRAL_TYPEDEF(uint64, 8, 8, FFI_TYPE_UINT64);
FFI_INTEGRAL_TYPEDEF(sint64, 8, 8, FFI_TYPE_SINT64);
#endif
#if defined X86 || defined X86_WIN32 || defined M68K
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 12, 4, FFI_TYPE_LONGDOUBLE);
#elif defined ARM || defined SH || defined POWERPC_AIX || defined POWERPC_DARWIN
FFI_INTEGRAL_TYPEDEF(double, 8, 4, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 8, 4, FFI_TYPE_LONGDOUBLE);
#elif defined SPARC
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
#ifdef SPARC64
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
#else
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 8, FFI_TYPE_LONGDOUBLE);
#endif
#elif defined X86_64
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 16, 16, FFI_TYPE_LONGDOUBLE);
#else
FFI_INTEGRAL_TYPEDEF(double, 8, 8, FFI_TYPE_DOUBLE);
FFI_INTEGRAL_TYPEDEF(longdouble, 8, 8, FFI_TYPE_LONGDOUBLE);
#endif

View file

@ -0,0 +1,162 @@
/* -----------------------------------------------------------------------
win32.S - Copyright (c) 1996, 1998, 2001, 2002 Red Hat, Inc.
Copyright (c) 2001 John Beniton
Copyright (c) 2002 Ranjit Mathew
X86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL CYGNUS SOLUTIONS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
----------------------------------------------------------------------- */
/* theller: almost verbatim translation from gas syntax to MSVC inline
assembler code. */
/* theller: ffi_call_x86 now returns an integer - the difference of the stack
pointer before and after the function call. If everything is ok, zero is
returned. If stdcall functions are passed the wrong number of arguments,
the difference will be nonzero. */
#include <ffi.h>
#include <ffi_common.h>
__declspec(naked) int
ffi_call_x86(void (* prepfunc)(char *, extended_cif *), /* 8 */
extended_cif *ecif, /* 12 */
unsigned bytes, /* 16 */
unsigned flags, /* 20 */
unsigned *rvalue, /* 24 */
void (*fn)()) /* 28 */
{
_asm {
push ebp
mov ebp, esp
push esi // NEW: this register must be preserved across function calls
// XXX SAVE ESP NOW!
mov esi, esp // save stack pointer before the call
// Make room for all of the new args.
mov ecx, [ebp+16]
sub esp, ecx // sub esp, bytes
mov eax, esp
// Place all of the ffi_prep_args in position
push [ebp + 12] // ecif
push eax
call [ebp + 8] // prepfunc
// Return stack to previous state and call the function
add esp, 8
// FIXME: Align the stack to a 128-bit boundary to avoid
// potential performance hits.
call [ebp + 28]
// Load ecif->cif->abi
mov ecx, [ebp + 12]
mov ecx, [ecx]ecif.cif
mov ecx, [ecx]ecif.cif.abi
cmp ecx, FFI_STDCALL
je noclean
// STDCALL: Remove the space we pushed for the args
mov ecx, [ebp + 16]
add esp, ecx
// CDECL: Caller has already cleaned the stack
noclean:
// Check that esp has the same value as before!
sub esi, esp
// Load %ecx with the return type code
mov ecx, [ebp + 20]
// If the return value pointer is NULL, assume no return value.
/*
Intel asm is weird. We have to explicitely specify 'DWORD PTR' in the nexr instruction,
otherwise only one BYTE will be compared (instead of a DWORD)!
*/
cmp DWORD PTR [ebp + 24], 0
jne sc_retint
// Even if there is no space for the return value, we are
// obliged to handle floating-point values.
cmp ecx, FFI_TYPE_FLOAT
jne sc_noretval
// fstp %st(0)
fstp st(0)
jmp sc_epilogue
sc_retint:
cmp ecx, FFI_TYPE_INT
jne sc_retfloat
// # Load %ecx with the pointer to storage for the return value
mov ecx, [ebp + 24]
mov [ecx + 0], eax
jmp sc_epilogue
sc_retfloat:
cmp ecx, FFI_TYPE_FLOAT
jne sc_retdouble
// Load %ecx with the pointer to storage for the return value
mov ecx, [ebp+24]
// fstps (%ecx)
fstp DWORD PTR [ecx]
jmp sc_epilogue
sc_retdouble:
cmp ecx, FFI_TYPE_DOUBLE
jne sc_retlongdouble
// movl 24(%ebp),%ecx
mov ecx, [ebp+24]
fstp QWORD PTR [ecx]
jmp sc_epilogue
jmp sc_retlongdouble // avoid warning about unused label
sc_retlongdouble:
cmp ecx, FFI_TYPE_LONGDOUBLE
jne sc_retint64
// Load %ecx with the pointer to storage for the return value
mov ecx, [ebp+24]
// fstpt (%ecx)
fstp QWORD PTR [ecx] /* XXX ??? */
jmp sc_epilogue
sc_retint64:
cmp ecx, FFI_TYPE_SINT64
jne sc_retstruct
// Load %ecx with the pointer to storage for the return value
mov ecx, [ebp+24]
mov [ecx+0], eax
mov [ecx+4], edx
sc_retstruct:
// Nothing to do!
sc_noretval:
sc_epilogue:
mov eax, esi
pop esi // NEW restore: must be preserved across function calls
mov esp, ebp
pop ebp
ret
}
}

View file

@ -0,0 +1,470 @@
/* -----------------------------------------------------------------------
win32.S - Copyright (c) 1996, 1998, 2001, 2002, 2009 Red Hat, Inc.
Copyright (c) 2001 John Beniton
Copyright (c) 2002 Ranjit Mathew
Copyright (c) 2009 Daniel Witte
X86 Foreign Function Interface
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
``Software''), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-----------------------------------------------------------------------
*/
#define LIBFFI_ASM
#include <fficonfig.h>
#include <ffi.h>
.386
.MODEL FLAT, C
EXTRN ffi_closure_SYSV_inner:NEAR
_TEXT SEGMENT
ffi_call_win32 PROC NEAR,
ffi_prep_args : NEAR PTR DWORD,
ecif : NEAR PTR DWORD,
cif_abi : DWORD,
cif_bytes : DWORD,
cif_flags : DWORD,
rvalue : NEAR PTR DWORD,
fn : NEAR PTR DWORD
;; Make room for all of the new args.
mov ecx, cif_bytes
sub esp, ecx
mov eax, esp
;; Place all of the ffi_prep_args in position
push ecif
push eax
call ffi_prep_args
;; Return stack to previous state and call the function
add esp, 8
;; Handle thiscall and fastcall
cmp cif_abi, 3 ;; FFI_THISCALL
jz do_thiscall
cmp cif_abi, 4 ;; FFI_FASTCALL
jnz do_stdcall
mov ecx, DWORD PTR [esp]
mov edx, DWORD PTR [esp+4]
add esp, 8
jmp do_stdcall
do_thiscall:
mov ecx, DWORD PTR [esp]
add esp, 4
do_stdcall:
call fn
;; cdecl: we restore esp in the epilogue, so there's no need to
;; remove the space we pushed for the args.
;; stdcall: the callee has already cleaned the stack.
;; Load ecx with the return type code
mov ecx, cif_flags
;; If the return value pointer is NULL, assume no return value.
cmp rvalue, 0
jne ca_jumptable
;; Even if there is no space for the return value, we are
;; obliged to handle floating-point values.
cmp ecx, FFI_TYPE_FLOAT
jne ca_epilogue
fstp st(0)
jmp ca_epilogue
ca_jumptable:
jmp [ca_jumpdata + 4 * ecx]
ca_jumpdata:
;; Do not insert anything here between label and jump table.
dd offset ca_epilogue ;; FFI_TYPE_VOID
dd offset ca_retint ;; FFI_TYPE_INT
dd offset ca_retfloat ;; FFI_TYPE_FLOAT
dd offset ca_retdouble ;; FFI_TYPE_DOUBLE
dd offset ca_retlongdouble ;; FFI_TYPE_LONGDOUBLE
dd offset ca_retuint8 ;; FFI_TYPE_UINT8
dd offset ca_retsint8 ;; FFI_TYPE_SINT8
dd offset ca_retuint16 ;; FFI_TYPE_UINT16
dd offset ca_retsint16 ;; FFI_TYPE_SINT16
dd offset ca_retint ;; FFI_TYPE_UINT32
dd offset ca_retint ;; FFI_TYPE_SINT32
dd offset ca_retint64 ;; FFI_TYPE_UINT64
dd offset ca_retint64 ;; FFI_TYPE_SINT64
dd offset ca_epilogue ;; FFI_TYPE_STRUCT
dd offset ca_retint ;; FFI_TYPE_POINTER
dd offset ca_retstruct1b ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset ca_retstruct2b ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset ca_retint ;; FFI_TYPE_SMALL_STRUCT_4B
dd offset ca_epilogue ;; FFI_TYPE_MS_STRUCT
/* Sign/zero extend as appropriate. */
ca_retuint8:
movzx eax, al
jmp ca_retint
ca_retsint8:
movsx eax, al
jmp ca_retint
ca_retuint16:
movzx eax, ax
jmp ca_retint
ca_retsint16:
movsx eax, ax
jmp ca_retint
ca_retint:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
mov [ecx + 0], eax
jmp ca_epilogue
ca_retint64:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
mov [ecx + 0], eax
mov [ecx + 4], edx
jmp ca_epilogue
ca_retfloat:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
fstp DWORD PTR [ecx]
jmp ca_epilogue
ca_retdouble:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
fstp QWORD PTR [ecx]
jmp ca_epilogue
ca_retlongdouble:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
fstp TBYTE PTR [ecx]
jmp ca_epilogue
ca_retstruct1b:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
mov [ecx + 0], al
jmp ca_epilogue
ca_retstruct2b:
;; Load %ecx with the pointer to storage for the return value
mov ecx, rvalue
mov [ecx + 0], ax
jmp ca_epilogue
ca_epilogue:
;; Epilogue code is autogenerated.
ret
ffi_call_win32 ENDP
ffi_closure_THISCALL PROC NEAR FORCEFRAME
sub esp, 40
lea edx, [ebp -24]
mov [ebp - 12], edx /* resp */
lea edx, [ebp + 12] /* account for stub return address on stack */
jmp stub
ffi_closure_THISCALL ENDP
ffi_closure_SYSV PROC NEAR FORCEFRAME
;; the ffi_closure ctx is passed in eax by the trampoline.
sub esp, 40
lea edx, [ebp - 24]
mov [ebp - 12], edx ;; resp
lea edx, [ebp + 8]
stub::
mov [esp + 8], edx ;; args
lea edx, [ebp - 12]
mov [esp + 4], edx ;; &resp
mov [esp], eax ;; closure
call ffi_closure_SYSV_inner
mov ecx, [ebp - 12]
cs_jumptable:
jmp [cs_jumpdata + 4 * eax]
cs_jumpdata:
;; Do not insert anything here between the label and jump table.
dd offset cs_epilogue ;; FFI_TYPE_VOID
dd offset cs_retint ;; FFI_TYPE_INT
dd offset cs_retfloat ;; FFI_TYPE_FLOAT
dd offset cs_retdouble ;; FFI_TYPE_DOUBLE
dd offset cs_retlongdouble ;; FFI_TYPE_LONGDOUBLE
dd offset cs_retuint8 ;; FFI_TYPE_UINT8
dd offset cs_retsint8 ;; FFI_TYPE_SINT8
dd offset cs_retuint16 ;; FFI_TYPE_UINT16
dd offset cs_retsint16 ;; FFI_TYPE_SINT16
dd offset cs_retint ;; FFI_TYPE_UINT32
dd offset cs_retint ;; FFI_TYPE_SINT32
dd offset cs_retint64 ;; FFI_TYPE_UINT64
dd offset cs_retint64 ;; FFI_TYPE_SINT64
dd offset cs_retstruct ;; FFI_TYPE_STRUCT
dd offset cs_retint ;; FFI_TYPE_POINTER
dd offset cs_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset cs_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset cs_retint ;; FFI_TYPE_SMALL_STRUCT_4B
dd offset cs_retmsstruct ;; FFI_TYPE_MS_STRUCT
cs_retuint8:
movzx eax, BYTE PTR [ecx]
jmp cs_epilogue
cs_retsint8:
movsx eax, BYTE PTR [ecx]
jmp cs_epilogue
cs_retuint16:
movzx eax, WORD PTR [ecx]
jmp cs_epilogue
cs_retsint16:
movsx eax, WORD PTR [ecx]
jmp cs_epilogue
cs_retint:
mov eax, [ecx]
jmp cs_epilogue
cs_retint64:
mov eax, [ecx + 0]
mov edx, [ecx + 4]
jmp cs_epilogue
cs_retfloat:
fld DWORD PTR [ecx]
jmp cs_epilogue
cs_retdouble:
fld QWORD PTR [ecx]
jmp cs_epilogue
cs_retlongdouble:
fld TBYTE PTR [ecx]
jmp cs_epilogue
cs_retstruct:
;; Caller expects us to pop struct return value pointer hidden arg.
;; Epilogue code is autogenerated.
ret 4
cs_retmsstruct:
;; Caller expects us to return a pointer to the real return value.
mov eax, ecx
;; Caller doesn't expects us to pop struct return value pointer hidden arg.
jmp cs_epilogue
cs_epilogue:
;; Epilogue code is autogenerated.
ret
ffi_closure_SYSV ENDP
#if !FFI_NO_RAW_API
#define RAW_CLOSURE_CIF_OFFSET ((FFI_TRAMPOLINE_SIZE + 3) AND NOT 3)
#define RAW_CLOSURE_FUN_OFFSET (RAW_CLOSURE_CIF_OFFSET + 4)
#define RAW_CLOSURE_USER_DATA_OFFSET (RAW_CLOSURE_FUN_OFFSET + 4)
#define CIF_FLAGS_OFFSET 20
ffi_closure_raw_THISCALL PROC NEAR USES esi FORCEFRAME
sub esp, 36
mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif
mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data
mov [esp + 12], edx
lea edx, [ebp + 12]
jmp stubraw
ffi_closure_raw_THISCALL ENDP
ffi_closure_raw_SYSV PROC NEAR USES esi FORCEFRAME
;; the ffi_closure ctx is passed in eax by the trampoline.
sub esp, 40
mov esi, [eax + RAW_CLOSURE_CIF_OFFSET] ;; closure->cif
mov edx, [eax + RAW_CLOSURE_USER_DATA_OFFSET] ;; closure->user_data
mov [esp + 12], edx ;; user_data
lea edx, [ebp + 8]
stubraw::
mov [esp + 8], edx ;; raw_args
lea edx, [ebp - 24]
mov [esp + 4], edx ;; &res
mov [esp], esi ;; cif
call DWORD PTR [eax + RAW_CLOSURE_FUN_OFFSET] ;; closure->fun
mov eax, [esi + CIF_FLAGS_OFFSET] ;; cif->flags
lea ecx, [ebp - 24]
cr_jumptable:
jmp [cr_jumpdata + 4 * eax]
cr_jumpdata:
;; Do not insert anything here between the label and jump table.
dd offset cr_epilogue ;; FFI_TYPE_VOID
dd offset cr_retint ;; FFI_TYPE_INT
dd offset cr_retfloat ;; FFI_TYPE_FLOAT
dd offset cr_retdouble ;; FFI_TYPE_DOUBLE
dd offset cr_retlongdouble ;; FFI_TYPE_LONGDOUBLE
dd offset cr_retuint8 ;; FFI_TYPE_UINT8
dd offset cr_retsint8 ;; FFI_TYPE_SINT8
dd offset cr_retuint16 ;; FFI_TYPE_UINT16
dd offset cr_retsint16 ;; FFI_TYPE_SINT16
dd offset cr_retint ;; FFI_TYPE_UINT32
dd offset cr_retint ;; FFI_TYPE_SINT32
dd offset cr_retint64 ;; FFI_TYPE_UINT64
dd offset cr_retint64 ;; FFI_TYPE_SINT64
dd offset cr_epilogue ;; FFI_TYPE_STRUCT
dd offset cr_retint ;; FFI_TYPE_POINTER
dd offset cr_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset cr_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset cr_retint ;; FFI_TYPE_SMALL_STRUCT_4B
dd offset cr_epilogue ;; FFI_TYPE_MS_STRUCT
cr_retuint8:
movzx eax, BYTE PTR [ecx]
jmp cr_epilogue
cr_retsint8:
movsx eax, BYTE PTR [ecx]
jmp cr_epilogue
cr_retuint16:
movzx eax, WORD PTR [ecx]
jmp cr_epilogue
cr_retsint16:
movsx eax, WORD PTR [ecx]
jmp cr_epilogue
cr_retint:
mov eax, [ecx]
jmp cr_epilogue
cr_retint64:
mov eax, [ecx + 0]
mov edx, [ecx + 4]
jmp cr_epilogue
cr_retfloat:
fld DWORD PTR [ecx]
jmp cr_epilogue
cr_retdouble:
fld QWORD PTR [ecx]
jmp cr_epilogue
cr_retlongdouble:
fld TBYTE PTR [ecx]
jmp cr_epilogue
cr_epilogue:
;; Epilogue code is autogenerated.
ret
ffi_closure_raw_SYSV ENDP
#endif /* !FFI_NO_RAW_API */
ffi_closure_STDCALL PROC NEAR FORCEFRAME
;; the ffi_closure ctx is passed in eax by the trampoline.
sub esp, 40
lea edx, [ebp - 24]
mov [ebp - 12], edx ;; resp
lea edx, [ebp + 12] ;; account for stub return address on stack
mov [esp + 8], edx ;; args
lea edx, [ebp - 12]
mov [esp + 4], edx ;; &resp
mov [esp], eax ;; closure
call ffi_closure_SYSV_inner
mov ecx, [ebp - 12]
cd_jumptable:
jmp [cd_jumpdata + 4 * eax]
cd_jumpdata:
;; Do not insert anything here between the label and jump table.
dd offset cd_epilogue ;; FFI_TYPE_VOID
dd offset cd_retint ;; FFI_TYPE_INT
dd offset cd_retfloat ;; FFI_TYPE_FLOAT
dd offset cd_retdouble ;; FFI_TYPE_DOUBLE
dd offset cd_retlongdouble ;; FFI_TYPE_LONGDOUBLE
dd offset cd_retuint8 ;; FFI_TYPE_UINT8
dd offset cd_retsint8 ;; FFI_TYPE_SINT8
dd offset cd_retuint16 ;; FFI_TYPE_UINT16
dd offset cd_retsint16 ;; FFI_TYPE_SINT16
dd offset cd_retint ;; FFI_TYPE_UINT32
dd offset cd_retint ;; FFI_TYPE_SINT32
dd offset cd_retint64 ;; FFI_TYPE_UINT64
dd offset cd_retint64 ;; FFI_TYPE_SINT64
dd offset cd_epilogue ;; FFI_TYPE_STRUCT
dd offset cd_retint ;; FFI_TYPE_POINTER
dd offset cd_retsint8 ;; FFI_TYPE_SMALL_STRUCT_1B
dd offset cd_retsint16 ;; FFI_TYPE_SMALL_STRUCT_2B
dd offset cd_retint ;; FFI_TYPE_SMALL_STRUCT_4B
cd_retuint8:
movzx eax, BYTE PTR [ecx]
jmp cd_epilogue
cd_retsint8:
movsx eax, BYTE PTR [ecx]
jmp cd_epilogue
cd_retuint16:
movzx eax, WORD PTR [ecx]
jmp cd_epilogue
cd_retsint16:
movsx eax, WORD PTR [ecx]
jmp cd_epilogue
cd_retint:
mov eax, [ecx]
jmp cd_epilogue
cd_retint64:
mov eax, [ecx + 0]
mov edx, [ecx + 4]
jmp cd_epilogue
cd_retfloat:
fld DWORD PTR [ecx]
jmp cd_epilogue
cd_retdouble:
fld QWORD PTR [ecx]
jmp cd_epilogue
cd_retlongdouble:
fld TBYTE PTR [ecx]
jmp cd_epilogue
cd_epilogue:
;; Epilogue code is autogenerated.
ret
ffi_closure_STDCALL ENDP
_TEXT ENDS
END

View file

@ -0,0 +1,156 @@
PUBLIC ffi_call_AMD64
EXTRN __chkstk:NEAR
EXTRN ffi_closure_SYSV:NEAR
_TEXT SEGMENT
;;; ffi_closure_OUTER will be called with these registers set:
;;; rax points to 'closure'
;;; r11 contains a bit mask that specifies which of the
;;; first four parameters are float or double
;;;
;;; It must move the parameters passed in registers to their stack location,
;;; call ffi_closure_SYSV for the actual work, then return the result.
;;;
ffi_closure_OUTER PROC FRAME
;; save actual arguments to their stack space.
test r11, 1
jne first_is_float
mov QWORD PTR [rsp+8], rcx
jmp second
first_is_float:
movlpd QWORD PTR [rsp+8], xmm0
second:
test r11, 2
jne second_is_float
mov QWORD PTR [rsp+16], rdx
jmp third
second_is_float:
movlpd QWORD PTR [rsp+16], xmm1
third:
test r11, 4
jne third_is_float
mov QWORD PTR [rsp+24], r8
jmp forth
third_is_float:
movlpd QWORD PTR [rsp+24], xmm2
forth:
test r11, 8
jne forth_is_float
mov QWORD PTR [rsp+32], r9
jmp done
forth_is_float:
movlpd QWORD PTR [rsp+32], xmm3
done:
.ALLOCSTACK 40
sub rsp, 40
.ENDPROLOG
mov rcx, rax ; context is first parameter
mov rdx, rsp ; stack is second parameter
add rdx, 40 ; correct our own area
mov rax, ffi_closure_SYSV
call rax ; call the real closure function
;; Here, code is missing that handles float return values
add rsp, 40
movd xmm0, rax ; In case the closure returned a float.
ret 0
ffi_closure_OUTER ENDP
;;; ffi_call_AMD64
stack$ = 0
prepfunc$ = 32
ecif$ = 40
bytes$ = 48
flags$ = 56
rvalue$ = 64
fn$ = 72
ffi_call_AMD64 PROC FRAME
mov QWORD PTR [rsp+32], r9
mov QWORD PTR [rsp+24], r8
mov QWORD PTR [rsp+16], rdx
mov QWORD PTR [rsp+8], rcx
.PUSHREG rbp
push rbp
.ALLOCSTACK 48
sub rsp, 48 ; 00000030H
.SETFRAME rbp, 32
lea rbp, QWORD PTR [rsp+32]
.ENDPROLOG
mov eax, DWORD PTR bytes$[rbp]
add rax, 15
and rax, -16
call __chkstk
sub rsp, rax
lea rax, QWORD PTR [rsp+32]
mov QWORD PTR stack$[rbp], rax
mov rdx, QWORD PTR ecif$[rbp]
mov rcx, QWORD PTR stack$[rbp]
call QWORD PTR prepfunc$[rbp]
mov rsp, QWORD PTR stack$[rbp]
movlpd xmm3, QWORD PTR [rsp+24]
movd r9, xmm3
movlpd xmm2, QWORD PTR [rsp+16]
movd r8, xmm2
movlpd xmm1, QWORD PTR [rsp+8]
movd rdx, xmm1
movlpd xmm0, QWORD PTR [rsp]
movd rcx, xmm0
call QWORD PTR fn$[rbp]
ret_int$:
cmp DWORD PTR flags$[rbp], 1 ; FFI_TYPE_INT
jne ret_float$
mov rcx, QWORD PTR rvalue$[rbp]
mov DWORD PTR [rcx], eax
jmp SHORT ret_nothing$
ret_float$:
cmp DWORD PTR flags$[rbp], 2 ; FFI_TYPE_FLOAT
jne SHORT ret_double$
mov rax, QWORD PTR rvalue$[rbp]
movlpd QWORD PTR [rax], xmm0
jmp SHORT ret_nothing$
ret_double$:
cmp DWORD PTR flags$[rbp], 3 ; FFI_TYPE_DOUBLE
jne SHORT ret_int64$
mov rax, QWORD PTR rvalue$[rbp]
movlpd QWORD PTR [rax], xmm0
jmp SHORT ret_nothing$
ret_int64$:
cmp DWORD PTR flags$[rbp], 12 ; FFI_TYPE_SINT64
jne ret_nothing$
mov rcx, QWORD PTR rvalue$[rbp]
mov QWORD PTR [rcx], rax
jmp SHORT ret_nothing$
ret_nothing$:
xor eax, eax
lea rsp, QWORD PTR [rbp+16]
pop rbp
ret 0
ffi_call_AMD64 ENDP
_TEXT ENDS
END

View file

@ -19,7 +19,7 @@ when defined(Windows):
type
my_bool* = bool
Pmy_bool* = ptr my_bool
PVIO* = Pointer
PVIO* = pointer
Pgptr* = ptr gptr
gptr* = cstring
Pmy_socket* = ptr my_socket
@ -645,7 +645,7 @@ type
next_slave*: Pst_mysql
last_used_slave*: Pst_mysql # needed for round-robin slave pick
last_used_con*: Pst_mysql # needed for send/read/store/use result to work correctly with replication
stmts*: Pointer # was PList, list of all statements
stmts*: pointer # was PList, list of all statements
methods*: Pst_mysql_methods
thd*: pointer # Points to boolean flag in MYSQL_RES or MYSQL_STMT. We set this flag
# from mysql_stmt_close if close had to cancel result set of this object.

View file

@ -243,7 +243,7 @@ type
# remain compatible.
type
Textra*{.pure, final.} = object
TExtra*{.pure, final.} = object
flags*: int ## Bits for which fields are set
study_data*: pointer ## Opaque data from pcre_study()
match_limit*: int ## Maximum number of calls to match()
@ -260,7 +260,7 @@ type
# without modification.
type
Tcallout_block*{.pure, final.} = object
TCalloutBlock*{.pure, final.} = object
version*: cint ## Identifies version of block
callout_number*: cint ## Number compiled into pattern
offset_vector*: ptr cint ## The offset vector
@ -284,7 +284,7 @@ type
# User defined callback which provides a stack just before the match starts.
type
Tjit_callback* = proc(p: pointer): ptr Tjit_stack{.cdecl.}
TJitCallback* = proc(p: pointer): ptr Tjit_stack{.cdecl.}
# Exported PCRE functions
@ -303,18 +303,18 @@ proc copy_substring*(a2: cstring, a3: ptr cint, a4: cint, a5: cint,
a6: cstring,
a7: cint): cint{.cdecl, importc: "pcre_copy_substring",
pcreImport.}
proc dfa_exec*(a2: ptr TPcre, a3: ptr Textra, a4: cstring, a5: cint,
proc dfa_exec*(a2: ptr TPcre, a3: ptr TExtra, a4: cstring, a5: cint,
a6: cint, a7: cint, a8: ptr cint, a9: cint, a10: ptr cint,
a11: cint): cint{.cdecl, importc: "pcre_dfa_exec",
pcreImport.}
proc exec*(a2: ptr TPcre, a3: ptr Textra, a4: cstring, a5: cint, a6: cint,
proc exec*(a2: ptr TPcre, a3: ptr TExtra, a4: cstring, a5: cint, a6: cint,
a7: cint, a8: ptr cint, a9: cint): cint {.
cdecl, importc: "pcre_exec", pcreImport.}
proc free_substring*(a2: cstring){.cdecl, importc: "pcre_free_substring",
pcreImport.}
proc free_substring_list*(a2: cstringArray){.cdecl,
importc: "pcre_free_substring_list", pcreImport.}
proc fullinfo*(a2: ptr TPcre, a3: ptr Textra, a4: cint, a5: pointer): cint{.
proc fullinfo*(a2: ptr TPcre, a3: ptr TExtra, a4: cint, a5: pointer): cint{.
cdecl, importc: "pcre_fullinfo", pcreImport.}
proc get_named_substring*(a2: ptr TPcre, a3: cstring, a4: ptr cint, a5: cint,
a6: cstring, a7: cstringArray): cint{.cdecl,
@ -334,13 +334,13 @@ proc maketables*(): ptr char{.cdecl, importc: "pcre_maketables",
pcreImport.}
proc refcount*(a2: ptr TPcre, a3: cint): cint{.cdecl, importc: "pcre_refcount",
pcreImport.}
proc study*(a2: ptr TPcre, a3: cint, a4: var cstring): ptr Textra{.cdecl,
proc study*(a2: ptr TPcre, a3: cint, a4: var cstring): ptr TExtra{.cdecl,
importc: "pcre_study", pcreImport.}
proc version*(): cstring{.cdecl, importc: "pcre_version", pcreImport.}
# Utility functions for byte order swaps.
proc pattern_to_host_byte_order*(a2: ptr TPcre, a3: ptr Textra,
proc pattern_to_host_byte_order*(a2: ptr TPcre, a3: ptr TExtra,
a4: ptr char): cint{.cdecl, importc: "pcre_pattern_to_host_byte_order",
pcreImport.}
@ -350,7 +350,7 @@ proc jit_stack_alloc*(a2: cint, a3: cint): ptr Tjit_stack{.cdecl,
importc: "pcre_jit_stack_alloc", pcreImport.}
proc jit_stack_free*(a2: ptr Tjit_stack){.cdecl, importc: "pcre_jit_stack_free",
pcreImport.}
proc assign_jit_stack*(a2: ptr Textra, a3: Tjit_callback, a4: pointer){.cdecl,
proc assign_jit_stack*(a2: ptr TExtra, a3: TJitCallback, a4: pointer){.cdecl,
importc: "pcre_assign_jit_stack", pcreImport.}
var

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