]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/utf8lib.c
Removal of PLIB/SG from SimGear
[simgear.git] / simgear / nasal / utf8lib.c
1 #include <string.h>
2 #include "nasal.h"
3 #include "parse.h"
4
5 // bytes required to store a given character
6 static int cbytes(unsigned int c)
7 {
8     static const int NB[] = { 0x7f, 0x07ff, 0xffff, 0x001fffff, 0x03ffffff };
9     int i;
10     for(i=0; i<(sizeof(NB)/sizeof(NB[0])) && c>NB[i]; i++) {}
11     return i+1;
12 }
13
14 // Returns a byte with the N high order bits set
15 #define TOPBITS(n) ((unsigned char)(((signed char)0x80)>>((n)-1)))
16
17 // write a utf8 character, return bytes written or zero on error
18 static int writec(unsigned int c, unsigned char* s, int len)
19 {
20     int i, n = cbytes(c);
21     if(len < n) return 0;
22     for(i=n-1; i>0; i--) {
23         s[i] = 0x80 | (c & 0x3f);
24         c >>= 6;
25     }
26     s[0] = (n > 1 ? TOPBITS(n) : 0) | c;
27     return n;
28 }
29
30 // read a utf8 character, or -1 on error.
31 static int readc(unsigned char* s, int len, int* used)
32 {
33     int n, i, c;
34     if(!len) return -1;
35     if(s[0] < 0x80) { *used = 1; return s[0]; }
36     for(n=2; n<7; n++)
37         if((s[0] & TOPBITS(n+1)) == TOPBITS(n))
38             break;
39     if(len < n || n > 6) return -1;
40     c = s[0] & (~TOPBITS(n+1));
41     for(i=1; i<n; i++) {
42         if((s[i] >> 6) != 2) return -1;
43         c = (c << 6) | (s[i] & 0x3f);
44     }
45     if(n != cbytes(c)) return -1;
46     *used = n;
47     return c;
48 }
49
50 /* Public symbol used by the parser */
51 int naLexUtf8C(char* s, int len, int* used)
52 { return readc((void*)s, len, used); }
53
54 static unsigned char* nthchar(unsigned char* s, int n, int* len)
55 {
56     int i, bytes;
57     for(i=0; *len && i<n; i++) {
58         if(readc(s, *len, &bytes) < 0) return 0;
59         s += bytes; *len -= bytes;
60     }
61     return s;
62 }
63
64 static naRef f_chstr(naContext ctx, naRef me, int argc, naRef* args)
65 {
66     int n;
67     naRef ch;
68     unsigned char buf[6];
69     if(argc < 1 || naIsNil(ch=naNumValue(args[0])))
70         naRuntimeError(ctx, "bad/missing argument to utf8.chstr");
71     n = writec((int)ch.num, buf, sizeof(buf));
72     return naStr_fromdata(naNewString(ctx), (void*)buf, n);
73 }
74
75 static naRef f_size(naContext c, naRef me, int argc, naRef* args)
76 {
77     unsigned char* s;
78     int sz=0, n=0, len;
79     if(argc < 1 || !naIsString(args[0]))
80         naRuntimeError(c, "bad/missing argument to utf8.strc");
81     s = (void*)naStr_data(args[0]);
82     len = naStr_len(args[0]);
83     while(len > 0) {
84         if(readc(s, len, &n) < 0)
85             naRuntimeError(c, "utf8 encoding error in utf8.size");
86         sz++; len -= n; s += n;
87     }
88     return naNum(sz);
89 }
90
91 static naRef f_strc(naContext ctx, naRef me, int argc, naRef* args)
92 {
93     naRef idx;
94     unsigned char* s;
95     int len, c=0, bytes;
96     if(argc < 2 || !naIsString(args[0]) || naIsNil(idx=naNumValue(args[1])))
97         naRuntimeError(ctx, "bad/missing argument to utf8.strc");
98     len = naStr_len(args[0]);
99     s = nthchar((void*)naStr_data(args[0]), (int)idx.num, &len);
100     if(!s || (c = readc(s, len, &bytes)) < 0)
101         naRuntimeError(ctx, "utf8 encoding error in utf8.strc");
102     return naNum(c);
103 }
104
105 static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
106 {
107     naRef start, end;
108     int len;
109     unsigned char *s, *s2;
110     end = argc > 2 ? naNumValue(args[2]) : naNil();
111     if((argc < 2 || !naIsString(args[0]) || naIsNil(start=naNumValue(args[1])))
112        || (argc > 2 && naIsNil(end)))
113         naRuntimeError(c, "bad/missing argument to utf8.substr");
114     len = naStr_len(args[0]);
115     if(!(s = nthchar((void*)naStr_data(args[0]), (int)start.num, &len)))
116         naRuntimeError(c, "start index overrun in utf8.substr");
117     if(!naIsNil(end)) {
118         if(!(s2 = nthchar(s, (int)end.num, &len)))
119             naRuntimeError(c, "end index overrun in utf8.substr");
120         len = (int)(s2-s);
121     }
122     return naStr_fromdata(naNewString(c), (void*)s, len);
123 }
124
125 static naRef f_validate(naContext c, naRef me, int argc, naRef* args)
126 {
127     naRef result, unkc=naNil();
128     int len, len2, lenout=0, n;
129     unsigned char *s, *s2, *buf;
130     if(argc < 1 || !naIsString(args[0]) ||
131        (argc > 1 && naIsNil(unkc=naNumValue(args[1]))))
132         naRuntimeError(c, "bad/missing argument to utf8.strc");
133     if(naIsNil(unkc)) unkc = naNum('?');
134     len = naStr_len(args[0]);
135     s = (void*)naStr_data(args[0]);
136     len2 = 6*len; // max for ridiculous unkc values
137     s2 = buf = naAlloc(len2);
138     while(len > 0) {
139         int c = readc(s, len, &n);
140         if(c < 0) { c = (int)unkc.num; n = 1; }
141         s += n; len -= n;
142         n = writec(c, s2, len2);
143         s2 += n; len2 -= n; lenout += n;
144     }
145     result = naStr_fromdata(naNewString(c), (char*)buf, lenout);
146     naFree(buf);
147     return result;
148 }
149
150 static naCFuncItem funcs[] = {
151     { "chstr", f_chstr },
152     { "strc", f_strc },
153     { "substr", f_substr },
154     { "size", f_size },
155     { "validate", f_validate },
156     { 0 }
157 };
158
159 naRef naInit_utf8(naContext c)
160 {
161     return naGenLib(c, funcs);
162 }