diff --git a/changelog.md b/changelog.md index 0f6be33c3..73d7e7d9b 100644 --- a/changelog.md +++ b/changelog.md @@ -104,6 +104,8 @@ This now needs to be written as: - [``poly``](https://github.com/lcrees/polynumeric) - [``pdcurses``](https://github.com/lcrees/pdcurses) - [``romans``](https://github.com/lcrees/romans) + - [``libsvm``](https://github.com/nim-lang/libsvm_legacy) + - [``joyent_http_parser``](https://github.com/nim-lang/joyent_http_parser) - Added ``system.runnableExamples`` to make examples in Nim's documentation easier to write and test. The examples are tested as the last step of @@ -263,4 +265,4 @@ bar() import std / [strutils, os, osproc] import someNimblePackage / [strutils, os] -``` +``` \ No newline at end of file diff --git a/doc/lib.rst b/doc/lib.rst index 0932b25e4..2e963451d 100644 --- a/doc/lib.rst +++ b/doc/lib.rst @@ -557,21 +557,10 @@ Database support Network Programming and Internet Protocols ------------------------------------------ -* `joyent_http_parser `_ - Wrapper for the joyent's high-performance HTTP parser. - * `openssl `_ Wrapper for OpenSSL. - -Scientific computing --------------------- - -* `libsvm `_ - Low level wrapper for `lib svm `_. - - Nimble ====== diff --git a/lib/pure/asyncfile.nim b/lib/pure/asyncfile.nim index 6ce9e8f75..97bec2815 100644 --- a/lib/pure/asyncfile.nim +++ b/lib/pure/asyncfile.nim @@ -50,22 +50,21 @@ when defined(windows) or defined(nimdoc): case mode of fmRead, fmReadWriteExisting: OPEN_EXISTING - of fmAppend, fmReadWrite, fmWrite: - if fileExists(filename): - OPEN_EXISTING - else: - CREATE_NEW + of fmReadWrite, fmWrite: + CREATE_ALWAYS + of fmAppend: + OPEN_ALWAYS else: proc getPosixFlags(mode: FileMode): cint = case mode of fmRead: result = O_RDONLY of fmWrite: - result = O_WRONLY or O_CREAT + result = O_WRONLY or O_CREAT or O_TRUNC of fmAppend: result = O_WRONLY or O_CREAT or O_APPEND of fmReadWrite: - result = O_RDWR or O_CREAT + result = O_RDWR or O_CREAT or O_TRUNC of fmReadWriteExisting: result = O_RDWR result = result or O_NONBLOCK diff --git a/lib/pure/httpclient.nim b/lib/pure/httpclient.nim index 4c40a81fe..f81e80766 100644 --- a/lib/pure/httpclient.nim +++ b/lib/pure/httpclient.nim @@ -150,6 +150,31 @@ proc code*(response: Response | AsyncResponse): HttpCode ## corresponding ``HttpCode``. return response.status[0 .. 2].parseInt.HttpCode +proc contentType*(response: Response | AsyncResponse): string = + ## Retrieves the specified response's content type. + ## + ## This is effectively the value of the "Content-Type" header. + response.headers.getOrDefault("content-type") + +proc contentLength*(response: Response | AsyncResponse): int = + ## Retrieves the specified response's content length. + ## + ## This is effectively the value of the "Content-Length" header. + ## + ## A ``ValueError`` exception will be raised if the value is not an integer. + var contentLengthHeader = response.headers.getOrDefault("Content-Length") + return contentLengthHeader.parseInt() + +proc lastModified*(response: Response | AsyncResponse): DateTime = + ## Retrieves the specified response's last modified time. + ## + ## This is effectively the value of the "Last-Modified" header. + ## + ## Raises a ``ValueError`` if the parsing fails or the value is not a correctly + ## formatted time. + var lastModifiedHeader = response.headers.getOrDefault("last-modified") + result = parse(lastModifiedHeader, "dd, dd MMM yyyy HH:mm:ss Z") + proc body*(response: Response): string = ## Retrieves the specified response's body. ## diff --git a/lib/pure/net.nim b/lib/pure/net.nim index ba964c39e..99d868847 100644 --- a/lib/pure/net.nim +++ b/lib/pure/net.nim @@ -64,6 +64,9 @@ ## socket.acceptAddr(client, address) ## echo("Client connected from: ", address) ## +## **Note:** The ``client`` variable is initialised with ``new Socket`` **not** +## ``newSocket()``. The difference is that the latter creates a new file +## descriptor. {.deadCodeElim: on.} import nativesockets, os, strutils, parseutils, times, sets, options @@ -753,6 +756,8 @@ proc acceptAddr*(server: Socket, client: var Socket, address: var string, ## flag is specified then this error will not be raised and instead ## accept will be called again. assert(client != nil) + assert client.fd.int <= 0, "Client socket needs to be initialised with " & + "`new`, not `newSocket`." let ret = accept(server.fd) let sock = ret[0] diff --git a/lib/pure/times.nim b/lib/pure/times.nim index 50bf8f7f2..6c1e1fe87 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -933,6 +933,14 @@ proc `$`*(time: Time): string {.tags: [], raises: [], benign.} = proc parseToken(dt: var DateTime; token, value: string; j: var int) = ## Helper of the parse proc to parse individual tokens. + + # Overwrite system.`[]` to raise a ValueError on index out of bounds. + proc `[]`[T, U](s: string, x: HSlice[T, U]): string = + if x.a >= s.len or x.b >= s.len: + raise newException(ValueError, "Value is missing required tokens, got: " & + s) + return system.`[]`(s, x) + var sv: int case token of "d": diff --git a/lib/windows/winlean.nim b/lib/windows/winlean.nim index bd6e58a10..b2c1cc1f5 100644 --- a/lib/windows/winlean.nim +++ b/lib/windows/winlean.nim @@ -666,6 +666,7 @@ const CREATE_ALWAYS* = 2'i32 CREATE_NEW* = 1'i32 OPEN_EXISTING* = 3'i32 + OPEN_ALWAYS* = 4'i32 FILE_BEGIN* = 0'i32 INVALID_SET_FILE_POINTER* = -1'i32 NO_ERROR* = 0'i32 diff --git a/lib/wrappers/joyent_http_parser.nim b/lib/wrappers/joyent_http_parser.nim deleted file mode 100644 index f7412d2b8..000000000 --- a/lib/wrappers/joyent_http_parser.nim +++ /dev/null @@ -1,93 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2015 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -type - csize = int - - HttpDataProc* = proc (a2: ptr HttpParser, at: cstring, length: csize): cint {.cdecl.} - HttpProc* = proc (a2: ptr HttpParser): cint {.cdecl.} - - HttpMethod* = enum - HTTP_DELETE = 0, HTTP_GET, HTTP_HEAD, HTTP_POST, HTTP_PUT, HTTP_CONNECT, - HTTP_OPTIONS, HTTP_TRACE, HTTP_COPY, HTTP_LOCK, HTTP_MKCOL, HTTP_MOVE, - HTTP_PROPFIND, HTTP_PROPPATCH, HTTP_UNLOCK, HTTP_REPORT, HTTP_MKACTIVITY, - HTTP_CHECKOUT, HTTP_MERGE, HTTP_MSEARCH, HTTP_NOTIFY, HTTP_SUBSCRIBE, - HTTP_UNSUBSCRIBE, HTTP_PATCH - - HttpParserType* = enum - HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH - - ParserFlag* = enum - F_CHUNKED = 1 shl 0, - F_CONNECTION_KEEP_ALIVE = 1 shl 1, - F_CONNECTION_CLOSE = 1 shl 2, - F_TRAILING = 1 shl 3, - F_UPGRADE = 1 shl 4, - F_SKIPBODY = 1 shl 5 - - HttpErrNo* = enum - HPE_OK, HPE_CB_message_begin, HPE_CB_path, HPE_CB_query_string, HPE_CB_url, - HPE_CB_fragment, HPE_CB_header_field, HPE_CB_header_value, - HPE_CB_headers_complete, HPE_CB_body, HPE_CB_message_complete, - HPE_INVALID_EOF_STATE, HPE_HEADER_OVERFLOW, HPE_CLOSED_CONNECTION, - HPE_INVALID_VERSION, HPE_INVALID_STATUS, HPE_INVALID_METHOD, - HPE_INVALID_URL, HPE_INVALID_HOST, HPE_INVALID_PORT, HPE_INVALID_PATH, - HPE_INVALID_QUERY_STRING, HPE_INVALID_FRAGMENT, HPE_LF_EXPECTED, - HPE_INVALID_HEADER_TOKEN, HPE_INVALID_CONTENT_LENGTH, - HPE_INVALID_CHUNK_SIZE, HPE_INVALID_CONSTANT, HPE_INVALID_INTERNAL_STATE, - HPE_STRICT, HPE_UNKNOWN - - HttpParser*{.pure, final, importc: "http_parser", header: "http_parser.h".} = object - typ {.importc: "type".}: char - flags {.importc: "flags".}: char - state*{.importc: "state".}: char - header_state*{.importc: "header_state".}: char - index*{.importc: "index".}: char - nread*{.importc: "nread".}: cint - content_length*{.importc: "content_length".}: int64 - http_major*{.importc: "http_major".}: cshort - http_minor*{.importc: "http_minor".}: cshort - status_code*{.importc: "status_code".}: cshort - http_method*{.importc: "method".}: cshort - http_errno_bits {.importc: "http_errno".}: char - upgrade {.importc: "upgrade".}: bool - data*{.importc: "data".}: pointer - - HttpParserSettings*{.pure, final, importc: "http_parser_settings", header: "http_parser.h".} = object - on_message_begin*{.importc: "on_message_begin".}: HttpProc - on_url*{.importc: "on_url".}: HttpDataProc - on_header_field*{.importc: "on_header_field".}: HttpDataProc - on_header_value*{.importc: "on_header_value".}: HttpDataProc - on_headers_complete*{.importc: "on_headers_complete".}: HttpProc - on_body*{.importc: "on_body".}: HttpDataProc - on_message_complete*{.importc: "on_message_complete".}: HttpProc -{.deprecated: [THttpMethod: HttpMethod, THttpParserType: HttpParserType, - TParserFlag: ParserFlag, THttpErrNo: HttpErrNo, - THttpParser: HttpParser, THttpParserSettings: HttpParserSettings].} - -proc http_parser_init*(parser: var HttpParser, typ: HttpParserType){. - importc: "http_parser_init", header: "http_parser.h".} - -proc http_parser_execute*(parser: var HttpParser, - settings: var HttpParserSettings, data: cstring, - len: csize): csize {. - importc: "http_parser_execute", header: "http_parser.h".} - -proc http_should_keep_alive*(parser: var HttpParser): cint{. - importc: "http_should_keep_alive", header: "http_parser.h".} - -proc http_method_str*(m: HttpMethod): cstring{. - importc: "http_method_str", header: "http_parser.h".} - -proc http_errno_name*(err: HttpErrNo): cstring{. - importc: "http_errno_name", header: "http_parser.h".} - -proc http_errno_description*(err: HttpErrNo): cstring{. - importc: "http_errno_description", header: "http_parser.h".} - diff --git a/lib/wrappers/libsvm.nim b/lib/wrappers/libsvm.nim deleted file mode 100644 index ac5889410..000000000 --- a/lib/wrappers/libsvm.nim +++ /dev/null @@ -1,117 +0,0 @@ -# -# -# Nim's Runtime Library -# (c) Copyright 2012 Andreas Rumpf -# -# See the file "copying.txt", included in this -# distribution, for details about the copyright. -# - -## This module is a low level wrapper for `libsvm`:idx:. - -{.deadCodeElim: on.} -const - LIBSVM_VERSION* = 312 - -when defined(windows): - const svmdll* = "libsvm.dll" -elif defined(macosx): - const svmdll* = "libsvm.dylib" -else: - const svmdll* = "libsvm.so" - -type - Node*{.pure, final.} = object - index*: cint - value*: cdouble - - Problem*{.pure, final.} = object - L*: cint - y*: ptr cdouble - x*: ptr ptr Node - - Type*{.size: sizeof(cint).} = enum - C_SVC, NU_SVC, ONE_CLASS, EPSILON_SVR, NU_SVR - - KernelType*{.size: sizeof(cint).} = enum - LINEAR, POLY, RBF, SIGMOID, PRECOMPUTED - - Parameter*{.pure, final.} = object - typ*: Type - kernelType*: KernelType - degree*: cint # for poly - gamma*: cdouble # for poly/rbf/sigmoid - coef0*: cdouble # for poly/sigmoid - # these are for training only - cache_size*: cdouble # in MB - eps*: cdouble # stopping criteria - C*: cdouble # for C_SVC, EPSILON_SVR and NU_SVR - nr_weight*: cint # for C_SVC - weight_label*: ptr cint # for C_SVC - weight*: ptr cdouble # for C_SVC - nu*: cdouble # for NU_SVC, ONE_CLASS, and NU_SVR - p*: cdouble # for EPSILON_SVR - shrinking*: cint # use the shrinking heuristics - probability*: cint # do probability estimates -{.deprecated: [Tnode: Node, Tproblem: Problem, Ttype: Type, - TKernelType: KernelType, Tparameter: Parameter].} - -# -# svm_model -# - -type - Model*{.pure, final.} = object - param*: Parameter # parameter - nr_class*: cint # number of classes, = 2 in regression/one class svm - L*: cint # total #SV - SV*: ptr ptr Node # SVs (SV[l]) - sv_coef*: ptr ptr cdouble # coefficients for SVs in decision functions (sv_coef[k-1][l]) - rho*: ptr cdouble # constants in decision functions (rho[k*(k-1)/2]) - probA*: ptr cdouble # pariwise probability information - probB*: ptr cdouble # for classification only - label*: ptr cint # label of each class (label[k]) - nSV*: ptr cint # number of SVs for each class (nSV[k]) - # nSV[0] + nSV[1] + ... + nSV[k-1] = l - # XXX - free_sv*: cint # 1 if svm_model is created by svm_load_model - # 0 if svm_model is created by svm_train -{.deprecated: [TModel: Model].} - -proc train*(prob: ptr Problem, param: ptr Parameter): ptr Model{.cdecl, - importc: "svm_train", dynlib: svmdll.} -proc cross_validation*(prob: ptr Problem, param: ptr Parameter, nr_fold: cint, - target: ptr cdouble){.cdecl, - importc: "svm_cross_validation", dynlib: svmdll.} -proc save_model*(model_file_name: cstring, model: ptr Model): cint{.cdecl, - importc: "svm_save_model", dynlib: svmdll.} -proc load_model*(model_file_name: cstring): ptr Model{.cdecl, - importc: "svm_load_model", dynlib: svmdll.} -proc get_svm_type*(model: ptr Model): cint{.cdecl, importc: "svm_get_svm_type", - dynlib: svmdll.} -proc get_nr_class*(model: ptr Model): cint{.cdecl, importc: "svm_get_nr_class", - dynlib: svmdll.} -proc get_labels*(model: ptr Model, label: ptr cint){.cdecl, - importc: "svm_get_labels", dynlib: svmdll.} -proc get_svr_probability*(model: ptr Model): cdouble{.cdecl, - importc: "svm_get_svr_probability", dynlib: svmdll.} -proc predict_values*(model: ptr Model, x: ptr Node, dec_values: ptr cdouble): cdouble{. - cdecl, importc: "svm_predict_values", dynlib: svmdll.} -proc predict*(model: ptr Model, x: ptr Node): cdouble{.cdecl, - importc: "svm_predict", dynlib: svmdll.} -proc predict_probability*(model: ptr Model, x: ptr Node, - prob_estimates: ptr cdouble): cdouble{.cdecl, - importc: "svm_predict_probability", dynlib: svmdll.} -proc free_model_content*(model_ptr: ptr Model){.cdecl, - importc: "svm_free_model_content", dynlib: svmdll.} -proc free_and_destroy_model*(model_ptr_ptr: ptr ptr Model){.cdecl, - importc: "svm_free_and_destroy_model", dynlib: svmdll.} -proc destroy_param*(param: ptr Parameter){.cdecl, importc: "svm_destroy_param", - dynlib: svmdll.} -proc check_parameter*(prob: ptr Problem, param: ptr Parameter): cstring{. - cdecl, importc: "svm_check_parameter", dynlib: svmdll.} -proc check_probability_model*(model: ptr Model): cint{.cdecl, - importc: "svm_check_probability_model", dynlib: svmdll.} - -proc set_print_string_function*(print_func: proc (arg: cstring) {.cdecl.}){. - cdecl, importc: "svm_set_print_string_function", dynlib: svmdll.} diff --git a/tests/async/tasyncfile.nim b/tests/async/tasyncfile.nim index 6c0725c88..aa7f03ab1 100644 --- a/tests/async/tasyncfile.nim +++ b/tests/async/tasyncfile.nim @@ -41,11 +41,11 @@ proc main() {.async.} = await file.write("test2") file.close() file = openAsync(fn, fmWrite) - await file.write("test3") + await file.write("t3") file.close() file = openAsync(fn, fmRead) let data = await file.readAll() - doAssert data == "test3" + doAssert data == "t3" file.close() diff --git a/tests/stdlib/ttimes.nim b/tests/stdlib/ttimes.nim index 1f8ae6a22..ae056a79f 100644 --- a/tests/stdlib/ttimes.nim +++ b/tests/stdlib/ttimes.nim @@ -131,6 +131,10 @@ template parseTest(s, f, sExpected: string, ydExpected: int) = echo parsed.yearday, " exp: ", ydExpected check(parsed.yearday == ydExpected) +template parseTestExcp(s, f: string) = + expect ValueError: + let parsed = s.parse(f) + template parseTestTimeOnly(s, f, sExpected: string) = check sExpected in $s.parse(f, utc()) @@ -281,6 +285,51 @@ suite "ttimes": test "parseTest": runTimezoneTests() + test "incorrect inputs: empty string": + parseTestExcp("", "yyyy-MM-dd") + + test "incorrect inputs: year": + parseTestExcp("20-02-19", "yyyy-MM-dd") + + test "incorrect inputs: month number": + parseTestExcp("2018-2-19", "yyyy-MM-dd") + + test "incorrect inputs: month name": + parseTestExcp("2018-Fe", "yyyy-MMM-dd") + + test "incorrect inputs: day": + parseTestExcp("2018-02-1", "yyyy-MM-dd") + + test "incorrect inputs: day of week": + parseTestExcp("2018-Feb-Mo", "yyyy-MMM-ddd") + + test "incorrect inputs: hour": + parseTestExcp("2018-02-19 1:30", "yyyy-MM-dd hh:mm") + + test "incorrect inputs: minute": + parseTestExcp("2018-02-19 16:3", "yyyy-MM-dd hh:mm") + + test "incorrect inputs: second": + parseTestExcp("2018-02-19 16:30:0", "yyyy-MM-dd hh:mm:ss") + + test "incorrect inputs: timezone (z)": + parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss z") + + test "incorrect inputs: timezone (zz) 1": + parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zz") + + test "incorrect inputs: timezone (zz) 2": + parseTestExcp("2018-02-19 16:30:00 +1", "yyyy-MM-dd hh:mm:ss zz") + + test "incorrect inputs: timezone (zzz) 1": + parseTestExcp("2018-02-19 16:30:00 ", "yyyy-MM-dd hh:mm:ss zzz") + + test "incorrect inputs: timezone (zzz) 2": + parseTestExcp("2018-02-19 16:30:00 +01:", "yyyy-MM-dd hh:mm:ss zzz") + + test "incorrect inputs: timezone (zzz) 3": + parseTestExcp("2018-02-19 16:30:00 +01:0", "yyyy-MM-dd hh:mm:ss zzz") + test "dynamic timezone": proc staticOffset(offset: int): Timezone = proc zoneInfoFromTz(adjTime: Time): ZonedTime = diff --git a/web/website.ini b/web/website.ini index 7edaaa712..9dc5949a0 100644 --- a/web/website.ini +++ b/web/website.ini @@ -77,7 +77,5 @@ webdoc: "wrappers/mysql;wrappers/iup" webdoc: "wrappers/sqlite3;wrappers/postgres;wrappers/tinyc;wrappers/odbcsql" webdoc: "wrappers/pcre" webdoc: "wrappers/openssl" -webdoc: "wrappers/joyent_http_parser" webdoc: "posix/posix;wrappers/odbcsql" -webdoc: "wrappers/libsvm.nim"