]> git.mxchange.org Git - simgear.git/blob - simgear/nasal/utf8lib.c
Modified Files:
[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 > 0 && s[0] < 0x80) { *used = 1; return s[0]; }
35     for(n=2; n<7; n++)
36         if((s[0] & TOPBITS(n+1)) == TOPBITS(n))
37             break;
38     if(len < n || n > 6) return -1;
39     c = s[0] & (~TOPBITS(n+1));
40     for(i=1; i<n; i++) {
41         if((s[i] >> 6) != 2) return -1;
42         c = (c << 6) | (s[i] & 0x3f);
43     }
44     if(n != cbytes(c)) return -1;
45     *used = n;
46     return c;
47 }
48
49 /* Public symbol used by the parser */
50 int naLexUtf8C(char* s, int len, int* used)
51 { return readc((void*)s, len, used); }
52
53 static unsigned char* nthchar(unsigned char* s, int n, int* len)
54 {
55     int i, bytes;
56     for(i=0; *len && i<n; i++) {
57         if(readc(s, *len, &bytes) < 0) return 0;
58         s += bytes; *len -= bytes;
59     }
60     return s;
61 }
62
63 static naRef f_chstr(naContext ctx, naRef me, int argc, naRef* args)
64 {
65     int n;
66     naRef ch;
67     unsigned char buf[6];
68     if(argc < 1 || naIsNil(ch=naNumValue(args[0])))
69         naRuntimeError(ctx, "bad/missing argument to utf8.chstr");
70     n = writec((int)ch.num, buf, sizeof(buf));
71     return naStr_fromdata(naNewString(ctx), (void*)buf, n);
72 }
73
74 static naRef f_size(naContext c, naRef me, int argc, naRef* args)
75 {
76     unsigned char* s;
77     int sz=0, n, len;
78     if(argc < 1 || !naIsString(args[0]))
79         naRuntimeError(c, "bad/missing argument to utf8.strc");
80     s = (void*)naStr_data(args[0]);
81     len = naStr_len(args[0]);
82     while(len > 0) {
83         if(readc(s, len, &n) < 0)
84             naRuntimeError(c, "utf8 encoding error in utf8.size");
85         sz++; len -= n; s += n;
86     }
87     return naNum(sz);
88 }
89
90 static naRef f_strc(naContext ctx, naRef me, int argc, naRef* args)
91 {
92     naRef idx;
93     unsigned char* s;
94     int len, c=0, bytes;
95     if(argc < 2 || !naIsString(args[0]) || naIsNil(idx=naNumValue(args[1])))
96         naRuntimeError(ctx, "bad/missing argument to utf8.strc");
97     len = naStr_len(args[0]);
98     s = nthchar((void*)naStr_data(args[0]), (int)idx.num, &len);
99     if(!s || (c = readc(s, len, &bytes)) < 0)
100         naRuntimeError(ctx, "utf8 encoding error in utf8.strc");
101     return naNum(c);
102 }
103
104 static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
105 {
106     naRef start, end;
107     int len;
108     unsigned char *s, *s2;
109     end = argc > 2 ? naNumValue(args[2]) : naNil();
110     if((argc < 2 || !naIsString(args[0]) || naIsNil(start=naNumValue(args[1])))
111        || (argc > 2 && naIsNil(end)))
112         naRuntimeError(c, "bad/missing argument to utf8.substr");
113     len = naStr_len(args[0]);
114     if(!(s = nthchar((void*)naStr_data(args[0]), (int)start.num, &len)))
115         naRuntimeError(c, "start index overrun in utf8.substr");
116     if(!naIsNil(end)) {
117         if(!(s2 = nthchar(s, (int)end.num, &len)))
118             naRuntimeError(c, "end index overrun in utf8.substr");
119         len = (int)(s2-s);
120     }
121     return naStr_fromdata(naNewString(c), (void*)s, len);
122 }
123
124 static naRef f_validate(naContext c, naRef me, int argc, naRef* args)
125 {
126     naRef result, unkc=naNil();
127     int len, len2, lenout=0, n;
128     unsigned char *s, *s2, *buf;
129     if(argc < 1 || !naIsString(args[0]) ||
130        (argc > 1 && naIsNil(unkc=naNumValue(args[1]))))
131         naRuntimeError(c, "bad/missing argument to utf8.strc");
132     if(naIsNil(unkc)) unkc = naNum('?');
133     len = naStr_len(args[0]);
134     s = (void*)naStr_data(args[0]);
135     len2 = 6*len; // max for ridiculous unkc values
136     s2 = buf = naAlloc(len2);
137     while(len > 0) {
138         int c = readc(s, len, &n);
139         if(c < 0) { c = (int)unkc.num; n = 1; }
140         s += n; len -= n;
141         n = writec(c, s2, len2);
142         s2 += n; len2 -= n; lenout += n;
143     }
144     result = naStr_fromdata(naNewString(c), (char*)buf, lenout);
145     naFree(buf);
146     return result;
147 }
148
149 static naCFuncItem funcs[] = {
150     { "chstr", f_chstr },
151     { "strc", f_strc },
152     { "substr", f_substr },
153     { "size", f_size },
154     { "validate", f_validate },
155     { 0 }
156 };
157
158 naRef naInit_utf8(naContext c)
159 {
160     return naGenLib(c, funcs);
161 }