Merge pull request #2 from xyb/test
add tests and upgrade leveldb to 1.22
This commit is contained in:
commit
b9c39010d7
74
leveldb.nim
74
leveldb.nim
|
@ -12,8 +12,8 @@ type
|
|||
LevelDbException* = object of Exception
|
||||
|
||||
const
|
||||
levelDbTrue = cuchar(1)
|
||||
levelDbFalse = cuchar(0)
|
||||
levelDbTrue = uint8(1)
|
||||
levelDbFalse = uint8(0)
|
||||
|
||||
proc checkError(errPtr: cstring) =
|
||||
if errPtr != nil:
|
||||
|
@ -46,6 +46,10 @@ proc open*(path: string): LevelDb =
|
|||
result.db = leveldb_open(options, path, addr errPtr)
|
||||
checkError(errPtr)
|
||||
|
||||
proc version*(self: LevelDb): (int, int) =
|
||||
result[0] = leveldb_major_version()
|
||||
result[1] = leveldb_minor_version()
|
||||
|
||||
proc put*(self: LevelDb, key: string, value: string, sync = true) =
|
||||
assert self.db != nil
|
||||
var errPtr: cstring = nil
|
||||
|
@ -116,30 +120,54 @@ iterator iter*(self: LevelDb, seek: string = "", reverse: bool = false): (
|
|||
else:
|
||||
leveldb_iter_next(iterPtr)
|
||||
|
||||
proc removeDb*(name: string) =
|
||||
var err: cstring = nil
|
||||
let options = leveldb_options_create()
|
||||
leveldb_destroy_db(options, name, addr err)
|
||||
checkError(err)
|
||||
|
||||
when isMainModule:
|
||||
let db = leveldb.open("test.db")
|
||||
db.put("hello", "world")
|
||||
echo db.get("nothing")
|
||||
echo db.get("hello")
|
||||
db.delete("hello")
|
||||
echo db.get("hello")
|
||||
import sequtils
|
||||
|
||||
db.put("aaa", "1")
|
||||
db.put("aba", "2")
|
||||
db.put("abb", "3")
|
||||
let env = leveldb_create_default_env()
|
||||
let dbName = $(leveldb_env_get_test_directory(env))
|
||||
let db = leveldb.open(dbName)
|
||||
|
||||
echo ">> iter"
|
||||
for i in db.iter:
|
||||
echo i
|
||||
block version:
|
||||
let (major, minor) = db.version()
|
||||
doAssert major > 0
|
||||
doAssert minor > 0
|
||||
|
||||
echo ">> iter reverse"
|
||||
for i in db.iter(reverse = true):
|
||||
echo i
|
||||
block getPutDelete:
|
||||
doAssert db.get("hello") == none(string)
|
||||
db.put("hello", "world")
|
||||
doAssert db.get("hello") == some("world")
|
||||
db.delete("hello")
|
||||
doAssert db.get("hello") == none(string)
|
||||
|
||||
echo ">> iter seek ab"
|
||||
for i in db.iter(seek = "ab"):
|
||||
echo i
|
||||
block iter:
|
||||
db.put("aa", "1")
|
||||
db.put("ba", "2")
|
||||
db.put("bb", "3")
|
||||
|
||||
echo ">> iter seek ab reverse"
|
||||
for i in db.iter(seek = "ab", reverse = true):
|
||||
echo i
|
||||
block iterNormal:
|
||||
doAssert toSeq(db.iter()) ==
|
||||
@[("aa", "1"), ("ba", "2"), ("bb", "3")]
|
||||
|
||||
block iterReverse:
|
||||
doAssert toSeq(db.iter(reverse = true)) ==
|
||||
@[("bb", "3"), ("ba", "2"), ("aa", "1")]
|
||||
|
||||
block iterSeek:
|
||||
doAssert toSeq(db.iter(seek = "ab")) ==
|
||||
@[("ba", "2"), ("bb", "3")]
|
||||
|
||||
block iterSeekReverse:
|
||||
doAssert toSeq(db.iter(seek = "ab", reverse = true)) ==
|
||||
@[("ba", "2"), ("aa", "1")]
|
||||
|
||||
block close:
|
||||
db.close()
|
||||
|
||||
block remove:
|
||||
removeDb(dbName)
|
||||
|
|
225
leveldb/raw.nim
225
leveldb/raw.nim
|
@ -1,41 +1,41 @@
|
|||
## # Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
## # Use of this source code is governed by a BSD-style license that can be
|
||||
## # found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
## #
|
||||
## # C bindings for leveldb. May be useful as a stable ABI that can be
|
||||
## # used by programs that keep leveldb in a shared library, or for
|
||||
## # a JNI api.
|
||||
## #
|
||||
## # Does not support:
|
||||
## # . getters for the option types
|
||||
## # . custom comparators that implement key shortening
|
||||
## # . custom iter, db, env, cache implementations using just the C bindings
|
||||
## #
|
||||
## # Some conventions:
|
||||
## #
|
||||
## # (1) We expose just opaque struct pointers and functions to clients.
|
||||
## # This allows us to change internal representations without having to
|
||||
## # recompile clients.
|
||||
## #
|
||||
## # (2) For simplicity, there is no equivalent to the Slice type. Instead,
|
||||
## # the caller has to pass the pointer and length as separate
|
||||
## # arguments.
|
||||
## #
|
||||
## # (3) Errors are represented by a null-terminated c string. NULL
|
||||
## # means no error. All operations that can raise an error are passed
|
||||
## # a "char** errptr" as the last argument. One of the following must
|
||||
## # be true on entry:
|
||||
## # errptr == NULL
|
||||
## # errptr points to a malloc()ed null-terminated error message
|
||||
## # (On Windows, *errptr must have been malloc()-ed by this library.)
|
||||
## # On success, a leveldb routine leaves *errptr unchanged.
|
||||
## # On failure, leveldb frees the old value of *errptr and
|
||||
## # set *errptr to a malloc()ed error message.
|
||||
## #
|
||||
## # (4) Bools have the type unsigned char (0 == false; rest == true)
|
||||
## #
|
||||
## # (5) All of the pointer arguments must be non-NULL.
|
||||
## #
|
||||
## Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||||
## Use of this source code is governed by a BSD-style license that can be
|
||||
## found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||||
##
|
||||
## C bindings for leveldb. May be useful as a stable ABI that can be
|
||||
## used by programs that keep leveldb in a shared library, or for
|
||||
## a JNI api.
|
||||
##
|
||||
## Does not support:
|
||||
## . getters for the option types
|
||||
## . custom comparators that implement key shortening
|
||||
## . custom iter, db, env, cache implementations using just the C bindings
|
||||
##
|
||||
## Some conventions:
|
||||
##
|
||||
## (1) We expose just opaque struct pointers and functions to clients.
|
||||
## This allows us to change internal representations without having to
|
||||
## recompile clients.
|
||||
##
|
||||
## (2) For simplicity, there is no equivalent to the Slice type. Instead,
|
||||
## the caller has to pass the pointer and length as separate
|
||||
## arguments.
|
||||
##
|
||||
## (3) Errors are represented by a null-terminated c string. NULL
|
||||
## means no error. All operations that can raise an error are passed
|
||||
## a "char** errptr" as the last argument. One of the following must
|
||||
## be true on entry:
|
||||
## errptr == NULL
|
||||
## errptr points to a malloc()ed null-terminated error message
|
||||
## (On Windows, *errptr must have been malloc()-ed by this library.)
|
||||
## On success, a leveldb routine leaves *errptr unchanged.
|
||||
## On failure, leveldb frees the old value of *errptr and
|
||||
## set *errptr to a malloc()ed error message.
|
||||
##
|
||||
## (4) Bools have the type uint8_t (0 == false; rest == true)
|
||||
##
|
||||
## (5) All of the pointer arguments must be non-NULL.
|
||||
##
|
||||
|
||||
{.passl: "-lleveldb".}
|
||||
|
||||
|
@ -55,7 +55,7 @@ type
|
|||
leveldb_cache_t* = object
|
||||
leveldb_t* = object
|
||||
|
||||
## # DB operations
|
||||
## DB operations
|
||||
|
||||
proc leveldb_open*(options: ptr leveldb_options_t; name: cstring; errptr: ptr cstring): ptr leveldb_t {.importc.}
|
||||
proc leveldb_close*(db: ptr leveldb_t) {.importc.}
|
||||
|
@ -65,16 +65,16 @@ proc leveldb_delete*(db: ptr leveldb_t; options: ptr leveldb_writeoptions_t;
|
|||
key: cstring; keylen: csize; errptr: ptr cstring) {.importc.}
|
||||
proc leveldb_write*(db: ptr leveldb_t; options: ptr leveldb_writeoptions_t;
|
||||
batch: ptr leveldb_writebatch_t; errptr: ptr cstring) {.importc.}
|
||||
## # Returns NULL if not found. A malloc()ed array otherwise.
|
||||
## # Stores the length of the array in *vallen.
|
||||
## Returns NULL if not found. A malloc()ed array otherwise.
|
||||
## Stores the length of the array in *vallen.
|
||||
|
||||
proc leveldb_get*(db: ptr leveldb_t; options: ptr leveldb_readoptions_t; key: cstring;
|
||||
keylen: csize; vallen: ptr csize; errptr: ptr cstring): cstring {.importc.}
|
||||
proc leveldb_create_iterator*(db: ptr leveldb_t; options: ptr leveldb_readoptions_t): ptr leveldb_iterator_t {.importc.}
|
||||
proc leveldb_create_snapshot*(db: ptr leveldb_t): ptr leveldb_snapshot_t {.importc.}
|
||||
proc leveldb_release_snapshot*(db: ptr leveldb_t; snapshot: ptr leveldb_snapshot_t) {.importc.}
|
||||
## # Returns NULL if property name is unknown.
|
||||
## # Else returns a pointer to a malloc()-ed null-terminated value.
|
||||
## Returns NULL if property name is unknown.
|
||||
## Else returns a pointer to a malloc()-ed null-terminated value.
|
||||
|
||||
proc leveldb_property_value*(db: ptr leveldb_t; propname: cstring): cstring {.importc.}
|
||||
proc leveldb_approximate_sizes*(db: ptr leveldb_t; num_ranges: cint;
|
||||
|
@ -85,96 +85,115 @@ proc leveldb_approximate_sizes*(db: ptr leveldb_t; num_ranges: cint;
|
|||
proc leveldb_compact_range*(db: ptr leveldb_t; start_key: cstring;
|
||||
start_key_len: csize; limit_key: cstring;
|
||||
limit_key_len: csize) {.importc.}
|
||||
## # Management operations
|
||||
## Management operations
|
||||
|
||||
proc leveldb_destroy_db*(options: ptr leveldb_options_t; name: cstring;
|
||||
errptr: ptr cstring) {.importc.}
|
||||
proc leveldb_repair_db*(options: ptr leveldb_options_t; name: cstring;
|
||||
errptr: ptr cstring) {.importc.}
|
||||
## # Iterator
|
||||
## Iterator
|
||||
|
||||
proc leveldb_iter_destroy*(a2: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_valid*(a2: ptr leveldb_iterator_t): cuchar {.importc.}
|
||||
proc leveldb_iter_seek_to_first*(a2: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_seek_to_last*(a2: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_seek*(a2: ptr leveldb_iterator_t; k: cstring; klen: csize) {.importc.}
|
||||
proc leveldb_iter_next*(a2: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_prev*(a2: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_key*(a2: ptr leveldb_iterator_t; klen: ptr csize): cstring {.importc.}
|
||||
proc leveldb_iter_value*(a2: ptr leveldb_iterator_t; vlen: ptr csize): cstring {.importc.}
|
||||
proc leveldb_iter_get_error*(a2: ptr leveldb_iterator_t; errptr: ptr cstring) {.importc.}
|
||||
## # Write batch
|
||||
proc leveldb_iter_destroy*(a1: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_valid*(a1: ptr leveldb_iterator_t): uint8 {.importc.}
|
||||
proc leveldb_iter_seek_to_first*(a1: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_seek_to_last*(a1: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_seek*(a1: ptr leveldb_iterator_t; k: cstring; klen: csize) {.importc.}
|
||||
proc leveldb_iter_next*(a1: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_prev*(a1: ptr leveldb_iterator_t) {.importc.}
|
||||
proc leveldb_iter_key*(a1: ptr leveldb_iterator_t; klen: ptr csize): cstring {.importc.}
|
||||
proc leveldb_iter_value*(a1: ptr leveldb_iterator_t; vlen: ptr csize): cstring {.importc.}
|
||||
proc leveldb_iter_get_error*(a1: ptr leveldb_iterator_t; errptr: ptr cstring) {.importc.}
|
||||
## Write batch
|
||||
|
||||
proc leveldb_writebatch_create*(): ptr leveldb_writebatch_t {.importc.}
|
||||
proc leveldb_writebatch_destroy*(a2: ptr leveldb_writebatch_t) {.importc.}
|
||||
proc leveldb_writebatch_clear*(a2: ptr leveldb_writebatch_t) {.importc.}
|
||||
proc leveldb_writebatch_put*(a2: ptr leveldb_writebatch_t; key: cstring; klen: csize;
|
||||
proc leveldb_writebatch_destroy*(a1: ptr leveldb_writebatch_t) {.importc.}
|
||||
proc leveldb_writebatch_clear*(a1: ptr leveldb_writebatch_t) {.importc.}
|
||||
proc leveldb_writebatch_put*(a1: ptr leveldb_writebatch_t; key: cstring; klen: csize;
|
||||
val: cstring; vlen: csize) {.importc.}
|
||||
proc leveldb_writebatch_delete*(a2: ptr leveldb_writebatch_t; key: cstring;
|
||||
proc leveldb_writebatch_delete*(a1: ptr leveldb_writebatch_t; key: cstring;
|
||||
klen: csize) {.importc.}
|
||||
## # Options
|
||||
proc leveldb_writebatch_iterate*(a1: ptr leveldb_writebatch_t; state: pointer; put: proc (
|
||||
a1: pointer; k: cstring; klen: csize; v: cstring; vlen: csize); deleted: proc (
|
||||
a1: pointer; k: cstring; klen: csize)) {.importc.}
|
||||
proc leveldb_writebatch_append*(destination: ptr leveldb_writebatch_t;
|
||||
source: ptr leveldb_writebatch_t) {.importc.}
|
||||
## Options
|
||||
|
||||
proc leveldb_options_create*(): ptr leveldb_options_t {.importc.}
|
||||
proc leveldb_options_destroy*(a2: ptr leveldb_options_t) {.importc.}
|
||||
proc leveldb_options_set_comparator*(a2: ptr leveldb_options_t;
|
||||
a3: ptr leveldb_comparator_t) {.importc.}
|
||||
proc leveldb_options_set_filter_policy*(a2: ptr leveldb_options_t;
|
||||
a3: ptr leveldb_filterpolicy_t) {.importc.}
|
||||
proc leveldb_options_set_create_if_missing*(a2: ptr leveldb_options_t; a3: cuchar) {.importc.}
|
||||
proc leveldb_options_set_error_if_exists*(a2: ptr leveldb_options_t; a3: cuchar) {.importc.}
|
||||
proc leveldb_options_set_paranoid_checks*(a2: ptr leveldb_options_t; a3: cuchar) {.importc.}
|
||||
proc leveldb_options_set_env*(a2: ptr leveldb_options_t; a3: ptr leveldb_env_t) {.importc.}
|
||||
proc leveldb_options_set_info_log*(a2: ptr leveldb_options_t;
|
||||
a3: ptr leveldb_logger_t) {.importc.}
|
||||
proc leveldb_options_set_write_buffer_size*(a2: ptr leveldb_options_t; a3: csize) {.importc.}
|
||||
proc leveldb_options_set_max_open_files*(a2: ptr leveldb_options_t; a3: cint) {.importc.}
|
||||
proc leveldb_options_set_cache*(a2: ptr leveldb_options_t; a3: ptr leveldb_cache_t) {.importc.}
|
||||
proc leveldb_options_set_block_size*(a2: ptr leveldb_options_t; a3: csize) {.importc.}
|
||||
proc leveldb_options_set_block_restart_interval*(a2: ptr leveldb_options_t; a3: cint) {.importc.}
|
||||
proc leveldb_options_destroy*(a1: ptr leveldb_options_t) {.importc.}
|
||||
proc leveldb_options_set_comparator*(a1: ptr leveldb_options_t;
|
||||
a2: ptr leveldb_comparator_t) {.importc.}
|
||||
proc leveldb_options_set_filter_policy*(a1: ptr leveldb_options_t;
|
||||
a2: ptr leveldb_filterpolicy_t) {.importc.}
|
||||
proc leveldb_options_set_create_if_missing*(a1: ptr leveldb_options_t; a2: uint8) {.importc.}
|
||||
proc leveldb_options_set_error_if_exists*(a1: ptr leveldb_options_t; a2: uint8) {.importc.}
|
||||
proc leveldb_options_set_paranoid_checks*(a1: ptr leveldb_options_t; a2: uint8) {.importc.}
|
||||
proc leveldb_options_set_env*(a1: ptr leveldb_options_t; a2: ptr leveldb_env_t) {.importc.}
|
||||
proc leveldb_options_set_info_log*(a1: ptr leveldb_options_t;
|
||||
a2: ptr leveldb_logger_t) {.importc.}
|
||||
proc leveldb_options_set_write_buffer_size*(a1: ptr leveldb_options_t; a2: csize) {.importc.}
|
||||
proc leveldb_options_set_max_open_files*(a1: ptr leveldb_options_t; a2: cint) {.importc.}
|
||||
proc leveldb_options_set_cache*(a1: ptr leveldb_options_t; a2: ptr leveldb_cache_t) {.importc.}
|
||||
proc leveldb_options_set_block_size*(a1: ptr leveldb_options_t; a2: csize) {.importc.}
|
||||
proc leveldb_options_set_block_restart_interval*(a1: ptr leveldb_options_t; a2: cint) {.importc.}
|
||||
proc leveldb_options_set_max_file_size*(a1: ptr leveldb_options_t; a2: csize) {.importc.}
|
||||
const
|
||||
leveldb_no_compression* = 0
|
||||
leveldb_snappy_compression* = 1
|
||||
|
||||
proc leveldb_options_set_compression*(a2: ptr leveldb_options_t; a3: cint) {.importc.}
|
||||
## # Comparator
|
||||
proc leveldb_comparator_destroy*(a2: ptr leveldb_comparator_t) {.importc.}
|
||||
## # Filter policy
|
||||
proc leveldb_options_set_compression*(a1: ptr leveldb_options_t; a2: cint) {.importc.}
|
||||
## Comparator
|
||||
|
||||
proc leveldb_filterpolicy_destroy*(a2: ptr leveldb_filterpolicy_t) {.importc.}
|
||||
proc leveldb_comparator_create*(state: pointer; destructor: proc (a1: pointer); compare: proc (
|
||||
a1: pointer; a: cstring; alen: csize; b: cstring; blen: csize): cint;
|
||||
name: proc (a1: pointer): cstring): ptr leveldb_comparator_t {.importc.}
|
||||
proc leveldb_comparator_destroy*(a1: ptr leveldb_comparator_t) {.importc.}
|
||||
## Filter policy
|
||||
|
||||
proc leveldb_filterpolicy_create*(state: pointer; destructor: proc (a1: pointer);
|
||||
create_filter: proc (a1: pointer; key_array: ptr cstring;
|
||||
key_length_array: ptr csize; num_keys: cint;
|
||||
filter_length: ptr csize): cstring; key_may_match: proc (
|
||||
a1: pointer; key: cstring; length: csize; filter: cstring; filter_length: csize): uint8;
|
||||
name: proc (a1: pointer): cstring): ptr leveldb_filterpolicy_t {.importc.}
|
||||
proc leveldb_filterpolicy_destroy*(a1: ptr leveldb_filterpolicy_t) {.importc.}
|
||||
proc leveldb_filterpolicy_create_bloom*(bits_per_key: cint): ptr leveldb_filterpolicy_t {.importc.}
|
||||
## # Read options
|
||||
## Read options
|
||||
|
||||
proc leveldb_readoptions_create*(): ptr leveldb_readoptions_t {.importc.}
|
||||
proc leveldb_readoptions_destroy*(a2: ptr leveldb_readoptions_t) {.importc.}
|
||||
proc leveldb_readoptions_set_verify_checksums*(a2: ptr leveldb_readoptions_t;
|
||||
a3: cuchar) {.importc.}
|
||||
proc leveldb_readoptions_set_fill_cache*(a2: ptr leveldb_readoptions_t; a3: cuchar) {.importc.}
|
||||
proc leveldb_readoptions_set_snapshot*(a2: ptr leveldb_readoptions_t;
|
||||
a3: ptr leveldb_snapshot_t) {.importc.}
|
||||
## # Write options
|
||||
proc leveldb_readoptions_destroy*(a1: ptr leveldb_readoptions_t) {.importc.}
|
||||
proc leveldb_readoptions_set_verify_checksums*(a1: ptr leveldb_readoptions_t;
|
||||
a2: uint8) {.importc.}
|
||||
proc leveldb_readoptions_set_fill_cache*(a1: ptr leveldb_readoptions_t; a2: uint8) {.importc.}
|
||||
proc leveldb_readoptions_set_snapshot*(a1: ptr leveldb_readoptions_t;
|
||||
a2: ptr leveldb_snapshot_t) {.importc.}
|
||||
## Write options
|
||||
|
||||
proc leveldb_writeoptions_create*(): ptr leveldb_writeoptions_t {.importc.}
|
||||
proc leveldb_writeoptions_destroy*(a2: ptr leveldb_writeoptions_t) {.importc.}
|
||||
proc leveldb_writeoptions_set_sync*(a2: ptr leveldb_writeoptions_t; a3: cuchar) {.importc.}
|
||||
## # Cache
|
||||
proc leveldb_writeoptions_destroy*(a1: ptr leveldb_writeoptions_t) {.importc.}
|
||||
proc leveldb_writeoptions_set_sync*(a1: ptr leveldb_writeoptions_t; a2: uint8) {.importc.}
|
||||
## Cache
|
||||
|
||||
proc leveldb_cache_create_lru*(capacity: csize): ptr leveldb_cache_t {.importc.}
|
||||
proc leveldb_cache_destroy*(cache: ptr leveldb_cache_t) {.importc.}
|
||||
## # Env
|
||||
## Env
|
||||
|
||||
proc leveldb_create_default_env*(): ptr leveldb_env_t {.importc.}
|
||||
proc leveldb_env_destroy*(a2: ptr leveldb_env_t) {.importc.}
|
||||
## # Utility
|
||||
## # Calls free(ptr).
|
||||
## # REQUIRES: ptr was malloc()-ed and returned by one of the routines
|
||||
## # in this file. Note that in certain cases (typically on Windows), you
|
||||
## # may need to call this routine instead of free(ptr) to dispose of
|
||||
## # malloc()-ed memory returned by this library.
|
||||
proc leveldb_env_destroy*(a1: ptr leveldb_env_t) {.importc.}
|
||||
## If not NULL, the returned buffer must be released using leveldb_free().
|
||||
|
||||
proc leveldb_env_get_test_directory*(a1: ptr leveldb_env_t): cstring {.importc.}
|
||||
## Utility
|
||||
## Calls free(ptr).
|
||||
## REQUIRES: ptr was malloc()-ed and returned by one of the routines
|
||||
## in this file. Note that in certain cases (typically on Windows), you
|
||||
## may need to call this routine instead of free(ptr) to dispose of
|
||||
## malloc()-ed memory returned by this library.
|
||||
|
||||
proc leveldb_free*(`ptr`: pointer) {.importc.}
|
||||
## # Return the major version number for this release.
|
||||
## Return the major version number for this release.
|
||||
|
||||
proc leveldb_major_version*(): cint {.importc.}
|
||||
## # Return the minor version number for this release.
|
||||
## Return the minor version number for this release.
|
||||
|
||||
proc leveldb_minor_version*(): cint {.importc.}
|
||||
|
|
Loading…
Reference in New Issue