V7_PRIVATE enum v7_err Str_match(struct v7_c_func_arg *cfa) { #define v7 (cfa->v7) /* Needed for TRY() macro below */ struct v7_val *arg = cfa->args[0]; struct Resub sub; struct v7_val *arr = NULL; unsigned long shift = 0; if (cfa->num_args > 0) { TRY(check_str_re_conv(v7, &arg, 1)); TRY(regex_check_prog(arg)); do { if (!re_exec(arg->v.str.prog, arg->fl.fl, cfa->this_obj->v.str.buf + shift, &sub)) { if (NULL == arr) { arr = v7_push_new_object(v7); v7_set_class(arr, V7_CLASS_ARRAY); } shift = sub.sub[0].end - cfa->this_obj->v.str.buf; v7_append(v7, arr, v7_mkv(v7, V7_TYPE_STR, sub.sub[0].start, sub.sub[0].end - sub.sub[0].start, 1)); } } while (arg->fl.fl.re_g && shift < cfa->this_obj->v.str.len); } if (0 == shift) TRY(v7_make_and_push(v7, V7_TYPE_NULL)); return V7_OK; #undef v7 }
V7_PRIVATE enum v7_err Str_split(struct v7_c_func_arg *cfa) { #define v7 (cfa->v7) /* Needed for TRY() macro below */ struct v7_val *arg = cfa->args[0], *arr = v7_push_new_object(v7); struct Resub sub, sub1; int limit = 1000000, elem = 0, i, len; unsigned long shift = 0; v7_set_class(arr, V7_CLASS_ARRAY); if (cfa->num_args > 0) { if (cfa->num_args > 1 && cfa->args[1]->type == V7_TYPE_NUM) limit = cfa->args[1]->v.num; TRY(check_str_re_conv(v7, &arg, 1)); TRY(regex_check_prog(arg)); for (; elem < limit && shift < cfa->this_obj->v.str.len; elem++) { if (re_exec(arg->v.str.prog, arg->fl.fl, cfa->this_obj->v.str.buf + shift, &sub)) break; v7_append(v7, arr, v7_mkv(v7, V7_TYPE_STR, cfa->this_obj->v.str.buf + shift, sub.sub[0].start - cfa->this_obj->v.str.buf - shift, 1)); for (i = 1; i < sub.subexpr_num; i++) v7_append(v7, arr, v7_mkv(v7, V7_TYPE_STR, sub.sub[i].start, sub.sub[i].end - sub.sub[i].start, 1)); shift = sub.sub[0].end - cfa->this_obj->v.str.buf; sub1 = sub; } } len = cfa->this_obj->v.str.len - shift; if (elem < limit && len > 0) v7_append(v7, arr, v7_mkv(v7, V7_TYPE_STR, cfa->this_obj->v.str.buf + shift, len, 1)); return V7_OK; #undef v7 }
V7_PRIVATE void init_json(void) { SET_METHOD(s_json, "stringify", Json_stringify); v7_set_class(&s_json, V7_CLASS_OBJECT); s_json.ref_count = 1; SET_RO_PROP_V(s_global, "JSON", s_json); }
V7_PRIVATE enum v7_err Obj_keys(struct v7_c_func_arg *cfa) { struct v7_prop *p; struct v7_val *result = v7_push_new_object(cfa->v7); v7_set_class(result, V7_CLASS_ARRAY); for (p = cfa->this_obj->props; p != NULL; p = p->next) { v7_append(cfa->v7, result, p->key); } return V7_OK; }
static void Str_split(struct v7_c_func_arg *cfa) { const struct v7_string *s = &cfa->this_obj->v.str; const char *p1, *p2, *e = s->buf + s->len; int limit = cfa->num_args == 2 && cfa->args[1]->type == V7_TYPE_NUM ? cfa->args[1]->v.num : -1; int num_elems = 0; v7_set_class(cfa->result, V7_CLASS_ARRAY); if (cfa->num_args == 0) { v7_append(cfa->v7, cfa->result, v7_mkv(cfa->v7, V7_TYPE_STR, s->buf, s->len, 1)); } else if (cfa->args[0]->type == V7_TYPE_STR) { const struct v7_string *sep = &cfa->args[0]->v.str; if (sep->len == 0) { // Separator is empty. Split string by characters. for (p1 = s->buf; p1 < e; p1++) { if (limit >= 0 && limit <= num_elems) return; v7_append(cfa->v7, cfa->result, v7_mkv(cfa->v7, V7_TYPE_STR, p1, 1, 1)); num_elems++; } } else { p1 = s->buf; while ((p2 = memstr(p1, e - p1, sep->buf, sep->len)) != NULL) { if (limit >= 0 && limit <= num_elems) return; v7_append(cfa->v7, cfa->result, v7_mkv(cfa->v7, V7_TYPE_STR, p1, p2 - p1, 1)); p1 = p2 + sep->len; num_elems++; } if (limit < 0 || limit > num_elems) { v7_append(cfa->v7, cfa->result, v7_mkv(cfa->v7, V7_TYPE_STR, p1, e - p1, 1)); } } } else if (instanceof(cfa->args[0], &s_constructors[V7_CLASS_REGEXP])) { char regex[200]; struct slre_cap caps[20]; int n = 0; snprintf(regex, sizeof(regex), "(%s)", cfa->args[0]->v.regex); p1 = s->buf; while ((n = slre_match(regex, p1, e - p1, caps, ARRAY_SIZE(caps), 0)) > 0) { if (limit >= 0 && limit <= num_elems) return; v7_append(cfa->v7, cfa->result, v7_mkv(cfa->v7, V7_TYPE_STR, p1, caps[0].ptr - p1, 1)); p1 += n; num_elems++; } if (limit < 0 || limit > num_elems) { v7_append(cfa->v7, cfa->result, v7_mkv(cfa->v7, V7_TYPE_STR, p1, e - p1, 1)); } } }
V7_PRIVATE enum v7_err String_ctor(struct v7_c_func_arg *cfa) { #define v7 (cfa->v7) /* Needed for TRY() macro below */ const char *str = NULL; size_t len = 0; int own = 0; struct v7_val *arg = cfa->args[0], *obj = cfa->this_obj; if (!cfa->called_as_constructor) obj = v7_push_new_object(v7); if (cfa->num_args > 0) { TRY(check_str_re_conv(v7, &arg, 0)); str = arg->v.str.buf; len = arg->v.str.len; own = 1; } v7_init_str(obj, str, len, own); v7_set_class(obj, V7_CLASS_STRING); return V7_OK; #undef v7 }
static void Str_match(struct v7_c_func_arg *cfa) { struct slre_cap caps[100]; const struct v7_string *s = &cfa->this_obj->v.str; int i, n; cfa->result->type = V7_TYPE_NULL; memset(caps, 0, sizeof(caps)); if (cfa->num_args == 1 && v7_is_class(cfa->args[0], V7_CLASS_REGEXP) && (n = slre_match(cfa->args[0]->v.regex, s->buf, s->len, caps, ARRAY_SIZE(caps) - 1, 0)) > 0) { v7_set_class(cfa->result, V7_CLASS_ARRAY); v7_append(cfa->v7, cfa->result, v7_mkv(cfa->v7, V7_TYPE_STR, s->buf, (long) n, 1)); for (i = 0; i < (int) ARRAY_SIZE(caps); i++) { if (caps[i].len == 0) break; v7_append(cfa->v7, cfa->result, v7_mkv(cfa->v7, V7_TYPE_STR, caps[i].ptr, (long) caps[i].len, 1)); } } }
V7_PRIVATE enum v7_err Error_ctor(struct v7_c_func_arg *cfa) { struct v7_val *obj = cfa->called_as_constructor ? cfa->this_obj : v7_push_new_object(cfa->v7); v7_set_class(obj, V7_CLASS_ERROR); return V7_OK; }
V7_PRIVATE void v7_init_func(struct v7_val *v, v7_func_t func) { v7_set_class(v, V7_CLASS_FUNCTION); v->v.c_func = func; }
V7_PRIVATE enum v7_err Str_replace(struct v7_c_func_arg *cfa) { #define v7 (cfa->v7) /* Needed for TRY() macro below */ struct v7_val *result = v7_push_new_object(v7); const char *out_str = cfa->this_obj->v.str.buf; uint8_t own = 1; size_t out_len = cfa->this_obj->v.str.len; int old_sp = v7->sp; if (cfa->num_args > 1) { const char *const str_end = cfa->this_obj->v.str.buf + cfa->this_obj->v.str.len; char *p = cfa->this_obj->v.str.buf; uint32_t out_sub_num = 0; struct v7_val *re = cfa->args[0], *str_func = cfa->args[1], *arr = NULL; struct re_tok out_sub[V7_RE_MAX_REPL_SUB], *ptok = out_sub; struct Resub loot; TRY(check_str_re_conv(v7, &re, 1)); TRY(regex_check_prog(re)); if (v7_is_class(str_func, V7_CLASS_FUNCTION)) { arr = v7_push_new_object(v7); v7_set_class(arr, V7_CLASS_ARRAY); TRY(v7_push(v7, str_func)); } else TRY(check_str_re_conv(v7, &str_func, 0)); out_len = 0; do { int i; if (re_exec(re->v.str.prog, re->fl.fl, p, &loot)) break; if (p != loot.sub->start) { ptok->start = p; ptok->end = loot.sub->start; ptok++; out_len += loot.sub->start - p; out_sub_num++; } if (NULL != arr) { /* replace function */ Rune rune; int old_sp = v7->sp, utf_shift = 0; struct v7_val *rez_str; for (i = 0; i < loot.subexpr_num; i++) v7_push_string(v7, loot.sub[i].start, loot.sub[i].end - loot.sub[i].start, 1); for (i = 0; p + i < loot.sub[0].start; i += chartorune(&rune, p + i), utf_shift++) ; TRY(push_number(v7, utf_shift)); TRY(v7_push(v7, cfa->this_obj)); rez_str = v7_call(v7, cfa->this_obj, loot.subexpr_num + 2); TRY(check_str_re_conv(v7, &rez_str, 0)); if (rez_str->v.str.len) { ptok->start = rez_str->v.str.buf; ptok->end = rez_str->v.str.buf + rez_str->v.str.len; ptok++; out_len += rez_str->v.str.len; out_sub_num++; v7_append(v7, arr, rez_str); } TRY(inc_stack(v7, old_sp - v7->sp)); } else { /* replace string */ struct Resub newsub; re_rplc(&loot, p, str_func->v.str.buf, &newsub); for (i = 0; i < newsub.subexpr_num; i++) { ptok->start = newsub.sub[i].start; ptok->end = newsub.sub[i].end; ptok++; out_len += newsub.sub[i].end - newsub.sub[i].start; out_sub_num++; } } p = (char *)loot.sub->end; } while (re->fl.fl.re_g && p < str_end); if (p < str_end) { ptok->start = p; ptok->end = str_end; ptok++; out_len += str_end - p; out_sub_num++; } out_str = malloc(out_len + 1); CHECK(out_str, V7_OUT_OF_MEMORY); ptok = out_sub; p = (char *)out_str; do { size_t ln = ptok->end - ptok->start; memcpy(p, ptok->start, ln); p += ln; ptok++; } while (--out_sub_num); *p = '\0'; own = 0; } TRY(inc_stack(v7, old_sp - v7->sp)); v7_init_str(result, out_str, out_len, own); result->fl.fl.str_alloc = 1; return V7_OK; #undef v7 }
V7_PRIVATE enum v7_err Boolean_ctor(struct v7_c_func_arg *cfa) { struct v7_val *obj = cfa->called_as_constructor ? cfa->this_obj : cfa->result; v7_set_class(obj, V7_CLASS_BOOLEAN); return V7_OK; }