diff options
-rw-r--r-- | compiler/ccgexprs.nim | 7 | ||||
-rw-r--r-- | compiler/ccgmerge.nim | 2 | ||||
-rw-r--r-- | compiler/cgen.nim | 1 | ||||
-rw-r--r-- | compiler/cgendata.nim | 2 | ||||
-rw-r--r-- | compiler/commands.nim | 2 | ||||
-rw-r--r-- | compiler/extccomp.nim | 2 | ||||
-rw-r--r-- | compiler/options.nim | 22 | ||||
-rw-r--r-- | compiler/pragmas.nim | 1 | ||||
-rw-r--r-- | compiler/semexprs.nim | 3 | ||||
-rw-r--r-- | lib/posix/termios.nim | 271 | ||||
-rw-r--r-- | lib/pure/asyncdispatch.nim | 19 | ||||
-rw-r--r-- | lib/pure/collections/tableimpl.nim | 7 | ||||
-rw-r--r-- | lib/pure/dynlib.nim | 32 | ||||
-rw-r--r-- | lib/pure/httpcore.nim | 4 | ||||
-rw-r--r-- | lib/pure/net.nim | 33 | ||||
-rw-r--r-- | lib/pure/terminal.nim | 48 | ||||
-rw-r--r-- | lib/pure/xmltree.nim | 23 | ||||
-rw-r--r-- | lib/system/gc.nim | 16 | ||||
-rw-r--r-- | lib/upcoming/asyncdispatch.nim | 25 | ||||
-rw-r--r-- | lib/wrappers/openssl.nim | 83 | ||||
-rw-r--r-- | tests/ccgbugs/tmissingderef2.nim | 25 | ||||
-rw-r--r-- | tests/ccgbugs/tobjconstr_regression.nim | 14 | ||||
-rw-r--r-- | tests/cpp/tasync_cpp.nim | 3 | ||||
-rw-r--r-- | tests/stdlib/thttpcore.nim | 28 | ||||
-rw-r--r-- | tests/stdlib/txmltree.nim | 18 | ||||
-rw-r--r-- | web/news/e029_version_0_16_0.rst | 3 |
26 files changed, 433 insertions, 261 deletions
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim index 2761f888b..18b0e5e20 100644 --- a/compiler/ccgexprs.nim +++ b/compiler/ccgexprs.nim @@ -1144,8 +1144,8 @@ proc handleConstExpr(p: BProc, n: PNode, d: var TLoc): bool = result = false proc genObjConstr(p: BProc, e: PNode, d: var TLoc) = - if handleConstExpr(p, e, d): return #echo rendertree e, " ", e.isDeepConstExpr + if handleConstExpr(p, e, d): return var tmp: TLoc var t = e.typ.skipTypes(abstractInst) getTemp(p, t, tmp) @@ -2152,6 +2152,11 @@ proc genNamedConstExpr(p: BProc, n: PNode): Rope = proc genConstSimpleList(p: BProc, n: PNode): Rope = var length = sonsLen(n) result = rope("{") + let t = n.typ.skipTypes(abstractInst) + if n.kind == nkObjConstr and not isObjLackingTypeField(t) and + not p.module.compileToCpp: + addf(result, "{$1}", [genTypeInfo(p.module, t)]) + if n.len > 1: add(result, ",") for i in countup(ord(n.kind == nkObjConstr), length - 2): addf(result, "$1,$n", [genNamedConstExpr(p, n.sons[i])]) if length > ord(n.kind == nkObjConstr): diff --git a/compiler/ccgmerge.nim b/compiler/ccgmerge.nim index 92b6aa9dc..67ffaf8b0 100644 --- a/compiler/ccgmerge.nim +++ b/compiler/ccgmerge.nim @@ -27,8 +27,8 @@ const cfsFieldInfo: "NIM_merge_FIELD_INFO", cfsTypeInfo: "NIM_merge_TYPE_INFO", cfsProcHeaders: "NIM_merge_PROC_HEADERS", - cfsData: "NIM_merge_DATA", cfsVars: "NIM_merge_VARS", + cfsData: "NIM_merge_DATA", cfsProcs: "NIM_merge_PROCS", cfsInitProc: "NIM_merge_INIT_PROC", cfsTypeInit1: "NIM_merge_TYPE_INIT1", diff --git a/compiler/cgen.nim b/compiler/cgen.nim index 6e18c8389..3217b86e4 100644 --- a/compiler/cgen.nim +++ b/compiler/cgen.nim @@ -17,6 +17,7 @@ import lowerings, semparallel from modulegraphs import ModuleGraph +from dynlib import libCandidates import strutils except `%` # collides with ropes.`%` diff --git a/compiler/cgendata.nim b/compiler/cgendata.nim index faeea7afb..def0b4fee 100644 --- a/compiler/cgendata.nim +++ b/compiler/cgendata.nim @@ -27,8 +27,8 @@ type cfsFieldInfo, # section for field information cfsTypeInfo, # section for type information cfsProcHeaders, # section for C procs prototypes - cfsData, # section for C constant data cfsVars, # section for C variable declarations + cfsData, # section for C constant data cfsProcs, # section for C procs that are not inline cfsInitProc, # section for the C init proc cfsTypeInit1, # section 1 for declarations of type information diff --git a/compiler/commands.nim b/compiler/commands.nim index 590c4871d..f85e53511 100644 --- a/compiler/commands.nim +++ b/compiler/commands.nim @@ -226,6 +226,8 @@ proc testCompileOptionArg*(switch, arg: string, info: TLineInfo): bool = of "staticlib": result = contains(gGlobalOptions, optGenStaticLib) and not contains(gGlobalOptions, optGenGuiApp) else: localError(info, errGuiConsoleOrLibExpectedButXFound, arg) + of "dynliboverride": + result = isDynlibOverride(arg) else: invalidCmdLineOption(passCmd1, switch, info) proc testCompileOption*(switch: string, info: TLineInfo): bool = diff --git a/compiler/extccomp.nim b/compiler/extccomp.nim index 6f8b0b197..1f9af95a5 100644 --- a/compiler/extccomp.nim +++ b/compiler/extccomp.nim @@ -34,7 +34,7 @@ type TInfoCCProps* = set[TInfoCCProp] TInfoCC* = tuple[ name: string, # the short name of the compiler - objExt: string, # the compiler's object file extenstion + objExt: string, # the compiler's object file extension optSpeed: string, # the options for optimization for speed optSize: string, # the options for optimization for size compilerExe: string, # the compiler's executable diff --git a/compiler/options.nim b/compiler/options.nim index b04f6a963..50f12d843 100644 --- a/compiler/options.nim +++ b/compiler/options.nim @@ -227,7 +227,16 @@ proc setDefaultLibpath*() = libpath = parentNimLibPath proc canonicalizePath*(path: string): string = - result = path.expandFilename + # on Windows, 'expandFilename' calls getFullPathName which doesn't do + # case corrections, so we have to use this convoluted way of retrieving + # the true filename (see tests/modules and Nimble uses 'import Uri' instead + # of 'import uri'): + when defined(windows): + result = path.expandFilename + for x in walkFiles(result): + return x + else: + result = path.expandFilename proc shortenDir*(dir: string): string = ## returns the interesting part of a dir @@ -372,17 +381,6 @@ proc findModule*(modulename, currentModule: string): string = result = findFile(m) patchModule() -proc libCandidates*(s: string, dest: var seq[string]) = - var le = strutils.find(s, '(') - var ri = strutils.find(s, ')', le+1) - if le >= 0 and ri > le: - var prefix = substr(s, 0, le - 1) - var suffix = substr(s, ri + 1) - for middle in split(substr(s, le + 1, ri - 1), '|'): - libCandidates(prefix & middle & suffix, dest) - else: - add(dest, s) - proc canonDynlibName(s: string): string = let start = if s.startsWith("lib"): 3 else: 0 let ende = strutils.find(s, {'(', ')', '.'}) diff --git a/compiler/pragmas.nim b/compiler/pragmas.nim index e11a8d08b..ffb2aa812 100644 --- a/compiler/pragmas.nim +++ b/compiler/pragmas.nim @@ -490,6 +490,7 @@ proc pragmaLine(c: PContext, n: PNode) = elif y.kind != nkIntLit: localError(n.info, errIntLiteralExpected) else: + # XXX this produces weird paths which are not properly resolved: n.info.fileIndex = msgs.fileInfoIdx(x.strVal) n.info.line = int16(y.intVal) else: diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim index 8aaf4f9d8..723045fb0 100644 --- a/compiler/semexprs.nim +++ b/compiler/semexprs.nim @@ -1274,7 +1274,8 @@ proc propertyWriteAccess(c: PContext, n, nOrig, a: PNode): PNode = # this is ugly. XXX Semantic checking should use the ``nfSem`` flag for # nodes? let aOrig = nOrig[0] - result = newNode(nkCall, n.info, sons = @[setterId, a[0], semExpr(c, n[1])]) + result = newNode(nkCall, n.info, sons = @[setterId, a[0], + semExprWithType(c, n[1])]) result.flags.incl nfDotSetter let orig = newNode(nkCall, n.info, sons = @[setterId, aOrig[0], nOrig[1]]) result = semOverloadedCallAnalyseEffects(c, result, orig, {}) diff --git a/lib/posix/termios.nim b/lib/posix/termios.nim index 1fbccba9c..af62bdb3d 100644 --- a/lib/posix/termios.nim +++ b/lib/posix/termios.nim @@ -16,7 +16,7 @@ type {.deprecated: [Tcflag: Cflag].} const - NCCS* = 32 + NCCS* = when defined(macosx): 20 else: 32 type Termios* {.importc: "struct termios", header: "<termios.h>".} = object @@ -28,174 +28,136 @@ type # cc characters -const - VINTR* = 0 - VQUIT* = 1 - VERASE* = 2 - VKILL* = 3 - VEOF* = 4 - VTIME* = 5 - VMIN* = 6 - VSWTC* = 7 - VSTART* = 8 - VSTOP* = 9 - VSUSP* = 10 - VEOL* = 11 - VREPRINT* = 12 - VDISCARD* = 13 - VWERASE* = 14 - VLNEXT* = 15 - VEOL2* = 16 +var + VINTR* {.importc, header: "<termios.h>".}: cint + VQUIT* {.importc, header: "<termios.h>".}: cint + VERASE* {.importc, header: "<termios.h>".}: cint + VKILL* {.importc, header: "<termios.h>".}: cint + VEOF* {.importc, header: "<termios.h>".}: cint + VTIME* {.importc, header: "<termios.h>".}: cint + VMIN* {.importc, header: "<termios.h>".}: cint + VSTART* {.importc, header: "<termios.h>".}: cint + VSTOP* {.importc, header: "<termios.h>".}: cint + VSUSP* {.importc, header: "<termios.h>".}: cint + VEOL* {.importc, header: "<termios.h>".}: cint # iflag bits -const - IGNBRK* = 1 - BRKINT* = 2 - IGNPAR* = 4 - PARMRK* = 10 - INPCK* = 20 - ISTRIP* = 40 - INLCR* = 100 - IGNCR* = 200 - ICRNL* = 400 - IUCLC* = 1000 - IXON* = 2000 - IXANY* = 4000 - IXOFF* = 10000 - IMAXBEL* = 20000 - IUTF8* = 40000 +var + IGNBRK* {.importc, header: "<termios.h>".}: Cflag + BRKINT* {.importc, header: "<termios.h>".}: Cflag + IGNPAR* {.importc, header: "<termios.h>".}: Cflag + PARMRK* {.importc, header: "<termios.h>".}: Cflag + INPCK* {.importc, header: "<termios.h>".}: Cflag + ISTRIP* {.importc, header: "<termios.h>".}: Cflag + INLCR* {.importc, header: "<termios.h>".}: Cflag + IGNCR* {.importc, header: "<termios.h>".}: Cflag + ICRNL* {.importc, header: "<termios.h>".}: Cflag + IUCLC* {.importc, header: "<termios.h>".}: Cflag + IXON* {.importc, header: "<termios.h>".}: Cflag + IXANY* {.importc, header: "<termios.h>".}: Cflag + IXOFF* {.importc, header: "<termios.h>".}: Cflag # oflag bits -const - OPOST* = 1 - OLCUC* = 2 - ONLCR* = 4 - OCRNL* = 10 - ONOCR* = 20 - ONLRET* = 40 - OFILL* = 100 - OFDEL* = 200 - NLDLY* = 400 - NL0* = 0 - NL1* = 400 - CRDLY* = 3000 - CR0* = 0 - CR1* = 1000 - CR2* = 2000 - CR3* = 3000 - TABDLY* = 14000 - TAB0* = 0 - TAB1* = 4000 - TAB2* = 10000 - TAB3* = 14000 - BSDLY* = 20000 - BS0* = 0 - BS1* = 20000 - FFDLY* = 0o000000100000 - FF0* = 0 - FF1* = 0o000000100000 - VTDLY* = 40000 - VT0* = 0 - VT1* = 40000 - XTABS* = 14000 +var + OPOST* {.importc, header: "<termios.h>".}: Cflag + ONLCR* {.importc, header: "<termios.h>".}: Cflag + OCRNL* {.importc, header: "<termios.h>".}: Cflag + ONOCR* {.importc, header: "<termios.h>".}: Cflag + ONLRET* {.importc, header: "<termios.h>".}: Cflag + OFILL* {.importc, header: "<termios.h>".}: Cflag + OFDEL* {.importc, header: "<termios.h>".}: Cflag + NLDLY* {.importc, header: "<termios.h>".}: Cflag + NL0* {.importc, header: "<termios.h>".}: Cflag + NL1* {.importc, header: "<termios.h>".}: Cflag + CRDLY* {.importc, header: "<termios.h>".}: Cflag + CR0* {.importc, header: "<termios.h>".}: Cflag + CR1* {.importc, header: "<termios.h>".}: Cflag + CR2* {.importc, header: "<termios.h>".}: Cflag + CR3* {.importc, header: "<termios.h>".}: Cflag + TABDLY* {.importc, header: "<termios.h>".}: Cflag + TAB0* {.importc, header: "<termios.h>".}: Cflag + TAB1* {.importc, header: "<termios.h>".}: Cflag + TAB2* {.importc, header: "<termios.h>".}: Cflag + TAB3* {.importc, header: "<termios.h>".}: Cflag + BSDLY* {.importc, header: "<termios.h>".}: Cflag + BS0* {.importc, header: "<termios.h>".}: Cflag + BS1* {.importc, header: "<termios.h>".}: Cflag + FFDLY* {.importc, header: "<termios.h>".}: Cflag + FF0* {.importc, header: "<termios.h>".}: Cflag + FF1* {.importc, header: "<termios.h>".}: Cflag + VTDLY* {.importc, header: "<termios.h>".}: Cflag + VT0* {.importc, header: "<termios.h>".}: Cflag + VT1* {.importc, header: "<termios.h>".}: Cflag # cflag bit meaning -const - CBAUD* = 10017 - B0* = 0 - B50* = 1 - B75* = 2 - B110* = 3 - B134* = 4 - B150* = 5 - B200* = 6 - B300* = 7 - B600* = 10 - B1200* = 11 - B1800* = 12 - B2400* = 13 - B4800* = 14 - B9600* = 15 - B19200* = 16 - B38400* = 17 - EXTA* = B19200 - EXTB* = B38400 - CSIZE* = 60 - CS5* = 0 - CS6* = 20 - CS7* = 40 - CS8* = 60 - CSTOPB* = 100 - CREAD* = 200 - PARENB* = 400 - PARODD* = 1000 - HUPCL* = 2000 - CLOCAL* = 4000 - CBAUDEX* = 10000 - B57600* = 10001 - B115200* = 10002 - B230400* = 10003 - B460800* = 10004 - B500000* = 10005 - B576000* = 10006 - B921600* = 10007 - B1000000* = 10010 - B1152000* = 10011 - B1500000* = 10012 - B2000000* = 10013 - B2500000* = 10014 - B3000000* = 10015 - B3500000* = 10016 - B4000000* = 10017 - MAX_BAUD* = B4000000 - CIBAUD* = 2003600000 - CMSPAR* = 0o010000000000 - CRTSCTS* = 0o020000000000 +var + B0* {.importc, header: "<termios.h>".}: Speed + B50* {.importc, header: "<termios.h>".}: Speed + B75* {.importc, header: "<termios.h>".}: Speed + B110* {.importc, header: "<termios.h>".}: Speed + B134* {.importc, header: "<termios.h>".}: Speed + B150* {.importc, header: "<termios.h>".}: Speed + B200* {.importc, header: "<termios.h>".}: Speed + B300* {.importc, header: "<termios.h>".}: Speed + B600* {.importc, header: "<termios.h>".}: Speed + B1200* {.importc, header: "<termios.h>".}: Speed + B1800* {.importc, header: "<termios.h>".}: Speed + B2400* {.importc, header: "<termios.h>".}: Speed + B4800* {.importc, header: "<termios.h>".}: Speed + B9600* {.importc, header: "<termios.h>".}: Speed + B19200* {.importc, header: "<termios.h>".}: Speed + B38400* {.importc, header: "<termios.h>".}: Speed + EXTA* {.importc, header: "<termios.h>".}: Speed + EXTB* {.importc, header: "<termios.h>".}: Speed + CSIZE* {.importc, header: "<termios.h>".}: Cflag + CS5* {.importc, header: "<termios.h>".}: Cflag + CS6* {.importc, header: "<termios.h>".}: Cflag + CS7* {.importc, header: "<termios.h>".}: Cflag + CS8* {.importc, header: "<termios.h>".}: Cflag + CSTOPB* {.importc, header: "<termios.h>".}: Cflag + CREAD* {.importc, header: "<termios.h>".}: Cflag + PARENB* {.importc, header: "<termios.h>".}: Cflag + PARODD* {.importc, header: "<termios.h>".}: Cflag + HUPCL* {.importc, header: "<termios.h>".}: Cflag + CLOCAL* {.importc, header: "<termios.h>".}: Cflag # lflag bits -const - ISIG* = 1 - ICANON* = 2 - XCASE* = 4 - ECHO* = 10 - ECHOE* = 20 - ECHOK* = 40 - ECHONL* = 100 - NOFLSH* = 200 - TOSTOP* = 400 - ECHOCTL* = 1000 - ECHOPRT* = 2000 - ECHOKE* = 4000 - FLUSHO* = 10000 - PENDIN* = 40000 - IEXTEN* = 0o000000100000 - EXTPROC* = 0o000000200000 +var + ISIG* {.importc, header: "<termios.h>".}: Cflag + ICANON* {.importc, header: "<termios.h>".}: Cflag + ECHO* {.importc, header: "<termios.h>".}: Cflag + ECHOE* {.importc, header: "<termios.h>".}: Cflag + ECHOK* {.importc, header: "<termios.h>".}: Cflag + ECHONL* {.importc, header: "<termios.h>".}: Cflag + NOFLSH* {.importc, header: "<termios.h>".}: Cflag + TOSTOP* {.importc, header: "<termios.h>".}: Cflag + IEXTEN* {.importc, header: "<termios.h>".}: Cflag # tcflow() and TCXONC use these -const - TCOOFF* = 0 - TCOON* = 1 - TCIOFF* = 2 - TCION* = 3 +var + TCOOFF* {.importc, header: "<termios.h>".}: cint + TCOON* {.importc, header: "<termios.h>".}: cint + TCIOFF* {.importc, header: "<termios.h>".}: cint + TCION* {.importc, header: "<termios.h>".}: cint # tcflush() and TCFLSH use these -const - TCIFLUSH* = 0 - TCOFLUSH* = 1 - TCIOFLUSH* = 2 +var + TCIFLUSH* {.importc, header: "<termios.h>".}: cint + TCOFLUSH* {.importc, header: "<termios.h>".}: cint + TCIOFLUSH* {.importc, header: "<termios.h>".}: cint # tcsetattr uses these -const - TCSANOW* = 0 - TCSADRAIN* = 1 - TCSAFLUSH* = 2 +var + TCSANOW* {.importc, header: "<termios.h>".}: cint + TCSADRAIN* {.importc, header: "<termios.h>".}: cint + TCSAFLUSH* {.importc, header: "<termios.h>".}: cint # 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. @@ -221,10 +183,6 @@ 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. -proc cfSetSpeed*(termios: ptr Termios; speed: Speed): cint {. - importc: "cfsetspeed", header: "<termios.h>".} -# 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. @@ -234,10 +192,6 @@ proc tcSetAttr*(fd: cint; optional_actions: cint; termios: ptr Termios): cint {. importc: "tcsetattr", header: "<termios.h>".} # Set *TERMIOS_P to indicate raw mode. -proc cfMakeRaw*(termios: ptr Termios) {.importc: "cfmakeraw", - header: "<termios.h>".} -# Send zero bits on FD. - proc tcSendBreak*(fd: cint; duration: cint): cint {.importc: "tcsendbreak", header: "<termios.h>".} # Wait for pending output to be written on FD. @@ -258,13 +212,10 @@ proc tcFlow*(fd: cint; action: cint): cint {.importc: "tcflow", header: "<termios.h>".} # Get process group ID for session leader for controlling terminal FD. -proc tcGetSid*(fd: cint): Pid {.importc: "tcgetsid", header: "<termios.h>".} - # Window size ioctl. Should work on on any Unix that xterm has been ported to. var TIOCGWINSZ*{.importc, header: "<sys/ioctl.h>".}: culong -type IOctl_WinSize* {.importc: "struct winsize", header: "<sys/ioctl.h>", - final, pure.} = object +type IOctl_WinSize* = object ws_row*, ws_col*, ws_xpixel*, ws_ypixel*: cushort proc ioctl*(fd: cint, request: culong, reply: ptr IOctl_WinSize): int {. diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 01088c2e7..1367bc411 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -893,9 +893,11 @@ when defined(windows) or defined(nimdoc): deallocShared(cast[pointer](pcd)) raiseOSError(osLastError()) else: - # we ref pcd.ovl one more time, because it will be unrefed in - # poll() + # we incref `pcd.ovl` and `protect` callback one more time, + # because it will be unrefed and disposed in `poll()` after + # callback finishes. GC_ref(pcd.ovl) + pcd.ovl.data.cell = system.protect(rawEnv(pcd.ovl.data.cb)) ) # We need to protect our callback environment value, so GC will not free it # accidentally. @@ -956,17 +958,8 @@ when defined(windows) or defined(nimdoc): initAll() else: import selectors - when defined(windows): - import winlean - const - EINTR = WSAEINPROGRESS - EINPROGRESS = WSAEINPROGRESS - EWOULDBLOCK = WSAEWOULDBLOCK - EAGAIN = EINPROGRESS - MSG_NOSIGNAL = 0 - else: - from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, - MSG_NOSIGNAL + from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, + MSG_NOSIGNAL type AsyncFD* = distinct cint diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim index 674fdddd2..5e871f08b 100644 --- a/lib/pure/collections/tableimpl.nim +++ b/lib/pure/collections/tableimpl.nim @@ -116,16 +116,15 @@ template hasKeyOrPutImpl(enlarge) {.dirty.} = maybeRehashPutImpl(enlarge) else: result = true -proc default[T](t: typedesc[T]): T {.inline.} = discard +template default[T](t: typedesc[T]): T = + var v: T + v template delImpl() {.dirty.} = var hc: Hash var i = rawGet(t, key, hc) let msk = maxHash(t) if i >= 0: - t.data[i].hcode = 0 - t.data[i].key = default(type(t.data[i].key)) - t.data[i].val = default(type(t.data[i].val)) dec(t.counter) block outer: while true: # KnuthV3 Algo6.4R adapted for i=i+1 instead of i=i-1 diff --git a/lib/pure/dynlib.nim b/lib/pure/dynlib.nim index 906a9d23e..fda41dadb 100644 --- a/lib/pure/dynlib.nim +++ b/lib/pure/dynlib.nim @@ -11,20 +11,22 @@ ## libraries. On POSIX this uses the ``dlsym`` mechanism, on ## Windows ``LoadLibrary``. +import strutils + type LibHandle* = pointer ## a handle to a dynamically loaded library {.deprecated: [TLibHandle: LibHandle].} -proc loadLib*(path: string, global_symbols=false): LibHandle +proc loadLib*(path: string, global_symbols=false): LibHandle {.gcsafe.} ## loads a library from `path`. Returns nil if the library could not ## be loaded. -proc loadLib*(): LibHandle +proc loadLib*(): LibHandle {.gcsafe.} ## gets the handle from the current executable. Returns nil if the ## library could not be loaded. -proc unloadLib*(lib: LibHandle) +proc unloadLib*(lib: LibHandle) {.gcsafe.} ## unloads the library `lib` proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} = @@ -34,7 +36,7 @@ proc raiseInvalidLibrary*(name: cstring) {.noinline, noreturn.} = e.msg = "could not find symbol: " & $name raise e -proc symAddr*(lib: LibHandle, name: cstring): pointer +proc symAddr*(lib: LibHandle, name: cstring): pointer {.gcsafe.} ## retrieves the address of a procedure/variable from `lib`. Returns nil ## if the symbol could not be found. @@ -44,6 +46,28 @@ proc checkedSymAddr*(lib: LibHandle, name: cstring): pointer = result = symAddr(lib, name) if result == nil: raiseInvalidLibrary(name) +proc libCandidates*(s: string, dest: var seq[string]) = + ## given a library name pattern `s` write possible library names to `dest`. + var le = strutils.find(s, '(') + var ri = strutils.find(s, ')', le+1) + if le >= 0 and ri > le: + var prefix = substr(s, 0, le - 1) + var suffix = substr(s, ri + 1) + for middle in split(substr(s, le + 1, ri - 1), '|'): + libCandidates(prefix & middle & suffix, dest) + else: + add(dest, s) + +proc loadLibPattern*(pattern: string, global_symbols=false): LibHandle = + ## loads a library with name matching `pattern`, similar to what `dlimport` + ## pragma does. Returns nil if the library could not be loaded. + ## Warning: this proc uses the GC and so cannot be used to load the GC. + var candidates = newSeq[string]() + libCandidates(pattern, candidates) + for c in candidates: + result = loadLib(c, global_symbols) + if not result.isNil: break + when defined(posix): # # ========================================================================= diff --git a/lib/pure/httpcore.nim b/lib/pure/httpcore.nim index 8147f1c50..48001ccaa 100644 --- a/lib/pure/httpcore.nim +++ b/lib/pure/httpcore.nim @@ -154,6 +154,10 @@ proc add*(headers: HttpHeaders, key, value: string) = else: headers.table[key.toLowerAscii].add(value) +proc del*(headers: HttpHeaders, key: string) = + ## Delete the header entries associated with ``key`` + headers.table.del(key.toLowerAscii) + iterator pairs*(headers: HttpHeaders): tuple[key, value: string] = ## Yields each key, value pair. for k, v in headers.table: diff --git a/lib/pure/net.nim b/lib/pure/net.nim index 863a8a6f4..5e10f2291 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -90,8 +90,8 @@ when defineSsl: SslContext* = ref object context*: SslCtx - extraInternalIndex: int referencedData: HashSet[int] + extraInternal: SslContextExtraInternal SslAcceptResult* = enum AcceptNoClient = 0, AcceptNoHandshake, AcceptSuccess @@ -103,6 +103,10 @@ when defineSsl: SslServerGetPskFunc* = proc(identity: string): string + SslContextExtraInternal = ref object of RootRef + serverGetPskFunc: SslServerGetPskFunc + clientGetPskFunc: SslClientGetPskFunc + {.deprecated: [ESSL: SSLError, TSSLCVerifyMode: SSLCVerifyMode, TSSLProtVersion: SSLProtVersion, PSSLContext: SSLContext, TSSLAcceptResult: SSLAcceptResult].} @@ -240,11 +244,6 @@ when defineSsl: ErrLoadBioStrings() OpenSSL_add_all_algorithms() - type - SslContextExtraInternal = ref object of RootRef - serverGetPskFunc: SslServerGetPskFunc - clientGetPskFunc: SslClientGetPskFunc - proc raiseSSLError*(s = "") = ## Raises a new SSL error. if s != "": @@ -257,12 +256,6 @@ when defineSsl: var errStr = ErrErrorString(err, nil) raise newException(SSLError, $errStr) - proc getExtraDataIndex*(ctx: SSLContext): int = - ## Retrieves unique index for storing extra data in SSLContext. - result = SSL_CTX_get_ex_new_index(0, nil, nil, nil, nil).int - if result < 0: - raiseSSLError() - proc getExtraData*(ctx: SSLContext, index: int): RootRef = ## Retrieves arbitrary data stored inside SSLContext. if index notin ctx.referencedData: @@ -347,15 +340,11 @@ when defineSsl: discard newCTX.SSLCTXSetMode(SSL_MODE_AUTO_RETRY) newCTX.loadCertificates(certFile, keyFile) - result = SSLContext(context: newCTX, extraInternalIndex: 0, - referencedData: initSet[int]()) - result.extraInternalIndex = getExtraDataIndex(result) - - let extraInternal = new(SslContextExtraInternal) - result.setExtraData(result.extraInternalIndex, extraInternal) + result = SSLContext(context: newCTX, referencedData: initSet[int](), + extraInternal: new(SslContextExtraInternal)) proc getExtraInternal(ctx: SSLContext): SslContextExtraInternal = - return SslContextExtraInternal(ctx.getExtraData(ctx.extraInternalIndex)) + return ctx.extraInternal proc destroyContext*(ctx: SSLContext) = ## Free memory referenced by SSLContext. @@ -379,7 +368,7 @@ when defineSsl: proc pskClientCallback(ssl: SslPtr; hint: cstring; identity: cstring; max_identity_len: cuint; psk: ptr cuchar; max_psk_len: cuint): cuint {.cdecl.} = - let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX, extraInternalIndex: 0) + let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX) let hintString = if hint == nil: nil else: $hint let (identityString, pskString) = (ctx.clientGetPskFunc)(hintString) if psk.len.cuint > max_psk_len: @@ -398,8 +387,6 @@ when defineSsl: ## ## Only used in PSK ciphersuites. ctx.getExtraInternal().clientGetPskFunc = fun - assert ctx.extraInternalIndex == 0, - "The pskClientCallback assumes the extraInternalIndex is 0" ctx.context.SSL_CTX_set_psk_client_callback( if fun == nil: nil else: pskClientCallback) @@ -407,7 +394,7 @@ when defineSsl: return ctx.getExtraInternal().serverGetPskFunc proc pskServerCallback(ssl: SslCtx; identity: cstring; psk: ptr cuchar; max_psk_len: cint): cuint {.cdecl.} = - let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX, extraInternalIndex: 0) + let ctx = SSLContext(context: ssl.SSL_get_SSL_CTX) let pskString = (ctx.serverGetPskFunc)($identity) if psk.len.cint > max_psk_len: return 0 diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim index 16cf91d40..7a8113b2a 100644 --- a/lib/pure/terminal.nim +++ b/lib/pure/terminal.nim @@ -83,6 +83,13 @@ when defined(windows): return int(csbi.srWindow.Right - csbi.srWindow.Left + 1) return 0 + proc terminalHeightIoctl*(handles: openArray[Handle]): int = + var csbi: CONSOLE_SCREEN_BUFFER_INFO + for h in handles: + if getConsoleScreenBufferInfo(h, addr csbi) != 0: + return int(csbi.srWindow.Bottom - csbi.srWindow.Top + 1) + return 0 + proc terminalWidth*(): int = var w: int = 0 w = terminalWidthIoctl([ getStdHandle(STD_INPUT_HANDLE), @@ -91,6 +98,14 @@ when defined(windows): if w > 0: return w return 80 + proc terminalHeight*(): int = + var h: int = 0 + h = terminalHeightIoctl([ getStdHandle(STD_INPUT_HANDLE), + getStdHandle(STD_OUTPUT_HANDLE), + getStdHandle(STD_ERROR_HANDLE) ] ) + if h > 0: return h + return 0 + proc setConsoleCursorPosition(hConsoleOutput: HANDLE, dwCursorPosition: COORD): WINBOOL{. stdcall, dynlib: "kernel32", importc: "SetConsoleCursorPosition".} @@ -177,7 +192,17 @@ else: return int(win.ws_col) return 0 + proc terminalHeightIoctl*(fds: openArray[int]): int = + ## Returns terminal height from first fd that supports the ioctl. + + var win: IOctl_WinSize + for fd in fds: + if ioctl(cint(fd), TIOCGWINSZ, addr win) != -1: + return int(win.ws_row) + return 0 + var L_ctermid{.importc, header: "<stdio.h>".}: cint + proc terminalWidth*(): int = ## Returns some reasonable terminal width from either standard file ## descriptors, controlling terminal, environment variables or tradition. @@ -195,6 +220,29 @@ else: return w return 80 #Finally default to venerable value + proc terminalHeight*(): int = + ## Returns some reasonable terminal height from either standard file + ## descriptors, controlling terminal, environment variables or tradition. + ## Zero is returned if the height could not be determined. + + var h = terminalHeightIoctl([0, 1, 2]) # Try standard file descriptors + if h > 0: return h + var cterm = newString(L_ctermid) # Try controlling tty + var fd = open(ctermid(cstring(cterm)), O_RDONLY) + if fd != -1: + h = terminalHeightIoctl([ int(fd) ]) + discard close(fd) + if h > 0: return h + var s = getEnv("LINES") # Try standard env var + if len(s) > 0 and parseInt(string(s), h) > 0 and h > 0: + return h + return 0 # Could not determine height + +proc terminalSize*(): tuple[w, h: int] = + ## Returns the terminal width and height as a tuple. Internally calls + ## `terminalWidth` and `terminalHeight`, so the same assumptions apply. + result = (terminalWidth(), terminalHeight()) + when defined(windows): proc setCursorVisibility(f: File, visible: bool) = var ccsi: CONSOLE_CURSOR_INFO diff --git a/lib/pure/xmltree.nim b/lib/pure/xmltree.nim index 3c6eb14e3..7cfb62157 100644 --- a/lib/pure/xmltree.nim +++ b/lib/pure/xmltree.nim @@ -91,13 +91,24 @@ proc rawTag*(n: XmlNode): string {.inline.} = shallowCopy(result, n.fTag) proc innerText*(n: XmlNode): string = - ## gets the inner text of `n`. `n` has to be an ``xnElement`` node. Only - ## ``xnText`` and ``xnEntity`` nodes are considered part of `n`'s inner text, - ## other child nodes are silently ignored. + ## gets the inner text of `n`: + ## + ## - If `n` is `xnText` or `xnEntity`, returns its content. + ## - If `n` is `xnElement`, runs recursively on each child node and + ## concatenates the results. + ## - Otherwise returns an empty string. + proc worker(res: var string, n: XmlNode) = + case n.k + of xnText, xnEntity: + res.add(n.fText) + of xnElement: + for sub in n.s: + worker(res, sub) + else: + discard + result = "" - assert n.k == xnElement - for i in 0 .. n.s.len-1: - if n.s[i].k in {xnText, xnEntity}: result.add(n.s[i].fText) + worker(result, n) proc tag*(n: XmlNode): string {.inline.} = ## gets the tag name of `n`. `n` has to be an ``xnElement`` node. diff --git a/lib/system/gc.nim b/lib/system/gc.nim index 7fb4c7ac7..6c418cc3a 100644 --- a/lib/system/gc.nim +++ b/lib/system/gc.nim @@ -153,13 +153,19 @@ template setColor(c, col) = proc writeCell(msg: cstring, c: PCell) = var kind = -1 - if c.typ != nil: kind = ord(c.typ.kind) + var typName: cstring = "nil" + if c.typ != nil: + kind = ord(c.typ.kind) + when defined(nimTypeNames): + if not c.typ.name.isNil: + typName = c.typ.name + when leakDetector: - c_fprintf(stdout, "[GC] %s: %p %d rc=%ld from %s(%ld)\n", - msg, c, kind, c.refcount shr rcShift, c.filename, c.line) + c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld from %s(%ld)\n", + msg, c, kind, typName, c.refcount shr rcShift, c.filename, c.line) else: - c_fprintf(stdout, "[GC] %s: %p %d rc=%ld; color=%ld\n", - msg, c, kind, c.refcount shr rcShift, c.color) + c_fprintf(stdout, "[GC] %s: %p %d %s rc=%ld; color=%ld\n", + msg, c, kind, typName, c.refcount shr rcShift, c.color) template gcTrace(cell, state: expr): stmt {.immediate.} = when traceGC: traceCell(cell, state) diff --git a/lib/upcoming/asyncdispatch.nim b/lib/upcoming/asyncdispatch.nim index 0b5ff89ba..9a35cf3c8 100644 --- a/lib/upcoming/asyncdispatch.nim +++ b/lib/upcoming/asyncdispatch.nim @@ -878,9 +878,11 @@ when defined(windows) or defined(nimdoc): deallocShared(cast[pointer](pcd)) raiseOSError(osLastError()) else: - # we ref pcd.ovl one more time, because it will be unrefed in - # poll() + # we incref `pcd.ovl` and `protect` callback one more time, + # because it will be unrefed and disposed in `poll()` after + # callback finishes. GC_ref(pcd.ovl) + pcd.ovl.data.cell = system.protect(rawEnv(pcd.ovl.data.cb)) ) # We need to protect our callback environment value, so GC will not free it # accidentally. @@ -988,6 +990,9 @@ when defined(windows) or defined(nimdoc): deallocShared(cast[pointer](pcd)) p.handles.excl(fd) else: + # if callback returned `false`, then it wants to be called again, so + # we need to ref and protect `pcd.ovl` again, because it will be + # unrefed and disposed in `poll()`. GC_ref(pcd.ovl) pcd.ovl.data.cell = system.protect(rawEnv(pcd.ovl.data.cb)) @@ -1073,6 +1078,9 @@ when defined(windows) or defined(nimdoc): if ev.hWaiter != 0: unregister(ev) deallocShared(cast[pointer](pcd)) else: + # if callback returned `false`, then it wants to be called again, so + # we need to ref and protect `pcd.ovl` again, because it will be + # unrefed and disposed in `poll()`. GC_ref(pcd.ovl) pcd.ovl.data.cell = system.protect(rawEnv(pcd.ovl.data.cb)) @@ -1082,17 +1090,8 @@ when defined(windows) or defined(nimdoc): initAll() else: import ioselectors - when defined(windows): - import winlean - const - EINTR = WSAEINPROGRESS - EINPROGRESS = WSAEINPROGRESS - EWOULDBLOCK = WSAEWOULDBLOCK - EAGAIN = EINPROGRESS - MSG_NOSIGNAL = 0 - else: - from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, - MSG_NOSIGNAL + from posix import EINTR, EAGAIN, EINPROGRESS, EWOULDBLOCK, MSG_PEEK, + MSG_NOSIGNAL const supportedPlatform = defined(linux) or defined(freebsd) or defined(netbsd) or defined(openbsd) or diff --git a/lib/wrappers/openssl.nim b/lib/wrappers/openssl.nim index 241ad17ae..5521476d9 100644 --- a/lib/wrappers/openssl.nim +++ b/lib/wrappers/openssl.nim @@ -37,6 +37,8 @@ else: DLLUtilName = "libcrypto.so" & versions from posix import SocketHandle +import dynlib + type SslStruct {.final, pure.} = object SslPtr* = ptr SslStruct @@ -185,16 +187,74 @@ const BIO_C_DO_STATE_MACHINE = 101 BIO_C_GET_SSL = 110 -proc SSL_library_init*(): cInt{.cdecl, dynlib: DLLSSLName, importc, discardable.} -proc SSL_load_error_strings*(){.cdecl, dynlib: DLLSSLName, importc.} -proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.} - -proc SSLv23_client_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} -proc SSLv23_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} -proc SSLv2_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} -proc SSLv3_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} proc TLSv1_method*(): PSSL_METHOD{.cdecl, dynlib: DLLSSLName, importc.} +when compileOption("dynlibOverride", "ssl"): + proc SSL_library_init*(): cint {.cdecl, dynlib: DLLSSLName, importc, discardable.} + proc SSL_load_error_strings*() {.cdecl, dynlib: DLLSSLName, importc.} + proc SSLv23_client_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} + + proc SSLv23_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} + proc SSLv2_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} + proc SSLv3_method*(): PSSL_METHOD {.cdecl, dynlib: DLLSSLName, importc.} + + template OpenSSL_add_all_algorithms*() = discard +else: + # Here we're trying to stay compatible with openssl 1.0.* and 1.1.*. Some + # symbols are loaded dynamically and we don't use them if not found. + proc thisModule(): LibHandle {.inline.} = + var thisMod {.global.}: LibHandle + if thisMod.isNil: thisMod = loadLib() + result = thisMod + + proc sslModule(): LibHandle {.inline.} = + var sslMod {.global.}: LibHandle + if sslMod.isNil: sslMod = loadLibPattern(DLLSSLName) + result = sslMod + + proc sslSym(name: string): pointer = + var dl = thisModule() + if not dl.isNil: + result = symAddr(dl, name) + if result.isNil: + dl = sslModule() + if not dl.isNil: + result = symAddr(dl, name) + + proc SSL_library_init*(): cint {.discardable.} = + let theProc = cast[proc(): cint {.cdecl.}](sslSym("SSL_library_init")) + if not theProc.isNil: result = theProc() + + proc SSL_load_error_strings*() = + let theProc = cast[proc() {.cdecl.}](sslSym("SSL_load_error_strings")) + if not theProc.isNil: theProc() + + proc SSLv23_client_method*(): PSSL_METHOD = + let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv23_client_method")) + if not theProc.isNil: result = theProc() + else: result = TLSv1_method() + + proc SSLv23_method*(): PSSL_METHOD = + let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv23_method")) + if not theProc.isNil: result = theProc() + else: result = TLSv1_method() + + proc SSLv2_method*(): PSSL_METHOD = + let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv2_method")) + if not theProc.isNil: result = theProc() + else: result = TLSv1_method() + + proc SSLv3_method*(): PSSL_METHOD = + let theProc = cast[proc(): PSSL_METHOD {.cdecl, gcsafe.}](sslSym("SSLv3_method")) + if not theProc.isNil: result = theProc() + else: result = TLSv1_method() + + proc OpenSSL_add_all_algorithms*() = + let theProc = cast[proc() {.cdecl.}](sslSym("OPENSSL_add_all_algorithms_conf")) + if not theProc.isNil: theProc() + +proc ERR_load_BIO_strings*(){.cdecl, dynlib: DLLUtilName, importc.} + proc SSL_new*(context: SslCtx): SslPtr{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_free*(ssl: SslPtr){.cdecl, dynlib: DLLSSLName, importc.} proc SSL_get_SSL_CTX*(ssl: SslPtr): SslCtx {.cdecl, dynlib: DLLSSLName, importc.} @@ -233,6 +293,8 @@ proc SSL_get_error*(s: SslPtr, ret_code: cInt): cInt{.cdecl, dynlib: DLLSSLName, proc SSL_accept*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.} proc SSL_pending*(ssl: SslPtr): cInt{.cdecl, dynlib: DLLSSLName, importc.} +proc BIO_new_mem_buf*(data: pointer, len: cint): BIO{.cdecl, + dynlib: DLLSSLName, importc.} proc BIO_new_ssl_connect*(ctx: SslCtx): BIO{.cdecl, dynlib: DLLSSLName, importc.} proc BIO_ctrl*(bio: BIO, cmd: cint, larg: int, arg: cstring): int{.cdecl, @@ -261,11 +323,6 @@ proc ERR_error_string*(e: cInt, buf: cstring): cstring{.cdecl, proc ERR_get_error*(): cInt{.cdecl, dynlib: DLLUtilName, importc.} proc ERR_peek_last_error*(): cInt{.cdecl, dynlib: DLLUtilName, importc.} -when defined(android): - template OpenSSL_add_all_algorithms*() = discard -else: - proc OpenSSL_add_all_algorithms*(){.cdecl, dynlib: DLLUtilName, importc: "OPENSSL_add_all_algorithms_conf".} - proc OPENSSL_config*(configName: cstring){.cdecl, dynlib: DLLSSLName, importc.} when not useWinVersion and not defined(macosx) and not defined(android): diff --git a/tests/ccgbugs/tmissingderef2.nim b/tests/ccgbugs/tmissingderef2.nim new file mode 100644 index 000000000..59cd24dd1 --- /dev/null +++ b/tests/ccgbugs/tmissingderef2.nim @@ -0,0 +1,25 @@ +discard """ + output: "c" +""" + +# bug #5079 + +import tables, strutils + +type Test = ref object + s: string + +proc `test=`(t: Test, s: string) = + t.s = s + +var t = Test() + +#t.test = spaces(2) # -- works + +var a = newTable[string, string]() +a["b"] = "c" + +#t.s = a["b"] # -- works +#t.test a["b"] # -- works +t.test = a["b"] # -- prints "out of memory" and quits +echo t.s diff --git a/tests/ccgbugs/tobjconstr_regression.nim b/tests/ccgbugs/tobjconstr_regression.nim new file mode 100644 index 000000000..87d037894 --- /dev/null +++ b/tests/ccgbugs/tobjconstr_regression.nim @@ -0,0 +1,14 @@ +discard """ + output: "@[(username: user, role: admin, description: desc, email_addr: email), (username: user, role: admin, description: desc, email_addr: email)]" +""" + +type + User = object of RootObj + username, role, description, email_addr: string + +# bug 5055 +let us4 = @[ + User(username:"user", role:"admin", description:"desc", email_addr:"email"), + User(username:"user", role:"admin", description:"desc", email_addr:"email"), +] +echo us4 diff --git a/tests/cpp/tasync_cpp.nim b/tests/cpp/tasync_cpp.nim index 792f2938b..ec78ae26c 100644 --- a/tests/cpp/tasync_cpp.nim +++ b/tests/cpp/tasync_cpp.nim @@ -8,4 +8,7 @@ discard """ import jester import asyncdispatch, asyncnet +# bug #5081 +#import nre + echo "hello" diff --git a/tests/stdlib/thttpcore.nim b/tests/stdlib/thttpcore.nim new file mode 100644 index 000000000..9f99df93a --- /dev/null +++ b/tests/stdlib/thttpcore.nim @@ -0,0 +1,28 @@ + +import unittest + +import httpcore + +suite "httpcore": + + test "HttpCode": + assert $Http418 == "418 I'm a teapot" + assert Http418.is4xx() == true + assert Http418.is2xx() == false + + test "headers": + var h = newHttpHeaders() + assert h.len == 0 + h.add("Cookie", "foo") + assert h.len == 1 + assert h.hasKey("cooKIE") + assert h["Cookie"] == "foo" + assert h["cookie"] == "foo" + h["cookie"] = @["bar", "x"] + assert h["Cookie"] == "bar" + assert h["Cookie", 1] == "x" + assert h["Cookie"].contains("BaR") == true + assert h["Cookie"].contains("X") == true + assert "baR" in h["cookiE"] + h.del("coOKie") + assert h.len == 0 diff --git a/tests/stdlib/txmltree.nim b/tests/stdlib/txmltree.nim index bfe2dc94a..a849859e3 100644 --- a/tests/stdlib/txmltree.nim +++ b/tests/stdlib/txmltree.nim @@ -1,6 +1,11 @@ discard """ file: "txmltree.nim" - output: "true" + output: '''true +true +true +true +true +''' """ import xmltree, strtabs @@ -9,5 +14,14 @@ var x = <>a(href="nim.de", newText("www.nim-test.de")) echo($x == "<a href=\"nim.de\">www.nim-test.de</a>") +echo(newText("foo").innerText == "foo") +echo(newEntity("bar").innerText == "bar") +echo(newComment("baz").innerText == "") - +let y = newXmlTree("x", [ + newText("foo"), + newXmlTree("y", [ + newText("bar") + ]) +]) +echo(y.innerText == "foobar") diff --git a/web/news/e029_version_0_16_0.rst b/web/news/e029_version_0_16_0.rst index d56c19e38..2a0c81b46 100644 --- a/web/news/e029_version_0_16_0.rst +++ b/web/news/e029_version_0_16_0.rst @@ -39,7 +39,8 @@ Library Additions ``deques`` provides a superset of ``queues`` API with clear naming. ``queues`` module is now deprecated and will be removed in the future. -- Added ``hideCursor`` and ``showCursor`` to the ``terminal`` +- Added ``hideCursor``, ``showCursor``, ``terminalWidth``, + ``terminalWidthIoctl`` and ``terminalSize`` to the ``terminal`` `(doc) <http://nim-lang.org/docs/terminal.html>`_ module. |