rktio: further improve header declarations

Also, add variants of `rktio_read` and `rktio_write` that can be more
convenient to use through an FFI.
This commit is contained in:
Matthew Flatt 2017-06-23 19:50:19 -06:00
parent 316df0af7a
commit 990a1d7154
3 changed files with 188 additions and 53 deletions

View File

@ -1,10 +1,32 @@
#lang racket/base #lang racket/base
(require racket/cmdline (require racket/cmdline
racket/pretty racket/pretty
racket/list
racket/match
parser-tools/lex parser-tools/lex
(prefix-in : parser-tools/lex-sre) (prefix-in : parser-tools/lex-sre)
parser-tools/yacc) parser-tools/yacc)
;; Parse "rktio.h" to produce a seqeuence
;; (define-constant <id> <const>) ...
;; <type-def> ...
;; <func-def> ...
;;
;; where
;; <type-def> = (define-type <id> <id>)
;; | (define-struct-type <id> ([<type> <name>] ...))
;;
;; <func-def> = (define-function <type> <id> ([<type> <arg-name>] ...))
;; => never fails
;; | (define-function/errno <err-v> <type> <id> ([<type> <arg-name>] ...))
;; => fails when result equals <err-v>
;; | (define-function/errno+step <err-v> <type> <id> ([<type> <arg-name>] ...))
;; => fails when result equals <err-v>, keep step
;;
;; <type> = <prim-type>
;; | (ref <type>) ; opaque, needs to be deallocated somehow
;; | (* <type>) ; transparent argument, can be represented by a byte string
(define output-file #f) (define output-file #f)
(define input-file (define input-file
@ -22,7 +44,7 @@
(define-empty-tokens delim-tokens (define-empty-tokens delim-tokens
(EOF WHITESPACE (EOF WHITESPACE
OPEN CLOSE COPEN CCLOSE SEMI COMMA STAR LSHIFT EQUAL OPEN CLOSE COPEN CCLOSE SEMI COMMA STAR LSHIFT EQUAL
__RKTIO_H__ EXTERN EXTERN/NOERR EXTERN/STEP __RKTIO_H__ EXTERN EXTERN/NOERR EXTERN/STEP EXTERN/ERR
DEFINE TYPEDEF ENUM STRUCT VOID UNSIGNED SHORT INT CONST)) DEFINE TYPEDEF ENUM STRUCT VOID UNSIGNED SHORT INT CONST))
(define lex (define lex
@ -50,6 +72,7 @@
["RKTIO_EXTERN" 'EXTERN] ["RKTIO_EXTERN" 'EXTERN]
["RKTIO_EXTERN_NOERR" 'EXTERN/NOERR] ["RKTIO_EXTERN_NOERR" 'EXTERN/NOERR]
["RKTIO_EXTERN_STEP" 'EXTERN/STEP] ["RKTIO_EXTERN_STEP" 'EXTERN/STEP]
["RKTIO_EXTERN_ERR" 'EXTERN/ERR]
[(:seq (:or #\_ (:/ #\A #\Z #\a #\z)) [(:seq (:or #\_ (:/ #\A #\Z #\a #\z))
(:* (:or #\_ (:/ #\A #\Z #\a #\z #\0 #\9)))) (:* (:or #\_ (:/ #\A #\Z #\a #\z #\0 #\9))))
(token-ID (string->symbol lexeme))] (token-ID (string->symbol lexeme))]
@ -77,11 +100,12 @@
(grammar (grammar
(<prog> [() null] (<prog> [() null]
[(<decl> <prog>) (cons $1 $2)]) [(<decl> <prog>) (cons $1 $2)])
(<decl> [(DEFINE ID <expr>) `(define ,$2 ,$3)] (<decl> [(DEFINE ID <expr>) `(define-constant ,$2 ,$3)]
[(DEFINE __RKTIO_H__ <expr>) #f] [(DEFINE __RKTIO_H__ <expr>) #f]
[(DEFINE EXTERN ID) #f] [(DEFINE EXTERN ID) #f]
[(DEFINE EXTERN/NOERR EXTERN) #f] [(DEFINE EXTERN/NOERR EXTERN) #f]
[(DEFINE EXTERN/STEP EXTERN) #f] [(DEFINE EXTERN/STEP EXTERN) #f]
[(DEFINE EXTERN/ERR OPEN ID CLOSE EXTERN) #f]
[(STRUCT ID SEMI) #f] [(STRUCT ID SEMI) #f]
[(TYPEDEF <type> <id> SEMI) [(TYPEDEF <type> <id> SEMI)
(if (eq? $2 $3) (if (eq? $2 $3)
@ -92,12 +116,14 @@
`(define-struct-type ,$2 ,$4) `(define-struct-type ,$2 ,$4)
(error 'parse "typedef struct names don't match at ~s" $5))] (error 'parse "typedef struct names don't match at ~s" $5))]
[(<extern> <return-type> <id> OPEN <params> SEMI) [(<extern> <return-type> <id> OPEN <params> SEMI)
(let ([r-type (shift-stars $3 $2)]) (let ([r-type (shift-stars $3 $2)]
`(,(adjust-errno $1 r-type) ,r-type ,(unstar $3) ,$5))] [id (unstar $3)])
`(,@(adjust-errno $1 r-type id) ,r-type ,id ,$5))]
[(ENUM COPEN <enumeration> SEMI) `(begin . ,(enum-definitions $3))]) [(ENUM COPEN <enumeration> SEMI) `(begin . ,(enum-definitions $3))])
(<extern> [(EXTERN) 'define-function/errno] (<extern> [(EXTERN) 'define-function/errno]
[(EXTERN/STEP) 'define-function/errno+step] [(EXTERN/STEP) 'define-function/errno+step]
[(EXTERN/NOERR) 'define-function]) [(EXTERN/NOERR) 'define-function]
[(EXTERN/ERR OPEN ID CLOSE) `(define-function/errno ,$3)])
(<params> [(VOID CLOSE) null] (<params> [(VOID CLOSE) null]
[(<paramlist>) $1]) [(<paramlist>) $1])
(<paramlist> [(<type> <id> CLOSE) `((,(shift-stars $2 $1) ,(unstar $2)))] (<paramlist> [(<type> <id> CLOSE) `((,(shift-stars $2 $1) ,(unstar $2)))]
@ -130,11 +156,15 @@
[(STRUCT ID) $2]) [(STRUCT ID) $2])
(<return-type> [(<type>) $1])))) (<return-type> [(<type>) $1]))))
(define (adjust-errno def-kind r) (define (adjust-errno def-kind r id)
(cond (cond
[(eq? r 'rktio_bool_t) 'define-function] [(eq? id 'rktio_init) '(define-function)] ; init is special, because we can't get an error
[(eq? r 'void) 'define-function] [(eq? r 'rktio_bool_t) '(define-function)]
[else def-kind])) [(eq? r 'void) '(define-function)]
[(pair? def-kind) def-kind]
[(pair? r) '(define-function/errno NULL)]
[(eq? r 'rktio_ok_t) '(define-function/errno #f)]
[else (list def-kind)]))
(define (shift-stars from to) (define (shift-stars from to)
(if (and (pair? from) (if (and (pair? from)
@ -155,16 +185,16 @@
[(pair? (car l)) [(pair? (car l))
(let ([i (cadar l)]) (let ([i (cadar l)])
(cons (cons
`(define ,(caar l) ,i) `(define-constant ,(caar l) ,i)
(loop (cdr l) (add1 i))))] (loop (cdr l) (add1 i))))]
[else [else
(cons (cons
`(define ,(car l) ,i) `(define-constant ,(car l) ,i)
(loop (cdr l) (add1 i)))]))) (loop (cdr l) (add1 i)))])))
;; ---------------------------------------- ;; ----------------------------------------
(define content (define unsorted-unflattened-content
(call-with-input-file input-file (call-with-input-file input-file
(lambda (i) (lambda (i)
(port-count-lines! i) (port-count-lines! i)
@ -175,14 +205,84 @@
[(eq? (position-token-token v) 'WHITESPACE) (loop)] [(eq? (position-token-token v) 'WHITESPACE) (loop)]
[else v])))))))) [else v]))))))))
(define unsorted-content
(for*/list ([l (in-list unsorted-unflattened-content)]
[e (in-list (if (and (pair? l)
(eq? 'begin (car l)))
(cdr l)
(list l)))])
e))
(define (constant-defn? e)
(and (pair? e)
(eq? (car e) 'define-constant)))
(define (type-defn? e)
(and (pair? e)
(or (eq? (car e) 'define-type)
(eq? (car e) 'define-struct-type))))
(define constant-content
(filter constant-defn? unsorted-content))
(define type-content
(filter type-defn? unsorted-content))
(define defined-types
(let ([ht (for/hash ([e (in-list type-content)])
(values (cadr e) #t))])
(for/fold ([ht ht]) ([t (in-list '(char int unsigned-short
intptr_t rktio_int64_t))])
(hash-set ht t #t))))
;; A pointer to a defined type in an argument position
;; is transparent, and it make sense to pass a byte
;; string directly (possibly to be filled in).
;; A pointer to an undefined type is opaque, and a pointer
;; to a defined type is "opaque" in a result position in
;; the sense that it should be explicitly dereferenced and
;; explicitly freed.
(define (update-type t #:as-argument? [as-argument? #f])
(cond
[(and (pair? t) (eq? (car t) '*))
(let ([s (update-type (cadr t))])
(if (and as-argument?
(or (pair? s)
(hash-ref defined-types s #f)))
`(* ,s)
`(ref ,s)))]
[else t]))
(define (update-bind a #:as-argument? [as-argument? #f])
`(,(update-type (car a) #:as-argument? as-argument?) ,(cadr a)))
(define (update-types e)
(match e
[`(,def ,ret ,name ,args)
`(,def ,(update-type ret) ,name
,(map (lambda (a) (update-bind a #:as-argument? #t)) args))]
[else e]))
(define (update-type-types e)
(match e
[`(define-struct-type ,name ,fields)
`(define-struct-type ,name ,(map update-bind fields))]
[else e]))
(define content
(append
constant-content
(map update-type-types type-content)
(map update-types
(filter (lambda (e) (not (or (constant-defn? e) (type-defn? e))))
unsorted-content))))
(define (show-content) (define (show-content)
(printf "(begin\n")
(for ([e (in-list content)] (for ([e (in-list content)]
#:when e) #:when e)
(if (and (pair? e)
(eq? 'begin (car e)))
(for ([e (in-list (cdr e))])
(pretty-write e)) (pretty-write e))
(pretty-write e)))) (printf ")\n"))
(if output-file (if output-file
(with-output-to-file output-file (with-output-to-file output-file

View File

@ -30,9 +30,10 @@ Return type conventions:
- A return type `rktio_tri_t` (alias for `int`) means that 0 is - A return type `rktio_tri_t` (alias for `int`) means that 0 is
returned for an expected failuree, some `RKTIO_...` (alias for 1) returned for an expected failuree, some `RKTIO_...` (alias for 1)
is returned for success, and `RKTIO_...ERROR` (alias for -2) is is returned for success, and `RKTIO_...ERROR` (alias for -2) is
returned for some error. Use `rktio_get_last_error_kind` and returned for some error. The function will be annotated with
`rktio_get_last_error` for more information about a `RKTIO_EXTERN_ERR(...)` to indicate the error value. Use
`RKTIO_...ERROR` result. `rktio_get_last_error_kind` and `rktio_get_last_error` for more
information about a `RKTIO_...ERROR` result.
- A return type `rktio_bool_t` means that the result is a simple 0 or - A return type `rktio_bool_t` means that the result is a simple 0 or
1, and no error is possible. 1, and no error is possible.
@ -82,6 +83,7 @@ Thread and signal conventions:
# define RKTIO_EXTERN extern # define RKTIO_EXTERN extern
#endif #endif
#define RKTIO_EXTERN_ERR(n) RKTIO_EXTERN
#define RKTIO_EXTERN_NOERR RKTIO_EXTERN #define RKTIO_EXTERN_NOERR RKTIO_EXTERN
#define RKTIO_EXTERN_STEP RKTIO_EXTERN #define RKTIO_EXTERN_STEP RKTIO_EXTERN
@ -95,7 +97,9 @@ typedef struct rktio_t rktio_t;
RKTIO_EXTERN rktio_t *rktio_init(void); RKTIO_EXTERN rktio_t *rktio_init(void);
/* Call `rktio_init` before anything else. The first call to /* Call `rktio_init` before anything else. The first call to
`rktio_init` must return before any additional calls (in other `rktio_init` must return before any additional calls (in other
threads), but there's no ordering requirement after that. */ threads), but there's no ordering requirement after that.
If the result is NULL, then there's no way to get an error
code, so assume `RKTIO_ERROR_INIT_FAILED`. */
RKTIO_EXTERN void rktio_destroy(rktio_t *rktio); RKTIO_EXTERN void rktio_destroy(rktio_t *rktio);
/* Call `rktio_destroy` as the last thing. Everything else must be /* Call `rktio_destroy` as the last thing. Everything else must be
@ -232,7 +236,8 @@ RKTIO_EXTERN rktio_fd_t *rktio_std_fd(rktio_t *rktio, int which);
#define RKTIO_STDOUT 1 #define RKTIO_STDOUT 1
#define RKTIO_STDERR 2 #define RKTIO_STDERR 2
RKTIO_EXTERN intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len); RKTIO_EXTERN_ERR(RKTIO_READ_ERROR)
intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len);
/* Returns the number of bytes read, possibly 0, in non-blocking mode. /* Returns the number of bytes read, possibly 0, in non-blocking mode.
Alternatively, the result can be `RKTIO_READ_EOF` for end-of-file Alternatively, the result can be `RKTIO_READ_EOF` for end-of-file
or `RKTIO_READ_ERROR` for an error. Although rktio_read is intended or `RKTIO_READ_ERROR` for an error. Although rktio_read is intended
@ -242,7 +247,8 @@ RKTIO_EXTERN intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *fd, char *buffer, i
#define RKTIO_READ_EOF (-1) #define RKTIO_READ_EOF (-1)
#define RKTIO_READ_ERROR (-2) #define RKTIO_READ_ERROR (-2)
RKTIO_EXTERN intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, const char *buffer, intptr_t len); RKTIO_EXTERN_ERR(RKTIO_WRITE_ERROR)
intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, const char *buffer, intptr_t len);
/* Returns the number of bytes written, possibly 0, in non-blocking /* Returns the number of bytes written, possibly 0, in non-blocking
mode. Alternatively, the result can be `RKTIO_WRITE_ERROR` for an mode. Alternatively, the result can be `RKTIO_WRITE_ERROR` for an
error. Although `rktio_write` is intended to write only bytes that error. Although `rktio_write` is intended to write only bytes that
@ -253,32 +259,45 @@ RKTIO_EXTERN intptr_t rktio_write(rktio_t *rktio, rktio_fd_t *fd, const char *bu
#define RKTIO_WRITE_ERROR (-2) #define RKTIO_WRITE_ERROR (-2)
RKTIO_EXTERN intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len, RKTIO_EXTERN_ERR(RKTIO_READ_ERROR)
intptr_t rktio_read_converted(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t len,
char *is_converted); char *is_converted);
/* Like `rktio_read`, but also reports whether each character was /* Like `rktio_read`, but also reports whether each character was
originally two characters that were converted to a single newline for originally two characters that were converted to a single newline for
text mode. */ text mode. */
RKTIO_EXTERN_ERR(RKTIO_READ_ERROR)
intptr_t rktio_read_in(rktio_t *rktio, rktio_fd_t *fd, char *buffer, intptr_t start, intptr_t end);
RKTIO_EXTERN_ERR(RKTIO_WRITE_ERROR)
intptr_t rktio_write_in(rktio_t *rktio, rktio_fd_t *fd, const char *buffer, intptr_t start, intptr_t end);
/* Like `rktio_read` and `rktio_write`, but accepting start and end
positions within `buffer`. */
RKTIO_EXTERN_NOERR intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd); RKTIO_EXTERN_NOERR intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd);
/* Reports the number of bytes that are buffered from the file descriptor. /* Reports the number of bytes that are buffered from the file descriptor.
The result is normally zero, but text-mode conversion and the rare The result is normally zero, but text-mode conversion and the rare
uncooperative corner of an OS can make the result 1 byte. */ uncooperative corner of an OS can make the result 1 byte. */
RKTIO_EXTERN rktio_tri_t rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN_ERR(RKTIO_POLL_ERROR)
RKTIO_EXTERN rktio_tri_t rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd); rktio_tri_t rktio_poll_read_ready(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN_ERR(RKTIO_POLL_ERROR)
rktio_tri_t rktio_poll_write_ready(rktio_t *rktio, rktio_fd_t *rfd);
/* Each polling function returns one of the following: */ /* Each polling function returns one of the following: */
#define RKTIO_POLL_NOT_READY 0 #define RKTIO_POLL_NOT_READY 0
#define RKTIO_POLL_READY 1 #define RKTIO_POLL_READY 1
#define RKTIO_POLL_ERROR (-2) #define RKTIO_POLL_ERROR (-2)
RKTIO_EXTERN rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN_ERR(RKTIO_POLL_ERROR)
rktio_tri_t rktio_poll_write_flushed(rktio_t *rktio, rktio_fd_t *rfd);
/* See `rktio_write` above. Currently, the result is `RKTIO_POLL_NO_READY` /* See `rktio_write` above. Currently, the result is `RKTIO_POLL_NO_READY`
only on Windows, and only for a pipe or similar non-regular file. only on Windows, and only for a pipe or similar non-regular file.
A pipe counts as "flushed" when the other end has received the data A pipe counts as "flushed" when the other end has received the data
(because the sent data doesn't persist beyond closing the pipe). */ (because the sent data doesn't persist beyond closing the pipe). */
RKTIO_EXTERN rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl); RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR)
RKTIO_EXTERN rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd); rktio_tri_t rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl);
RKTIO_EXTERN_ERR(RKTIO_LOCK_ERROR)
rktio_ok_t rktio_file_unlock(rktio_t *rktio, rktio_fd_t *rfd);
/* Advisory file locks, where `excl` attempts to claim an exclusive /* Advisory file locks, where `excl` attempts to claim an exclusive
lock. Whether these work in various situations depend on many OS lock. Whether these work in various situations depend on many OS
details, where the differences involve promoting from non-exlcusive details, where the differences involve promoting from non-exlcusive
@ -335,7 +354,8 @@ RKTIO_EXTERN rktio_addrinfo_lookup_t *rktio_start_addrinfo_lookup(rktio_t *rktio
#define RKTIO_FAMILY_ANY (-1) #define RKTIO_FAMILY_ANY (-1)
RKTIO_EXTERN_NOERR int rktio_get_ipv4_family(rktio_t *rktio); RKTIO_EXTERN_NOERR int rktio_get_ipv4_family(rktio_t *rktio);
RKTIO_EXTERN rktio_tri_t rktio_poll_addrinfo_lookup_ready(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup); RKTIO_EXTERN_ERR(RKTIO_POLL_ERROR)
rktio_tri_t rktio_poll_addrinfo_lookup_ready(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup);
/* Check whether an address is available for a lookup request. */ /* Check whether an address is available for a lookup request. */
RKTIO_EXTERN rktio_addrinfo_t *rktio_addrinfo_lookup_get(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup); RKTIO_EXTERN rktio_addrinfo_t *rktio_addrinfo_lookup_get(rktio_t *rktio, rktio_addrinfo_lookup_t *lookup);
@ -358,7 +378,8 @@ RKTIO_EXTERN rktio_listener_t *rktio_listen(rktio_t *rktio, rktio_addrinfo_t *lo
RKTIO_EXTERN void rktio_listen_stop(rktio_t *rktio, rktio_listener_t *l); RKTIO_EXTERN void rktio_listen_stop(rktio_t *rktio, rktio_listener_t *l);
/* Stops a listener. */ /* Stops a listener. */
RKTIO_EXTERN rktio_tri_t rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener); RKTIO_EXTERN_ERR(RKTIO_POLL_ERROR)
rktio_tri_t rktio_poll_accept_ready(rktio_t *rktio, rktio_listener_t *listener);
/* Returns one of `RKTIO_POLL_READY`, etc. */ /* Returns one of `RKTIO_POLL_READY`, etc. */
RKTIO_EXTERN rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener); RKTIO_EXTERN rktio_fd_t *rktio_accept(rktio_t *rktio, rktio_listener_t *listener);
@ -377,7 +398,8 @@ RKTIO_EXTERN rktio_fd_t *rktio_connect_finish(rktio_t *rktio, rktio_connect_t *c
RKTIO_EXTERN void rktio_connect_stop(rktio_t *rktio, rktio_connect_t *conn); RKTIO_EXTERN void rktio_connect_stop(rktio_t *rktio, rktio_connect_t *conn);
/* Stops a connection whose result or error has not been received. */ /* Stops a connection whose result or error has not been received. */
RKTIO_EXTERN rktio_tri_t rktio_poll_connect_ready(rktio_t *rktio, rktio_connect_t *conn); RKTIO_EXTERN_ERR(RKTIO_POLL_ERROR)
rktio_tri_t rktio_poll_connect_ready(rktio_t *rktio, rktio_connect_t *conn);
/* Returns one of `RKTIO_POLL_READY`, etc. */ /* Returns one of `RKTIO_POLL_READY`, etc. */
RKTIO_EXTERN rktio_fd_t *rktio_connect_trying(rktio_t *rktio, rktio_connect_t *conn); RKTIO_EXTERN rktio_fd_t *rktio_connect_trying(rktio_t *rktio, rktio_connect_t *conn);
@ -405,7 +427,8 @@ RKTIO_EXTERN rktio_ok_t rktio_udp_bind(rktio_t *rktio, rktio_fd_t *rfd, rktio_ad
rktio_bool_t reuse); rktio_bool_t reuse);
RKTIO_EXTERN rktio_ok_t rktio_udp_connect(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr); RKTIO_EXTERN rktio_ok_t rktio_udp_connect(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr);
RKTIO_EXTERN intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr, RKTIO_EXTERN_ERR(RKTIO_WRITE_ERROR)
intptr_t rktio_udp_sendto(rktio_t *rktio, rktio_fd_t *rfd, rktio_addrinfo_t *addr,
const char *buffer, intptr_t len); const char *buffer, intptr_t len);
/* Extends `rktio_write` to accept a destination `addr`, and binds `rfd` if it /* Extends `rktio_write` to accept a destination `addr`, and binds `rfd` if it
is not bound aready. The `addr` can be NULL if the socket is connected. */ is not bound aready. The `addr` can be NULL if the socket is connected. */
@ -421,10 +444,9 @@ RKTIO_EXTERN rktio_length_and_addrinfo_t *rktio_udp_recvfrom(rktio_t *rktio, rkt
be `RKTIO_ERROR_TRY_AGAIN` or `RKTIO_ERROR_INFO_TRY_AGAIN`, where be `RKTIO_ERROR_TRY_AGAIN` or `RKTIO_ERROR_INFO_TRY_AGAIN`, where
the latter can happen if the sock claims to be ready to read. */ the latter can happen if the sock claims to be ready to read. */
/* The following accessors return `RKTIO_PROP_ERROR` on failure */ RKTIO_EXTERN_ERR(RKTIO_PROP_ERROR) rktio_tri_t rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_tri_t rktio_udp_get_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, rktio_bool_t on); RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_loopback(rktio_t *rktio, rktio_fd_t *rfd, rktio_bool_t on);
RKTIO_EXTERN rktio_tri_t rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd); RKTIO_EXTERN_ERR(RKTIO_PROP_ERROR) rktio_tri_t rktio_udp_get_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd);
RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val); RKTIO_EXTERN rktio_ok_t rktio_udp_set_multicast_ttl(rktio_t *rktio, rktio_fd_t *rfd, int ttl_val);
#define RKTIO_PROP_ERROR (-2) #define RKTIO_PROP_ERROR (-2)
@ -487,7 +509,7 @@ RKTIO_EXTERN char *rktio_envvars_get(rktio_t *rktio, rktio_envvars_t *envvars, c
RKTIO_EXTERN void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, const char *name, const char *value); RKTIO_EXTERN void rktio_envvars_set(rktio_t *rktio, rktio_envvars_t *envvars, const char *name, const char *value);
/* Access/update environment-variables record by name. */ /* Access/update environment-variables record by name. */
RKTIO_EXTERN intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars); RKTIO_EXTERN_NOERR intptr_t rktio_envvars_count(rktio_t *rktio, rktio_envvars_t *envvars);
RKTIO_EXTERN char *rktio_envvars_name_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i); RKTIO_EXTERN char *rktio_envvars_name_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i);
RKTIO_EXTERN char *rktio_envvars_value_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i); RKTIO_EXTERN char *rktio_envvars_value_ref(rktio_t *rktio, rktio_envvars_t *envvars, intptr_t i);
/* Access/update environment-variables record by index. */ /* Access/update environment-variables record by index. */
@ -576,7 +598,8 @@ RKTIO_EXTERN rktio_fs_change_t *rktio_fs_change(rktio_t *rktio, const char *path
RKTIO_EXTERN void rktio_fs_change_forget(rktio_t *rktio, rktio_fs_change_t *fc); RKTIO_EXTERN void rktio_fs_change_forget(rktio_t *rktio, rktio_fs_change_t *fc);
RKTIO_EXTERN rktio_tri_t rktio_poll_fs_change_ready(rktio_t *rktio, rktio_fs_change_t *fc); RKTIO_EXTERN_ERR(RKTIO_POLL_ERROR)
rktio_tri_t rktio_poll_fs_change_ready(rktio_t *rktio, rktio_fs_change_t *fc);
/* Returns one of `RKTIO_POLL_READY`, etc. */ /* Returns one of `RKTIO_POLL_READY`, etc. */
/*************************************************/ /*************************************************/
@ -703,7 +726,7 @@ RKTIO_EXTERN rktio_bool_t rktio_directory_exists(rktio_t *rktio, const char *dir
RKTIO_EXTERN rktio_bool_t rktio_link_exists(rktio_t *rktio, const char *filename); RKTIO_EXTERN rktio_bool_t rktio_link_exists(rktio_t *rktio, const char *filename);
RKTIO_EXTERN rktio_bool_t rktio_is_regular_file(rktio_t *rktio, const char *filename); RKTIO_EXTERN rktio_bool_t rktio_is_regular_file(rktio_t *rktio, const char *filename);
RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, const char *fn, int enable_write_on_fail); RKTIO_EXTERN rktio_ok_t rktio_delete_file(rktio_t *rktio, const char *fn, rktio_bool_t enable_write_on_fail);
RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, const char *dest, const char *src, int exists_ok); RKTIO_EXTERN rktio_ok_t rktio_rename_file(rktio_t *rktio, const char *dest, const char *src, int exists_ok);
/* Can report `RKTIO_ERROR_EXISTS`. */ /* Can report `RKTIO_ERROR_EXISTS`. */
@ -757,7 +780,8 @@ RKTIO_EXTERN rktio_identity_t *rktio_path_identity(rktio_t *rktio, const char *p
#define RKTIO_PERMISSION_ERROR (-1) #define RKTIO_PERMISSION_ERROR (-1)
RKTIO_EXTERN int rktio_get_file_or_directory_permissions(rktio_t *rktio, const char *filename, int all_bits); RKTIO_EXTERN_ERR(RKTIO_PERMISSION_ERROR)
int rktio_get_file_or_directory_permissions(rktio_t *rktio, const char *filename, int all_bits);
/* Result is `RKTIO_PERMISSION_ERROR` for error, otherwise a combination of /* Result is `RKTIO_PERMISSION_ERROR` for error, otherwise a combination of
bits. If not `all_bits`, then use constants above. */ bits. If not `all_bits`, then use constants above. */
@ -973,7 +997,8 @@ RKTIO_EXTERN rktio_converter_t *rktio_converter_open(rktio_t *rktio, const char
RKTIO_EXTERN void rktio_converter_close(rktio_t *rktio, rktio_converter_t *cvt); RKTIO_EXTERN void rktio_converter_close(rktio_t *rktio, rktio_converter_t *cvt);
/* Destroys an encoding converter. */ /* Destroys an encoding converter. */
RKTIO_EXTERN intptr_t rktio_convert(rktio_t *rktio, RKTIO_EXTERN_ERR(RKTIO_CONVERT_ERROR)
intptr_t rktio_convert(rktio_t *rktio,
rktio_converter_t *cvt, rktio_converter_t *cvt,
char **in, intptr_t *in_left, char **in, intptr_t *in_left,
char **out, intptr_t *out_left); char **out, intptr_t *out_left);
@ -1005,12 +1030,12 @@ RKTIO_EXTERN rktio_char16_t *rktio_recase_utf16(rktio_t *rktio,
Takes and optionally returns a length (`olen` can be NULL), but the Takes and optionally returns a length (`olen` can be NULL), but the
UTF-16 sequence is expected to have no nuls. */ UTF-16 sequence is expected to have no nuls. */
RKTIO_EXTERN int rktio_locale_strcoll(rktio_t *rktio, char *s1, char *s2); RKTIO_EXTERN_NOERR int rktio_locale_strcoll(rktio_t *rktio, char *s1, char *s2);
/* Returns -1 if `s1` is less than `s2` by the current locale's /* Returns -1 if `s1` is less than `s2` by the current locale's
comparison, positive is `s1` is greater, and 0 if the strings comparison, positive is `s1` is greater, and 0 if the strings
are equal. */ are equal. */
RKTIO_EXTERN int rktio_strcoll_utf16(rktio_t *rktio, RKTIO_EXTERN_NOERR int rktio_strcoll_utf16(rktio_t *rktio,
rktio_char16_t *s1, intptr_t l1, rktio_char16_t *s1, intptr_t l1,
rktio_char16_t *s2, intptr_t l2, rktio_char16_t *s2, intptr_t l2,
rktio_bool_t cvt_case); rktio_bool_t cvt_case);

View File

@ -853,6 +853,16 @@ intptr_t rktio_read(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t len)
return rktio_read_converted(rktio, rfd, buffer, len, NULL); return rktio_read_converted(rktio, rfd, buffer, len, NULL);
} }
intptr_t rktio_read_in(rktio_t *rktio, rktio_fd_t *rfd, char *buffer, intptr_t start, intptr_t end)
{
return rktio_read_converted(rktio, rfd, buffer+start, end-start, NULL);
}
intptr_t rktio_write_in(rktio_t *rktio, rktio_fd_t *rfd, const char *buffer, intptr_t start, intptr_t end)
{
return rktio_write(rktio, rfd, buffer+start, end-start);
}
RKTIO_EXTERN intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd) RKTIO_EXTERN intptr_t rktio_buffered_byte_count(rktio_t *rktio, rktio_fd_t *fd)
{ {
#ifdef RKTIO_SYSTEM_UNIX #ifdef RKTIO_SYSTEM_UNIX