Deprecate TaintedString (#15423)

Co-authored-by: Timothee Cour <timothee.cour2@gmail.com>
Co-authored-by: Dominik Picheta <dominikpicheta@googlemail.com>
This commit is contained in:
Juan Carlos 2021-01-15 23:56:38 -03:00 • committed by GitHub
commit 78a99587a4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 184 additions and 229 deletions

View file

@ -122,6 +122,8 @@ with other backends. see #9125. Use `-d:nimLegacyJsRound` for previous behavior.
- Added `--declaredlocs` to show symbol declaration location in messages. - Added `--declaredlocs` to show symbol declaration location in messages.
- Deprecated `TaintedString` and `--taintmode`.
- Source+Edit links now appear on top of every docgen'd page when - Source+Edit links now appear on top of every docgen'd page when
`nim doc --git.url:url ...` is given. `nim doc --git.url:url ...` is given.

View file

@ -312,7 +312,7 @@ proc testCompileOption*(conf: ConfigRef; switch: string, info: TLineInfo): bool
of "symbolfiles": result = conf.symbolFiles != disabledSf of "symbolfiles": result = conf.symbolFiles != disabledSf
of "genscript": result = contains(conf.globalOptions, optGenScript) of "genscript": result = contains(conf.globalOptions, optGenScript)
of "threads": result = contains(conf.globalOptions, optThreads) of "threads": result = contains(conf.globalOptions, optThreads)
of "taintmode": result = contains(conf.globalOptions, optTaintMode) of "taintmode": result = false # pending https://github.com/nim-lang/Nim/issues/16731
of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation) of "tlsemulation": result = contains(conf.globalOptions, optTlsEmulation)
of "implicitstatic": result = contains(conf.options, optImplicitStatic) of "implicitstatic": result = contains(conf.options, optImplicitStatic)
of "patterns", "trmacros": result = contains(conf.options, optTrMacros) of "patterns", "trmacros": result = contains(conf.options, optTrMacros)
@ -670,7 +670,7 @@ proc processSwitch*(switch, arg: string, pass: TCmdLinePass, info: TLineInfo;
processOnOffSwitchG(conf, {optThreads}, arg, pass, info) processOnOffSwitchG(conf, {optThreads}, arg, pass, info)
#if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe) #if optThreads in conf.globalOptions: conf.setNote(warnGcUnsafe)
of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info) of "tlsemulation": processOnOffSwitchG(conf, {optTlsEmulation}, arg, pass, info)
of "taintmode": processOnOffSwitchG(conf, {optTaintMode}, arg, pass, info) of "taintmode": discard # pending https://github.com/nim-lang/Nim/issues/16731
of "implicitstatic": of "implicitstatic":
processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info) processOnOffSwitch(conf, {optImplicitStatic}, arg, pass, info)
of "patterns", "trmacros": of "patterns", "trmacros":

View file

@ -68,7 +68,6 @@ type # please make sure we have under 32 options
optThreads, # support for multi-threading optThreads, # support for multi-threading
optStdout, # output to stdout optStdout, # output to stdout
optThreadAnalysis, # thread analysis pass optThreadAnalysis, # thread analysis pass
optTaintMode, # taint mode turned on
optTlsEmulation, # thread var emulation turned on optTlsEmulation, # thread var emulation turned on
optGenIndex # generate index file for documentation; optGenIndex # generate index file for documentation;
optEmbedOrigSrc # embed the original source in the generated code optEmbedOrigSrc # embed the original source in the generated code

View file

@ -93,7 +93,6 @@ Advanced options:
in the generated output in the generated output
--threadanalysis:on|off turn thread analysis on|off --threadanalysis:on|off turn thread analysis on|off
--tlsEmulation:on|off turn thread local storage emulation on|off --tlsEmulation:on|off turn thread local storage emulation on|off
--taintMode:on|off turn taint mode on|off
--implicitStatic:on|off turn implicit compile time evaluation on|off --implicitStatic:on|off turn implicit compile time evaluation on|off
--trmacros:on|off turn term rewriting macros on|off --trmacros:on|off turn term rewriting macros on|off
--multimethods:on|off turn multi-methods on|off --multimethods:on|off turn multi-methods on|off

View file

@ -329,7 +329,7 @@ skLet
let let
text = "some text" text = "some text"
--> col 2: $MODULE.text --> col 2: $MODULE.text
col 3: TaintedString col 3: string
col 7: "" col 7: ""

View file

@ -1718,28 +1718,6 @@ e.g. with given example ``echo("ab")`` will be rewritten just once:
``noRewrite`` pragma can be useful to control term-rewriting macros recursion. ``noRewrite`` pragma can be useful to control term-rewriting macros recursion.
Taint mode
==========
The Nim compiler and most parts of the standard library support
a taint mode. Input strings are declared with the `TaintedString`:idx:
string type declared in the ``system`` module.
If the taint mode is turned on (via the ``--taintMode:on`` command line
option) it is a distinct string type which helps to detect input
validation errors:
.. code-block:: nim
echo "your name: "
var name: TaintedString = stdin.readline
# it is safe here to output the name without any input validation, so
# we simply convert `name` to string to make the compiler happy:
echo "hi, ", name.string
If the taint mode is turned off, ``TaintedString`` is simply an alias for
``string``.
Aliasing restrictions in parameter passing Aliasing restrictions in parameter passing
========================================== ==========================================

View file

@ -37,7 +37,7 @@ type
pos: int pos: int
remainingShortOptions: string remainingShortOptions: string
kind*: CmdLineKind ## the detected command line token kind*: CmdLineKind ## the detected command line token
key*, val*: TaintedString ## key and value pair; ``key`` is the option key*, val*: string ## key and value pair; ``key`` is the option
## or the argument, ``value`` is not "" if ## or the argument, ``value`` is not "" if
## the option was given a value ## the option was given a value
@ -80,7 +80,7 @@ proc nextOption(p: var OptParser, token: string, allowEmpty: bool) =
proc next(p: var OptParser) = proc next(p: var OptParser) =
if p.remainingShortOptions.len != 0: if p.remainingShortOptions.len != 0:
p.kind = cmdShortOption p.kind = cmdShortOption
p.key = TaintedString(p.remainingShortOptions[0..0]) p.key = p.remainingShortOptions[0..0]
p.val = "" p.val = ""
p.remainingShortOptions = p.remainingShortOptions[1..p.remainingShortOptions.len-1] p.remainingShortOptions = p.remainingShortOptions[1..p.remainingShortOptions.len-1]
return return
@ -103,13 +103,13 @@ proc next(p: var OptParser) =
p.key = token p.key = token
p.val = "" p.val = ""
proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo2$1".} = proc cmdLineRest*(p: OptParser): string {.rtl, extern: "npo2$1".} =
## Returns the part of command line string that has not been parsed yet, ## Returns the part of command line string that has not been parsed yet,
## properly quoted. ## properly quoted.
return p.cmd[p.pos..p.cmd.len-1].quoteShellCommand return p.cmd[p.pos..p.cmd.len-1].quoteShellCommand
type type
GetoptResult* = tuple[kind: CmdLineKind, key, val: TaintedString] GetoptResult* = tuple[kind: CmdLineKind, key, val: string]
iterator getopt*(p: var OptParser): GetoptResult = iterator getopt*(p: var OptParser): GetoptResult =
## This is an convenience iterator for iterating over the given OptParser object. ## This is an convenience iterator for iterating over the given OptParser object.

View file

@ -22,13 +22,13 @@
## echo userResponse ## echo userResponse
when defined(Windows): when defined(Windows):
proc readLineFromStdin*(prompt: string): TaintedString {. proc readLineFromStdin*(prompt: string): string {.
tags: [ReadIOEffect, WriteIOEffect].} = tags: [ReadIOEffect, WriteIOEffect].} =
## Reads a line from stdin. ## Reads a line from stdin.
stdout.write(prompt) stdout.write(prompt)
result = readLine(stdin) result = readLine(stdin)
proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. proc readLineFromStdin*(prompt: string, line: var string): bool {.
tags: [ReadIOEffect, WriteIOEffect].} = tags: [ReadIOEffect, WriteIOEffect].} =
## Reads a `line` from stdin. `line` must not be ## Reads a `line` from stdin. `line` must not be
## ``nil``! May throw an IO exception. ## ``nil``! May throw an IO exception.
@ -40,35 +40,35 @@ when defined(Windows):
result = readLine(stdin, line) result = readLine(stdin, line)
elif defined(genode): elif defined(genode):
proc readLineFromStdin*(prompt: string): TaintedString {. proc readLineFromStdin*(prompt: string): string {.
tags: [ReadIOEffect, WriteIOEffect].} = tags: [ReadIOEffect, WriteIOEffect].} =
stdin.readLine() stdin.readLine()
proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. proc readLineFromStdin*(prompt: string, line: var string): bool {.
tags: [ReadIOEffect, WriteIOEffect].} = tags: [ReadIOEffect, WriteIOEffect].} =
stdin.readLine(line) stdin.readLine(line)
else: else:
import linenoise import linenoise
proc readLineFromStdin*(prompt: string): TaintedString {. proc readLineFromStdin*(prompt: string): string {.
tags: [ReadIOEffect, WriteIOEffect].} = tags: [ReadIOEffect, WriteIOEffect].} =
var buffer = linenoise.readLine(prompt) var buffer = linenoise.readLine(prompt)
if isNil(buffer): if isNil(buffer):
raise newException(IOError, "Linenoise returned nil") raise newException(IOError, "Linenoise returned nil")
result = TaintedString($buffer) result = $buffer
if result.string.len > 0: if result.len > 0:
historyAdd(buffer) historyAdd(buffer)
linenoise.free(buffer) linenoise.free(buffer)
proc readLineFromStdin*(prompt: string, line: var TaintedString): bool {. proc readLineFromStdin*(prompt: string, line: var string): bool {.
tags: [ReadIOEffect, WriteIOEffect].} = tags: [ReadIOEffect, WriteIOEffect].} =
var buffer = linenoise.readLine(prompt) var buffer = linenoise.readLine(prompt)
if isNil(buffer): if isNil(buffer):
line.string.setLen(0) line.setLen(0)
return false return false
line = TaintedString($buffer) line = $buffer
if line.string.len > 0: if line.len > 0:
historyAdd(buffer) historyAdd(buffer)
linenoise.free(buffer) linenoise.free(buffer)
result = true result = true

View file

@ -134,9 +134,9 @@ type
const multiLineLimit = 10000 const multiLineLimit = 10000
proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = proc expectReply(ftp: AsyncFtpClient): Future[string] {.async.} =
var line = await ftp.csock.recvLine() var line = await ftp.csock.recvLine()
result = TaintedString(line) result = line
var count = 0 var count = 0
while line.len > 3 and line[3] == '-': while line.len > 3 and line[3] == '-':
## Multi-line reply. ## Multi-line reply.
@ -146,7 +146,7 @@ proc expectReply(ftp: AsyncFtpClient): Future[TaintedString] {.async.} =
if count >= multiLineLimit: if count >= multiLineLimit:
raise newException(ReplyError, "Reached maximum multi-line reply count.") raise newException(ReplyError, "Reached maximum multi-line reply count.")
proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} = proc send*(ftp: AsyncFtpClient, m: string): Future[string] {.async.} =
## Send a message to the server, and wait for a primary reply. ## Send a message to the server, and wait for a primary reply.
## ``\c\L`` is added for you. ## ``\c\L`` is added for you.
## ##
@ -158,9 +158,9 @@ proc send*(ftp: AsyncFtpClient, m: string): Future[TaintedString] {.async.} =
await ftp.csock.send(m & "\c\L") await ftp.csock.send(m & "\c\L")
return await ftp.expectReply() return await ftp.expectReply()
proc assertReply(received: TaintedString, expected: varargs[string]) = proc assertReply(received: string, expected: varargs[string]) =
for i in items(expected): for i in items(expected):
if received.string.startsWith(i): return if received.startsWith(i): return
raise newException(ReplyError, raise newException(ReplyError,
"Expected reply '$1' got: $2" % "Expected reply '$1' got: $2" %
[expected.join("' or '"), received.string]) [expected.join("' or '"), received.string])
@ -169,7 +169,7 @@ proc pasv(ftp: AsyncFtpClient) {.async.} =
## Negotiate a data connection. ## Negotiate a data connection.
ftp.dsock = newAsyncSocket() ftp.dsock = newAsyncSocket()
var pasvMsg = (await ftp.send("PASV")).string.strip.TaintedString var pasvMsg = (await ftp.send("PASV")).strip
assertReply(pasvMsg, "227") assertReply(pasvMsg, "227")
var betweenParens = captureBetween(pasvMsg.string, '(', ')') var betweenParens = captureBetween(pasvMsg.string, '(', ')')
var nums = betweenParens.split(',') var nums = betweenParens.split(',')
@ -201,11 +201,11 @@ proc connect*(ftp: AsyncFtpClient) {.async.} =
if ftp.pass != "": if ftp.pass != "":
assertReply(await(ftp.send("PASS " & ftp.pass)), "230") assertReply(await(ftp.send("PASS " & ftp.pass)), "230")
proc pwd*(ftp: AsyncFtpClient): Future[TaintedString] {.async.} = proc pwd*(ftp: AsyncFtpClient): Future[string] {.async.} =
## Returns the current working directory. ## Returns the current working directory.
let wd = await ftp.send("PWD") let wd = await ftp.send("PWD")
assertReply wd, "257" assertReply wd, "257"
return wd.string.captureBetween('"').TaintedString # " return wd.captureBetween('"') # "
proc cd*(ftp: AsyncFtpClient, dir: string) {.async.} = proc cd*(ftp: AsyncFtpClient, dir: string) {.async.} =
## Changes the current directory on the remote FTP server to ``dir``. ## Changes the current directory on the remote FTP server to ``dir``.
@ -253,7 +253,7 @@ proc createDir*(ftp: AsyncFtpClient, dir: string, recursive = false){.async.} =
if not recursive: if not recursive:
assertReply(await(ftp.send("MKD " & dir.normalizePathSep)), "257") assertReply(await(ftp.send("MKD " & dir.normalizePathSep)), "257")
else: else:
var reply = TaintedString"" var reply = ""
var previousDirs = "" var previousDirs = ""
for p in split(dir, {os.DirSep, os.AltSep}): for p in split(dir, {os.DirSep, os.AltSep}):
if p != "": if p != "":

View file

@ -81,14 +81,14 @@ proc getEncodedData(allowedMethods: set[RequestMethod]): string =
if methodNone notin allowedMethods: if methodNone notin allowedMethods:
cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'") cgiError("'REQUEST_METHOD' must be 'POST' or 'GET'")
iterator decodeData*(data: string): tuple[key, value: TaintedString] = iterator decodeData*(data: string): tuple[key, value: string] =
## Reads and decodes CGI data and yields the (name, value) pairs the ## Reads and decodes CGI data and yields the (name, value) pairs the
## data consists of. ## data consists of.
for (key, value) in uri.decodeQuery(data): for (key, value) in uri.decodeQuery(data):
yield (key, value) yield (key, value)
iterator decodeData*(allowedMethods: set[RequestMethod] = iterator decodeData*(allowedMethods: set[RequestMethod] =
{methodNone, methodPost, methodGet}): tuple[key, value: TaintedString] = {methodNone, methodPost, methodGet}): tuple[key, value: string] =
## Reads and decodes CGI data and yields the (name, value) pairs the ## Reads and decodes CGI data and yields the (name, value) pairs the
## data consists of. If the client does not use a method listed in the ## data consists of. If the client does not use a method listed in the
## `allowedMethods` set, a `CgiError` exception is raised. ## `allowedMethods` set, a `CgiError` exception is raised.
@ -301,10 +301,10 @@ proc setCookie*(name, value: string) =
var var
gcookies {.threadvar.}: StringTableRef gcookies {.threadvar.}: StringTableRef
proc getCookie*(name: string): TaintedString = proc getCookie*(name: string): string =
## Gets a cookie. If no cookie of `name` exists, "" is returned. ## Gets a cookie. If no cookie of `name` exists, "" is returned.
if gcookies == nil: gcookies = parseCookies(getHttpCookie()) if gcookies == nil: gcookies = parseCookies(getHttpCookie())
result = TaintedString(gcookies.getOrDefault(name)) result = gcookies.getOrDefault(name)
proc existsCookie*(name: string): bool = proc existsCookie*(name: string): bool =
## Checks if a cookie of `name` exists. ## Checks if a cookie of `name` exists.

View file

@ -4,7 +4,7 @@ when not declared(os) and not declared(ospaths):
{.error: "This is an include file for os.nim!".} {.error: "This is an include file for os.nim!".}
when defined(nodejs): when defined(nodejs):
proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} = proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} =
var ret: cstring var ret: cstring
let key2 = key.cstring let key2 = key.cstring
{.emit: "`ret` = process.env[`key2`];".} {.emit: "`ret` = process.env[`key2`];".}
@ -25,7 +25,7 @@ when defined(nodejs):
var key2 = key.cstring var key2 = key.cstring
{.emit: "delete process.env[`key2`];".} {.emit: "delete process.env[`key2`];".}
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} =
var num: int var num: int
var keys: RootObj var keys: RootObj
{.emit: "`keys` = Object.keys(process.env); `num` = `keys`.length;".} {.emit: "`keys` = Object.keys(process.env); `num` = `keys`.length;".}
@ -144,7 +144,7 @@ else:
if startsWith(environment[i], temp): return i if startsWith(environment[i], temp): return i
return -1 return -1
proc getEnv*(key: string, default = ""): TaintedString {.tags: [ReadEnvEffect].} = proc getEnv*(key: string, default = ""): string {.tags: [ReadEnvEffect].} =
## Returns the value of the `environment variable`:idx: named `key`. ## Returns the value of the `environment variable`:idx: named `key`.
## ##
## If the variable does not exist, `""` is returned. To distinguish ## If the variable does not exist, `""` is returned. To distinguish
@ -165,11 +165,11 @@ else:
else: else:
var i = findEnvVar(key) var i = findEnvVar(key)
if i >= 0: if i >= 0:
return TaintedString(substr(environment[i], find(environment[i], '=')+1)) return substr(environment[i], find(environment[i], '=')+1)
else: else:
var env = c_getenv(key) var env = c_getenv(key)
if env == nil: return TaintedString(default) if env == nil: return default
result = TaintedString($env) result = $env
proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} = proc existsEnv*(key: string): bool {.tags: [ReadEnvEffect].} =
## Checks whether the environment variable named `key` exists. ## Checks whether the environment variable named `key` exists.
@ -248,7 +248,7 @@ else:
raiseOSError(osLastError()) raiseOSError(osLastError())
environment.delete(indx) environment.delete(indx)
iterator envPairs*(): tuple[key, value: TaintedString] {.tags: [ReadEnvEffect].} = iterator envPairs*(): tuple[key, value: string] {.tags: [ReadEnvEffect].} =
## Iterate over all `environments variables`:idx:. ## Iterate over all `environments variables`:idx:.
## ##
## In the first component of the tuple is the name of the current variable stored, ## In the first component of the tuple is the name of the current variable stored,
@ -262,5 +262,5 @@ else:
getEnvVarsC() getEnvVarsC()
for i in 0..high(environment): for i in 0..high(environment):
var p = find(environment[i], '=') var p = find(environment[i], '=')
yield (TaintedString(substr(environment[i], 0, p-1)), yield (substr(environment[i], 0, p-1),
TaintedString(substr(environment[i], p+1))) substr(environment[i], p+1))

View file

@ -428,17 +428,17 @@ iterator memSlices*(mfile: MemFile, delim = '\l', eat = '\r'): MemSlice {.inline
ms.data = cast[pointer](cast[int](ending) +% 1) # skip delim ms.data = cast[pointer](cast[int](ending) +% 1) # skip delim
remaining = mfile.size - (ms.data -! mfile.mem) remaining = mfile.size - (ms.data -! mfile.mem)
iterator lines*(mfile: MemFile, buf: var TaintedString, delim = '\l', iterator lines*(mfile: MemFile, buf: var string, delim = '\l',
eat = '\r'): TaintedString {.inline.} = eat = '\r'): string {.inline.} =
## Replace contents of passed buffer with each new line, like ## Replace contents of passed buffer with each new line, like
## `readLine(File) <io.html#readLine,File,TaintedString>`_. ## `readLine(File) <io.html#readLine,File,string>`_.
## `delim`, `eat`, and delimiting logic is exactly as for `memSlices ## `delim`, `eat`, and delimiting logic is exactly as for `memSlices
## <#memSlices.i,MemFile,char,char>`_, but Nim strings are returned. ## <#memSlices.i,MemFile,char,char>`_, but Nim strings are returned.
## ##
## Example: ## Example:
## ##
## .. code-block:: nim ## .. code-block:: nim
## var buffer: TaintedString = "" ## var buffer: string = ""
## for line in lines(memfiles.open("foo"), buffer): ## for line in lines(memfiles.open("foo"), buffer):
## echo line ## echo line
@ -448,7 +448,7 @@ iterator lines*(mfile: MemFile, buf: var TaintedString, delim = '\l',
copyMem(addr string(buf)[0], ms.data, ms.size) copyMem(addr string(buf)[0], ms.data, ms.size)
yield buf yield buf
iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): TaintedString {.inline.} = iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): string {.inline.} =
## Return each line in a file as a Nim string, like ## Return each line in a file as a Nim string, like
## `lines(File) <io.html#lines.i,File>`_. ## `lines(File) <io.html#lines.i,File>`_.
## `delim`, `eat`, and delimiting logic is exactly as for `memSlices ## `delim`, `eat`, and delimiting logic is exactly as for `memSlices
@ -460,7 +460,7 @@ iterator lines*(mfile: MemFile, delim = '\l', eat = '\r'): TaintedString {.inlin
## for line in lines(memfiles.open("foo")): ## for line in lines(memfiles.open("foo")):
## echo line ## echo line
var buf = TaintedString(newStringOfCap(80)) var buf = newStringOfCap(80)
for line in lines(mfile, buf, delim, eat): for line in lines(mfile, buf, delim, eat):
yield buf yield buf

View file

@ -840,7 +840,7 @@ when defineSsl:
if sidCtx.len > 32: if sidCtx.len > 32:
raiseSSLError("sessionIdContext must be shorter than 32 characters") raiseSSLError("sessionIdContext must be shorter than 32 characters")
SSL_CTX_set_session_id_context(ctx.context, sidCtx, sidCtx.len) SSL_CTX_set_session_id_context(ctx.context, sidCtx, sidCtx.len)
proc getSocketError*(socket: Socket): OSErrorCode = proc getSocketError*(socket: Socket): OSErrorCode =
## Checks ``osLastError`` for a valid error. If it has been reset it uses ## Checks ``osLastError`` for a valid error. If it has been reset it uses
## the last error stored in the socket object. ## the last error stored in the socket object.
@ -1490,7 +1490,7 @@ proc peekChar(socket: Socket, c: var char): int {.tags: [ReadIOEffect].} =
return return
result = recv(socket.fd, addr(c), 1, MSG_PEEK) result = recv(socket.fd, addr(c), 1, MSG_PEEK)
proc readLine*(socket: Socket, line: var TaintedString, timeout = -1, proc readLine*(socket: Socket, line: var string, timeout = -1,
flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {. flags = {SocketFlag.SafeDisconn}, maxLength = MaxLineLength) {.
tags: [ReadIOEffect, TimeEffect].} = tags: [ReadIOEffect, TimeEffect].} =
## Reads a line of data from ``socket``. ## Reads a line of data from ``socket``.
@ -1548,7 +1548,7 @@ proc readLine*(socket: Socket, line: var TaintedString, timeout = -1,
proc recvLine*(socket: Socket, timeout = -1, proc recvLine*(socket: Socket, timeout = -1,
flags = {SocketFlag.SafeDisconn}, flags = {SocketFlag.SafeDisconn},
maxLength = MaxLineLength): TaintedString = maxLength = MaxLineLength): string =
## Reads a line of data from ``socket``. ## Reads a line of data from ``socket``.
## ##
## If a full line is read ``\r\L`` is not ## If a full line is read ``\r\L`` is not
@ -1566,7 +1566,7 @@ proc recvLine*(socket: Socket, timeout = -1,
## that can be read. The result is truncated after that. ## that can be read. The result is truncated after that.
## ##
## **Warning**: Only the ``SafeDisconn`` flag is currently supported. ## **Warning**: Only the ``SafeDisconn`` flag is currently supported.
result = "".TaintedString result = ""
readLine(socket, result, timeout, flags, maxLength) readLine(socket, result, timeout, flags, maxLength)
proc recvFrom*(socket: Socket, data: var string, length: int, proc recvFrom*(socket: Socket, data: var string, length: int,

View file

@ -2670,7 +2670,7 @@ when defined(nimdoc):
## else: ## else:
## # Do something else! ## # Do something else!
proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = proc paramStr*(i: int): string {.tags: [ReadIOEffect].} =
## Returns the `i`-th `command line argument`:idx: given to the application. ## Returns the `i`-th `command line argument`:idx: given to the application.
## ##
## `i` should be in the range `1..paramCount()`, the `IndexDefect` ## `i` should be in the range `1..paramCount()`, the `IndexDefect`
@ -2704,7 +2704,7 @@ when defined(nimdoc):
elif defined(nimscript): discard elif defined(nimscript): discard
elif defined(nintendoswitch) or weirdTarget: elif defined(nintendoswitch) or weirdTarget:
proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = proc paramStr*(i: int): string {.tags: [ReadIOEffect].} =
raise newException(OSError, "paramStr is not implemented on Nintendo Switch") raise newException(OSError, "paramStr is not implemented on Nintendo Switch")
proc paramCount*(): int {.tags: [ReadIOEffect].} = proc paramCount*(): int {.tags: [ReadIOEffect].} =
@ -2727,17 +2727,17 @@ elif defined(windows):
ownParsedArgv = true ownParsedArgv = true
result = ownArgv.len-1 result = ownArgv.len-1
proc paramStr*(i: int): TaintedString {.rtl, extern: "nos$1", proc paramStr*(i: int): string {.rtl, extern: "nos$1",
tags: [ReadIOEffect].} = tags: [ReadIOEffect].} =
# Docstring in nimdoc block. # Docstring in nimdoc block.
if not ownParsedArgv: if not ownParsedArgv:
ownArgv = parseCmdLine($getCommandLine()) ownArgv = parseCmdLine($getCommandLine())
ownParsedArgv = true ownParsedArgv = true
if i < ownArgv.len and i >= 0: return TaintedString(ownArgv[i]) if i < ownArgv.len and i >= 0: return ownArgv[i]
raise newException(IndexDefect, formatErrorIndexBound(i, ownArgv.len-1)) raise newException(IndexDefect, formatErrorIndexBound(i, ownArgv.len-1))
elif defined(genode): elif defined(genode):
proc paramStr*(i: int): TaintedString = proc paramStr*(i: int): string =
raise newException(OSError, "paramStr is not implemented on Genode") raise newException(OSError, "paramStr is not implemented on Genode")
proc paramCount*(): int = proc paramCount*(): int =
@ -2750,9 +2750,9 @@ elif not defined(createNimRtl) and
cmdCount {.importc: "cmdCount".}: cint cmdCount {.importc: "cmdCount".}: cint
cmdLine {.importc: "cmdLine".}: cstringArray cmdLine {.importc: "cmdLine".}: cstringArray
proc paramStr*(i: int): TaintedString {.tags: [ReadIOEffect].} = proc paramStr*(i: int): string {.tags: [ReadIOEffect].} =
# Docstring in nimdoc block. # Docstring in nimdoc block.
if i < cmdCount and i >= 0: return TaintedString($cmdLine[i]) if i < cmdCount and i >= 0: return $cmdLine[i]
raise newException(IndexDefect, formatErrorIndexBound(i, cmdCount-1)) raise newException(IndexDefect, formatErrorIndexBound(i, cmdCount-1))
proc paramCount*(): int {.tags: [ReadIOEffect].} = proc paramCount*(): int {.tags: [ReadIOEffect].} =
@ -2760,7 +2760,7 @@ elif not defined(createNimRtl) and
result = cmdCount-1 result = cmdCount-1
when declared(paramCount) or defined(nimdoc): when declared(paramCount) or defined(nimdoc):
proc commandLineParams*(): seq[TaintedString] = proc commandLineParams*(): seq[string] =
## Convenience proc which returns the command line parameters. ## Convenience proc which returns the command line parameters.
## ##
## This returns **only** the parameters. If you want to get the application ## This returns **only** the parameters. If you want to get the application
@ -2789,7 +2789,7 @@ when declared(paramCount) or defined(nimdoc):
for i in 1..paramCount(): for i in 1..paramCount():
result.add(paramStr(i)) result.add(paramStr(i))
else: else:
proc commandLineParams*(): seq[TaintedString] {.error: proc commandLineParams*(): seq[string] {.error:
"commandLineParams() unsupported by dynamic libraries".} = "commandLineParams() unsupported by dynamic libraries".} =
discard discard

View file

@ -75,7 +75,7 @@ const poDemon* {.deprecated.} = poDaemon ## Nim versions before 0.20
proc execProcess*(command: string, workingDir: string = "", proc execProcess*(command: string, workingDir: string = "",
args: openArray[string] = [], env: StringTableRef = nil, args: openArray[string] = [], env: StringTableRef = nil,
options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}): options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, poEvalCommand}):
TaintedString {.rtl, extern: "nosp$1", string {.rtl, extern: "nosp$1",
tags: [ExecIOEffect, ReadIOEffect, RootEffect].} tags: [ExecIOEffect, ReadIOEffect, RootEffect].}
## A convenience procedure that executes ``command`` with ``startProcess`` ## A convenience procedure that executes ``command`` with ``startProcess``
## and returns its output as a string. ## and returns its output as a string.
@ -504,13 +504,13 @@ when not defined(useNimRtl):
args: openArray[string] = [], env: StringTableRef = nil, args: openArray[string] = [], env: StringTableRef = nil,
options: set[ProcessOption] = {poStdErrToStdOut, poUsePath, options: set[ProcessOption] = {poStdErrToStdOut, poUsePath,
poEvalCommand}): poEvalCommand}):
TaintedString = string =
var p = startProcess(command, workingDir = workingDir, args = args, var p = startProcess(command, workingDir = workingDir, args = args,
env = env, options = options) env = env, options = options)
var outp = outputStream(p) var outp = outputStream(p)
result = TaintedString"" result = ""
var line = newStringOfCap(120).TaintedString var line = newStringOfCap(120)
while true: while true:
# FIXME: converts CR-LF to LF. # FIXME: converts CR-LF to LF.
if outp.readLine(line): if outp.readLine(line):
@ -1572,7 +1572,7 @@ elif not defined(useNimRtl):
proc execCmdEx*(command: string, options: set[ProcessOption] = { proc execCmdEx*(command: string, options: set[ProcessOption] = {
poStdErrToStdOut, poUsePath}, env: StringTableRef = nil, poStdErrToStdOut, poUsePath}, env: StringTableRef = nil,
workingDir = "", input = ""): tuple[ workingDir = "", input = ""): tuple[
output: TaintedString, output: string,
exitCode: int] {.tags: exitCode: int] {.tags:
[ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} =
## A convenience proc that runs the `command`, and returns its `output` and ## A convenience proc that runs the `command`, and returns its `output` and
@ -1619,8 +1619,8 @@ proc execCmdEx*(command: string, options: set[ProcessOption] = {
inputStream(p).write(input) inputStream(p).write(input)
close inputStream(p) close inputStream(p)
result = (TaintedString"", -1) result = ("", -1)
var line = newStringOfCap(120).TaintedString var line = newStringOfCap(120)
while true: while true:
if outp.readLine(line): if outp.readLine(line):
result[0].string.add(line.string) result[0].string.add(line.string)

View file

@ -172,7 +172,7 @@ type
cmds: seq[string] cmds: seq[string]
idx: int idx: int
kind*: CmdLineKind ## The detected command line token kind*: CmdLineKind ## The detected command line token
key*, val*: TaintedString ## Key and value pair; the key is the option key*, val*: string ## Key and value pair; the key is the option
## or the argument, and the value is not "" if ## or the argument, and the value is not "" if
## the option was given a value ## the option was given a value
@ -231,10 +231,10 @@ when declared(os.paramCount):
result.cmds[i-1] = os.paramStr(i).string result.cmds[i-1] = os.paramStr(i).string
result.kind = cmdEnd result.kind = cmdEnd
result.key = TaintedString"" result.key = ""
result.val = TaintedString"" result.val = ""
proc initOptParser*(cmdline: seq[TaintedString], shortNoVal: set[char] = {}, proc initOptParser*(cmdline: seq[string], shortNoVal: set[char] = {},
longNoVal: seq[string] = @[]; longNoVal: seq[string] = @[];
allowWhitespaceAfterColon = true): OptParser = allowWhitespaceAfterColon = true): OptParser =
## Initializes the command line parser. ## Initializes the command line parser.
@ -245,7 +245,7 @@ when declared(os.paramCount):
## <#initOptParser,string,set[char],seq[string]>`_. ## <#initOptParser,string,set[char],seq[string]>`_.
## ##
## See also: ## See also:
## * `getopt iterator<#getopt.i,seq[TaintedString],set[char],seq[string]>`_ ## * `getopt iterator<#getopt.i,seq[string],set[char],seq[string]>`_
runnableExamples: runnableExamples:
var p = initOptParser() var p = initOptParser()
p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"]) p = initOptParser(@["--left", "--debug:3", "-l", "-r:2"])
@ -267,8 +267,8 @@ when declared(os.paramCount):
for i in countup(1, os.paramCount()): for i in countup(1, os.paramCount()):
result.cmds[i-1] = os.paramStr(i).string result.cmds[i-1] = os.paramStr(i).string
result.kind = cmdEnd result.kind = cmdEnd
result.key = TaintedString"" result.key = ""
result.val = TaintedString"" result.val = ""
proc handleShortOption(p: var OptParser; cmd: string) = proc handleShortOption(p: var OptParser; cmd: string) =
var i = p.pos var i = p.pos
@ -286,7 +286,7 @@ proc handleShortOption(p: var OptParser; cmd: string) =
inc(i) inc(i)
p.inShortState = false p.inShortState = false
while i < cmd.len and cmd[i] in {'\t', ' '}: inc(i) while i < cmd.len and cmd[i] in {'\t', ' '}: inc(i)
p.val = TaintedString substr(cmd, i) p.val = substr(cmd, i)
p.pos = 0 p.pos = 0
inc p.idx inc p.idx
else: else:
@ -349,12 +349,12 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
inc p.idx inc p.idx
i = 0 i = 0
if p.idx < p.cmds.len: if p.idx < p.cmds.len:
p.val = TaintedString p.cmds[p.idx].substr(i) p.val = p.cmds[p.idx].substr(i)
elif len(p.longNoVal) > 0 and p.key.string notin p.longNoVal and p.idx+1 < p.cmds.len: elif len(p.longNoVal) > 0 and p.key.string notin p.longNoVal and p.idx+1 < p.cmds.len:
p.val = TaintedString p.cmds[p.idx+1] p.val = p.cmds[p.idx+1]
inc p.idx inc p.idx
else: else:
p.val = TaintedString"" p.val = ""
inc p.idx inc p.idx
p.pos = 0 p.pos = 0
else: else:
@ -362,11 +362,11 @@ proc next*(p: var OptParser) {.rtl, extern: "npo$1".} =
handleShortOption(p, p.cmds[p.idx]) handleShortOption(p, p.cmds[p.idx])
else: else:
p.kind = cmdArgument p.kind = cmdArgument
p.key = TaintedString p.cmds[p.idx] p.key = p.cmds[p.idx]
inc p.idx inc p.idx
p.pos = 0 p.pos = 0
proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} = proc cmdLineRest*(p: OptParser): string {.rtl, extern: "npo$1".} =
## Retrieves the rest of the command line that has not been parsed yet. ## Retrieves the rest of the command line that has not been parsed yet.
## ##
## See also: ## See also:
@ -382,9 +382,9 @@ proc cmdLineRest*(p: OptParser): TaintedString {.rtl, extern: "npo$1".} =
## break ## break
## else: continue ## else: continue
## doAssert p.cmdLineRest == "foo.txt bar.txt" ## doAssert p.cmdLineRest == "foo.txt bar.txt"
result = p.cmds[p.idx .. ^1].quoteShellCommand.TaintedString result = p.cmds[p.idx .. ^1].quoteShellCommand
proc remainingArgs*(p: OptParser): seq[TaintedString] {.rtl, extern: "npo$1".} = proc remainingArgs*(p: OptParser): seq[string] {.rtl, extern: "npo$1".} =
## Retrieves a sequence of the arguments that have not been parsed yet. ## Retrieves a sequence of the arguments that have not been parsed yet.
## ##
## See also: ## See also:
@ -401,10 +401,10 @@ proc remainingArgs*(p: OptParser): seq[TaintedString] {.rtl, extern: "npo$1".} =
## else: continue ## else: continue
## doAssert p.remainingArgs == @["foo.txt", "bar.txt"] ## doAssert p.remainingArgs == @["foo.txt", "bar.txt"]
result = @[] result = @[]
for i in p.idx..<p.cmds.len: result.add TaintedString(p.cmds[i]) for i in p.idx..<p.cmds.len: result.add p.cmds[i]
iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key, iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key,
val: TaintedString] = val: string] =
## Convenience iterator for iterating over the given ## Convenience iterator for iterating over the given
## `OptParser<#OptParser>`_. ## `OptParser<#OptParser>`_.
## ##
@ -443,9 +443,9 @@ iterator getopt*(p: var OptParser): tuple[kind: CmdLineKind, key,
yield (p.kind, p.key, p.val) yield (p.kind, p.key, p.val)
when declared(initOptParser): when declared(initOptParser):
iterator getopt*(cmdline: seq[TaintedString] = commandLineParams(), iterator getopt*(cmdline: seq[string] = commandLineParams(),
shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]): shortNoVal: set[char] = {}, longNoVal: seq[string] = @[]):
tuple[kind: CmdLineKind, key, val: TaintedString] = tuple[kind: CmdLineKind, key, val: string] =
## Convenience iterator for iterating over command line arguments. ## Convenience iterator for iterating over command line arguments.
## ##
## This creates a new `OptParser<#OptParser>`_. If no command line ## This creates a new `OptParser<#OptParser>`_. If no command line
@ -460,7 +460,7 @@ when declared(initOptParser):
## There is no need to check for ``cmdEnd`` while iterating. ## There is no need to check for ``cmdEnd`` while iterating.
## ##
## See also: ## See also:
## * `initOptParser proc<#initOptParser,seq[TaintedString],set[char],seq[string]>`_ ## * `initOptParser proc<#initOptParser,seq[string],set[char],seq[string]>`_
## ##
## **Examples:** ## **Examples:**
## ##

View file

@ -86,7 +86,7 @@ proc debugSend*(smtp: Smtp | AsyncSmtp, cmd: string) {.multisync.} =
echo("C:" & cmd) echo("C:" & cmd)
await smtp.sock.send(cmd) await smtp.sock.send(cmd)
proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[TaintedString] {.multisync.} = proc debugRecv*(smtp: Smtp | AsyncSmtp): Future[string] {.multisync.} =
## Receives a line of data from the socket connected to the ## Receives a line of data from the socket connected to the
## SMTP server. ## SMTP server.
## ##

View file

@ -96,8 +96,6 @@
import std/private/since import std/private/since
const taintMode = compileOption("taintmode")
proc newEIO(msg: string): owned(ref IOError) = proc newEIO(msg: string): owned(ref IOError) =
new(result) new(result)
result.msg = msg result.msg = msg
@ -124,7 +122,7 @@ type
readDataStrImpl*: proc (s: Stream, buffer: var string, slice: Slice[int]): int readDataStrImpl*: proc (s: Stream, buffer: var string, slice: Slice[int]): int
{.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.} {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.}
readLineImpl*: proc(s: Stream, line: var TaintedString): bool readLineImpl*: proc(s: Stream, line: var string): bool
{.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.} {.nimcall, raises: [Defect, IOError, OSError], tags: [ReadIOEffect], gcsafe.}
readDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int): int readDataImpl*: proc (s: Stream, buffer: pointer, bufLen: int): int
@ -216,7 +214,7 @@ proc getPosition*(s: Stream): int =
proc readData*(s: Stream, buffer: pointer, bufLen: int): int = proc readData*(s: Stream, buffer: pointer, bufLen: int): int =
## Low level proc that reads data into an untyped `buffer` of `bufLen` size. ## Low level proc that reads data into an untyped `buffer` of `bufLen` size.
## ##
## **JS note:** `buffer` is treated as a ``ptr string`` and written to between ## **JS note:** `buffer` is treated as a ``ptr string`` and written to between
## ``0..<bufLen``. ## ``0..<bufLen``.
runnableExamples: runnableExamples:
@ -293,7 +291,7 @@ when (NimMajor, NimMinor) >= (1, 3) or not defined(js):
proc peekData*(s: Stream, buffer: pointer, bufLen: int): int = proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
## Low level proc that reads data into an untyped `buffer` of `bufLen` size ## Low level proc that reads data into an untyped `buffer` of `bufLen` size
## without moving stream position. ## without moving stream position.
## ##
## **JS note:** `buffer` is treated as a ``ptr string`` and written to between ## **JS note:** `buffer` is treated as a ``ptr string`` and written to between
## ``0..<bufLen``. ## ``0..<bufLen``.
runnableExamples: runnableExamples:
@ -309,7 +307,7 @@ proc peekData*(s: Stream, buffer: pointer, bufLen: int): int =
proc writeData*(s: Stream, buffer: pointer, bufLen: int) = proc writeData*(s: Stream, buffer: pointer, bufLen: int) =
## Low level proc that writes an untyped `buffer` of `bufLen` size ## Low level proc that writes an untyped `buffer` of `bufLen` size
## to the stream `s`. ## to the stream `s`.
## ##
## **JS note:** `buffer` is treated as a ``ptr string`` and read between ## **JS note:** `buffer` is treated as a ``ptr string`` and read between
## ``0..<bufLen``. ## ``0..<bufLen``.
runnableExamples: runnableExamples:
@ -921,26 +919,20 @@ proc peekFloat64*(s: Stream): float64 =
peek(s, result) peek(s, result)
template untaint(s: var TaintedString): var string = proc readStrPrivate(s: Stream, length: int, str: var string) =
when taintMode: # for VM, bug #12282 if length > len(str): setLen(str, length)
s.string
else:
s
proc readStrPrivate(s: Stream, length: int, str: var TaintedString) =
if length > len(str): setLen(str.untaint, length)
when defined(js): when defined(js):
let L = readData(s, addr(str), length) let L = readData(s, addr(str), length)
else: else:
let L = readData(s, cstring(str.string), length) let L = readData(s, cstring(str.string), length)
if L != len(str): setLen(str.untaint, L) if L != len(str): setLen(str, L)
proc readStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} = proc readStr*(s: Stream, length: int, str: var string) {.since: (1, 3).} =
## Reads a string of length `length` from the stream `s`. Raises `IOError` if ## Reads a string of length `length` from the stream `s`. Raises `IOError` if
## an error occurred. ## an error occurred.
readStrPrivate(s, length, str) readStrPrivate(s, length, str)
proc readStr*(s: Stream, length: int): TaintedString = proc readStr*(s: Stream, length: int): string =
## Reads a string of length `length` from the stream `s`. Raises `IOError` if ## Reads a string of length `length` from the stream `s`. Raises `IOError` if
## an error occurred. ## an error occurred.
runnableExamples: runnableExamples:
@ -950,23 +942,23 @@ proc readStr*(s: Stream, length: int): TaintedString =
doAssert strm.readStr(2) == "e" doAssert strm.readStr(2) == "e"
doAssert strm.readStr(2) == "" doAssert strm.readStr(2) == ""
strm.close() strm.close()
result = newString(length).TaintedString result = newString(length)
readStrPrivate(s, length, result) readStrPrivate(s, length, result)
proc peekStrPrivate(s: Stream, length: int, str: var TaintedString) = proc peekStrPrivate(s: Stream, length: int, str: var string) =
if length > len(str): setLen(str.untaint, length) if length > len(str): setLen(str, length)
when defined(js): when defined(js):
let L = peekData(s, addr(str), length) let L = peekData(s, addr(str), length)
else: else:
let L = peekData(s, cstring(str.string), length) let L = peekData(s, cstring(str.string), length)
if L != len(str): setLen(str.untaint, L) if L != len(str): setLen(str, L)
proc peekStr*(s: Stream, length: int, str: var TaintedString) {.since: (1, 3).} = proc peekStr*(s: Stream, length: int, str: var string) {.since: (1, 3).} =
## Peeks a string of length `length` from the stream `s`. Raises `IOError` if ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if
## an error occurred. ## an error occurred.
peekStrPrivate(s, length, str) peekStrPrivate(s, length, str)
proc peekStr*(s: Stream, length: int): TaintedString = proc peekStr*(s: Stream, length: int): string =
## Peeks a string of length `length` from the stream `s`. Raises `IOError` if ## Peeks a string of length `length` from the stream `s`. Raises `IOError` if
## an error occurred. ## an error occurred.
runnableExamples: runnableExamples:
@ -977,10 +969,10 @@ proc peekStr*(s: Stream, length: int): TaintedString =
doAssert strm.readStr(2) == "ab" doAssert strm.readStr(2) == "ab"
doAssert strm.peekStr(2) == "cd" doAssert strm.peekStr(2) == "cd"
strm.close() strm.close()
result = newString(length).TaintedString result = newString(length)
peekStrPrivate(s, length, result) peekStrPrivate(s, length, result)
proc readLine*(s: Stream, line: var TaintedString): bool = proc readLine*(s: Stream, line: var string): bool =
## Reads a line of text from the stream `s` into `line`. `line` must not be ## Reads a line of text from the stream `s` into `line`. `line` must not be
## ``nil``! May throw an IO exception. ## ``nil``! May throw an IO exception.
## ##
@ -992,7 +984,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
## See also: ## See also:
## * `readLine(Stream) proc <#readLine,Stream>`_ ## * `readLine(Stream) proc <#readLine,Stream>`_
## * `peekLine(Stream) proc <#peekLine,Stream>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_
## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_
runnableExamples: runnableExamples:
var strm = newStringStream("The first line\nthe second line\nthe third line") var strm = newStringStream("The first line\nthe second line\nthe third line")
var line = "" var line = ""
@ -1010,7 +1002,7 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
result = s.readLineImpl(s, line) result = s.readLineImpl(s, line)
else: else:
# fallback # fallback
line.untaint.setLen(0) line.setLen(0)
while true: while true:
var c = readChar(s) var c = readChar(s)
if c == '\c': if c == '\c':
@ -1020,10 +1012,10 @@ proc readLine*(s: Stream, line: var TaintedString): bool =
elif c == '\0': elif c == '\0':
if line.len > 0: break if line.len > 0: break
else: return false else: return false
line.untaint.add(c) line.add(c)
result = true result = true
proc peekLine*(s: Stream, line: var TaintedString): bool = proc peekLine*(s: Stream, line: var string): bool =
## Peeks a line of text from the stream `s` into `line`. `line` must not be ## Peeks a line of text from the stream `s` into `line`. `line` must not be
## ``nil``! May throw an IO exception. ## ``nil``! May throw an IO exception.
## ##
@ -1034,7 +1026,7 @@ proc peekLine*(s: Stream, line: var TaintedString): bool =
## ##
## See also: ## See also:
## * `readLine(Stream) proc <#readLine,Stream>`_ ## * `readLine(Stream) proc <#readLine,Stream>`_
## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_
## * `peekLine(Stream) proc <#peekLine,Stream>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_
runnableExamples: runnableExamples:
var strm = newStringStream("The first line\nthe second line\nthe third line") var strm = newStringStream("The first line\nthe second line\nthe third line")
@ -1054,15 +1046,15 @@ proc peekLine*(s: Stream, line: var TaintedString): bool =
defer: setPosition(s, pos) defer: setPosition(s, pos)
result = readLine(s, line) result = readLine(s, line)
proc readLine*(s: Stream): TaintedString = proc readLine*(s: Stream): string =
## Reads a line from a stream `s`. Raises `IOError` if an error occurred. ## Reads a line from a stream `s`. Raises `IOError` if an error occurred.
## ##
## **Note:** This is not very efficient. ## **Note:** This is not very efficient.
## ##
## See also: ## See also:
## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_
## * `peekLine(Stream) proc <#peekLine,Stream>`_ ## * `peekLine(Stream) proc <#peekLine,Stream>`_
## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_
runnableExamples: runnableExamples:
var strm = newStringStream("The first line\nthe second line\nthe third line") var strm = newStringStream("The first line\nthe second line\nthe third line")
doAssert strm.readLine() == "The first line" doAssert strm.readLine() == "The first line"
@ -1071,7 +1063,7 @@ proc readLine*(s: Stream): TaintedString =
doAssertRaises(IOError): discard strm.readLine() doAssertRaises(IOError): discard strm.readLine()
strm.close() strm.close()
result = TaintedString"" result = ""
if s.atEnd: if s.atEnd:
raise newEIO("cannot read from stream") raise newEIO("cannot read from stream")
while true: while true:
@ -1082,17 +1074,17 @@ proc readLine*(s: Stream): TaintedString =
if c == '\L' or c == '\0': if c == '\L' or c == '\0':
break break
else: else:
result.untaint.add(c) result.add(c)
proc peekLine*(s: Stream): TaintedString = proc peekLine*(s: Stream): string =
## Peeks a line from a stream `s`. Raises `IOError` if an error occurred. ## Peeks a line from a stream `s`. Raises `IOError` if an error occurred.
## ##
## **Note:** This is not very efficient. ## **Note:** This is not very efficient.
## ##
## See also: ## See also:
## * `readLine(Stream) proc <#readLine,Stream>`_ ## * `readLine(Stream) proc <#readLine,Stream>`_
## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_
## * `peekLine(Stream, TaintedString) proc <#peekLine,Stream,TaintedString>`_ ## * `peekLine(Stream, string) proc <#peekLine,Stream,string>`_
runnableExamples: runnableExamples:
var strm = newStringStream("The first line\nthe second line\nthe third line") var strm = newStringStream("The first line\nthe second line\nthe third line")
doAssert strm.peekLine() == "The first line" doAssert strm.peekLine() == "The first line"
@ -1106,13 +1098,13 @@ proc peekLine*(s: Stream): TaintedString =
defer: setPosition(s, pos) defer: setPosition(s, pos)
result = readLine(s) result = readLine(s)
iterator lines*(s: Stream): TaintedString = iterator lines*(s: Stream): string =
## Iterates over every line in the stream. ## Iterates over every line in the stream.
## The iteration is based on ``readLine``. ## The iteration is based on ``readLine``.
## ##
## See also: ## See also:
## * `readLine(Stream) proc <#readLine,Stream>`_ ## * `readLine(Stream) proc <#readLine,Stream>`_
## * `readLine(Stream, TaintedString) proc <#readLine,Stream,TaintedString>`_ ## * `readLine(Stream, string) proc <#readLine,Stream,string>`_
runnableExamples: runnableExamples:
var strm = newStringStream("The first line\nthe second line\nthe third line") var strm = newStringStream("The first line\nthe second line\nthe third line")
var lines: seq[string] var lines: seq[string]
@ -1121,7 +1113,7 @@ iterator lines*(s: Stream): TaintedString =
doAssert lines == @["The first line", "the second line", "the third line"] doAssert lines == @["The first line", "the second line", "the third line"]
strm.close() strm.close()
var line: TaintedString var line: string
while s.readLine(line): while s.readLine(line):
yield line yield line
@ -1187,7 +1179,7 @@ when (NimMajor, NimMinor) < (1, 3) and defined(js):
if readBytes < bufferSize: if readBytes < bufferSize:
break break
else: # after 1.3 or JS not defined else: # after 1.3 or JS not defined
proc ssAtEnd(s: Stream): bool = proc ssAtEnd(s: Stream): bool =
var s = StringStream(s) var s = StringStream(s)
return s.pos >= s.data.len return s.pos >= s.data.len
@ -1333,7 +1325,7 @@ proc fsWriteData(s: Stream, buffer: pointer, bufLen: int) =
if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen: if writeBuffer(FileStream(s).f, buffer, bufLen) != bufLen:
raise newEIO("cannot write to stream") raise newEIO("cannot write to stream")
proc fsReadLine(s: Stream, line: var TaintedString): bool = proc fsReadLine(s: Stream, line: var string): bool =
result = readLine(FileStream(s).f, line) result = readLine(FileStream(s).f, line)
proc newFileStream*(f: File): owned FileStream = proc newFileStream*(f: File): owned FileStream =

View file

@ -26,7 +26,7 @@ type
baseReadLineImpl: typeof(StreamObj.readLineImpl) baseReadLineImpl: typeof(StreamObj.readLineImpl)
baseReadDataImpl: typeof(StreamObj.readDataImpl) baseReadDataImpl: typeof(StreamObj.readDataImpl)
proc posReadLine[T](s: Stream, line: var TaintedString): bool = proc posReadLine[T](s: Stream, line: var string): bool =
var s = PipeOutStream[T](s) var s = PipeOutStream[T](s)
assert s.baseReadLineImpl != nil assert s.baseReadLineImpl != nil

View file

@ -771,7 +771,7 @@ proc getch*(): char =
when defined(windows): when defined(windows):
from unicode import toUTF8, Rune, runeLenAt from unicode import toUTF8, Rune, runeLenAt
proc readPasswordFromStdin*(prompt: string, password: var TaintedString): proc readPasswordFromStdin*(prompt: string, password: var string):
bool {.tags: [ReadIOEffect, WriteIOEffect].} = bool {.tags: [ReadIOEffect, WriteIOEffect].} =
## Reads a `password` from stdin without printing it. `password` must not ## Reads a `password` from stdin without printing it. `password` must not
## be ``nil``! Returns ``false`` if the end of the file has been reached, ## be ``nil``! Returns ``false`` if the end of the file has been reached,
@ -797,7 +797,7 @@ when defined(windows):
else: else:
import termios import termios
proc readPasswordFromStdin*(prompt: string, password: var TaintedString): proc readPasswordFromStdin*(prompt: string, password: var string):
bool {.tags: [ReadIOEffect, WriteIOEffect].} = bool {.tags: [ReadIOEffect, WriteIOEffect].} =
password.string.setLen(0) password.string.setLen(0)
let fd = stdin.getFileHandle() let fd = stdin.getFileHandle()
@ -811,9 +811,9 @@ else:
stdout.write "\n" stdout.write "\n"
discard fd.tcSetAttr(TCSADRAIN, old.addr) discard fd.tcSetAttr(TCSADRAIN, old.addr)
proc readPasswordFromStdin*(prompt = "password: "): TaintedString = proc readPasswordFromStdin*(prompt = "password: "): string =
## Reads a password from stdin without printing it. ## Reads a password from stdin without printing it.
result = TaintedString("") result = ""
discard readPasswordFromStdin(prompt, result) discard readPasswordFromStdin(prompt, result)

View file

@ -160,7 +160,7 @@ func encodeQuery*(query: openArray[(string, string)], usePlus = true,
result.add('=') result.add('=')
result.add(encodeUrl(val, usePlus)) result.add(encodeUrl(val, usePlus))
iterator decodeQuery*(data: string): tuple[key, value: TaintedString] = iterator decodeQuery*(data: string): tuple[key, value: string] =
## Reads and decodes query string `data` and yields the `(key, value)` pairs ## Reads and decodes query string `data` and yields the `(key, value)` pairs
## the data consists of. If compiled with `-d:nimLegacyParseQueryStrict`, an ## the data consists of. If compiled with `-d:nimLegacyParseQueryStrict`, an
## error is raised when there is an unencoded `=` character in a decoded ## error is raised when there is an unencoded `=` character in a decoded
@ -197,7 +197,7 @@ iterator decodeQuery*(data: string): tuple[key, value: TaintedString] =
i = parseData(data, i, value, '=') i = parseData(data, i, value, '=')
else: else:
i = parseData(data, i, value, '&') i = parseData(data, i, value, '&')
yield (name.TaintedString, value.TaintedString) yield (name, value)
if i < data.len: if i < data.len:
when defined(nimLegacyParseQueryStrict): when defined(nimLegacyParseQueryStrict):
if data[i] != '&': if data[i] != '&':

View file

@ -1084,7 +1084,6 @@ const
const const
hasThreadSupport = compileOption("threads") and not defined(nimscript) hasThreadSupport = compileOption("threads") and not defined(nimscript)
hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own hasSharedHeap = defined(boehmgc) or defined(gogc) # don't share heaps; every thread has its own
taintMode = compileOption("taintmode")
nimEnableCovariance* = defined(nimEnableCovariance) # or true nimEnableCovariance* = defined(nimEnableCovariance) # or true
when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"): when hasThreadSupport and defined(tcc) and not compileOption("tlsEmulation"):
@ -1107,22 +1106,8 @@ when defined(boehmgc):
const boehmLib = "libgc.so.1" const boehmLib = "libgc.so.1"
{.pragma: boehmGC, noconv, dynlib: boehmLib.} {.pragma: boehmGC, noconv, dynlib: boehmLib.}
when taintMode: type TaintedString* {.deprecated: "Deprecated since 1.5".} = string
type TaintedString* = distinct string ## A distinct string type that
## is `tainted`:idx:, see `taint mode
## <manual_experimental.html#taint-mode>`_
## for details. It is an alias for
## ``string`` if the taint mode is not
## turned on.
proc len*(s: TaintedString): int {.borrow.}
else:
type TaintedString* = string ## A distinct string type that
## is `tainted`:idx:, see `taint mode
## <manual_experimental.html#taint-mode>`_
## for details. It is an alias for
## ``string`` if the taint mode is not
## turned on.
when defined(profiler) and not defined(nimscript): when defined(profiler) and not defined(nimscript):
proc nimProfile() {.compilerproc, noinline.} proc nimProfile() {.compilerproc, noinline.}

View file

@ -358,7 +358,7 @@ when defined(nimdoc) or (defined(posix) and not defined(nimscript)) or defined(w
result = setHandleInformation(cast[IoHandle](f), HANDLE_FLAG_INHERIT, result = setHandleInformation(cast[IoHandle](f), HANDLE_FLAG_INHERIT,
inheritable.WinDWORD) != 0 inheritable.WinDWORD) != 0
proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect], proc readLine*(f: File, line: var string): bool {.tags: [ReadIOEffect],
benign.} = benign.} =
## reads a line of text from the file `f` into `line`. May throw an IO ## reads a line of text from the file `f` into `line`. May throw an IO
## exception. ## exception.
@ -420,15 +420,15 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
if buffer[i].uint16 == 26: #Ctrl+Z if buffer[i].uint16 == 26: #Ctrl+Z
close(f) #has the same effect as setting EOF close(f) #has the same effect as setting EOF
if i == 0: if i == 0:
line = TaintedString("") line = ""
return false return false
numberOfCharsRead = i numberOfCharsRead = i
break break
buffer[numberOfCharsRead] = 0.Utf16Char buffer[numberOfCharsRead] = 0.Utf16Char
when defined(nimv2): when defined(nimv2):
line = TaintedString($toWideCString(buffer)) line = $toWideCString(buffer)
else: else:
line = TaintedString($buffer) line = $buffer
return(true) return(true)
var pos = 0 var pos = 0
@ -479,11 +479,11 @@ proc readLine*(f: File, line: var TaintedString): bool {.tags: [ReadIOEffect],
sp = 128 # read in 128 bytes at a time sp = 128 # read in 128 bytes at a time
line.string.setLen(pos+sp) line.string.setLen(pos+sp)
proc readLine*(f: File): TaintedString {.tags: [ReadIOEffect], benign.} = proc readLine*(f: File): string {.tags: [ReadIOEffect], benign.} =
## reads a line of text from the file `f`. May throw an IO exception. ## reads a line of text from the file `f`. May throw an IO exception.
## A line of text may be delimited by ``LF`` or ``CRLF``. The newline ## A line of text may be delimited by ``LF`` or ``CRLF``. The newline
## character(s) are not part of the returned string. ## character(s) are not part of the returned string.
result = TaintedString(newStringOfCap(80)) result = newStringOfCap(80)
if not readLine(f, result): raiseEOF() if not readLine(f, result): raiseEOF()
proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.} = proc write*(f: File, i: int) {.tags: [WriteIOEffect], benign.} =
@ -563,7 +563,7 @@ proc readAllFile(file: File): string =
var len = rawFileSize(file) var len = rawFileSize(file)
result = readAllFile(file, len) result = readAllFile(file, len)
proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} = proc readAll*(file: File): string {.tags: [ReadIOEffect], benign.} =
## Reads all data from the stream `file`. ## Reads all data from the stream `file`.
## ##
## Raises an IO exception in case of an error. It is an error if the ## Raises an IO exception in case of an error. It is an error if the
@ -576,9 +576,9 @@ proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} =
else: else:
let len = rawFileSize(file) let len = rawFileSize(file)
if len > 0: if len > 0:
result = readAllFile(file, len).TaintedString result = readAllFile(file, len)
else: else:
result = readAllBuffer(file).TaintedString result = readAllBuffer(file)
proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline, proc writeLine*[Ty](f: File, x: varargs[Ty, `$`]) {.inline,
tags: [WriteIOEffect], benign.} = tags: [WriteIOEffect], benign.} =
@ -841,7 +841,7 @@ when defined(windows) and appType == "console" and
discard setConsoleOutputCP(Utf8codepage) discard setConsoleOutputCP(Utf8codepage)
discard setConsoleCP(Utf8codepage) discard setConsoleCP(Utf8codepage)
proc readFile*(filename: string): TaintedString {.tags: [ReadIOEffect], benign.} = proc readFile*(filename: string): string {.tags: [ReadIOEffect], benign.} =
## Opens a file named `filename` for reading, calls `readAll ## Opens a file named `filename` for reading, calls `readAll
## <#readAll,File>`_ and closes the file afterwards. Returns the string. ## <#readAll,File>`_ and closes the file afterwards. Returns the string.
## Raises an IO exception in case of an error. If you need to call ## Raises an IO exception in case of an error. If you need to call
@ -882,7 +882,7 @@ proc writeFile*(filename: string, content: openArray[byte]) {.since: (1, 1).} =
else: else:
raise newException(IOError, "cannot open: " & filename) raise newException(IOError, "cannot open: " & filename)
proc readLines*(filename: string, n: Natural): seq[TaintedString] = proc readLines*(filename: string, n: Natural): seq[string] =
## read `n` lines from the file named `filename`. Raises an IO exception ## read `n` lines from the file named `filename`. Raises an IO exception
## in case of an error. Raises EOF if file does not contain at least `n` lines. ## in case of an error. Raises EOF if file does not contain at least `n` lines.
## Available at compile time. A line of text may be delimited by ``LF`` or ``CRLF``. ## Available at compile time. A line of text may be delimited by ``LF`` or ``CRLF``.
@ -890,7 +890,7 @@ proc readLines*(filename: string, n: Natural): seq[TaintedString] =
var f: File = nil var f: File = nil
if open(f, filename): if open(f, filename):
try: try:
result = newSeq[TaintedString](n) result = newSeq[string](n)
for i in 0 .. n - 1: for i in 0 .. n - 1:
if not readLine(f, result[i]): if not readLine(f, result[i]):
raiseEOF() raiseEOF()
@ -899,10 +899,10 @@ proc readLines*(filename: string, n: Natural): seq[TaintedString] =
else: else:
sysFatal(IOError, "cannot open: " & filename) sysFatal(IOError, "cannot open: " & filename)
template readLines*(filename: string): seq[TaintedString] {.deprecated: "use readLines with two arguments".} = template readLines*(filename: string): seq[string] {.deprecated: "use readLines with two arguments".} =
readLines(filename, 1) readLines(filename, 1)
iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} = iterator lines*(filename: string): string {.tags: [ReadIOEffect].} =
## Iterates over any line in the file named `filename`. ## Iterates over any line in the file named `filename`.
## ##
## If the file does not exist `IOError` is raised. The trailing newline ## If the file does not exist `IOError` is raised. The trailing newline
@ -918,12 +918,12 @@ iterator lines*(filename: string): TaintedString {.tags: [ReadIOEffect].} =
## writeFile(filename, buffer) ## writeFile(filename, buffer)
var f = open(filename, bufSize=8000) var f = open(filename, bufSize=8000)
try: try:
var res = TaintedString(newStringOfCap(80)) var res = newStringOfCap(80)
while f.readLine(res): yield res while f.readLine(res): yield res
finally: finally:
close(f) close(f)
iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} = iterator lines*(f: File): string {.tags: [ReadIOEffect].} =
## Iterate over any line in the file `f`. ## Iterate over any line in the file `f`.
## ##
## The trailing newline character(s) are removed from the iterated lines. ## The trailing newline character(s) are removed from the iterated lines.
@ -936,5 +936,5 @@ iterator lines*(f: File): TaintedString {.tags: [ReadIOEffect].} =
## if letter == '0': ## if letter == '0':
## result.zeros += 1 ## result.zeros += 1
## result.lines += 1 ## result.lines += 1
var res = TaintedString(newStringOfCap(80)) var res = newStringOfCap(80)
while f.readLine(res): yield res while f.readLine(res): yield res

View file

@ -360,21 +360,21 @@ proc cppDefine*(define: string) =
## needs to be mangled. ## needs to be mangled.
builtin builtin
proc stdinReadLine(): TaintedString {. proc stdinReadLine(): string {.
tags: [ReadIOEffect], raises: [IOError].} = tags: [ReadIOEffect], raises: [IOError].} =
builtin builtin
proc stdinReadAll(): TaintedString {. proc stdinReadAll(): string {.
tags: [ReadIOEffect], raises: [IOError].} = tags: [ReadIOEffect], raises: [IOError].} =
builtin builtin
proc readLineFromStdin*(): TaintedString {.raises: [IOError].} = proc readLineFromStdin*(): string {.raises: [IOError].} =
## Reads a line of data from stdin - blocks until \n or EOF which happens when stdin is closed ## Reads a line of data from stdin - blocks until \n or EOF which happens when stdin is closed
log "readLineFromStdin": log "readLineFromStdin":
result = stdinReadLine() result = stdinReadLine()
checkError(EOFError) checkError(EOFError)
proc readAllFromStdin*(): TaintedString {.raises: [IOError].} = proc readAllFromStdin*(): string {.raises: [IOError].} =
## Reads all data from stdin - blocks until EOF which happens when stdin is closed ## Reads all data from stdin - blocks until EOF which happens when stdin is closed
log "readAllFromStdin": log "readAllFromStdin":
result = stdinReadAll() result = stdinReadAll()

View file

@ -319,7 +319,7 @@ proc replTcp(x: ThreadParams) {.thread.} =
else: else:
server.bindAddr(x.port, x.address) server.bindAddr(x.port, x.address)
server.listen() server.listen()
var inp = "".TaintedString var inp = ""
var stdoutSocket: Socket var stdoutSocket: Socket
while true: while true:
accept(server, stdoutSocket) accept(server, stdoutSocket)

View file

@ -62,7 +62,7 @@ proc doCaasCommand(session: var NimSession, command: string): string =
result = "" result = ""
while true: while true:
var line = TaintedString("") var line = ""
if session.nim.outputStream.readLine(line): if session.nim.outputStream.readLine(line):
if line.string == "": break if line.string == "": break
result.add(line.string & "\n") result.add(line.string & "\n")
@ -78,7 +78,7 @@ proc doProcCommand(session: var NimSession, command: string): string =
var var
process = startProcess(NimBin, args = session.replaceVars(command).split) process = startProcess(NimBin, args = session.replaceVars(command).split)
stream = outputStream(process) stream = outputStream(process)
line = TaintedString("") line = ""
result = "" result = ""
while stream.readLine(line): while stream.readLine(line):
@ -113,12 +113,12 @@ proc doScenario(script: string, output: Stream, mode: TRunMode, verbose: bool):
result = true result = true
var f = open(script) var f = open(script)
var project = TaintedString("") var project = ""
if f.readLine(project): if f.readLine(project):
var var
s = startNimSession(script.parentDir / project.string, script, mode) s = startNimSession(script.parentDir / project.string, script, mode)
tline = TaintedString("") tline = ""
ln = 1 ln = 1
while f.readLine(tline): while f.readLine(tline):

View file

@ -102,7 +102,7 @@ proc getFileDir(filename: string): string =
proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: string = ""): tuple[ proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: string = ""): tuple[
cmdLine: string, cmdLine: string,
output: TaintedString, output: string,
exitCode: int] {.tags: exitCode: int] {.tags:
[ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} =
@ -122,7 +122,7 @@ proc execCmdEx2(command: string, args: openArray[string]; workingDir, input: str
close instream close instream
result.exitCode = -1 result.exitCode = -1
var line = newStringOfCap(120).TaintedString var line = newStringOfCap(120)
while true: while true:
if outp.readLine(line): if outp.readLine(line):
result.output.string.add(line.string) result.output.string.add(line.string)
@ -161,7 +161,7 @@ proc callCompiler(cmdTemplate, filename, options, nimcache: string,
var x = newStringOfCap(120) var x = newStringOfCap(120)
result.nimout = "" result.nimout = ""
while true: while true:
if outp.readLine(x.TaintedString): if outp.readLine(x):
result.nimout.add(x & "\n") result.nimout.add(x & "\n")
if x =~ pegOfInterest: if x =~ pegOfInterest:
# `err` should contain the last error/warning message # `err` should contain the last error/warning message
@ -210,7 +210,7 @@ proc callCCompiler(cmdTemplate, filename, options: string,
result.output = "" result.output = ""
result.line = -1 result.line = -1
while true: while true:
if outp.readLine(x.TaintedString): if outp.readLine(x):
result.nimout.add(x & "\n") result.nimout.add(x & "\n")
elif not running(p): elif not running(p):
break break

View file

@ -28,7 +28,7 @@ block :tmp:
try: try:
var res var res
try: try:
res = TaintedString(newStringOfCap(80)) res = newStringOfCap(80)
block :tmp_1: block :tmp_1:
while readLine(f, res): while readLine(f, res):
x_cursor = res x_cursor = res

View file

@ -774,13 +774,13 @@ block: # issue #9458
Option[T] = object Option[T] = object
val: T val: T
has: bool has: bool
Bar = object Bar = object
proc none(T: typedesc): Option[T] = proc none(T: typedesc): Option[T] =
discard discard
proc foo[T](self: T; x: Option[Bar] = Bar.none) = proc foo[T](self: T; x: Option[Bar] = Bar.none) =
discard discard
foo(1) foo(1)
@ -834,7 +834,7 @@ proc getBar(x: string): Bar =
Bar(foo: none[seq[Foo]](), Bar(foo: none[seq[Foo]](),
s: "") s: "")
proc fakeReadLine(): TaintedString = "hey" proc fakeReadLine(): string = "hey"
echo getBar(fakeReadLine()) # causes error echo getBar(fakeReadLine()) # causes error

View file

@ -98,7 +98,7 @@ proc unused =
iterator lineIter2*(filename: string): string {.closure.} = iterator lineIter2*(filename: string): string {.closure.} =
var f = open(filename, bufSize=8000) var f = open(filename, bufSize=8000)
defer: close(f) # <-- commenting defer "solves" the problem defer: close(f) # <-- commenting defer "solves" the problem
var res = TaintedString(newStringOfCap(80)) var res = newStringOfCap(80)
while f.readLine(res): yield res while f.readLine(res): yield res
proc unusedB = proc unusedB =

View file

@ -225,7 +225,7 @@ template raise_or_quit(exception, message: untyped) =
template run_custom_proc(parsed_parameter: Tparsed_parameter, template run_custom_proc(parsed_parameter: Tparsed_parameter,
custom_validator: Tparameter_callback, custom_validator: Tparameter_callback,
parameter: TaintedString) = parameter: string) =
## Runs the custom validator if it is not nil. ## Runs the custom validator if it is not nil.
## ##
## Pass in the string of the parameter triggering the call. If the ## Pass in the string of the parameter triggering the call. If the
@ -318,7 +318,7 @@ proc echo_help*(expected: seq[Tparameter_specification] = @[],
proc parse*(expected: seq[Tparameter_specification] = @[], proc parse*(expected: seq[Tparameter_specification] = @[],
type_of_positional_parameters = PK_STRING, args: seq[TaintedString] = @[], type_of_positional_parameters = PK_STRING, args: seq[string] = @[],
bad_prefixes = @["-", "--"], end_of_options = "--", bad_prefixes = @["-", "--"], end_of_options = "--",
quit_on_failure = true): Tcommandline_results = quit_on_failure = true): Tcommandline_results =
## Parses parameters and returns results. ## Parses parameters and returns results.

View file

@ -1,7 +1,7 @@
import streams import streams
from strutils import repeat from strutils import repeat
proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): TaintedString = proc readPaddedStr*(s: PStream, length: int, padChar = '\0'): string =
var lastChr = length var lastChr = length
result = s.readStr(length) result = s.readStr(length)
while lastChr >= 0 and result[lastChr - 1] == padChar: dec(lastChr) while lastChr >= 0 and result[lastChr - 1] == padChar: dec(lastChr)
@ -16,7 +16,7 @@ proc writePaddedStr*(s: PStream, str: string, length: int, padChar = '\0') =
else: else:
s.write(str) s.write(str)
proc readLEStr*(s: PStream): TaintedString = proc readLEStr*(s: PStream): string =
var len = s.readInt16() var len = s.readInt16()
result = s.readStr(len) result = s.readStr(len)

View file

@ -5,7 +5,7 @@ disabled: "appveyor"
import memfiles import memfiles
var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim") var inp = memfiles.open("tests/stdlib/tmemlinesBuf.nim")
var buffer: TaintedString = "" var buffer: string = ""
var lineCount = 0 var lineCount = 0
for line in lines(inp, buffer): for line in lines(inp, buffer):
lineCount += 1 lineCount += 1

View file

@ -195,15 +195,15 @@ else: # main driver
# bugfix: windows stdin.close was a noop and led to blocking reads # bugfix: windows stdin.close was a noop and led to blocking reads
proc startProcessTest(command: string, options: set[ProcessOption] = { proc startProcessTest(command: string, options: set[ProcessOption] = {
poStdErrToStdOut, poUsePath}, input = ""): tuple[ poStdErrToStdOut, poUsePath}, input = ""): tuple[
output: TaintedString, output: string,
exitCode: int] {.tags: exitCode: int] {.tags:
[ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} = [ExecIOEffect, ReadIOEffect, RootEffect], gcsafe.} =
var p = startProcess(command, options = options + {poEvalCommand}) var p = startProcess(command, options = options + {poEvalCommand})
var outp = outputStream(p) var outp = outputStream(p)
if input.len > 0: inputStream(p).write(input) if input.len > 0: inputStream(p).write(input)
close inputStream(p) close inputStream(p)
result = (TaintedString"", -1) result = ("", -1)
var line = newStringOfCap(120).TaintedString var line = newStringOfCap(120)
while true: while true:
if outp.readLine(line): if outp.readLine(line):
result[0].string.add(line.string) result[0].string.add(line.string)
@ -223,7 +223,7 @@ else: # main driver
p.inputStream.flush() p.inputStream.flush()
var line = "" var line = ""
var s: seq[string] var s: seq[string]
while p.outputStream.readLine(line.TaintedString): while p.outputStream.readLine(line):
s.add line s.add line
doAssert s == @["10"] doAssert s == @["10"]
@ -235,15 +235,15 @@ else: # main driver
deferScoped: p.close() deferScoped: p.close()
do: do:
var sout: seq[string] var sout: seq[string]
while p.outputStream.readLine(x.TaintedString): sout.add x while p.outputStream.readLine(x): sout.add x
doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stderr", "to stderr", "to stdout", "to stdout", "end ta_out"] doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stderr", "to stderr", "to stdout", "to stdout", "end ta_out"]
block: # startProcess stderr (replaces old test `tstderr` + `ta_out`) block: # startProcess stderr (replaces old test `tstderr` + `ta_out`)
var p = startProcess(output, dir, options={}) var p = startProcess(output, dir, options={})
deferScoped: p.close() deferScoped: p.close()
do: do:
var serr, sout: seq[string] var serr, sout: seq[string]
while p.errorStream.readLine(x.TaintedString): serr.add x while p.errorStream.readLine(x): serr.add x
while p.outputStream.readLine(x.TaintedString): sout.add x while p.outputStream.readLine(x): sout.add x
doAssert serr == @["to stderr", "to stderr"] doAssert serr == @["to stderr", "to stderr"]
doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stdout", "to stdout", "end ta_out"] doAssert sout == @["start ta_out", "to stdout", "to stdout", "to stdout", "to stdout", "end ta_out"]

View file

@ -5,7 +5,7 @@ proc exec(cmd: string) =
let status = execShellCmd(cmd) let status = execShellCmd(cmd)
doAssert status == 0, cmd doAssert status == 0, cmd
proc execEx(cmd: string): tuple[output: TaintedString, exitCode: int] = proc execEx(cmd: string): tuple[output: string, exitCode: int] =
echo "deps.cmd: " & cmd echo "deps.cmd: " & cmd
execCmdEx(cmd, {poStdErrToStdOut, poUsePath, poEvalCommand}) execCmdEx(cmd, {poStdErrToStdOut, poUsePath, poEvalCommand})

View file

@ -93,7 +93,7 @@ Options:
--sdktype:<type> Specify the SDK flavor to use. Defaults to the Desktop SDK. --sdktype:<type> Specify the SDK flavor to use. Defaults to the Desktop SDK.
<type>: {empty} | store | uwp | onecore <type>: {empty} | store | uwp | onecore
--sdkversion:<v> Use a specific Windows SDK version: --sdkversion:<v> Use a specific Windows SDK version:
<v> is either the full Windows 10 SDK version number or <v> is either the full Windows 10 SDK version number or
"8.1" to use the windows 8.1 SDK "8.1" to use the windows 8.1 SDK
--verbose Echoes the command line for loading the Developer Command Prompt --verbose Echoes the command line for loading the Developer Command Prompt
and the command line passed on to the secondary command. and the command line passed on to the secondary command.
@ -104,12 +104,12 @@ Microsoft (R) C/C++ Optimizing Compiler if no secondary
command was specified command was specified
""" """
proc parseVccexeCmdLine(argseq: seq[TaintedString], proc parseVccexeCmdLine(argseq: seq[string],
vccversionArg: var seq[string], printPathArg: var bool, vccversionArg: var seq[string], printPathArg: var bool,
vcvarsallArg: var string, commandArg: var string, noCommandArg: var bool, vcvarsallArg: var string, commandArg: var string, noCommandArg: var bool,
platformArg: var VccArch, sdkTypeArg: var VccPlatformType, platformArg: var VccArch, sdkTypeArg: var VccPlatformType,
sdkVersionArg: var string, verboseArg: var bool, sdkVersionArg: var string, verboseArg: var bool,
clArgs: var seq[TaintedString]) = clArgs: var seq[string]) =
## Cannot use usual command-line argument parser here ## Cannot use usual command-line argument parser here
## Since vccexe command-line arguments are intermingled ## Since vccexe command-line arguments are intermingled
## with the secondary command-line arguments which have ## with the secondary command-line arguments which have
@ -160,7 +160,7 @@ when isMainModule:
var sdkVersionArg: string var sdkVersionArg: string
var verboseArg: bool = false var verboseArg: bool = false
var clArgs: seq[TaintedString] = @[] var clArgs: seq[string] = @[]
let wrapperArgs = commandLineParams() let wrapperArgs = commandLineParams()
parseVccexeCmdLine(wrapperArgs, vccversionArg, printPathArg, vcvarsallArg, parseVccexeCmdLine(wrapperArgs, vccversionArg, printPathArg, vcvarsallArg,