view src/ploki/pp.c @ 9554:23f43464694e

<Zarutian> le/rn Frams\xc3\xb3knarflokkurinn/A, now defunct, political party in Iceland. Like its sister party Sj\xc3\xa1lfst\xc3\xa6\xc3\xb0isflokkurinn it is named by the antonym of what it is. (The name means the Progressive Party but they have nearly always been highly regressive). Think dumb Hill-Billies in ill fitting suits and you get their constiuents.
author HackBot
date Sun, 30 Oct 2016 14:33:24 +0000
parents ac0403686959
children
line wrap: on
line source

#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;
}