summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/lexer.nim4
-rw-r--r--lib/core/locks.nim10
-rw-r--r--lib/posix/kqueue.nim135
-rw-r--r--lib/pure/collections/tableimpl.nim5
-rw-r--r--lib/pure/logging.nim13
-rw-r--r--lib/pure/strutils.nim26
-rw-r--r--lib/system/sysio.nim21
7 files changed, 169 insertions, 45 deletions
diff --git a/compiler/lexer.nim b/compiler/lexer.nim
index 69a0fea2a..0032b97df 100644
--- a/compiler/lexer.nim
+++ b/compiler/lexer.nim
@@ -263,7 +263,7 @@ template eatChar(L: var TLexer, t: var TToken) =
   add(t.literal, L.buf[L.bufpos])
   inc(L.bufpos)
 
-proc getNumber(L: var TLexer): TToken =
+proc getNumber(L: var TLexer, result: var TToken) =
   proc matchUnderscoreChars(L: var TLexer, tok: var TToken, chars: set[char]) =
     var pos = L.bufpos              # use registers for pos, buf
     var buf = L.buf
@@ -1061,7 +1061,7 @@ proc rawGetTok*(L: var TLexer, tok: var TToken) =
       getCharacter(L, tok)
       tok.tokType = tkCharLit
     of '0'..'9':
-      tok = getNumber(L)
+      getNumber(L, tok)
     else:
       if c in OpChars:
         getOperator(L, tok)
diff --git a/lib/core/locks.nim b/lib/core/locks.nim
index f1a74876e..66e0ab520 100644
--- a/lib/core/locks.nim
+++ b/lib/core/locks.nim
@@ -54,3 +54,13 @@ proc wait*(cond: var Cond, lock: var Lock) {.inline.} =
 proc signal*(cond: var Cond) {.inline.} =
   ## sends a signal to the condition variable `cond`.
   signalSysCond(cond)
+
+template withLock*(a: Lock, body: untyped) =
+  ## Acquires the given lock, executes the statements in body and
+  ## releases the lock after the statements finish executing.
+  a.acquire()
+  {.locks: [a].}:
+    try:
+      body
+    finally:
+      a.release()
\ No newline at end of file
diff --git a/lib/posix/kqueue.nim b/lib/posix/kqueue.nim
index d91da632b..5c67d621e 100644
--- a/lib/posix/kqueue.nim
+++ b/lib/posix/kqueue.nim
@@ -1,7 +1,7 @@
 #
 #
 #            Nim's Runtime Library
-#        (c) Copyright 2015 Adam Strzelecki
+#        (c) Copyright 2016 Eugene Kabanov
 #
 #    See the file "copying.txt", included in this
 #    distribution, for details about the copyright.
@@ -11,20 +11,35 @@
 
 from posix import Timespec
 
-# Filters:
-const
-  EVFILT_READ*     = -1
-  EVFILT_WRITE*    = -2
-  EVFILT_AIO*      = -3
-  EVFILT_VNODE*    = -4
-  EVFILT_PROC*     = -5
-  EVFILT_SIGNAL*   = -6
-  EVFILT_TIMER*    = -7
-  EVFILT_MACHPORT* = -8
-  EVFILT_FS*       = -9
-  EVFILT_USER*     = -10
-  # -11 is unused
-  EVFILT_VM*       = -12
+when defined(macosx) or defined(freebsd) or defined(openbsd):
+  const
+    EVFILT_READ*     = -1
+    EVFILT_WRITE*    = -2
+    EVFILT_AIO*      = -3 ## attached to aio requests
+    EVFILT_VNODE*    = -4 ## attached to vnodes
+    EVFILT_PROC*     = -5 ## attached to struct proc
+    EVFILT_SIGNAL*   = -6 ## attached to struct proc
+    EVFILT_TIMER*    = -7 ## timers
+elif defined(netbsd):
+  const
+    EVFILT_READ*     = 0
+    EVFILT_WRITE*    = 1
+    EVFILT_AIO*      = 2 ## attached to aio requests
+    EVFILT_VNODE*    = 3 ## attached to vnodes
+    EVFILT_PROC*     = 4 ## attached to struct proc
+    EVFILT_SIGNAL*   = 5 ## attached to struct proc
+    EVFILT_TIMER*    = 6 ## timers (in ms)
+when defined(macosx):
+  const
+    EVFILT_MACHPORT* = -8  ## Mach portsets
+    EVFILT_FS*       = -9  ## filesystem events
+    EVFILT_USER*     = -10 ## user events
+    EVFILT_VM        = -12 ## virtual memory events
+elif defined(freebsd):
+  const
+    EVFILT_FS*       = -9  ## filesystem events
+    EVFILT_LIO*      = -10 ## attached to lio requests
+    EVFILT_USER*     = -11 ## user events
 
 # Actions:
 const
@@ -40,22 +55,92 @@ const
   EV_CLEAR*    = 0x0020 ## Clear event state after reporting.
   EV_RECEIPT*  = 0x0040 ## Force EV_ERROR on success, data == 0
   EV_DISPATCH* = 0x0080 ## Disable event after reporting.
+  
+  EV_SYSFLAGS* = 0xF000 ## Reserved by system
+  EV_DROP*     = 0x1000 ## Not should be dropped
+  EV_FLAG1*    = 0x2000 ## Filter-specific flag
 
 # Return values:
 const
   EV_EOF*      = 0x8000 ## EOF detected
   EV_ERROR*    = 0x4000 ## Error, data contains errno
 
+
+when defined(macosx) or defined(freebsd):
+  # EVFILT_USER is not supported by OpenBSD and NetBSD
+  #
+  # data/hint flags/masks for EVFILT_USER, shared with userspace
+  #
+  # On input, the top two bits of fflags specifies how the lower twenty four
+  # bits should be applied to the stored value of fflags.
+  #
+  # On output, the top two bits will always be set to NOTE_FFNOP and the
+  # remaining twenty four bits will contain the stored fflags value.
+  const
+    NOTE_FFNOP*      = 0x00000000'u32 ## ignore input fflags
+    NOTE_FFAND*      = 0x40000000'u32 ## AND fflags
+    NOTE_FFOR*       = 0x80000000'u32 ## OR fflags
+    NOTE_FFCOPY*     = 0xc0000000'u32 ## copy fflags
+    NOTE_FFCTRLMASK* = 0xc0000000'u32 ## masks for operations 
+    NOTE_FFLAGSMASK* = 0x00ffffff'u32
+
+    NOTE_TRIGGER*    = 0x01000000'u32 ## Cause the event to be triggered 
+                                      ## for output.
+
+# data/hint flags for EVFILT_{READ|WRITE}, shared with userspace
+const
+  NOTE_LOWAT*      = 0x0001 ## low water mark
+
+# data/hint flags for EVFILT_VNODE, shared with userspace
+const
+  NOTE_DELETE*     = 0x0001 ## vnode was removed
+  NOTE_WRITE*      = 0x0002 ## data contents changed
+  NOTE_EXTEND*     = 0x0004 ## size increased
+  NOTE_ATTRIB*     = 0x0008 ## attributes changed
+  NOTE_LINK*       = 0x0010 ## link count changed
+  NOTE_RENAME*     = 0x0020 ## vnode was renamed
+  NOTE_REVOKE*     = 0x0040 ## vnode access was revoked
+
+# data/hint flags for EVFILT_PROC, shared with userspace
+const
+  NOTE_EXIT*       = 0x80000000'u32 ## process exited
+  NOTE_FORK*       = 0x40000000'u32 ## process forked
+  NOTE_EXEC*       = 0x20000000'u32 ## process exec'd
+  NOTE_PCTRLMASK*  = 0xf0000000'u32 ## mask for hint bits
+  NOTE_PDATAMASK*  = 0x000fffff'u32 ## mask for pid
+
+# additional flags for EVFILT_PROC
+const
+  NOTE_TRACK*      = 0x00000001'u32 ## follow across forks
+  NOTE_TRACKERR*   = 0x00000002'u32 ## could not track child
+  NOTE_CHILD*      = 0x00000004'u32 ## am a child process
+
+when defined(macosx) or defined(freebsd):
+  # additional flags for EVFILE_TIMER
+  const
+    NOTE_SECONDS*    = 0x00000001'u32 ## data is seconds
+    NOTE_MSECONDS*   = 0x00000002'u32 ## data is milliseconds
+    NOTE_USECONDS*   = 0x00000004'u32 ## data is microseconds
+    NOTE_NSECONDS*   = 0x00000008'u32 ## data is nanoseconds
+else:
+  # NetBSD and OpenBSD doesnt support NOTE_{TIME} constants, but
+  # support EVFILT_TIMER with granularity of milliseconds.
+  const
+    NOTE_MSECONDS*   = 0x00000000'u32
+
 type
-  KEvent* {.importc: "struct kevent", pure, final
+  ## This define not fully satisfy NetBSD "struct kevent"
+  ## but it works and tested.
+  KEvent* {.importc: "struct kevent",
             header: """#include <sys/types.h>
-                       #include <sys/event.h>""".} = object
-    ident*: cuint    ## identifier for this event  (uintptr_t)
-    filter*: cshort  ## filter for event
-    flags*: cushort  ## general flags
-    fflags*: cuint   ## filter-specific flags
-    data*: cuint     ## filter-specific data  (intptr_t)
-    #udata*: ptr void ## opaque user data identifier
+                       #include <sys/event.h>
+                       #include <sys/time.h>""", pure, final.} = object
+    ident*  : uint     ## identifier for this event  (uintptr_t)
+    filter* : cshort   ## filter for event
+    flags*  : cushort  ## general flags
+    fflags* : cuint    ## filter-specific flags
+    data*   : int      ## filter-specific data  (intptr_t)
+    udata*  : pointer  ## opaque user data identifier
 
 proc kqueue*(): cint {.importc: "kqueue", header: "<sys/event.h>".}
   ## Creates new queue and returns its descriptor.
@@ -66,7 +151,7 @@ proc kevent*(kqFD: cint,
      {.importc: "kevent", header: "<sys/event.h>".}
   ## Manipulates queue for given ``kqFD`` descriptor.
 
-proc EV_SET*(event: ptr KEvent, ident: cuint, filter: cshort, flags: cushort,
-             fflags: cuint, data: cuint, udata: ptr void)
+proc EV_SET*(event: ptr KEvent, ident: uint, filter: cshort, flags: cushort,
+             fflags: cuint, data: int, udata: pointer)
      {.importc: "EV_SET", header: "<sys/event.h>".}
   ## Fills event with given data.
diff --git a/lib/pure/collections/tableimpl.nim b/lib/pure/collections/tableimpl.nim
index beafe1109..e4ec05b1c 100644
--- a/lib/pure/collections/tableimpl.nim
+++ b/lib/pure/collections/tableimpl.nim
@@ -129,4 +129,7 @@ template delImpl() {.dirty, immediate.} =
           r = t.data[i].hcode and msk    # "home" location of key@i
           if not ((i >= r and r > j) or (r > j and j > i) or (j > i and i >= r)):
             break
-        shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
+        when defined(js):
+          t.data[j] = t.data[i]
+        else:
+          shallowCopy(t.data[j], t.data[i]) # data[j] will be marked EMPTY next loop
diff --git a/lib/pure/logging.nim b/lib/pure/logging.nim
index aa55b5ade..f602ce31d 100644
--- a/lib/pure/logging.nim
+++ b/lib/pure/logging.nim
@@ -92,6 +92,10 @@ type
 {.deprecated: [TLevel: Level, PLogger: Logger, PConsoleLogger: ConsoleLogger,
     PFileLogger: FileLogger, PRollingFileLogger: RollingFileLogger].}
 
+var
+  level {.threadvar.}: Level   ## global log filter
+  handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
+
 proc substituteLog*(frmt: string, level: Level, args: varargs[string, `$`]): string =
   ## Format a log message using the ``frmt`` format string, ``level`` and varargs.
   ## See the module documentation for the format string syntax.
@@ -133,13 +137,13 @@ method log*(logger: Logger, level: Level, args: varargs[string, `$`]) {.
 
 method log*(logger: ConsoleLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to the console using ``logger`` only.
-  if level >= logger.levelThreshold:
+  if level >= logging.level and level >= logger.levelThreshold:
     writeLine(stdout, substituteLog(logger.fmtStr, level, args))
     if level in {lvlError, lvlFatal}: flushFile(stdout)
 
 method log*(logger: FileLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to a file using ``logger`` only.
-  if level >= logger.levelThreshold:
+  if level >= logging.level and level >= logger.levelThreshold:
     writeLine(logger.file, substituteLog(logger.fmtStr, level, args))
     if level in {lvlError, lvlFatal}: flushFile(logger.file)
 
@@ -224,7 +228,7 @@ proc rotate(logger: RollingFileLogger) =
 
 method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`]) =
   ## Logs to a file using rolling ``logger`` only.
-  if level >= logger.levelThreshold:
+  if level >= logging.level and level >= logger.levelThreshold:
     if logger.curLine >= logger.maxLines:
       logger.file.close()
       rotate(logger)
@@ -238,9 +242,6 @@ method log*(logger: RollingFileLogger, level: Level, args: varargs[string, `$`])
 
 # --------
 
-var level {.threadvar.}: Level   ## global log filter
-var handlers {.threadvar.}: seq[Logger] ## handlers with their own log levels
-
 proc logLoop(level: Level, args: varargs[string, `$`]) =
   for logger in items(handlers):
     if level >= logger.levelThreshold:
diff --git a/lib/pure/strutils.nim b/lib/pure/strutils.nim
index a446f85b4..f2c1e77e1 100644
--- a/lib/pure/strutils.nim
+++ b/lib/pure/strutils.nim
@@ -882,7 +882,7 @@ proc abbrev*(s: string, possibilities: openArray[string]): int =
 
 # ---------------------------------------------------------------------------
 
-proc join*(a: openArray[string], sep: string): string {.
+proc join*(a: openArray[string], sep: string = ""): string {.
   noSideEffect, rtl, extern: "nsuJoinSep".} =
   ## Concatenates all strings in `a` separating them with `sep`.
   if len(a) > 0:
@@ -896,16 +896,15 @@ proc join*(a: openArray[string], sep: string): string {.
   else:
     result = ""
 
-proc join*(a: openArray[string]): string {.
-  noSideEffect, rtl, extern: "nsuJoin".} =
-  ## Concatenates all strings in `a`.
-  if len(a) > 0:
-    var L = 0
-    for i in 0..high(a): inc(L, a[i].len)
-    result = newStringOfCap(L)
-    for i in 0..high(a): add(result, a[i])
-  else:
-    result = ""
+proc join*[T: not string](a: openArray[T], sep: string = ""): string {.
+  noSideEffect, rtl.} =
+  ## Converts all elements in `a` to strings using `$` and concatenates them
+  ## with `sep`.
+  result = ""
+  for i, x in a:
+    if i > 0:
+      add(result, sep)
+    add(result, $x)
 
 type
   SkipTable = array[char, int]
@@ -1721,3 +1720,8 @@ when isMainModule:
   doAssert(not isUpper("AAcc"))
   doAssert(not isUpper("A#$"))
   doAssert(unescape(r"\x013", "", "") == "\x013")
+
+  doAssert join(["foo", "bar", "baz"]) == "foobarbaz"
+  doAssert join(@["foo", "bar", "baz"], ", ") == "foo, bar, baz"
+  doAssert join([1, 2, 3]) == "123"
+  doAssert join(@[1, 2, 3], ", ") == "1, 2, 3"
diff --git a/lib/system/sysio.nim b/lib/system/sysio.nim
index 78c7b1ca1..d0bba6775 100644
--- a/lib/system/sysio.nim
+++ b/lib/system/sysio.nim
@@ -270,12 +270,33 @@ const
     # we always use binary here as for Nim the OS line ending
     # should not be translated.
 
+when defined(posix) and not defined(nimscript):
+  type
+    Mode {.importc: "mode_t", header: "<sys/types.h>".} = cint
+
+    Stat {.importc: "struct stat",
+             header: "<sys/stat.h>", final, pure.} = object ## struct stat
+      st_mode: Mode        ## Mode of file
+
+  proc S_ISDIR(m: Mode): bool {.importc, header: "<sys/stat.h>".}
+    ## Test for a directory.
+
+  proc fstat(a1: cint, a2: var Stat): cint {.importc, header: "<sys/stat.h>".}
 
 proc open(f: var File, filename: string,
           mode: FileMode = fmRead,
           bufSize: int = -1): bool =
   var p: pointer = fopen(filename, FormatOpen[mode])
   if p != nil:
+    when defined(posix) and not defined(nimscript):
+      # How `fopen` handles opening a directory is not specified in ISO C and
+      # POSIX. We do not want to handle directories as regular files that can
+      # be opened.
+      var f2 = cast[File](p)
+      var res: Stat
+      if fstat(getFileHandle(f2), res) >= 0'i32 and S_ISDIR(res.st_mode):
+        close(f2)
+        return false
     result = true
     f = cast[File](p)
     if bufSize > 0 and bufSize <= high(cint).int: