/*************************************************************************** gbx_subr_string.c (c) 2000-2017 BenoĆ®t Minisini 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 #include #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; if (NPARAM == 1) { PARAM--; VALUE_conv_string(&PARAM[1]); len2 = PARAM[1]._string.len; if (PARAM[0].type == T_STRING) { if (len2 == 0) { RELEASE_STRING(&PARAM[0]); RELEASE_STRING(&PARAM[1]); SP -= 2; PC++; return; } str = PARAM[0]._string.addr; len = PARAM[0]._string.len; if (len && PARAM[0]._string.start == 0 && len == STRING_length(str) && STRING_from_ptr(str)->ref == 2) { STRING_from_ptr(str)->ref--; str = STRING_add(str, PARAM[1]._string.addr + PARAM[1]._string.start, len2); if (PCODE_is(PC[1], C_POP_LOCAL)) { VALUE *bp = &BP[(signed char)PC[1]]; bp->_string.addr = str; bp->_string.len += len2; } else if (PCODE_is(PC[1], C_POP_PARAM)) { VALUE *pp = &PP[(signed char)PC[1]]; pp->_string.addr = str; pp->_string.len += len2; } else if (PCODE_is(PC[1], C_POP_STATIC)) { CLASS_VAR *var = &CP->load->stat[PC[1] & 0x7FF]; *(char **)((char *)CP->stat + var->pos) = str; } else if (PCODE_is(PC[1], C_POP_DYNAMIC)) { CLASS_VAR *var = &CP->load->dyn[PC[1] & 0x7FF]; *(char **)(OP + var->pos) = str; } RELEASE_STRING(&PARAM[1]); SP -= 2; PC++; return; } } else { VALUE_conv_string(&PARAM[0]); len = PARAM[0]._string.len ; } } else { VALUE_conv_string(&PARAM[0]); len = PARAM[0]._string.len ; VALUE_conv_string(&PARAM[1]); len2 = PARAM[1]._string.len; } 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_string(&PARAM[i]); VALUE_get_string(&PARAM[i], &addr, &len); //SUBR_get_string_len(&PARAM[i], &addr, &len); if (addr && 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(); } void SUBR_is_chr(ushort code) { static ushort test[256] = { 0x0041, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x00C1, 0x0041, 0x0041, 0x0041, 0x0041, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x0001, 0x00C1, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0231, 0x0231, 0x0231, 0x0231, 0x0231, 0x0231, 0x0231, 0x0231, 0x0231, 0x0231, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x022B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x020B, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0227, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0207, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101 }; char *addr; int len; int i; bool ret; ushort bit; SUBR_ENTER_PARAM(1); VALUE_conv_string(PARAM); //SUBR_get_string_len(PARAM, &addr, &len); VALUE_get_string(PARAM, &addr, &len); if (len == 1) ret = (test[(unsigned char)*addr] & (1 << ((code & 0xF) - 1))) != 0; else if (len <= 0) ret = FALSE; else { bit = 1 << ((code & 0xF) - 1); ret = TRUE; for (i = 0; i < len; i++) { if ((test[(unsigned char)addr[i]] & bit) == 0) { ret = FALSE; break; } } } RELEASE_STRING(PARAM); SP--; SP->type = T_BOOLEAN; SP->_boolean.value = ret; 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[] = "0123456789ABCDEF"; STRING_make_char(hex_digit[c >> 4]); STRING_make_char(hex_digit[c & 15]); } 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("&", 5); else if (c == '<') STRING_make("<", 4); else if (c == '>') STRING_make(">", 4); else if (c == '"') STRING_make(""", 6); else if (c == '\'') STRING_make("'", 6); else if (c == 0xC2 && (uchar)str[i + 1] == 0xA0) { STRING_make(" ", 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(); }