Mercurial > repo
diff src/ploki/pp.c @ 4223:ac0403686959
<oerjan> rm -rf src/ploki; mv ploki src
author | HackBot |
---|---|
date | Fri, 20 Dec 2013 22:18:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ploki/pp.c Fri Dec 20 22:18:50 2013 +0000 @@ -0,0 +1,957 @@ +#include "IO.h" +#include "Str.h" +#include "kork.h" +#include "list.h" +#include "main_io.h" +#include "main_opt.h" +#include "match.h" +#include "pp.h" +#include "re.h" +#include "run.h" +#include "val.h" +#include "xmalloc.h" + +#include <ctype.h> +#include <errno.h> +#include <float.h> +#include <math.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void pp_abs(struct val *v) { + V_NUM(v); + v_set_n(v, fabs(v->num)); +} + +void pp_acos(struct val *v) { + V_NUM(v); + v_set_n(v, acos(v->num)); +} + +void pp_asin(struct val *v) { + V_NUM(v); + v_set_n(v, asin(v->num)); +} + +void pp_atan(struct val *v) { + V_NUM(v); + v_set_n(v, atan(v->num)); +} + +void pp_atan2(struct val *v) { + if (!V_LIST_P(v) || li_length(v->magic.list) != 2) { + v_set_undef(v); + #ifdef EINVAL + errno = EINVAL; + #endif + return; + } else { + struct val *const a = li_at(v->magic.list, 0); + struct val *const b = li_at(v->magic.list, 1); + V_NUM(a); + V_NUM(b); + v_set_n(v, atan2(a->num, b->num)); + } +} + +void pp_chr(struct val *v) { + V_NUM(v); + V_xxx_OFF(v); + ko_cpy_c(v->ko, (unsigned char)(v->num + .5)); + v->type = V_STR_K; +} + +void pp_cos(struct val *v) { + V_NUM(v); + v_set_n(v, cos(v->num)); +} + +void pp_defined(struct val *v) { + if (v->type != V_UNDEF) { + v_set_n(v, 1.0); + } +} + +void pp_eof(struct val *v) { + if (!V_EXT_P(v)) { + v_set_undef(v); + #ifdef EBADF + errno = EBADF; + #endif + return; + } + if (io_eof(v->magic.ext)) { + v_set_n(v, 1.0); + } else { + v_set_m(v, "", 0); + } +} + +void pp_error(struct val *v) { + if (!V_EXT_P(v)) { + v_set_undef(v); + #ifdef EBADF + errno = EBADF; + #endif + return; + } + if (io_err(v->magic.ext)) { + v_set_n(v, 1.0); + } else { + v_set_m(v, "", 0); + } +} + +void pp_escape(struct val *v) { + String tmp; + size_t i; + + V_STR(v); + V_xxx_OFF(v); + St_init(&tmp); + St_cpy(&tmp, ko_str(v->ko)); + ko_zero(v->ko); + for (i = St_len(&tmp); i; ) { + --i; + if (!(ST_INDEX(&tmp, i) == '_' || isalnum(ST_INDEX(&tmp, i)))) { + ko_cat_c(v->ko, '!'); + } + ko_cat_c(v->ko, ST_INDEX(&tmp, i)); + } + St_clear(&tmp); + ko_reverse(v->ko); + v->type = V_STR_K; +} + +void pp_getc(struct val *v) { + int c; + + if (!V_EXT_P(v)) { + V_xxx_OFF(v); + v->type = V_UNDEF; + #ifdef EBADF + errno = EBADF; + #endif + return; + } + c = io_getc(v->magic.ext); + #if EOF != -1 + if (c == EOF) { + c = -1; + } + #endif + v_set_n(v, c); +} + +void pp_getenv(struct val *v) { + const char *const tmp = getenv(v_sptr(v, NULL)); + if (tmp) { + v_set_m(v, tmp, strlen(tmp)); + } else { + V_xxx_OFF(v); + v->type = V_UNDEF; + } +} + +void pp_gets(struct val *v) { + + if (!V_EXT_P(v)) { + V_xxx_OFF(v); + v->type = V_UNDEF; + #ifdef EBADF + errno = EBADF; + #endif + return; + } + + if (ko_getline(v->magic.ext, v->ko) + 1u) { + V_xxx_OFF(v); + v->type = V_STR_K; + } else { + V_xxx_OFF(v); + v->type = V_UNDEF; + } +} + +void pp_int(struct val *v) { + V_NUM(v); + v_set_n(v, floor(v->num + .5)); +} + +void pp_io(struct val *v) { + if (V_EXT_P(v)) { + v_set_n(v, 1.0); + } else { + v_set_m(v, "", 0); + } +} + +void pp_length(struct val *v) { + if (V_LIST_P(v)) { + v_set_n(v, li_length(v->magic.list)); + return; + } + v_set_n(v, ko_length(v_kork(v))); +} + +void pp_log(struct val *v) { + V_NUM(v); + v_set_n(v, log(v->num)); +} + +void pp_log10(struct val *v) { + V_NUM(v); + v_set_n(v, log10(v->num)); +} + +void pp_lower(struct val *v) { + V_STR(v); + V_xxx_OFF(v); + ko_lower(v->ko); +} + +void pp_moend(struct val *v) { + size_t n; + + V_NUM(v); + n = RINT(v->num); + if (n < Interp.m_end.size) { + v_set_n(v, Interp.m_end.index[n]); + } else { + v_set_undef(v); + } +} + +void pp_mostart(struct val *v) { + size_t n; + + V_NUM(v); + n = RINT(v->num); + if (n < Interp.m_start.size) { + v_set_n(v, Interp.m_start.index[n]); + } else { + v_set_undef(v); + } +} + +void pp_neg(struct val *v) { + V_NUM(v); + V_xxx_OFF(v); + v->num = -v->num; + v->type = V_NUM_K; +} + +void pp_not(struct val *v) { + if (v_true(v)) { + v_set_m(v, "", 0); + } else { + v_set_n(v, 1.0); + } +} + +void pp_num(struct val *v) { + V_NUM(v); + V_xxx_OFF(v); + v->type = V_NUM_K; +} + +void pp_open(struct val *v) { + IO *fh; + struct val *name, *mode; + enum io_flags flags; + + if (!V_LIST_P(v) || li_length(v->magic.list) != 2) { + v_set_undef(v); + #ifdef ENOENT + errno = ENOENT; + #endif + return; + } + + name = li_at(v->magic.list, 0); + V_STR(name); + if (ko_chr(name->ko, '\0') + 1u) { + v_set_undef(v); + #ifdef ENOENT + errno = ENOENT; + #endif + return; + } + + mode = li_at(v->magic.list, 1); + flags = 0; + V_STR(mode); + + if (ko_chr(mode->ko, 'A') + 1u) { + flags |= IO_APPEND; + if (ko_chr(mode->ko, '+') + 1u) { + flags |= IO_READ; + } + } else if (ko_chr(mode->ko, 'W') + 1u) { + flags |= IO_WRITE | IO_TRUNCATE; + if (ko_chr(mode->ko, '+') + 1u) { + flags |= IO_READ; + } + } else { + flags |= IO_READ; + if (ko_chr(mode->ko, '+') + 1u) { + flags |= IO_WRITE; + } else if (ko_chr(mode->ko, 'Z') + 1u) { + flags |= IO_BUFFERED; + } + } + + if (ko_chr(mode->ko, 'B') + 1u) { + flags |= IO_BINARY; + } + if ((flags & IO_WRITE || flags & IO_APPEND) && ko_chr(mode->ko, 'F') + 1u) { + flags |= IO_AUTOFLUSH; + } + + if (!(fh = io_open(ko_szp(name->ko), flags))) { + v_set_undef(v); + return; + } + + v_set_io(v, fh); +} + +void pp_openr(struct val *v) { + V_STR(v); + V_xxx_OFF(v); + if (ko_chr(v->ko, '\0') + 1u) { + v->type = V_UNDEF; + #ifdef ENOENT + errno = ENOENT; + #endif + } else if ((v->magic.ext = io_open(ko_szp(v->ko), IO_READ | IO_BINARY))) { + v->type = V_EXT_K; + } else { + v->type = V_UNDEF; + } +} + +void pp_openw(struct val *v) { + V_STR(v); + V_xxx_OFF(v); + if (ko_chr(v->ko, '\0') + 1u) { + v->type = V_UNDEF; + #ifdef ENOENT + errno = ENOENT; + #endif + } else if ((v->magic.ext = io_open(ko_szp(v->ko), IO_WRITE | IO_TRUNCATE | IO_BINARY | IO_AUTOFLUSH))) { + v->type = V_EXT_K; + } else { + v->type = V_UNDEF; + } +} + +void pp_ord(struct val *v) { + V_STR(v); + V_xxx_OFF(v); + if (ko_length(v->ko)) { + v->num = ko_at(v->ko, 0); + v->type = V_NUM_K; + } else { + v->type = V_UNDEF; + } +} + +void pp_quote(struct val *v) { + String tmp; + size_t i; + + V_STR(v); + V_xxx_OFF(v); + St_init(&tmp); + St_cpy_m(&tmp, ko_ptr(v->ko), ko_length(v->ko)); + ko_zero(v->ko); + for (i = 0; i < St_len(&tmp); ++i) { + if (!(ST_INDEX(&tmp, i) == '_' || isalnum(ST_INDEX(&tmp, i)))) { + ko_cat_c(v->ko, '\\'); + } + ko_cat_c(v->ko, ST_INDEX(&tmp, i)); + } + St_clear(&tmp); + v->type = V_STR_K; +} + +void pp_remove(struct val *v) { + V_STR(v); + V_xxx_OFF(v); + if (ko_chr(v->ko, '\0') + 1u) { + v->type = V_UNDEF; + #ifdef ENOENT + errno = ENOENT; + #endif + return; + } + + if (remove(ko_szp(v->ko))) { + v_set_m(v, "", 0); + } else { + v_set_n(v, 1.0); + } +} + +void pp_rename(struct val *v) { + struct val *from, *to; + + if (!V_LIST_P(v) || li_length(v->magic.list) != 2) { + v_set_undef(v); + #ifdef ENOENT + errno = ENOENT; + #endif + return; + } + + from = li_at(v->magic.list, 0); + V_STR(from); + if (ko_chr(from->ko, '\0') + 1u) { + v_set_undef(v); + #ifdef ENOENT + errno = ENOENT; + #endif + return; + } + + to = li_at(v->magic.list, 1); + V_STR(to); + if (ko_chr(to->ko, '\0') + 1u) { + v_set_undef(v); + #ifdef EINVAL + errno = EINVAL; + #endif + return; + } + + if (rename(ko_szp(from->ko), ko_szp(to->ko))) { + v_set_m(v, "", 0); + } else { + v_set_n(v, 1.0); + } +} + +void pp_reverse(struct val *v) { + if (V_LIST_P(v)) { + li_reverse(v->magic.list); + v->type = V_LIST_K; + return; + } + V_STR(v); + V_xxx_OFF(v); + ko_reverse(v->ko); + v->type = V_STR_K; +} + +void pp_seek(struct val *v) { + struct val *fh, *tmp; + long off; + enum io_whence whence = IOS_START; + + if (!V_LIST_P(v) || li_length(v->magic.list) < 2 || li_length(v->magic.list) > 3) { + v_set_undef(v); + #ifdef EINVAL + errno = EINVAL; + #endif + return; + } + + fh = li_at(v->magic.list, 0); + if (!V_EXT_P(fh)) { + v_set_undef(v); + #ifdef EBADF + errno = EBADF; + #endif + return; + } + + tmp = li_at(v->magic.list, 1); + V_NUM(tmp); + off = RINT(tmp->num); + + if ((tmp = li_at(v->magic.list, 2))) { + V_NUM(tmp); + switch ((long)RINT(tmp->num)) { + case 0: whence = IOS_START; break; + case 1: whence = IOS_CUR; break; + case 2: whence = IOS_END; break; + default: + v_set_undef(v); + #ifdef EINVAL + errno = EINVAL; + #endif + return; + } + } + + v_set_n(v, io_seek(fh->magic.ext, off, whence)); +} + +void pp_sin(struct val *v) { + V_NUM(v); + v_set_n(v, sin(v->num)); +} + +void pp_sqrt(struct val *v) { + V_NUM(v); + V_xxx_OFF(v); + v->num = sqrt(v->num); + v->type = V_NUM_K; +} + +void pp_str(struct val *v) { + V_STR(v); + V_xxx_OFF(v); + v->type |= V_STR_K; +} + +void pp_tan(struct val *v) { + V_NUM(v); + v_set_n(v, tan(v->num)); +} + +void pp_tell(struct val *v) { + if (!V_EXT_P(v)) { + v_set_undef(v); + #ifdef EBADF + errno = EBADF; + #endif + return; + } + v_set_n(v, io_tell(v->magic.ext)); +} + +void pp_typeof(struct val *v) { + if (V_SUB_P(v)) { + v_set_m(v, "stuff", 5); + } else if (V_EXT_P(v)) { + v_set_m(v, "stream", 6); + } else if (V_LIST_P(v)) { + v_set_m(v, "list", 4); + } else if (V_NUM_P(v)) { + v_set_m(v, "number", 6); + } else if (V_STR_P(v)) { + v_set_m(v, "string", 6); + } else { + v_set_m(v, "nothing", 7); + } +} + +void pp_upper(struct val *v) { + V_STR(v); + V_xxx_OFF(v); + ko_upper(v->ko); +} + +#define NUMB(expr) \ +do { \ + V_NUM(b); \ + V_NUM(v); \ + v_set_n(v, expr); \ +} while (0) + +#define ARITH(op) NUMB(v->num op b->num) + +void pp_add(struct val *v, struct val *b) { + ARITH(+); +} + +#define LOGIC(init, cond) \ +do { \ + init; \ + if (cond) { \ + v_set_n(v, 1.0); \ + } else { \ + v_set_m(v, "", 0); \ + } \ +} while (0) + +void pp_and(struct val *v, struct val *b) { + LOGIC((void)0, v_true(v) && v_true(b)); +} + +void pp_comma(struct val *v, struct val *b) { + v_set(v, b); +} + +void pp_concat(struct val *v, struct val *b) { + v_cat(v, b); +} + +void pp_div(struct val *v, struct val *b) { + ARITH(/); +} + +#define CMP_LS(op) LOGIC((void)0, v_cmp_ls(v, b) op 0) + +void pp_eq(struct val *v, struct val *b) { + CMP_LS(==); +} + +#define CMP_N(op) LOGIC(V_NUM(v); V_NUM(b), v->num op b->num) + +void pp_eq_n(struct val *v, struct val *b) { + if (V_EXT_P(v)) { + if (V_EXT_P(b)) { + LOGIC((void)0, v->magic.ext == b->magic.ext); + } else if (V_SUB_P(b)) { + goto false_cmp; + } else { + goto default_cmp; + } + } else if (V_SUB_P(v)) { + if (V_SUB_P(b)) { + LOGIC((void)0, v->magic.sub == b->magic.sub); + } else if (V_EXT_P(b)) false_cmp: { + LOGIC((void)0, 0); + } else { + goto default_cmp; + } + } else default_cmp: { + CMP_N(==); + } +} + +static const char xdigits[] = "0123456789" "abcdefghijklmnopqrstuvwxyz"; + +void pp_frombase(struct val *v, struct val *b) { + double p; + size_t i; + int base, sign; + const char *tmp; + + V_NUM(b); + V_STR(v); + V_xxx_OFF(v); + if (floor(b->num + .5) < 2. || floor(b->num + .5) > 36.) { + v->type = V_UNDEF; + return; + } + base = floor(b->num + .5); + ko_shiftws(v->ko); + + sign = 0; + if (ko_at(v->ko, 0) == '-') { + sign = 1; + ko_shift(v->ko, 1); + } else if (ko_at(v->ko, 0) == '+') { + ko_shift(v->ko, 1); + } + + p = 0.0; + for (i = 0; i < ko_length(v->ko); ++i) { + if ((tmp = strchr(xdigits, tolower(ko_at(v->ko, i)))) && + tmp - xdigits < base) { + p *= base; + p += tmp - xdigits; + } else { + break; + } + } + + if (i < ko_length(v->ko)) { + if (ko_at(v->ko, i) == '.') { + double shift = 1.0; + + for (++i; i < ko_length(v->ko); ++i) { + if ((tmp = strchr(xdigits, tolower(ko_at(v->ko, i)))) && + tmp - xdigits < base) { + shift *= base; + p *= base; + p += tmp - xdigits; + } else { + break; + } + } + + p /= shift; + } + } + + if (sign) { + p = -p; + } + v_set_n(v, p); +} + +void pp_gt(struct val *v, struct val *b) { + CMP_LS(>); +} + +void pp_gt_n(struct val *v, struct val *b) { + CMP_N(>); +} + +void pp_lt(struct val *v, struct val *b) { + CMP_LS(<); +} + +void pp_lt_n(struct val *v, struct val *b) { + CMP_N(<); +} + +void pp_match(struct val *v, struct val *b) { + t_regex *re; + + V_STR(b); + re = re_compile(ko_str(b->ko)); + do_match(v, re); + re_free(re); +} + +void pp_mod(struct val *v, struct val *b) { + NUMB(fmod(v->num, b->num)); +} + +void pp_mult(struct val *v, struct val *b) { + ARITH(*); +} + +void pp_ne(struct val *v, struct val *b) { + CMP_LS(!=); +} + +void pp_ne_n(struct val *v, struct val *b) { + if (V_EXT_P(v)) { + if (V_EXT_P(b)) { + LOGIC((void)0, v->magic.ext != b->magic.ext); + } else if (V_SUB_P(b)) { + goto true_cmp; + } else { + goto default_cmp; + } + } else if (V_SUB_P(v)) { + if (V_SUB_P(b)) { + LOGIC((void)0, v->magic.sub != b->magic.sub); + } else if (V_EXT_P(b)) true_cmp: { + LOGIC((void)0, 1); + } else { + goto default_cmp; + } + } else default_cmp: { + CMP_N(!=); + } +} + +void pp_or(struct val *v, struct val *b) { + LOGIC((void)0, v_true(v) || v_true(b)); +} + +void pp_pop(struct val *v, struct val *b) { + long p; + + V_NUM(b); + p = RINT(b->num); + + if (V_LIST_P(v)) { + v->type = V_LIST_K; + if (p < 0) { + p += li_length(v->magic.list); + } + if (p < 0) { + p = 0; + } + if ((size_t)p >= li_length(v->magic.list)) { + return; + } + li_trunc(v->magic.list, p); + return; + } + + V_STR(v); + V_xxx_OFF(v); + v->type = V_STR_K; + if (p < 0) { + p += ko_length(v->ko); + } + if (p < 0) { + p = 0; + } + if ((size_t)p >= ko_length(v->ko)) { + return; + } + ko_trunc(v->ko, p); +} + +void pp_pow(struct val *v, struct val *b) { + NUMB(pow(v->num, b->num)); +} + +void pp_read(struct val *v, struct val *b) { + long n; + + if (V_SUB_P(v)) { + const size_t curdepth = depth_get(); + stack_store(&Interp.arg, b); + eval_into(sub_expr(v->magic.sub), v); + depth_restore(curdepth); + return; + } + + if (V_EXT_P(v)) { + V_NUM(b); + ko_read(v->magic.ext, v->ko, b->num < 0.0 ? (size_t)-1 : b->num + .5); + V_xxx_OFF(v); + v->type = V_STR_K; + return; + } + + if (V_LIST_P(v)) { + struct val *ptr; + V_NUM(b); + n = RINT(b->num); + if (n < 0) { + n += li_length(v->magic.list); + } + + if (n >= 0 && (ptr = li_at(v->magic.list, n))) { + struct list *tmp = li_dup(v->magic.list); + v_set(v, ptr); + li_delete(tmp); + } else { + v_set_undef(v); + } + return; + } + + V_STR(v); + V_xxx_OFF(v); + V_NUM(b); + n = RINT(b->num); + if (n < 0) { + n += ko_length(v->ko); + } + if (n >= 0 && (size_t)n < ko_length(v->ko)) { + ko_shift(v->ko, n); + ko_trunc(v->ko, 1); + v->type = V_STR_K; + } else { + v->type = V_UNDEF; + } +} + +void pp_shift(struct val *v, struct val *b) { + long p; + + V_NUM(b); + p = RINT(b->num); + + if (V_LIST_P(v)) { + v->type = V_LIST_K; + if (p < 0) { + p += li_length(v->magic.list); + } + if (p <= 0) { + return; + } + if ((size_t)p >= li_length(v->magic.list)) { + li_zero(v->magic.list); + } else { + li_shift(v->magic.list, p); + } + return; + } + + V_STR(v); + V_xxx_OFF(v); + v->type = V_STR_K; + if (p < 0) { + p += ko_length(v->ko); + } + if (p <= 0) { + return; + } + if ((size_t)p >= ko_length(v->ko)) { + ko_zero(v->ko); + } else { + ko_shift(v->ko, p); + } +} + +void pp_sub(struct val *v, struct val *b) { + ARITH(-); +} + +void pp_tobase(struct val *v, struct val *b) { + double p; + int base, sign; + size_t i; + + V_NUM(b); + V_NUM(v); + V_xxx_OFF(v); + + if (floor(b->num + .5) < 2. || floor(b->num + .5) > 36.) { + v->type = V_UNDEF; + return; + } + base = floor(b->num + .5); + + sign = 0; + if (v->num < 0.) { + v->num = -v->num; + sign = 1; + } + + p = v->num; + ko_zero(v->ko); + + if (floor(p) < p) { + double foo, bar; + size_t rounds; + + foo = 1 + floor(log(pow(10, DBL_DIG)) / log(base)); + bar = p > 0. ? 1 + floor(log(p) / log(base)) : 0.; + if (bar >= foo) { + rounds = 0; + } else { + rounds = foo - bar; + } + + for (i = 0; i < rounds; ++i) { + p *= base; + if (floor(p) >= p) { + ++i; + break; + } + } + + p = floor(p); + while (i--) { + int c; + c = fmod(p, base); + p = floor(p / base); + if (c >= 0) { + ko_cat_c(v->ko, xdigits[c]); + } + } + } + + while (ko_at(v->ko, 0) == '0') { + ko_shift(v->ko, 1); + } + + if (ko_length(v->ko)) { + ko_cat_c(v->ko, '.'); + } + + while (p > 0.) { + int c; + c = fmod(p, base); + p = floor(p / base); + if (c >= 0) { + ko_cat_c(v->ko, xdigits[c]); + } + } + + if (!ko_length(v->ko) || ko_lastchar(v->ko) == '.') { + ko_cat_c(v->ko, '0'); + } + if (sign) { + ko_cat_c(v->ko, '-'); + } + + v->type = V_STR_K; +}