Sigrid Solveig Haflínudóttiradd argcount_{least,most} for better errors messagesf739ebf2 months agoHistory
774 lines · 17.0 KB · C
RawDownload
#include "inc/priv.h"#include "inc/operators.h"#include "inc/cvalues.h"#include "inc/print.h"#include "inc/read.h"#include "inc/equal.h"#include "inc/io.h"#include "inc/str.h" static sl_v basesym; static const u8int ws[] = {	0x20, 0x0a, 0x09, 0x0b, 0x0c, 0x0d, 0xc2, 0x85,	0xc2, 0xa0, 0xe1, 0x9a, 0x80, 0xe2, 0x80, 0x80,	0xe2, 0x80, 0x81, 0xe2, 0x80, 0x82, 0xe2, 0x80,	0x83, 0xe2, 0x80, 0x84, 0xe2, 0x80, 0x85, 0xe2,	0x80, 0x86, 0xe2, 0x80, 0x87, 0xe2, 0x80, 0x88,	0xe2, 0x80, 0x89, 0xe2, 0x80, 0x8a, 0xe2, 0x80,	0xa8, 0xe2, 0x80, 0xa9, 0xe2, 0x80, 0xaf, 0xe2,	0x81, 0x9f, 0xe3, 0x80, 0x80, 0x00}; static const u32int offsetsFromUTF8[6] = {	0x00000000U, 0x00003080U, 0x000E2080U,	0x03C82080U, 0xFA082080U, 0x82082080U}; static const u8int trailingBytesForUTF8[256] = {	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,	2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5}; /* returns length of next utf-8 sequence */usizeu8_seqlen(const char *s){	return trailingBytesForUTF8[(u8int)s[0]] + 1;} /* modified runenlen from 9front */usizeu8_runelen(const char *s, usize m, bool *err){	const char *es = s + m;	usize n; 	*err = false;	for(n = 0; s < es; n++) {		if(*(const u8int*)s < Runeself){			s++;			continue;		}		if(sl_unlikely(!fullrune(s, es-s))){			*err = true;			break;		}		Rune r;		s += chartorune(&r, s);		if(sl_unlikely(r == Runeerror)){			*err = true;			break;		}	}	return n;} usizeu8_strnlen(const char *s, usize n, ssize maxwidth, ssize *outwidth, bool *err){	usize i, len = 0;	ssize totw = 0, clw = 0;	Rune lastr = Runeerror;	bool skip = false, incluster = false; 	*err = false;	for(i = 0; i < n;){		if(sl_unlikely(!fullrune(s+i, n-i))){			*err = true;			break;		}		Rune r;		usize dt = chartorune(&r, s+i);		if(sl_unlikely(r == Runeerror)){			*err = true;			break;		} 		bool boundary = !skip && !(r == Runevs16 && lastr != Runeerror);		if(boundary && incluster){			if(maxwidth >= 0 && totw + clw > maxwidth)				break;			totw += clw;			len = i;			clw = 0;		}		if(boundary)			incluster = true; 		int w;		if(skip)			skip = false;		else if(r == Runezwj)			skip = true;		else if(r == Runevs16 && lastr != Runeerror){			clw += sl_wcwidth_vs16(lastr);			lastr = Runeerror;		}else if(sl_likely((w = sl_wcwidth(r)) > 0)){			lastr = r;			clw += w;		}else if(w < 0){			*err = true;			break;		}		i += dt;	}	if(incluster && (maxwidth < 0 || totw + clw <= maxwidth)){		totw += clw;		len = i;	}	*outwidth = totw;	return len;} ssizeu8_strwidth(const char *s, usize n, bool *err){	ssize w;	u8_strnlen(s, n, -1, &w, err);	return w;} /* next character without NUL character terminator */Runeu8_nextmemchar(const char *s, usize *i){	usize sz = trailingBytesForUTF8[(u8int)s[*i]];	Rune ch = 0; 	for(usize j = 0; j <= sz; j++){		ch <<= 6;		ch += (u8int)s[(*i)++];	};	return ch - offsetsFromUTF8[sz];} booloctal_digit(char c){	return c >= '0' && c <= '7';} boolhex_digit(char c){	return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');} charread_escape_control_char(char c){	switch(c){	case 'n': return '\n';	case 't': return '\t';	case 'a': return '\a';	case 'b': return '\b';	case 'e': return 0x1b;	case 'f': return '\f';	case 'r': return '\r';	case 'v': return '\v';	}	return c;} static inline intbuf_put2c(char *buf, const char *src){	buf[0] = src[0];	buf[1] = src[1];	buf[2] = '\0';	return 2;} intu8_escape_rune(char *buf, usize sz, Rune ch){	assert(sz > 12);	if(ch == '\\')		return buf_put2c(buf, "\\\\");	if(ch >= 0x20 && ch < 0x7f){		buf[0] = ch;		buf[1] = '\0';		return 1;	}	if(ch > 0xffff)		return snprintf(buf, sz, "\\U%.8"PRIx32, ch);	if(ch >= Runeself)		return snprintf(buf, sz, "\\u%04"PRIx32, ch);	switch(ch){	case '\n': return buf_put2c(buf, "\\n");	case '\t': return buf_put2c(buf, "\\t");	case '\a': return buf_put2c(buf, "\\a");	case '\b': return buf_put2c(buf, "\\b");	case 0x1b: return buf_put2c(buf, "\\e");	case '\f': return buf_put2c(buf, "\\f");	case '\r': return buf_put2c(buf, "\\r");	case '\v': return buf_put2c(buf, "\\v");	}	return snprintf(buf, sz, "\\x%02"PRIx32, ch);} usizeu8_escape(char *buf, usize sz, const char *src, usize *pi, usize end, bool escape_quotes, bool ascii){	usize i = *pi, i0;	Rune ch;	char *start = buf;	char *blim = start + sz-12;	assert(sz > 12); 	while(i < end && buf < blim){		// sz-12: leaves room for longest escape sequence		if(escape_quotes && src[i] == '"'){			buf += buf_put2c(buf, "\\\"");			i++;		}else if(src[i] == '\\'){			buf += buf_put2c(buf, "\\\\");			i++;		}else{			i0 = i;			ch = u8_nextmemchar(src, &i);			if(ascii || !sl_iswprint(ch)){				buf += u8_escape_rune(buf, sz - (buf-start), ch);			}else{				i = i0;				do{					*buf++ = src[i++];				}while(i < end && !isutf(src[i]));			}		}	}	*buf++ = '\0';	*pi = i;	return buf - start;} u8int*u8_memchr(u8int *s, Rune ch, usize sz, usize *charn){	usize i = 0, lasti = 0;	Rune c;	int csz; 	*charn = 0;	while(i < sz){		c = csz = 0;		do{			c <<= 6;			c += (u8int)s[i++];			csz++;		}while(i < sz && !isutf(s[i]));		c -= offsetsFromUTF8[csz-1]; 		if(c == ch)			return s+lasti;		lasti = i;		(*charn)++;	}	return nil;} /* based on the valid_utf8 routine from the PCRE library by Philip Hazel    length is in bytes, since without knowing whether the string is valid   it's hard to know how many characters there are! */boolu8_isvalid(const char *str, int length){	const u8int *p, *pend = (const u8int*)str + length;	u8int c;	int ab; 	for(p = (const u8int*)str; p < pend; p++){		c = *p;		if(sl_likely(c < Runeself))			continue;		if(sl_unlikely((c & 0xc0) != 0xc0))			return false;		ab = trailingBytesForUTF8[c];		if(sl_unlikely(length < ab))			return false;		length -= ab; 		p++;		/* Check top bits in the second byte */		if(sl_unlikely((*p & 0xc0) != 0x80))			return false; 		/* Check for overlong sequences for each different length */		switch(ab){			/* Check for xx00 000x */		case 1:			if(sl_unlikely((c & 0x3e) == 0))				return false;			continue; /* We know there aren't any more bytes to check */ 			/* Check for 1110 0000, xx0x xxxx */		case 2:			if(sl_unlikely(c == 0xe0 && (*p & 0x20) == 0))				return false;			break; 			/* Check for 1111 0000, xx00 xxxx */		case 3:			if(sl_unlikely(c == 0xf0 && (*p & 0x30) == 0))				return false;			break; 			/* Check for 1111 1000, xx00 0xxx */		case 4:			if(sl_unlikely(c == 0xf8 && (*p & 0x38) == 0))				return false;			break; 			/* Check for leading 0xfe or 0xff and then for 1111 1100, xx00 00xx */		case 5:			if(sl_unlikely(c == 0xfe || c == 0xff || (c == 0xfc && (*p & 0x3c) == 0)))				return false;			break; 		default:			abort();		} 		/* Check for valid bytes after the 2nd, if any; all must start 10 */		while(--ab > 0)			if(sl_unlikely((*(++p) & 0xc0) != 0x80))				return false;	} 	return true;} voidu8_reverse(char *dest, const char *src, usize len){	usize si, di; 	if(len == 0)		return; 	dest[di = len] = '\0';	for(si = 0; si < len;){		switch((u8int)src[si]>>4){		case 0xf:			di -= 4;			dest[di+0] = src[si++];			dest[di+1] = src[si++];			dest[di+2] = src[si++];			dest[di+3] = src[si++];			break;		case 0xe:			di -= 3;			dest[di+0] = src[si++];			dest[di+1] = src[si++];			dest[di+2] = src[si++];			break;		case 0xd:		case 0xc:			di -= 2;			dest[di+0] = src[si++];			dest[di+1] = src[si++];			break;		default:			di--;			dest[di+0] = src[si++];			break;		}	}} intisdigit_base(char c, int base){	if(sl_unlikely(base < 11))		return c >= '0' && c < '0'+base;	if(sl_unlikely(base == 32))		return (c >= 'A' && c <= 'Z') || (c >= '2' && c <= '7');	return (c >= '0' && c <= '9') || (c >= 'a' && c < 'a'+base-10) || (c >= 'A' && c < 'A'+base-10);} BUILTIN("str?", strp){	argcount(1);	return isstr(args[0]) ? sl_t : sl_nil;} BUILTIN("str-width", str_width){	argcount(1);	if(sl_unlikely(sl_isrune(args[0]))){		int w = sl_wcwidth(torune(args[0]));		return w < 0 ? sl_nil : fixnum(w);	}	if(sl_unlikely(!isstr(args[0])))		bthrow(type_error(nil, "str", args[0]));	char *str = tostr(args[0]);	usize len = cvalue_len(args[0]);	bool err = false;	ssize w = u8_strwidth(str, len, &err);	return err ? sl_nil : fixnum(w);} BUILTIN("str-reverse", str_reverse){	argcount(1);	if(sl_unlikely(sl_isrune(args[0])))		return args[0];	if(sl_unlikely(!isstr(args[0])))		bthrow(type_error(nil, "str", args[0]));	usize len = cvalue_len(args[0]);	sl_v ns = cvalue_str(len);	u8_reverse(cvalue_data(ns), cvalue_data(args[0]), len);	return ns;} BUILTIN("str", str){	if(sl_unlikely(nargs == 1) && isstr(args[0]))		return args[0];	ios s;	if(sl_unlikely(ios_mem(&s, 0) == nil))		bthrow(error(sl_errmem, "could not allocate in-memory io"));	sl_v oldpr = sym_value(sl_printreadablysym); // FIXME: gc if cvalue	sl_v oldpp = sym_value(sl_printprettysym); // FIXME: gc if cvalue	set(sl_printreadablysym, sl_nil);	set(sl_printprettysym, sl_nil);	sl_v arg;	int i;	sl.pr.f = &s;	FOR_ARGS(i, 0, arg, args){		USED(arg);		sl_print(args[i]);	}	set(sl_printreadablysym, oldpr);	set(sl_printprettysym, oldpp);	sl_cv cv = {		.type = sl_iotype,		{.data = &s},		.len = s.size,	};	sl_v buf = tagptr(&cv, TAG_CVALUE);	sl_v outp = io_to_str(&buf);	ios_free(&s);	return outp;} BUILTIN("str-split", str_split){	argcount_least(1);	char *s = tostr(args[0]);	usize len = cvalue_len(args[0]);	// split on whitespace by default	const char *delim0 = (const char*)ws, *delim = delim0;	usize dlen = 5;	int n = 1;	// second is either a :trim or a separator	if(nargs > n && args[n] != sl_trimsym){		delim = tostr(args[n]);		dlen = cvalue_len(args[n]);		n++;	}	bool trim = false;	// it can only be a :trim X now	if(sl_unlikely(nargs > n)){		if(sl_unlikely(args[n] != sl_trimsym))			bthrow(error(sl_errarg, "invalid argument at position %d", n));		n++;		if(nargs <= n)			argcount(n+1);		trim = args[n] != sl_nil;	}	usize ssz, tokend, tokstart, i = 0;	sl_v first = sl_nil, c = sl_nil, last;	usize junk;	sl_gc_handle(&first);	sl_gc_handle(&last); 	do{		// find and allocate next token		tokstart = tokend = i;		while(i < len && !u8_memchr((u8int*)delim, u8_nextmemchar(s, &i), dlen, &junk))			tokend = i;		ssz = tokend - tokstart;		if(ssz == 0 && trim)

Lines 1–500 of 774.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t