Files
LNXSDK/Kha/Backends/Kinc-HL/hl/src/std/ucs2.c
2025-01-22 16:18:30 +01:00

275 lines
6.6 KiB
C

/*
* Copyright (C)2005-2016 Haxe Foundation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <hl.h>
#include <stdarg.h>
#ifndef HL_NATIVE_UCHAR_FUN
#ifdef HL_ANDROID
# include <android/log.h>
# ifndef HL_ANDROID_LOG_TAG
# define HL_ANDROID_LOG_TAG "hl"
# endif
# ifndef HL_ANDROID_LOG_LEVEL
# define HL_ANDROID_LOG_LEVEL ANDROID_LOG_DEBUG
# endif
# define LOG_ANDROID(cfmt,cstr) __android_log_print(HL_ANDROID_LOG_LEVEL, HL_ANDROID_LOG_TAG, cfmt, cstr);
#endif
int ustrlen( const uchar *str ) {
const uchar *p = str;
while( *p ) p++;
return (int)(p - str);
}
static int ustrlen_utf8( const uchar *str ) {
int size = 0;
while(1) {
uchar c = *str++;
if( c == 0 ) break;
if( c < 0x80 )
size++;
else if( c < 0x800 )
size += 2;
else if( c >= 0xD800 && c <= 0xDFFF ) {
str++;
size += 4;
} else
size += 3;
}
return size;
}
uchar *ustrdup( const uchar *str ) {
int len = ustrlen(str);
int size = (len + 1) << 1;
uchar *d = (uchar*)malloc(size);
memcpy(d,str,size);
return d;
}
double utod( const uchar *str, uchar **end ) {
char buf[31];
char *bend;
double result;
int i = 0;
while( i < 30 ) {
int c = str[i];
if( (c < '0' || c > '9') && c != '.' && c != 'e' && c != 'E' && c != '-' && c != '+' )
break;
buf[i++] = (char)c;
}
buf[i] = 0;
result = strtod(buf,&bend);
*end = str + (bend - buf);
return result;
}
int utoi( const uchar *str, uchar **end ) {
char buf[17];
char *bend;
int result;
int i = 0;
uchar sign = str[0];
if( sign == '-' || sign == '+' ) {
buf[i++] = (char)sign;
}
while( i < 16 ) {
int c = str[i];
if( c < '0' || c > '9' )
break;
buf[i++] = (char)c;
}
buf[i] = 0;
result = strtol(buf,&bend,10);
*end = str + (bend - buf);
return result;
}
int ucmp( const uchar *a, const uchar *b ) {
while(true) {
int d = (unsigned)*a - (unsigned)*b;
if( d ) return d;
if( !*a ) return 0;
a++;
b++;
}
}
int usprintf( uchar *out, int out_size, const uchar *fmt, ... ) {
va_list args;
int ret;
va_start(args, fmt);
ret = uvszprintf(out, out_size, fmt, args);
va_end(args);
return ret;
}
// USE UTF-8 encoding
int utostr( char *out, int out_size, const uchar *str ) {
char *start = out;
char *end = out + out_size - 1; // final 0
if( out_size <= 0 ) return 0;
while( out < end ) {
unsigned int c = *str++;
if( c == 0 ) break;
if( c < 0x80 )
*out++ = (char)c;
else if( c < 0x800 ) {
if( out + 2 > end ) break;
*out++ = (char)(0xC0|(c>>6));
*out++ = 0x80|(c&63);
} else if( c >= 0xD800 && c <= 0xDFFF ) { // surrogate pair
if( out + 4 > end ) break;
unsigned int full = (((c - 0xD800) << 10) | ((*str++) - 0xDC00)) + 0x10000;
*out++ = (char)(0xF0|(full>>18));
*out++ = 0x80|((full>>12)&63);
*out++ = 0x80|((full>>6)&63);
*out++ = 0x80|(full&63);
} else {
if( out + 3 > end ) break;
*out++ = (char)(0xE0|(c>>12));
*out++ = 0x80|((c>>6)&63);
*out++ = 0x80|(c&63);
}
}
*out = 0;
return (int)(out - start);
}
static char *utos( const uchar *s ) {
int len = ustrlen_utf8(s);
char *out = (char*)malloc(len + 1);
if( utostr(out,len+1,s) < 0 )
*out = 0;
return out;
}
void uprintf( const uchar *fmt, const uchar *str ) {
char *cfmt = utos(fmt);
char *cstr = utos(str);
#ifdef HL_ANDROID
LOG_ANDROID(cfmt,cstr);
#else
printf(cfmt,cstr);
#endif
free(cfmt);
free(cstr);
}
#endif
#if !defined(HL_NATIVE_UCHAR_FUN) || defined(HL_WIN)
#ifdef HL_VCC
#pragma warning(disable:4774)
#endif
HL_PRIM int uvszprintf( uchar *out, int out_size, const uchar *fmt, va_list arglist ) {
uchar *start = out;
uchar *end = out + out_size - 1;
char cfmt[20];
char tmp[32];
uchar c;
while(true) {
sprintf_loop:
c = *fmt++;
if( out == end ) c = 0;
switch( c ) {
case 0:
*out = 0;
return (int)(out - start);
case '%':
{
int i = 0, size = 0;
cfmt[i++] = '%';
while( true ) {
c = *fmt++;
cfmt[i++] = (char)c;
switch( c ) {
case 'd':
cfmt[i++] = 0;
if( cfmt[i-3] == 'l' ) {
size = sprintf(tmp,cfmt,va_arg(arglist,int64));
} else {
size = sprintf(tmp,cfmt,va_arg(arglist,int));
}
goto sprintf_add;
case 'f':
cfmt[i++] = 0;
size = sprintf(tmp,cfmt,va_arg(arglist,double)); // according to GCC warning, float is promoted to double in var_args
goto sprintf_add;
case 'g':
cfmt[i++] = 0;
size = sprintf(tmp,cfmt,va_arg(arglist,double));
goto sprintf_add;
case 'x':
case 'X':
cfmt[i++] = 0;
if( cfmt[i-3] == 'l' )
size = sprintf(tmp,cfmt,va_arg(arglist,void*));
else
size = sprintf(tmp,cfmt,va_arg(arglist,int));
goto sprintf_add;
case 's':
if( i != 2 ) hl_fatal("Unsupported printf format"); // no support for precision qualifier
{
uchar *s = va_arg(arglist,uchar *);
while( *s && out < end )
*out++ = *s++;
goto sprintf_loop;
}
case '.':
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'l':
break;
default:
hl_fatal("Unsupported printf format");
break;
}
}
sprintf_add:
// copy from c string to u string
i = 0;
while( i < size && out < end )
*out++ = tmp[i++];
}
break;
default:
*out++ = c;
break;
}
}
return 0;
}
#endif