gambas-source-code/main/gbx/gbx_subr_string.c
gambas 706a605cc3 Correctly restore the stack after calling a method through the interpreter, and handle null values as object values having a null address automatically.
[INTERPRETER]
* NEW: Creating a NULL value now clears the object address field so that it can be freely interpreted as a Object value with a null address by the JIT compiled code.

[GB.JIT]
* BUG: Correctly restore stack after calling a method through the interpreter.
2018-08-22 09:30:27 +02:00

1359 lines
23 KiB
C

/***************************************************************************
gbx_subr_string.c
(c) 2000-2017 Benoît Minisini <g4mba5@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
MA 02110-1301, USA.
***************************************************************************/
#include "gb_common.h"
#include "gb_common_buffer.h"
#include "gb_common_case.h"
#include <ctype.h>
#include <regex.h>
#include "gb_pcode.h"
#include "gbx_value.h"
#include "gbx_subr.h"
#include "gbx_regexp.h"
#include "gbx_class.h"
#include "gbx_string.h"
#include "gbx_split.h"
#include "gbx_c_array.h"
#include "gbx_local.h"
#include "gbx_compare.h"
//static int _count = 0;
//---------------------------------------------------------------------------
void SUBR_cat(ushort code)
{
SUBR_ENTER();
if (NPARAM == 2)
{
int len, len2;
char *str;
VALUE_conv_string(&PARAM[0]);
len = PARAM[0]._string.len ;
VALUE_conv_string(&PARAM[1]);
len2 = PARAM[1]._string.len;
#if 0
if (EXEC_string_add)
{
EXEC_string_add = FALSE;
str = PARAM[0]._string.addr;
if (0 && PARAM[0].type == T_STRING && PARAM[0]._string.start == 0 && STRING_length(str) == len)
{
if (str && !STRING_extend_will_realloc(str, len + len2))
{
//_count++;
//fprintf(stderr, "[%d] &= optimization: str = %p (%d) param2 = %p (%d)\n", _count, str, len, PARAM[1]._string.addr + PARAM[1]._string.start, len2);
str = STRING_add(str, PARAM[1]._string.addr + PARAM[1]._string.start, len2);
/*if (str != PARAM[0]._string.addr)
{
//fprintf(stderr, "--> %p !\n", str);
BREAKPOINT();
}*/
RELEASE_STRING(&PARAM[1]);
SP -= 2;
//SP->type = T_STRING;
//SP->_string.addr = str;
//SP->_string.start = 0;
SP->_string.len += len2;
SP++;
return;
}
}
/*else
{
if (PARAM[0].type != T_STRING)
fprintf(stderr, "PARAM[0].type == %ld\n", PARAM[0].type);
else if (PARAM[0]._string.start)
fprintf(stderr, "PARAM[0]._string.start == %d\n", PARAM[0]._string.start);
else if (STRING_length(str) != len)
fprintf(stderr, "len == %d / %d\n", len, STRING_length(str));
}*/
}
#endif
str = STRING_new(NULL, len + len2);
//fprintf(stderr, "normal: str = %p p0 = %p p1 = %p\n", str, PARAM[0]._string.addr + PARAM[0]._string.start, PARAM[1]._string.addr + PARAM[1]._string.start);
memcpy(str, PARAM[0]._string.addr + PARAM[0]._string.start, len);
memcpy(&str[len], PARAM[1]._string.addr + PARAM[1]._string.start, len2);
RELEASE_STRING(&PARAM[0]);
RELEASE_STRING(&PARAM[1]);
SP -= 2;
SP->type = T_STRING;
SP->_string.addr = str;
SP->_string.start = 0;
SP->_string.len = len + len2;
SP++;
}
else
{
int i;
int len, len_cat;
char *str, *ptr;
len_cat = 0;
for (i = 0; i < NPARAM; i++)
{
VALUE_conv_string(&PARAM[i]);
len_cat += PARAM[i]._string.len;
}
str = STRING_new(NULL, len_cat);
ptr = str;
i = NPARAM;
while (i--)
{
len = PARAM->_string.len;
if (len)
{
memcpy(ptr, PARAM->_string.addr + PARAM->_string.start, len);
ptr += len;
}
RELEASE_STRING(PARAM);
PARAM++;
}
SP -= NPARAM;
SP->type = T_STRING;
SP->_string.addr = str;
SP->_string.start = 0;
SP->_string.len = len_cat;
SP++;
}
}
void SUBR_file(ushort code)
{
int i;
int length;
char *addr;
int len;
char *str, *ptr;
bool slash;
SUBR_ENTER();
length = 0;
slash = FALSE;
for (i = 0; i < NPARAM; i++)
{
/*VALUE_conv(&PARAM[i], T_STRING);*/
SUBR_get_string_len(&PARAM[i], &addr, &len);
if (len > 0)
{
if (length > 0)
{
if (!slash && addr[0] != '/')
length++;
else if (slash && addr[0] == '/')
length--;
}
slash = addr[len - 1] == '/';
length += len;
}
}
str = STRING_new(NULL, length);
ptr = str;
slash = FALSE;
i = NPARAM;
while (i--)
{
if (PARAM->type != T_NULL)
{
VALUE_get_string(PARAM, &addr, &len);
if (len > 0)
{
if (ptr > str)
{
if (!slash && *addr != '/')
*ptr++ = '/';
else if (slash && *addr == '/')
ptr--;
}
slash = addr[len - 1] == '/';
memcpy(ptr, addr, len);
ptr += len;
}
RELEASE_STRING(PARAM);
}
PARAM++;
}
SP -= NPARAM;
SP->type = T_STRING;
SP->_string.addr = str;
SP->_string.start = 0;
SP->_string.len = length;
SP++;
}
void SUBR_space(void)
{
int len;
SUBR_ENTER_PARAM(1);
SUBR_check_integer(PARAM);
len = PARAM->_integer.value;
if (len < 0)
THROW(E_ARG);
if (len == 0)
{
STRING_void_value(&SP[-1]);
}
else
{
char *str = STRING_new(NULL, len);
memset(str, ' ', len);
SP--;
SP->type = T_STRING;
SP->_string.addr = str;
SP->_string.start = 0;
SP->_string.len = len;
SP++;
}
//SUBR_LEAVE();
}
void SUBR_string(void)
{
int i;
char *d;
char *s;
int ld, ls;
SUBR_ENTER_PARAM(2);
SUBR_check_integer(PARAM);
SUBR_get_string_len(&PARAM[1], &s, &ls);
ld = PARAM->_integer.value * ls;
if (ld < 0)
THROW(E_ARG);
if (ld == 0)
{
STRING_void_value(RETURN);
}
else
{
STRING_new_temp_value(RETURN, NULL, ld);
d = RETURN->_string.addr;
for (i = 0; i < PARAM->_integer.value; i++)
{
memcpy(d, s, ls);
d += ls;
}
*d = 0;
}
SUBR_LEAVE();
}
void SUBR_trim(ushort code)
{
unsigned char *str;
bool left, right;
SUBR_GET_PARAM(1);
if (SUBR_check_string(PARAM))
{
VOID_STRING(PARAM);
return;
}
code &= 0x1F;
left = (code == 0 || code == 1);
right = (code == 0 || code == 2);
if (PARAM->_string.len > 0)
{
str = (uchar *)&PARAM->_string.addr[PARAM->_string.start];
if (left)
{
while (PARAM->_string.len > 0 && *str <= ' ')
{
PARAM->_string.start++;
PARAM->_string.len--;
str++;
}
}
if (right)
{
while (PARAM->_string.len > 0 && str[PARAM->_string.len - 1] <= ' ')
{
PARAM->_string.len--;
}
}
}
}
void SUBR_upper(ushort code)
{
char *str;
int len, i;
SUBR_ENTER_PARAM(1);
if (SUBR_check_string(PARAM))
{
VOID_STRING(&SP[-1]);
}
else
{
len = PARAM->_string.len;
if (len > 0)
{
str = STRING_new(&PARAM->_string.addr[PARAM->_string.start], PARAM->_string.len);
if (code & 0x3F)
{
for (i = 0; i < len; i++)
str[i] = tolower(str[i]);
}
else
{
for (i = 0; i < len; i++)
str[i] = toupper(str[i]);
}
SP--;
RELEASE_STRING(SP);
SP->type = T_STRING;
SP->_string.addr = str;
SP->_string.start = 0;
SP->_string.len = len;
SP++;
}
}
}
void SUBR_chr(void)
{
int car;
SUBR_GET_PARAM(1);
VALUE_conv_integer(PARAM);
car = PARAM->_integer.value;
if (car < 0 || car > 255)
THROW(E_ARG);
STRING_char_value(PARAM, car);
}
void SUBR_asc(ushort code)
{
int pos = 0;
SUBR_ENTER();
if (!SUBR_check_string(PARAM))
{
pos = 1;
if (NPARAM == 2)
{
SUBR_check_integer(&PARAM[1]);
pos = PARAM[1]._integer.value;
}
if (pos < 1 || pos > PARAM->_string.len)
pos = 0;
else
pos = (unsigned char)PARAM->_string.addr[PARAM->_string.start + pos - 1];
}
RETURN->type = T_INTEGER;
RETURN->_integer.value = pos;
SUBR_LEAVE();
}
void SUBR_instr(ushort code)
{
bool right, nocase = FALSE;
int is, pos;
//int pos2;
char *ps, *pp;
int ls, lp;
SUBR_ENTER();
pos = 0;
if (SUBR_check_string(PARAM))
goto __FOUND;
if (SUBR_check_string(&PARAM[1]))
goto __FOUND;
lp = PARAM[1]._string.len;
ls = PARAM->_string.len;
right = ((code >> 8) == CODE_RINSTR);
if (lp > ls) goto __FOUND;
is = 0;
if (NPARAM >= 3)
is = SUBR_get_integer(&PARAM[2]);
if (NPARAM == 4)
nocase = SUBR_get_integer(&PARAM[3]) == GB_COMP_NOCASE;
ps = PARAM->_string.addr + PARAM->_string.start;
pp = PARAM[1]._string.addr + PARAM[1]._string.start;
pos = STRING_search(ps, ls, pp, lp, is, right, nocase);
/*pos2 = STRING_search2(ps, ls, pp, lp, is, right, nocase);
if (pos != pos2)
{
for(;;)
usleep(1000);
}*/
__FOUND:
RELEASE_STRING(PARAM);
RELEASE_STRING(&PARAM[1]);
SP -= NPARAM;
SP->type = T_INTEGER;
SP->_integer.value = pos;
SP++;
}
void SUBR_like(ushort code)
{
static const void *jump[] = { &&__LIKE, &&__BEGINS, &&__ENDS, &&__MATCH };
char *pattern;
char *string;
int len_pattern, len_string;
bool ret = FALSE;
SUBR_ENTER_PARAM(2);
SUBR_get_string_len(&PARAM[0], &string, &len_string);
SUBR_get_string_len(&PARAM[1], &pattern, &len_pattern);
goto *jump[code & 0x3];
__LIKE:
ret = REGEXP_match(pattern, len_pattern, string, len_string);
goto __RETURN;
__BEGINS:
if (len_pattern == 0)
ret = TRUE;
else if (len_pattern <= len_string)
ret = STRING_equal_same(string, pattern, len_pattern);
goto __RETURN;
__ENDS:
if (len_pattern == 0)
ret = TRUE;
else if (len_pattern <= len_string)
ret = STRING_equal_same(string + len_string - len_pattern, pattern, len_pattern);
goto __RETURN;
__MATCH:
ret = REGEXP_match_pcre(pattern, len_pattern, string, len_string);
goto __RETURN;
__RETURN:
RETURN->type = T_BOOLEAN;
RETURN->_boolean.value = -(ret ^ !!(code & 0x4));
SUBR_LEAVE();
}
static int subst_nparam;
static VALUE *subst_param;
static void get_subst(int np, char **str, int *len)
{
if (np > 0 && np < subst_nparam)
VALUE_get_string(&subst_param[np], str, len);
else
{
*str = NULL;
*len = 0;
}
}
void SUBR_subst(ushort code)
{
char *string;
int len;
int np;
SUBR_ENTER();
SUBR_get_string_len(&PARAM[0], &string, &len);
for (np = 1; np < NPARAM; np++)
VALUE_conv_string(&PARAM[np]);
subst_param = PARAM;
subst_nparam = NPARAM;
string = STRING_subst(string, len, get_subst);
/*for (np = 0; np < NPARAM; np++)
RELEASE_STRING(&PARAM[np]);*/
RETURN->type = T_STRING;
RETURN->_string.addr = (char *)string;
RETURN->_string.start = 0;
RETURN->_string.len = STRING_length(string);
SUBR_LEAVE();
}
void SUBR_replace(ushort code)
{
char *ps;
char *pp;
char *pr;
int ls, lp, lr;
int pos;
bool nocase = FALSE;
SUBR_ENTER();
SUBR_get_string_len(&PARAM[0], &ps, &ls);
SUBR_get_string_len(&PARAM[1], &pp, &lp);
SUBR_get_string_len(&PARAM[2], &pr, &lr);
if (NPARAM == 4)
nocase = SUBR_get_integer(&PARAM[3]) == GB_COMP_NOCASE;
if (lp == 0 || ls == 0)
{
RELEASE(&PARAM[1]);
RELEASE(&PARAM[2]);
SP -= NPARAM;
SP++;
return;
}
if (lp == lr)
{
ps = STRING_new_temp(ps, ls);
RETURN->_string.addr = ps;
RETURN->_string.len = ls;
if (lp == 1)
{
char cp = *pp;
char cr = *pr;
if (nocase)
{
char cpl = tolower(cp);
cp = toupper(cp);
for (pos = 0; pos < ls; pos++)
{
if (ps[pos] == cp || ps[pos] == cpl)
ps[pos] = cr;
}
}
else
{
for (pos = 0; pos < ls; pos++)
{
if (ps[pos] == cp)
ps[pos] = cr;
}
}
}
else
{
for(;;)
{
pos = STRING_search(ps, ls, pp, lp, 0, FALSE, nocase);
if (pos == 0)
break;
pos--;
memcpy(&ps[pos], pr, lp);
pos += lp;
ps += pos;
ls -= pos;
}
}
}
else
{
STRING_start_len(ls);
for(;;)
{
pos = STRING_search(ps, ls, pp, lp, 1, FALSE, nocase);
if (pos == 0)
break;
pos--;
if (pos > 0)
STRING_make(ps, pos);
STRING_make(pr, lr);
pos += lp;
ps += pos;
ls -= pos;
if (ls <= 0)
break;
}
STRING_make(ps, ls);
RETURN->_string.addr = STRING_end_temp();
RETURN->_string.len = STRING_length(RETURN->_string.addr);
}
RETURN->type = T_STRING;
RETURN->_string.start = 0;
SUBR_LEAVE();
}
void SUBR_split(ushort code)
{
CARRAY *array;
char *str;
int lstr;
char *sep = NULL;
int lsep = 0;
char *esc = NULL;
int lesc = 0;
bool no_void = FALSE;
bool keep_esc = FALSE;
SUBR_ENTER();
VALUE_conv_string(PARAM);
VALUE_get_string(PARAM, &str, &lstr);
if (NPARAM >= 2)
{
SUBR_get_string_len(&PARAM[1], &sep, &lsep);
if (NPARAM >= 3)
{
SUBR_get_string_len(&PARAM[2], &esc, &lesc);
if (NPARAM >= 4)
{
no_void = SUBR_get_boolean(&PARAM[3]);
if (NPARAM == 5)
keep_esc = SUBR_get_boolean(&PARAM[4]);
}
}
}
array = STRING_split(str, lstr, sep, lsep, esc, lesc, no_void, keep_esc);
RETURN->_object.class = CLASS_StringArray;
RETURN->_object.object = array;
SUBR_LEAVE();
}
void SUBR_scan(void)
{
CARRAY *array;
char *str;
int len_str;
char *pat;
int len_pat;
SUBR_ENTER_PARAM(2);
SUBR_get_string_len(&PARAM[0], &str, &len_str);
SUBR_get_string_len(&PARAM[1], &pat, &len_pat);
array = OBJECT_create(CLASS_StringArray, NULL, NULL, 0);
if (len_str && len_pat)
REGEXP_scan(array, pat, len_pat, str, len_str);
RETURN->_object.class = CLASS_StringArray;
RETURN->_object.object = array;
SUBR_LEAVE();
}
void SUBR_iconv(void)
{
char *str;
const char *src;
const char *dst;
char *result;
int len;
SUBR_ENTER_PARAM(3);
str = SUBR_get_string(&PARAM[0]);
len = PARAM[0]._string.len;
src = SUBR_get_string(&PARAM[1]);
dst = SUBR_get_string(&PARAM[2]);
STRING_conv(&result, str, len, src, dst, TRUE);
if (!result)
VALUE_null(RETURN);
else
{
RETURN->type = T_STRING;
RETURN->_string.addr = result;
RETURN->_string.start = 0;
RETURN->_string.len = STRING_length(result);
}
SUBR_LEAVE();
}
void SUBR_sconv(ushort code)
{
char *str;
const char *src;
const char *dst;
char *result;
int len;
SUBR_ENTER_PARAM(1);
if (LOCAL_is_UTF8)
return;
str = SUBR_get_string(&PARAM[0]);
len = PARAM[0]._string.len;
if (code & 0xF)
{
src = LOCAL_encoding;
dst = SC_UTF8;
}
else
{
src = SC_UTF8;
dst = LOCAL_encoding;
}
STRING_conv(&result, str, len, src, dst, TRUE);
if (!result)
VALUE_null(RETURN);
else
{
RETURN->type = T_STRING;
RETURN->_string.addr = result;
RETURN->_string.start = 0;
RETURN->_string.len = STRING_length(result);
}
SUBR_LEAVE();
}
static int _is_ascii(int c)
{
return (c & ~0x7F) == 0;
}
static int _is_letter(int c)
{
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
static int _is_lower(int c)
{
return (c >= 'a' && c <= 'z');
}
static int _is_upper(int c)
{
return (c >= 'A' && c <= 'Z');
}
static int _is_digit(int c)
{
return (c >= '0' && c <= '9');
}
static int _is_hexa(int c)
{
return (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F');
}
static int _is_space(int c)
{
return strchr(" \n\r\t\f\v", c) != NULL;
}
static int _is_blank(int c)
{
return (c == 32 || c == '\t');
}
static int _is_punct(int c)
{
return ((c > 32) && (c < 128) && !(_is_letter(c) || _is_digit(c)));
}
static int _is_alnum(int c)
{
return _is_letter(c) || _is_digit(c);
}
void SUBR_is_chr(ushort code)
{
static void *jump[] =
{
NULL, _is_ascii, _is_letter, _is_lower, _is_upper, _is_digit, _is_hexa, _is_space, _is_blank, _is_punct, _is_alnum
};
char *addr;
int len;
int i;
int (*func)(int);
SUBR_ENTER_PARAM(1);
VALUE_conv_string(PARAM);
//SUBR_get_string_len(PARAM, &addr, &len);
VALUE_get_string(PARAM, &addr, &len);
func = jump[code & 0x3F];
i = len;
while(i)
{
if (!(*func)(*addr++))
break;
i--;
}
RELEASE_STRING(PARAM);
SP--;
SP->type = T_BOOLEAN;
SP->_boolean.value = (len > 0 && i == 0) ? -1 : 0;
SP++;
}
void SUBR_tr(void)
{
char *str;
SUBR_ENTER_PARAM(1);
VALUE_conv_string(&PARAM[0]);
if (SUBR_check_string(PARAM))
STRING_void_value(RETURN);
else
{
str = STRING_new_temp(&PARAM->_string.addr[PARAM->_string.start], PARAM->_string.len);
RETURN->type = T_CSTRING;
RETURN->_string.addr = (char *)LOCAL_gettext(str);
RETURN->_string.start = 0;
RETURN->_string.len = strlen(RETURN->_string.addr);
}
SUBR_LEAVE();
}
static void make_hex_char(uchar c)
{
static const char hex_digit[] = "0213456789ABCDEF";
STRING_make_char(hex_digit[c >> 4]);
STRING_make_char(hex_digit[c & 7]);
}
void SUBR_quote(ushort code)
{
static void *jump[8] = { &&__QUOTE, &&__SHELL, &&__HTML, &&__BASE64, &&__URL , &&__ILLEGAL, &&__ILLEGAL, &&__ILLEGAL };
char *str;
int lstr;
int i;
unsigned char c;
char buf[8];
SUBR_ENTER_PARAM(1);
VALUE_conv_string(&PARAM[0]);
str = PARAM->_string.addr + PARAM->_string.start;
lstr = PARAM->_string.len;
STRING_start_len(lstr);
goto *jump[code & 0x7];
__QUOTE:
STRING_make_char('"');
for (i = 0; i < lstr; i++)
{
c = str[i];
//if (c >= ' ' && c <= 126 && c != '\\' && c != '"')
if (c >= ' ' && c != '\\' && c != '"')
STRING_make_char(c);
else
{
STRING_make_char('\\');
if (c == '\n')
c = 'n';
else if (c == '\r')
c = 'r';
else if (c == '\t')
c = 't';
else if (!(c == '"' || c == '\\'))
{
snprintf(buf, sizeof(buf), "x%02X", c);
STRING_make(buf, 3);
continue;
}
STRING_make_char(c);
}
}
STRING_make_char('"');
goto __END;
__SHELL:
/*if (!LOCAL_is_UTF8)
{
char *conv;
STRING_conv(&conv, str, lstr, SC_UTF8, LOCAL_encoding, FALSE);
str = conv;
lstr = str ? strlen(str) : 0;
}*/
// TODO: The following works with bash, but not with dash!
STRING_make_char('\'');
for (i = 0; i < lstr; i++)
{
c = str[i];
if (c == '\'')
{
STRING_make("'\\'", 3);
}
STRING_make_char(c);
/*
if (c == '\n')
STRING_make("$'\\n'", 5);
else if (c == '\r')
STRING_make("$'\\r'", 5);
else if (c == '\t')
STRING_make("$'\\t'", 5);
else if (c < ' ') //|| (c > 126 && !LOCAL_is_UTF8))
{
snprintf(buf, sizeof(buf), "$'\\x%02X'", c);
STRING_make(buf, 7);
}
else if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || index(".-/_~", c) || c > 126)
STRING_make_char(c);
else
{
STRING_make_char('\\');
STRING_make_char(c);
}
*/
}
STRING_make_char('\'');
goto __END;
__HTML:
for (i = 0; i < lstr; i++)
{
c = str[i];
if (c == '&')
STRING_make("&amp;", 5);
else if (c == '<')
STRING_make("&lt;", 4);
else if (c == '>')
STRING_make("&gt;", 4);
else if (c == '"')
STRING_make("&quot;", 6);
else if (c == '\'')
STRING_make("&#x27;", 6);
else if (c == 0xC2 && (uchar)str[i + 1] == 0xA0)
{
STRING_make("&nbsp;", 6);
i++;
}
else
STRING_make_char(c);
}
goto __END;
__BASE64:
{
static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
uchar *in;
char *out = buf;
for (i = 0; i < (lstr - 2); i += 3)
{
in = (uchar *)&str[i];
out[0] = base64[in[0] >> 2];
out[1] = base64[((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4)];
out[2] = base64[((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6)];
out[3] = base64[in[2] & 0x3F];
STRING_make(out, 4);
}
if (i < lstr)
{
in = (uchar *)&str[i];
lstr -= i;
out[0] = base64[in[0] >> 2];
out[1] = base64[((in[0] & 0x03) << 4) | ((in[1] & 0xF0) >> 4)];
out[2] = (lstr > 1 ? base64[((in[1] & 0x0F) << 2) | ((in[2] & 0xC0) >> 6) ] : '=');
out[3] = (lstr > 2 ? base64[in[2] & 0x3F] : '=');
STRING_make(out, 4);
}
}
goto __END;
__URL:
// Warning! '/' is not encoded, so that the function is more pratical, by supposing that no file url will have '/' in its name.
for (i = 0; i < lstr; i++)
{
c = str[i];
if (c == ' ')
STRING_make_char('+');
else if ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || index("-._~,$!/", c))
STRING_make_char(c);
else
{
STRING_make_char('%');
make_hex_char(c);
}
}
goto __END;
#if 0
__JAVASCRIPT:
{
STRING_make_char('\'');
for (i = 0; i < lstr; i++)
{
c = str[i];
if (c >= ' ' && c <= 126 && c != '\\' && c != '\'')
STRING_make_char(c);
else
{
STRING_make_char('\\');
if (c == '\n')
c = 'n';
else if (c == '\r')
c = 'r';
else if (c == '\t')
c = 't';
else if (!(c == '\'' || c == '\\'))
{
snprintf(buf, sizeof(buf), "x%02X", c);
STRING_make(buf, 3);
continue;
}
STRING_make_char(c);
}
}
STRING_make_char('\'');
}
goto __END;
#endif
__ILLEGAL:
THROW_ILLEGAL();
__END:
RETURN->type = T_STRING;
RETURN->_string.addr = STRING_end_temp();
RETURN->_string.start = 0;
RETURN->_string.len = STRING_length(RETURN->_string.addr);
SUBR_LEAVE();
}
static int read_hex_digit(unsigned char c)
{
if (c >= '0' && c <= '9')
return (c - '0');
else if (c >= 'A' && c <= 'F')
return (c - 'A' + 10);
else if (c >= 'a' && c <= 'f')
return (c - 'a' + 10);
else
return 0;
}
void SUBR_unquote(ushort code)
{
static void *jump[4] = { &&__UNQUOTE, &&__FROM_BASE64, &&__FROM_URL, &&__ILLEGAL };
char *str;
int lstr;
int i;
unsigned char c;
SUBR_ENTER_PARAM(1);
VALUE_conv_string(&PARAM[0]);
str = PARAM->_string.addr + PARAM->_string.start;
lstr = PARAM->_string.len;
STRING_start_len(lstr);
goto *jump[code & 0x3];
__UNQUOTE:
if (lstr >= 2 && str[0] == '"' && str[lstr - 1] == '"')
{
str++;
lstr -= 2;
}
for (i = 0; i < lstr; i++)
{
c = str[i];
if (c == '\\')
{
i++;
if (i >= lstr)
break;
c = str[i];
if (c == 'n')
c = '\n';
else if (c == 't')
c = '\t';
else if (c == 'r')
c = '\r';
else if (c == 'x')
{
if (i >= (lstr - 2))
break;
c = (read_hex_digit(str[i + 1]) << 4) + read_hex_digit(str[i + 2]);
i += 2;
}
}
STRING_make_char(c);
}
goto __END;
__FROM_BASE64:
{
char buf[4];
unsigned char n = 0;
for (i = 0; i < lstr; i++)
{
c = str[i];
if (c >= 'A' && c <= 'Z')
c = c - 'A';
else if (c >= 'a' && c <= 'z')
c = c - 'a' + 26;
else if (c >= '0' && c <= '9')
c = c - '0' + 52;
else if (c == '+')
c = 62;
else if (c == '/')
c = 63;
else if (c == '=')
break;
else
continue;
switch (n & 3)
{
case 0: buf[0] = c << 2; break;
case 1: buf[0] |= c >> 4; buf[1] = c << 4; break;
case 2: buf[1] |= c >> 2; buf[2] = c << 6; break;
case 3: buf[2] |= c; STRING_make(buf, 3); break;
}
n++;
}
if ((n & 3) > 1)
STRING_make(buf, (n & 3) - 1);
}
goto __END;
__FROM_URL:
for (i = 0; i < lstr; i++)
{
c = str[i];
if (c == '+')
c = ' ';
else if (c == '%')
{
if (i >= (lstr - 2))
break;
c = (read_hex_digit(str[i + 1]) << 4) + read_hex_digit(str[i + 2]);
i += 2;
}
STRING_make_char(c);
}
goto __END;
__ILLEGAL:
THROW_ILLEGAL();
__END:
RETURN->type = T_STRING;
RETURN->_string.addr = STRING_end_temp();
RETURN->_string.start = 0;
RETURN->_string.len = STRING_length(RETURN->_string.addr);
SUBR_LEAVE();
}
void SUBR_swap(ushort code)
{
char *src, *dst;
int len, i, j;
if (!(code & 0xFF))
{
SUBR_move(1);
return;
}
SUBR_ENTER();
if (NPARAM == 2 && (SUBR_get_integer(&PARAM[1]) == GB_BIG_ENDIAN) == EXEC_big_endian)
{
SP--;
return;
}
if (SUBR_check_string(PARAM))
STRING_void_value(RETURN);
else
{
len = PARAM->_string.len;
if (len > 0)
{
src = PARAM->_string.addr + PARAM->_string.start;
dst = STRING_new_temp(NULL, PARAM->_string.len);
for (i = 0, j = len - 1; i < len; i++,j--)
dst[i] = src[j];
RETURN->type = T_STRING;
RETURN->_string.addr = dst;
RETURN->_string.start = 0;
RETURN->_string.len = len;
}
}
SUBR_LEAVE();
}