Merged upstream/devel into this branch to resolve conflicts and ensure an easy merge back into upstream/devel

This commit is contained in:
A. S. Budden 2016-06-13 16:44:14 +01:00
commit 1095b35a79
28 changed files with 436 additions and 359 deletions

View file

@ -48,7 +48,6 @@ Start: "doc/overview.html"
[Other] [Other]
Files: "readme.txt;install.txt;contributors.txt;copying.txt" Files: "readme.txt;install.txt;contributors.txt;copying.txt"
Files: "makefile" Files: "makefile"
Files: "*.ini"
Files: "koch.nim" Files: "koch.nim"
Files: "icons/nim.ico" Files: "icons/nim.ico"
@ -66,7 +65,6 @@ Files: "tools"
Files: "web/website.ini" Files: "web/website.ini"
Files: "web/ticker.html" Files: "web/ticker.html"
Files: "web/*.nim" Files: "web/*.nim"
Files: "web/*.txt"
Files: "web/*.rst" Files: "web/*.rst"
Files: "web/*.csv" Files: "web/*.csv"
Files: "web/news/*.rst" Files: "web/news/*.rst"

View file

@ -7,8 +7,11 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
## Regular expression support for Nim. Deprecated. Consider using the ``nre`` ## Regular expression support for Nim. This module still has some
## or ``pegs`` modules instead. ## obscure bugs and limitations,
## consider using the ``nre`` or ``pegs`` modules instead.
## We had to de-deprecate this module since too much code relies on it
## and many people prefer its API over ``nre``'s.
## ##
## **Note:** The 're' proc defaults to the **extended regular expression ## **Note:** The 're' proc defaults to the **extended regular expression
## syntax** which lets you use whitespace freely to make your regexes readable. ## syntax** which lets you use whitespace freely to make your regexes readable.
@ -28,8 +31,6 @@
import import
pcre, strutils, rtarrays pcre, strutils, rtarrays
{.deprecated.}
const const
MaxSubpatterns* = 20 MaxSubpatterns* = 20
## defines the maximum number of subpatterns that can be captured. ## defines the maximum number of subpatterns that can be captured.
@ -78,7 +79,7 @@ proc finalizeRegEx(x: Regex) =
if not isNil(x.e): if not isNil(x.e):
pcre.free_substring(cast[cstring](x.e)) pcre.free_substring(cast[cstring](x.e))
proc re*(s: string, flags = {reExtended, reStudy}): Regex {.deprecated.} = proc re*(s: string, flags = {reExtended, reStudy}): Regex =
## Constructor of regular expressions. Note that Nim's ## Constructor of regular expressions. Note that Nim's
## extended raw string literals support this syntax ``re"[abc]"`` as ## extended raw string literals support this syntax ``re"[abc]"`` as
## a short form for ``re(r"[abc]")``. ## a short form for ``re(r"[abc]")``.

View file

@ -347,9 +347,6 @@ static N_INLINE(NI32, float32ToInt32)(float x) {
#define float64ToInt64(x) ((NI64) (x)) #define float64ToInt64(x) ((NI64) (x))
#define zeroMem(a, size) memset(a, 0, size)
#define equalMem(a, b, size) (memcmp(a, b, size) == 0)
#define STRING_LITERAL(name, str, length) \ #define STRING_LITERAL(name, str, length) \
static const struct { \ static const struct { \
TGenericSeq Sup; \ TGenericSeq Sup; \

View file

@ -257,12 +257,10 @@ type MemSlice* = object ## represent slice of a MemFile for iteration over deli
data*: pointer data*: pointer
size*: int size*: int
proc c_memcpy(a, b: pointer, n: int) {.importc: "memcpy", header: "<string.h>".}
proc `$`*(ms: MemSlice): string {.inline.} = proc `$`*(ms: MemSlice): string {.inline.} =
## Return a Nim string built from a MemSlice. ## Return a Nim string built from a MemSlice.
var buf = newString(ms.size) var buf = newString(ms.size)
c_memcpy(addr(buf[0]), ms.data, ms.size) copyMem(addr(buf[0]), ms.data, ms.size)
buf[ms.size] = '\0' buf[ms.size] = '\0'
result = buf result = buf
@ -329,7 +327,7 @@ iterator lines*(mfile: MemFile, buf: var TaintedString, delim='\l', eat='\r'): T
for ms in memSlices(mfile, delim, eat): for ms in memSlices(mfile, delim, eat):
buf.setLen(ms.size) buf.setLen(ms.size)
c_memcpy(addr(buf[0]), ms.data, ms.size) copyMem(addr(buf[0]), ms.data, ms.size)
buf[ms.size] = '\0' buf[ms.size] = '\0'
yield buf yield buf

View file

@ -26,7 +26,6 @@ elif defined(posix):
else: else:
{.error: "OS module not ported to your operating system!".} {.error: "OS module not ported to your operating system!".}
include "system/ansi_c"
include ospaths include ospaths
when defined(posix): when defined(posix):
@ -37,6 +36,23 @@ when defined(posix):
var var
pathMax {.importc: "PATH_MAX", header: "<stdlib.h>".}: cint pathMax {.importc: "PATH_MAX", header: "<stdlib.h>".}: cint
proc c_remove(filename: cstring): cint {.
importc: "remove", header: "<stdio.h>".}
proc c_rename(oldname, newname: cstring): cint {.
importc: "rename", header: "<stdio.h>".}
proc c_system(cmd: cstring): cint {.
importc: "system", header: "<stdlib.h>".}
proc c_strerror(errnum: cint): cstring {.
importc: "strerror", header: "<string.h>".}
proc c_strlen(a: cstring): cint {.
importc: "strlen", header: "<string.h>", noSideEffect.}
proc c_getenv(env: cstring): cstring {.
importc: "getenv", header: "<stdlib.h>".}
proc c_putenv(env: cstring): cint {.
importc: "putenv", header: "<stdlib.h>".}
var errno {.importc, header: "<errno.h>".}: cint
proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} = proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
## Retrieves the operating system's error flag, ``errno``. ## Retrieves the operating system's error flag, ``errno``.
## On Windows ``GetLastError`` is checked before ``errno``. ## On Windows ``GetLastError`` is checked before ``errno``.
@ -61,7 +77,7 @@ proc osErrorMsg*(): string {.rtl, extern: "nos$1", deprecated.} =
result = $msgbuf result = $msgbuf
if msgbuf != nil: localFree(msgbuf) if msgbuf != nil: localFree(msgbuf)
if errno != 0'i32: if errno != 0'i32:
result = $os.strerror(errno) result = $os.c_strerror(errno)
{.push warning[deprecated]: off.} {.push warning[deprecated]: off.}
proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1", proc raiseOSError*(msg: string = "") {.noinline, rtl, extern: "nos$1",
@ -114,7 +130,7 @@ proc osErrorMsg*(errorCode: OSErrorCode): string =
if msgbuf != nil: localFree(msgbuf) if msgbuf != nil: localFree(msgbuf)
else: else:
if errorCode != OSErrorCode(0'i32): if errorCode != OSErrorCode(0'i32):
result = $os.strerror(errorCode.int32) result = $os.c_strerror(errorCode.int32)
proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} = proc raiseOSError*(errorCode: OSErrorCode; additionalInfo = "") {.noinline.} =
## Raises an ``OSError`` exception. The ``errorCode`` will determine the ## Raises an ``OSError`` exception. The ``errorCode`` will determine the

View file

@ -25,6 +25,28 @@
## echo "##", val, "##" ## echo "##", val, "##"
## close(x) ## close(x)
## ##
## For CSV files with a header row, the header can be read and then used as a
## reference for item access with `rowEntry <#rowEntry.CsvParser.string>`_:
##
## .. code-block:: nim
## import parsecsv
## import os
## # Prepare a file
## var csv_content = """One,Two,Three,Four
## 1,2,3,4
## 10,20,30,40
## 100,200,300,400
## """
## writeFile("temp.csv", content)
##
## var p: CsvParser
## p.open("temp.csv")
## p.readHeaderRow()
## while p.readRow():
## echo "new row: "
## for col in items(p.headers):
## echo "##", col, ":", p.rowEntry(col), "##"
## p.close()
import import
lexbase, streams lexbase, streams
@ -37,6 +59,9 @@ type
sep, quote, esc: char sep, quote, esc: char
skipWhite: bool skipWhite: bool
currRow: int currRow: int
headers*: seq[string] ## The columns that are defined in the csv file
## (read using `readHeaderRow <#readHeaderRow.CsvParser>`_).
## Used with `rowEntry <#rowEntry.CsvParser.string>`_).
CsvError* = object of IOError ## exception that is raised if CsvError* = object of IOError ## exception that is raised if
## a parsing error occurs ## a parsing error occurs
@ -177,6 +202,22 @@ proc close*(my: var CsvParser) {.inline.} =
## closes the parser `my` and its associated input stream. ## closes the parser `my` and its associated input stream.
lexbase.close(my) lexbase.close(my)
proc readHeaderRow*(my: var CsvParser) =
## Reads the first row and creates a look-up table for column numbers
## See also `rowEntry <#rowEntry.CsvParser.string>`_.
var present = my.readRow()
if present:
my.headers = my.row
proc rowEntry*(my: var CsvParser, entry: string): string =
## Reads a specified `entry` from the current row.
##
## Assumes that `readHeaderRow <#readHeaderRow.CsvParser>`_ has already been
## called.
var index = my.headers.find(entry)
if index >= 0:
result = my.row[index]
when not defined(testing) and isMainModule: when not defined(testing) and isMainModule:
import os import os
var s = newFileStream(paramStr(1), fmRead) var s = newFileStream(paramStr(1), fmRead)
@ -189,3 +230,35 @@ when not defined(testing) and isMainModule:
echo "##", val, "##" echo "##", val, "##"
close(x) close(x)
when isMainModule:
import os
import strutils
block: # Tests for reading the header row
var content = "One,Two,Three,Four\n1,2,3,4\n10,20,30,40,\n100,200,300,400\n"
writeFile("temp.csv", content)
var p: CsvParser
p.open("temp.csv")
p.readHeaderRow()
while p.readRow():
var zeros = repeat('0', p.currRow-2)
doAssert p.rowEntry("One") == "1" & zeros
doAssert p.rowEntry("Two") == "2" & zeros
doAssert p.rowEntry("Three") == "3" & zeros
doAssert p.rowEntry("Four") == "4" & zeros
p.close()
when not defined(testing):
var parser: CsvParser
parser.open("temp.csv")
parser.readHeaderRow()
while parser.readRow():
echo "new row: "
for col in items(parser.headers):
echo "##", col, ":", parser.rowEntry(col), "##"
parser.close()
removeFile("temp.csv")
# Tidy up
removeFile("temp.csv")

View file

@ -306,6 +306,8 @@ proc peekLine*(s: Stream): TaintedString =
defer: setPosition(s, pos) defer: setPosition(s, pos)
result = readLine(s) result = readLine(s)
when not defined(js):
type type
StringStream* = ref StringStreamObj ## a stream that encapsulates a string StringStream* = ref StringStreamObj ## a stream that encapsulates a string
StringStreamObj* = object of StreamObj StringStreamObj* = object of StreamObj
@ -365,8 +367,6 @@ proc newStringStream*(s: string = ""): StringStream =
result.peekDataImpl = ssPeekData result.peekDataImpl = ssPeekData
result.writeDataImpl = ssWriteData result.writeDataImpl = ssWriteData
when not defined(js):
type type
FileStream* = ref FileStreamObj ## a stream that encapsulates a `File` FileStream* = ref FileStreamObj ## a stream that encapsulates a `File`
FileStreamObj* = object of Stream FileStreamObj* = object of Stream

View file

@ -51,6 +51,9 @@ const
# Illegal characters # Illegal characters
illegalChars = {'>', '<', '&', '"'} illegalChars = {'>', '<', '&', '"'}
# standard xml: attribute names
# see https://www.w3.org/XML/1998/namespace
stdattrnames = ["lang", "space", "base", "id"]
type type
Feature = tuple[name: string, version: string] Feature = tuple[name: string, version: string]
@ -229,12 +232,15 @@ proc createAttributeNS*(doc: PDocument, namespaceURI: string, qualifiedName: str
raise newException(EInvalidCharacterErr, "Invalid character") raise newException(EInvalidCharacterErr, "Invalid character")
# Exceptions # Exceptions
if qualifiedName.contains(':'): if qualifiedName.contains(':'):
let qfnamespaces = qualifiedName.toLower().split(':')
if isNil(namespaceURI): if isNil(namespaceURI):
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
elif qualifiedName.split(':')[0].toLower() == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace": elif qfnamespaces[0] == "xml" and
namespaceURI != "http://www.w3.org/XML/1998/namespace" and
qfnamespaces[1] notin stdattrnames:
raise newException(ENamespaceErr, raise newException(ENamespaceErr,
"When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"") "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")
elif qualifiedName.split(':')[1].toLower() == "xmlns" and namespaceURI != "http://www.w3.org/2000/xmlns/": elif qfnamespaces[1] == "xmlns" and namespaceURI != "http://www.w3.org/2000/xmlns/":
raise newException(ENamespaceErr, raise newException(ENamespaceErr,
"When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"") "When the namespace prefix is \"xmlns\" namespaceURI has to be \"http://www.w3.org/2000/xmlns/\"")
@ -305,9 +311,12 @@ proc createElement*(doc: PDocument, tagName: string): PElement =
proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement = proc createElementNS*(doc: PDocument, namespaceURI: string, qualifiedName: string): PElement =
## Creates an element of the given qualified name and namespace URI. ## Creates an element of the given qualified name and namespace URI.
if qualifiedName.contains(':'): if qualifiedName.contains(':'):
let qfnamespaces = qualifiedName.toLower().split(':')
if isNil(namespaceURI): if isNil(namespaceURI):
raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil") raise newException(ENamespaceErr, "When qualifiedName contains a prefix namespaceURI cannot be nil")
elif qualifiedName.split(':')[0].toLower() == "xml" and namespaceURI != "http://www.w3.org/XML/1998/namespace": elif qfnamespaces[0] == "xml" and
namespaceURI != "http://www.w3.org/XML/1998/namespace" and
qfnamespaces[1] notin stdattrnames:
raise newException(ENamespaceErr, raise newException(ENamespaceErr,
"When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"") "When the namespace prefix is \"xml\" namespaceURI has to be \"http://www.w3.org/XML/1998/namespace\"")

View file

@ -1593,34 +1593,32 @@ proc substr*(s: string, first, last: int): string {.
## is used instead: This means ``substr`` can also be used to `cut`:idx: ## is used instead: This means ``substr`` can also be used to `cut`:idx:
## or `limit`:idx: a string's length. ## or `limit`:idx: a string's length.
when not defined(nimscript): when not defined(nimscript) and not defined(JS):
proc zeroMem*(p: pointer, size: Natural) {.importc, noDecl, benign.} proc zeroMem*(p: pointer, size: Natural) {.inline, benign.}
## overwrites the contents of the memory at ``p`` with the value 0. ## overwrites the contents of the memory at ``p`` with the value 0.
## Exactly ``size`` bytes will be overwritten. Like any procedure ## Exactly ``size`` bytes will be overwritten. Like any procedure
## dealing with raw memory this is *unsafe*. ## dealing with raw memory this is *unsafe*.
proc copyMem*(dest, source: pointer, size: Natural) {. proc copyMem*(dest, source: pointer, size: Natural) {.inline, benign.}
importc: "memcpy", header: "<string.h>", benign.}
## copies the contents from the memory at ``source`` to the memory ## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
## regions may not overlap. Like any procedure dealing with raw ## regions may not overlap. Like any procedure dealing with raw
## memory this is *unsafe*. ## memory this is *unsafe*.
proc moveMem*(dest, source: pointer, size: Natural) {. proc moveMem*(dest, source: pointer, size: Natural) {.inline, benign.}
importc: "memmove", header: "<string.h>", benign.}
## copies the contents from the memory at ``source`` to the memory ## copies the contents from the memory at ``source`` to the memory
## at ``dest``. Exactly ``size`` bytes will be copied. The memory ## at ``dest``. Exactly ``size`` bytes will be copied. The memory
## regions may overlap, ``moveMem`` handles this case appropriately ## regions may overlap, ``moveMem`` handles this case appropriately
## and is thus somewhat more safe than ``copyMem``. Like any procedure ## and is thus somewhat more safe than ``copyMem``. Like any procedure
## dealing with raw memory this is still *unsafe*, though. ## dealing with raw memory this is still *unsafe*, though.
proc equalMem*(a, b: pointer, size: Natural): bool {. proc equalMem*(a, b: pointer, size: Natural): bool {.inline, noSideEffect.}
importc: "equalMem", noDecl, noSideEffect.}
## compares the memory blocks ``a`` and ``b``. ``size`` bytes will ## compares the memory blocks ``a`` and ``b``. ``size`` bytes will
## be compared. If the blocks are equal, true is returned, false ## be compared. If the blocks are equal, true is returned, false
## otherwise. Like any procedure dealing with raw memory this is ## otherwise. Like any procedure dealing with raw memory this is
## *unsafe*. ## *unsafe*.
when not defined(nimscript):
when hasAlloc: when hasAlloc:
proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.} proc alloc*(size: Natural): pointer {.noconv, rtl, tags: [], benign.}
## allocates a new memory block with at least ``size`` bytes. The ## allocates a new memory block with at least ``size`` bytes. The
@ -2618,11 +2616,21 @@ when not defined(JS): #and not defined(nimscript):
{.deprecated: [TFile: File, TFileHandle: FileHandle, TFileMode: FileMode].} {.deprecated: [TFile: File, TFileHandle: FileHandle, TFileMode: FileMode].}
when not defined(nimscript):
include "system/ansi_c" include "system/ansi_c"
when not defined(nimscript):
proc cmp(x, y: string): int = proc cmp(x, y: string): int =
result = int(c_strcmp(x, y)) result = int(c_strcmp(x, y))
proc zeroMem(p: pointer, size: Natural) =
c_memset(p, 0, size)
proc copyMem(dest, source: pointer, size: Natural) =
c_memcpy(dest, source, size)
proc moveMem(dest, source: pointer, size: Natural) =
c_memmove(dest, source, size)
proc equalMem(a, b: pointer, size: Natural): bool =
c_memcmp(a, b, size) == 0
else: else:
proc cmp(x, y: string): int = proc cmp(x, y: string): int =
if x < y: result = -1 if x < y: result = -1
@ -2644,22 +2652,6 @@ when not defined(JS): #and not defined(nimscript):
## Raises an IO exception in case of an error. ## Raises an IO exception in case of an error.
when not defined(nimscript) and hostOS != "standalone": when not defined(nimscript) and hostOS != "standalone":
when defined(windows):
# work-around C's sucking abstraction:
# BUGFIX: stdin and stdout should be binary files!
proc setmode(handle, mode: int) {.importc: "setmode",
header: "<io.h>".}
proc fileno(f: C_TextFileStar): int {.importc: "fileno",
header: "<fcntl.h>".}
var
O_BINARY {.importc: "O_BINARY", nodecl.}: int
# we use binary mode on Windows:
setmode(fileno(c_stdin), O_BINARY)
setmode(fileno(c_stdout), O_BINARY)
when defined(endb):
proc endbStep()
# text file handling: # text file handling:
var var
@ -2670,6 +2662,21 @@ when not defined(JS): #and not defined(nimscript):
stderr* {.importc: "stderr", header: "<stdio.h>".}: File stderr* {.importc: "stderr", header: "<stdio.h>".}: File
## The standard error stream. ## The standard error stream.
when defined(windows):
# work-around C's sucking abstraction:
# BUGFIX: stdin and stdout should be binary files!
proc c_setmode(handle, mode: cint) {.importc: "_setmode",
header: "<io.h>".}
var
O_BINARY {.importc: "O_BINARY", nodecl.}: cint
# we use binary mode on Windows:
c_setmode(c_fileno(stdin), O_BINARY)
c_setmode(c_fileno(stdout), O_BINARY)
when defined(endb):
proc endbStep()
when defined(useStdoutAsStdmsg): when defined(useStdoutAsStdmsg):
template stdmsg*: File = stdout template stdmsg*: File = stdout
else: else:
@ -2711,17 +2718,16 @@ when not defined(JS): #and not defined(nimscript):
proc setStdIoUnbuffered() {.tags: [], benign.} proc setStdIoUnbuffered() {.tags: [], benign.}
## Configures `stdin`, `stdout` and `stderr` to be unbuffered. ## Configures `stdin`, `stdout` and `stderr` to be unbuffered.
proc close*(f: File) {.importc: "fclose", header: "<stdio.h>", tags: [].} proc close*(f: File) {.tags: [].}
## Closes the file. ## Closes the file.
proc endOfFile*(f: File): bool {.tags: [], benign.} proc endOfFile*(f: File): bool {.tags: [], benign.}
## Returns true iff `f` is at the end. ## Returns true iff `f` is at the end.
proc readChar*(f: File): char {. proc readChar*(f: File): char {.tags: [ReadIOEffect].}
importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
## Reads a single character from the stream `f`. ## Reads a single character from the stream `f`.
proc flushFile*(f: File) {.
importc: "fflush", header: "<stdio.h>", tags: [WriteIOEffect].} proc flushFile*(f: File) {.tags: [WriteIOEffect].}
## Flushes `f`'s buffer. ## Flushes `f`'s buffer.
proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.} proc readAll*(file: File): TaintedString {.tags: [ReadIOEffect], benign.}
@ -2827,8 +2833,7 @@ when not defined(JS): #and not defined(nimscript):
## retrieves the current position of the file pointer that is used to ## retrieves the current position of the file pointer that is used to
## read from the file `f`. The file's first byte has the index zero. ## read from the file `f`. The file's first byte has the index zero.
proc getFileHandle*(f: File): FileHandle {.importc: "fileno", proc getFileHandle*(f: File): FileHandle
header: "<stdio.h>"}
## returns the OS file handle of the file ``f``. This is only useful for ## returns the OS file handle of the file ``f``. This is only useful for
## platform specific programming. ## platform specific programming.

View file

@ -324,9 +324,9 @@ proc contains[T](list, x: T): bool =
proc writeFreeList(a: MemRegion) = proc writeFreeList(a: MemRegion) =
var it = a.freeChunksList var it = a.freeChunksList
c_fprintf(c_stdout, "freeChunksList: %p\n", it) c_fprintf(stdout, "freeChunksList: %p\n", it)
while it != nil: while it != nil:
c_fprintf(c_stdout, "it: %p, next: %p, prev: %p\n", c_fprintf(stdout, "it: %p, next: %p, prev: %p\n",
it, it.next, it.prev) it, it.next, it.prev)
it = it.next it = it.next

View file

@ -13,41 +13,22 @@
{.push hints:off} {.push hints:off}
proc c_strcmp(a, b: cstring): cint {.header: "<string.h>", proc c_memchr(s: pointer, c: cint, n: csize): pointer {.
noSideEffect, importc: "strcmp".} importc: "memchr", header: "<string.h>".}
proc c_memcmp(a, b: cstring, size: int): cint {.header: "<string.h>", proc c_memcmp(a, b: pointer, size: csize): cint {.
noSideEffect, importc: "memcmp".} importc: "memcmp", header: "<string.h>", noSideEffect.}
proc c_memcpy(a, b: cstring, size: int) {.header: "<string.h>", importc: "memcpy".} proc c_memcpy(a, b: pointer, size: csize): pointer {.
proc c_strlen(a: cstring): int {.header: "<string.h>", importc: "memcpy", header: "<string.h>", discardable.}
noSideEffect, importc: "strlen".} proc c_memmove(a, b: pointer, size: csize): pointer {.
proc c_memset(p: pointer, value: cint, size: int) {. importc: "memmove", header: "<string.h>",discardable.}
header: "<string.h>", importc: "memset".} proc c_memset(p: pointer, value: cint, size: csize): pointer {.
importc: "memset", header: "<string.h>", discardable.}
when not declared(File): proc c_strcmp(a, b: cstring): cint {.
type importc: "strcmp", header: "<string.h>", noSideEffect.}
C_TextFile {.importc: "FILE", header: "<stdio.h>",
final, incompleteStruct.} = object
C_BinaryFile {.importc: "FILE", header: "<stdio.h>",
final, incompleteStruct.} = object
C_TextFileStar = ptr C_TextFile
C_BinaryFileStar = ptr C_BinaryFile
else:
type
C_TextFileStar = File
C_BinaryFileStar = File
type type
C_JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = object C_JmpBuf {.importc: "jmp_buf", header: "<setjmp.h>".} = object
when not defined(vm):
var
c_stdin {.importc: "stdin", nodecl.}: C_TextFileStar
c_stdout {.importc: "stdout", nodecl.}: C_TextFileStar
c_stderr {.importc: "stderr", nodecl.}: C_TextFileStar
# constants faked as variables:
when not declared(SIGINT):
when NoFakeVars:
when defined(windows): when defined(windows):
const const
SIGABRT = cint(22) SIGABRT = cint(22)
@ -66,6 +47,7 @@ when not declared(SIGINT):
SIGTERM = cint(15) SIGTERM = cint(15)
SIGPIPE = cint(13) SIGPIPE = cint(13)
else: else:
when NoFakeVars:
{.error: "SIGABRT not ported to your platform".} {.error: "SIGABRT not ported to your platform".}
else: else:
var var
@ -78,10 +60,7 @@ when not declared(SIGINT):
var SIGPIPE {.importc: "SIGPIPE", nodecl.}: cint var SIGPIPE {.importc: "SIGPIPE", nodecl.}: cint
when defined(macosx): when defined(macosx):
when NoFakeVars:
const SIGBUS = cint(10) const SIGBUS = cint(10)
else:
var SIGBUS {.importc: "SIGBUS", nodecl.}: cint
else: else:
template SIGBUS: expr = SIGSEGV template SIGBUS: expr = SIGSEGV
@ -103,72 +82,27 @@ else:
proc c_setjmp(jmpb: C_JmpBuf): cint {. proc c_setjmp(jmpb: C_JmpBuf): cint {.
header: "<setjmp.h>", importc: "setjmp".} header: "<setjmp.h>", importc: "setjmp".}
proc c_signal(sign: cint, handler: proc (a: cint) {.noconv.}) {. type c_sighandler_t = proc (a: cint) {.noconv.}
importc: "signal", header: "<signal.h>".} proc c_signal(sign: cint, handler: proc (a: cint) {.noconv.}): c_sighandler_t {.
proc c_raise(sign: cint) {.importc: "raise", header: "<signal.h>".} importc: "signal", header: "<signal.h>", discardable.}
proc c_fputs(c: cstring, f: C_TextFileStar) {.importc: "fputs", proc c_fprintf(f: File, frmt: cstring): cint {.
header: "<stdio.h>".} importc: "fprintf", header: "<stdio.h>", varargs, discardable.}
proc c_fgets(c: cstring, n: int, f: C_TextFileStar): cstring {. proc c_printf(frmt: cstring): cint {.
importc: "fgets", header: "<stdio.h>".} importc: "printf", header: "<stdio.h>", varargs, discardable.}
proc c_fgetc(stream: C_TextFileStar): int {.importc: "fgetc",
header: "<stdio.h>".}
proc c_ungetc(c: int, f: C_TextFileStar) {.importc: "ungetc",
header: "<stdio.h>".}
proc c_putc(c: char, stream: C_TextFileStar) {.importc: "putc",
header: "<stdio.h>".}
proc c_fprintf(f: C_TextFileStar, frmt: cstring) {.
importc: "fprintf", header: "<stdio.h>", varargs.}
proc c_printf(frmt: cstring) {.
importc: "printf", header: "<stdio.h>", varargs.}
proc c_fopen(filename, mode: cstring): C_TextFileStar {. proc c_sprintf(buf, frmt: cstring): cint {.
importc: "fopen", header: "<stdio.h>".} importc: "sprintf", header: "<stdio.h>", varargs, noSideEffect.}
proc c_fclose(f: C_TextFileStar) {.importc: "fclose", header: "<stdio.h>".}
proc c_sprintf(buf, frmt: cstring): cint {.header: "<stdio.h>",
importc: "sprintf", varargs, noSideEffect.}
# we use it only in a way that cannot lead to security issues # we use it only in a way that cannot lead to security issues
proc c_fread(buf: pointer, size, n: int, f: C_BinaryFileStar): int {. proc c_fileno(f: File): cint {.
importc: "fread", header: "<stdio.h>".} importc: "fileno", header: "<fcntl.h>".}
proc c_fseek(f: C_BinaryFileStar, offset: clong, whence: int): int {.
importc: "fseek", header: "<stdio.h>".}
proc c_fwrite(buf: pointer, size, n: int, f: C_BinaryFileStar): int {. proc c_malloc(size: csize): pointer {.
importc: "fwrite", header: "<stdio.h>".} importc: "malloc", header: "<stdlib.h>".}
proc c_free(p: pointer) {.
proc c_exit(errorcode: cint) {.importc: "exit", header: "<stdlib.h>".} importc: "free", header: "<stdlib.h>".}
proc c_ferror(stream: C_TextFileStar): bool {. proc c_realloc(p: pointer, newsize: csize): pointer {.
importc: "ferror", header: "<stdio.h>".}
proc c_fflush(stream: C_TextFileStar) {.importc: "fflush", header: "<stdio.h>".}
proc c_abort() {.importc: "abort", header: "<stdlib.h>".}
proc c_feof(stream: C_TextFileStar): bool {.
importc: "feof", header: "<stdio.h>".}
proc c_malloc(size: int): pointer {.importc: "malloc", header: "<stdlib.h>".}
proc c_free(p: pointer) {.importc: "free", header: "<stdlib.h>".}
proc c_realloc(p: pointer, newsize: int): pointer {.
importc: "realloc", header: "<stdlib.h>".} importc: "realloc", header: "<stdlib.h>".}
when hostOS != "standalone":
when not declared(errno):
when defined(NimrodVM):
var vmErrnoWrapper {.importc.}: ptr cint
template errno: expr =
bind vmErrnoWrapper
vmErrnoWrapper[]
else:
var errno {.importc, header: "<errno.h>".}: cint ## error variable
proc strerror(errnum: cint): cstring {.importc, header: "<string.h>".}
proc c_remove(filename: cstring): cint {.
importc: "remove", header: "<stdio.h>".}
proc c_rename(oldname, newname: cstring): cint {.
importc: "rename", header: "<stdio.h>".}
proc c_system(cmd: cstring): cint {.importc: "system", header: "<stdlib.h>".}
proc c_getenv(env: cstring): cstring {.importc: "getenv", header: "<stdlib.h>".}
proc c_putenv(env: cstring): cint {.importc: "putenv", header: "<stdlib.h>".}
{.pop} {.pop}

View file

@ -51,7 +51,6 @@ proc chckRangeF(x, a, b: float): float =
proc chckNil(p: pointer) = proc chckNil(p: pointer) =
if p == nil: if p == nil:
sysFatal(ValueError, "attempt to write to a nil address") sysFatal(ValueError, "attempt to write to a nil address")
#c_raise(SIGSEGV)
proc chckObj(obj, subclass: PNimType) {.compilerproc.} = proc chckObj(obj, subclass: PNimType) {.compilerproc.} =
# checks if obj is of type subclass: # checks if obj is of type subclass:

View file

@ -108,8 +108,8 @@ proc fileMatches(c, bp: cstring): bool =
# and the character for the suffix does not exist or # and the character for the suffix does not exist or
# is one of: \ / : # is one of: \ / :
# depending on the OS case does not matter! # depending on the OS case does not matter!
var blen: int = c_strlen(bp) var blen: int = bp.len
var clen: int = c_strlen(c) var clen: int = c.len
if blen > clen: return false if blen > clen: return false
# check for \ / : # check for \ / :
if clen-blen-1 >= 0 and c[clen-blen-1] notin {'\\', '/', ':'}: if clen-blen-1 >= 0 and c[clen-blen-1] notin {'\\', '/', ':'}:

View file

@ -36,7 +36,7 @@ proc copyDeepString(src: NimString): NimString {.inline.} =
if src != nil: if src != nil:
result = rawNewStringNoInit(src.len) result = rawNewStringNoInit(src.len)
result.len = src.len result.len = src.len
c_memcpy(result.data, src.data, src.len + 1) copyMem(addr(result.data), addr(src.data), src.len + 1)
proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) = proc genericDeepCopyAux(dest, src: pointer, mt: PNimType) =
var var

View file

@ -52,11 +52,14 @@ when defined(posix):
# #
# c stuff: # c stuff:
when defined(linux) or defined(macosx):
const RTLD_NOW = cint(2)
else:
var var
RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: int RTLD_NOW {.importc: "RTLD_NOW", header: "<dlfcn.h>".}: cint
proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".} proc dlclose(lib: LibHandle) {.importc, header: "<dlfcn.h>".}
proc dlopen(path: cstring, mode: int): LibHandle {. proc dlopen(path: cstring, mode: cint): LibHandle {.
importc, header: "<dlfcn.h>".} importc, header: "<dlfcn.h>".}
proc dlsym(lib: LibHandle, name: cstring): ProcAddr {. proc dlsym(lib: LibHandle, name: cstring): ProcAddr {.
importc, header: "<dlfcn.h>".} importc, header: "<dlfcn.h>".}

View file

@ -329,14 +329,14 @@ proc dbgStackFrame(s: cstring, start: int, currFrame: PFrame) =
proc readLine(f: File, line: var StaticStr): bool = proc readLine(f: File, line: var StaticStr): bool =
while true: while true:
var c = fgetc(f) var c = c_fgetc(f)
if c < 0'i32: if c < 0'i32:
if line.len > 0: break if line.len > 0: break
else: return false else: return false
if c == 10'i32: break # LF if c == 10'i32: break # LF
if c == 13'i32: # CR if c == 13'i32: # CR
c = fgetc(f) # is the next char LF? c = c_fgetc(f) # is the next char LF?
if c != 10'i32: ungetc(c, f) # no, put the character back if c != 10'i32: discard c_ungetc(c, f) # no, put the character back
break break
add line, chr(int(c)) add line, chr(int(c))
result = true result = true

View file

@ -255,7 +255,7 @@ proc raiseExceptionAux(e: ref Exception) =
add(buf, "Error: unhandled exception: ") add(buf, "Error: unhandled exception: ")
if not isNil(e.msg): add(buf, e.msg) if not isNil(e.msg): add(buf, e.msg)
add(buf, " [") add(buf, " [")
xadd(buf, e.name, c_strlen(e.name)) xadd(buf, e.name, e.name.len)
add(buf, "]\n") add(buf, "]\n")
showErrorMessage(buf) showErrorMessage(buf)
quitOrDebug() quitOrDebug()

View file

@ -152,10 +152,10 @@ proc writeCell(msg: cstring, c: PCell) =
var kind = -1 var kind = -1
if c.typ != nil: kind = ord(c.typ.kind) if c.typ != nil: kind = ord(c.typ.kind)
when leakDetector: when leakDetector:
c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld from %s(%ld)\n", c_fprintf(stdout, "[GC] %s: %p %d rc=%ld from %s(%ld)\n",
msg, c, kind, c.refcount shr rcShift, c.filename, c.line) msg, c, kind, c.refcount shr rcShift, c.filename, c.line)
else: else:
c_fprintf(c_stdout, "[GC] %s: %p %d rc=%ld; color=%ld\n", c_fprintf(stdout, "[GC] %s: %p %d rc=%ld; color=%ld\n",
msg, c, kind, c.refcount shr rcShift, c.color) msg, c, kind, c.refcount shr rcShift, c.color)
template gcTrace(cell, state: expr): stmt {.immediate.} = template gcTrace(cell, state: expr): stmt {.immediate.} =

View file

@ -272,7 +272,7 @@ when false:
proc copyDeepString(dr: var MemRegion; stack: var PointerStackChunk; src: NimString): NimString {.inline.} = proc copyDeepString(dr: var MemRegion; stack: var PointerStackChunk; src: NimString): NimString {.inline.} =
result = rawNewStringNoInit(dr, src.len) result = rawNewStringNoInit(dr, src.len)
result.len = src.len result.len = src.len
c_memcpy(result.data, src.data, src.len + 1) copyMem(result.data, src.data, src.len + 1)
proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk; proc genericDeepCopyAux(dr: var MemRegion; stack: var PointerStackChunk;
dest, src: pointer, mt: PNimType) = dest, src: pointer, mt: PNimType) =
@ -417,15 +417,15 @@ proc asgnRefNoCycle(dest: PPointer, src: pointer) {.compilerproc, inline.} =
dest[] = src dest[] = src
proc alloc(size: Natural): pointer = proc alloc(size: Natural): pointer =
result = cmalloc(size) result = c_malloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc alloc0(size: Natural): pointer = proc alloc0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc realloc(p: pointer, newsize: Natural): pointer = proc realloc(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = c_realloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = cfree(p) proc dealloc(p: pointer) = c_free(p)
proc alloc0(r: var MemRegion; size: Natural): pointer = proc alloc0(r: var MemRegion; size: Natural): pointer =
# ignore the region. That is correct for the channels module # ignore the region. That is correct for the channels module
@ -435,15 +435,15 @@ proc alloc0(r: var MemRegion; size: Natural): pointer =
proc dealloc(r: var MemRegion; p: pointer) = dealloc(p) proc dealloc(r: var MemRegion; p: pointer) = dealloc(p)
proc allocShared(size: Natural): pointer = proc allocShared(size: Natural): pointer =
result = cmalloc(size) result = c_malloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc allocShared0(size: Natural): pointer = proc allocShared0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc reallocShared(p: pointer, newsize: Natural): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = c_realloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = cfree(p) proc deallocShared(p: pointer) = c_free(p)
when hasThreadSupport: when hasThreadSupport:
proc getFreeSharedMem(): int = 0 proc getFreeSharedMem(): int = 0

View file

@ -300,7 +300,7 @@ elif defined(gogc):
proc setStackBottom(theStackBottom: pointer) = discard proc setStackBottom(theStackBottom: pointer) = discard
proc alloc(size: Natural): pointer = proc alloc(size: Natural): pointer =
result = cmalloc(size) result = c_malloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc alloc0(size: Natural): pointer = proc alloc0(size: Natural): pointer =
@ -308,13 +308,13 @@ elif defined(gogc):
zeroMem(result, size) zeroMem(result, size)
proc realloc(p: pointer, newsize: Natural): pointer = proc realloc(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = c_realloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc dealloc(p: pointer) = cfree(p) proc dealloc(p: pointer) = c_free(p)
proc allocShared(size: Natural): pointer = proc allocShared(size: Natural): pointer =
result = cmalloc(size) result = c_malloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc allocShared0(size: Natural): pointer = proc allocShared0(size: Natural): pointer =
@ -322,10 +322,10 @@ elif defined(gogc):
zeroMem(result, size) zeroMem(result, size)
proc reallocShared(p: pointer, newsize: Natural): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = c_realloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = cfree(p) proc deallocShared(p: pointer) = c_free(p)
when hasThreadSupport: when hasThreadSupport:
proc getFreeSharedMem(): int = discard proc getFreeSharedMem(): int = discard
@ -389,7 +389,7 @@ elif defined(nogc) and defined(useMalloc):
when not defined(useNimRtl): when not defined(useNimRtl):
proc alloc(size: Natural): pointer = proc alloc(size: Natural): pointer =
var x = cmalloc(size + sizeof(size)) var x = c_malloc(size + sizeof(size))
if x == nil: raiseOutOfMem() if x == nil: raiseOutOfMem()
cast[ptr int](x)[] = size cast[ptr int](x)[] = size
@ -402,7 +402,7 @@ elif defined(nogc) and defined(useMalloc):
var x = cast[pointer](cast[int](p) - sizeof(newsize)) var x = cast[pointer](cast[int](p) - sizeof(newsize))
let oldsize = cast[ptr int](x)[] let oldsize = cast[ptr int](x)[]
x = crealloc(x, newsize + sizeof(newsize)) x = c_realloc(x, newsize + sizeof(newsize))
if x == nil: raiseOutOfMem() if x == nil: raiseOutOfMem()
@ -412,18 +412,18 @@ elif defined(nogc) and defined(useMalloc):
if newsize > oldsize: if newsize > oldsize:
zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize) zeroMem(cast[pointer](cast[int](result) + oldsize), newsize - oldsize)
proc dealloc(p: pointer) = cfree(cast[pointer](cast[int](p) - sizeof(int))) proc dealloc(p: pointer) = c_free(cast[pointer](cast[int](p) - sizeof(int)))
proc allocShared(size: Natural): pointer = proc allocShared(size: Natural): pointer =
result = cmalloc(size) result = c_malloc(size)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc allocShared0(size: Natural): pointer = proc allocShared0(size: Natural): pointer =
result = alloc(size) result = alloc(size)
zeroMem(result, size) zeroMem(result, size)
proc reallocShared(p: pointer, newsize: Natural): pointer = proc reallocShared(p: pointer, newsize: Natural): pointer =
result = crealloc(p, newsize) result = c_realloc(p, newsize)
if result == nil: raiseOutOfMem() if result == nil: raiseOutOfMem()
proc deallocShared(p: pointer) = cfree(p) proc deallocShared(p: pointer) = c_free(p)
proc GC_disable() = discard proc GC_disable() = discard
proc GC_enable() = discard proc GC_enable() = discard

View file

@ -68,7 +68,7 @@ when defined(emscripten):
mmapDescr.realSize = realSize mmapDescr.realSize = realSize
mmapDescr.realPointer = realPointer mmapDescr.realPointer = realPointer
c_fprintf(c_stdout, "[Alloc] size %d %d realSize:%d realPos:%d\n", block_size, cast[int](result), realSize, cast[int](realPointer)) #c_fprintf(c_stdout, "[Alloc] size %d %d realSize:%d realPos:%d\n", block_size, cast[int](result), realSize, cast[int](realPointer))
proc osTryAllocPages(size: int): pointer = osAllocPages(size) proc osTryAllocPages(size: int): pointer = osAllocPages(size)
@ -87,6 +87,8 @@ elif defined(posix):
const MAP_ANONYMOUS = 0x1000 const MAP_ANONYMOUS = 0x1000
elif defined(solaris): elif defined(solaris):
const MAP_ANONYMOUS = 0x100 const MAP_ANONYMOUS = 0x100
elif defined(linux):
const MAP_ANONYMOUS = 0x20
else: else:
var var
MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint MAP_ANONYMOUS {.importc: "MAP_ANONYMOUS", header: "<sys/mman.h>".}: cint

View file

@ -16,43 +16,43 @@
# of the standard library! # of the standard library!
proc fputs(c: cstring, f: File) {.importc: "fputs", header: "<stdio.h>", proc c_fdopen(filehandle: cint, mode: cstring): File {.
tags: [WriteIOEffect].} importc: "fdopen", header: "<stdio.h>".}
proc fgets(c: cstring, n: int, f: File): cstring {. proc c_fputs(c: cstring, f: File): cint {.
importc: "fputs", header: "<stdio.h>", tags: [WriteIOEffect].}
proc c_fgets(c: cstring, n: cint, f: File): cstring {.
importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].} importc: "fgets", header: "<stdio.h>", tags: [ReadIOEffect].}
proc fgetc(stream: File): cint {.importc: "fgetc", header: "<stdio.h>", proc c_fgetc(stream: File): cint {.
tags: [ReadIOEffect].} importc: "fgetc", header: "<stdio.h>", tags: [ReadIOEffect].}
proc ungetc(c: cint, f: File) {.importc: "ungetc", header: "<stdio.h>", proc c_ungetc(c: cint, f: File): cint {.
tags: [].} importc: "ungetc", header: "<stdio.h>", tags: [].}
proc putc(c: char, stream: File) {.importc: "putc", header: "<stdio.h>", proc c_putc(c: cint, stream: File): cint {.
tags: [WriteIOEffect].} importc: "putc", header: "<stdio.h>", tags: [WriteIOEffect].}
proc fprintf(f: File, frmt: cstring) {.importc: "fprintf", proc c_fflush(f: File): cint {.
header: "<stdio.h>", varargs, tags: [WriteIOEffect].} importc: "fflush", header: "<stdio.h>".}
proc strlen(c: cstring): int {. proc c_fclose(f: File): cint {.
importc: "strlen", header: "<string.h>", tags: [].} importc: "fclose", header: "<stdio.h>".}
# C routine that is used here: # C routine that is used here:
proc fread(buf: pointer, size, n: int, f: File): int {. proc c_fread(buf: pointer, size, n: csize, f: File): csize {.
importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].} importc: "fread", header: "<stdio.h>", tags: [ReadIOEffect].}
proc fseek(f: File, offset: clong, whence: int): int {. proc c_fseek(f: File, offset: clong, whence: cint): cint {.
importc: "fseek", header: "<stdio.h>", tags: [].} importc: "fseek", header: "<stdio.h>", tags: [].}
proc ftell(f: File): int {.importc: "ftell", header: "<stdio.h>", tags: [].} proc c_ftell(f: File): clong {.
proc ferror(f: File): int {.importc: "ferror", header: "<stdio.h>", tags: [].} importc: "ftell", header: "<stdio.h>", tags: [].}
proc setvbuf(stream: File, buf: pointer, typ, size: cint): cint {. proc c_ferror(f: File): cint {.
importc, header: "<stdio.h>", tags: [].} importc: "ferror", header: "<stdio.h>", tags: [].}
proc memchr(s: pointer, c: cint, n: csize): pointer {. proc c_setvbuf(f: File, buf: pointer, mode: cint, size: csize): cint {.
importc: "memchr", header: "<string.h>", tags: [].} importc: "setvbuf", header: "<stdio.h>", tags: [].}
proc memset(s: pointer, c: cint, n: csize) {. proc c_fwrite(buf: pointer, size, n: csize, f: File): cint {.
header: "<string.h>", importc: "memset", tags: [].} importc: "fwrite", header: "<stdio.h>".}
proc fwrite(buf: pointer, size, n: int, f: File): int {.
importc: "fwrite", noDecl.}
proc raiseEIO(msg: string) {.noinline, noreturn.} = proc raiseEIO(msg: string) {.noinline, noreturn.} =
sysFatal(IOError, msg) sysFatal(IOError, msg)
{.push stackTrace:off, profiler:off.} {.push stackTrace:off, profiler:off.}
proc readBuffer(f: File, buffer: pointer, len: Natural): int = proc readBuffer(f: File, buffer: pointer, len: Natural): int =
result = fread(buffer, 1, len, f) result = c_fread(buffer, 1, len, f)
proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int = proc readBytes(f: File, a: var openArray[int8|uint8], start, len: Natural): int =
result = readBuffer(f, addr(a[start]), len) result = readBuffer(f, addr(a[start]), len)
@ -62,10 +62,10 @@ proc readChars(f: File, a: var openArray[char], start, len: Natural): int =
raiseEIO("buffer overflow: (start+len) > length of openarray buffer") raiseEIO("buffer overflow: (start+len) > length of openarray buffer")
result = readBuffer(f, addr(a[start]), len) result = readBuffer(f, addr(a[start]), len)
proc write(f: File, c: cstring) = fputs(c, f) proc write(f: File, c: cstring) = discard c_fputs(c, f)
proc writeBuffer(f: File, buffer: pointer, len: Natural): int = proc writeBuffer(f: File, buffer: pointer, len: Natural): int =
result = fwrite(buffer, 1, len, f) result = c_fwrite(buffer, 1, len, f)
proc writeBytes(f: File, a: openArray[int8|uint8], start, len: Natural): int = proc writeBytes(f: File, a: openArray[int8|uint8], start, len: Natural): int =
var x = cast[ptr array[0..1000_000_000, int8]](a) var x = cast[ptr array[0..1000_000_000, int8]](a)
@ -97,23 +97,28 @@ else:
const const
BufSize = 4000 BufSize = 4000
proc close*(f: File) = discard c_fclose(f)
proc readChar*(f: File): char = result = char(c_fgetc(f))
proc flushFile*(f: File) = discard c_fflush(f)
proc getFileHandle*(f: File): FileHandle = c_fileno(f)
proc readLine(f: File, line: var TaintedString): bool = proc readLine(f: File, line: var TaintedString): bool =
var pos = 0 var pos = 0
# Use the currently reserved space for a first try # Use the currently reserved space for a first try
when defined(nimscript): when defined(nimscript):
var space = 80 var space: cint = 80
else: else:
var space = cast[PGenericSeq](line.string).space var space: cint = cint(cast[PGenericSeq](line.string).space)
line.string.setLen(space) line.string.setLen(space)
while true: while true:
# memset to \l so that we can tell how far fgets wrote, even on EOF, where # memset to \l so that we can tell how far fgets wrote, even on EOF, where
# fgets doesn't append an \l # fgets doesn't append an \l
memset(addr line.string[pos], '\l'.ord, space) c_memset(addr line.string[pos], '\l'.ord, space)
if fgets(addr line.string[pos], space, f) == nil: if c_fgets(addr line.string[pos], space, f) == nil:
line.string.setLen(0) line.string.setLen(0)
return false return false
let m = memchr(addr line.string[pos], '\l'.ord, space) let m = c_memchr(addr line.string[pos], '\l'.ord, space)
if m != nil: if m != nil:
# \l found: Could be our own or the one by fgets, in any case, we're done # \l found: Could be our own or the one by fgets, in any case, we're done
var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0]) var last = cast[ByteAddress](m) - cast[ByteAddress](addr line.string[0])
@ -142,23 +147,23 @@ proc readLine(f: File): TaintedString =
proc write(f: File, i: int) = proc write(f: File, i: int) =
when sizeof(int) == 8: when sizeof(int) == 8:
fprintf(f, "%lld", i) c_fprintf(f, "%lld", i)
else: else:
fprintf(f, "%ld", i) c_fprintf(f, "%ld", i)
proc write(f: File, i: BiggestInt) = proc write(f: File, i: BiggestInt) =
when sizeof(BiggestInt) == 8: when sizeof(BiggestInt) == 8:
fprintf(f, "%lld", i) c_fprintf(f, "%lld", i)
else: else:
fprintf(f, "%ld", i) c_fprintf(f, "%ld", i)
proc write(f: File, b: bool) = proc write(f: File, b: bool) =
if b: write(f, "true") if b: write(f, "true")
else: write(f, "false") else: write(f, "false")
proc write(f: File, r: float32) = fprintf(f, "%g", r) proc write(f: File, r: float32) = c_fprintf(f, "%g", r)
proc write(f: File, r: BiggestFloat) = fprintf(f, "%g", r) proc write(f: File, r: BiggestFloat) = c_fprintf(f, "%g", r)
proc write(f: File, c: char) = putc(c, f) proc write(f: File, c: char) = discard c_putc(ord(c), f)
proc write(f: File, a: varargs[string, `$`]) = proc write(f: File, a: varargs[string, `$`]) =
for x in items(a): write(f, x) for x in items(a): write(f, x)
@ -178,15 +183,15 @@ proc readAllBuffer(file: File): string =
proc rawFileSize(file: File): int = proc rawFileSize(file: File): int =
# this does not raise an error opposed to `getFileSize` # this does not raise an error opposed to `getFileSize`
var oldPos = ftell(file) var oldPos = c_ftell(file)
discard fseek(file, 0, 2) # seek the end of the file discard c_fseek(file, 0, 2) # seek the end of the file
result = ftell(file) result = c_ftell(file)
discard fseek(file, clong(oldPos), 0) discard c_fseek(file, clong(oldPos), 0)
proc endOfFile(f: File): bool = proc endOfFile(f: File): bool =
# do not blame me; blame the ANSI C standard this is so brain-damaged # do not blame me; blame the ANSI C standard this is so brain-damaged
var c = fgetc(f) var c = c_fgetc(f)
ungetc(c, f) discard c_ungetc(c, f)
return c < 0'i32 return c < 0'i32
proc readAllFile(file: File, len: int): string = proc readAllFile(file: File, len: int): string =
@ -197,7 +202,7 @@ proc readAllFile(file: File, len: int): string =
if endOfFile(file): if endOfFile(file):
if bytes < len: if bytes < len:
result.setLen(bytes) result.setLen(bytes)
elif ferror(file) != 0: elif c_ferror(file) != 0:
raiseEIO("error while reading from file") raiseEIO("error while reading from file")
else: else:
# We read all the bytes but did not reach the EOF # We read all the bytes but did not reach the EOF
@ -272,6 +277,22 @@ const
# should not be translated. # should not be translated.
when defined(posix) and not defined(nimscript): when defined(posix) and not defined(nimscript):
when defined(linux) and defined(amd64):
type
Mode {.importc: "mode_t", header: "<sys/types.h>".} = cint
# fillers ensure correct size & offsets
Stat {.importc: "struct stat",
header: "<sys/stat.h>", final, pure.} = object ## struct stat
filler_1: array[24, char]
st_mode: Mode ## Mode of file
filler_2: array[144 - 24 - 4, char]
proc S_ISDIR(m: Mode): bool =
## Test for a directory.
(m and 0o170000) == 0o40000
else:
type type
Mode {.importc: "mode_t", header: "<sys/types.h>".} = cint Mode {.importc: "mode_t", header: "<sys/types.h>".} = cint
@ -282,7 +303,8 @@ when defined(posix) and not defined(nimscript):
proc S_ISDIR(m: Mode): bool {.importc, header: "<sys/stat.h>".} proc S_ISDIR(m: Mode): bool {.importc, header: "<sys/stat.h>".}
## Test for a directory. ## Test for a directory.
proc fstat(a1: cint, a2: var Stat): cint {.importc, header: "<sys/stat.h>".} proc c_fstat(a1: cint, a2: var Stat): cint {.
importc: "fstat", header: "<sys/stat.h>".}
proc open(f: var File, filename: string, proc open(f: var File, filename: string,
mode: FileMode = fmRead, mode: FileMode = fmRead,
@ -295,45 +317,38 @@ proc open(f: var File, filename: string,
# be opened. # be opened.
var f2 = cast[File](p) var f2 = cast[File](p)
var res: Stat var res: Stat
if fstat(getFileHandle(f2), res) >= 0'i32 and S_ISDIR(res.st_mode): if c_fstat(getFileHandle(f2), res) >= 0'i32 and S_ISDIR(res.st_mode):
close(f2) close(f2)
return false return false
result = true result = true
f = cast[File](p) f = cast[File](p)
if bufSize > 0 and bufSize <= high(cint).int: if bufSize > 0 and bufSize <= high(cint).int:
discard setvbuf(f, nil, IOFBF, bufSize.cint) discard c_setvbuf(f, nil, IOFBF, bufSize.cint)
elif bufSize == 0: elif bufSize == 0:
discard setvbuf(f, nil, IONBF, 0) discard c_setvbuf(f, nil, IONBF, 0)
proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool = proc reopen(f: File, filename: string, mode: FileMode = fmRead): bool =
var p: pointer = freopen(filename, FormatOpen[mode], f) var p: pointer = freopen(filename, FormatOpen[mode], f)
result = p != nil result = p != nil
proc fdopen(filehandle: FileHandle, mode: cstring): File {.
importc: "fdopen", header: "<stdio.h>".}
proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool = proc open(f: var File, filehandle: FileHandle, mode: FileMode): bool =
f = fdopen(filehandle, FormatOpen[mode]) f = c_fdopen(filehandle, FormatOpen[mode])
result = f != nil result = f != nil
proc setFilePos(f: File, pos: int64) = proc setFilePos(f: File, pos: int64) =
if fseek(f, clong(pos), 0) != 0: if c_fseek(f, clong(pos), 0) != 0:
raiseEIO("cannot set file position") raiseEIO("cannot set file position")
proc getFilePos(f: File): int64 = proc getFilePos(f: File): int64 =
result = ftell(f) result = c_ftell(f)
if result < 0: raiseEIO("cannot retrieve file position") if result < 0: raiseEIO("cannot retrieve file position")
proc getFileSize(f: File): int64 = proc getFileSize(f: File): int64 =
var oldPos = getFilePos(f) var oldPos = getFilePos(f)
discard fseek(f, 0, 2) # seek the end of the file discard c_fseek(f, 0, 2) # seek the end of the file
result = getFilePos(f) result = getFilePos(f)
setFilePos(f, oldPos) setFilePos(f, oldPos)
when not declared(close):
proc close(f: File) {.
importc: "fclose", header: "<stdio.h>", tags: [].}
proc readFile(filename: string): TaintedString = proc readFile(filename: string): TaintedString =
var f: File var f: File
if open(f, filename): if open(f, filename):

View file

@ -30,7 +30,7 @@ proc eqStrings(a, b: NimString): bool {.inline, compilerProc.} =
if a == b: return true if a == b: return true
if a == nil or b == nil: return false if a == nil or b == nil: return false
return a.len == b.len and return a.len == b.len and
c_memcmp(a.data, b.data, a.len) == 0'i32 equalMem(addr(a.data), addr(b.data), a.len)
when declared(allocAtomic): when declared(allocAtomic):
template allocStr(size: expr): expr = template allocStr(size: expr): expr =
@ -71,7 +71,7 @@ proc copyStrLast(s: NimString, start, last: int): NimString {.compilerProc.} =
if len > 0: if len > 0:
result = rawNewStringNoInit(len) result = rawNewStringNoInit(len)
result.len = len result.len = len
c_memcpy(result.data, addr(s.data[start]), len) copyMem(addr(result.data), addr(s.data[start]), len)
result.data[len] = '\0' result.data[len] = '\0'
else: else:
result = rawNewString(len) result = rawNewString(len)
@ -82,10 +82,10 @@ proc copyStr(s: NimString, start: int): NimString {.compilerProc.} =
proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} = proc toNimStr(str: cstring, len: int): NimString {.compilerProc.} =
result = rawNewStringNoInit(len) result = rawNewStringNoInit(len)
result.len = len result.len = len
c_memcpy(result.data, str, len + 1) copyMem(addr(result.data), str, len + 1)
proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} = proc cstrToNimstr(str: cstring): NimString {.compilerRtl.} =
result = toNimStr(str, c_strlen(str)) result = toNimStr(str, str.len)
proc copyString(src: NimString): NimString {.compilerRtl.} = proc copyString(src: NimString): NimString {.compilerRtl.} =
if src != nil: if src != nil:
@ -94,7 +94,7 @@ proc copyString(src: NimString): NimString {.compilerRtl.} =
else: else:
result = rawNewStringNoInit(src.len) result = rawNewStringNoInit(src.len)
result.len = src.len result.len = src.len
c_memcpy(result.data, src.data, src.len + 1) copyMem(addr(result.data), addr(src.data), src.len + 1)
proc copyStringRC1(src: NimString): NimString {.compilerRtl.} = proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
if src != nil: if src != nil:
@ -107,7 +107,7 @@ proc copyStringRC1(src: NimString): NimString {.compilerRtl.} =
else: else:
result = rawNewStringNoInit(src.len) result = rawNewStringNoInit(src.len)
result.len = src.len result.len = src.len
c_memcpy(result.data, src.data, src.len + 1) copyMem(addr(result.data), addr(src.data), src.len + 1)
proc hashString(s: string): int {.compilerproc.} = proc hashString(s: string): int {.compilerproc.} =
@ -177,7 +177,7 @@ proc resizeString(dest: NimString, addlen: int): NimString {.compilerRtl.} =
# DO NOT UPDATE LEN YET: dest.len = newLen # DO NOT UPDATE LEN YET: dest.len = newLen
proc appendString(dest, src: NimString) {.compilerproc, inline.} = proc appendString(dest, src: NimString) {.compilerproc, inline.} =
c_memcpy(addr(dest.data[dest.len]), src.data, src.len + 1) copyMem(addr(dest.data[dest.len]), addr(src.data), src.len + 1)
inc(dest.len, src.len) inc(dest.len, src.len)
proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} = proc appendChar(dest: NimString, c: char) {.compilerproc, inline.} =
@ -301,8 +301,8 @@ proc nimFloatToStr(f: float): string {.compilerproc.} =
else: else:
result = $buf result = $buf
proc strtod(buf: cstring, endptr: ptr cstring): float64 {.importc, proc c_strtod(buf: cstring, endptr: ptr cstring): float64 {.
header: "<stdlib.h>", noSideEffect.} importc: "strtod", header: "<stdlib.h>", noSideEffect.}
const const
IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'} IdentChars = {'a'..'z', 'A'..'Z', '0'..'9', '_'}
@ -460,7 +460,7 @@ proc nimParseBiggestFloat(s: string, number: var BiggestFloat,
t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10 t[ti-2] = ('0'.ord + abs_exponent mod 10).char; abs_exponent = abs_exponent div 10
t[ti-3] = ('0'.ord + abs_exponent mod 10).char t[ti-3] = ('0'.ord + abs_exponent mod 10).char
number = strtod(t, nil) number = c_strtod(t, nil)
proc nimInt64ToStr(x: int64): string {.compilerRtl.} = proc nimInt64ToStr(x: int64): string {.compilerRtl.} =
result = newString(sizeof(x)*4) result = newString(sizeof(x)*4)

View file

@ -117,6 +117,11 @@ else:
schedh = "#define _GNU_SOURCE\n#include <sched.h>" schedh = "#define _GNU_SOURCE\n#include <sched.h>"
pthreadh = "#define _GNU_SOURCE\n#include <pthread.h>" pthreadh = "#define _GNU_SOURCE\n#include <pthread.h>"
when defined(linux):
type Time = clong
else:
type Time = int
type type
SysThread {.importc: "pthread_t", header: "<sys/types.h>", SysThread {.importc: "pthread_t", header: "<sys/types.h>",
final, pure.} = object final, pure.} = object
@ -125,8 +130,8 @@ else:
Timespec {.importc: "struct timespec", Timespec {.importc: "struct timespec",
header: "<time.h>", final, pure.} = object header: "<time.h>", final, pure.} = object
tv_sec: int tv_sec: Time
tv_nsec: int tv_nsec: clong
{.deprecated: [TSysThread: SysThread, Tpthread_attr: PThreadAttr, {.deprecated: [TSysThread: SysThread, Tpthread_attr: PThreadAttr,
Ttimespec: Timespec].} Ttimespec: Timespec].}

View file

@ -78,11 +78,16 @@ elif defined(posixRealtime):
else: else:
# fallback Posix implementation: # fallback Posix implementation:
when defined(linux):
type Time = clong
else:
type Time = int
type type
Timeval {.importc: "struct timeval", header: "<sys/select.h>", Timeval {.importc: "struct timeval", header: "<sys/select.h>",
final, pure.} = object ## struct timeval final, pure.} = object ## struct timeval
tv_sec: int ## Seconds. tv_sec: Time ## Seconds.
tv_usec: int ## Microseconds. tv_usec: clong ## Microseconds.
{.deprecated: [Ttimeval: Timeval].} {.deprecated: [Ttimeval: Timeval].}
proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {. proc posix_gettimeofday(tp: var Timeval, unused: pointer = nil) {.
importc: "gettimeofday", header: "<sys/time.h>".} importc: "gettimeofday", header: "<sys/time.h>".}

View file

@ -104,12 +104,7 @@ proc newWideCString*(source: cstring, L: int): WideCString =
proc newWideCString*(s: cstring): WideCString = proc newWideCString*(s: cstring): WideCString =
if s.isNil: return nil if s.isNil: return nil
when not declared(c_strlen): result = newWideCString(s, s.len)
proc c_strlen(a: cstring): int {.
header: "<string.h>", noSideEffect, importc: "strlen".}
let L = c_strlen(s)
result = newWideCString(s, L)
proc newWideCString*(s: string): WideCString = proc newWideCString*(s: string): WideCString =
result = newWideCString(s, s.len) result = newWideCString(s, s.len)

View file

@ -202,14 +202,34 @@ proc parseCmdLine(c: var ConfigData) =
if c.infile.len == 0: quit(Usage) if c.infile.len == 0: quit(Usage)
if c.mainfile.len == 0: c.mainfile = changeFileExt(c.infile, "nim") if c.mainfile.len == 0: c.mainfile = changeFileExt(c.infile, "nim")
proc ignoreFile(f, root: string, allowHtml: bool): bool = proc eqT(a, b: string; t: proc (a: char): char{.nimcall.}): bool =
## equality under a transformation ``t``. candidate for the stdlib?
var i = 0
var j = 0
while i < a.len and j < b.len:
let aa = t a[i]
let bb = t b[j]
if aa == '\0':
inc i
if bb == '\0': inc j
elif bb == '\0': inc j
else:
if aa != bb: return false
inc i
inc j
result = i >= a.len and j >= b.len
proc tPath(c: char): char =
if c == '\\': '/'
else: c
proc ignoreFile(f, explicit: string, allowHtml: bool): bool =
let (_, name, ext) = splitFile(f) let (_, name, ext) = splitFile(f)
let html = if not allowHtml: ".html" else: "" let html = if not allowHtml: ".html" else: ""
let explicit = splitPath(root).tail result = (ext in ["", ".exe", ".idx", ".o", ".obj", ".dylib"] or
result = (ext in ["", ".exe", ".idx"] or ext == html or name[0] == '.') and not eqT(f, explicit, tPath)
ext == html or name[0] == '.') and name & ext != explicit
proc walkDirRecursively(s: var seq[string], root: string, proc walkDirRecursively(s: var seq[string], root, explicit: string,
allowHtml: bool) = allowHtml: bool) =
let tail = splitPath(root).tail let tail = splitPath(root).tail
if tail == "nimcache" or tail[0] == '.': if tail == "nimcache" or tail[0] == '.':
@ -221,21 +241,21 @@ proc walkDirRecursively(s: var seq[string], root: string,
else: else:
case k case k
of pcFile, pcLinkToFile: of pcFile, pcLinkToFile:
if not ignoreFile(f, root, allowHtml): if not ignoreFile(f, explicit, allowHtml):
add(s, unixToNativePath(f)) add(s, unixToNativePath(f))
of pcDir: of pcDir:
walkDirRecursively(s, f, allowHtml) walkDirRecursively(s, f, explicit, allowHtml)
of pcLinkToDir: discard of pcLinkToDir: discard
proc addFiles(s: var seq[string], patterns: seq[string]) = proc addFiles(s: var seq[string], patterns: seq[string]) =
for p in items(patterns): for p in items(patterns):
if existsDir(p): if existsDir(p):
walkDirRecursively(s, p, false) walkDirRecursively(s, p, p, false)
else: else:
var i = 0 var i = 0
for f in walkFiles(p): for f in walkFiles(p):
if existsDir(f): if existsDir(f):
walkDirRecursively(s, f, false) walkDirRecursively(s, f, p, false)
elif not ignoreFile(f, p, false): elif not ignoreFile(f, p, false):
add(s, unixToNativePath(f)) add(s, unixToNativePath(f))
inc(i) inc(i)

View file

@ -14,6 +14,8 @@ Changes affecting backwards compatibility
Library Additions Library Additions
----------------- -----------------
- Added ``readHeaderRow`` and ``rowEntry`` to ``parsecsv.nim`` to provide
a lightweight alternative to python's ``csv.DictReader``.
- Added ``setStdIoUnbuffered`` proc to ``system.nim`` to enable unbuffered I/O. - Added ``setStdIoUnbuffered`` proc to ``system.nim`` to enable unbuffered I/O.
Compiler Additions Compiler Additions