merged devel into epc
This commit is contained in:
commit
f5cca89610
183 changed files with 5295 additions and 4043 deletions
|
|
@ -88,7 +88,9 @@ type
|
|||
ntyBigNum,
|
||||
ntyConst, ntyMutable, ntyVarargs,
|
||||
ntyIter,
|
||||
ntyError
|
||||
ntyError,
|
||||
ntyBuiltinTypeClass, ntyConcept, ntyConceptInst, ntyComposite,
|
||||
ntyAnd, ntyOr, ntyNot
|
||||
|
||||
TNimTypeKinds* {.deprecated.} = set[NimTypeKind]
|
||||
NimSymKind* = enum
|
||||
|
|
@ -162,6 +164,7 @@ proc kind*(n: NimNode): NimNodeKind {.magic: "NKind", noSideEffect.}
|
|||
## returns the `kind` of the node `n`.
|
||||
|
||||
proc intVal*(n: NimNode): BiggestInt {.magic: "NIntVal", noSideEffect.}
|
||||
proc boolVal*(n: NimNode): bool {.compileTime, noSideEffect.} = n.intVal != 0
|
||||
proc floatVal*(n: NimNode): BiggestFloat {.magic: "NFloatVal", noSideEffect.}
|
||||
proc symbol*(n: NimNode): NimSym {.magic: "NSymbol", noSideEffect.}
|
||||
proc ident*(n: NimNode): NimIdent {.magic: "NIdent", noSideEffect.}
|
||||
|
|
@ -355,6 +358,12 @@ proc expectLen*(n: NimNode, len: int) {.compileTime.} =
|
|||
## macros that check its number of arguments.
|
||||
if n.len != len: error("macro expects a node with " & $len & " children")
|
||||
|
||||
proc newTree*(kind: NimNodeKind,
|
||||
children: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new node with children.
|
||||
result = newNimNode(kind)
|
||||
result.add(children)
|
||||
|
||||
proc newCall*(theProc: NimNode,
|
||||
args: varargs[NimNode]): NimNode {.compileTime.} =
|
||||
## produces a new call node. `theProc` is the proc that is called with
|
||||
|
|
@ -389,6 +398,11 @@ proc newLit*(i: BiggestInt): NimNode {.compileTime.} =
|
|||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = i
|
||||
|
||||
proc newLit*(b: bool): NimNode {.compileTime.} =
|
||||
## produces a new boolean literal node.
|
||||
result = newNimNode(nnkIntLit)
|
||||
result.intVal = ord(b)
|
||||
|
||||
proc newLit*(f: BiggestFloat): NimNode {.compileTime.} =
|
||||
## produces a new float literal node.
|
||||
result = newNimNode(nnkFloatLit)
|
||||
|
|
|
|||
|
|
@ -205,7 +205,7 @@ proc setEncoding*(connection: TDbConn, encoding: string): bool {.
|
|||
exec(connection, sql"PRAGMA encoding = ?", [encoding])
|
||||
result = connection.getValue(sql"PRAGMA encoding") == encoding
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var db = open("db.sql", "", "", "")
|
||||
exec(db, sql"create table tbl1(one varchar(10), two smallint)", [])
|
||||
exec(db, sql"insert into tbl1 values('hello!',10)", [])
|
||||
|
|
|
|||
|
|
@ -499,7 +499,7 @@ template withEvents*(surf: PSurface, event: expr, actions: stmt): stmt {.
|
|||
if sdl.init(sdl.INIT_VIDEO) < 0: raiseEGraphics()
|
||||
if sdl_ttf.init() < 0: raiseEGraphics()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var surf = newScreenSurface(800, 600)
|
||||
|
||||
surf.fillSurface(colWhite)
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ else:
|
|||
var cur, old: Termios
|
||||
discard fd.tcgetattr(cur.addr)
|
||||
old = cur
|
||||
cur.lflag = cur.lflag and not Tcflag(ECHO)
|
||||
cur.c_lflag = cur.c_lflag and not Tcflag(ECHO)
|
||||
discard fd.tcsetattr(TCSADRAIN, cur.addr)
|
||||
stdout.write prompt
|
||||
result = stdin.readLine(password)
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@
|
|||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Regular expression support for Nim. Consider using the pegs module
|
||||
## instead.
|
||||
## Regular expression support for Nim. Consider using the pegs module instead.
|
||||
##
|
||||
## There is an alternative regular expressions library with a more unified API:
|
||||
## `nre <https://github.com/flaviut/nre>`_. It may be added to the standard
|
||||
## library in the future, instead of `re`.
|
||||
##
|
||||
## **Note:** The 're' proc defaults to the **extended regular expression
|
||||
## syntax** which lets you use whitespace freely to make your regexes readable.
|
||||
|
|
@ -41,11 +44,11 @@ type
|
|||
reExtended = 3, ## ignore whitespace and ``#`` comments
|
||||
reStudy = 4 ## study the expression (may be omitted if the
|
||||
## expression will be used only once)
|
||||
|
||||
RegexDesc = object
|
||||
h: PPcre
|
||||
e: ptr TExtra
|
||||
|
||||
|
||||
RegexDesc = object
|
||||
h: ptr Pcre
|
||||
e: ptr ExtraData
|
||||
|
||||
Regex* = ref RegexDesc ## a compiled regular expression
|
||||
|
||||
RegexError* = object of ValueError
|
||||
|
|
@ -60,7 +63,7 @@ proc raiseInvalidRegex(msg: string) {.noinline, noreturn.} =
|
|||
e.msg = msg
|
||||
raise e
|
||||
|
||||
proc rawCompile(pattern: string, flags: cint): PPcre =
|
||||
proc rawCompile(pattern: string, flags: cint): ptr Pcre =
|
||||
var
|
||||
msg: cstring
|
||||
offset: cint
|
||||
|
|
@ -84,7 +87,7 @@ proc re*(s: string, flags = {reExtended, reStudy}): Regex =
|
|||
result.h = rawCompile(s, cast[cint](flags - {reStudy}))
|
||||
if reStudy in flags:
|
||||
var msg: cstring
|
||||
result.e = pcre.study(result.h, 0, msg)
|
||||
result.e = pcre.study(result.h, 0, addr msg)
|
||||
if not isNil(msg): raiseInvalidRegex($msg)
|
||||
|
||||
proc matchOrFind(s: string, pattern: Regex, matches: var openArray[string],
|
||||
|
|
@ -143,8 +146,8 @@ proc findBounds*(s: string, pattern: Regex,
|
|||
|
||||
proc findBounds*(s: string, pattern: Regex,
|
||||
start = 0): tuple[first, last: int] =
|
||||
## returns the starting position of `pattern` in `s`. If it does not
|
||||
## match, ``(-1,0)`` is returned.
|
||||
## returns the starting position and end position of ``pattern`` in ``s``.
|
||||
## If it does not match, ``(-1,0)`` is returned.
|
||||
var
|
||||
rtarray = initRtArray[cint](3)
|
||||
rawMatches = rtarray.getRawData
|
||||
|
|
@ -413,22 +416,28 @@ proc escapeRe*(s: string): string =
|
|||
result.add(toHex(ord(c), 2))
|
||||
|
||||
const ## common regular expressions
|
||||
reIdentifier* = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b" ## describes an identifier
|
||||
reNatural* = r"\b\d+\b" ## describes a natural number
|
||||
reInteger* = r"\b[-+]?\d+\b" ## describes an integer
|
||||
reHex* = r"\b0[xX][0-9a-fA-F]+\b" ## describes a hexadecimal number
|
||||
reBinary* = r"\b0[bB][01]+\b" ## describes a binary number (example: 0b11101)
|
||||
reOctal* = r"\b0[oO][0-7]+\b" ## describes an octal number (example: 0o777)
|
||||
reFloat* = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
|
||||
reIdentifier* {.deprecated.} = r"\b[a-zA-Z_]+[a-zA-Z_0-9]*\b"
|
||||
## describes an identifier
|
||||
reNatural* {.deprecated.} = r"\b\d+\b"
|
||||
## describes a natural number
|
||||
reInteger* {.deprecated.} = r"\b[-+]?\d+\b"
|
||||
## describes an integer
|
||||
reHex* {.deprecated.} = r"\b0[xX][0-9a-fA-F]+\b"
|
||||
## describes a hexadecimal number
|
||||
reBinary* {.deprecated.} = r"\b0[bB][01]+\b"
|
||||
## describes a binary number (example: 0b11101)
|
||||
reOctal* {.deprecated.} = r"\b0[oO][0-7]+\b"
|
||||
## describes an octal number (example: 0o777)
|
||||
reFloat* {.deprecated.} = r"\b[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?\b"
|
||||
## describes a floating point number
|
||||
reEmail* = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
|
||||
r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)" &
|
||||
r"*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
|
||||
r"(?:[a-zA-Z]{2}|com|org|" &
|
||||
r"net|gov|mil|biz|info|mobi|name|aero|jobs|museum)\b"
|
||||
reEmail* {.deprecated.} = r"\b[a-zA-Z0-9!#$%&'*+/=?^_`{|}~\-]+(?:\. &" &
|
||||
r"[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@" &
|
||||
r"(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+" &
|
||||
r"(?:[a-zA-Z]{2}|com|org|net|gov|mil|biz|" &
|
||||
r"info|mobi|name|aero|jobs|museum)\b"
|
||||
## describes a common email address
|
||||
reURL* = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms\-help):" &
|
||||
r"((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
|
||||
reURL* {.deprecated.} = r"\b(http(s)?|ftp|gopher|telnet|file|notes|ms-help)" &
|
||||
r":((//)|(\\\\))+[\w\d:#@%/;$()~_?\+\-\=\\\.\&]*\b"
|
||||
## describes an URL
|
||||
|
||||
when isMainModule:
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ proc close*(sock: TSecureSocket) =
|
|||
ERR_print_errors_fp(stderr)
|
||||
raiseOSError(osLastError())
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var s: TSecureSocket
|
||||
echo connect(s, "smtp.gmail.com", 465)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
|
||||
## This module implements a zip archive creator/reader/modifier.
|
||||
|
||||
import
|
||||
streams, libzip, times, os
|
||||
import
|
||||
streams, libzip, times, os, strutils
|
||||
|
||||
type
|
||||
TZipArchive* = object of RootObj ## represents a zip archive
|
||||
|
|
@ -18,14 +18,14 @@ type
|
|||
w: PZip
|
||||
|
||||
|
||||
proc zipError(z: var TZipArchive) =
|
||||
proc zipError(z: var TZipArchive) =
|
||||
var e: ref IOError
|
||||
new(e)
|
||||
e.msg = $zip_strerror(z.w)
|
||||
raise e
|
||||
|
||||
|
||||
proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool =
|
||||
## Opens a zip file for reading, writing or appending. All file modes are
|
||||
## Opens a zip file for reading, writing or appending. All file modes are
|
||||
## supported. Returns true iff successful, false otherwise.
|
||||
var err, flags: int32
|
||||
case mode
|
||||
|
|
@ -41,21 +41,21 @@ proc open*(z: var TZipArchive, filename: string, mode: FileMode = fmRead): bool
|
|||
proc close*(z: var TZipArchive) =
|
||||
## Closes a zip file.
|
||||
zip_close(z.w)
|
||||
|
||||
proc createDir*(z: var TZipArchive, dir: string) =
|
||||
|
||||
proc createDir*(z: var TZipArchive, dir: string) =
|
||||
## Creates a directory within the `z` archive. This does not fail if the
|
||||
## directory already exists. Note that for adding a file like
|
||||
## directory already exists. Note that for adding a file like
|
||||
## ``"path1/path2/filename"`` it is not necessary
|
||||
## to create the ``"path/path2"`` subdirectories - it will be done
|
||||
## automatically by ``addFile``.
|
||||
assert(z.mode != fmRead)
|
||||
## to create the ``"path/path2"`` subdirectories - it will be done
|
||||
## automatically by ``addFile``.
|
||||
assert(z.mode != fmRead)
|
||||
discard zip_add_dir(z.w, dir)
|
||||
zip_error_clear(z.w)
|
||||
|
||||
proc addFile*(z: var TZipArchive, dest, src: string) =
|
||||
proc addFile*(z: var TZipArchive, dest, src: string) =
|
||||
## Adds the file `src` to the archive `z` with the name `dest`. `dest`
|
||||
## may contain a path that will be created.
|
||||
assert(z.mode != fmRead)
|
||||
## may contain a path that will be created.
|
||||
assert(z.mode != fmRead)
|
||||
if not fileExists(src):
|
||||
raise newException(IOError, "File '" & src & "' does not exist")
|
||||
var zipsrc = zip_source_file(z.w, src, 0, -1)
|
||||
|
|
@ -67,21 +67,21 @@ proc addFile*(z: var TZipArchive, dest, src: string) =
|
|||
zip_source_free(zipsrc)
|
||||
zipError(z)
|
||||
|
||||
proc addFile*(z: var TZipArchive, file: string) =
|
||||
proc addFile*(z: var TZipArchive, file: string) =
|
||||
## A shortcut for ``addFile(z, file, file)``, i.e. the name of the source is
|
||||
## the name of the destination.
|
||||
addFile(z, file, file)
|
||||
|
||||
proc mySourceCallback(state, data: pointer, len: int,
|
||||
cmd: TZipSourceCmd): int {.cdecl.} =
|
||||
|
||||
proc mySourceCallback(state, data: pointer, len: int,
|
||||
cmd: TZipSourceCmd): int {.cdecl.} =
|
||||
var src = cast[Stream](state)
|
||||
case cmd
|
||||
of ZIP_SOURCE_OPEN:
|
||||
of ZIP_SOURCE_OPEN:
|
||||
if src.setPositionImpl != nil: setPosition(src, 0) # reset
|
||||
of ZIP_SOURCE_READ:
|
||||
result = readData(src, data, len)
|
||||
of ZIP_SOURCE_CLOSE: close(src)
|
||||
of ZIP_SOURCE_STAT:
|
||||
of ZIP_SOURCE_STAT:
|
||||
var stat = cast[PZipStat](data)
|
||||
zip_stat_init(stat)
|
||||
stat.size = high(int32)-1 # we don't know the size
|
||||
|
|
@ -94,8 +94,8 @@ proc mySourceCallback(state, data: pointer, len: int,
|
|||
result = 2*sizeof(cint)
|
||||
of constZIP_SOURCE_FREE: GC_unref(src)
|
||||
else: assert(false)
|
||||
|
||||
proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
|
||||
|
||||
proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
|
||||
## Adds a file named with `dest` to the archive `z`. `dest`
|
||||
## may contain a path. The file's content is read from the `src` stream.
|
||||
assert(z.mode != fmRead)
|
||||
|
|
@ -105,39 +105,45 @@ proc addFile*(z: var TZipArchive, dest: string, src: Stream) =
|
|||
if zip_add(z.w, dest, zipsrc) < 0'i32:
|
||||
zip_source_free(zipsrc)
|
||||
zipError(z)
|
||||
|
||||
|
||||
# -------------- zip file stream ---------------------------------------------
|
||||
|
||||
type
|
||||
TZipFileStream = object of StreamObj
|
||||
f: PZipFile
|
||||
atEnd: bool
|
||||
|
||||
PZipFileStream* =
|
||||
ref TZipFileStream ## a reader stream of a file within a zip archive
|
||||
PZipFileStream* =
|
||||
ref TZipFileStream ## a reader stream of a file within a zip archive
|
||||
|
||||
proc fsClose(s: Stream) = zip_fclose(PZipFileStream(s).f)
|
||||
proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||
proc fsAtEnd(s: Stream): bool = PZipFileStream(s).atEnd
|
||||
proc fsReadData(s: Stream, buffer: pointer, bufLen: int): int =
|
||||
result = zip_fread(PZipFileStream(s).f, buffer, bufLen)
|
||||
if result == 0:
|
||||
PZipFileStream(s).atEnd = true
|
||||
|
||||
proc newZipFileStream(f: PZipFile): PZipFileStream =
|
||||
proc newZipFileStream(f: PZipFile): PZipFileStream =
|
||||
new(result)
|
||||
result.f = f
|
||||
result.atEnd = false
|
||||
result.closeImpl = fsClose
|
||||
result.readDataImpl = fsReadData
|
||||
result.atEndImpl = fsAtEnd
|
||||
# other methods are nil!
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
|
||||
|
||||
proc getStream*(z: var TZipArchive, filename: string): PZipFileStream =
|
||||
## returns a stream that can be used to read the file named `filename`
|
||||
## from the archive `z`. Returns nil in case of an error.
|
||||
## The returned stream does not support the `setPosition`, `getPosition`,
|
||||
## The returned stream does not support the `setPosition`, `getPosition`,
|
||||
## `writeData` or `atEnd` methods.
|
||||
var x = zip_fopen(z.w, filename, 0'i32)
|
||||
if x != nil: result = newZipFileStream(x)
|
||||
|
||||
iterator walkFiles*(z: var TZipArchive): string =
|
||||
## walks over all files in the archive `z` and returns the filename
|
||||
|
||||
iterator walkFiles*(z: var TZipArchive): string =
|
||||
## walks over all files in the archive `z` and returns the filename
|
||||
## (including the path).
|
||||
var i = 0'i32
|
||||
var num = zip_get_num_files(z.w)
|
||||
|
|
@ -158,12 +164,20 @@ proc extractFile*(z: var TZipArchive, srcFile: string, dest: Stream) =
|
|||
|
||||
proc extractFile*(z: var TZipArchive, srcFile: string, dest: string) =
|
||||
## extracts a file from the zip archive `z` to the destination filename.
|
||||
var file = newFileStream(dest, fmReadWrite)
|
||||
var file = newFileStream(dest, fmWrite)
|
||||
extractFile(z, srcFile, file)
|
||||
file.close()
|
||||
|
||||
proc extractAll*(z: var TZipArchive, dest: string) =
|
||||
## extracts all files from archive `z` to the destination directory.
|
||||
for file in walkFiles(z):
|
||||
extractFile(z, file, dest / extractFilename(file))
|
||||
if file.endsWith("/"):
|
||||
createDir(dest / file)
|
||||
else:
|
||||
extractFile(z, file, dest / file)
|
||||
|
||||
when not defined(testing) and isMainModule:
|
||||
var zip: TZipArchive
|
||||
if not zip.open("nim-0.11.0.zip"):
|
||||
raise newException(IOError, "opening zip failed")
|
||||
zip.extractAll("test")
|
||||
|
|
|
|||
|
|
@ -152,10 +152,12 @@ type
|
|||
DocumentObj {.importc.} = object of NodeObj
|
||||
alinkColor*: cstring
|
||||
bgColor*: cstring
|
||||
body*: Element
|
||||
charset*: cstring
|
||||
cookie*: cstring
|
||||
defaultCharset*: cstring
|
||||
fgColor*: cstring
|
||||
head*: Element
|
||||
lastModified*: cstring
|
||||
linkColor*: cstring
|
||||
referrer*: cstring
|
||||
|
|
|
|||
|
|
@ -343,15 +343,15 @@ struct TFrame {
|
|||
};
|
||||
|
||||
#define nimfr(proc, file) \
|
||||
TFrame F; \
|
||||
F.procname = proc; F.filename = file; F.line = 0; F.len = 0; nimFrame(&F);
|
||||
TFrame FR; \
|
||||
FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = 0; nimFrame(&FR);
|
||||
|
||||
#define nimfrs(proc, file, slots, length) \
|
||||
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} F; \
|
||||
F.procname = proc; F.filename = file; F.line = 0; F.len = length; nimFrame((TFrame*)&F);
|
||||
struct {TFrame* prev;NCSTRING procname;NI line;NCSTRING filename; NI len; TVarSlot s[slots];} FR; \
|
||||
FR.procname = proc; FR.filename = file; FR.line = 0; FR.len = length; nimFrame((TFrame*)&FR);
|
||||
|
||||
#define nimln(n, file) \
|
||||
F.line = n; F.filename = file;
|
||||
FR.line = n; FR.filename = file;
|
||||
|
||||
#define NIM_POSIX_INIT __attribute__((constructor))
|
||||
|
||||
|
|
|
|||
|
|
@ -564,7 +564,7 @@ proc fixupEmbeddedRef(n, a, b: PRstNode) =
|
|||
|
||||
proc parsePostfix(p: var TRstParser, n: PRstNode): PRstNode =
|
||||
result = n
|
||||
if isInlineMarkupEnd(p, "_"):
|
||||
if isInlineMarkupEnd(p, "_") or isInlineMarkupEnd(p, "__"):
|
||||
inc(p.idx)
|
||||
if p.tok[p.idx-2].symbol == "`" and p.tok[p.idx-3].symbol == ">":
|
||||
var a = newRstNode(rnInner)
|
||||
|
|
|
|||
|
|
@ -34,14 +34,14 @@ type
|
|||
TOutputTarget* = enum ## which document type to generate
|
||||
outHtml, # output is HTML
|
||||
outLatex # output is Latex
|
||||
|
||||
TTocEntry = object
|
||||
|
||||
TTocEntry = object
|
||||
n*: PRstNode
|
||||
refname*, header*: string
|
||||
|
||||
TMetaEnum* = enum
|
||||
TMetaEnum* = enum
|
||||
metaNone, metaTitle, metaSubtitle, metaAuthor, metaVersion
|
||||
|
||||
|
||||
TRstGenerator* = object of RootObj
|
||||
target*: TOutputTarget
|
||||
config*: StringTableRef
|
||||
|
|
@ -60,7 +60,7 @@ type
|
|||
seenIndexTerms: Table[string, int] ## \
|
||||
## Keeps count of same text index terms to generate different identifiers
|
||||
## for hyperlinks. See renderIndexTerm proc for details.
|
||||
|
||||
|
||||
PDoc = var TRstGenerator ## Alias to type less.
|
||||
|
||||
CodeBlockParams = object ## Stores code block params.
|
||||
|
|
@ -136,7 +136,7 @@ proc initRstGenerator*(g: var TRstGenerator, target: TOutputTarget,
|
|||
g.currentSection = "Module " & fileParts.name
|
||||
g.seenIndexTerms = initTable[string, int]()
|
||||
g.msgHandler = msgHandler
|
||||
|
||||
|
||||
let s = config["split.item.toc"]
|
||||
if s != "": g.splitAfter = parseInt(s)
|
||||
for i in low(g.meta)..high(g.meta): g.meta[i] = ""
|
||||
|
|
@ -147,23 +147,23 @@ proc writeIndexFile*(g: var TRstGenerator, outfile: string) =
|
|||
## You previously need to add entries to the index with the `setIndexTerm()
|
||||
## <#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, "&")
|
||||
of '<': add(dest, "<")
|
||||
of '>': add(dest, ">")
|
||||
of '\"': add(dest, """)
|
||||
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}")
|
||||
|
|
@ -183,54 +183,54 @@ 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)
|
||||
|
||||
proc nextSplitPoint*(s: string, start: int): int =
|
||||
|
||||
proc nextSplitPoint*(s: string, start: int): int =
|
||||
result = start
|
||||
while result < len(s) + 0:
|
||||
while result < len(s) + 0:
|
||||
case s[result]
|
||||
of '_': return
|
||||
of 'a'..'z':
|
||||
if result + 1 < len(s) + 0:
|
||||
if s[result + 1] in {'A'..'Z'}: return
|
||||
of '_': return
|
||||
of 'a'..'z':
|
||||
if result + 1 < len(s) + 0:
|
||||
if s[result + 1] in {'A'..'Z'}: return
|
||||
else: discard
|
||||
inc(result)
|
||||
dec(result) # last valid index
|
||||
|
||||
proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
|
||||
|
||||
proc esc*(target: TOutputTarget, s: string, splitAfter = -1): string =
|
||||
result = ""
|
||||
if splitAfter >= 0:
|
||||
if splitAfter >= 0:
|
||||
var partLen = 0
|
||||
var j = 0
|
||||
while j < len(s):
|
||||
while j < len(s):
|
||||
var k = nextSplitPoint(s, j)
|
||||
if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
|
||||
if (splitter != " ") or (partLen + k - j + 1 > splitAfter):
|
||||
partLen = 0
|
||||
add(result, splitter)
|
||||
for i in countup(j, k): escChar(target, result, s[i])
|
||||
inc(partLen, k - j + 1)
|
||||
j = k + 1
|
||||
else:
|
||||
else:
|
||||
for i in countup(0, len(s) - 1): escChar(target, result, s[i])
|
||||
|
||||
|
||||
proc disp(target: TOutputTarget, xml, tex: string): string =
|
||||
if target != outLatex: result = xml
|
||||
if target != outLatex: result = xml
|
||||
else: result = tex
|
||||
|
||||
proc dispF(target: TOutputTarget, xml, tex: string,
|
||||
args: varargs[string]): string =
|
||||
if target != outLatex: result = xml % args
|
||||
|
||||
proc dispF(target: TOutputTarget, xml, tex: string,
|
||||
args: varargs[string]): string =
|
||||
if target != outLatex: result = xml % args
|
||||
else: result = tex % args
|
||||
|
||||
proc dispA(target: TOutputTarget, dest: var string,
|
||||
|
||||
proc dispA(target: TOutputTarget, dest: var string,
|
||||
xml, tex: string, args: varargs[string]) =
|
||||
if target != outLatex: addf(dest, xml, args)
|
||||
else: addf(dest, tex, args)
|
||||
|
||||
|
||||
proc `or`(x, y: string): string {.inline.} =
|
||||
result = if x.isNil: y else: x
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ proc renderRstToOut*(d: var TRstGenerator, n: PRstNode, result: var string)
|
|||
## renderRstToOut(gen, rst, generatedHTML)
|
||||
## echo generatedHTML
|
||||
|
||||
proc renderAux(d: PDoc, n: PRstNode, result: var string) =
|
||||
proc renderAux(d: PDoc, n: PRstNode, result: var string) =
|
||||
for i in countup(0, len(n)-1): renderRstToOut(d, n.sons[i], result)
|
||||
|
||||
proc renderAux(d: PDoc, n: PRstNode, frmtA, frmtB: string, result: var string) =
|
||||
|
|
@ -347,7 +347,7 @@ proc renderIndexTerm*(d: PDoc, n: PRstNode, result: var string) =
|
|||
var term = ""
|
||||
renderAux(d, n, term)
|
||||
setIndexTerm(d, id, term, d.currentSection)
|
||||
dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}",
|
||||
dispA(d.target, result, "<span id=\"$1\">$2</span>", "$2\\label{$1}",
|
||||
[id, term])
|
||||
|
||||
type
|
||||
|
|
@ -656,7 +656,7 @@ proc mergeIndexes*(dir: string): string =
|
|||
result.add("<h2>API symbols</h2>\n")
|
||||
result.add(generateSymbolIndex(symbols))
|
||||
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
proc stripTOCHTML(s: string): string =
|
||||
|
|
@ -677,7 +677,7 @@ proc stripTOCHTML(s: string): string =
|
|||
result.delete(first, last)
|
||||
first = result.find('<', first)
|
||||
|
||||
proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||
proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
||||
var tmp = ""
|
||||
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
|
||||
d.currentSection = tmp
|
||||
|
|
@ -700,9 +700,9 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
|||
"id=\"$2\" href=\"#$2\">$3</a></h$1>", "\\rsth$4{$3}\\label{$2}\n",
|
||||
[$n.level, d.tocPart[length].refname, tmp, $chr(n.level - 1 + ord('A'))])
|
||||
else:
|
||||
dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>",
|
||||
dispA(d.target, result, "\n<h$1 id=\"$2\">$3</h$1>",
|
||||
"\\rsth$4{$3}\\label{$2}\n", [
|
||||
$n.level, refname, tmp,
|
||||
$n.level, refname, tmp,
|
||||
$chr(n.level - 1 + ord('A'))])
|
||||
|
||||
# Generate index entry using spaces to indicate TOC level for the output HTML.
|
||||
|
|
@ -710,7 +710,7 @@ proc renderHeadline(d: PDoc, n: PRstNode, result: var string) =
|
|||
setIndexTerm(d, refname, tmp.stripTOCHTML,
|
||||
spaces(max(0, n.level)) & tmp)
|
||||
|
||||
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
||||
if d.meta[metaTitle].len == 0:
|
||||
for i in countup(0, len(n)-1):
|
||||
renderRstToOut(d, n.sons[i], d.meta[metaTitle])
|
||||
|
|
@ -723,14 +723,14 @@ proc renderOverline(d: PDoc, n: PRstNode, result: var string) =
|
|||
var tmp = ""
|
||||
for i in countup(0, len(n) - 1): renderRstToOut(d, n.sons[i], tmp)
|
||||
d.currentSection = tmp
|
||||
dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>",
|
||||
dispA(d.target, result, "<h$1 id=\"$2\"><center>$3</center></h$1>",
|
||||
"\\rstov$4{$3}\\label{$2}\n", [$n.level,
|
||||
rstnodeToRefname(n), tmp, $chr(n.level - 1 + ord('A'))])
|
||||
|
||||
|
||||
proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
|
||||
|
||||
proc renderTocEntry(d: PDoc, e: TTocEntry, result: var string) =
|
||||
dispA(d.target, result,
|
||||
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
||||
"<li><a class=\"reference\" id=\"$1_toc\" href=\"#$1\">$2</a></li>\n",
|
||||
"\\item\\label{$1_toc} $2\\ref{$1}\n", [e.refname, e.header])
|
||||
|
||||
proc renderTocEntries*(d: var TRstGenerator, j: var int, lvl: int,
|
||||
|
|
@ -759,33 +759,33 @@ proc renderImage(d: PDoc, n: PRstNode, result: var string) =
|
|||
var options = ""
|
||||
var s = getFieldValue(n, "scale")
|
||||
if s.valid: dispA(d.target, options, " scale=\"$1\"", " scale=$1", [strip(s)])
|
||||
|
||||
|
||||
s = getFieldValue(n, "height")
|
||||
if s.valid: dispA(d.target, options, " height=\"$1\"", " height=$1", [strip(s)])
|
||||
|
||||
|
||||
s = getFieldValue(n, "width")
|
||||
if s.valid: dispA(d.target, options, " width=\"$1\"", " width=$1", [strip(s)])
|
||||
|
||||
|
||||
s = getFieldValue(n, "alt")
|
||||
if s.valid: dispA(d.target, options, " alt=\"$1\"", "", [strip(s)])
|
||||
|
||||
|
||||
s = getFieldValue(n, "align")
|
||||
if s.valid: dispA(d.target, options, " align=\"$1\"", "", [strip(s)])
|
||||
|
||||
|
||||
if options.len > 0: options = dispF(d.target, "$1", "[$1]", [options])
|
||||
|
||||
let arg = getArgument(n)
|
||||
if arg.valid:
|
||||
dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
|
||||
dispA(d.target, result, "<img src=\"$1\"$2 />", "\\includegraphics$2{$1}",
|
||||
[arg, options])
|
||||
if len(n) >= 3: renderRstToOut(d, n.sons[2], result)
|
||||
|
||||
|
||||
proc renderSmiley(d: PDoc, n: PRstNode, result: var string) =
|
||||
dispA(d.target, result,
|
||||
"""<img src="$1" width="15"
|
||||
"""<img src="$1" width="15"
|
||||
height="17" hspace="2" vspace="2" class="smiley" />""",
|
||||
"\\includegraphics{$1}", [d.config["doc.smiley_format"] % n.text])
|
||||
|
||||
|
||||
proc parseCodeBlockField(d: PDoc, n: PRstNode, params: var CodeBlockParams) =
|
||||
## Parses useful fields which can appear before a code block.
|
||||
##
|
||||
|
|
@ -880,11 +880,11 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
|||
else:
|
||||
var g: TGeneralTokenizer
|
||||
initGeneralTokenizer(g, m.text)
|
||||
while true:
|
||||
while true:
|
||||
getNextToken(g, params.lang)
|
||||
case g.kind
|
||||
of gtEof: break
|
||||
of gtNone, gtWhitespace:
|
||||
of gtEof: break
|
||||
of gtNone, gtWhitespace:
|
||||
add(result, substr(m.text, g.start, g.length + g.start - 1))
|
||||
else:
|
||||
dispA(d.target, result, "<span class=\"$2\">$1</span>", "\\span$2{$1}", [
|
||||
|
|
@ -893,36 +893,36 @@ proc renderCodeBlock(d: PDoc, n: PRstNode, result: var string) =
|
|||
deinitGeneralTokenizer(g)
|
||||
dispA(d.target, result, blockEnd, "\n\\end{rstpre}\n")
|
||||
|
||||
proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
|
||||
proc renderContainer(d: PDoc, n: PRstNode, result: var string) =
|
||||
var tmp = ""
|
||||
renderRstToOut(d, n.sons[2], tmp)
|
||||
var arg = strip(getArgument(n))
|
||||
if arg == "":
|
||||
if arg == "":
|
||||
dispA(d.target, result, "<div>$1</div>", "$1", [tmp])
|
||||
else:
|
||||
dispA(d.target, result, "<div class=\"$1\">$2</div>", "$2", [arg, tmp])
|
||||
|
||||
proc texColumns(n: PRstNode): string =
|
||||
|
||||
proc texColumns(n: PRstNode): string =
|
||||
result = ""
|
||||
for i in countup(1, len(n)): add(result, "|X")
|
||||
|
||||
proc renderField(d: PDoc, n: PRstNode, result: var string) =
|
||||
|
||||
proc renderField(d: PDoc, n: PRstNode, result: var string) =
|
||||
var b = false
|
||||
if d.target == outLatex:
|
||||
if d.target == outLatex:
|
||||
var fieldname = addNodes(n.sons[0])
|
||||
var fieldval = esc(d.target, strip(addNodes(n.sons[1])))
|
||||
if cmpIgnoreStyle(fieldname, "author") == 0 or
|
||||
if cmpIgnoreStyle(fieldname, "author") == 0 or
|
||||
cmpIgnoreStyle(fieldname, "authors") == 0:
|
||||
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
|
||||
if not b:
|
||||
renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
|
||||
|
||||
|
||||
proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
||||
if n == nil: return
|
||||
case n.kind
|
||||
|
|
@ -947,54 +947,54 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
|||
of rnDefBody: renderAux(d, n, "<dd>$1</dd>\n", "$1\n", result)
|
||||
of rnFieldList:
|
||||
var tmp = ""
|
||||
for i in countup(0, len(n) - 1):
|
||||
for i in countup(0, len(n) - 1):
|
||||
renderRstToOut(d, n.sons[i], tmp)
|
||||
if tmp.len != 0:
|
||||
if tmp.len != 0:
|
||||
dispA(d.target, result,
|
||||
"<table class=\"docinfo\" frame=\"void\" rules=\"none\">" &
|
||||
"<col class=\"docinfo-name\" />" &
|
||||
"<col class=\"docinfo-content\" />" &
|
||||
"<col class=\"docinfo-content\" />" &
|
||||
"<tbody valign=\"top\">$1" &
|
||||
"</tbody></table>",
|
||||
"\\begin{description}$1\\end{description}\n",
|
||||
"</tbody></table>",
|
||||
"\\begin{description}$1\\end{description}\n",
|
||||
[tmp])
|
||||
of rnField: renderField(d, n, result)
|
||||
of rnFieldName:
|
||||
of rnFieldName:
|
||||
renderAux(d, n, "<th class=\"docinfo-name\">$1:</th>",
|
||||
"\\item[$1:]", result)
|
||||
of rnFieldBody:
|
||||
of rnFieldBody:
|
||||
renderAux(d, n, "<td>$1</td>", " $1\n", result)
|
||||
of rnIndex:
|
||||
of rnIndex:
|
||||
renderRstToOut(d, n.sons[2], result)
|
||||
of rnOptionList:
|
||||
renderAux(d, n, "<table frame=\"void\">$1</table>",
|
||||
of rnOptionList:
|
||||
renderAux(d, n, "<table frame=\"void\">$1</table>",
|
||||
"\\begin{description}\n$1\\end{description}\n", result)
|
||||
of rnOptionListItem:
|
||||
of rnOptionListItem:
|
||||
renderAux(d, n, "<tr>$1</tr>\n", "$1", result)
|
||||
of rnOptionGroup:
|
||||
of rnOptionGroup:
|
||||
renderAux(d, n, "<th align=\"left\">$1</th>", "\\item[$1]", result)
|
||||
of rnDescription:
|
||||
of rnDescription:
|
||||
renderAux(d, n, "<td align=\"left\">$1</td>\n", " $1\n", result)
|
||||
of rnOption, rnOptionString, rnOptionArgument:
|
||||
of rnOption, rnOptionString, rnOptionArgument:
|
||||
doAssert false, "renderRstToOut"
|
||||
of rnLiteralBlock:
|
||||
renderAux(d, n, "<pre>$1</pre>\n",
|
||||
renderAux(d, n, "<pre>$1</pre>\n",
|
||||
"\\begin{rstpre}\n$1\n\\end{rstpre}\n", result)
|
||||
of rnQuotedLiteralBlock:
|
||||
of rnQuotedLiteralBlock:
|
||||
doAssert false, "renderRstToOut"
|
||||
of rnLineBlock:
|
||||
of rnLineBlock:
|
||||
renderAux(d, n, "<p>$1</p>", "$1\n\n", result)
|
||||
of rnLineBlockItem:
|
||||
of rnLineBlockItem:
|
||||
renderAux(d, n, "$1<br />", "$1\\\\\n", result)
|
||||
of rnBlockQuote:
|
||||
renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
|
||||
of rnBlockQuote:
|
||||
renderAux(d, n, "<blockquote><p>$1</p></blockquote>\n",
|
||||
"\\begin{quote}$1\\end{quote}\n", result)
|
||||
of rnTable, rnGridTable:
|
||||
renderAux(d, n,
|
||||
"<table border=\"1\" class=\"docutils\">$1</table>",
|
||||
of rnTable, rnGridTable:
|
||||
renderAux(d, n,
|
||||
"<table border=\"1\" class=\"docutils\">$1</table>",
|
||||
"\\begin{table}\\begin{rsttab}{" &
|
||||
texColumns(n) & "|}\n\\hline\n$1\\end{rsttab}\\end{table}", result)
|
||||
of rnTableRow:
|
||||
of rnTableRow:
|
||||
if len(n) >= 1:
|
||||
if d.target == outLatex:
|
||||
#var tmp = ""
|
||||
|
|
@ -1007,25 +1007,25 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
|||
result.add("<tr>")
|
||||
renderAux(d, n, result)
|
||||
result.add("</tr>\n")
|
||||
of rnTableDataCell:
|
||||
of rnTableDataCell:
|
||||
renderAux(d, n, "<td>$1</td>", "$1", result)
|
||||
of rnTableHeaderCell:
|
||||
of rnTableHeaderCell:
|
||||
renderAux(d, n, "<th>$1</th>", "\\textbf{$1}", result)
|
||||
of rnLabel:
|
||||
of rnLabel:
|
||||
doAssert false, "renderRstToOut" # used for footnotes and other
|
||||
of rnFootnote:
|
||||
of rnFootnote:
|
||||
doAssert false, "renderRstToOut" # a footnote
|
||||
of rnCitation:
|
||||
of rnCitation:
|
||||
doAssert false, "renderRstToOut" # similar to footnote
|
||||
of rnRef:
|
||||
of rnRef:
|
||||
var tmp = ""
|
||||
renderAux(d, n, tmp)
|
||||
dispA(d.target, result,
|
||||
"<a class=\"reference external\" href=\"#$2\">$1</a>",
|
||||
"$1\\ref{$2}", [tmp, rstnodeToRefname(n)])
|
||||
of rnStandaloneHyperlink:
|
||||
renderAux(d, n,
|
||||
"<a class=\"reference external\" href=\"$1\">$1</a>",
|
||||
of rnStandaloneHyperlink:
|
||||
renderAux(d, n,
|
||||
"<a class=\"reference external\" href=\"$1\">$1</a>",
|
||||
"\\href{$1}{$1}", result)
|
||||
of rnHyperlink:
|
||||
var tmp0 = ""
|
||||
|
|
@ -1042,11 +1042,11 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
|||
of rnRawLatex:
|
||||
if d.target == outLatex:
|
||||
result.add addNodes(lastSon(n))
|
||||
|
||||
|
||||
of rnImage, rnFigure: renderImage(d, n, result)
|
||||
of rnCodeBlock: renderCodeBlock(d, n, result)
|
||||
of rnContainer: renderContainer(d, n, result)
|
||||
of rnSubstitutionReferences, rnSubstitutionDef:
|
||||
of rnSubstitutionReferences, rnSubstitutionDef:
|
||||
renderAux(d, n, "|$1|", "|$1|", result)
|
||||
of rnDirective:
|
||||
renderAux(d, n, "", "", result)
|
||||
|
|
@ -1063,15 +1063,15 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
|||
of rnStrongEmphasis:
|
||||
renderAux(d, n, "<strong>$1</strong>", "\\textbf{$1}", result)
|
||||
of rnTripleEmphasis:
|
||||
renderAux(d, n, "<strong><em>$1</em></strong>",
|
||||
renderAux(d, n, "<strong><em>$1</em></strong>",
|
||||
"\\textbf{emph{$1}}", result)
|
||||
of rnInterpretedText:
|
||||
renderAux(d, n, "<cite>$1</cite>", "\\emph{$1}", result)
|
||||
of rnIdx:
|
||||
renderIndexTerm(d, n, result)
|
||||
of rnInlineLiteral:
|
||||
renderAux(d, n,
|
||||
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
|
||||
of rnInlineLiteral:
|
||||
renderAux(d, n,
|
||||
"<tt class=\"docutils literal\"><span class=\"pre\">$1</span></tt>",
|
||||
"\\texttt{$1}", result)
|
||||
of rnSmiley: renderSmiley(d, n, result)
|
||||
of rnLeaf: result.add(esc(d.target, n.text))
|
||||
|
|
@ -1082,55 +1082,55 @@ proc renderRstToOut(d: PDoc, n: PRstNode, result: var string) =
|
|||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
proc getVarIdx(varnames: openArray[string], id: string): int =
|
||||
for i in countup(0, high(varnames)):
|
||||
if cmpIgnoreStyle(varnames[i], id) == 0:
|
||||
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 = ""
|
||||
var num = 0
|
||||
while i < L:
|
||||
if frmt[i] == '$':
|
||||
while i < L:
|
||||
if frmt[i] == '$':
|
||||
inc(i) # skip '$'
|
||||
case frmt[i]
|
||||
of '#':
|
||||
of '#':
|
||||
add(result, varvalues[num])
|
||||
inc(num)
|
||||
inc(i)
|
||||
of '$':
|
||||
of '$':
|
||||
add(result, "$")
|
||||
inc(i)
|
||||
of '0'..'9':
|
||||
of '0'..'9':
|
||||
var j = 0
|
||||
while true:
|
||||
while true:
|
||||
j = (j * 10) + ord(frmt[i]) - ord('0')
|
||||
inc(i)
|
||||
if i > L-1 or frmt[i] notin {'0'..'9'}: break
|
||||
if i > L-1 or frmt[i] notin {'0'..'9'}: break
|
||||
if j > high(varvalues) + 1:
|
||||
raise newException(ValueError, "invalid index: " & $j)
|
||||
num = j
|
||||
add(result, varvalues[j - 1])
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
of 'A'..'Z', 'a'..'z', '\x80'..'\xFF':
|
||||
var id = ""
|
||||
while true:
|
||||
while true:
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
|
||||
if frmt[i] notin {'A'..'Z', '_', 'a'..'z', '\x80'..'\xFF'}: break
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0:
|
||||
if idx >= 0:
|
||||
add(result, varvalues[idx])
|
||||
else:
|
||||
raise newException(ValueError, "unknown substitution var: " & id)
|
||||
of '{':
|
||||
of '{':
|
||||
var id = ""
|
||||
inc(i)
|
||||
while frmt[i] != '}':
|
||||
if frmt[i] == '\0':
|
||||
while frmt[i] != '}':
|
||||
if frmt[i] == '\0':
|
||||
raise newException(ValueError, "'}' expected")
|
||||
add(id, frmt[i])
|
||||
inc(i)
|
||||
|
|
@ -1138,12 +1138,12 @@ proc formatNamedVars*(frmt: string, varnames: openArray[string],
|
|||
# search for the variable:
|
||||
var idx = getVarIdx(varnames, id)
|
||||
if idx >= 0: add(result, varvalues[idx])
|
||||
else:
|
||||
else:
|
||||
raise newException(ValueError, "unknown substitution var: " & id)
|
||||
else:
|
||||
raise newException(ValueError, "unknown substitution: $" & $frmt[i])
|
||||
var start = i
|
||||
while i < L:
|
||||
while i < L:
|
||||
if frmt[i] != '$': inc(i)
|
||||
else: break
|
||||
if i-1 >= start: add(result, substr(frmt, start, i - 1))
|
||||
|
|
@ -1163,10 +1163,10 @@ proc defaultConfig*(): StringTableRef =
|
|||
## 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) =
|
||||
result[key] = val
|
||||
|
||||
|
||||
# If you need to modify these values, it might be worth updating the template
|
||||
# file in config/nimdoc.cfg.
|
||||
setConfigVar("split.item.toc", "20")
|
||||
|
|
@ -1214,7 +1214,7 @@ $content
|
|||
|
||||
# ---------- forum ---------------------------------------------------------
|
||||
|
||||
proc rstToHtml*(s: string, options: TRstParseOptions,
|
||||
proc rstToHtml*(s: string, options: TRstParseOptions,
|
||||
config: StringTableRef): string =
|
||||
## Converts an input rst string into embeddable HTML.
|
||||
##
|
||||
|
|
@ -1236,13 +1236,13 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
|
|||
## output you have to create your own ``TRstGenerator`` with
|
||||
## ``initRstGenerator`` and related procs.
|
||||
|
||||
proc myFindFile(filename: string): string =
|
||||
proc myFindFile(filename: string): string =
|
||||
# we don't find any files in online mode:
|
||||
result = ""
|
||||
|
||||
const filen = "input"
|
||||
var d: TRstGenerator
|
||||
initRstGenerator(d, outHtml, config, filen, options, myFindFile,
|
||||
initRstGenerator(d, outHtml, config, filen, options, myFindFile,
|
||||
rst.defaultMsgHandler)
|
||||
var dummyHasToc = false
|
||||
var rst = rstParse(s, filen, 0, 1, dummyHasToc, options)
|
||||
|
|
@ -1251,5 +1251,6 @@ proc rstToHtml*(s: string, options: TRstParseOptions,
|
|||
|
||||
|
||||
when isMainModule:
|
||||
echo rstToHtml("*Hello* **world**!", {},
|
||||
newStringTable(modeStyleInsensitive))
|
||||
assert rstToHtml("*Hello* **world**!", {},
|
||||
newStringTable(modeStyleInsensitive)) ==
|
||||
"<em>Hello</em> <strong>world</strong>!"
|
||||
|
|
|
|||
|
|
@ -10,28 +10,25 @@
|
|||
{.deadCodeElim: on.}
|
||||
import posix
|
||||
|
||||
type
|
||||
type
|
||||
Speed* = cuint
|
||||
Tcflag* = cuint
|
||||
|
||||
const
|
||||
const
|
||||
NCCS* = 32
|
||||
|
||||
type
|
||||
Termios* = object {.importc: "struct termios", header: "<termios.h>", final, pure.}
|
||||
iflag*: Tcflag # input mode flags
|
||||
oflag*: Tcflag # output mode flags
|
||||
cflag*: Tcflag # control mode flags
|
||||
lflag*: Tcflag # local mode flags
|
||||
line*: cuchar # line discipline
|
||||
cc*: array[NCCS, cuchar] # control characters
|
||||
ispeed*: Speed # input speed
|
||||
ospeed*: Speed # output speed
|
||||
|
||||
type
|
||||
Termios* {.importc: "struct termios", header: "<termios.h>".} = object
|
||||
c_iflag*: Tcflag # input mode flags
|
||||
c_oflag*: Tcflag # output mode flags
|
||||
c_cflag*: Tcflag # control mode flags
|
||||
c_lflag*: Tcflag # local mode flags
|
||||
c_line*: cuchar # line discipline
|
||||
c_cc*: array[NCCS, cuchar] # control characters
|
||||
|
||||
# cc characters
|
||||
# cc characters
|
||||
|
||||
const
|
||||
const
|
||||
VINTR* = 0
|
||||
VQUIT* = 1
|
||||
VERASE* = 2
|
||||
|
|
@ -50,9 +47,9 @@ const
|
|||
VLNEXT* = 15
|
||||
VEOL2* = 16
|
||||
|
||||
# iflag bits
|
||||
# iflag bits
|
||||
|
||||
const
|
||||
const
|
||||
IGNBRK* = 1
|
||||
BRKINT* = 2
|
||||
IGNPAR* = 4
|
||||
|
|
@ -69,9 +66,9 @@ const
|
|||
IMAXBEL* = 20000
|
||||
IUTF8* = 40000
|
||||
|
||||
# oflag bits
|
||||
# oflag bits
|
||||
|
||||
const
|
||||
const
|
||||
OPOST* = 1
|
||||
OLCUC* = 2
|
||||
ONLCR* = 4
|
||||
|
|
@ -104,9 +101,9 @@ const
|
|||
VT1* = 40000
|
||||
XTABS* = 14000
|
||||
|
||||
# cflag bit meaning
|
||||
# cflag bit meaning
|
||||
|
||||
const
|
||||
const
|
||||
CBAUD* = 10017
|
||||
B0* = 0
|
||||
B50* = 1
|
||||
|
|
@ -158,9 +155,9 @@ const
|
|||
CMSPAR* = 0o010000000000
|
||||
CRTSCTS* = 0o020000000000
|
||||
|
||||
# lflag bits
|
||||
# lflag bits
|
||||
|
||||
const
|
||||
const
|
||||
ISIG* = 1
|
||||
ICANON* = 2
|
||||
XCASE* = 4
|
||||
|
|
@ -178,87 +175,87 @@ const
|
|||
IEXTEN* = 0o000000100000
|
||||
EXTPROC* = 0o000000200000
|
||||
|
||||
# tcflow() and TCXONC use these
|
||||
# tcflow() and TCXONC use these
|
||||
|
||||
const
|
||||
const
|
||||
TCOOFF* = 0
|
||||
TCOON* = 1
|
||||
TCIOFF* = 2
|
||||
TCION* = 3
|
||||
|
||||
# tcflush() and TCFLSH use these
|
||||
# tcflush() and TCFLSH use these
|
||||
|
||||
const
|
||||
const
|
||||
TCIFLUSH* = 0
|
||||
TCOFLUSH* = 1
|
||||
TCIOFLUSH* = 2
|
||||
|
||||
# tcsetattr uses these
|
||||
# tcsetattr uses these
|
||||
|
||||
const
|
||||
const
|
||||
TCSANOW* = 0
|
||||
TCSADRAIN* = 1
|
||||
TCSAFLUSH* = 2
|
||||
|
||||
# Compare a character C to a value VAL from the `cc' array in a
|
||||
# `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it.
|
||||
# `struct termios'. If VAL is _POSIX_VDISABLE, no character can match it.
|
||||
|
||||
template cceq*(val, c: expr): expr =
|
||||
template cceq*(val, c: expr): expr =
|
||||
c == val and val != POSIX_VDISABLE
|
||||
|
||||
# Return the output baud rate stored in *TERMIOS_P.
|
||||
# Return the output baud rate stored in *TERMIOS_P.
|
||||
|
||||
proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed",
|
||||
proc cfGetOspeed*(termios: ptr Termios): Speed {.importc: "cfgetospeed",
|
||||
header: "<termios.h>".}
|
||||
# Return the input baud rate stored in *TERMIOS_P.
|
||||
# Return the input baud rate stored in *TERMIOS_P.
|
||||
|
||||
proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed",
|
||||
proc cfGetIspeed*(termios: ptr Termios): Speed {.importc: "cfgetispeed",
|
||||
header: "<termios.h>".}
|
||||
# Set the output baud rate stored in *TERMIOS_P to SPEED.
|
||||
# Set the output baud rate stored in *TERMIOS_P to SPEED.
|
||||
|
||||
proc cfSetOspeed*(termios: ptr Termios; speed: Speed): cint {.
|
||||
importc: "cfsetospeed", header: "<termios.h>".}
|
||||
# Set the input baud rate stored in *TERMIOS_P to SPEED.
|
||||
# Set the input baud rate stored in *TERMIOS_P to SPEED.
|
||||
|
||||
proc cfSetIspeed*(termios: ptr Termios; speed: Speed): cint {.
|
||||
importc: "cfsetispeed", header: "<termios.h>".}
|
||||
# Set both the input and output baud rates in *TERMIOS_OP to SPEED.
|
||||
# Set both the input and output baud rates in *TERMIOS_OP to SPEED.
|
||||
|
||||
proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {.
|
||||
importc: "cfsetspeed", header: "<termios.h>".}
|
||||
# Put the state of FD into *TERMIOS_P.
|
||||
# Put the state of FD into *TERMIOS_P.
|
||||
|
||||
proc tcGetAttr*(fd: cint; termios: ptr Termios): cint {.
|
||||
importc: "tcgetattr", header: "<termios.h>".}
|
||||
# Set the state of FD to *TERMIOS_P.
|
||||
# Values for OPTIONAL_ACTIONS (TCSA*) are in <bits/termios.h>.
|
||||
# Values for OPTIONAL_ACTIONS (TCSA*) are in <bits/termios.h>.
|
||||
|
||||
proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {.
|
||||
importc: "tcsetattr", header: "<termios.h>".}
|
||||
# Set *TERMIOS_P to indicate raw mode.
|
||||
# Set *TERMIOS_P to indicate raw mode.
|
||||
|
||||
proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw",
|
||||
proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw",
|
||||
header: "<termios.h>".}
|
||||
# Send zero bits on FD.
|
||||
# Send zero bits on FD.
|
||||
|
||||
proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak",
|
||||
proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak",
|
||||
header: "<termios.h>".}
|
||||
# Wait for pending output to be written on FD.
|
||||
#
|
||||
# This function is a cancellation point and therefore not marked with
|
||||
# .
|
||||
# .
|
||||
|
||||
proc tcDrain*(fd: cint): cint {.importc: "tcdrain", header: "<termios.h>".}
|
||||
# Flush pending data on FD.
|
||||
# Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in <bits/termios.h>.
|
||||
# Values for QUEUE_SELECTOR (TC{I,O,IO}FLUSH) are in <bits/termios.h>.
|
||||
|
||||
proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush",
|
||||
proc tcFlush*(fd: cint; queue_selector: cint): cint {.importc: "tcflush",
|
||||
header: "<termios.h>".}
|
||||
# Suspend or restart transmission on FD.
|
||||
# Values for ACTION (TC[IO]{OFF,ON}) are in <bits/termios.h>.
|
||||
# Values for ACTION (TC[IO]{OFF,ON}) are in <bits/termios.h>.
|
||||
|
||||
proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
|
||||
proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow",
|
||||
header: "<termios.h>".}
|
||||
# Get process group ID for session leader for controlling terminal FD.
|
||||
# Get process group ID for session leader for controlling terminal FD.
|
||||
|
||||
proc tcGetSid*(fd: cint): TPid {.importc: "tcgetsid", header: "<termios.h>".}
|
||||
|
|
|
|||
|
|
@ -221,7 +221,7 @@ proc spawn*[TIn](p: var TActorPool[TIn, void], input: TIn,
|
|||
setupTask()
|
||||
schedule()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var
|
||||
a: TActorPool[int, void]
|
||||
createActorPool(a)
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ proc reverse*[T](a: var openArray[T]) =
|
|||
proc reversed*[T](a: openArray[T], first, last: Natural): seq[T] =
|
||||
## returns the reverse of the array `a[first..last]`.
|
||||
result = newSeq[T](last - first + 1)
|
||||
var x = first
|
||||
var y = last
|
||||
var x = first.int
|
||||
var y = last.int
|
||||
while x <= last:
|
||||
result[x] = a[y]
|
||||
dec(y)
|
||||
|
|
|
|||
|
|
@ -634,6 +634,93 @@ when defined(windows) or defined(nimdoc):
|
|||
# free ``ol``.
|
||||
return retFuture
|
||||
|
||||
proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[int] =
|
||||
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``, which must
|
||||
## at least be of that size. Returned future will complete once all the
|
||||
## data requested is read, a part of the data has been read, or the socket
|
||||
## has disconnected in which case the future will complete with a value of
|
||||
## ``0``.
|
||||
##
|
||||
## **Warning**: The ``Peek`` socket flag is not supported on Windows.
|
||||
|
||||
|
||||
# Things to note:
|
||||
# * When WSARecv completes immediately then ``bytesReceived`` is very
|
||||
# unreliable.
|
||||
# * Still need to implement message-oriented socket disconnection,
|
||||
# '\0' in the message currently signifies a socket disconnect. Who
|
||||
# knows what will happen when someone sends that to our socket.
|
||||
verifyPresence(socket)
|
||||
assert SocketFlag.Peek notin flags, "Peek not supported on Windows."
|
||||
|
||||
var retFuture = newFuture[int]("recvInto")
|
||||
|
||||
#buf[] = '\0'
|
||||
var dataBuf: TWSABuf
|
||||
dataBuf.buf = buf
|
||||
dataBuf.len = size
|
||||
|
||||
var bytesReceived: Dword
|
||||
var flagsio = flags.toOSFlags().Dword
|
||||
var ol = PCustomOverlapped()
|
||||
GC_ref(ol)
|
||||
ol.data = TCompletionData(fd: socket, cb:
|
||||
proc (fd: TAsyncFD, bytesCount: Dword, errcode: OSErrorCode) =
|
||||
if not retFuture.finished:
|
||||
if errcode == OSErrorCode(-1):
|
||||
if bytesCount == 0 and dataBuf.buf[0] == '\0':
|
||||
retFuture.complete(0)
|
||||
else:
|
||||
retFuture.complete(bytesCount)
|
||||
else:
|
||||
if flags.isDisconnectionError(errcode):
|
||||
retFuture.complete(0)
|
||||
else:
|
||||
retFuture.fail(newException(OSError, osErrorMsg(errcode)))
|
||||
if dataBuf.buf != nil:
|
||||
dataBuf.buf = nil
|
||||
)
|
||||
|
||||
let ret = WSARecv(socket.SocketHandle, addr dataBuf, 1, addr bytesReceived,
|
||||
addr flagsio, cast[POVERLAPPED](ol), nil)
|
||||
if ret == -1:
|
||||
let err = osLastError()
|
||||
if err.int32 != ERROR_IO_PENDING:
|
||||
if dataBuf.buf != nil:
|
||||
dataBuf.buf = nil
|
||||
GC_unref(ol)
|
||||
if flags.isDisconnectionError(err):
|
||||
retFuture.complete(0)
|
||||
else:
|
||||
retFuture.fail(newException(OSError, osErrorMsg(err)))
|
||||
elif ret == 0 and bytesReceived == 0 and dataBuf.buf[0] == '\0':
|
||||
# We have to ensure that the buffer is empty because WSARecv will tell
|
||||
# us immediately when it was disconnected, even when there is still
|
||||
# data in the buffer.
|
||||
# We want to give the user as much data as we can. So we only return
|
||||
# the empty string (which signals a disconnection) when there is
|
||||
# nothing left to read.
|
||||
retFuture.complete(0)
|
||||
# TODO: "For message-oriented sockets, where a zero byte message is often
|
||||
# allowable, a failure with an error code of WSAEDISCON is used to
|
||||
# indicate graceful closure."
|
||||
# ~ http://msdn.microsoft.com/en-us/library/ms741688%28v=vs.85%29.aspx
|
||||
else:
|
||||
# Request to read completed immediately.
|
||||
# From my tests bytesReceived isn't reliable.
|
||||
let realSize =
|
||||
if bytesReceived == 0:
|
||||
size
|
||||
else:
|
||||
bytesReceived
|
||||
assert realSize <= size
|
||||
retFuture.complete(realSize)
|
||||
# We don't deallocate ``ol`` here because even though this completed
|
||||
# immediately poll will still be notified about its completion and it will
|
||||
# free ``ol``.
|
||||
return retFuture
|
||||
|
||||
proc send*(socket: TAsyncFD, data: string,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[void] =
|
||||
## Sends ``data`` to ``socket``. The returned future will complete once all
|
||||
|
|
@ -983,6 +1070,30 @@ else:
|
|||
addRead(socket, cb)
|
||||
return retFuture
|
||||
|
||||
proc recvInto*(socket: TAsyncFD, buf: cstring, size: int,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[int] =
|
||||
var retFuture = newFuture[int]("recvInto")
|
||||
|
||||
proc cb(sock: TAsyncFD): bool =
|
||||
result = true
|
||||
let res = recv(sock.SocketHandle, buf, size.cint,
|
||||
flags.toOSFlags())
|
||||
if res < 0:
|
||||
let lastError = osLastError()
|
||||
if lastError.int32 notin {EINTR, EWOULDBLOCK, EAGAIN}:
|
||||
if flags.isDisconnectionError(lastError):
|
||||
retFuture.complete(0)
|
||||
else:
|
||||
retFuture.fail(newException(OSError, osErrorMsg(lastError)))
|
||||
else:
|
||||
result = false # We still want this callback to be called.
|
||||
else:
|
||||
retFuture.complete(res)
|
||||
# TODO: The following causes a massive slowdown.
|
||||
#if not cb(socket):
|
||||
addRead(socket, cb)
|
||||
return retFuture
|
||||
|
||||
proc send*(socket: TAsyncFD, data: string,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[void] =
|
||||
var retFuture = newFuture[void]("send")
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ proc newAsyncFtpClient*(address: string, port = Port(21),
|
|||
result.dsockConnected = false
|
||||
result.csock = newAsyncSocket()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var ftp = newAsyncFtpClient("example.com", user = "test", pass = "test")
|
||||
proc main(ftp: AsyncFtpClient) {.async.} =
|
||||
await ftp.connect()
|
||||
|
|
|
|||
|
|
@ -23,8 +23,7 @@
|
|||
## proc cb(req: Request) {.async.} =
|
||||
## await req.respond(Http200, "Hello World")
|
||||
##
|
||||
## asyncCheck server.serve(Port(8080), cb)
|
||||
## runForever()
|
||||
## waitFor server.serve(Port(8080), cb)
|
||||
|
||||
import strtabs, asyncnet, asyncdispatch, parseutils, uri, strutils
|
||||
type
|
||||
|
|
@ -109,22 +108,19 @@ proc sendHeaders*(req: Request, headers: StringTableRef): Future[void] =
|
|||
addHeaders(msg, headers)
|
||||
return req.client.send(msg)
|
||||
|
||||
proc respond*(req: Request, code: HttpCode,
|
||||
content: string, headers = newStringTable()) {.async.} =
|
||||
proc respond*(req: Request, code: HttpCode, content: string,
|
||||
headers: StringTableRef = nil): Future[void] =
|
||||
## Responds to the request with the specified ``HttpCode``, headers and
|
||||
## content.
|
||||
##
|
||||
## This procedure will **not** close the client socket.
|
||||
var customHeaders = headers
|
||||
customHeaders["Content-Length"] = $content.len
|
||||
var msg = "HTTP/1.1 " & $code & "\c\L"
|
||||
msg.addHeaders(customHeaders)
|
||||
await req.client.send(msg & "\c\L" & content)
|
||||
|
||||
proc newRequest(): Request =
|
||||
result.headers = newStringTable(modeCaseInsensitive)
|
||||
result.hostname = ""
|
||||
result.body = ""
|
||||
if headers != nil:
|
||||
msg.addHeaders(headers)
|
||||
msg.add("Content-Length: " & $content.len & "\c\L\c\L")
|
||||
msg.add(content)
|
||||
result = req.client.send(msg)
|
||||
|
||||
proc parseHeader(line: string): tuple[key, value: string] =
|
||||
var i = 0
|
||||
|
|
@ -149,59 +145,65 @@ proc sendStatus(client: AsyncSocket, status: string): Future[void] =
|
|||
proc processClient(client: AsyncSocket, address: string,
|
||||
callback: proc (request: Request):
|
||||
Future[void] {.closure, gcsafe.}) {.async.} =
|
||||
var request: Request
|
||||
request.url = initUri()
|
||||
request.headers = newStringTable(modeCaseInsensitive)
|
||||
var line = newStringOfCap(80)
|
||||
var key, value = ""
|
||||
|
||||
while not client.isClosed:
|
||||
# GET /path HTTP/1.1
|
||||
# Header: val
|
||||
# \n
|
||||
var request = newRequest()
|
||||
request.hostname = address
|
||||
request.headers.clear(modeCaseInsensitive)
|
||||
request.hostname.shallowCopy(address)
|
||||
assert client != nil
|
||||
request.client = client
|
||||
|
||||
# First line - GET /path HTTP/1.1
|
||||
let line = await client.recvLine() # TODO: Timeouts.
|
||||
line.setLen(0)
|
||||
await client.recvLineInto(addr line) # TODO: Timeouts.
|
||||
if line == "":
|
||||
client.close()
|
||||
return
|
||||
let lineParts = line.split(' ')
|
||||
if lineParts.len != 3:
|
||||
await request.respond(Http400, "Invalid request. Got: " & line)
|
||||
continue
|
||||
|
||||
let reqMethod = lineParts[0]
|
||||
let path = lineParts[1]
|
||||
let protocol = lineParts[2]
|
||||
var i = 0
|
||||
for linePart in line.split(' '):
|
||||
case i
|
||||
of 0: request.reqMethod.shallowCopy(linePart.normalize)
|
||||
of 1: parseUri(linePart, request.url)
|
||||
of 2:
|
||||
try:
|
||||
request.protocol = parseProtocol(linePart)
|
||||
except ValueError:
|
||||
asyncCheck request.respond(Http400,
|
||||
"Invalid request protocol. Got: " & linePart)
|
||||
continue
|
||||
else:
|
||||
await request.respond(Http400, "Invalid request. Got: " & line)
|
||||
continue
|
||||
inc i
|
||||
|
||||
# Headers
|
||||
var i = 0
|
||||
while true:
|
||||
i = 0
|
||||
let headerLine = await client.recvLine()
|
||||
if headerLine == "":
|
||||
line.setLen(0)
|
||||
await client.recvLineInto(addr line)
|
||||
|
||||
if line == "":
|
||||
client.close(); return
|
||||
if headerLine == "\c\L": break
|
||||
# TODO: Compiler crash
|
||||
#let (key, value) = parseHeader(headerLine)
|
||||
let kv = parseHeader(headerLine)
|
||||
request.headers[kv.key] = kv.value
|
||||
if line == "\c\L": break
|
||||
let (key, value) = parseHeader(line)
|
||||
request.headers[key] = value
|
||||
|
||||
request.reqMethod = reqMethod
|
||||
request.url = parseUri(path)
|
||||
try:
|
||||
request.protocol = protocol.parseProtocol()
|
||||
except ValueError:
|
||||
asyncCheck request.respond(Http400, "Invalid request protocol. Got: " &
|
||||
protocol)
|
||||
continue
|
||||
|
||||
if reqMethod.normalize == "post":
|
||||
if request.reqMethod == "post":
|
||||
# Check for Expect header
|
||||
if request.headers.hasKey("Expect"):
|
||||
if request.headers["Expect"].toLower == "100-continue":
|
||||
await client.sendStatus("100 Continue")
|
||||
else:
|
||||
await client.sendStatus("417 Expectation Failed")
|
||||
|
||||
|
||||
# Read the body
|
||||
# - Check for Content-length header
|
||||
if request.headers.hasKey("Content-Length"):
|
||||
|
|
@ -215,11 +217,11 @@ proc processClient(client: AsyncSocket, address: string,
|
|||
await request.respond(Http400, "Bad Request. No Content-Length.")
|
||||
continue
|
||||
|
||||
case reqMethod.normalize
|
||||
case request.reqMethod
|
||||
of "get", "post", "head", "put", "delete", "trace", "options", "connect", "patch":
|
||||
await callback(request)
|
||||
else:
|
||||
await request.respond(Http400, "Invalid request method. Got: " & reqMethod)
|
||||
await request.respond(Http400, "Invalid request method. Got: " & request.reqMethod)
|
||||
|
||||
# Persistent connections
|
||||
if (request.protocol == HttpVer11 and
|
||||
|
|
@ -247,7 +249,7 @@ proc serve*(server: AsyncHttpServer, port: Port,
|
|||
server.socket.setSockOpt(OptReuseAddr, true)
|
||||
server.socket.bindAddr(port, address)
|
||||
server.socket.listen()
|
||||
|
||||
|
||||
while true:
|
||||
# TODO: Causes compiler crash.
|
||||
#var (address, client) = await server.socket.acceptAddr()
|
||||
|
|
@ -260,7 +262,7 @@ proc close*(server: AsyncHttpServer) =
|
|||
## Terminates the async http server instance.
|
||||
server.socket.close()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
proc main =
|
||||
var server = newAsyncHttpServer()
|
||||
proc cb(req: Request) {.async.} =
|
||||
|
|
|
|||
|
|
@ -660,7 +660,7 @@ proc len*(disp: Dispatcher): int =
|
|||
## Retrieves the amount of delegates in ``disp``.
|
||||
return disp.delegates.len
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
|
||||
proc testConnect(s: AsyncSocket, no: int) =
|
||||
echo("Connected! " & $no)
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
##
|
||||
## Chat server
|
||||
## ^^^^^^^^^^^
|
||||
##
|
||||
##
|
||||
## The following example demonstrates a simple chat server.
|
||||
##
|
||||
## .. code-block::nim
|
||||
|
|
@ -182,26 +182,30 @@ proc connect*(socket: AsyncSocket, address: string, port: Port,
|
|||
sslSetConnectState(socket.sslHandle)
|
||||
sslLoop(socket, flags, sslDoHandshake(socket.sslHandle))
|
||||
|
||||
proc readInto(buf: cstring, size: int, socket: AsyncSocket,
|
||||
flags: set[SocketFlag]): Future[int] {.async.} =
|
||||
template readInto(buf: cstring, size: int, socket: AsyncSocket,
|
||||
flags: set[SocketFlag]): int =
|
||||
## Reads **up to** ``size`` bytes from ``socket`` into ``buf``. Note that
|
||||
## this is a template and not a proc.
|
||||
var res = 0
|
||||
if socket.isSsl:
|
||||
when defined(ssl):
|
||||
# SSL mode.
|
||||
sslLoop(socket, flags,
|
||||
sslRead(socket.sslHandle, buf, size.cint))
|
||||
result = opResult
|
||||
res = opResult
|
||||
else:
|
||||
var data = await recv(socket.fd.TAsyncFD, size, flags)
|
||||
if data.len != 0:
|
||||
copyMem(buf, addr data[0], data.len)
|
||||
var recvIntoFut = recvInto(socket.fd.TAsyncFD, buf, size, flags)
|
||||
yield recvIntoFut
|
||||
# Not in SSL mode.
|
||||
result = data.len
|
||||
res = recvIntoFut.read()
|
||||
res
|
||||
|
||||
proc readIntoBuf(socket: AsyncSocket,
|
||||
flags: set[SocketFlag]): Future[int] {.async.} =
|
||||
result = await readInto(addr socket.buffer[0], BufferSize, socket, flags)
|
||||
template readIntoBuf(socket: AsyncSocket,
|
||||
flags: set[SocketFlag]): int =
|
||||
var size = readInto(addr socket.buffer[0], BufferSize, socket, flags)
|
||||
socket.currPos = 0
|
||||
socket.bufLen = result
|
||||
socket.bufLen = size
|
||||
size
|
||||
|
||||
proc recv*(socket: AsyncSocket, size: int,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
|
||||
|
|
@ -222,10 +226,11 @@ proc recv*(socket: AsyncSocket, size: int,
|
|||
## to be read then the future will complete with a value of ``""``.
|
||||
if socket.isBuffered:
|
||||
result = newString(size)
|
||||
shallow(result)
|
||||
let originalBufPos = socket.currPos
|
||||
|
||||
if socket.bufLen == 0:
|
||||
let res = await socket.readIntoBuf(flags - {SocketFlag.Peek})
|
||||
let res = socket.readIntoBuf(flags - {SocketFlag.Peek})
|
||||
if res == 0:
|
||||
result.setLen(0)
|
||||
return
|
||||
|
|
@ -236,7 +241,7 @@ proc recv*(socket: AsyncSocket, size: int,
|
|||
if SocketFlag.Peek in flags:
|
||||
# We don't want to get another buffer if we're peeking.
|
||||
break
|
||||
let res = await socket.readIntoBuf(flags - {SocketFlag.Peek})
|
||||
let res = socket.readIntoBuf(flags - {SocketFlag.Peek})
|
||||
if res == 0:
|
||||
break
|
||||
|
||||
|
|
@ -251,7 +256,7 @@ proc recv*(socket: AsyncSocket, size: int,
|
|||
result.setLen(read)
|
||||
else:
|
||||
result = newString(size)
|
||||
let read = await readInto(addr result[0], size, socket, flags)
|
||||
let read = readInto(addr result[0], size, socket, flags)
|
||||
result.setLen(read)
|
||||
|
||||
proc send*(socket: AsyncSocket, data: string,
|
||||
|
|
@ -302,15 +307,14 @@ proc accept*(socket: AsyncSocket,
|
|||
retFut.complete(future.read.client)
|
||||
return retFut
|
||||
|
||||
proc recvLine*(socket: AsyncSocket,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
|
||||
## Reads a line of data from ``socket``. Returned future will complete once
|
||||
## a full line is read or an error occurs.
|
||||
proc recvLineInto*(socket: AsyncSocket, resString: ptr string,
|
||||
flags = {SocketFlag.SafeDisconn}) {.async.} =
|
||||
## Reads a line of data from ``socket`` into ``resString``.
|
||||
##
|
||||
## If a full line is read ``\r\L`` is not
|
||||
## added to ``line``, however if solely ``\r\L`` is read then ``line``
|
||||
## will be set to it.
|
||||
##
|
||||
##
|
||||
## If the socket is disconnected, ``line`` will be set to ``""``.
|
||||
##
|
||||
## If the socket is disconnected in the middle of a line (before ``\r\L``
|
||||
|
|
@ -318,27 +322,32 @@ proc recvLine*(socket: AsyncSocket,
|
|||
## The partial line **will be lost**.
|
||||
##
|
||||
## **Warning**: The ``Peek`` flag is not yet implemented.
|
||||
##
|
||||
## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
|
||||
## uses ``\r\L`` to delimit a new line.
|
||||
template addNLIfEmpty(): stmt =
|
||||
if result.len == 0:
|
||||
result.add("\c\L")
|
||||
##
|
||||
## **Warning**: ``recvLineInto`` on unbuffered sockets assumes that the
|
||||
## protocol uses ``\r\L`` to delimit a new line.
|
||||
##
|
||||
## **Warning**: ``recvLineInto`` currently uses a raw pointer to a string for
|
||||
## performance reasons. This will likely change soon to use FutureVars.
|
||||
assert SocketFlag.Peek notin flags ## TODO:
|
||||
result = newFuture[void]("asyncnet.recvLineInto")
|
||||
|
||||
template addNLIfEmpty(): stmt =
|
||||
if resString[].len == 0:
|
||||
resString[].add("\c\L")
|
||||
|
||||
if socket.isBuffered:
|
||||
result = ""
|
||||
if socket.bufLen == 0:
|
||||
let res = await socket.readIntoBuf(flags)
|
||||
let res = socket.readIntoBuf(flags)
|
||||
if res == 0:
|
||||
return
|
||||
|
||||
var lastR = false
|
||||
while true:
|
||||
if socket.currPos >= socket.bufLen:
|
||||
let res = await socket.readIntoBuf(flags)
|
||||
let res = socket.readIntoBuf(flags)
|
||||
if res == 0:
|
||||
result = ""
|
||||
break
|
||||
resString[].setLen(0)
|
||||
return
|
||||
|
||||
case socket.buffer[socket.currPos]
|
||||
of '\r':
|
||||
|
|
@ -353,24 +362,53 @@ proc recvLine*(socket: AsyncSocket,
|
|||
socket.currPos.inc()
|
||||
return
|
||||
else:
|
||||
result.add socket.buffer[socket.currPos]
|
||||
resString[].add socket.buffer[socket.currPos]
|
||||
socket.currPos.inc()
|
||||
else:
|
||||
result = ""
|
||||
var c = ""
|
||||
while true:
|
||||
c = await recv(socket, 1, flags)
|
||||
let recvFut = recv(socket, 1, flags)
|
||||
c = recvFut.read()
|
||||
if c.len == 0:
|
||||
return ""
|
||||
resString[].setLen(0)
|
||||
return
|
||||
if c == "\r":
|
||||
c = await recv(socket, 1, flags) # Skip \L
|
||||
let recvFut = recv(socket, 1, flags) # Skip \L
|
||||
c = recvFut.read()
|
||||
assert c == "\L"
|
||||
addNLIfEmpty()
|
||||
return
|
||||
elif c == "\L":
|
||||
addNLIfEmpty()
|
||||
return
|
||||
add(result.string, c)
|
||||
resString[].add c
|
||||
|
||||
proc recvLine*(socket: AsyncSocket,
|
||||
flags = {SocketFlag.SafeDisconn}): Future[string] {.async.} =
|
||||
## Reads a line of data from ``socket``. Returned future will complete once
|
||||
## a full line is read or an error occurs.
|
||||
##
|
||||
## If a full line is read ``\r\L`` is not
|
||||
## added to ``line``, however if solely ``\r\L`` is read then ``line``
|
||||
## will be set to it.
|
||||
##
|
||||
## If the socket is disconnected, ``line`` will be set to ``""``.
|
||||
##
|
||||
## If the socket is disconnected in the middle of a line (before ``\r\L``
|
||||
## is read) then line will be set to ``""``.
|
||||
## The partial line **will be lost**.
|
||||
##
|
||||
## **Warning**: The ``Peek`` flag is not yet implemented.
|
||||
##
|
||||
## **Warning**: ``recvLine`` on unbuffered sockets assumes that the protocol
|
||||
## uses ``\r\L`` to delimit a new line.
|
||||
template addNLIfEmpty(): stmt =
|
||||
if result.len == 0:
|
||||
result.add("\c\L")
|
||||
assert SocketFlag.Peek notin flags ## TODO:
|
||||
|
||||
result = ""
|
||||
await socket.recvLineInto(addr result, flags)
|
||||
|
||||
proc listen*(socket: AsyncSocket, backlog = SOMAXCONN) {.tags: [ReadIOEffect].} =
|
||||
## Marks ``socket`` as accepting connections.
|
||||
|
|
@ -458,7 +496,7 @@ proc isClosed*(socket: AsyncSocket): bool =
|
|||
## Determines whether the socket has been closed.
|
||||
return socket.closed
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
type
|
||||
TestCases = enum
|
||||
HighClient, LowClient, LowServer
|
||||
|
|
@ -500,11 +538,11 @@ when isMainModule:
|
|||
proc (future: Future[void]) =
|
||||
echo("Send")
|
||||
client.close()
|
||||
|
||||
|
||||
var f = accept(sock)
|
||||
f.callback = onAccept
|
||||
|
||||
|
||||
var f = accept(sock)
|
||||
f.callback = onAccept
|
||||
runForever()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,33 +16,33 @@ import times
|
|||
## Vectors are implemented as direction vectors, ie. when transformed with a matrix
|
||||
## the translation part of matrix is ignored. The coordinate system used is
|
||||
## right handed, because its compatible with 2d coordinate system (rotation around
|
||||
## zaxis equals 2d rotation).
|
||||
## zaxis equals 2d rotation).
|
||||
## Operators `+` , `-` , `*` , `/` , `+=` , `-=` , `*=` and `/=` are implemented
|
||||
## for vectors and scalars.
|
||||
##
|
||||
##
|
||||
## Quick start example:
|
||||
##
|
||||
##
|
||||
## # Create a matrix which first rotates, then scales and at last translates
|
||||
##
|
||||
##
|
||||
## var m:TMatrix3d=rotate(PI,vector3d(1,1,2.5)) & scale(2.0) & move(100.0,200.0,300.0)
|
||||
##
|
||||
##
|
||||
## # Create a 3d point at (100,150,200) and a vector (5,2,3)
|
||||
##
|
||||
## var pt:TPoint3d=point3d(100.0,150.0,200.0)
|
||||
##
|
||||
##
|
||||
## var pt:TPoint3d=point3d(100.0,150.0,200.0)
|
||||
##
|
||||
## var vec:TVector3d=vector3d(5.0,2.0,3.0)
|
||||
##
|
||||
##
|
||||
##
|
||||
##
|
||||
## pt &= m # transforms pt in place
|
||||
##
|
||||
##
|
||||
## var pt2:TPoint3d=pt & m #concatenates pt with m and returns a new point
|
||||
##
|
||||
##
|
||||
## var vec2:TVector3d=vec & m #concatenates vec with m and returns a new vector
|
||||
|
||||
|
||||
|
||||
type
|
||||
type
|
||||
TMatrix3d* =object
|
||||
## Implements a row major 3d matrix, which means
|
||||
## transformations are applied the order they are concatenated.
|
||||
|
|
@ -53,12 +53,12 @@ type
|
|||
## [ tx ty tz tw ]
|
||||
ax*,ay*,az*,aw*, bx*,by*,bz*,bw*, cx*,cy*,cz*,cw*, tx*,ty*,tz*,tw*:float
|
||||
TPoint3d* = object
|
||||
## Implements a non-homegeneous 2d point stored as
|
||||
## Implements a non-homegeneous 2d point stored as
|
||||
## an `x` , `y` and `z` coordinate.
|
||||
x*,y*,z*:float
|
||||
TVector3d* = object
|
||||
## Implements a 3d **direction vector** stored as
|
||||
## an `x` , `y` and `z` coordinate. Direction vector means,
|
||||
TVector3d* = object
|
||||
## Implements a 3d **direction vector** stored as
|
||||
## an `x` , `y` and `z` coordinate. Direction vector means,
|
||||
## that when transforming a vector with a matrix, the translational
|
||||
## part of the matrix is ignored.
|
||||
x*,y*,z*:float
|
||||
|
|
@ -67,7 +67,7 @@ type
|
|||
|
||||
# Some forward declarations
|
||||
proc matrix3d*(ax,ay,az,aw,bx,by,bz,bw,cx,cy,cz,cw,tx,ty,tz,tw:float):TMatrix3d {.noInit.}
|
||||
## Creates a new 4x4 3d transformation matrix.
|
||||
## Creates a new 4x4 3d transformation matrix.
|
||||
## `ax` , `ay` , `az` is the local x axis.
|
||||
## `bx` , `by` , `bz` is the local y axis.
|
||||
## `cx` , `cy` , `cz` is the local z axis.
|
||||
|
|
@ -76,7 +76,7 @@ proc vector3d*(x,y,z:float):TVector3d {.noInit,inline.}
|
|||
## Returns a new 3d vector (`x`,`y`,`z`)
|
||||
proc point3d*(x,y,z:float):TPoint3d {.noInit,inline.}
|
||||
## Returns a new 4d point (`x`,`y`,`z`)
|
||||
proc tryNormalize*(v:var TVector3d):bool
|
||||
proc tryNormalize*(v:var TVector3d):bool
|
||||
## Modifies `v` to have a length of 1.0, keeping its angle.
|
||||
## If `v` has zero length (and thus no angle), it is left unmodified and false is
|
||||
## returned, otherwise true is returned.
|
||||
|
|
@ -85,7 +85,7 @@ proc tryNormalize*(v:var TVector3d):bool
|
|||
|
||||
let
|
||||
IDMATRIX*:TMatrix3d=matrix3d(
|
||||
1.0,0.0,0.0,0.0,
|
||||
1.0,0.0,0.0,0.0,
|
||||
0.0,1.0,0.0,0.0,
|
||||
0.0,0.0,1.0,0.0,
|
||||
0.0,0.0,0.0,1.0)
|
||||
|
|
@ -114,20 +114,20 @@ proc safeArccos(v:float):float=
|
|||
## due to rounding issues
|
||||
return arccos(clamp(v,-1.0,1.0))
|
||||
|
||||
template makeBinOpVector(s:expr)=
|
||||
template makeBinOpVector(s:expr)=
|
||||
## implements binary operators + , - , * and / for vectors
|
||||
proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
|
||||
proc s*(a,b:TVector3d):TVector3d {.inline,noInit.} =
|
||||
vector3d(s(a.x,b.x),s(a.y,b.y),s(a.z,b.z))
|
||||
proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.} =
|
||||
proc s*(a:TVector3d,b:float):TVector3d {.inline,noInit.} =
|
||||
vector3d(s(a.x,b),s(a.y,b),s(a.z,b))
|
||||
proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.} =
|
||||
proc s*(a:float,b:TVector3d):TVector3d {.inline,noInit.} =
|
||||
vector3d(s(a,b.x),s(a,b.y),s(a,b.z))
|
||||
|
||||
template makeBinOpAssignVector(s:expr)=
|
||||
|
||||
template makeBinOpAssignVector(s:expr)=
|
||||
## implements inplace binary operators += , -= , /= and *= for vectors
|
||||
proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
|
||||
proc s*(a:var TVector3d,b:TVector3d) {.inline.} =
|
||||
s(a.x,b.x) ; s(a.y,b.y) ; s(a.z,b.z)
|
||||
proc s*(a:var TVector3d,b:float) {.inline.} =
|
||||
proc s*(a:var TVector3d,b:float) {.inline.} =
|
||||
s(a.x,b) ; s(a.y,b) ; s(a.z,b)
|
||||
|
||||
|
||||
|
|
@ -188,20 +188,20 @@ proc scale*(s:float):TMatrix3d {.noInit.} =
|
|||
|
||||
proc scale*(s:float,org:TPoint3d):TMatrix3d {.noInit.} =
|
||||
## Returns a new scaling matrix using, `org` as scale origin.
|
||||
result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
|
||||
result.setElements(s,0,0,0, 0,s,0,0, 0,0,s,0,
|
||||
org.x-s*org.x,org.y-s*org.y,org.z-s*org.z,1.0)
|
||||
|
||||
proc stretch*(sx,sy,sz:float):TMatrix3d {.noInit.} =
|
||||
## Returns new a stretch matrix, which is a
|
||||
## scale matrix with non uniform scale in x,y and z.
|
||||
result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, 0,0,0,1)
|
||||
|
||||
|
||||
proc stretch*(sx,sy,sz:float,org:TPoint3d):TMatrix3d {.noInit.} =
|
||||
## Returns a new stretch matrix, which is a
|
||||
## scale matrix with non uniform scale in x,y and z.
|
||||
## `org` is used as stretch origin.
|
||||
result.setElements(sx,0,0,0, 0,sy,0,0, 0,0,sz,0, org.x-sx*org.x,org.y-sy*org.y,org.z-sz*org.z,1)
|
||||
|
||||
|
||||
proc move*(dx,dy,dz:float):TMatrix3d {.noInit.} =
|
||||
## Returns a new translation matrix.
|
||||
result.setElements(1,0,0,0, 0,1,0,0, 0,0,1,0, dx,dy,dz,1)
|
||||
|
|
@ -235,7 +235,7 @@ proc rotate*(angle:float,axis:TVector3d):TMatrix3d {.noInit.}=
|
|||
uvomc=normax.x*normax.y*omc
|
||||
uwomc=normax.x*normax.z*omc
|
||||
vwomc=normax.y*normax.z*omc
|
||||
|
||||
|
||||
result.setElements(
|
||||
u2+(1.0-u2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
|
||||
uvomc-wsi, v2+(1.0-v2)*cs, vwomc+usi, 0.0,
|
||||
|
|
@ -248,11 +248,11 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
|
|||
|
||||
# see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
|
||||
# for how this is computed
|
||||
|
||||
|
||||
var normax=axis
|
||||
if not normax.tryNormalize: #simplifies matrix computation below a lot
|
||||
raise newException(DivByZeroError,"Cannot rotate around zero length axis")
|
||||
|
||||
|
||||
let
|
||||
u=normax.x
|
||||
v=normax.y
|
||||
|
|
@ -272,7 +272,7 @@ proc rotate*(angle:float,org:TPoint3d,axis:TVector3d):TMatrix3d {.noInit.}=
|
|||
uvomc=normax.x*normax.y*omc
|
||||
uwomc=normax.x*normax.z*omc
|
||||
vwomc=normax.y*normax.z*omc
|
||||
|
||||
|
||||
result.setElements(
|
||||
u2+(v2+w2)*cs, uvomc+wsi, uwomc-vsi, 0.0,
|
||||
uvomc-wsi, v2+(u2+w2)*cs, vwomc+usi, 0.0,
|
||||
|
|
@ -305,7 +305,7 @@ proc rotateY*(angle:float):TMatrix3d {.noInit.}=
|
|||
0,1,0,0,
|
||||
s,0,c,0,
|
||||
0,0,0,1)
|
||||
|
||||
|
||||
proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
|
||||
## Creates a matrix that rotates around the z-axis with `angle` radians,
|
||||
## which is also called a 'yaw' matrix.
|
||||
|
|
@ -317,19 +317,19 @@ proc rotateZ*(angle:float):TMatrix3d {.noInit.}=
|
|||
-s,c,0,0,
|
||||
0,0,1,0,
|
||||
0,0,0,1)
|
||||
|
||||
|
||||
proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
|
||||
## Checks if the transform is uniform, that is
|
||||
## Checks if the transform is uniform, that is
|
||||
## perpendicular axes of equal length, which means (for example)
|
||||
## it cannot transform a sphere into an ellipsoid.
|
||||
## `tol` is used as tolerance for both equal length comparison
|
||||
## `tol` is used as tolerance for both equal length comparison
|
||||
## and perpendicular comparison.
|
||||
|
||||
|
||||
#dot product=0 means perpendicular coord. system, check xaxis vs yaxis and xaxis vs zaxis
|
||||
if abs(m.ax*m.bx+m.ay*m.by+m.az*m.bz)<=tol and # x vs y
|
||||
abs(m.ax*m.cx+m.ay*m.cy+m.az*m.cz)<=tol and #x vs z
|
||||
abs(m.bx*m.cx+m.by*m.cy+m.bz*m.cz)<=tol: #y vs z
|
||||
|
||||
|
||||
#subtract squared lengths of axes to check if uniform scaling:
|
||||
let
|
||||
sqxlen=(m.ax*m.ax+m.ay*m.ay+m.az*m.az)
|
||||
|
|
@ -340,16 +340,16 @@ proc isUniform*(m:TMatrix3d,tol=1.0e-6):bool=
|
|||
return false
|
||||
|
||||
|
||||
|
||||
|
||||
proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
|
||||
## Creates a matrix that mirrors over the plane that has `planeperp` as normal,
|
||||
## and passes through origo. `planeperp` does not need to be normalized.
|
||||
|
||||
|
||||
# https://en.wikipedia.org/wiki/Transformation_matrix
|
||||
var n=planeperp
|
||||
if not n.tryNormalize:
|
||||
raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
|
||||
|
||||
|
||||
let
|
||||
a=n.x
|
||||
b=n.y
|
||||
|
|
@ -357,7 +357,7 @@ proc mirror*(planeperp:TVector3d):TMatrix3d {.noInit.}=
|
|||
ab=a*b
|
||||
ac=a*c
|
||||
bc=b*c
|
||||
|
||||
|
||||
result.setElements(
|
||||
1-2*a*a , -2*ab,-2*ac,0,
|
||||
-2*ab , 1-2*b*b, -2*bc, 0,
|
||||
|
|
@ -376,7 +376,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
|
|||
var n=planeperp
|
||||
if not n.tryNormalize:
|
||||
raise newException(DivByZeroError,"Cannot mirror over a plane with a zero length normal")
|
||||
|
||||
|
||||
let
|
||||
a=n.x
|
||||
b=n.y
|
||||
|
|
@ -390,7 +390,7 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
|
|||
tx=org.x
|
||||
ty=org.y
|
||||
tz=org.z
|
||||
|
||||
|
||||
result.setElements(
|
||||
1-2*aa , -2*ab,-2*ac,0,
|
||||
-2*ab , 1-2*bb, -2*bc, 0,
|
||||
|
|
@ -402,8 +402,8 @@ proc mirror*(org:TPoint3d,planeperp:TVector3d):TMatrix3d {.noInit.}=
|
|||
|
||||
proc determinant*(m:TMatrix3d):float=
|
||||
## Computes the determinant of matrix `m`.
|
||||
|
||||
# This computation is gotten from ratsimp(optimize(determinant(m)))
|
||||
|
||||
# This computation is gotten from ratsimp(optimize(determinant(m)))
|
||||
# in maxima CAS
|
||||
let
|
||||
O1=m.cx*m.tw-m.cw*m.tx
|
||||
|
|
@ -423,10 +423,10 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
|
|||
## Computes the inverse of matrix `m`. If the matrix
|
||||
## determinant is zero, thus not invertible, a EDivByZero
|
||||
## will be raised.
|
||||
|
||||
|
||||
# this computation comes from optimize(invert(m)) in maxima CAS
|
||||
|
||||
let
|
||||
|
||||
let
|
||||
det=m.determinant
|
||||
O2=m.cy*m.tw-m.cw*m.ty
|
||||
O3=m.cz*m.tw-m.cw*m.tz
|
||||
|
|
@ -464,7 +464,7 @@ proc inverse*(m:TMatrix3d):TMatrix3d {.noInit.}=
|
|||
proc equals*(m1:TMatrix3d,m2:TMatrix3d,tol=1.0e-6):bool=
|
||||
## Checks if all elements of `m1`and `m2` is equal within
|
||||
## a given tolerance `tol`.
|
||||
return
|
||||
return
|
||||
abs(m1.ax-m2.ax)<=tol and
|
||||
abs(m1.ay-m2.ay)<=tol and
|
||||
abs(m1.az-m2.az)<=tol and
|
||||
|
|
@ -486,11 +486,11 @@ proc `=~`*(m1,m2:TMatrix3d):bool=
|
|||
## Checks if `m1` and `m2` is approximately equal, using a
|
||||
## tolerance of 1e-6.
|
||||
equals(m1,m2)
|
||||
|
||||
|
||||
proc transpose*(m:TMatrix3d):TMatrix3d {.noInit.}=
|
||||
## Returns the transpose of `m`
|
||||
result.setElements(m.ax,m.bx,m.cx,m.tx,m.ay,m.by,m.cy,m.ty,m.az,m.bz,m.cz,m.tz,m.aw,m.bw,m.cw,m.tw)
|
||||
|
||||
|
||||
proc getXAxis*(m:TMatrix3d):TVector3d {.noInit.}=
|
||||
## Gets the local x axis of `m`
|
||||
result.x=m.ax
|
||||
|
|
@ -509,26 +509,26 @@ proc getZAxis*(m:TMatrix3d):TVector3d {.noInit.}=
|
|||
result.y=m.cy
|
||||
result.z=m.cz
|
||||
|
||||
|
||||
|
||||
proc `$`*(m:TMatrix3d):string=
|
||||
## String representation of `m`
|
||||
return rtos(m.ax) & "," & rtos(m.ay) & "," &rtos(m.az) & "," & rtos(m.aw) &
|
||||
"\n" & rtos(m.bx) & "," & rtos(m.by) & "," &rtos(m.bz) & "," & rtos(m.bw) &
|
||||
"\n" & rtos(m.cx) & "," & rtos(m.cy) & "," &rtos(m.cz) & "," & rtos(m.cw) &
|
||||
"\n" & rtos(m.tx) & "," & rtos(m.ty) & "," &rtos(m.tz) & "," & rtos(m.tw)
|
||||
|
||||
return rtos(m.ax) & "," & rtos(m.ay) & "," & rtos(m.az) & "," & rtos(m.aw) &
|
||||
"\n" & rtos(m.bx) & "," & rtos(m.by) & "," & rtos(m.bz) & "," & rtos(m.bw) &
|
||||
"\n" & rtos(m.cx) & "," & rtos(m.cy) & "," & rtos(m.cz) & "," & rtos(m.cw) &
|
||||
"\n" & rtos(m.tx) & "," & rtos(m.ty) & "," & rtos(m.tz) & "," & rtos(m.tw)
|
||||
|
||||
proc apply*(m:TMatrix3d, x,y,z:var float, translate=false)=
|
||||
## Applies transformation `m` onto `x` , `y` , `z` , optionally
|
||||
## using the translation part of the matrix.
|
||||
let
|
||||
let
|
||||
oldx=x
|
||||
oldy=y
|
||||
oldz=z
|
||||
|
||||
|
||||
x=m.cx*oldz+m.bx*oldy+m.ax*oldx
|
||||
y=m.cy*oldz+m.by*oldy+m.ay*oldx
|
||||
z=m.cz*oldz+m.bz*oldy+m.az*oldx
|
||||
|
||||
|
||||
if translate:
|
||||
x+=m.tx
|
||||
y+=m.ty
|
||||
|
|
@ -552,13 +552,13 @@ proc `len=`*(v:var TVector3d,newlen:float) {.noInit.} =
|
|||
## an arbitrary vector of the requested length is returned.
|
||||
|
||||
let fac=newlen/v.len
|
||||
|
||||
|
||||
if newlen==0.0:
|
||||
v.x=0.0
|
||||
v.y=0.0
|
||||
v.z=0.0
|
||||
return
|
||||
|
||||
|
||||
if fac==Inf or fac==NegInf:
|
||||
#to short for float accuracy
|
||||
#do as good as possible:
|
||||
|
|
@ -588,7 +588,7 @@ proc `&` *(v:TVector3d,m:TMatrix3d):TVector3d {.noInit.} =
|
|||
## Concatenate vector `v` with a transformation matrix.
|
||||
## Transforming a vector ignores the translational part
|
||||
## of the matrix.
|
||||
|
||||
|
||||
# | AX AY AZ AW |
|
||||
# | X Y Z 1 | * | BX BY BZ BW |
|
||||
# | CX CY CZ CW |
|
||||
|
|
@ -605,12 +605,12 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
|
|||
## Applies transformation `m` onto `v` in place.
|
||||
## Transforming a vector ignores the translational part
|
||||
## of the matrix.
|
||||
|
||||
|
||||
# | AX AY AZ AW |
|
||||
# | X Y Z 1 | * | BX BY BZ BW |
|
||||
# | CX CY CZ CW |
|
||||
# | 0 0 0 1 |
|
||||
|
||||
|
||||
let
|
||||
newx=m.cx*v.z+m.bx*v.y+m.ax*v.x
|
||||
newy=m.cy*v.z+m.by*v.y+m.ay*v.x
|
||||
|
|
@ -620,38 +620,38 @@ proc `&=` *(v:var TVector3d,m:TMatrix3d) {.noInit.} =
|
|||
|
||||
proc transformNorm*(v:var TVector3d,m:TMatrix3d)=
|
||||
## Applies a normal direction transformation `m` onto `v` in place.
|
||||
## The resulting vector is *not* normalized. Transforming a vector ignores the
|
||||
## translational part of the matrix. If the matrix is not invertible
|
||||
## The resulting vector is *not* normalized. Transforming a vector ignores the
|
||||
## translational part of the matrix. If the matrix is not invertible
|
||||
## (determinant=0), an EDivByZero will be raised.
|
||||
|
||||
# transforming a normal is done by transforming
|
||||
# by the transpose of the inverse of the original matrix
|
||||
|
||||
|
||||
# Major reason this simple function is here is that this function can be optimized in the future,
|
||||
# (possibly by hardware) as well as having a consistent API with the 2d version.
|
||||
v&=transpose(inverse(m))
|
||||
|
||||
|
||||
proc transformInv*(v:var TVector3d,m:TMatrix3d)=
|
||||
## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
|
||||
## the translational part of the matrix. Transforming a vector ignores the
|
||||
## Applies the inverse of `m` on vector `v`. Transforming a vector ignores
|
||||
## the translational part of the matrix. Transforming a vector ignores the
|
||||
## translational part of the matrix.
|
||||
## If the matrix is not invertible (determinant=0), an EDivByZero
|
||||
## will be raised.
|
||||
|
||||
|
||||
# Major reason this simple function is here is that this function can be optimized in the future,
|
||||
# (possibly by hardware) as well as having a consistent API with the 2d version.
|
||||
v&=m.inverse
|
||||
|
||||
|
||||
proc transformNormInv*(vec:var TVector3d,m:TMatrix3d)=
|
||||
## Applies an inverse normal direction transformation `m` onto `v` in place.
|
||||
## This is faster than creating an inverse
|
||||
## matrix and transformNorm(...) it. Transforming a vector ignores the
|
||||
## This is faster than creating an inverse
|
||||
## matrix and transformNorm(...) it. Transforming a vector ignores the
|
||||
## translational part of the matrix.
|
||||
|
||||
|
||||
# see vector2d:s equivalent for a deeper look how/why this works
|
||||
vec&=m.transpose
|
||||
|
||||
proc tryNormalize*(v:var TVector3d):bool=
|
||||
proc tryNormalize*(v:var TVector3d):bool=
|
||||
## Modifies `v` to have a length of 1.0, keeping its angle.
|
||||
## If `v` has zero length (and thus no angle), it is left unmodified and false is
|
||||
## returned, otherwise true is returned.
|
||||
|
|
@ -663,26 +663,26 @@ proc tryNormalize*(v:var TVector3d):bool=
|
|||
v.x/=mag
|
||||
v.y/=mag
|
||||
v.z/=mag
|
||||
|
||||
|
||||
return true
|
||||
|
||||
proc normalize*(v:var TVector3d) {.inline.}=
|
||||
proc normalize*(v:var TVector3d) {.inline.}=
|
||||
## Modifies `v` to have a length of 1.0, keeping its angle.
|
||||
## If `v` has zero length, an EDivByZero will be raised.
|
||||
if not tryNormalize(v):
|
||||
raise newException(DivByZeroError,"Cannot normalize zero length vector")
|
||||
|
||||
proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
|
||||
## Rotates `vec` in place, with `angle` radians over `axis`, which passes
|
||||
## Rotates `vec` in place, with `angle` radians over `axis`, which passes
|
||||
## through origo.
|
||||
|
||||
# see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
|
||||
# for how this is computed
|
||||
|
||||
|
||||
var normax=axis
|
||||
if not normax.tryNormalize:
|
||||
raise newException(DivByZeroError,"Cannot rotate around zero length axis")
|
||||
|
||||
|
||||
let
|
||||
cs=cos(angle)
|
||||
si=sin(angle)
|
||||
|
|
@ -694,11 +694,11 @@ proc rotate*(vec:var TVector3d,angle:float,axis:TVector3d)=
|
|||
y=vec.y
|
||||
z=vec.z
|
||||
uxyzomc=(u*x+v*y+w*z)*omc
|
||||
|
||||
|
||||
vec.x=u*uxyzomc+x*cs+(v*z-w*y)*si
|
||||
vec.y=v*uxyzomc+y*cs+(w*x-u*z)*si
|
||||
vec.z=w*uxyzomc+z*cs+(u*y-v*x)*si
|
||||
|
||||
|
||||
proc scale*(v:var TVector3d,s:float)=
|
||||
## Scales the vector in place with factor `s`
|
||||
v.x*=s
|
||||
|
|
@ -713,12 +713,12 @@ proc stretch*(v:var TVector3d,sx,sy,sz:float)=
|
|||
|
||||
proc mirror*(v:var TVector3d,planeperp:TVector3d)=
|
||||
## Computes the mirrored vector of `v` over the plane
|
||||
## that has `planeperp` as normal direction.
|
||||
## that has `planeperp` as normal direction.
|
||||
## `planeperp` does not need to be normalized.
|
||||
|
||||
|
||||
var n=planeperp
|
||||
n.normalize
|
||||
|
||||
|
||||
let
|
||||
x=v.x
|
||||
y=v.y
|
||||
|
|
@ -729,7 +729,7 @@ proc mirror*(v:var TVector3d,planeperp:TVector3d)=
|
|||
ac=a*c
|
||||
ab=a*b
|
||||
bc=b*c
|
||||
|
||||
|
||||
v.x= -2*(ac*z+ab*y+a*a*x)+x
|
||||
v.y= -2*(bc*z+b*b*y+ab*x)+y
|
||||
v.z= -2*(c*c*z+bc*y+ac*x)+z
|
||||
|
|
@ -740,7 +740,7 @@ proc `-` *(v:TVector3d):TVector3d=
|
|||
result.x= -v.x
|
||||
result.y= -v.y
|
||||
result.z= -v.z
|
||||
|
||||
|
||||
# declare templated binary operators
|
||||
makeBinOpVector(`+`)
|
||||
makeBinOpVector(`-`)
|
||||
|
|
@ -752,7 +752,7 @@ makeBinOpAssignVector(`*=`)
|
|||
makeBinOpAssignVector(`/=`)
|
||||
|
||||
proc dot*(v1,v2:TVector3d):float {.inline.}=
|
||||
## Computes the dot product of two vectors.
|
||||
## Computes the dot product of two vectors.
|
||||
## Returns 0.0 if the vectors are perpendicular.
|
||||
return v1.x*v2.x+v1.y*v2.y+v1.z*v2.z
|
||||
|
||||
|
|
@ -769,12 +769,12 @@ proc cross*(v1,v2:TVector3d):TVector3d {.inline.}=
|
|||
proc equals*(v1,v2:TVector3d,tol=1.0e-6):bool=
|
||||
## Checks if two vectors approximately equals with a tolerance.
|
||||
return abs(v2.x-v1.x)<=tol and abs(v2.y-v1.y)<=tol and abs(v2.z-v1.z)<=tol
|
||||
|
||||
|
||||
proc `=~` *(v1,v2:TVector3d):bool=
|
||||
## Checks if two vectors approximately equals with a
|
||||
## Checks if two vectors approximately equals with a
|
||||
## hardcoded tolerance 1e-6
|
||||
equals(v1,v2)
|
||||
|
||||
|
||||
proc angleTo*(v1,v2:TVector3d):float=
|
||||
## Returns the smallest angle between v1 and v2,
|
||||
## which is in range 0-PI
|
||||
|
|
@ -801,7 +801,7 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
|
|||
ay=cross(norm,ax)
|
||||
ay.normalize()
|
||||
az=cross(ax,ay)
|
||||
|
||||
|
||||
result.setElements(
|
||||
ax.x,ax.y,ax.z,0.0,
|
||||
ay.x,ay.y,ay.z,0.0,
|
||||
|
|
@ -811,20 +811,20 @@ proc arbitraryAxis*(norm:TVector3d):TMatrix3d {.noInit.}=
|
|||
proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
|
||||
## Computes the bisector between v1 and v2 as a normalized vector.
|
||||
## If one of the input vectors has zero length, a normalized version
|
||||
## of the other is returned. If both input vectors has zero length,
|
||||
## of the other is returned. If both input vectors has zero length,
|
||||
## an arbitrary normalized vector `v1` is returned.
|
||||
var
|
||||
vmag1=v1.len
|
||||
vmag2=v2.len
|
||||
|
||||
# zero length vector equals arbitrary vector, just change
|
||||
|
||||
# zero length vector equals arbitrary vector, just change
|
||||
# magnitude to one to avoid zero division
|
||||
if vmag1==0.0:
|
||||
if vmag1==0.0:
|
||||
if vmag2==0: #both are zero length return any normalized vector
|
||||
return XAXIS
|
||||
vmag1=1.0
|
||||
if vmag2==0.0: vmag2=1.0
|
||||
|
||||
if vmag2==0.0: vmag2=1.0
|
||||
|
||||
let
|
||||
x1=v1.x/vmag1
|
||||
y1=v1.y/vmag1
|
||||
|
|
@ -832,14 +832,14 @@ proc bisect*(v1,v2:TVector3d):TVector3d {.noInit.}=
|
|||
x2=v2.x/vmag2
|
||||
y2=v2.y/vmag2
|
||||
z2=v2.z/vmag2
|
||||
|
||||
|
||||
result.x=(x1 + x2) * 0.5
|
||||
result.y=(y1 + y2) * 0.5
|
||||
result.z=(z1 + z2) * 0.5
|
||||
|
||||
|
||||
if not result.tryNormalize():
|
||||
# This can happen if vectors are colinear. In this special case
|
||||
# there are actually inifinitely many bisectors, we select just
|
||||
# there are actually inifinitely many bisectors, we select just
|
||||
# one of them.
|
||||
result=v1.cross(XAXIS)
|
||||
if result.sqrLen<1.0e-9:
|
||||
|
|
@ -857,14 +857,14 @@ proc point3d*(x,y,z:float):TPoint3d=
|
|||
result.x=x
|
||||
result.y=y
|
||||
result.z=z
|
||||
|
||||
|
||||
proc sqrDist*(a,b:TPoint3d):float=
|
||||
## Computes the squared distance between `a`and `b`
|
||||
let dx=b.x-a.x
|
||||
let dy=b.y-a.y
|
||||
let dz=b.z-a.z
|
||||
result=dx*dx+dy*dy+dz*dz
|
||||
|
||||
|
||||
proc dist*(a,b:TPoint3d):float {.inline.}=
|
||||
## Computes the absolute distance between `a`and `b`
|
||||
result=sqrt(sqrDist(a,b))
|
||||
|
|
@ -876,7 +876,7 @@ proc `$` *(p:TPoint3d):string=
|
|||
result.add(rtos(p.y))
|
||||
result.add(",")
|
||||
result.add(rtos(p.z))
|
||||
|
||||
|
||||
proc `&`*(p:TPoint3d,m:TMatrix3d):TPoint3d=
|
||||
## Concatenates a point `p` with a transform `m`,
|
||||
## resulting in a new, transformed point.
|
||||
|
|
@ -893,18 +893,18 @@ proc `&=` *(p:var TPoint3d,m:TMatrix3d)=
|
|||
p.x=m.cx*z+m.bx*y+m.ax*x+m.tx
|
||||
p.y=m.cy*z+m.by*y+m.ay*x+m.ty
|
||||
p.z=m.cz*z+m.bz*y+m.az*x+m.tz
|
||||
|
||||
|
||||
proc transformInv*(p:var TPoint3d,m:TMatrix3d)=
|
||||
## Applies the inverse of transformation `m` onto `p` in place.
|
||||
## If the matrix is not invertable (determinant=0) , EDivByZero will
|
||||
## be raised.
|
||||
|
||||
|
||||
# can possibly be more optimized in the future so use this function when possible
|
||||
p&=inverse(m)
|
||||
|
||||
|
||||
proc `+`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
|
||||
## Adds a vector `v` to a point `p`, resulting
|
||||
## Adds a vector `v` to a point `p`, resulting
|
||||
## in a new point.
|
||||
result.x=p.x+v.x
|
||||
result.y=p.y+v.y
|
||||
|
|
@ -917,7 +917,7 @@ proc `+=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
|
|||
p.z+=v.z
|
||||
|
||||
proc `-`*(p:TPoint3d,v:TVector3d):TPoint3d {.noInit,inline.} =
|
||||
## Subtracts a vector `v` from a point `p`, resulting
|
||||
## Subtracts a vector `v` from a point `p`, resulting
|
||||
## in a new point.
|
||||
result.x=p.x-v.x
|
||||
result.y=p.y-v.y
|
||||
|
|
@ -933,37 +933,37 @@ proc `-=`*(p:var TPoint3d,v:TVector3d) {.noInit,inline.} =
|
|||
## Subtracts a vector `v` from a point `p` in place.
|
||||
p.x-=v.x
|
||||
p.y-=v.y
|
||||
p.z-=v.z
|
||||
p.z-=v.z
|
||||
|
||||
proc equals(p1,p2:TPoint3d,tol=1.0e-6):bool {.inline.}=
|
||||
## Checks if two points approximately equals with a tolerance.
|
||||
return abs(p2.x-p1.x)<=tol and abs(p2.y-p1.y)<=tol and abs(p2.z-p1.z)<=tol
|
||||
|
||||
proc `=~`*(p1,p2:TPoint3d):bool {.inline.}=
|
||||
## Checks if two vectors approximately equals with a
|
||||
## Checks if two vectors approximately equals with a
|
||||
## hardcoded tolerance 1e-6
|
||||
equals(p1,p2)
|
||||
|
||||
proc rotate*(p:var TPoint3d,rad:float,axis:TVector3d)=
|
||||
## Rotates point `p` in place `rad` radians about an axis
|
||||
## Rotates point `p` in place `rad` radians about an axis
|
||||
## passing through origo.
|
||||
|
||||
|
||||
var v=vector3d(p.x,p.y,p.z)
|
||||
v.rotate(rad,axis) # reuse this code here since doing the same thing and quite complicated
|
||||
p.x=v.x
|
||||
p.y=v.y
|
||||
p.z=v.z
|
||||
|
||||
|
||||
proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
|
||||
## Rotates point `p` in place `rad` radians about an axis
|
||||
## Rotates point `p` in place `rad` radians about an axis
|
||||
## passing through `org`
|
||||
|
||||
|
||||
# see PDF document http://inside.mines.edu/~gmurray/ArbitraryAxisRotation/ArbitraryAxisRotation.pdf
|
||||
# for how this is computed
|
||||
|
||||
|
||||
var normax=axis
|
||||
normax.normalize
|
||||
|
||||
|
||||
let
|
||||
cs=cos(angle)
|
||||
omc=1.0-cs
|
||||
|
|
@ -987,17 +987,17 @@ proc rotate*(p:var TPoint3d,angle:float,org:TPoint3d,axis:TVector3d)=
|
|||
bv=b*v
|
||||
cw=c*w
|
||||
uxmvymwz=ux-vy-wz
|
||||
|
||||
|
||||
p.x=(a*(vv+ww)-u*(bv+cw-uxmvymwz))*omc + x*cs + (b*w+v*z-c*v-w*y)*si
|
||||
p.y=(b*(uu+ww)-v*(au+cw-uxmvymwz))*omc + y*cs + (c*u-a*w+w*x-u*z)*si
|
||||
p.z=(c*(uu+vv)-w*(au+bv-uxmvymwz))*omc + z*cs + (a*v+u*y-b*u-v*x)*si
|
||||
|
||||
|
||||
proc scale*(p:var TPoint3d,fac:float) {.inline.}=
|
||||
## Scales a point in place `fac` times with world origo as origin.
|
||||
p.x*=fac
|
||||
p.y*=fac
|
||||
p.z*=fac
|
||||
|
||||
|
||||
proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
|
||||
## Scales the point in place `fac` times with `org` as origin.
|
||||
p.x=(p.x - org.x) * fac + org.x
|
||||
|
|
@ -1005,7 +1005,7 @@ proc scale*(p:var TPoint3d,fac:float,org:TPoint3d){.inline.}=
|
|||
p.z=(p.z - org.z) * fac + org.z
|
||||
|
||||
proc stretch*(p:var TPoint3d,facx,facy,facz:float){.inline.}=
|
||||
## Scales a point in place non uniformly `facx` , `facy` , `facz` times
|
||||
## Scales a point in place non uniformly `facx` , `facy` , `facz` times
|
||||
## with world origo as origin.
|
||||
p.x*=facx
|
||||
p.y*=facy
|
||||
|
|
@ -1017,7 +1017,7 @@ proc stretch*(p:var TPoint3d,facx,facy,facz:float,org:TPoint3d){.inline.}=
|
|||
p.x=(p.x - org.x) * facx + org.x
|
||||
p.y=(p.y - org.y) * facy + org.y
|
||||
p.z=(p.z - org.z) * facz + org.z
|
||||
|
||||
|
||||
|
||||
proc move*(p:var TPoint3d,dx,dy,dz:float){.inline.}=
|
||||
## Translates a point `dx` , `dy` , `dz` in place.
|
||||
|
|
@ -1033,7 +1033,7 @@ proc move*(p:var TPoint3d,v:TVector3d){.inline.}=
|
|||
|
||||
proc area*(a,b,c:TPoint3d):float {.inline.}=
|
||||
## Computes the area of the triangle thru points `a` , `b` and `c`
|
||||
|
||||
|
||||
# The area of a planar 3d quadliteral is the magnitude of the cross
|
||||
# product of two edge vectors. Taking this time 0.5 gives the triangle area.
|
||||
return cross(b-a,c-a).len*0.5
|
||||
|
|
|
|||
|
|
@ -525,7 +525,7 @@ proc get*[K,V](table: var PConcTable[K,V], key: var K): V =
|
|||
|
||||
|
||||
#Tests ----------------------------
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
import locks, times, mersenne
|
||||
|
||||
const
|
||||
|
|
|
|||
|
|
@ -286,18 +286,19 @@ proc `$`*[T](c: CritBitTree[T]): string =
|
|||
result.add("}")
|
||||
|
||||
when isMainModule:
|
||||
import sequtils
|
||||
|
||||
var r: CritBitTree[void]
|
||||
r.incl "abc"
|
||||
r.incl "xyz"
|
||||
r.incl "def"
|
||||
r.incl "definition"
|
||||
r.incl "prefix"
|
||||
|
||||
doAssert r.contains"def"
|
||||
#r.del "def"
|
||||
|
||||
for w in r.items:
|
||||
echo w
|
||||
|
||||
for w in r.itemsWithPrefix("de"):
|
||||
echo w
|
||||
r.excl "def"
|
||||
|
||||
assert toSeq(r.items) == @["abc", "definition", "prefix", "xyz"]
|
||||
|
||||
assert toSeq(r.itemsWithPrefix("de")) == @["definition"]
|
||||
|
|
|
|||
|
|
@ -198,14 +198,21 @@ proc empty*(s: IntSet): bool {.inline, deprecated.} =
|
|||
result = s.counter == 0
|
||||
|
||||
when isMainModule:
|
||||
import sequtils, algorithm
|
||||
|
||||
var x = initIntSet()
|
||||
x.incl(1)
|
||||
x.incl(2)
|
||||
x.incl(7)
|
||||
x.incl(1056)
|
||||
for e in items(x): echo e
|
||||
|
||||
var y: TIntSet
|
||||
var xs = toSeq(items(x))
|
||||
xs.sort(cmp[int])
|
||||
assert xs == @[1, 2, 7, 1056]
|
||||
|
||||
var y: IntSet
|
||||
assign(y, x)
|
||||
for e in items(y): echo e
|
||||
var ys = toSeq(items(y))
|
||||
ys.sort(cmp[int])
|
||||
assert ys == @[1, 2, 7, 1056]
|
||||
|
||||
|
|
|
|||
|
|
@ -492,9 +492,8 @@ when isMainModule:
|
|||
|
||||
block: # filter iterator test
|
||||
let numbers = @[1, 4, 5, 8, 9, 7, 4]
|
||||
for n in filter(numbers, proc (x: int): bool = x mod 2 == 0):
|
||||
echo($n)
|
||||
# echoes 4, 8, 4 in separate lines
|
||||
assert toSeq(filter(numbers, proc (x: int): bool = x mod 2 == 0)) ==
|
||||
@[4, 8, 4]
|
||||
|
||||
block: # keepIf test
|
||||
var floats = @[13.0, 12.5, 5.8, 2.0, 6.1, 9.9, 10.1]
|
||||
|
|
@ -616,4 +615,5 @@ when isMainModule:
|
|||
#doAssert a.repeat(-1) == @[] # will not compile!
|
||||
doAssert b.repeat(3) == @[]
|
||||
|
||||
echo "Finished doc tests"
|
||||
when not defined(testing):
|
||||
echo "Finished doc tests"
|
||||
|
|
|
|||
|
|
@ -970,6 +970,7 @@ when isMainModule and not defined(release):
|
|||
if s <= i or mustRehash(s, i):
|
||||
echo "performance issue: rightSize() will not elide enlarge() at ", i
|
||||
|
||||
echo "Micro tests run successfully."
|
||||
when not defined(testing):
|
||||
echo "Micro tests run successfully."
|
||||
|
||||
testModule()
|
||||
|
|
|
|||
|
|
@ -819,15 +819,18 @@ proc enlarge[A](t: var CountTable[A]) =
|
|||
swap(t.data, n)
|
||||
|
||||
proc `[]=`*[A](t: var CountTable[A], key: A, val: int) =
|
||||
## puts a (key, value)-pair into `t`. `val` has to be positive.
|
||||
## puts a (key, value)-pair into `t`.
|
||||
assert val > 0
|
||||
var h = rawGet(t, key)
|
||||
if h >= 0:
|
||||
t.data[h].val = val
|
||||
else:
|
||||
h = -1 - h
|
||||
t.data[h].key = key
|
||||
t.data[h].val = val
|
||||
if mustRehash(len(t.data), t.counter): enlarge(t)
|
||||
rawInsert(t, t.data, key, val)
|
||||
inc(t.counter)
|
||||
#h = -1 - h
|
||||
#t.data[h].key = key
|
||||
#t.data[h].val = val
|
||||
|
||||
proc initCountTable*[A](initialSize=64): CountTable[A] =
|
||||
## creates a new count table that is empty.
|
||||
|
|
@ -984,6 +987,22 @@ proc sort*[A](t: CountTableRef[A]) =
|
|||
## `t` in the sorted order.
|
||||
t[].sort
|
||||
|
||||
proc merge*[A](s: var CountTable[A], t: CountTable[A]) =
|
||||
## merges the second table into the first one
|
||||
for key, value in t:
|
||||
s.inc(key, value)
|
||||
|
||||
proc merge*[A](s, t: CountTable[A]): CountTable[A] =
|
||||
## merges the two tables into a new one
|
||||
result = initCountTable[A](nextPowerOfTwo(max(s.len, t.len)))
|
||||
for table in @[s, t]:
|
||||
for key, value in table:
|
||||
result.inc(key, value)
|
||||
|
||||
proc merge*[A](s, t: CountTableRef[A]) =
|
||||
## merges the second table into the first one
|
||||
s[].merge(t[])
|
||||
|
||||
when isMainModule:
|
||||
type
|
||||
Person = object
|
||||
|
|
@ -1012,3 +1031,48 @@ when isMainModule:
|
|||
s2[p2] = 45_000
|
||||
s3[p1] = 30_000
|
||||
s3[p2] = 45_000
|
||||
|
||||
var
|
||||
t1 = initCountTable[string]()
|
||||
t2 = initCountTable[string]()
|
||||
t1.inc("foo")
|
||||
t1.inc("bar", 2)
|
||||
t1.inc("baz", 3)
|
||||
t2.inc("foo", 4)
|
||||
t2.inc("bar")
|
||||
t2.inc("baz", 11)
|
||||
merge(t1, t2)
|
||||
assert(t1["foo"] == 5)
|
||||
assert(t1["bar"] == 3)
|
||||
assert(t1["baz"] == 14)
|
||||
|
||||
let
|
||||
t1r = newCountTable[string]()
|
||||
t2r = newCountTable[string]()
|
||||
t1r.inc("foo")
|
||||
t1r.inc("bar", 2)
|
||||
t1r.inc("baz", 3)
|
||||
t2r.inc("foo", 4)
|
||||
t2r.inc("bar")
|
||||
t2r.inc("baz", 11)
|
||||
merge(t1r, t2r)
|
||||
assert(t1r["foo"] == 5)
|
||||
assert(t1r["bar"] == 3)
|
||||
assert(t1r["baz"] == 14)
|
||||
|
||||
var
|
||||
t1l = initCountTable[string]()
|
||||
t2l = initCountTable[string]()
|
||||
t1l.inc("foo")
|
||||
t1l.inc("bar", 2)
|
||||
t1l.inc("baz", 3)
|
||||
t2l.inc("foo", 4)
|
||||
t2l.inc("bar")
|
||||
t2l.inc("baz", 11)
|
||||
let
|
||||
t1merging = t1l
|
||||
t2merging = t2l
|
||||
let merged = merge(t1merging, t2merging)
|
||||
assert(merged["foo"] == 5)
|
||||
assert(merged["bar"] == 3)
|
||||
assert(merged["baz"] == 14)
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ proc advice*(s: var ThreadPoolState): ThreadPoolAdvice =
|
|||
result = doNothing
|
||||
inc s.calls
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
proc busyLoop() =
|
||||
while true:
|
||||
discard random(80)
|
||||
|
|
|
|||
|
|
@ -300,7 +300,7 @@ proc setMinPoolSize*(size: range[1..MaxThreadPoolSize]) =
|
|||
minPoolSize = size
|
||||
|
||||
proc setMaxPoolSize*(size: range[1..MaxThreadPoolSize]) =
|
||||
## sets the minimal thread pool size. The default value of this
|
||||
## sets the maximal thread pool size. The default value of this
|
||||
## is ``MaxThreadPoolSize``.
|
||||
maxPoolSize = size
|
||||
if currentPoolSize > maxPoolSize:
|
||||
|
|
|
|||
|
|
@ -56,6 +56,12 @@ proc setCookie*(key, value: string, expires: TimeInfo,
|
|||
when isMainModule:
|
||||
var tim = Time(int(getTime()) + 76 * (60 * 60 * 24))
|
||||
|
||||
echo(setCookie("test", "value", tim.getGMTime()))
|
||||
let cookie = setCookie("test", "value", tim.getGMTime())
|
||||
when not defined(testing):
|
||||
echo cookie
|
||||
let start = "Set-Cookie: test=value; Expires="
|
||||
assert cookie[0..start.high] == start
|
||||
|
||||
echo parseCookies("uid=1; kp=2")
|
||||
let table = parseCookies("uid=1; kp=2")
|
||||
assert table["uid"] == "1"
|
||||
assert table["kp"] == "2"
|
||||
|
|
|
|||
|
|
@ -451,7 +451,7 @@ proc convert*(s: string, destEncoding = "UTF-8",
|
|||
finally:
|
||||
close(c)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
let
|
||||
orig = "öäüß"
|
||||
cp1252 = convert(orig, "CP1252", "UTF-8")
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ proc register*(d: Dispatcher, monitor: FSMonitor,
|
|||
var deleg = toDelegate(monitor)
|
||||
d.register(deleg)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
proc main =
|
||||
var disp = newDispatcher()
|
||||
var monitor = newMonitor()
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ proc register*(d: Dispatcher, ftp: AsyncFTPClient): Delegate {.discardable.} =
|
|||
ftp.disp = d
|
||||
return ftp.disp.register(ftp.csock)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
proc main =
|
||||
var d = newDispatcher()
|
||||
let hev =
|
||||
|
|
@ -629,7 +629,7 @@ when isMainModule:
|
|||
if not d.poll(): break
|
||||
main()
|
||||
|
||||
when isMainModule and false:
|
||||
when not defined(testing) and isMainModule:
|
||||
var ftp = ftpClient("example.com", user = "foo", pass = "bar")
|
||||
ftp.connect()
|
||||
echo ftp.pwd()
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
## The ``gentabs`` module implements an efficient hash table that is a
|
||||
## key-value mapping. The keys are required to be strings, but the values
|
||||
## may be any Nim or user defined type. This module supports matching
|
||||
## may be any Nim or user defined type. This module supports matching
|
||||
## of keys in case-sensitive, case-insensitive and style-insensitive modes.
|
||||
|
||||
{.deprecated.}
|
||||
|
|
@ -22,7 +22,7 @@ type
|
|||
modeCaseSensitive, ## case sensitive matching of keys
|
||||
modeCaseInsensitive, ## case insensitive matching of keys
|
||||
modeStyleInsensitive ## style sensitive matching of keys
|
||||
|
||||
|
||||
TGenKeyValuePair[T] = tuple[key: string, val: T]
|
||||
TGenKeyValuePairSeq[T] = seq[TGenKeyValuePair[T]]
|
||||
TGenTable*[T] = object of RootObj
|
||||
|
|
@ -83,7 +83,7 @@ proc rawGet[T](tbl: PGenTable[T], key: string): int =
|
|||
h = nextTry(h, high(tbl.data))
|
||||
result = - 1
|
||||
|
||||
proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
|
||||
proc rawInsert[T](tbl: PGenTable[T], data: var TGenKeyValuePairSeq[T],
|
||||
key: string, val: T) =
|
||||
var h: THash
|
||||
h = myhash(tbl, key) and high(data)
|
||||
|
|
@ -96,7 +96,7 @@ proc enlarge[T](tbl: PGenTable[T]) =
|
|||
var n: TGenKeyValuePairSeq[T]
|
||||
newSeq(n, len(tbl.data) * growthFactor)
|
||||
for i in countup(0, high(tbl.data)):
|
||||
if not isNil(tbl.data[i].key):
|
||||
if not isNil(tbl.data[i].key):
|
||||
rawInsert[T](tbl, n, tbl.data[i].key, tbl.data[i].val)
|
||||
swap(tbl.data, n)
|
||||
|
||||
|
|
@ -141,20 +141,20 @@ when isMainModule:
|
|||
assert(not x.hasKey("NOPE")) # ...but key "NOPE" is not in the table.
|
||||
for k,v in pairs(x): # make sure the 'pairs' iterator works
|
||||
assert(x[k]==v)
|
||||
|
||||
|
||||
#
|
||||
# Verify a table of user-defined types
|
||||
#
|
||||
type
|
||||
TMyType = tuple[first, second: string] # a pair of strings
|
||||
|
||||
|
||||
var y = newGenTable[TMyType](modeCaseInsensitive) # hash table where each
|
||||
# value is TMyType tuple
|
||||
|
||||
|
||||
#var junk: TMyType = ("OK", "Here")
|
||||
|
||||
|
||||
#echo junk.first, " ", junk.second
|
||||
|
||||
|
||||
y["Hello"] = ("Hello", "World")
|
||||
y["Goodbye"] = ("Goodbye", "Everyone")
|
||||
#y["Hello"] = TMyType( ("Hello", "World") )
|
||||
|
|
@ -163,31 +163,44 @@ when isMainModule:
|
|||
assert( not isNil(y["Hello"].first) )
|
||||
assert( y["Hello"].first == "Hello" )
|
||||
assert( y["Hello"].second == "World" )
|
||||
|
||||
|
||||
#
|
||||
# Verify table of tables
|
||||
#
|
||||
var z: PGenTable[ PGenTable[int] ] # hash table where each value is
|
||||
var z: PGenTable[ PGenTable[int] ] # hash table where each value is
|
||||
# a hash table of ints
|
||||
|
||||
|
||||
z = newGenTable[PGenTable[int]](modeCaseInsensitive)
|
||||
z["first"] = newGenTable[int](modeCaseInsensitive)
|
||||
z["first"]["one"] = 1
|
||||
z["first"]["two"] = 2
|
||||
z["first"]["three"] = 3
|
||||
|
||||
|
||||
z["second"] = newGenTable[int](modeCaseInsensitive)
|
||||
z["second"]["red"] = 10
|
||||
z["second"]["blue"] = 20
|
||||
|
||||
|
||||
assert(len(z) == 2) # length of outer table
|
||||
assert(len(z["first"]) == 3) # length of "first" table
|
||||
assert(len(z["second"]) == 2) # length of "second" table
|
||||
assert( z["first"]["one"] == 1) # retrieve from first inner table
|
||||
assert( z["second"]["red"] == 10) # retrieve from second inner table
|
||||
|
||||
for k,v in pairs(z):
|
||||
echo( "$# ($#) ->" % [k,$len(v)] )
|
||||
#for k2,v2 in pairs(v):
|
||||
# echo( " $# <-> $#" % [k2,$v2] )
|
||||
echo()
|
||||
|
||||
when false:
|
||||
# disabled: depends on hash order:
|
||||
var output = ""
|
||||
for k, v in pairs(z):
|
||||
output.add( "$# ($#) ->\L" % [k,$len(v)] )
|
||||
for k2,v2 in pairs(v):
|
||||
output.add( " $# <-> $#\L" % [k2,$v2] )
|
||||
|
||||
let expected = unindent """
|
||||
first (3) ->
|
||||
two <-> 2
|
||||
three <-> 3
|
||||
one <-> 1
|
||||
second (2) ->
|
||||
red <-> 10
|
||||
blue <-> 20
|
||||
"""
|
||||
assert output == expected
|
||||
|
|
|
|||
|
|
@ -37,29 +37,29 @@
|
|||
## h = h !& hash(x.bar)
|
||||
## result = !$h
|
||||
|
||||
import
|
||||
import
|
||||
strutils
|
||||
|
||||
type
|
||||
THash* = int ## a hash value; hash tables using these values should
|
||||
type
|
||||
THash* = int ## a hash value; hash tables using these values should
|
||||
## always have a size of a power of two and can use the ``and``
|
||||
## operator instead of ``mod`` for truncation of the hash value.
|
||||
|
||||
proc `!&`*(h: THash, val: int): THash {.inline.} =
|
||||
proc `!&`*(h: THash, val: int): THash {.inline.} =
|
||||
## mixes a hash value `h` with `val` to produce a new hash value. This is
|
||||
## only needed if you need to implement a hash proc for a new datatype.
|
||||
result = h +% val
|
||||
result = result +% result shl 10
|
||||
result = result xor (result shr 6)
|
||||
|
||||
proc `!$`*(h: THash): THash {.inline.} =
|
||||
proc `!$`*(h: THash): THash {.inline.} =
|
||||
## finishes the computation of the hash value. This is
|
||||
## only needed if you need to implement a hash proc for a new datatype.
|
||||
result = h +% h shl 3
|
||||
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):
|
||||
|
|
@ -69,7 +69,7 @@ proc hashData*(data: pointer, size: int): THash =
|
|||
var p = cast[cstring](data)
|
||||
var i = 0
|
||||
var s = size
|
||||
while s > 0:
|
||||
while s > 0:
|
||||
h = h !& ord(p[i])
|
||||
inc(i)
|
||||
dec(s)
|
||||
|
|
@ -78,7 +78,7 @@ proc hashData*(data: pointer, size: int): THash =
|
|||
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 """
|
||||
|
|
@ -93,7 +93,7 @@ proc hash*(x: pointer): THash {.inline.} =
|
|||
"""
|
||||
else:
|
||||
result = (cast[THash](x)) shr 3 # skip the alignment
|
||||
|
||||
|
||||
when not defined(booting):
|
||||
proc hash*[T: proc](x: T): THash {.inline.} =
|
||||
## efficient hashing of proc vars; closures are supported too.
|
||||
|
|
@ -101,58 +101,65 @@ when not defined(booting):
|
|||
result = hash(rawProc(x)) !& hash(rawEnv(x))
|
||||
else:
|
||||
result = hash(pointer(x))
|
||||
|
||||
proc hash*(x: int): THash {.inline.} =
|
||||
|
||||
proc hash*(x: int): THash {.inline.} =
|
||||
## efficient hashing of integers
|
||||
result = x
|
||||
|
||||
proc hash*(x: int64): THash {.inline.} =
|
||||
proc hash*(x: int64): THash {.inline.} =
|
||||
## efficient hashing of integers
|
||||
result = toU32(x)
|
||||
|
||||
proc hash*(x: char): THash {.inline.} =
|
||||
proc hash*(x: char): THash {.inline.} =
|
||||
## efficient hashing of characters
|
||||
result = ord(x)
|
||||
|
||||
proc hash*(x: string): THash =
|
||||
proc hash*(x: string): THash =
|
||||
## efficient hashing of strings
|
||||
var h: THash = 0
|
||||
for i in 0..x.len-1:
|
||||
for i in 0..x.len-1:
|
||||
h = h !& ord(x[i])
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreStyle*(x: string): THash =
|
||||
|
||||
proc hashIgnoreStyle*(x: string): THash =
|
||||
## efficient hashing of strings; style is ignored
|
||||
var h: THash = 0
|
||||
for i in 0..x.len-1:
|
||||
for i in 0..x.len-1:
|
||||
var c = x[i]
|
||||
if c == '_':
|
||||
if c == '_':
|
||||
continue # skip _
|
||||
if c in {'A'..'Z'}:
|
||||
if c in {'A'..'Z'}:
|
||||
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||
h = h !& ord(c)
|
||||
result = !$h
|
||||
|
||||
proc hashIgnoreCase*(x: string): THash =
|
||||
proc hashIgnoreCase*(x: string): THash =
|
||||
## efficient hashing of strings; case is ignored
|
||||
var h: THash = 0
|
||||
for i in 0..x.len-1:
|
||||
for i in 0..x.len-1:
|
||||
var c = x[i]
|
||||
if c in {'A'..'Z'}:
|
||||
if c in {'A'..'Z'}:
|
||||
c = chr(ord(c) + (ord('a') - ord('A'))) # toLower()
|
||||
h = h !& ord(c)
|
||||
result = !$h
|
||||
|
||||
proc hash*[T: tuple](x: T): THash =
|
||||
## efficient hashing of tuples.
|
||||
for f in fields(x):
|
||||
result = result !& hash(f)
|
||||
result = !$result
|
||||
|
||||
proc hash*(x: float): THash {.inline.} =
|
||||
var y = x + 1.0
|
||||
result = cast[ptr THash](addr(y))[]
|
||||
|
||||
|
||||
# Forward declarations before methods that hash containers. This allows
|
||||
# containers to contain other containers
|
||||
proc hash*[A](x: openArray[A]): THash
|
||||
proc hash*[A](x: set[A]): THash
|
||||
|
||||
|
||||
proc hash*[T: tuple](x: T): THash =
|
||||
## efficient hashing of tuples.
|
||||
for f in fields(x):
|
||||
result = result !& hash(f)
|
||||
result = !$result
|
||||
|
||||
proc hash*[A](x: openArray[A]): THash =
|
||||
for it in items(x): result = result !& hash(it)
|
||||
result = !$result
|
||||
|
|
@ -160,3 +167,4 @@ proc hash*[A](x: openArray[A]): THash =
|
|||
proc hash*[A](x: set[A]): THash =
|
||||
for it in items(x): result = result !& hash(it)
|
||||
result = !$result
|
||||
|
||||
|
|
|
|||
|
|
@ -483,7 +483,8 @@ macro `var`*(e: expr): expr {.immediate.} =
|
|||
result = xmlCheckedTag(e, "var", commonAttr)
|
||||
|
||||
when isMainModule:
|
||||
var nim = "Nim"
|
||||
echo h1(a(href="http://nim-lang.org", nim))
|
||||
echo form(action="test", `accept-charset` = "Content-Type")
|
||||
|
||||
let nim = "Nim"
|
||||
assert h1(a(href="http://nim-lang.org", nim)) ==
|
||||
"""<h1><a href="http://nim-lang.org">Nim</a></h1>"""
|
||||
assert form(action="test", `accept-charset` = "Content-Type") ==
|
||||
"""<form action="test" accept-charset="Content-Type"></form>"""
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ proc loadHtml*(path: string): XmlNode =
|
|||
var errors: seq[string] = @[]
|
||||
result = loadHtml(path, errors)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
import os
|
||||
|
||||
var errors: seq[string] = @[]
|
||||
|
|
|
|||
|
|
@ -819,7 +819,7 @@ proc get*(client: AsyncHttpClient, url: string): Future[Response] {.async.} =
|
|||
result = await client.request(redirectTo, httpGET)
|
||||
lastUrl = redirectTo
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
when true:
|
||||
# Async
|
||||
proc main() {.async.} =
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ proc close*(h: PAsyncHTTPServer) =
|
|||
## Closes the ``PAsyncHTTPServer``.
|
||||
h.asyncSocket.close()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var counter = 0
|
||||
|
||||
var s: TServer
|
||||
|
|
|
|||
|
|
@ -808,22 +808,25 @@ proc `[]=`*(obj: JsonNode, key: string, val: JsonNode) =
|
|||
return
|
||||
obj.fields.add((key, val))
|
||||
|
||||
proc `{}`*(node: JsonNode, key: string): JsonNode =
|
||||
## Transverses the node and gets the given value. If any of the
|
||||
## names does not exist, returns nil
|
||||
proc `{}`*(node: JsonNode, keys: varargs[string]): JsonNode =
|
||||
## Traverses the node and gets the given value. If any of the
|
||||
## keys do not exist, returns nil. Also returns nil if one of the
|
||||
## intermediate data structures is not an object
|
||||
result = node
|
||||
if isNil(node): return nil
|
||||
result = result[key]
|
||||
for key in keys:
|
||||
if isNil(result) or result.kind!=JObject:
|
||||
return nil
|
||||
result=result[key]
|
||||
|
||||
proc `{}=`*(node: JsonNode, names: varargs[string], value: JsonNode) =
|
||||
## Transverses the node and tries to set the value at the given location
|
||||
## to `value` If any of the names are missing, they are added
|
||||
proc `{}=`*(node: JsonNode, keys: varargs[string], value: JsonNode) =
|
||||
## Traverses the node and tries to set the value at the given location
|
||||
## to `value` If any of the keys are missing, they are added
|
||||
var node = node
|
||||
for i in 0..(names.len-2):
|
||||
if isNil(node[names[i]]):
|
||||
node[names[i]] = newJObject()
|
||||
node = node[names[i]]
|
||||
node[names[names.len-1]] = value
|
||||
for i in 0..(keys.len-2):
|
||||
if isNil(node[keys[i]]):
|
||||
node[keys[i]] = newJObject()
|
||||
node = node[keys[i]]
|
||||
node[keys[keys.len-1]] = value
|
||||
|
||||
proc delete*(obj: JsonNode, key: string) =
|
||||
## Deletes ``obj[key]`` preserving the order of the other (key, value)-pairs.
|
||||
|
|
@ -1150,19 +1153,22 @@ when false:
|
|||
when isMainModule:
|
||||
#var node = parse("{ \"test\": null }")
|
||||
#echo(node.existsKey("test56"))
|
||||
|
||||
var parsed = parseFile("tests/testdata/jsontest.json")
|
||||
var parsed2 = parseFile("tests/testdata/jsontest2.json")
|
||||
echo(parsed)
|
||||
echo()
|
||||
echo(pretty(parsed, 2))
|
||||
echo()
|
||||
echo(parsed["keyÄÖöoßß"])
|
||||
echo()
|
||||
echo(pretty(parsed2))
|
||||
try:
|
||||
echo(parsed["key2"][12123])
|
||||
raise newException(ValueError, "That line was expected to fail")
|
||||
except IndexError: echo()
|
||||
|
||||
when not defined(testing):
|
||||
echo(parsed)
|
||||
echo()
|
||||
echo(pretty(parsed, 2))
|
||||
echo()
|
||||
echo(parsed["keyÄÖöoßß"])
|
||||
echo()
|
||||
echo(pretty(parsed2))
|
||||
try:
|
||||
echo(parsed["key2"][12123])
|
||||
raise newException(ValueError, "That line was expected to fail")
|
||||
except IndexError: echo()
|
||||
|
||||
let testJson = parseJson"""{ "a": [1, 2, 3, 4], "b": "asd" }"""
|
||||
# nil passthrough
|
||||
|
|
@ -1186,9 +1192,17 @@ when isMainModule:
|
|||
except:
|
||||
assert(false, "EInvalidIndex thrown for valid index")
|
||||
|
||||
assert(testJson{"b"}.str=="asd", "Couldn't fetch a singly nested key with {}")
|
||||
assert(isNil(testJson{"nonexistent"}), "Non-existent keys should return nil")
|
||||
assert(parsed2{"repository", "description"}.str=="IRC Library for Haskell", "Couldn't fetch via multiply nested key using {}")
|
||||
assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
||||
assert(isNil(testJson{"a", "b"}), "Indexing through a list should return nil")
|
||||
assert(testJson{"a"}==parseJson"[1, 2, 3, 4]", "Didn't return a non-JObject when there was one to be found")
|
||||
assert(isNil(parseJson("[1, 2, 3]"){"foo"}), "Indexing directly into a list should return nil")
|
||||
|
||||
# Generator:
|
||||
var j = %* [{"name": "John", "age": 30}, {"name": "Susan", "age": 31}]
|
||||
assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
assert j == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
|
||||
var j2 = %*
|
||||
[
|
||||
|
|
@ -1216,12 +1230,13 @@ when isMainModule:
|
|||
}
|
||||
]
|
||||
assert j3 == %[%{"name": %"John", "age": %30}, %{"name": %"Susan", "age": %31}]
|
||||
|
||||
discard """
|
||||
while true:
|
||||
var json = stdin.readLine()
|
||||
var node = parse(json)
|
||||
echo(node)
|
||||
echo()
|
||||
echo()
|
||||
"""
|
||||
|
||||
when not defined(testing):
|
||||
discard """
|
||||
while true:
|
||||
var json = stdin.readLine()
|
||||
var node = parse(json)
|
||||
echo(node)
|
||||
echo()
|
||||
echo()
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -278,7 +278,7 @@ proc getLogFilter*(): Level =
|
|||
|
||||
# --------------
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var L = newConsoleLogger()
|
||||
var fL = newFileLogger("test.log", fmtStr = verboseFmtStr)
|
||||
var rL = newRollingFileLogger("rolling.log", fmtStr = verboseFmtStr)
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
## type than its compiletime type:
|
||||
##
|
||||
## .. code-block:: nim
|
||||
##
|
||||
## type
|
||||
##
|
||||
## type
|
||||
## TA = object
|
||||
## TB = object of TA
|
||||
## f: int
|
||||
|
|
@ -28,6 +28,8 @@
|
|||
## new(b)
|
||||
## a = b
|
||||
## echo($$a[]) # produces "{}", not "{f: 0}"
|
||||
##
|
||||
## **Note**: The ``to`` and ``$$`` operations are available at compile-time!
|
||||
|
||||
import streams, typeinfo, json, intsets, tables
|
||||
|
||||
|
|
@ -38,7 +40,12 @@ proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
|
|||
case a.kind
|
||||
of akNone: assert false
|
||||
of akBool: s.write($getBool(a))
|
||||
of akChar: s.write(escapeJson($getChar(a)))
|
||||
of akChar:
|
||||
let ch = getChar(a)
|
||||
if ch < '\128':
|
||||
s.write(escapeJson($ch))
|
||||
else:
|
||||
s.write($int(ch))
|
||||
of akArray, akSequence:
|
||||
if a.kind == akSequence and isNil(a): s.write("null")
|
||||
else:
|
||||
|
|
@ -92,7 +99,7 @@ proc storeAny(s: Stream, a: TAny, stored: var IntSet) =
|
|||
proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
||||
case a.kind
|
||||
of akNone: assert false
|
||||
of akBool:
|
||||
of akBool:
|
||||
case p.kind
|
||||
of jsonFalse: setBiggestInt(a, 0)
|
||||
of jsonTrue: setBiggestInt(a, 1)
|
||||
|
|
@ -105,8 +112,12 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
|||
setBiggestInt(a, ord(x[0]))
|
||||
next(p)
|
||||
return
|
||||
elif p.kind == jsonInt:
|
||||
setBiggestInt(a, getInt(p))
|
||||
next(p)
|
||||
return
|
||||
raiseParseErr(p, "string of length 1 expected for a char")
|
||||
of akEnum:
|
||||
of akEnum:
|
||||
if p.kind == jsonString:
|
||||
setBiggestInt(a, getEnumOrdinal(a, p.str))
|
||||
next(p)
|
||||
|
|
@ -122,7 +133,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
|||
if p.kind == jsonArrayEnd: next(p)
|
||||
else: raiseParseErr(p, "']' end of array expected")
|
||||
of akSequence:
|
||||
case p.kind
|
||||
case p.kind
|
||||
of jsonNull:
|
||||
setPointer(a, nil)
|
||||
next(p)
|
||||
|
|
@ -143,7 +154,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
|||
if p.kind != jsonObjectStart: raiseParseErr(p, "'{' expected for an object")
|
||||
next(p)
|
||||
while p.kind != jsonObjectEnd and p.kind != jsonEof:
|
||||
if p.kind != jsonString:
|
||||
if p.kind != jsonString:
|
||||
raiseParseErr(p, "string expected for a field name")
|
||||
var fieldName = p.str
|
||||
next(p)
|
||||
|
|
@ -160,7 +171,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
|||
if p.kind == jsonArrayEnd: next(p)
|
||||
else: raiseParseErr(p, "']' end of array expected")
|
||||
of akPtr, akRef:
|
||||
case p.kind
|
||||
case p.kind
|
||||
of jsonNull:
|
||||
setPointer(a, nil)
|
||||
next(p)
|
||||
|
|
@ -170,7 +181,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
|||
of jsonArrayStart:
|
||||
next(p)
|
||||
if a.kind == akRef: invokeNew(a)
|
||||
else: setPointer(a, alloc0(a.baseTypeSize))
|
||||
else: setPointer(a, alloc0(a.baseTypeSize))
|
||||
if p.kind == jsonInt:
|
||||
t[p.getInt] = getPointer(a)
|
||||
next(p)
|
||||
|
|
@ -179,8 +190,8 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
|||
if p.kind == jsonArrayEnd: next(p)
|
||||
else: raiseParseErr(p, "']' end of ref-address pair expected")
|
||||
else: raiseParseErr(p, "int for pointer type expected")
|
||||
of akProc, akPointer, akCString:
|
||||
case p.kind
|
||||
of akProc, akPointer, akCString:
|
||||
case p.kind
|
||||
of jsonNull:
|
||||
setPointer(a, nil)
|
||||
next(p)
|
||||
|
|
@ -189,7 +200,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
|||
next(p)
|
||||
else: raiseParseErr(p, "int for pointer type expected")
|
||||
of akString:
|
||||
case p.kind
|
||||
case p.kind
|
||||
of jsonNull:
|
||||
setPointer(a, nil)
|
||||
next(p)
|
||||
|
|
@ -197,7 +208,7 @@ proc loadAny(p: var JsonParser, a: TAny, t: var Table[BiggestInt, pointer]) =
|
|||
setString(a, p.str)
|
||||
next(p)
|
||||
else: raiseParseErr(p, "string expected")
|
||||
of akInt..akInt64, akUInt..akUInt64:
|
||||
of akInt..akInt64, akUInt..akUInt64:
|
||||
if p.kind == jsonInt:
|
||||
setBiggestInt(a, getInt(p))
|
||||
next(p)
|
||||
|
|
@ -243,22 +254,22 @@ proc to*[T](data: string): T =
|
|||
## reads data and transforms it to a ``T``.
|
||||
var tab = initTable[BiggestInt, pointer]()
|
||||
loadAny(newStringStream(data), toAny(result), tab)
|
||||
|
||||
when isMainModule:
|
||||
|
||||
when not defined(testing) and isMainModule:
|
||||
template testit(x: expr) = echo($$to[type(x)]($$x))
|
||||
|
||||
var x: array[0..4, array[0..4, string]] = [
|
||||
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
|
||||
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
|
||||
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
|
||||
["test", "1", "2", "3", "4"], ["test", "1", "2", "3", "4"],
|
||||
["test", "1", "2", "3", "4"]]
|
||||
testit(x)
|
||||
var test2: tuple[name: string, s: uint] = ("tuple test", 56u)
|
||||
testit(test2)
|
||||
|
||||
|
||||
type
|
||||
TE = enum
|
||||
blah, blah2
|
||||
|
||||
|
||||
TestObj = object
|
||||
test, asd: int
|
||||
case test2: TE
|
||||
|
|
@ -266,7 +277,7 @@ when isMainModule:
|
|||
help: string
|
||||
else:
|
||||
nil
|
||||
|
||||
|
||||
PNode = ref TNode
|
||||
TNode = object
|
||||
next, prev: PNode
|
||||
|
|
@ -294,7 +305,7 @@ when isMainModule:
|
|||
test4.a = "ref string test: A"
|
||||
test4.b = "ref string test: B"
|
||||
testit(test4)
|
||||
|
||||
|
||||
var test5 = @[(0,1),(2,3),(4,5)]
|
||||
testit(test5)
|
||||
|
||||
|
|
@ -305,7 +316,7 @@ when isMainModule:
|
|||
echo($$test7)
|
||||
testit(test7)
|
||||
|
||||
type
|
||||
type
|
||||
TA {.inheritable.} = object
|
||||
TB = object of TA
|
||||
f: int
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ proc fac*(n: int): int {.noSideEffect.} =
|
|||
proc isPowerOfTwo*(x: int): bool {.noSideEffect.} =
|
||||
## returns true, if `x` is a power of two, false otherwise.
|
||||
## Zero and negative numbers are not a power of two.
|
||||
return (x != 0) and ((x and (x - 1)) == 0)
|
||||
return (x > 0) and ((x and (x - 1)) == 0)
|
||||
|
||||
proc nextPowerOfTwo*(x: int): int {.noSideEffect.} =
|
||||
## returns `x` rounded up to the nearest power of two.
|
||||
|
|
@ -114,18 +114,23 @@ proc sum*[T](x: openArray[T]): T {.noSideEffect.} =
|
|||
## If `x` is empty, 0 is returned.
|
||||
for i in items(x): result = result + i
|
||||
|
||||
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))
|
||||
template toFloat(f: float): float = f
|
||||
|
||||
proc variance*(x: openArray[float]): float {.noSideEffect.} =
|
||||
proc mean*[T](x: openArray[T]): float {.noSideEffect.} =
|
||||
## computes the mean of the elements in `x`, which are first converted to floats.
|
||||
## If `x` is empty, NaN is returned.
|
||||
## ``toFloat(x: T): float`` must be defined.
|
||||
for i in items(x): result = result + toFloat(i)
|
||||
result = result / toFloat(len(x))
|
||||
|
||||
proc variance*[T](x: openArray[T]): float {.noSideEffect.} =
|
||||
## computes the variance of the elements in `x`.
|
||||
## If `x` is empty, NaN is returned.
|
||||
## ``toFloat(x: T): float`` must be defined.
|
||||
result = 0.0
|
||||
var m = mean(x)
|
||||
for i in 0 .. high(x):
|
||||
var diff = x[i] - m
|
||||
for i in items(x):
|
||||
var diff = toFloat(i) - m
|
||||
result = result + diff*diff
|
||||
result = result / toFloat(len(x))
|
||||
|
||||
|
|
@ -372,7 +377,9 @@ when isMainModule and not defined(JS):
|
|||
randomize(seed)
|
||||
for i in 0..SIZE-1:
|
||||
assert buf[i] == random(high(int)), "non deterministic random seeding"
|
||||
echo "random values equal after reseeding"
|
||||
|
||||
when not defined(testing):
|
||||
echo "random values equal after reseeding"
|
||||
|
||||
# Check for no side effect annotation
|
||||
proc mySqrt(num: float): float {.noSideEffect.} =
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ proc getNum*(m: var MersenneTwister): int =
|
|||
return int(y)
|
||||
|
||||
# Test
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var mt = newMersenneTwister(2525)
|
||||
|
||||
for i in 0..99:
|
||||
|
|
|
|||
|
|
@ -518,5 +518,5 @@ proc register*(mimedb: var MimeDB, ext: string, mimetype: string) =
|
|||
|
||||
when isMainModule:
|
||||
var m = newMimetypes()
|
||||
echo m.getMimetype("mp4")
|
||||
echo m.getExt("text/html")
|
||||
assert m.getMimetype("mp4") == "video/mp4"
|
||||
assert m.getExt("text/html") == "html"
|
||||
|
|
|
|||
|
|
@ -88,6 +88,6 @@ proc generatedTime*(oid: Oid): Time =
|
|||
bigEndian32(addr(tmp), addr(dummy))
|
||||
result = Time(tmp)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
let xo = genOid()
|
||||
echo xo.generatedTime
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ proc terminate*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
|
|||
proc kill*(p: Process) {.rtl, extern: "nosp$1", tags: [].}
|
||||
## Kill the process `p`. On Posix OSes the procedure sends ``SIGKILL`` to
|
||||
## the process. On Windows ``kill()`` is simply an alias for ``terminate()``.
|
||||
|
||||
|
||||
proc running*(p: Process): bool {.rtl, extern: "nosp$1", tags: [].}
|
||||
## Returns true iff the process `p` is still running. Returns immediately.
|
||||
|
||||
|
|
@ -666,7 +666,7 @@ elif not defined(useNimRtl):
|
|||
data.workingDir = workingDir
|
||||
|
||||
|
||||
when declared(posix_spawn) and not defined(useFork) and
|
||||
when declared(posix_spawn) and not defined(useFork) and
|
||||
not defined(useClone) and not defined(linux):
|
||||
pid = startProcessAuxSpawn(data)
|
||||
else:
|
||||
|
|
@ -823,7 +823,7 @@ elif not defined(useNimRtl):
|
|||
discard execvp(data.sysCommand, data.sysArgs)
|
||||
else:
|
||||
when defined(uClibc):
|
||||
# uClibc environment (OpenWrt included) doesn't have the full execvpe
|
||||
# uClibc environment (OpenWrt included) doesn't have the full execvpe
|
||||
discard execve(data.sysCommand, data.sysArgs, data.sysEnv)
|
||||
else:
|
||||
discard execvpe(data.sysCommand, data.sysArgs, data.sysEnv)
|
||||
|
|
@ -864,9 +864,9 @@ elif not defined(useNimRtl):
|
|||
raiseOsError(osLastError())
|
||||
|
||||
proc kill(p: Process) =
|
||||
if kill(p.id, SIGKILL) != 0'i32:
|
||||
if kill(p.id, SIGKILL) != 0'i32:
|
||||
raiseOsError(osLastError())
|
||||
|
||||
|
||||
proc waitForExit(p: Process, timeout: int = -1): int =
|
||||
#if waitPid(p.id, p.exitCode, 0) == int(p.id):
|
||||
# ``waitPid`` fails if the process is not running anymore. But then
|
||||
|
|
@ -883,7 +883,7 @@ elif not defined(useNimRtl):
|
|||
var ret = waitpid(p.id, p.exitCode, WNOHANG)
|
||||
var b = ret == int(p.id)
|
||||
if b: result = -1
|
||||
if p.exitCode == -3: result = -1
|
||||
if not WIFEXITED(p.exitCode): result = -1
|
||||
else: result = p.exitCode.int shr 8
|
||||
|
||||
proc createStream(stream: var Stream, handle: var FileHandle,
|
||||
|
|
@ -907,7 +907,7 @@ elif not defined(useNimRtl):
|
|||
createStream(p.errStream, p.errHandle, fmRead)
|
||||
return p.errStream
|
||||
|
||||
proc csystem(cmd: cstring): cint {.nodecl, importc: "system",
|
||||
proc csystem(cmd: cstring): cint {.nodecl, importc: "system",
|
||||
header: "<stdlib.h>".}
|
||||
|
||||
proc execCmd(command: string): int =
|
||||
|
|
|
|||
|
|
@ -166,7 +166,7 @@ proc close*(my: var CsvParser) {.inline.} =
|
|||
## closes the parser `my` and its associated input stream.
|
||||
lexbase.close(my)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
import os
|
||||
var s = newFileStream(paramStr(1), fmRead)
|
||||
if s == nil: quit("cannot open the file" & paramStr(1))
|
||||
|
|
|
|||
|
|
@ -1330,7 +1330,7 @@ proc renderSQL*(n: SqlNode): string =
|
|||
result = ""
|
||||
ra(n, result, 0)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
echo(renderSQL(parseSQL(newStringStream("""
|
||||
CREATE TYPE happiness AS ENUM ('happy', 'very happy', 'ecstatic');
|
||||
CREATE TABLE holidays (
|
||||
|
|
|
|||
|
|
@ -323,8 +323,12 @@ iterator interpolatedFragments*(s: string): tuple[kind: InterpolatedKind,
|
|||
i = j
|
||||
|
||||
when isMainModule:
|
||||
for k, v in interpolatedFragments("$test{} $this is ${an{ example}} "):
|
||||
echo "(", k, ", \"", v, "\")"
|
||||
import sequtils
|
||||
let input = "$test{} $this is ${an{ example}} "
|
||||
let expected = @[(ikVar, "test"), (ikStr, "{} "), (ikVar, "this"),
|
||||
(ikStr, " is "), (ikExpr, "an{ example}"), (ikStr, " ")]
|
||||
assert toSeq(interpolatedFragments(input)) == expected
|
||||
|
||||
var value = 0
|
||||
discard parseHex("0x38", value)
|
||||
assert value == 56
|
||||
|
|
|
|||
|
|
@ -628,7 +628,7 @@ proc next*(my: var XmlParser) =
|
|||
my.kind = xmlError
|
||||
my.state = stateNormal
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
import os
|
||||
var s = newFileStream(paramStr(1), fmRead)
|
||||
if s == nil: quit("cannot open the file" & paramStr(1))
|
||||
|
|
|
|||
1770
lib/pure/pegs.nimfix
1770
lib/pure/pegs.nimfix
File diff suppressed because it is too large
Load diff
|
|
@ -1080,7 +1080,7 @@ proc assertListsIdentical(listA, listB: seq[string]) =
|
|||
assert(item == listB[i])
|
||||
i = i + 1
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
when false:
|
||||
var r = open()
|
||||
|
||||
|
|
|
|||
|
|
@ -44,16 +44,13 @@ proc decimalToRoman*(number: range[1..3_999]): string =
|
|||
("XC", 90), ("L", 50), ("XL", 40), ("X", 10), ("IX", 9),
|
||||
("V", 5), ("IV", 4), ("I", 1)]
|
||||
result = ""
|
||||
var decVal = number
|
||||
var decVal: int = number
|
||||
for key, val in items(romanComposites):
|
||||
while decVal >= val:
|
||||
dec(decVal, val)
|
||||
result.add(key)
|
||||
|
||||
when isMainModule:
|
||||
import math
|
||||
randomize()
|
||||
for i in 1 .. 100:
|
||||
var rnd = 1 + random(3990)
|
||||
assert rnd == rnd.decimalToRoman.romanToDecimal
|
||||
for i in 1 .. 3_999:
|
||||
assert i == i.decimalToRoman.romanToDecimal
|
||||
|
||||
|
|
|
|||
|
|
@ -296,7 +296,7 @@ proc contains*(s: Selector, key: SelectorKey): bool =
|
|||
TReadyInfo: ReadyInfo, PSelector: Selector].}
|
||||
|
||||
|
||||
when isMainModule and not defined(nimdoc):
|
||||
when not defined(testing) and isMainModule and not defined(nimdoc):
|
||||
# Select()
|
||||
import sockets
|
||||
type
|
||||
|
|
|
|||
|
|
@ -253,7 +253,7 @@ proc close*(smtp: AsyncSmtp) {.async.} =
|
|||
await smtp.sock.send("QUIT\c\L")
|
||||
smtp.sock.close()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
#var msg = createMessage("Test subject!",
|
||||
# "Hello, my name is dom96.\n What\'s yours?", @["dominik@localhost"])
|
||||
#echo(msg)
|
||||
|
|
|
|||
|
|
@ -168,6 +168,12 @@ proc newStringTable*(mode: StringTableMode): StringTableRef {.
|
|||
result.counter = 0
|
||||
newSeq(result.data, startSize)
|
||||
|
||||
proc clear*(s: StringTableRef, mode: StringTableMode) =
|
||||
## resets a string table to be empty again.
|
||||
s.mode = mode
|
||||
s.counter = 0
|
||||
s.data.setLen(startSize)
|
||||
|
||||
proc newStringTable*(keyValuePairs: varargs[string],
|
||||
mode: StringTableMode): StringTableRef {.
|
||||
rtl, extern: "nst$1WithPairs".} =
|
||||
|
|
@ -227,7 +233,7 @@ proc `$`*(t: StringTableRef): string {.rtl, extern: "nstDollar".} =
|
|||
result = "{:}"
|
||||
else:
|
||||
result = "{"
|
||||
for key, val in pairs(t):
|
||||
for key, val in pairs(t):
|
||||
if result.len > 1: result.add(", ")
|
||||
result.add(key)
|
||||
result.add(": ")
|
||||
|
|
|
|||
|
|
@ -169,14 +169,12 @@ proc cmpIgnoreStyle*(a, b: string): int {.noSideEffect,
|
|||
|
||||
{.pop.}
|
||||
|
||||
proc strip*(s: string, leading = true, trailing = true): string {.noSideEffect,
|
||||
rtl, extern: "nsuStrip".} =
|
||||
## Strips whitespace from `s` and returns the resulting string.
|
||||
proc strip*(s: string, leading = true, trailing = true, chars: set[char] = Whitespace): string
|
||||
{.noSideEffect, rtl, extern: "nsuStrip".} =
|
||||
## Strips `chars` from `s` and returns the resulting string.
|
||||
##
|
||||
## If `leading` is true, leading whitespace is stripped.
|
||||
## If `trailing` is true, trailing whitespace is stripped.
|
||||
const
|
||||
chars: set[char] = Whitespace
|
||||
## If `leading` is true, leading `chars` are stripped.
|
||||
## If `trailing` is true, trailing `chars` are stripped.
|
||||
var
|
||||
first = 0
|
||||
last = len(s)-1
|
||||
|
|
@ -1402,14 +1400,21 @@ when isMainModule:
|
|||
doAssert align("a", 0) == "a"
|
||||
doAssert align("1232", 6) == " 1232"
|
||||
doAssert align("1232", 6, '#') == "##1232"
|
||||
echo wordWrap(""" this is a long text -- muchlongerthan10chars and here
|
||||
it goes""", 10, false)
|
||||
|
||||
let
|
||||
inp = """ this is a long text -- muchlongerthan10chars and here
|
||||
it goes"""
|
||||
outp = " this is a\nlong text\n--\nmuchlongerthan10chars\nand here\nit goes"
|
||||
doAssert wordWrap(inp, 10, false) == outp
|
||||
|
||||
doAssert formatBiggestFloat(0.00000000001, ffDecimal, 11) == "0.00000000001"
|
||||
doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) == "1.0e-11"
|
||||
doAssert formatBiggestFloat(0.00000000001, ffScientific, 1) in
|
||||
["1.0e-11", "1.0e-011"]
|
||||
|
||||
doAssert "$# $3 $# $#" % ["a", "b", "c"] == "a c b c"
|
||||
echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
|
||||
echo formatSize(1'i64 shl 31)
|
||||
when not defined(testing):
|
||||
echo formatSize(1'i64 shl 31 + 300'i64) # == "4,GB"
|
||||
echo formatSize(1'i64 shl 31)
|
||||
|
||||
doAssert "$animal eats $food." % ["animal", "The cat", "food", "fish"] ==
|
||||
"The cat eats fish."
|
||||
|
|
@ -1426,3 +1431,11 @@ when isMainModule:
|
|||
doAssert count("foofoofoo", "foofoo", overlapping = true) == 2
|
||||
doAssert count("foofoofoo", 'f') == 3
|
||||
doAssert count("foofoofoobar", {'f','b'}) == 4
|
||||
|
||||
doAssert strip(" foofoofoo ") == "foofoofoo"
|
||||
doAssert strip("sfoofoofoos", chars = {'s'}) == "foofoofoo"
|
||||
doAssert strip("barfoofoofoobar", chars = {'b', 'a', 'r'}) == "foofoofoo"
|
||||
doAssert strip("stripme but don't strip this stripme",
|
||||
chars = {'s', 't', 'r', 'i', 'p', 'm', 'e'}) == " but don't strip this "
|
||||
doAssert strip("sfoofoofoos", leading = false, chars = {'s'}) == "sfoofoofoo"
|
||||
doAssert strip("sfoofoofoos", trailing = false, chars = {'s'}) == "foofoofoos"
|
||||
|
|
|
|||
|
|
@ -386,8 +386,13 @@ when isMainModule:
|
|||
longishA,
|
||||
longish)"""
|
||||
|
||||
echo "type TMyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
|
||||
"fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"]
|
||||
assert "type TMyEnum* = enum\n $', '2i'\n '{..}" % ["fieldA",
|
||||
"fieldB", "FiledClkad", "fieldD", "fieldE", "longishFieldName"] ==
|
||||
strutils.unindent """
|
||||
type TMyEnum* = enum
|
||||
fieldA, fieldB,
|
||||
FiledClkad, fieldD,
|
||||
fieldE, longishFieldName"""
|
||||
|
||||
doAssert subex"$1($', '{2..})" % ["f", "a", "b", "c"] == "f(a, b, c)"
|
||||
|
||||
|
|
@ -395,7 +400,12 @@ when isMainModule:
|
|||
|
||||
doAssert subex"$['''|'|''''|']']#" % "0" == "'|"
|
||||
|
||||
echo subex("type\n TEnum = enum\n $', '40c'\n '{..}") % [
|
||||
"fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"]
|
||||
assert subex("type\n TEnum = enum\n $', '40c'\n '{..}") % [
|
||||
"fieldNameA", "fieldNameB", "fieldNameC", "fieldNameD"] ==
|
||||
strutils.unindent """
|
||||
type
|
||||
TEnum = enum
|
||||
fieldNameA, fieldNameB, fieldNameC,
|
||||
fieldNameD"""
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -51,12 +51,13 @@ else:
|
|||
proc setRaw(fd: FileHandle, time: cint = TCSAFLUSH) =
|
||||
var mode: Termios
|
||||
discard fd.tcgetattr(addr mode)
|
||||
mode.iflag = mode.iflag and not Tcflag(BRKINT or ICRNL or INPCK or ISTRIP or IXON)
|
||||
mode.oflag = mode.oflag and not Tcflag(OPOST)
|
||||
mode.cflag = (mode.cflag and not Tcflag(CSIZE or PARENB)) or CS8
|
||||
mode.lflag = mode.lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
|
||||
mode.cc[VMIN] = 1.cuchar
|
||||
mode.cc[VTIME] = 0.cuchar
|
||||
mode.c_iflag = mode.c_iflag and not Tcflag(BRKINT or ICRNL or INPCK or
|
||||
ISTRIP or IXON)
|
||||
mode.c_oflag = mode.c_oflag and not Tcflag(OPOST)
|
||||
mode.c_cflag = (mode.c_cflag and not Tcflag(CSIZE or PARENB)) or CS8
|
||||
mode.c_lflag = mode.c_lflag and not Tcflag(ECHO or ICANON or IEXTEN or ISIG)
|
||||
mode.c_cc[VMIN] = 1.cuchar
|
||||
mode.c_cc[VTIME] = 0.cuchar
|
||||
discard fd.tcsetattr(time, addr mode)
|
||||
|
||||
proc setCursorPos*(x, y: int) =
|
||||
|
|
@ -375,7 +376,7 @@ when not defined(windows):
|
|||
result = stdin.readChar()
|
||||
discard fd.tcsetattr(TCSADRAIN, addr oldMode)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
system.addQuitProc(resetAttributes)
|
||||
write(stdout, "never mind")
|
||||
eraseLine()
|
||||
|
|
|
|||
|
|
@ -119,7 +119,7 @@ type
|
|||
## in the range 0 to 23.
|
||||
monthday*: range[1..31] ## The day of the month, in the range 1 to 31.
|
||||
month*: Month ## The current month.
|
||||
year*: range[-10_000..10_000] ## The current year.
|
||||
year*: int ## The current year.
|
||||
weekday*: WeekDay ## The current day of the week.
|
||||
yearday*: range[0..365] ## The number of days since January 1,
|
||||
## in the range 0 to 365.
|
||||
|
|
@ -379,7 +379,7 @@ when not defined(JS):
|
|||
result.hour = t.hour
|
||||
result.monthday = t.monthday
|
||||
result.month = ord(t.month)
|
||||
result.year = t.year - 1900
|
||||
result.year = cint(t.year - 1900)
|
||||
result.weekday = weekDays[t.weekday]
|
||||
result.yearday = t.yearday
|
||||
result.isdst = if t.isDST: 1 else: 0
|
||||
|
|
@ -764,7 +764,7 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) =
|
|||
info.monthday = value[j..j+1].parseInt()
|
||||
j += 2
|
||||
of "ddd":
|
||||
case value[j..j+2].toLower():
|
||||
case value[j..j+2].toLower()
|
||||
of "sun":
|
||||
info.weekday = dSun
|
||||
of "mon":
|
||||
|
|
@ -1036,8 +1036,6 @@ when isMainModule:
|
|||
# Tue 19 Jan 03:14:07 GMT 2038
|
||||
|
||||
var t = getGMTime(fromSeconds(2147483647))
|
||||
echo t.format("ddd dd MMM hh:mm:ss ZZZ yyyy")
|
||||
echo t.format("ddd ddMMMhhmmssZZZyyyy")
|
||||
assert t.format("ddd dd MMM hh:mm:ss ZZZ yyyy") == "Tue 19 Jan 03:14:07 UTC 2038"
|
||||
assert t.format("ddd ddMMMhh:mm:ssZZZyyyy") == "Tue 19Jan03:14:07UTC2038"
|
||||
|
||||
|
|
@ -1070,46 +1068,48 @@ when isMainModule:
|
|||
var f = "dddd at hh:mmtt on MMM d, yyyy"
|
||||
assert($s.parse(f) == "Tue Dec 15 09:04:00 2015")
|
||||
# ANSIC = "Mon Jan _2 15:04:05 2006"
|
||||
s = "Mon Jan 2 15:04:05 2006"
|
||||
f = "ddd MMM d HH:mm:ss yyyy"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
|
||||
s = "Thu Jan 12 15:04:05 2006"
|
||||
f = "ddd MMM dd HH:mm:ss yyyy"
|
||||
assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
||||
# UnixDate = "Mon Jan _2 15:04:05 MST 2006"
|
||||
s = "Mon Jan 2 15:04:05 MST 2006"
|
||||
f = "ddd MMM d HH:mm:ss ZZZ yyyy"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
|
||||
s = "Thu Jan 12 15:04:05 MST 2006"
|
||||
f = "ddd MMM dd HH:mm:ss ZZZ yyyy"
|
||||
assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
||||
# RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
|
||||
s = "Mon Jan 02 15:04:05 -07:00 2006"
|
||||
s = "Thu Jan 12 15:04:05 -07:00 2006"
|
||||
f = "ddd MMM dd HH:mm:ss zzz yyyy"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
|
||||
assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
||||
# RFC822 = "02 Jan 06 15:04 MST"
|
||||
s = "02 Jan 06 15:04 MST"
|
||||
s = "12 Jan 16 15:04 MST"
|
||||
f = "dd MMM yy HH:mm ZZZ"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:00 2006")
|
||||
assert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
|
||||
# RFC822Z = "02 Jan 06 15:04 -0700" # RFC822 with numeric zone
|
||||
s = "02 Jan 06 15:04 -07:00"
|
||||
s = "12 Jan 16 15:04 -07:00"
|
||||
f = "dd MMM yy HH:mm zzz"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:00 2006")
|
||||
assert($s.parse(f) == "Tue Jan 12 15:04:00 2016")
|
||||
# RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
|
||||
s = "Monday, 02-Jan-06 15:04:05 MST"
|
||||
s = "Monday, 12-Jan-06 15:04:05 MST"
|
||||
f = "dddd, dd-MMM-yy HH:mm:ss ZZZ"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
|
||||
assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
||||
# RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
|
||||
s = "Mon, 02 Jan 2006 15:04:05 MST"
|
||||
s = "Thu, 12 Jan 2006 15:04:05 MST"
|
||||
f = "ddd, dd MMM yyyy HH:mm:ss ZZZ"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
|
||||
assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
||||
# RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" # RFC1123 with numeric zone
|
||||
s = "Mon, 02 Jan 2006 15:04:05 -07:00"
|
||||
s = "Thu, 12 Jan 2006 15:04:05 -07:00"
|
||||
f = "ddd, dd MMM yyyy HH:mm:ss zzz"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
|
||||
assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
||||
# RFC3339 = "2006-01-02T15:04:05Z07:00"
|
||||
s = "2006-01-02T15:04:05Z-07:00"
|
||||
s = "2006-01-12T15:04:05Z-07:00"
|
||||
f = "yyyy-MM-ddTHH:mm:ssZzzz"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
|
||||
assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
||||
# RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
|
||||
s = "2006-01-02T15:04:05.999999999Z-07:00"
|
||||
s = "2006-01-12T15:04:05.999999999Z-07:00"
|
||||
f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz"
|
||||
assert($s.parse(f) == "Mon Jan 2 15:04:05 2006")
|
||||
assert($s.parse(f) == "Thu Jan 12 15:04:05 2006")
|
||||
# Kitchen = "3:04PM"
|
||||
s = "3:04PM"
|
||||
f = "h:mmtt"
|
||||
echo "Kitchen: " & $s.parse(f)
|
||||
assert "15:04:00" in $s.parse(f)
|
||||
when not defined(testing):
|
||||
echo "Kitchen: " & $s.parse(f)
|
||||
|
|
|
|||
|
|
@ -105,6 +105,31 @@ template fastRuneAt*(s: string, i: int, result: expr, doInc = true) =
|
|||
result = Rune(ord(s[i]))
|
||||
when doInc: inc(i)
|
||||
|
||||
proc validateUtf8*(s: string): int =
|
||||
## returns the position of the invalid byte in ``s`` if the string ``s`` does
|
||||
## not hold valid UTF-8 data. Otherwise -1 is returned.
|
||||
var i = 0
|
||||
let L = s.len
|
||||
while i < L:
|
||||
if ord(s[i]) <=% 127:
|
||||
inc(i)
|
||||
elif ord(s[i]) shr 5 == 0b110:
|
||||
if i+1 < L and ord(s[i+1]) shr 6 == 0b10: inc(i, 2)
|
||||
else: return i
|
||||
elif ord(s[i]) shr 4 == 0b1110:
|
||||
if i+2 < L and ord(s[i+1]) shr 6 == 0b10 and ord(s[i+2]) shr 6 == 0b10:
|
||||
inc i, 3
|
||||
else: return i
|
||||
elif ord(s[i]) shr 3 == 0b11110:
|
||||
if i+3 < L and ord(s[i+1]) shr 6 == 0b10 and
|
||||
ord(s[i+2]) shr 6 == 0b10 and
|
||||
ord(s[i+3]) shr 6 == 0b10:
|
||||
inc i, 4
|
||||
else: return i
|
||||
else:
|
||||
return i
|
||||
return -1
|
||||
|
||||
proc runeAt*(s: string, i: Natural): Rune =
|
||||
## returns the unicode character in `s` at byte index `i`
|
||||
fastRuneAt(s, i, result, false)
|
||||
|
|
|
|||
|
|
@ -70,5 +70,5 @@ proc unidecode*(s: string): string =
|
|||
|
||||
when isMainModule:
|
||||
loadUnidecodeTable("lib/pure/unidecode/unidecode.dat")
|
||||
echo unidecode("Äußerst")
|
||||
assert unidecode("Äußerst") == "Ausserst"
|
||||
|
||||
|
|
|
|||
|
|
@ -53,10 +53,10 @@ proc parseAuthority(authority: string, result: var Uri) =
|
|||
while true:
|
||||
case authority[i]
|
||||
of '@':
|
||||
result.password = result.port
|
||||
result.port = ""
|
||||
result.username = result.hostname
|
||||
result.hostname = ""
|
||||
swap result.password, result.port
|
||||
result.port.setLen(0)
|
||||
swap result.username, result.hostname
|
||||
result.hostname.setLen(0)
|
||||
inPort = false
|
||||
of ':':
|
||||
inPort = true
|
||||
|
|
@ -75,7 +75,7 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
|
|||
# The 'mailto' scheme's PATH actually contains the hostname/username
|
||||
if result.scheme.toLower == "mailto":
|
||||
parseAuthority(result.path, result)
|
||||
result.path = ""
|
||||
result.path.setLen(0)
|
||||
|
||||
if uri[i] == '?':
|
||||
i.inc # Skip '?'
|
||||
|
|
@ -85,13 +85,21 @@ proc parsePath(uri: string, i: var int, result: var Uri) =
|
|||
i.inc # Skip '#'
|
||||
i.inc parseUntil(uri, result.anchor, {}, i)
|
||||
|
||||
proc initUri(): Uri =
|
||||
proc initUri*(): Uri =
|
||||
## Initializes a URI.
|
||||
result = Uri(scheme: "", username: "", password: "", hostname: "", port: "",
|
||||
path: "", query: "", anchor: "")
|
||||
|
||||
proc parseUri*(uri: string): Uri =
|
||||
## Parses a URI.
|
||||
result = initUri()
|
||||
proc resetUri(uri: var Uri) =
|
||||
for f in uri.fields:
|
||||
when f is string:
|
||||
f.setLen(0)
|
||||
else:
|
||||
f = false
|
||||
|
||||
proc parseUri*(uri: string, result: var Uri) =
|
||||
## Parses a URI. The `result` variable will be cleared before.
|
||||
resetUri(result)
|
||||
|
||||
var i = 0
|
||||
|
||||
|
|
@ -105,7 +113,7 @@ proc parseUri*(uri: string): Uri =
|
|||
if uri[i] != ':':
|
||||
# Assume this is a reference URI (relative URI)
|
||||
i = 0
|
||||
result.scheme = ""
|
||||
result.scheme.setLen(0)
|
||||
parsePath(uri, i, result)
|
||||
return
|
||||
i.inc # Skip ':'
|
||||
|
|
@ -124,6 +132,11 @@ proc parseUri*(uri: string): Uri =
|
|||
# Path
|
||||
parsePath(uri, i, result)
|
||||
|
||||
proc parseUri*(uri: string): Uri =
|
||||
## Parses a URI and returns it.
|
||||
result = initUri()
|
||||
parseUri(uri, result)
|
||||
|
||||
proc removeDotSegments(path: string): string =
|
||||
var collection: seq[string] = @[]
|
||||
let endsWithSlash = path[path.len-1] == '/'
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ proc loadXMLFile*(path: string): PDocument =
|
|||
return loadXMLStream(s)
|
||||
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var xml = loadXMLFile("nim/xmldom/test.xml")
|
||||
#echo(xml.getElementsByTagName("m:test2")[0].namespaceURI)
|
||||
#echo(xml.getElementsByTagName("bla:test")[0].namespaceURI)
|
||||
|
|
|
|||
|
|
@ -143,7 +143,7 @@ proc loadXml*(path: string): XmlNode =
|
|||
result = loadXml(path, errors)
|
||||
if errors.len > 0: raiseInvalidXml(errors)
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
import os
|
||||
|
||||
var errors: seq[string] = @[]
|
||||
|
|
|
|||
|
|
@ -353,5 +353,6 @@ proc findAll*(n: XmlNode, tag: string): seq[XmlNode] =
|
|||
findAll(n, tag, result)
|
||||
|
||||
when isMainModule:
|
||||
assert """<a href="http://nim-lang.org">Nim rules.</a>""" ==
|
||||
let link = "http://nim-lang.org"
|
||||
assert """<a href="""" & escape(link) & """">Nim rules.</a>""" ==
|
||||
$(<>a(href="http://nim-lang.org", newText("Nim rules.")))
|
||||
|
|
|
|||
|
|
@ -663,7 +663,7 @@ proc `+` *(x: int): int {.magic: "UnaryPlusI", noSideEffect.}
|
|||
proc `+` *(x: int8): int8 {.magic: "UnaryPlusI", noSideEffect.}
|
||||
proc `+` *(x: int16): int16 {.magic: "UnaryPlusI", noSideEffect.}
|
||||
proc `+` *(x: int32): int32 {.magic: "UnaryPlusI", noSideEffect.}
|
||||
proc `+` *(x: int64): int64 {.magic: "UnaryPlusI64", noSideEffect.}
|
||||
proc `+` *(x: int64): int64 {.magic: "UnaryPlusI", noSideEffect.}
|
||||
## Unary `+` operator for an integer. Has no effect.
|
||||
|
||||
proc `-` *(x: int): int {.magic: "UnaryMinusI", noSideEffect.}
|
||||
|
|
@ -1532,10 +1532,10 @@ const
|
|||
NimMajor*: int = 0
|
||||
## is the major number of Nim's version.
|
||||
|
||||
NimMinor*: int = 10
|
||||
NimMinor*: int = 11
|
||||
## is the minor number of Nim's version.
|
||||
|
||||
NimPatch*: int = 3
|
||||
NimPatch*: int = 2
|
||||
## is the patch number of Nim's version.
|
||||
|
||||
NimVersion*: string = $NimMajor & "." & $NimMinor & "." & $NimPatch
|
||||
|
|
@ -1638,7 +1638,7 @@ proc min*(x, y: int16): int16 {.magic: "MinI", noSideEffect.} =
|
|||
if x <= y: x else: y
|
||||
proc min*(x, y: int32): int32 {.magic: "MinI", noSideEffect.} =
|
||||
if x <= y: x else: y
|
||||
proc min*(x, y: int64): int64 {.magic: "MinI64", noSideEffect.} =
|
||||
proc min*(x, y: int64): int64 {.magic: "MinI", noSideEffect.} =
|
||||
## The minimum value of two integers.
|
||||
if x <= y: x else: y
|
||||
|
||||
|
|
@ -1656,7 +1656,7 @@ proc max*(x, y: int16): int16 {.magic: "MaxI", noSideEffect.} =
|
|||
if y <= x: x else: y
|
||||
proc max*(x, y: int32): int32 {.magic: "MaxI", noSideEffect.} =
|
||||
if y <= x: x else: y
|
||||
proc max*(x, y: int64): int64 {.magic: "MaxI64", noSideEffect.} =
|
||||
proc max*(x, y: int64): int64 {.magic: "MaxI", noSideEffect.} =
|
||||
## The maximum value of two integers.
|
||||
if y <= x: x else: y
|
||||
|
||||
|
|
@ -1744,6 +1744,12 @@ iterator items*(E: typedesc[enum]): E =
|
|||
for v in low(E)..high(E):
|
||||
yield v
|
||||
|
||||
iterator items*[T](s: Slice[T]): T =
|
||||
## iterates over the slice `s`, yielding each value between `s.a` and `s.b`
|
||||
## (inclusively).
|
||||
for x in s.a..s.b:
|
||||
yield x
|
||||
|
||||
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
|
||||
|
|
@ -3201,7 +3207,7 @@ when hostOS != "standalone":
|
|||
if x == nil: x = y
|
||||
else: x.add(y)
|
||||
|
||||
proc locals*(): RootObj {.magic: "Locals", noSideEffect.} =
|
||||
proc locals*(): RootObj {.magic: "Plugin", noSideEffect.} =
|
||||
## generates a tuple constructor expression listing all the local variables
|
||||
## 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
|
||||
|
|
@ -3250,4 +3256,20 @@ proc `^`*(x: int): int {.noSideEffect, magic: "Roof".} =
|
|||
## overloaded ``[]`` or ``[]=`` accessors.
|
||||
discard
|
||||
|
||||
template `..^`*(a, b: expr): expr =
|
||||
## a shortcut for '.. ^' to avoid the common gotcha that a space between
|
||||
## '..' and '^' is required.
|
||||
a .. ^b
|
||||
|
||||
template `..<`*(a, b: expr): expr =
|
||||
## a shortcut for '.. <' to avoid the common gotcha that a space between
|
||||
## '..' and '<' is required.
|
||||
a .. <b
|
||||
|
||||
proc xlen*(x: string): int {.magic: "XLenStr", noSideEffect.} = discard
|
||||
proc xlen*[T](x: seq[T]): int {.magic: "XLenSeq", noSideEffect.} =
|
||||
## returns the length of a sequence or a string without testing for 'nil'.
|
||||
## This is an optimization that rarely makes sense.
|
||||
discard
|
||||
|
||||
{.pop.} #{.push warning[GcMem]: off.}
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ when someGcc and hasThreadSupport:
|
|||
|
||||
proc atomicCompareExchange*[T: TAtomType](p, expected, desired: ptr T,
|
||||
weak: bool, success_memmodel: AtomMemModel, failure_memmodel: AtomMemModel): bool {.
|
||||
importc: "__atomic_compare_exchange_n ", nodecl.}
|
||||
importc: "__atomic_compare_exchange", nodecl.}
|
||||
## This proc implements the generic version of atomic_compare_exchange.
|
||||
## The proc is virtually identical to atomic_compare_exchange_n, except the desired
|
||||
## value is also a pointer.
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ proc pushSafePoint(s: PSafePoint) {.compilerRtl, inl.} =
|
|||
proc popSafePoint {.compilerRtl, inl.} =
|
||||
excHandler = excHandler.prev
|
||||
|
||||
proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
|
||||
proc pushCurrentException(e: ref Exception) {.compilerRtl, inl.} =
|
||||
e.parent = currException
|
||||
currException = e
|
||||
|
||||
|
|
@ -69,12 +69,12 @@ proc popCurrentException {.compilerRtl, inl.} =
|
|||
const
|
||||
nativeStackTraceSupported* = (defined(macosx) or defined(linux)) and
|
||||
not NimStackTrace
|
||||
hasSomeStackTrace = NimStackTrace or
|
||||
hasSomeStackTrace = NimStackTrace or
|
||||
defined(nativeStackTrace) and nativeStackTraceSupported
|
||||
|
||||
when defined(nativeStacktrace) and nativeStackTraceSupported:
|
||||
type
|
||||
TDl_info {.importc: "Dl_info", header: "<dlfcn.h>",
|
||||
TDl_info {.importc: "Dl_info", header: "<dlfcn.h>",
|
||||
final, pure.} = object
|
||||
dli_fname: cstring
|
||||
dli_fbase: pointer
|
||||
|
|
@ -98,7 +98,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
|||
tempDlInfo: TDl_info
|
||||
# This is allowed to be expensive since it only happens during crashes
|
||||
# (but this way you don't need manual stack tracing)
|
||||
var size = backtrace(cast[ptr pointer](addr(tempAddresses)),
|
||||
var size = backtrace(cast[ptr pointer](addr(tempAddresses)),
|
||||
len(tempAddresses))
|
||||
var enabled = false
|
||||
for i in 0..size-1:
|
||||
|
|
@ -123,7 +123,7 @@ when defined(nativeStacktrace) and nativeStackTraceSupported:
|
|||
when not hasThreadSupport:
|
||||
var
|
||||
tempFrames: array [0..127, PFrame] # should not be alloc'd on stack
|
||||
|
||||
|
||||
proc auxWriteStackTrace(f: PFrame, s: var string) =
|
||||
when hasThreadSupport:
|
||||
var
|
||||
|
|
@ -160,7 +160,7 @@ proc auxWriteStackTrace(f: PFrame, s: var string) =
|
|||
inc(i)
|
||||
b = b.prev
|
||||
for j in countdown(i-1, 0):
|
||||
if tempFrames[j] == nil:
|
||||
if tempFrames[j] == nil:
|
||||
add(s, "(")
|
||||
add(s, $skipped)
|
||||
add(s, " calls omitted) ...")
|
||||
|
|
@ -214,41 +214,49 @@ proc raiseExceptionAux(e: ref Exception) =
|
|||
if not localRaiseHook(e): return
|
||||
if globalRaiseHook != nil:
|
||||
if not globalRaiseHook(e): return
|
||||
if excHandler != nil:
|
||||
if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
|
||||
pushCurrentException(e)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
elif e[] of OutOfMemError:
|
||||
showErrorMessage(e.name)
|
||||
quitOrDebug()
|
||||
else:
|
||||
when hasSomeStackTrace:
|
||||
var buf = newStringOfCap(2000)
|
||||
if isNil(e.trace): rawWriteStackTrace(buf)
|
||||
else: add(buf, e.trace)
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
if not isNil(e.msg): add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
add(buf, $e.name)
|
||||
add(buf, "]\n")
|
||||
showErrorMessage(buf)
|
||||
when defined(cpp):
|
||||
if e[] of OutOfMemError:
|
||||
showErrorMessage(e.name)
|
||||
quitOrDebug()
|
||||
else:
|
||||
# ugly, but avoids heap allocations :-)
|
||||
template xadd(buf, s, slen: expr) =
|
||||
if L + slen < high(buf):
|
||||
copyMem(addr(buf[L]), cstring(s), slen)
|
||||
inc L, slen
|
||||
template add(buf, s: expr) =
|
||||
xadd(buf, s, s.len)
|
||||
var buf: array [0..2000, char]
|
||||
var L = 0
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
if not isNil(e.msg): add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
xadd(buf, e.name, c_strlen(e.name))
|
||||
add(buf, "]\n")
|
||||
showErrorMessage(buf)
|
||||
quitOrDebug()
|
||||
pushCurrentException(e)
|
||||
{.emit: "throw NimException(`e`, `e`->name);".}
|
||||
else:
|
||||
if excHandler != nil:
|
||||
if not excHandler.hasRaiseAction or excHandler.raiseAction(e):
|
||||
pushCurrentException(e)
|
||||
c_longjmp(excHandler.context, 1)
|
||||
elif e[] of OutOfMemError:
|
||||
showErrorMessage(e.name)
|
||||
quitOrDebug()
|
||||
else:
|
||||
when hasSomeStackTrace:
|
||||
var buf = newStringOfCap(2000)
|
||||
if isNil(e.trace): rawWriteStackTrace(buf)
|
||||
else: add(buf, e.trace)
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
if not isNil(e.msg): add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
add(buf, $e.name)
|
||||
add(buf, "]\n")
|
||||
showErrorMessage(buf)
|
||||
else:
|
||||
# ugly, but avoids heap allocations :-)
|
||||
template xadd(buf, s, slen: expr) =
|
||||
if L + slen < high(buf):
|
||||
copyMem(addr(buf[L]), cstring(s), slen)
|
||||
inc L, slen
|
||||
template add(buf, s: expr) =
|
||||
xadd(buf, s, s.len)
|
||||
var buf: array [0..2000, char]
|
||||
var L = 0
|
||||
add(buf, "Error: unhandled exception: ")
|
||||
if not isNil(e.msg): add(buf, e.msg)
|
||||
add(buf, " [")
|
||||
xadd(buf, e.name, c_strlen(e.name))
|
||||
add(buf, "]\n")
|
||||
showErrorMessage(buf)
|
||||
quitOrDebug()
|
||||
|
||||
proc raiseException(e: ref Exception, ename: cstring) {.compilerRtl.} =
|
||||
e.name = ename
|
||||
|
|
@ -309,7 +317,7 @@ when not defined(noSignalHandler):
|
|||
proc signalHandler(sig: cint) {.exportc: "signalHandler", noconv.} =
|
||||
template processSignal(s, action: expr) {.immediate, dirty.} =
|
||||
if s == SIGINT: action("SIGINT: Interrupted by Ctrl-C.\n")
|
||||
elif s == SIGSEGV:
|
||||
elif s == SIGSEGV:
|
||||
action("SIGSEGV: Illegal storage access. (Attempt to read from nil?)\n")
|
||||
elif s == SIGABRT:
|
||||
when defined(endb):
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
## This module implements a small wrapper for some needed Win API procedures,
|
||||
## so that the Nim compiler does not depend on the huge Windows module.
|
||||
|
||||
{.deadCodeElim:on.}
|
||||
|
||||
const
|
||||
useWinUnicode* = not defined(useWinAnsi)
|
||||
|
||||
|
|
@ -29,7 +31,7 @@ type
|
|||
nLength*: int32
|
||||
lpSecurityDescriptor*: pointer
|
||||
bInheritHandle*: WINBOOL
|
||||
|
||||
|
||||
TSTARTUPINFO* {.final, pure.} = object
|
||||
cb*: int32
|
||||
lpReserved*: cstring
|
||||
|
|
@ -59,7 +61,7 @@ type
|
|||
TFILETIME* {.final, pure.} = object ## CANNOT BE int64 BECAUSE OF ALIGNMENT
|
||||
dwLowDateTime*: DWORD
|
||||
dwHighDateTime*: DWORD
|
||||
|
||||
|
||||
TBY_HANDLE_FILE_INFORMATION* {.final, pure.} = object
|
||||
dwFileAttributes*: DWORD
|
||||
ftCreationTime*: TFILETIME
|
||||
|
|
@ -94,26 +96,26 @@ const
|
|||
STD_ERROR_HANDLE* = -12'i32
|
||||
|
||||
DETACHED_PROCESS* = 8'i32
|
||||
|
||||
|
||||
SW_SHOWNORMAL* = 1'i32
|
||||
INVALID_HANDLE_VALUE* = THandle(-1)
|
||||
|
||||
|
||||
CREATE_UNICODE_ENVIRONMENT* = 1024'i32
|
||||
|
||||
proc closeHandle*(hObject: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "CloseHandle".}
|
||||
|
||||
|
||||
proc readFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToRead: int32,
|
||||
lpNumberOfBytesRead: ptr int32, lpOverlapped: pointer): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "ReadFile".}
|
||||
|
||||
|
||||
proc writeFile*(hFile: THandle, Buffer: pointer, nNumberOfBytesToWrite: int32,
|
||||
lpNumberOfBytesWritten: ptr int32,
|
||||
lpNumberOfBytesWritten: ptr int32,
|
||||
lpOverlapped: pointer): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "WriteFile".}
|
||||
|
||||
proc createPipe*(hReadPipe, hWritePipe: var THandle,
|
||||
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
|
||||
lpPipeAttributes: var TSECURITY_ATTRIBUTES,
|
||||
nSize: int32): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "CreatePipe".}
|
||||
|
||||
|
|
@ -159,7 +161,7 @@ proc setStdHandle*(nStdHandle: int32, hHandle: THandle): WINBOOL {.stdcall,
|
|||
proc flushFileBuffers*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
|
||||
importc: "FlushFileBuffers".}
|
||||
|
||||
proc getLastError*(): int32 {.importc: "GetLastError",
|
||||
proc getLastError*(): int32 {.importc: "GetLastError",
|
||||
stdcall, dynlib: "kernel32".}
|
||||
|
||||
when useWinUnicode:
|
||||
|
|
@ -179,7 +181,7 @@ proc localFree*(p: pointer) {.
|
|||
importc: "LocalFree", stdcall, dynlib: "kernel32".}
|
||||
|
||||
when useWinUnicode:
|
||||
proc getCurrentDirectoryW*(nBufferLength: int32,
|
||||
proc getCurrentDirectoryW*(nBufferLength: int32,
|
||||
lpBuffer: WideCString): int32 {.
|
||||
importc: "GetCurrentDirectoryW", dynlib: "kernel32", stdcall.}
|
||||
proc setCurrentDirectoryW*(lpPathName: WideCString): int32 {.
|
||||
|
|
@ -191,8 +193,8 @@ when useWinUnicode:
|
|||
proc setEnvironmentVariableW*(lpName, lpValue: WideCString): int32 {.
|
||||
stdcall, dynlib: "kernel32", importc: "SetEnvironmentVariableW".}
|
||||
|
||||
proc getModuleFileNameW*(handle: THandle, buf: WideCString,
|
||||
size: int32): int32 {.importc: "GetModuleFileNameW",
|
||||
proc getModuleFileNameW*(handle: THandle, buf: WideCString,
|
||||
size: int32): int32 {.importc: "GetModuleFileNameW",
|
||||
dynlib: "kernel32", stdcall.}
|
||||
else:
|
||||
proc getCurrentDirectoryA*(nBufferLength: int32, lpBuffer: cstring): int32 {.
|
||||
|
|
@ -269,14 +271,14 @@ proc findClose*(hFindFile: THandle) {.stdcall, dynlib: "kernel32",
|
|||
|
||||
when useWinUnicode:
|
||||
proc getFullPathNameW*(lpFileName: WideCString, nBufferLength: int32,
|
||||
lpBuffer: WideCString,
|
||||
lpBuffer: WideCString,
|
||||
lpFilePart: var WideCString): int32 {.
|
||||
stdcall, dynlib: "kernel32",
|
||||
stdcall, dynlib: "kernel32",
|
||||
importc: "GetFullPathNameW".}
|
||||
proc getFileAttributesW*(lpFileName: WideCString): int32 {.
|
||||
stdcall, dynlib: "kernel32",
|
||||
stdcall, dynlib: "kernel32",
|
||||
importc: "GetFileAttributesW".}
|
||||
proc setFileAttributesW*(lpFileName: WideCString,
|
||||
proc setFileAttributesW*(lpFileName: WideCString,
|
||||
dwFileAttributes: int32): WINBOOL {.
|
||||
stdcall, dynlib: "kernel32", importc: "SetFileAttributesW".}
|
||||
|
||||
|
|
@ -299,12 +301,12 @@ when useWinUnicode:
|
|||
else:
|
||||
proc getFullPathNameA*(lpFileName: cstring, nBufferLength: int32,
|
||||
lpBuffer: cstring, lpFilePart: var cstring): int32 {.
|
||||
stdcall, dynlib: "kernel32",
|
||||
stdcall, dynlib: "kernel32",
|
||||
importc: "GetFullPathNameA".}
|
||||
proc getFileAttributesA*(lpFileName: cstring): int32 {.
|
||||
stdcall, dynlib: "kernel32",
|
||||
stdcall, dynlib: "kernel32",
|
||||
importc: "GetFileAttributesA".}
|
||||
proc setFileAttributesA*(lpFileName: cstring,
|
||||
proc setFileAttributesA*(lpFileName: cstring,
|
||||
dwFileAttributes: int32): WINBOOL {.
|
||||
stdcall, dynlib: "kernel32", importc: "SetFileAttributesA".}
|
||||
|
||||
|
|
@ -324,10 +326,10 @@ else:
|
|||
proc getCommandLineA*(): cstring {.
|
||||
importc: "GetCommandLineA", stdcall, dynlib: "kernel32".}
|
||||
|
||||
proc rdFileTime*(f: TFILETIME): int64 =
|
||||
proc rdFileTime*(f: TFILETIME): int64 =
|
||||
result = ze64(f.dwLowDateTime) or (ze64(f.dwHighDateTime) shl 32)
|
||||
|
||||
proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
|
||||
proc rdFileSize*(f: TWIN32_FIND_DATA): int64 =
|
||||
result = ze64(f.nFileSizeLow) or (ze64(f.nFileSizeHigh) shl 32)
|
||||
|
||||
proc getSystemTimeAsFileTime*(lpSystemTimeAsFileTime: var TFILETIME) {.
|
||||
|
|
@ -347,7 +349,7 @@ else:
|
|||
lpParameters, lpDirectory: cstring,
|
||||
nShowCmd: int32): THandle{.
|
||||
stdcall, dynlib: "shell32.dll", importc: "ShellExecuteA".}
|
||||
|
||||
|
||||
proc getFileInformationByHandle*(hFile: THandle,
|
||||
lpFileInformation: ptr TBY_HANDLE_FILE_INFORMATION): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "GetFileInformationByHandle".}
|
||||
|
|
@ -357,12 +359,12 @@ const
|
|||
WSASYS_STATUS_LEN* = 128
|
||||
FD_SETSIZE* = 64
|
||||
MSG_PEEK* = 2
|
||||
|
||||
|
||||
INADDR_ANY* = 0
|
||||
INADDR_LOOPBACK* = 0x7F000001
|
||||
INADDR_BROADCAST* = -1
|
||||
INADDR_NONE* = -1
|
||||
|
||||
|
||||
ws2dll = "Ws2_32.dll"
|
||||
|
||||
WSAEWOULDBLOCK* = 10035
|
||||
|
|
@ -376,31 +378,31 @@ type
|
|||
{.deprecated: [TSocketHandle: SocketHandle].}
|
||||
|
||||
type
|
||||
WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object
|
||||
WSAData* {.importc: "WSADATA", header: "winsock2.h".} = object
|
||||
wVersion, wHighVersion: int16
|
||||
szDescription: array[0..WSADESCRIPTION_LEN, char]
|
||||
szSystemStatus: array[0..WSASYS_STATUS_LEN, char]
|
||||
iMaxSockets, iMaxUdpDg: int16
|
||||
lpVendorInfo: cstring
|
||||
|
||||
SockAddr* {.importc: "SOCKADDR", header: "winsock2.h".} = object
|
||||
|
||||
SockAddr* {.importc: "SOCKADDR", header: "winsock2.h".} = object
|
||||
sa_family*: int16 # unsigned
|
||||
sa_data: array[0..13, char]
|
||||
|
||||
InAddr* {.importc: "IN_ADDR", header: "winsock2.h".} = object
|
||||
s_addr*: int32 # IP address
|
||||
|
||||
Sockaddr_in* {.importc: "SOCKADDR_IN",
|
||||
|
||||
Sockaddr_in* {.importc: "SOCKADDR_IN",
|
||||
header: "winsock2.h".} = object
|
||||
sin_family*: int16
|
||||
sin_port*: int16 # unsigned
|
||||
sin_addr*: InAddr
|
||||
sin_zero*: array[0..7, char]
|
||||
|
||||
In6_addr* {.importc: "IN6_ADDR", header: "winsock2.h".} = object
|
||||
In6_addr* {.importc: "IN6_ADDR", header: "winsock2.h".} = object
|
||||
bytes*: array[0..15, char]
|
||||
|
||||
Sockaddr_in6* {.importc: "SOCKADDR_IN6",
|
||||
Sockaddr_in6* {.importc: "SOCKADDR_IN6",
|
||||
header: "winsock2.h".} = object
|
||||
sin6_family*: int16
|
||||
sin6_port*: int16 # unsigned
|
||||
|
|
@ -430,23 +432,23 @@ type
|
|||
h_addrtype*: int16
|
||||
h_length*: int16
|
||||
h_addr_list*: cstringArray
|
||||
|
||||
|
||||
TFdSet* = object
|
||||
fd_count*: cint # unsigned
|
||||
fd_array*: array[0..FD_SETSIZE-1, SocketHandle]
|
||||
|
||||
|
||||
Timeval* = object
|
||||
tv_sec*, tv_usec*: int32
|
||||
|
||||
|
||||
AddrInfo* = object
|
||||
ai_flags*: cint ## Input flags.
|
||||
ai_family*: cint ## Address family of socket.
|
||||
ai_socktype*: cint ## Socket type.
|
||||
ai_protocol*: cint ## Protocol of socket.
|
||||
ai_addrlen*: int ## Length of socket address.
|
||||
ai_flags*: cint ## Input flags.
|
||||
ai_family*: cint ## Address family of socket.
|
||||
ai_socktype*: cint ## Socket type.
|
||||
ai_protocol*: cint ## Protocol of socket.
|
||||
ai_addrlen*: int ## Length of socket address.
|
||||
ai_canonname*: cstring ## Canonical name of service location.
|
||||
ai_addr*: ptr SockAddr ## Socket address of socket.
|
||||
ai_next*: ptr AddrInfo ## Pointer to next in list.
|
||||
ai_addr*: ptr SockAddr ## Socket address of socket.
|
||||
ai_next*: ptr AddrInfo ## Pointer to next in list.
|
||||
|
||||
SockLen* = cuint
|
||||
|
||||
|
|
@ -501,7 +503,7 @@ proc bindSocket*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {.
|
|||
stdcall, importc: "bind", dynlib: ws2dll.}
|
||||
proc connect*(s: SocketHandle, name: ptr SockAddr, namelen: SockLen): cint {.
|
||||
stdcall, importc: "connect", dynlib: ws2dll.}
|
||||
proc getsockname*(s: SocketHandle, name: ptr SockAddr,
|
||||
proc getsockname*(s: SocketHandle, name: ptr SockAddr,
|
||||
namelen: ptr SockLen): cint {.
|
||||
stdcall, importc: "getsockname", dynlib: ws2dll.}
|
||||
proc getsockopt*(s: SocketHandle, level, optname: cint, optval: pointer,
|
||||
|
|
@ -515,7 +517,7 @@ proc listen*(s: SocketHandle, backlog: cint): cint {.
|
|||
stdcall, importc: "listen", dynlib: ws2dll.}
|
||||
proc recv*(s: SocketHandle, buf: pointer, len, flags: cint): cint {.
|
||||
stdcall, importc: "recv", dynlib: ws2dll.}
|
||||
proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint,
|
||||
proc recvfrom*(s: SocketHandle, buf: cstring, len, flags: cint,
|
||||
fromm: ptr SockAddr, fromlen: ptr SockLen): cint {.
|
||||
stdcall, importc: "recvfrom", dynlib: ws2dll.}
|
||||
proc select*(nfds: cint, readfds, writefds, exceptfds: ptr TFdSet,
|
||||
|
|
@ -529,22 +531,22 @@ proc sendto*(s: SocketHandle, buf: pointer, len, flags: cint,
|
|||
|
||||
proc shutdown*(s: SocketHandle, how: cint): cint {.
|
||||
stdcall, importc: "shutdown", dynlib: ws2dll.}
|
||||
|
||||
|
||||
proc getnameinfo*(a1: ptr SockAddr, a2: SockLen,
|
||||
a3: cstring, a4: SockLen, a5: cstring,
|
||||
a6: SockLen, a7: cint): cint {.
|
||||
stdcall, importc: "getnameinfo", dynlib: ws2dll.}
|
||||
|
||||
|
||||
proc inet_addr*(cp: cstring): int32 {.
|
||||
stdcall, importc: "inet_addr", dynlib: ws2dll.}
|
||||
stdcall, importc: "inet_addr", dynlib: ws2dll.}
|
||||
|
||||
proc WSAFDIsSet(s: SocketHandle, set: var TFdSet): bool {.
|
||||
stdcall, importc: "__WSAFDIsSet", dynlib: ws2dll, noSideEffect.}
|
||||
|
||||
proc FD_ISSET*(socket: SocketHandle, set: var TFdSet): cint =
|
||||
proc FD_ISSET*(socket: SocketHandle, set: var TFdSet): cint =
|
||||
result = if WSAFDIsSet(socket, set): 1'i32 else: 0'i32
|
||||
|
||||
proc FD_SET*(socket: SocketHandle, s: var TFdSet) =
|
||||
proc FD_SET*(socket: SocketHandle, s: var TFdSet) =
|
||||
if s.fd_count < FD_SETSIZE:
|
||||
s.fd_array[int(s.fd_count)] = socket
|
||||
inc(s.fd_count)
|
||||
|
|
@ -575,8 +577,8 @@ type
|
|||
proc waitForMultipleObjects*(nCount: DWORD, lpHandles: PWOHandleArray,
|
||||
bWaitAll: WINBOOL, dwMilliseconds: DWORD): DWORD{.
|
||||
stdcall, dynlib: "kernel32", importc: "WaitForMultipleObjects".}
|
||||
|
||||
|
||||
|
||||
|
||||
# for memfiles.nim:
|
||||
|
||||
const
|
||||
|
|
@ -586,7 +588,7 @@ const
|
|||
FILE_SHARE_READ* = 1'i32
|
||||
FILE_SHARE_DELETE* = 4'i32
|
||||
FILE_SHARE_WRITE* = 2'i32
|
||||
|
||||
|
||||
CREATE_ALWAYS* = 2'i32
|
||||
CREATE_NEW* = 1'i32
|
||||
OPEN_EXISTING* = 3'i32
|
||||
|
|
@ -628,7 +630,7 @@ proc setEndOfFile*(hFile: THandle): WINBOOL {.stdcall, dynlib: "kernel32",
|
|||
importc: "SetEndOfFile".}
|
||||
|
||||
proc setFilePointer*(hFile: THandle, lDistanceToMove: LONG,
|
||||
lpDistanceToMoveHigh: ptr LONG,
|
||||
lpDistanceToMoveHigh: ptr LONG,
|
||||
dwMoveMethod: DWORD): DWORD {.
|
||||
stdcall, dynlib: "kernel32", importc: "SetFilePointer".}
|
||||
|
||||
|
|
@ -637,14 +639,14 @@ proc getFileSize*(hFile: THandle, lpFileSizeHigh: ptr DWORD): DWORD{.stdcall,
|
|||
|
||||
proc mapViewOfFileEx*(hFileMappingObject: THandle, dwDesiredAccess: DWORD,
|
||||
dwFileOffsetHigh, dwFileOffsetLow: DWORD,
|
||||
dwNumberOfBytesToMap: DWORD,
|
||||
dwNumberOfBytesToMap: DWORD,
|
||||
lpBaseAddress: pointer): pointer{.
|
||||
stdcall, dynlib: "kernel32", importc: "MapViewOfFileEx".}
|
||||
|
||||
proc createFileMappingW*(hFile: THandle,
|
||||
lpFileMappingAttributes: pointer,
|
||||
flProtect, dwMaximumSizeHigh: DWORD,
|
||||
dwMaximumSizeLow: DWORD,
|
||||
dwMaximumSizeLow: DWORD,
|
||||
lpName: pointer): THandle {.
|
||||
stdcall, dynlib: "kernel32", importc: "CreateFileMappingW".}
|
||||
|
||||
|
|
@ -702,7 +704,7 @@ proc getOverlappedResult*(hFile: THandle, lpOverlapped: TOVERLAPPED,
|
|||
lpNumberOfBytesTransferred: var DWORD, bWait: WINBOOL): WINBOOL{.
|
||||
stdcall, dynlib: "kernel32", importc: "GetOverlappedResult".}
|
||||
|
||||
const
|
||||
const
|
||||
IOC_OUT* = 0x40000000
|
||||
IOC_IN* = 0x80000000
|
||||
IOC_WS2* = 0x08000000
|
||||
|
|
@ -725,7 +727,7 @@ var
|
|||
proc WSAIoctl*(s: SocketHandle, dwIoControlCode: DWORD, lpvInBuffer: pointer,
|
||||
cbInBuffer: DWORD, lpvOutBuffer: pointer, cbOutBuffer: DWORD,
|
||||
lpcbBytesReturned: PDWORD, lpOverlapped: POVERLAPPED,
|
||||
lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint
|
||||
lpCompletionRoutine: POVERLAPPED_COMPLETION_ROUTINE): cint
|
||||
{.stdcall, importc: "WSAIoctl", dynlib: "Ws2_32.dll".}
|
||||
|
||||
type
|
||||
|
|
@ -746,7 +748,7 @@ proc WSASend*(s: SocketHandle, buf: ptr TWSABuf, bufCount: DWORD,
|
|||
proc get_osfhandle*(fd:FileHandle): THandle {.
|
||||
importc: "_get_osfhandle", header:"<io.h>".}
|
||||
|
||||
proc getSystemTimes*(lpIdleTime, lpKernelTime,
|
||||
proc getSystemTimes*(lpIdleTime, lpKernelTime,
|
||||
lpUserTime: var TFILETIME): WINBOOL {.stdcall,
|
||||
dynlib: "kernel32", importc: "GetSystemTimes".}
|
||||
|
||||
|
|
|
|||
|
|
@ -2710,7 +2710,7 @@ proc workspace_window_set_icon*(w: ptr TWorkspaceWindow, icon: ptr TImage){.
|
|||
claro_base_init()
|
||||
claro_graphics_init()
|
||||
|
||||
when isMainModule:
|
||||
when not defined(testing) and isMainModule:
|
||||
var w = newWindow(nil, newBounds(100, 100, 230, 230), 0)
|
||||
window_set_title(w, "Hello, World!")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,158 +1,190 @@
|
|||
#************************************************
|
||||
# Perl-Compatible Regular Expressions *
|
||||
#***********************************************
|
||||
# Perl-Compatible Regular Expressions *
|
||||
#************************************************
|
||||
# This is the public header file for the PCRE library, to be #included by
|
||||
#applications that call the PCRE functions.
|
||||
# applications that call the PCRE functions.
|
||||
#
|
||||
# Copyright (c) 1997-2010 University of Cambridge
|
||||
# Copyright (c) 1997-2014 University of Cambridge
|
||||
#
|
||||
#-----------------------------------------------------------------------------
|
||||
#Redistribution and use in source and binary forms, with or without
|
||||
#modification, are permitted provided that the following conditions are met:
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
#
|
||||
# Redistributions of source code must retain the above copyright notice,
|
||||
# * Redistributions of source code must retain the above copyright notice,
|
||||
# this list of conditions and the following disclaimer.
|
||||
#
|
||||
# Redistributions in binary form must reproduce the above copyright
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# Neither the name of the University of Cambridge nor the names of its
|
||||
# * Neither the name of the University of Cambridge nor the names of its
|
||||
# contributors may be used to endorse or promote products derived from
|
||||
# this software without specific prior written permission.
|
||||
#
|
||||
#THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
#AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
#IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
#ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
#LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
#CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
#SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
#INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
#CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
#ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
#POSSIBILITY OF SUCH DAMAGE.
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
# POSSIBILITY OF SUCH DAMAGE.
|
||||
#-----------------------------------------------------------------------------
|
||||
#
|
||||
|
||||
{.deadcodeElim: on.}
|
||||
{.deadCodeElim: on.}
|
||||
|
||||
when not defined(pcreDll):
|
||||
when hostOS == "windows":
|
||||
const pcreDll = "pcre.dll"
|
||||
elif hostOS == "macosx":
|
||||
const pcreDll = "libpcre(.3|.1|).dylib"
|
||||
else:
|
||||
const pcreDll = "libpcre.so(.3|.1|)"
|
||||
{.pragma: pcreImport, dynlib: pcreDll.}
|
||||
else:
|
||||
{.pragma: pcreImport, header: "<pcre.h>".}
|
||||
# The current PCRE version information.
|
||||
|
||||
# The current PCRE version information.
|
||||
|
||||
const
|
||||
MAJOR* = 8
|
||||
MINOR* = 31
|
||||
PRERELEASE* = true
|
||||
DATE* = "2012-07-06"
|
||||
const
|
||||
PCRE_MAJOR* = 8
|
||||
PCRE_MINOR* = 36
|
||||
PCRE_PRERELEASE* = true
|
||||
PCRE_DATE* = "2014-09-26"
|
||||
|
||||
# When an application links to a PCRE DLL in Windows, the symbols that are
|
||||
# imported have to be identified as such. When building PCRE, the appropriate
|
||||
# export setting is defined in pcre_internal.h, which includes this file. So we
|
||||
# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL.
|
||||
# don't change existing definitions of PCRE_EXP_DECL and PCRECPP_EXP_DECL.
|
||||
|
||||
# Have to include stdlib.h in order to ensure that size_t is defined;
|
||||
# it is needed here for malloc.
|
||||
# By default, we use the standard "extern" declarations.
|
||||
|
||||
# Allow for C++ users
|
||||
# Allow for C++ users
|
||||
|
||||
# Options. Some are compile-time only, some are run-time only, and some are
|
||||
# both, so we keep them all distinct.
|
||||
|
||||
const
|
||||
CASELESS* = 0x00000001
|
||||
MULTILINE* = 0x00000002
|
||||
DOTALL* = 0x00000004
|
||||
EXTENDED* = 0x00000008
|
||||
ANCHORED* = 0x00000010
|
||||
DOLLAR_ENDONLY* = 0x00000020
|
||||
EXTRA* = 0x00000040
|
||||
NOTBOL* = 0x00000080
|
||||
NOTEOL* = 0x00000100
|
||||
UNGREEDY* = 0x00000200
|
||||
NOTEMPTY* = 0x00000400
|
||||
UTF8* = 0x00000800
|
||||
NO_AUTO_CAPTURE* = 0x00001000
|
||||
NO_UTF8_CHECK* = 0x00002000
|
||||
AUTO_CALLOUT* = 0x00004000
|
||||
PARTIAL_SOFT* = 0x00008000
|
||||
PARTIAL* = 0x00008000 # Backwards compatible synonym
|
||||
DFA_SHORTEST* = 0x00010000
|
||||
DFA_RESTART* = 0x00020000
|
||||
FIRSTLINE* = 0x00040000
|
||||
DUPNAMES* = 0x00080000
|
||||
NEWLINE_CR* = 0x00100000
|
||||
NEWLINE_LF* = 0x00200000
|
||||
NEWLINE_CRLF* = 0x00300000
|
||||
NEWLINE_ANY* = 0x00400000
|
||||
NEWLINE_ANYCRLF* = 0x00500000
|
||||
BSR_ANYCRLF* = 0x00800000
|
||||
BSR_UNICODE* = 0x01000000
|
||||
JAVASCRIPT_COMPAT* = 0x02000000
|
||||
NO_START_OPTIMIZE* = 0x04000000
|
||||
NO_START_OPTIMISE* = 0x04000000
|
||||
PARTIAL_HARD* = 0x08000000
|
||||
NOTEMPTY_ATSTART* = 0x10000000
|
||||
UCP* = 0x20000000
|
||||
|
||||
# Exec-time and get/set-time error codes
|
||||
|
||||
const
|
||||
ERROR_NOMATCH* = (- 1)
|
||||
ERROR_NULL* = (- 2)
|
||||
ERROR_BADOPTION* = (- 3)
|
||||
ERROR_BADMAGIC* = (- 4)
|
||||
ERROR_UNKNOWN_OPCODE* = (- 5)
|
||||
ERROR_UNKNOWN_NODE* = (- 5) # For backward compatibility
|
||||
ERROR_NOMEMORY* = (- 6)
|
||||
ERROR_NOSUBSTRING* = (- 7)
|
||||
ERROR_MATCHLIMIT* = (- 8)
|
||||
ERROR_CALLOUT* = (- 9) # Never used by PCRE itself
|
||||
ERROR_BADUTF8* = (- 10)
|
||||
ERROR_BADUTF8_OFFSET* = (- 11)
|
||||
ERROR_PARTIAL* = (- 12)
|
||||
ERROR_BADPARTIAL* = (- 13)
|
||||
ERROR_INTERNAL* = (- 14)
|
||||
ERROR_BADCOUNT* = (- 15)
|
||||
ERROR_DFA_UITEM* = (- 16)
|
||||
ERROR_DFA_UCOND* = (- 17)
|
||||
ERROR_DFA_UMLIMIT* = (- 18)
|
||||
ERROR_DFA_WSSIZE* = (- 19)
|
||||
ERROR_DFA_RECURSE* = (- 20)
|
||||
ERROR_RECURSIONLIMIT* = (- 21)
|
||||
ERROR_NULLWSLIMIT* = (- 22) # No longer actually used
|
||||
ERROR_BADNEWLINE* = (- 23)
|
||||
ERROR_BADOFFSET* = (- 24)
|
||||
ERROR_SHORTUTF8* = (- 25)
|
||||
ERROR_RECURSELOOP* = (- 26)
|
||||
ERROR_JIT_STACKLIMIT* = (- 27)
|
||||
ERROR_BADMODE* = (- 28)
|
||||
ERROR_BADENDIANNESS* = (- 29)
|
||||
ERROR_DFA_BADRESTART* = (- 30)
|
||||
|
||||
# Specific error codes for UTF-8 validity checks
|
||||
# Public options. Some are compile-time only, some are run-time only, and some
|
||||
# are both. Most of the compile-time options are saved with the compiled regex
|
||||
# so that they can be inspected during studying (and therefore JIT compiling).
|
||||
# Note that pcre_study() has its own set of options. Originally, all the options
|
||||
# defined here used distinct bits. However, almost all the bits in a 32-bit word
|
||||
# are now used, so in order to conserve them, option bits that were previously
|
||||
# only recognized at matching time (i.e. by pcre_exec() or pcre_dfa_exec()) may
|
||||
# also be used for compile-time options that affect only compiling and are not
|
||||
# relevant for studying or JIT compiling.
|
||||
#
|
||||
# Some options for pcre_compile() change its behaviour but do not affect the
|
||||
# behaviour of the execution functions. Other options are passed through to the
|
||||
# execution functions and affect their behaviour, with or without affecting the
|
||||
# behaviour of pcre_compile().
|
||||
#
|
||||
# Options that can be passed to pcre_compile() are tagged Cx below, with these
|
||||
# variants:
|
||||
#
|
||||
# C1 Affects compile only
|
||||
# C2 Does not affect compile; affects exec, dfa_exec
|
||||
# C3 Affects compile, exec, dfa_exec
|
||||
# C4 Affects compile, exec, dfa_exec, study
|
||||
# C5 Affects compile, exec, study
|
||||
#
|
||||
# Options that can be set for pcre_exec() and/or pcre_dfa_exec() are flagged
|
||||
# with E and D, respectively. They take precedence over C3, C4, and C5 settings
|
||||
# passed from pcre_compile(). Those that are compatible with JIT execution are
|
||||
# flagged with J.
|
||||
|
||||
const
|
||||
UTF8_ERR0* = 0
|
||||
UTF8_ERR1* = 1
|
||||
UTF8_ERR2* = 2
|
||||
UTF8_ERR3* = 3
|
||||
UTF8_ERR4* = 4
|
||||
UTF8_ERR5* = 5
|
||||
UTF8_ERR6* = 6
|
||||
UTF8_ERR7* = 7
|
||||
UTF8_ERR8* = 8
|
||||
UTF8_ERR9* = 9
|
||||
CASELESS* = 0x00000001 # C1
|
||||
MULTILINE* = 0x00000002 # C1
|
||||
DOTALL* = 0x00000004 # C1
|
||||
EXTENDED* = 0x00000008 # C1
|
||||
ANCHORED* = 0x00000010 # C4 E D
|
||||
DOLLAR_ENDONLY* = 0x00000020 # C2
|
||||
EXTRA* = 0x00000040 # C1
|
||||
NOTBOL* = 0x00000080 # E D J
|
||||
NOTEOL* = 0x00000100 # E D J
|
||||
UNGREEDY* = 0x00000200 # C1
|
||||
NOTEMPTY* = 0x00000400 # E D J
|
||||
UTF8* = 0x00000800 # C4 )
|
||||
UTF16* = 0x00000800 # C4 ) Synonyms
|
||||
UTF32* = 0x00000800 # C4 )
|
||||
NO_AUTO_CAPTURE* = 0x00001000 # C1
|
||||
NO_UTF8_CHECK* = 0x00002000 # C1 E D J )
|
||||
NO_UTF16_CHECK* = 0x00002000 # C1 E D J ) Synonyms
|
||||
NO_UTF32_CHECK* = 0x00002000 # C1 E D J )
|
||||
AUTO_CALLOUT* = 0x00004000 # C1
|
||||
PARTIAL_SOFT* = 0x00008000 # E D J ) Synonyms
|
||||
PARTIAL* = 0x00008000 # E D J )
|
||||
|
||||
# This pair use the same bit.
|
||||
const
|
||||
NEVER_UTF* = 0x00010000 # C1 ) Overlaid
|
||||
DFA_SHORTEST* = 0x00010000 # D ) Overlaid
|
||||
|
||||
# This pair use the same bit.
|
||||
const
|
||||
NO_AUTO_POSSESS* = 0x00020000 # C1 ) Overlaid
|
||||
DFA_RESTART* = 0x00020000 # D ) Overlaid
|
||||
|
||||
const
|
||||
FIRSTLINE* = 0x00040000 # C3
|
||||
DUPNAMES* = 0x00080000 # C1
|
||||
NEWLINE_CR* = 0x00100000 # C3 E D
|
||||
NEWLINE_LF* = 0x00200000 # C3 E D
|
||||
NEWLINE_CRLF* = 0x00300000 # C3 E D
|
||||
NEWLINE_ANY* = 0x00400000 # C3 E D
|
||||
NEWLINE_ANYCRLF* = 0x00500000 # C3 E D
|
||||
BSR_ANYCRLF* = 0x00800000 # C3 E D
|
||||
BSR_UNICODE* = 0x01000000 # C3 E D
|
||||
JAVASCRIPT_COMPAT* = 0x02000000 # C5
|
||||
NO_START_OPTIMIZE* = 0x04000000 # C2 E D ) Synonyms
|
||||
NO_START_OPTIMISE* = 0x04000000 # C2 E D )
|
||||
PARTIAL_HARD* = 0x08000000 # E D J
|
||||
NOTEMPTY_ATSTART* = 0x10000000 # E D J
|
||||
UCP* = 0x20000000 # C3
|
||||
|
||||
## Exec-time and get/set-time error codes
|
||||
const
|
||||
ERROR_NOMATCH* = -1
|
||||
ERROR_NULL* = -2
|
||||
ERROR_BADOPTION* = -3
|
||||
ERROR_BADMAGIC* = -4
|
||||
ERROR_UNKNOWN_OPCODE* = -5
|
||||
ERROR_UNKNOWN_NODE* = -5 ## For backward compatibility
|
||||
ERROR_NOMEMORY* = -6
|
||||
ERROR_NOSUBSTRING* = -7
|
||||
ERROR_MATCHLIMIT* = -8
|
||||
ERROR_CALLOUT* = -9 ## Never used by PCRE itself
|
||||
ERROR_BADUTF8* = -10 ## Same for 8/16/32
|
||||
ERROR_BADUTF16* = -10 ## Same for 8/16/32
|
||||
ERROR_BADUTF32* = -10 ## Same for 8/16/32
|
||||
ERROR_BADUTF8_OFFSET* = -11 ## Same for 8/16
|
||||
ERROR_BADUTF16_OFFSET* = -11 ## Same for 8/16
|
||||
ERROR_PARTIAL* = -12
|
||||
ERROR_BADPARTIAL* = -13
|
||||
ERROR_INTERNAL* = -14
|
||||
ERROR_BADCOUNT* = -15
|
||||
ERROR_DFA_UITEM* = -16
|
||||
ERROR_DFA_UCOND* = -17
|
||||
ERROR_DFA_UMLIMIT* = -18
|
||||
ERROR_DFA_WSSIZE* = -19
|
||||
ERROR_DFA_RECURSE* = -20
|
||||
ERROR_RECURSIONLIMIT* = -21
|
||||
ERROR_NULLWSLIMIT* = -22 ## No longer actually used
|
||||
ERROR_BADNEWLINE* = -23
|
||||
ERROR_BADOFFSET* = -24
|
||||
ERROR_SHORTUTF8* = -25
|
||||
ERROR_SHORTUTF16* = -25 ## Same for 8/16
|
||||
ERROR_RECURSELOOP* = -26
|
||||
ERROR_JIT_STACKLIMIT* = -27
|
||||
ERROR_BADMODE* = -28
|
||||
ERROR_BADENDIANNESS* = -29
|
||||
ERROR_DFA_BADRESTART* = -30
|
||||
ERROR_JIT_BADOPTION* = -31
|
||||
ERROR_BADLENGTH* = -32
|
||||
ERROR_UNSET* = -33
|
||||
|
||||
## Specific error codes for UTF-8 validity checks
|
||||
const
|
||||
UTF8_ERR0* = 0
|
||||
UTF8_ERR1* = 1
|
||||
UTF8_ERR2* = 2
|
||||
UTF8_ERR3* = 3
|
||||
UTF8_ERR4* = 4
|
||||
UTF8_ERR5* = 5
|
||||
UTF8_ERR6* = 6
|
||||
UTF8_ERR7* = 7
|
||||
UTF8_ERR8* = 8
|
||||
UTF8_ERR9* = 9
|
||||
UTF8_ERR10* = 10
|
||||
UTF8_ERR11* = 11
|
||||
UTF8_ERR12* = 12
|
||||
|
|
@ -165,193 +197,305 @@ const
|
|||
UTF8_ERR19* = 19
|
||||
UTF8_ERR20* = 20
|
||||
UTF8_ERR21* = 21
|
||||
UTF8_ERR22* = 22 # Unused (was non-character)
|
||||
|
||||
# Request types for pcre_fullinfo()
|
||||
|
||||
const
|
||||
INFO_OPTIONS* = 0
|
||||
INFO_SIZE* = 1
|
||||
INFO_CAPTURECOUNT* = 2
|
||||
INFO_BACKREFMAX* = 3
|
||||
INFO_FIRSTBYTE* = 4
|
||||
INFO_FIRSTCHAR* = 4 # For backwards compatibility
|
||||
INFO_FIRSTTABLE* = 5
|
||||
INFO_LASTLITERAL* = 6
|
||||
INFO_NAMEENTRYSIZE* = 7
|
||||
INFO_NAMECOUNT* = 8
|
||||
INFO_NAMETABLE* = 9
|
||||
INFO_STUDYSIZE* = 10
|
||||
INFO_DEFAULT_TABLES* = 11
|
||||
INFO_OKPARTIAL* = 12
|
||||
INFO_JCHANGED* = 13
|
||||
INFO_HASCRORLF* = 14
|
||||
INFO_MINLENGTH* = 15
|
||||
INFO_JIT* = 16
|
||||
INFO_JITSIZE* = 17
|
||||
INFO_MAXLOOKBEHIND* = 18
|
||||
|
||||
# Request types for pcre_config(). Do not re-arrange, in order to remain
|
||||
# compatible.
|
||||
|
||||
const
|
||||
CONFIG_UTF8* = 0
|
||||
CONFIG_NEWLINE* = 1
|
||||
CONFIG_LINK_SIZE* = 2
|
||||
CONFIG_POSIX_MALLOC_THRESHOLD* = 3
|
||||
CONFIG_MATCH_LIMIT* = 4
|
||||
CONFIG_STACKRECURSE* = 5
|
||||
CONFIG_UNICODE_PROPERTIES* = 6
|
||||
CONFIG_MATCH_LIMIT_RECURSION* = 7
|
||||
CONFIG_BSR* = 8
|
||||
CONFIG_JIT* = 9
|
||||
CONFIG_JITTARGET* = 11
|
||||
|
||||
# Request types for pcre_study(). Do not re-arrange, in order to remain
|
||||
# compatible.
|
||||
|
||||
## Specific error codes for UTF-16 validity checks
|
||||
const
|
||||
STUDY_JIT_COMPILE* = 0x00000001
|
||||
STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x00000002
|
||||
STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x00000004
|
||||
UTF16_ERR0* = 0
|
||||
UTF16_ERR1* = 1
|
||||
UTF16_ERR2* = 2
|
||||
UTF16_ERR3* = 3
|
||||
UTF16_ERR4* = 4 # Unused (was non-character)
|
||||
|
||||
# Bit flags for the pcre_extra structure. Do not re-arrange or redefine
|
||||
# these bits, just add new ones on the end, in order to remain compatible.
|
||||
## Specific error codes for UTF-32 validity checks
|
||||
const
|
||||
UTF32_ERR0* = 0
|
||||
UTF32_ERR1* = 1
|
||||
UTF32_ERR2* = 2 # Unused (was non-character)
|
||||
UTF32_ERR3* = 3
|
||||
|
||||
const
|
||||
EXTRA_STUDY_DATA* = 0x00000001
|
||||
EXTRA_MATCH_LIMIT* = 0x00000002
|
||||
EXTRA_CALLOUT_DATA* = 0x00000004
|
||||
EXTRA_TABLES* = 0x00000008
|
||||
EXTRA_MATCH_LIMIT_RECURSION* = 0x00000010
|
||||
EXTRA_MARK* = 0x00000020
|
||||
EXTRA_EXECUTABLE_JIT* = 0x00000040
|
||||
## Request types for pcre_fullinfo()
|
||||
const
|
||||
INFO_OPTIONS* = 0
|
||||
INFO_SIZE* = 1
|
||||
INFO_CAPTURECOUNT* = 2
|
||||
INFO_BACKREFMAX* = 3
|
||||
INFO_FIRSTBYTE* = 4
|
||||
INFO_FIRSTCHAR* = 4 ## For backwards compatibility
|
||||
INFO_FIRSTTABLE* = 5
|
||||
INFO_LASTLITERAL* = 6
|
||||
INFO_NAMEENTRYSIZE* = 7
|
||||
INFO_NAMECOUNT* = 8
|
||||
INFO_NAMETABLE* = 9
|
||||
INFO_STUDYSIZE* = 10
|
||||
INFO_DEFAULT_TABLES* = 11
|
||||
INFO_OKPARTIAL* = 12
|
||||
INFO_JCHANGED* = 13
|
||||
INFO_HASCRORLF* = 14
|
||||
INFO_MINLENGTH* = 15
|
||||
INFO_JIT* = 16
|
||||
INFO_JITSIZE* = 17
|
||||
INFO_MAXLOOKBEHIND* = 18
|
||||
INFO_FIRSTCHARACTER* = 19
|
||||
INFO_FIRSTCHARACTERFLAGS* = 20
|
||||
INFO_REQUIREDCHAR* = 21
|
||||
INFO_REQUIREDCHARFLAGS* = 22
|
||||
INFO_MATCHLIMIT* = 23
|
||||
INFO_RECURSIONLIMIT* = 24
|
||||
INFO_MATCH_EMPTY* = 25
|
||||
|
||||
# Types
|
||||
## Request types for pcre_config(). Do not re-arrange, in order to remain
|
||||
## compatible.
|
||||
const
|
||||
CONFIG_UTF8* = 0
|
||||
CONFIG_NEWLINE* = 1
|
||||
CONFIG_LINK_SIZE* = 2
|
||||
CONFIG_POSIX_MALLOC_THRESHOLD* = 3
|
||||
CONFIG_MATCH_LIMIT* = 4
|
||||
CONFIG_STACKRECURSE* = 5
|
||||
CONFIG_UNICODE_PROPERTIES* = 6
|
||||
CONFIG_MATCH_LIMIT_RECURSION* = 7
|
||||
CONFIG_BSR* = 8
|
||||
CONFIG_JIT* = 9
|
||||
CONFIG_UTF16* = 10
|
||||
CONFIG_JITTARGET* = 11
|
||||
CONFIG_UTF32* = 12
|
||||
CONFIG_PARENS_LIMIT* = 13
|
||||
|
||||
type
|
||||
TPcre*{.pure, final.} = object
|
||||
PPcre* = ptr TPcre
|
||||
Tjit_stack*{.pure, final.} = object
|
||||
Pjit_stack* = ptr Tjit_stack
|
||||
## Request types for pcre_study(). Do not re-arrange, in order to remain
|
||||
## compatible.
|
||||
const
|
||||
STUDY_JIT_COMPILE* = 0x0001
|
||||
STUDY_JIT_PARTIAL_SOFT_COMPILE* = 0x0002
|
||||
STUDY_JIT_PARTIAL_HARD_COMPILE* = 0x0004
|
||||
STUDY_EXTRA_NEEDED* = 0x0008
|
||||
|
||||
# When PCRE is compiled as a C++ library, the subject pointer type can be
|
||||
# replaced with a custom type. For conventional use, the public interface is a
|
||||
# const char *.
|
||||
|
||||
# The structure for passing additional data to pcre_exec(). This is defined in
|
||||
# such as way as to be extensible. Always add new fields at the end, in order to
|
||||
# remain compatible.
|
||||
|
||||
type
|
||||
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()
|
||||
callout_data*: pointer ## Data passed back in callouts
|
||||
tables*: cstring ## Pointer to character tables
|
||||
match_limit_recursion*: int ## Max recursive calls to match()
|
||||
mark*: ptr cstring ## For passing back a mark pointer
|
||||
executable_jit*: pointer ## Contains a pointer to a compiled jit code
|
||||
|
||||
|
||||
# The structure for passing out data via the pcre_callout_function. We use a
|
||||
# structure so that new fields can be added on the end in future versions,
|
||||
# without changing the API of the function, thereby allowing old clients to work
|
||||
# without modification.
|
||||
|
||||
type
|
||||
TCalloutBlock*{.pure, final.} = object
|
||||
version*: cint ## Identifies version of block
|
||||
callout_number*: cint ## Number compiled into pattern
|
||||
offset_vector*: ptr cint ## The offset vector
|
||||
subject*: cstring ## The subject being matched
|
||||
subject_length*: cint ## The length of the subject
|
||||
start_match*: cint ## Offset to start of this match attempt
|
||||
current_position*: cint ## Where we currently are in the subject
|
||||
capture_top*: cint ## Max current capture
|
||||
capture_last*: cint ## Most recently closed capture
|
||||
callout_data*: pointer ## Data passed in with the call
|
||||
pattern_position*: cint ## Offset to next item in the pattern
|
||||
next_item_length*: cint ## Length of next item in the pattern
|
||||
mark*: cstring ## Pointer to current mark or NULL
|
||||
|
||||
# Indirection for store get and free functions. These can be set to
|
||||
#alternative malloc/free functions if required. Special ones are used in the
|
||||
#non-recursive case for "frames". There is also an optional callout function
|
||||
#that is triggered by the (?) regex item. For Virtual Pascal, these definitions
|
||||
#have to take another form.
|
||||
|
||||
# User defined callback which provides a stack just before the match starts.
|
||||
## Bit flags for the pcre[16|32]_extra structure. Do not re-arrange or redefine
|
||||
## these bits, just add new ones on the end, in order to remain compatible.
|
||||
const
|
||||
EXTRA_STUDY_DATA* = 0x0001
|
||||
EXTRA_MATCH_LIMIT* = 0x0002
|
||||
EXTRA_CALLOUT_DATA* = 0x0004
|
||||
EXTRA_TABLES* = 0x0008
|
||||
EXTRA_MATCH_LIMIT_RECURSION* = 0x0010
|
||||
EXTRA_MARK* = 0x0020
|
||||
EXTRA_EXECUTABLE_JIT* = 0x0040
|
||||
|
||||
## Types
|
||||
type
|
||||
TJitCallback* = proc(p: pointer): ptr Tjit_stack{.cdecl.}
|
||||
Pcre* = object
|
||||
Pcre16* = object
|
||||
Pcre32* = object
|
||||
JitStack* = object
|
||||
JitStack16* = object
|
||||
JitStack32* = object
|
||||
|
||||
# Exported PCRE functions
|
||||
|
||||
proc compile*(a2: cstring, a3: cint, a4: ptr cstring, a5: ptr cint,
|
||||
a6: ptr char): ptr TPcre{.cdecl, importc: "pcre_compile",
|
||||
pcreImport.}
|
||||
proc compile2*(a2: cstring, a3: cint, a4: ptr cint, a5: ptr cstring,
|
||||
a6: ptr cint, a7: ptr char): ptr TPcre{.cdecl,
|
||||
importc: "pcre_compile2", pcreImport.}
|
||||
proc config*(a2: cint, a3: pointer): cint{.cdecl, importc: "pcre_config",
|
||||
pcreImport.}
|
||||
proc copy_named_substring*(a2: ptr TPcre, a3: cstring, a4: ptr cint, a5: cint,
|
||||
a6: cstring, a7: cstring, a8: cint): cint{.cdecl,
|
||||
importc: "pcre_copy_named_substring", pcreImport.}
|
||||
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,
|
||||
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,
|
||||
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{.
|
||||
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,
|
||||
importc: "pcre_get_named_substring", pcreImport.}
|
||||
proc get_stringnumber*(a2: ptr TPcre, a3: cstring): cint{.cdecl,
|
||||
importc: "pcre_get_stringnumber", pcreImport.}
|
||||
proc get_stringtable_entries*(a2: ptr TPcre, a3: cstring, a4: cstringArray,
|
||||
a5: cstringArray): cint{.cdecl,
|
||||
importc: "pcre_get_stringtable_entries", pcreImport.}
|
||||
proc get_substring*(a2: cstring, a3: ptr cint, a4: cint, a5: cint,
|
||||
a6: cstringArray): cint{.cdecl,
|
||||
importc: "pcre_get_substring", pcreImport.}
|
||||
proc get_substring_list*(a2: cstring, a3: ptr cint, a4: cint,
|
||||
a5: ptr cstringArray): cint{.cdecl,
|
||||
importc: "pcre_get_substring_list", pcreImport.}
|
||||
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,
|
||||
importc: "pcre_study", pcreImport.}
|
||||
proc version*(): cstring{.cdecl, importc: "pcre_version", pcreImport.}
|
||||
## The structure for passing additional data to pcre_exec(). This is defined in
|
||||
## such as way as to be extensible. Always add new fields at the end, in order
|
||||
## to remain compatible.
|
||||
type
|
||||
ExtraData* = object
|
||||
flags*: clong ## Bits for which fields are set
|
||||
study_data*: pointer ## Opaque data from pcre_study()
|
||||
match_limit*: clong ## Maximum number of calls to match()
|
||||
callout_data*: pointer ## Data passed back in callouts
|
||||
tables*: pointer ## Pointer to character tables
|
||||
match_limit_recursion*: clong ## Max recursive calls to match()
|
||||
mark*: pointer ## For passing back a mark pointer
|
||||
executable_jit*: pointer ## Contains a pointer to a compiled jit code
|
||||
|
||||
## The structure for passing out data via the pcre_callout_function. We use a
|
||||
## structure so that new fields can be added on the end in future versions,
|
||||
## without changing the API of the function, thereby allowing old clients to
|
||||
## work without modification.
|
||||
type
|
||||
CalloutBlock* = object
|
||||
version* : cint ## Identifies version of block
|
||||
# ------------------------ Version 0 -------------------------------
|
||||
callout_number* : cint ## Number compiled into pattern
|
||||
offset_vector* : ptr cint ## The offset vector
|
||||
subject* : cstring ## The subject being matched
|
||||
subject_length* : cint ## The length of the subject
|
||||
start_match* : cint ## Offset to start of this match attempt
|
||||
current_position*: cint ## Where we currently are in the subject
|
||||
capture_top* : cint ## Max current capture
|
||||
capture_last* : cint ## Most recently closed capture
|
||||
callout_data* : pointer ## Data passed in with the call
|
||||
# ------------------- Added for Version 1 --------------------------
|
||||
pattern_position*: cint ## Offset to next item in the pattern
|
||||
next_item_length*: cint ## Length of next item in the pattern
|
||||
# ------------------- Added for Version 2 --------------------------
|
||||
mark* : pointer ## Pointer to current mark or NULL
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
|
||||
## User defined callback which provides a stack just before the match starts.
|
||||
type
|
||||
JitCallback* = proc (a: pointer): ptr JitStack {.cdecl.}
|
||||
|
||||
|
||||
when not defined(usePcreHeader):
|
||||
when hostOS == "windows":
|
||||
const pcreDll = "pcre.dll"
|
||||
elif hostOS == "macosx":
|
||||
const pcreDll = "libpcre(.3|.1|).dylib"
|
||||
else:
|
||||
const pcreDll = "libpcre.so(.3|.1|)"
|
||||
{.push dynlib: pcreDll.}
|
||||
else:
|
||||
{.push header: "<pcre.h>".}
|
||||
|
||||
{.push cdecl, importc: "pcre_$1".}
|
||||
|
||||
# Exported PCRE functions
|
||||
|
||||
proc compile*(pattern: cstring,
|
||||
options: cint,
|
||||
errptr: ptr cstring,
|
||||
erroffset: ptr cint,
|
||||
tableptr: pointer): ptr Pcre
|
||||
|
||||
proc compile2*(pattern: cstring,
|
||||
options: cint,
|
||||
errorcodeptr: ptr cint,
|
||||
errptr: ptr cstring,
|
||||
erroffset: ptr cint,
|
||||
tableptr: pointer): ptr Pcre
|
||||
|
||||
proc config*(what: cint,
|
||||
where: pointer): cint
|
||||
|
||||
proc copy_named_substring*(code: ptr Pcre,
|
||||
subject: cstring,
|
||||
ovector: ptr cint,
|
||||
stringcount: cint,
|
||||
stringname: cstring,
|
||||
buffer: cstring,
|
||||
buffersize: cint): cint
|
||||
|
||||
proc copy_substring*(subject: cstring,
|
||||
ovector: ptr cint,
|
||||
stringcount: cint,
|
||||
stringnumber: cint,
|
||||
buffer: cstring,
|
||||
buffersize: cint): cint
|
||||
|
||||
proc dfa_exec*(code: ptr Pcre,
|
||||
extra: ptr ExtraData,
|
||||
subject: cstring,
|
||||
length: cint,
|
||||
startoffset: cint,
|
||||
options: cint,
|
||||
ovector: ptr cint,
|
||||
ovecsize: cint,
|
||||
workspace: ptr cint,
|
||||
wscount: cint): cint
|
||||
|
||||
proc exec*(code: ptr Pcre,
|
||||
extra: ptr ExtraData,
|
||||
subject: cstring,
|
||||
length: cint,
|
||||
startoffset: cint,
|
||||
options: cint,
|
||||
ovector: ptr cint,
|
||||
ovecsize: cint): cint
|
||||
|
||||
proc jit_exec*(code: ptr Pcre,
|
||||
extra: ptr ExtraData,
|
||||
subject: cstring,
|
||||
length: cint,
|
||||
startoffset: cint,
|
||||
options: cint,
|
||||
ovector: ptr cint,
|
||||
ovecsize: cint,
|
||||
jstack: ptr JitStack): cint
|
||||
|
||||
proc free_substring*(stringptr: cstring)
|
||||
|
||||
proc free_substring_list*(stringptr: cstringArray)
|
||||
|
||||
proc fullinfo*(code: ptr Pcre,
|
||||
extra: ptr ExtraData,
|
||||
what: cint,
|
||||
where: pointer): cint
|
||||
|
||||
proc get_named_substring*(code: ptr Pcre,
|
||||
subject: cstring,
|
||||
ovector: ptr cint,
|
||||
stringcount: cint,
|
||||
stringname: cstring,
|
||||
stringptr: cstringArray): cint
|
||||
|
||||
proc get_stringnumber*(code: ptr Pcre,
|
||||
name: cstring): cint
|
||||
|
||||
proc get_stringtable_entries*(code: ptr Pcre,
|
||||
name: cstring,
|
||||
first: cstringArray,
|
||||
last: cstringArray): cint
|
||||
|
||||
proc get_substring*(subject: cstring,
|
||||
ovector: ptr cint,
|
||||
stringcount: cint,
|
||||
stringnumber: cint,
|
||||
stringptr: cstringArray): cint
|
||||
|
||||
proc get_substring_list*(subject: cstring,
|
||||
ovector: ptr cint,
|
||||
stringcount: cint,
|
||||
listptr: ptr cstringArray): cint
|
||||
|
||||
proc maketables*(): pointer
|
||||
|
||||
proc refcount*(code: ptr Pcre,
|
||||
adjust: cint): cint
|
||||
|
||||
proc study*(code: ptr Pcre,
|
||||
options: cint,
|
||||
errptr: ptr cstring): ptr ExtraData
|
||||
|
||||
proc free_study*(extra: ptr ExtraData)
|
||||
|
||||
proc version*(): cstring
|
||||
|
||||
# Utility functions for byte order swaps.
|
||||
|
||||
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.}
|
||||
proc pattern_to_host_byte_order*(code: ptr Pcre,
|
||||
extra: ptr ExtraData,
|
||||
tables: pointer): cint
|
||||
|
||||
# JIT compiler related functions.
|
||||
|
||||
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: TJitCallback, a4: pointer){.cdecl,
|
||||
importc: "pcre_assign_jit_stack", pcreImport.}
|
||||
proc jit_stack_alloc*(startsize: cint,
|
||||
maxsize: cint): ptr JitStack
|
||||
|
||||
var
|
||||
pcre_free*: proc (p: ptr TPcre) {.cdecl.}
|
||||
proc jit_stack_free*(stack: ptr JitStack)
|
||||
|
||||
proc assign_jit_stack*(extra: ptr ExtraData,
|
||||
callback: JitCallback,
|
||||
data: pointer)
|
||||
|
||||
proc jit_free_unused_memory*()
|
||||
|
||||
|
||||
# There was an odd function with `var cstring` instead of `ptr`
|
||||
proc study*(code: ptr Pcre,
|
||||
options: cint,
|
||||
errptr: var cstring): ptr ExtraData {.deprecated.}
|
||||
|
||||
{.pop.}
|
||||
{.pop.}
|
||||
|
||||
|
||||
{.deprecated: [MAJOR: PCRE_MAJOR, MINOR: PCRE_MINOR,
|
||||
PRERELEASE: PCRE_PRERELEASE, DATE: PCRE_DATE].}
|
||||
|
||||
{.deprecated: [TPcre: Pcre, TJitStack: JitStack].}
|
||||
type
|
||||
PPcre* {.deprecated.} = ptr Pcre
|
||||
PJitStack* {.deprecated.} = ptr JitStack
|
||||
|
||||
{.deprecated: [TExtra: ExtraData].}
|
||||
{.deprecated: [TCalloutBlock: CalloutBlock].}
|
||||
{.deprecated: [TJitCallback: JitCallback].}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue