443 lines · 7.5 KB · C
RawDownload
#include "platform.h"#include "utf.h" #include "runenormdata" //Unicode Standard: Section 3.12 Conjoining Jamo Behaviorenum {	SBase = 0xAC00,	LBase = 0x1100,	VBase = 0x1161,	TBase = 0x11A7, 	LCount = 19,	VCount = 21,	TCount = 28,	NCount = VCount * TCount,	SCount = LCount * NCount, 	LLast = LBase + LCount - 1,	SLast = SBase + SCount - 1,	VLast = VBase + VCount - 1,	TLast = TBase + TCount - 1,}; /* * Most runes decompose in to one/two * other runes with codepoints < 0xFFFF, * however there are some exceptions. * To keep the table size down we instead * store an index in to an exception range * within the private use section and use * an exception table. */enum {	Estart = 0xEEEE,	Estop = 0xF8FF,}; static Rune_runedecomp(Rune c, Rune *r2){	u32int x; 	if(c < Runeself){		*r2 = 0;		return 0;	} 	//korean	if(c >= SBase && c <= SLast){		c -= SBase;		x = c % TCount;		if(x){			*r2 = TBase + x;			return SBase + (c - x);		}		*r2 = VBase + ((c % NCount) / TCount);		return LBase + (c / NCount);	} 	x = decomplkup(c);	if((x & 0xFFFF) != 0){		*r2 = x & 0xFFFF;		return x>>16;	}	x >>= 16;	if(x >= Estart && x < Estop){		const Rune *r = _decompexceptions[x - Estart];		*r2 = r[1];		return r[0];	}	*r2 = 0;	return x;} sl_purefnstatic Rune_runerecomp(Rune r0, Rune r1){	u32int x, y, next;	const u32int *p; 	if(r0 >= LBase && r0 <= LLast){		if(r1 < VBase || r1 > VLast)			return 0;		x = (r0 - LBase) * NCount + (r1 - VBase) * TCount;		return SBase + x;	}	if(r0 >= SBase && r0 <= SLast && (r0 - SBase) % TCount == 0){		if(r1 > TBase && r1 <= TLast)			return r0 + (r1 - TBase);		return 0;	}	if(r0 > 0xFFFF || r1 > 0xFFFF){		for(x = 0; x < nelem(_recompexceptions); x++)			if(r0 == _recompexceptions[x][1] && r1 == _recompexceptions[x][2])				return  _recompexceptions[x][0];		return 0;	}	y = x = r0<<16 | r1;	x ^= x >> 16;	x *= 0x21f0aaad;	x ^= x >> 15;	x *= 0xd35a2d97;	x ^= x >> 15;	p = _recompdata + (x%512)*2;	while(p[0] != y){		next = p[1]>>16;		if(!next)			return 0;		p = _recompcoll + (next-1)*2;	}	return p[1] & 0xFFFF;} static voidrunecccsort(Rune *a, int len){	Rune r;	int i, j; 	for(i = 1; i < len; i++){		r = a[i];		for(j = i; j > 0 && ccclkup(a[j-1]) > ccclkup(r); j--)			a[j] = a[j-1];		a[j] = r;	}} static intboundary(Rune r){	return !(qclkup(r) & (Qnfcno|Qnfcmay));} /* * Stk stores the entire context for a chunk of * an input string that is being normalized. * In accordance to the standard, Unicode text * has no upper bound for the amount of conjoining * (also called non-starter) elements associated with * a base rune. Thus to implement normalization within * reasonable memory constraints we implement the * "Stream-Safe Text Format" as defined in UAX #15 § 13. */typedef struct {	Rune a[Maxnormctx];	Rune *e;} Stk; static intpush(Stk *s, Rune c){	int n, l;	Rune r2, b[Maxdecomp];	Rune *p = b + nelem(b) - 1; 	for(*p = c; (c = _runedecomp(c, &r2)); *p = c){		assert(p > b);		if(r2 != 0)			*p-- = r2;	} 	n = b + nelem(b) - p;	l = nelem(s->a) - (s->e - s->a);	if(n > l)		abort(); // runenorm: buffer overflow	l -= n;	for(; n > 0; n--)		*s->e++ = *p++;	return l;} /* * Worst case recomposition, this happens when we have to compose * two runes who both have a CCC of zero. */static voidworstrecomp(Stk *s){	int done;	Rune c, *p, *rp; 	for(done = 0; done == 0;){		done = 1;		for(p = s->a; p+1 < s->e; p++){			c = _runerecomp(p[0], p[1]);			if(c == 0)				continue;			done = 0;			*p = c;			for(rp = p+1; rp < s->e-1; rp++)				rp[0] = rp[1];			s->e--;			p--;		}	}} static voidcccrecomp(Stk *s){	Rune c, *p, *rp; 	for(p = s->a + 1; p < s->e; p++){		c  = _runerecomp(s->a[0], *p);		if(c != 0){			s->a[0] = c;			for(rp = p; rp < s->e-1; rp++){				rp[0] = rp[1];			}			s->e--;			p--;		} else while(p + 1 < s->e && ccclkup(p[0]) == ccclkup(p[1]))			p++;	}} voidnorminit(Norm *n, int compose, void *ctx, long (*getrune)(void*)){	memset(n, 0, sizeof *n);	n->ctx = ctx;	n->getrune = getrune;	n->compose = compose;	n->obuf.e = n->obuf.a;	n->ibuf.e = n->ibuf.a;} int NORMDEBUG; static longpeekrune(Norm *n){	long r; 	if(n->ibuf.e > n->ibuf.a)		return n->ibuf.e[-1]; 	r = n->getrune(n->ctx);	if(r >= 0)		*n->ibuf.e++ = r;	return r;} static longgetrune(Norm *n){	if(n->ibuf.e > n->ibuf.a)		return *--n->ibuf.e;	return n->getrune(n->ctx);} longnormpull(Norm *n, Rune *rdst, long max, int flush){	Rune *rp, *re;	Stk stk;	Rune *dot;	int r;	long c; 	rp = rdst;	re = rdst + max;	dot = nil;	c = 0;	while(rp < re){		if(n->obuf.e != n->obuf.a){			memcpy(stk.a, n->obuf.a, (n->obuf.e - n->obuf.a)*sizeof(Rune));			stk.e = stk.a + (n->obuf.e - n->obuf.a);			n->obuf.e = n->obuf.a;			c = stk.a[0];			goto Flush;		} 		stk.e = stk.a;		c = getrune(n);		if(c < 0)			break;		push(&stk, c);		c = peekrune(n);		if(stk.e == stk.a+1 && stk.a[0] < Runeself && c < Runeself && c >= 0)			goto Flush;		while(c >= 0 && ccclkup(c) != 0){			r = push(&stk, getrune(n));			c = peekrune(n);			if(r > 2)				continue;			if(ccclkup(stk.a[0]) != 0){				assert(r > 0);				r--;			} else				assert(r >= 0);			if(r == 0 || (c == 0x0344 && r < 2)){				/* in reverse */				if(r > 0){					getrune(n);					*n->ibuf.e++ = 0x301;					*n->ibuf.e++ = 0x308;				}				*n->ibuf.e++ = 0x034F;				break;			}		}		if(stk.e - stk.a > 1)			runecccsort(stk.a, stk.e - stk.a); 		if(!n->compose)			goto Flush; 		if(ccclkup(stk.e[-1]) == 0){			Rune tmp;			while(c >= 0 && (!boundary(c) || !boundary(_runedecomp(c, &tmp)))){				if(push(&stk, getrune(n)) == -1){					*n->ibuf.e++ = c;					for(r = 0; r < Maxdecomp; r++)						*n->ibuf.e++ = *--stk.e;					break;				}				c = peekrune(n);			}			worstrecomp(&stk);		} else if(ccclkup(stk.a[0]) == 0)			cccrecomp(&stk); Flush:		if(flush || c >= 0)			for(dot = stk.a; dot < stk.e; dot++){				if(rp == re)					goto Out;				*rp++ = *dot;			}		dot = nil;		if(c < 0)			break;	}Out:	if(c < 0 && !flush){		while(stk.e > stk.a)			*n->ibuf.e++ = *--stk.e;	}	if(dot != nil){		memcpy(n->obuf.a, dot, (stk.e - dot) * sizeof(Rune));		n->obuf.e = n->obuf.a + (stk.e - dot);	} 	return rp - rdst;} typedef struct {	Rune *s, *p;	int n;} Rctx; static longrunegetrune(void *ctx){	Rctx *c; 	c = ctx;	if(c->p >= c->s + c->n)		return -1;	return *c->p++;} static longrunedostr(Rune *dst, long ndst, Rune *src, long nsrc, int comp){	Rctx c;	Norm n; 	c.s = c.p = src;	c.n = nsrc;	norminit(&n, comp, &c, runegetrune);	return normpull(&n, dst, ndst, 1);} longrunecomp(Rune *dst, long ndst, Rune *src, long nsrc){	return runedostr(dst, ndst, src, nsrc, 1);} longrunedecomp(Rune *dst, long ndst, Rune *src, long nsrc){	return runedostr(dst, ndst, src, nsrc, 0);} typedef struct {	char *s, *p;	int n;} Uctx; static longutfgetrune(void *ctx){	Uctx *c;	Rune r; 	c = ctx;	if(c->p >= c->s + c->n)		return -1;	c->p += chartorune(&r, c->p);	return r;} static longutfdostr(char *dst, long ndst, char *src, long nsrc, int comp){	Uctx c;	Norm n;	Rune buf[Maxnormctx];	long i, w;	char *e, *p; 	c.s = c.p = src;	c.n = nsrc;	norminit(&n, comp, &c, utfgetrune);	for(p = dst, e = dst + ndst; p < e;){		w = normpull(&n, buf, nelem(buf), 1);		if(w == 0)			break;		for(i = 0; i < w; i++){			if(p + runelen(buf[i]) >= e)				break;			p += runetochar(p, buf+i);		}	}	return p - dst;} longutfcomp(char *dst, long ndst, char *src, long nsrc){	return utfdostr(dst, ndst, src, nsrc, 1);} longutfdecomp(char *dst, long ndst, char *src, long nsrc){	return utfdostr(dst, ndst, src, nsrc, 0);}

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