refactored escape sequence handling a bit, added error for invalid hex

discarding rest of input line after a parse error
made compare() do less work for unordered comparison
added peekc and purge to ios
This commit is contained in:
JeffBezanson 2008-11-06 04:04:04 +00:00
parent 120522c212
commit c89111f7cb
12 changed files with 180 additions and 99 deletions

View File

@ -30,10 +30,8 @@ static void eq_union(ptrhash_t *table, value_t a, value_t b,
ptrhash_put(table, (void*)b, (void*)ca); ptrhash_put(table, (void*)b, (void*)ca);
} }
// ordered comparison
// a is a fixnum, b is a cvalue // a is a fixnum, b is a cvalue
static value_t compare_num_cvalue(value_t a, value_t b) static value_t compare_num_cvalue(value_t a, value_t b, int eq)
{ {
cvalue_t *bcv = (cvalue_t*)ptr(b); cvalue_t *bcv = (cvalue_t*)ptr(b);
numerictype_t bt; numerictype_t bt;
@ -42,6 +40,7 @@ static value_t compare_num_cvalue(value_t a, value_t b)
void *bptr = cv_data(bcv); void *bptr = cv_data(bcv);
if (cmp_eq(&ia, T_FIXNUM, bptr, bt)) if (cmp_eq(&ia, T_FIXNUM, bptr, bt))
return fixnum(0); return fixnum(0);
if (eq) return fixnum(1);
if (cmp_lt(&ia, T_FIXNUM, bptr, bt)) if (cmp_lt(&ia, T_FIXNUM, bptr, bt))
return fixnum(-1); return fixnum(-1);
} }
@ -51,17 +50,19 @@ static value_t compare_num_cvalue(value_t a, value_t b)
return fixnum(1); return fixnum(1);
} }
static value_t bounded_compare(value_t a, value_t b, int bound); static value_t bounded_compare(value_t a, value_t b, int bound, int eq);
static value_t cyc_compare(value_t a, value_t b, ptrhash_t *table); static value_t cyc_compare(value_t a, value_t b, ptrhash_t *table, int eq);
static value_t bounded_vector_compare(value_t a, value_t b, int bound) static value_t bounded_vector_compare(value_t a, value_t b, int bound, int eq)
{ {
size_t la = vector_size(a); size_t la = vector_size(a);
size_t lb = vector_size(b); size_t lb = vector_size(b);
size_t m, i; size_t m, i;
if (eq && (la!=lb)) return fixnum(1);
m = la < lb ? la : lb; m = la < lb ? la : lb;
for (i = 0; i < m; i++) { for (i = 0; i < m; i++) {
value_t d = bounded_compare(vector_elt(a,i), vector_elt(b,i), bound-1); value_t d = bounded_compare(vector_elt(a,i), vector_elt(b,i),
bound-1, eq);
if (d==NIL || numval(d)!=0) return d; if (d==NIL || numval(d)!=0) return d;
} }
if (la < lb) return fixnum(-1); if (la < lb) return fixnum(-1);
@ -71,7 +72,7 @@ static value_t bounded_vector_compare(value_t a, value_t b, int bound)
// strange comparisons are resolved arbitrarily but consistently. // strange comparisons are resolved arbitrarily but consistently.
// ordering: number < builtin < cvalue < vector < symbol < cons // ordering: number < builtin < cvalue < vector < symbol < cons
static value_t bounded_compare(value_t a, value_t b, int bound) static value_t bounded_compare(value_t a, value_t b, int bound, int eq)
{ {
value_t d; value_t d;
@ -88,16 +89,17 @@ static value_t bounded_compare(value_t a, value_t b, int bound)
return (numval(a) < numval(b)) ? fixnum(-1) : fixnum(1); return (numval(a) < numval(b)) ? fixnum(-1) : fixnum(1);
} }
if (iscvalue(b)) { if (iscvalue(b)) {
return compare_num_cvalue(a, b); return compare_num_cvalue(a, b, eq);
} }
return fixnum(-1); return fixnum(-1);
case TAG_SYM: case TAG_SYM:
if (eq) return fixnum(1);
if (tagb < TAG_SYM) return fixnum(1); if (tagb < TAG_SYM) return fixnum(1);
if (tagb > TAG_SYM) return fixnum(-1); if (tagb > TAG_SYM) return fixnum(-1);
return fixnum(strcmp(symbol_name(a), symbol_name(b))); return fixnum(strcmp(symbol_name(a), symbol_name(b)));
case TAG_VECTOR: case TAG_VECTOR:
if (isvector(b)) if (isvector(b))
return bounded_vector_compare(a, b, bound); return bounded_vector_compare(a, b, bound, eq);
break; break;
case TAG_CVALUE: case TAG_CVALUE:
if (iscvalue(b)) { if (iscvalue(b)) {
@ -109,6 +111,7 @@ static value_t bounded_compare(value_t a, value_t b, int bound)
void *bptr = cv_data(bcv); void *bptr = cv_data(bcv);
if (cmp_eq(aptr, at, bptr, bt)) if (cmp_eq(aptr, at, bptr, bt))
return fixnum(0); return fixnum(0);
if (eq) return fixnum(1);
if (cmp_lt(aptr, at, bptr, bt)) if (cmp_lt(aptr, at, bptr, bt))
return fixnum(-1); return fixnum(-1);
return fixnum(1); return fixnum(1);
@ -116,7 +119,7 @@ static value_t bounded_compare(value_t a, value_t b, int bound)
return cvalue_compare(a, b); return cvalue_compare(a, b);
} }
else if (isfixnum(b)) { else if (isfixnum(b)) {
return fixnum(-numval(compare_num_cvalue(b, a))); return fixnum(-numval(compare_num_cvalue(b, a, eq)));
} }
break; break;
case TAG_BUILTIN: case TAG_BUILTIN:
@ -126,7 +129,7 @@ static value_t bounded_compare(value_t a, value_t b, int bound)
break; break;
case TAG_CONS: case TAG_CONS:
if (tagb < TAG_CONS) return fixnum(1); if (tagb < TAG_CONS) return fixnum(1);
d = bounded_compare(car_(a), car_(b), bound-1); d = bounded_compare(car_(a), car_(b), bound-1, eq);
if (d==NIL || numval(d) != 0) return d; if (d==NIL || numval(d) != 0) return d;
a = cdr_(a); b = cdr_(b); a = cdr_(a); b = cdr_(b);
bound--; bound--;
@ -135,7 +138,8 @@ static value_t bounded_compare(value_t a, value_t b, int bound)
return (taga < tagb) ? fixnum(-1) : fixnum(1); return (taga < tagb) ? fixnum(-1) : fixnum(1);
} }
static value_t cyc_vector_compare(value_t a, value_t b, ptrhash_t *table) static value_t cyc_vector_compare(value_t a, value_t b, ptrhash_t *table,
int eq)
{ {
size_t la = vector_size(a); size_t la = vector_size(a);
size_t lb = vector_size(b); size_t lb = vector_size(b);
@ -143,12 +147,13 @@ static value_t cyc_vector_compare(value_t a, value_t b, ptrhash_t *table)
value_t d, xa, xb, ca, cb; value_t d, xa, xb, ca, cb;
// first try to prove them different with no recursion // first try to prove them different with no recursion
if (eq && (la!=lb)) return fixnum(1);
m = la < lb ? la : lb; m = la < lb ? la : lb;
for (i = 0; i < m; i++) { for (i = 0; i < m; i++) {
xa = vector_elt(a,i); xa = vector_elt(a,i);
xb = vector_elt(b,i); xb = vector_elt(b,i);
if (leafp(xa) || leafp(xb)) { if (leafp(xa) || leafp(xb)) {
d = bounded_compare(xa, xb, 1); d = bounded_compare(xa, xb, 1, eq);
if (numval(d)!=0) return d; if (numval(d)!=0) return d;
} }
else if (cmptag(xa) < cmptag(xb)) { else if (cmptag(xa) < cmptag(xb)) {
@ -170,7 +175,7 @@ static value_t cyc_vector_compare(value_t a, value_t b, ptrhash_t *table)
xa = vector_elt(a,i); xa = vector_elt(a,i);
xb = vector_elt(b,i); xb = vector_elt(b,i);
if (!leafp(xa) && !leafp(xb)) { if (!leafp(xa) && !leafp(xb)) {
d = cyc_compare(xa, xb, table); d = cyc_compare(xa, xb, table, eq);
if (numval(d)!=0) if (numval(d)!=0)
return d; return d;
} }
@ -181,7 +186,7 @@ static value_t cyc_vector_compare(value_t a, value_t b, ptrhash_t *table)
return fixnum(0); return fixnum(0);
} }
static value_t cyc_compare(value_t a, value_t b, ptrhash_t *table) static value_t cyc_compare(value_t a, value_t b, ptrhash_t *table, int eq)
{ {
if (a==b) if (a==b)
return fixnum(0); return fixnum(0);
@ -193,7 +198,7 @@ static value_t cyc_compare(value_t a, value_t b, ptrhash_t *table)
int tagab = cmptag(ab); int tagdb = cmptag(db); int tagab = cmptag(ab); int tagdb = cmptag(db);
value_t d, ca, cb; value_t d, ca, cb;
if (leafp(aa) || leafp(ab)) { if (leafp(aa) || leafp(ab)) {
d = bounded_compare(aa, ab, 1); d = bounded_compare(aa, ab, 1, eq);
if (numval(d)!=0) return d; if (numval(d)!=0) return d;
} }
else if (tagaa < tagab) else if (tagaa < tagab)
@ -201,7 +206,7 @@ static value_t cyc_compare(value_t a, value_t b, ptrhash_t *table)
else if (tagaa > tagab) else if (tagaa > tagab)
return fixnum(1); return fixnum(1);
if (leafp(da) || leafp(db)) { if (leafp(da) || leafp(db)) {
d = bounded_compare(da, db, 1); d = bounded_compare(da, db, 1, eq);
if (numval(d)!=0) return d; if (numval(d)!=0) return d;
} }
else if (tagda < tagdb) else if (tagda < tagdb)
@ -215,18 +220,18 @@ static value_t cyc_compare(value_t a, value_t b, ptrhash_t *table)
return fixnum(0); return fixnum(0);
eq_union(table, a, b, ca, cb); eq_union(table, a, b, ca, cb);
d = cyc_compare(aa, ab, table); d = cyc_compare(aa, ab, table, eq);
if (numval(d)!=0) return d; if (numval(d)!=0) return d;
return cyc_compare(da, db, table); return cyc_compare(da, db, table, eq);
} }
else { else {
return fixnum(1); return fixnum(1);
} }
} }
else if (isvector(a) && isvector(b)) { else if (isvector(a) && isvector(b)) {
return cyc_vector_compare(a, b, table); return cyc_vector_compare(a, b, table, eq);
} }
return bounded_compare(a, b, 1); return bounded_compare(a, b, 1, eq);
} }
static ptrhash_t equal_eq_hashtable; static ptrhash_t equal_eq_hashtable;
@ -235,21 +240,27 @@ void comparehash_init()
ptrhash_new(&equal_eq_hashtable, 512); ptrhash_new(&equal_eq_hashtable, 512);
} }
value_t compare(value_t a, value_t b) // 'eq' means unordered comparison is sufficient
static value_t compare_(value_t a, value_t b, int eq)
{ {
value_t guess = bounded_compare(a, b, 2048); value_t guess = bounded_compare(a, b, 2048, eq);
if (guess == NIL) { if (guess == NIL) {
guess = cyc_compare(a, b, &equal_eq_hashtable); guess = cyc_compare(a, b, &equal_eq_hashtable, eq);
ptrhash_reset(&equal_eq_hashtable, 512); ptrhash_reset(&equal_eq_hashtable, 512);
} }
return guess; return guess;
} }
value_t compare(value_t a, value_t b)
{
return compare_(a, b, 0);
}
value_t equal(value_t a, value_t b) value_t equal(value_t a, value_t b)
{ {
if (eq_comparable(a, b)) if (eq_comparable(a, b))
return (a == b) ? T : NIL; return (a == b) ? T : NIL;
return (numval(compare(a,b))==0 ? T : NIL); return (numval(compare_(a,b,1))==0 ? T : NIL);
} }
/* /*

View File

@ -1509,7 +1509,13 @@ int main(int argc, char *argv[])
repl: repl:
while (1) { while (1) {
ios_puts("> ", ios_stdout); ios_flush(ios_stdout); ios_puts("> ", ios_stdout); ios_flush(ios_stdout);
v = read_sexpr(ios_stdin); FL_TRY {
v = read_sexpr(ios_stdin);
}
FL_CATCH {
ios_purge(ios_stdin);
raise(lasterror);
}
if (ios_eof(ios_stdin)) break; if (ios_eof(ios_stdin)) break;
print(ios_stdout, v=toplevel_eval(v), 0); print(ios_stdout, v=toplevel_eval(v), 0);
set(symbol("that"), v); set(symbol("that"), v);

View File

@ -357,7 +357,6 @@ static value_t read_string(ios_t *f)
else if ((c=='x' && (ndig=2)) || else if ((c=='x' && (ndig=2)) ||
(c=='u' && (ndig=4)) || (c=='u' && (ndig=4)) ||
(c=='U' && (ndig=8))) { (c=='U' && (ndig=8))) {
wc = c;
c = ios_getc(f); c = ios_getc(f);
while (hex_digit(c) && j<ndig && (c!=IOS_EOF)) { while (hex_digit(c) && j<ndig && (c!=IOS_EOF)) {
eseq[j++] = c; eseq[j++] = c;
@ -366,24 +365,15 @@ static value_t read_string(ios_t *f)
if (c!=IOS_EOF) ios_ungetc(c, f); if (c!=IOS_EOF) ios_ungetc(c, f);
eseq[j] = '\0'; eseq[j] = '\0';
if (j) wc = strtol(eseq, NULL, 16); if (j) wc = strtol(eseq, NULL, 16);
else {
free(buf);
lerror(ParseError, "read: invalid escape sequence");
}
i += u8_wc_toutf8(&buf[i], wc); i += u8_wc_toutf8(&buf[i], wc);
} }
else if (c == 'n') else {
buf[i++] = '\n'; buf[i++] = read_escape_control_char((char)c);
else if (c == 't') }
buf[i++] = '\t';
else if (c == 'r')
buf[i++] = '\r';
else if (c == 'b')
buf[i++] = '\b';
else if (c == 'f')
buf[i++] = '\f';
else if (c == 'v')
buf[i++] = '\v';
else if (c == 'a')
buf[i++] = '\a';
else
buf[i++] = c;
} }
else { else {
buf[i++] = c; buf[i++] = c;

View File

@ -47,11 +47,10 @@
(defun nconc lsts (defun nconc lsts
(cond ((null lsts) ()) (cond ((null lsts) ())
((null (cdr lsts)) (car lsts)) ((null (cdr lsts)) (car lsts))
(T ((lambda (l d) (if (null l) d ((null (car lsts)) (apply nconc (cdr lsts)))
(prog1 l (T (prog1 (car lsts)
(while (consp (cdr l)) (setq l (cdr l))) (rplacd (last (car lsts))
(rplacd l d)))) (apply nconc (cdr lsts)))))))
(car lsts) (apply nconc (cdr lsts))))))
(defun append lsts (defun append lsts
(cond ((null lsts) ()) (cond ((null lsts) ())
@ -211,10 +210,21 @@
(defun transpose (M) (apply mapcar (cons list M))) (defun transpose (M) (apply mapcar (cons list M)))
(defun filter (pred lst) (defun filter (pred lst) (filter- pred lst nil))
(cond ((null lst) ()) (defun filter- (pred lst accum)
((pred (car lst)) (cons (car lst) (filter pred (cdr lst)))) (cond ((null lst) accum)
(T (filter pred (cdr lst))))) ((pred (car lst))
(filter- pred (cdr lst) (cons (car lst) accum)))
(T
(filter- pred (cdr lst) accum))))
(defun separate (pred lst) (separate- pred lst nil nil))
(defun separate- (pred lst yes no)
(cond ((null lst) (cons yes no))
((pred (car lst))
(separate- pred (cdr lst) (cons (car lst) yes) no))
(T
(separate- pred (cdr lst) yes (cons (car lst) no)))))
(define (foldr f zero lst) (define (foldr f zero lst)
(if (null lst) zero (if (null lst) zero

View File

@ -79,22 +79,30 @@ value_t fl_hashtablep(value_t *args, u_int32_t nargs)
return NIL; return NIL;
} }
// (put table key value)
value_t fl_hash_put(value_t *args, u_int32_t nargs) value_t fl_hash_put(value_t *args, u_int32_t nargs)
{ {
argcount("put", nargs, 3);
return NIL; return NIL;
} }
// (get table key)
value_t fl_hash_get(value_t *args, u_int32_t nargs) value_t fl_hash_get(value_t *args, u_int32_t nargs)
{ {
argcount("get", nargs, 2);
return NIL; return NIL;
} }
// (has table key)
value_t fl_hash_has(value_t *args, u_int32_t nargs) value_t fl_hash_has(value_t *args, u_int32_t nargs)
{ {
argcount("has", nargs, 2);
return NIL; return NIL;
} }
// (del table key)
value_t fl_hash_delete(value_t *args, u_int32_t nargs) value_t fl_hash_delete(value_t *args, u_int32_t nargs)
{ {
argcount("del", nargs, 2);
return NIL; return NIL;
} }

View File

@ -43,10 +43,11 @@
(defun sort (l) (defun sort (l)
(if (or (null l) (null (cdr l))) l (if (or (null l) (null (cdr l))) l
(let ((piv (car l))) (let* ((piv (car l))
(nconc (sort (filter (lambda (x) (<= x piv)) (cdr l))) (halves (separate (lambda (x) (< x piv)) (cdr l))))
(nconc (sort (car halves))
(list piv) (list piv)
(sort (filter (lambda (x) (> x piv)) (cdr l))))))) (sort (cdr halves))))))
(defmacro dotimes (var . body) (defmacro dotimes (var . body)
(let ((v (car var)) (let ((v (car var))

View File

@ -928,3 +928,35 @@ consolidated todo list as of 8/30:
- remaining cvalues functions - remaining cvalues functions
- special efficient reader for #array - special efficient reader for #array
- finish ios - finish ios
-----------------------------------------------------------------------------
cvalues redesign
goals:
. allow custom types with vtables
. use less space, share types more
. simplify access to important metadata like length
. unify vectors and arrays
typedef struct {
fltype_t *type;
void *data;
size_t len; // length of *data in bytes
value_t parent; // optional
char data[1]; // variable size
} cvalue_t;
typedef struct {
fltype_t *type;
void *data;
} cprim_t;
typedef struct _fltype_t {
value_t type;
int numtype;
size_t sz;
cvtable_t *vtable;
struct _fltype_t *eltype; // for arrays
} fltype_t;

View File

@ -715,6 +715,16 @@ int ios_getc(ios_t *s)
return (int)ch; return (int)ch;
} }
int ios_peekc(ios_t *s)
{
if (s->bpos < s->size)
return s->buf[s->bpos];
if (s->_eof) return IOS_EOF;
size_t n = ios_readprep(s, 1);
if (n == 0) return IOS_EOF;
return s->buf[s->bpos];
}
int ios_ungetc(int c, ios_t *s) int ios_ungetc(int c, ios_t *s)
{ {
if (s->state == bst_wr) if (s->state == bst_wr)
@ -761,6 +771,13 @@ int ios_getutf8(ios_t *s, uint32_t *pwc)
return 1; return 1;
} }
void ios_purge(ios_t *s)
{
if (s->state == bst_rd) {
s->bpos = s->size;
}
}
int ios_printf(ios_t *s, char *format, ...) int ios_printf(ios_t *s, char *format, ...)
{ {
char *str=NULL; char *str=NULL;

View File

@ -112,6 +112,9 @@ int ios_getstringn(ios_t *dest, ios_t *src, size_t nchars);
int ios_readline(ios_t *dest, ios_t *s, char delim); int ios_readline(ios_t *dest, ios_t *s, char delim);
int ios_getline(ios_t *s, char **pbuf, size_t *psz); int ios_getline(ios_t *s, char **pbuf, size_t *psz);
// discard data buffered for reading
void ios_purge(ios_t *s);
// seek by utf8 sequence increments // seek by utf8 sequence increments
int ios_nextutf8(ios_t *s); int ios_nextutf8(ios_t *s);
int ios_prevutf8(ios_t *s); int ios_prevutf8(ios_t *s);
@ -121,6 +124,7 @@ int ios_prevutf8(ios_t *s);
int ios_putc(int c, ios_t *s); int ios_putc(int c, ios_t *s);
//wint_t ios_putwc(ios_t *s, wchar_t wc); //wint_t ios_putwc(ios_t *s, wchar_t wc);
int ios_getc(ios_t *s); int ios_getc(ios_t *s);
int ios_peekc(ios_t *s);
//wint_t ios_getwc(ios_t *s); //wint_t ios_getwc(ios_t *s);
int ios_ungetc(int c, ios_t *s); int ios_ungetc(int c, ios_t *s);
//wint_t ios_ungetwc(ios_t *s, wint_t wc); //wint_t ios_ungetwc(ios_t *s, wint_t wc);

View File

@ -70,7 +70,7 @@ static void **ptrhash_lookup_bp(ptrhash_t *h, void *key)
orig = index; orig = index;
do { do {
if (tab[index] == PH_NOTFOUND) { if (tab[index+1] == PH_NOTFOUND) {
tab[index] = key; tab[index] = key;
return &tab[index+1]; return &tab[index+1];
} }

View File

@ -313,56 +313,56 @@ int hex_digit(char c)
(c >= 'a' && c <= 'f')); (c >= 'a' && c <= 'f'));
} }
/* assumes that src points to the character after a backslash char read_escape_control_char(char c)
returns number of input characters processed */
int u8_read_escape_sequence(const char *str, u_int32_t *dest)
{ {
u_int32_t ch; if (c == 'n')
char digs[9]="\0\0\0\0\0\0\0\0\0"; return '\n';
int dno=0, i=1; else if (c == 't')
return '\t';
else if (c == 'r')
return '\r';
else if (c == 'b')
return '\b';
else if (c == 'f')
return '\f';
else if (c == 'v')
return '\v';
else if (c == 'a')
return '\a';
return c;
}
ch = (u_int32_t)str[0]; /* take literal character */ /* assumes that src points to the character after a backslash
if (str[0] == 'n') returns number of input characters processed, 0 if error */
ch = L'\n'; size_t u8_read_escape_sequence(const char *str, size_t ssz, u_int32_t *dest)
else if (str[0] == 't') {
ch = L'\t'; assert(ssz > 0);
else if (str[0] == 'r') u_int32_t ch;
ch = L'\r'; char digs[10];
else if (str[0] == 'b') int dno=0, ndig;
ch = L'\b'; size_t i=1;
else if (str[0] == 'f') char c0 = str[0];
ch = L'\f';
else if (str[0] == 'v') if (octal_digit(c0)) {
ch = L'\v';
else if (str[0] == 'a')
ch = L'\a';
else if (octal_digit(str[0])) {
i = 0; i = 0;
do { do {
digs[dno++] = str[i++]; digs[dno++] = str[i++];
} while (octal_digit(str[i]) && dno < 3); } while (i<ssz && octal_digit(str[i]) && dno<3);
digs[dno] = '\0';
ch = strtol(digs, NULL, 8); ch = strtol(digs, NULL, 8);
} }
else if (str[0] == 'x') { else if ((c0=='x' && (ndig=2)) ||
while (hex_digit(str[i]) && dno < 2) { (c0=='u' && (ndig=4)) ||
(c0=='U' && (ndig=8))) {
while (i<ssz && hex_digit(str[i]) && dno<ndig) {
digs[dno++] = str[i++]; digs[dno++] = str[i++];
} }
if (dno > 0) if (dno == 0) return 0;
ch = strtol(digs, NULL, 16); digs[dno] = '\0';
ch = strtol(digs, NULL, 16);
} }
else if (str[0] == 'u') { else {
while (hex_digit(str[i]) && dno < 4) { ch = (u_int32_t)read_escape_control_char(c0);
digs[dno++] = str[i++];
}
if (dno > 0)
ch = strtol(digs, NULL, 16);
}
else if (str[0] == 'U') {
while (hex_digit(str[i]) && dno < 8) {
digs[dno++] = str[i++];
}
if (dno > 0)
ch = strtol(digs, NULL, 16);
} }
*dest = ch; *dest = ch;
@ -381,7 +381,7 @@ size_t u8_unescape(char *buf, size_t sz, const char *src)
while (*src && c < sz) { while (*src && c < sz) {
if (*src == '\\') { if (*src == '\\') {
src++; src++;
amt = u8_read_escape_sequence(src, &ch); amt = u8_read_escape_sequence(src, 1000, &ch);
} }
else { else {
ch = (u_int32_t)*src; ch = (u_int32_t)*src;

View File

@ -55,10 +55,12 @@ size_t u8_charlen(u_int32_t ch);
/* computes the # of bytes needed to encode a WC string as UTF-8 */ /* computes the # of bytes needed to encode a WC string as UTF-8 */
size_t u8_codingsize(u_int32_t *wcstr, size_t n); size_t u8_codingsize(u_int32_t *wcstr, size_t n);
char read_escape_control_char(char c);
/* assuming src points to the character after a backslash, read an /* assuming src points to the character after a backslash, read an
escape sequence, storing the result in dest and returning the number of escape sequence, storing the result in dest and returning the number of
input characters processed */ input characters processed */
int u8_read_escape_sequence(const char *src, u_int32_t *dest); size_t u8_read_escape_sequence(const char *src, size_t ssz, u_int32_t *dest);
/* given a wide character, convert it to an ASCII escape sequence stored in /* given a wide character, convert it to an ASCII escape sequence stored in
buf, where buf is "sz" bytes. returns the number of characters output. buf, where buf is "sz" bytes. returns the number of characters output.