Files
simgear/simgear/nasal/utf8lib.c
T
andy dd1ea541ec Sync with Nasal upstream (Melchior already had a chance to test this,
so hopefully not too much breaks).  New syntax features:

1. Call-by-name function arguments.  You can specify a hash literal in
place of ordered function arguments, and it will become the local
variable namespace for the called function, making functions with many
arguments more readable.  Ex:

   view_manager.lookat(heading:180, pitch:20, roll:0, x:X0, y:Y0, z:Z0,
                       time:now, fov:55);

Declared arguments are checked and defaulted as would be expected:
it's an error if you fail to pass a value for an undefaulted argument,
missing default arguments get assigned, and any rest parameter
(e.g. "func(a,b=2,rest...){}") will be assigned with an empty vector.

2. Vector slicing.  Vectors (lists) can now be created from others
using an ordered list of indexes and ranges.  For example:

   var v1 = ["a","b","c","d","e"]

   var v2 = v1[3,2];   # == ["d","c"];
   var v3 = v1[1:3];   # i.e. range from 1 to 3: ["b","c","d"];
   var v4 = v1[1:];    # no value means "to the end": ["b","c","d","e"]
   var i = 2;
   var v5 = v1[i];     # runtime expressions are fine: ["c"]
   var v6 = v1[-2,-1]; # negative indexes are relative to end: ["d","e"]

The range values can be computed at runtime (e.g. i=1; v5=v1[i:]).
Negative indices work the same way the do with the vector functions
(-1 is the last element, -2 is 2nd to last, etc...).

3. Multi-assignment expressions.  You can assign more than one
variable (or lvalue) at a time by putting them in a parenthesized
list:

   (var a, var b) = (1, 2);
   var (a, b) = (1, 2);               # Shorthand for (var a, var b)
   (var a, v[0], obj.field) = (1,2,3) # Any assignable lvalue works

   var color = [1, 1, 0.5];
   var (r, g, b) = color;  # works with runtime vectors too
2008-09-26 18:22:12 +00:00

163 lines
4.7 KiB
C

#include <string.h>
#include "nasal.h"
#include "parse.h"
// bytes required to store a given character
static int cbytes(unsigned int c)
{
static const int NB[] = { 0x7f, 0x07ff, 0xffff, 0x001fffff, 0x03ffffff };
int i;
for(i=0; i<(sizeof(NB)/sizeof(NB[0])) && c>NB[i]; i++) {}
return i+1;
}
// Returns a byte with the N high order bits set
#define TOPBITS(n) ((unsigned char)(((signed char)0x80)>>((n)-1)))
// write a utf8 character, return bytes written or zero on error
static int writec(unsigned int c, unsigned char* s, int len)
{
int i, n = cbytes(c);
if(len < n) return 0;
for(i=n-1; i>0; i--) {
s[i] = 0x80 | (c & 0x3f);
c >>= 6;
}
s[0] = (n > 1 ? TOPBITS(n) : 0) | c;
return n;
}
// read a utf8 character, or -1 on error.
static int readc(unsigned char* s, int len, int* used)
{
int n, i, c;
if(!len) return -1;
if(s[0] < 0x80) { *used = 1; return s[0]; }
for(n=2; n<7; n++)
if((s[0] & TOPBITS(n+1)) == TOPBITS(n))
break;
if(len < n || n > 6) return -1;
c = s[0] & (~TOPBITS(n+1));
for(i=1; i<n; i++) {
if((s[i] >> 6) != 2) return -1;
c = (c << 6) | (s[i] & 0x3f);
}
if(n != cbytes(c)) return -1;
*used = n;
return c;
}
/* Public symbol used by the parser */
int naLexUtf8C(char* s, int len, int* used)
{ return readc((void*)s, len, used); }
static unsigned char* nthchar(unsigned char* s, int n, int* len)
{
int i, bytes;
for(i=0; *len && i<n; i++) {
if(readc(s, *len, &bytes) < 0) return 0;
s += bytes; *len -= bytes;
}
return s;
}
static naRef f_chstr(naContext ctx, naRef me, int argc, naRef* args)
{
int n;
naRef ch;
unsigned char buf[6];
if(argc < 1 || naIsNil(ch=naNumValue(args[0])))
naRuntimeError(ctx, "bad/missing argument to utf8.chstr");
n = writec((int)ch.num, buf, sizeof(buf));
return naStr_fromdata(naNewString(ctx), (void*)buf, n);
}
static naRef f_size(naContext c, naRef me, int argc, naRef* args)
{
unsigned char* s;
int sz=0, n=0, len;
if(argc < 1 || !naIsString(args[0]))
naRuntimeError(c, "bad/missing argument to utf8.strc");
s = (void*)naStr_data(args[0]);
len = naStr_len(args[0]);
while(len > 0) {
if(readc(s, len, &n) < 0)
naRuntimeError(c, "utf8 encoding error in utf8.size");
sz++; len -= n; s += n;
}
return naNum(sz);
}
static naRef f_strc(naContext ctx, naRef me, int argc, naRef* args)
{
naRef idx;
unsigned char* s;
int len, c=0, bytes;
if(argc < 2 || !naIsString(args[0]) || naIsNil(idx=naNumValue(args[1])))
naRuntimeError(ctx, "bad/missing argument to utf8.strc");
len = naStr_len(args[0]);
s = nthchar((void*)naStr_data(args[0]), (int)idx.num, &len);
if(!s || (c = readc(s, len, &bytes)) < 0)
naRuntimeError(ctx, "utf8 encoding error in utf8.strc");
return naNum(c);
}
static naRef f_substr(naContext c, naRef me, int argc, naRef* args)
{
naRef start, end;
int len;
unsigned char *s, *s2;
end = argc > 2 ? naNumValue(args[2]) : naNil();
if((argc < 2 || !naIsString(args[0]) || naIsNil(start=naNumValue(args[1])))
|| (argc > 2 && naIsNil(end)))
naRuntimeError(c, "bad/missing argument to utf8.substr");
len = naStr_len(args[0]);
if(!(s = nthchar((void*)naStr_data(args[0]), (int)start.num, &len)))
naRuntimeError(c, "start index overrun in utf8.substr");
if(!naIsNil(end)) {
if(!(s2 = nthchar(s, (int)end.num, &len)))
naRuntimeError(c, "end index overrun in utf8.substr");
len = (int)(s2-s);
}
return naStr_fromdata(naNewString(c), (void*)s, len);
}
static naRef f_validate(naContext c, naRef me, int argc, naRef* args)
{
naRef result, unkc=naNil();
int len, len2, lenout=0, n;
unsigned char *s, *s2, *buf;
if(argc < 1 || !naIsString(args[0]) ||
(argc > 1 && naIsNil(unkc=naNumValue(args[1]))))
naRuntimeError(c, "bad/missing argument to utf8.strc");
if(naIsNil(unkc)) unkc = naNum('?');
len = naStr_len(args[0]);
s = (void*)naStr_data(args[0]);
len2 = 6*len; // max for ridiculous unkc values
s2 = buf = naAlloc(len2);
while(len > 0) {
int c = readc(s, len, &n);
if(c < 0) { c = (int)unkc.num; n = 1; }
s += n; len -= n;
n = writec(c, s2, len2);
s2 += n; len2 -= n; lenout += n;
}
result = naStr_fromdata(naNewString(c), (char*)buf, lenout);
naFree(buf);
return result;
}
static naCFuncItem funcs[] = {
{ "chstr", f_chstr },
{ "strc", f_strc },
{ "substr", f_substr },
{ "size", f_size },
{ "validate", f_validate },
{ 0 }
};
naRef naInit_utf8(naContext c)
{
return naGenLib(c, funcs);
}