view src/ploki/Str.c @ 12292:d51f2100210c draft

<kspalaiologos> `` cat <<<"asmbf && bfi output.b" > /hackenv/ibin/asmbf
author HackEso <hackeso@esolangs.org>
date Thu, 02 Jan 2020 15:38:21 +0000
parents ac0403686959
children
line wrap: on
line source

#include "config.h"
#include "Str.h"
#include "strutil.h"
#include "xmalloc.h"

#include <ctype.h>
#include <errno.h>
#include <float.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

enum {MAGIC = 4};

#define OFFSET_OFF(s)                                               \
do {                                                                \
	if ((s)->offset) {                                              \
		memmove((s)->buf - (s)->offset, (s)->buf, (s)->length + 1); \
		(s)->buf -= (s)->offset;                                    \
		(s)->offset = 0;                                            \
	}                                                               \
} while (0)


void
St_init(String *s) {
	s->buf = xmalloc(s->size = MAGIC, sizeof *s->buf);
	s->buf[s->offset = s->length = 0] = '\0';
}

void
St_fake(String *s, char *p, size_t n) {
	assert(s != NULL);
	assert(p != NULL);
	s->buf = p;
	s->offset = 0;
	s->length = s->size = n;
}

void
St_clear(String *s) {
	assert(s != NULL);
	if (!s->buf) {
		return;
	}
	xfree(s->buf - s->offset);
	s->buf = NULL;
	DEBUG(s->offset = s->length = s->size = 0;)
}

#if 0
void
(St_zero)(String *s) {
	St_zero(s);
}

char *
(St_ptr)(const String *s) {
	return St_ptr(s);
}

size_t
(St_len)(const String *s) {
	return St_len(s);
}
#endif

static void
St_grow(String *s, size_t n) {
	if (s->size - s->offset <= n) {
		OFFSET_OFF(s);
		if (s->size <= n) {
			s->buf = xrealloc(s->buf, n + 1u);
			s->size = n + 1u;
		}
	}
}

void
St_trunc(String *s, size_t n) {
	if (s->length > n) {
		s->buf[s->length = n] = '\0';
	}
	if (s->size > n + 1 && n >= MAGIC) {
		OFFSET_OFF(s);
		s->buf = xrealloc(s->buf, n + 1);
		s->size = n + 1;
	}
}

#if 0
int
St_lastchar(const String *s) {
	return ST_LASTCHAR(s);
}

int
St_firstchar(const String *s) {
	return ST_FIRSTCHAR(s);
}

int
St_chop(String *s) {
	int tmp;

	if (!s->length) {
		return EOF;
	}
	tmp = (unsigned char)s->buf[s->length - 1];
	s->buf[--s->length] = '\0';
	return tmp;
}
#endif

int
St_shift(String *s) {
	int tmp;

	if (!s->length) {
		return EOF;
	}
	tmp = (unsigned char)s->buf[0];
	++s->offset;
	++s->buf;
	--s->length;
	return tmp;
}


size_t
St_shiftws(String *s) {
	size_t n;

	for (n = 0; n < s->length && isspace((unsigned char)s->buf[n]); ++n)
		;
	s->offset += n;
	s->buf += n;
	s->length -= n;

	return n;
}

#if 0
int
St_index(const String *s, size_t n) {
	return ST_INDEX(s, n);
}
#endif

size_t
St_chr(const String *s, int c) {
	const char *tmp;
	if (!(tmp = memchr(s->buf, c, s->length))) {
		return -1;
	}
	return tmp - s->buf;
}

#if 0
size_t
St_rchr(const String *s, int c) {
	size_t i;

	for (i = s->length; i; --i) {
		if (s->buf[i - 1] == c)
			return i - 1;
	}
	return -1;
}
#endif

int
St_cmp(const String *s, const String *t) {
	return u_cmp(St_ptr(s), St_len(s), St_ptr(t), St_len(t));
}

int
St_cmp_m(const String *s, const void *m, size_t n) {
	return u_cmp(St_ptr(s), St_len(s), m, n);
}

#if 0
int
St_cmp_s(const String *s, const char *tz) {
	return u_cmp(St_ptr(s), St_len(s), tz, strlen(tz));
}
#endif

#define NCMP(s, m, n)                                                  \
do {                                                                   \
	return memcmp((s)->buf, m, (s)->length < (n) ? (s)->length : (n)); \
} while (0)

#if 0
int
St_ncmp(const String *s, const String *t) {
	NCMP(s, t->buf, t->length);
}
#endif

int
St_ncmp_m(const String *s, const void *m, size_t n) {
	NCMP(s, m, n);
}

#if 0
int
St_ncmp_s(const String *s, const char *tz) {
	size_t length = strlen(tz);

	NCMP(s, tz, length);
}

static int
my_memcasecmp(const void *p, const void *q, size_t n) {
	const unsigned char *s = p, *t = q;
	size_t i;

	for (i = 0; i < n; ++i) {
		if (tolower(s[i]) < tolower(t[i])) {
			return -1;
		}
		if (tolower(s[i]) > tolower(t[i])) {
			return 1;
		}
	}
	return 0;
}

#define CASECMP(s, m, n)       \
do {                           \
	int tmp__;                 \
	if (!(tmp__ = my_memcasecmp((s)->buf, m, (s)->length < (n) ? (s)->length : (n)))) { \
		if ((s)->length < (n)) \
			return -1;         \
		if ((s)->length > (n)) \
			return 1;          \
	}                          \
	return tmp__;              \
} while (0)

int
St_casecmp(const String *s, const String *t) {
	CASECMP(s, t->buf, t->length);
}

int
St_casecmp_m(const String *s, const void *m, size_t n) {
	CASECMP(s, m, n);
}

int
St_casecmp_s(const String *s, const char *tz) {
	size_t length = strlen(tz);

	CASECMP(s, tz, length);
}

#define NCASECMP(s, m, n)                 \
do {                                      \
	return my_memcasecmp((s)->buf, m, n); \
} while (0)

int
St_ncasecmp(const String *s, const String *t) {
	NCASECMP(s, t->buf, t->length);
}

int
St_ncasecmp_m(const String *s, const void *m, size_t n) {
	NCASECMP(s, m, n);
}

int
St_ncasecmp_s(const String *s, const char *tz) {
	size_t length = strlen(tz);

	NCASECMP(s, tz, length);
}
#endif

#define STR(s, m, n)                                 \
do {                                                 \
	size_t i__;                                      \
	if ((n) == 0)                                    \
		return 0;                                    \
	if ((s)->length < (n))                           \
		return -1;                                   \
	for (i__ = 0; i__ <= (s)->length - (n); ++i__) { \
		if (!memcmp((s)->buf + i__, m, n))           \
			return i__;                              \
	}                                                \
	return -1;                                       \
} while (0)

size_t
St_str(const String *s, const String *t) {
	STR(s, t->buf, t->length);
}

size_t
St_str_m(const String *s, const void *m, size_t n) {
	STR(s, m, n);
}

#if 0
size_t
St_str_s(const String *s, const char *tz) {
	size_t length = strlen(tz);

	STR(s, tz, length);
}
#endif

#define RSTR(s, m, n)                               \
do {                                                \
	size_t i__;                                     \
	if ((n) == 0)                                   \
		return (s)->length;                         \
	if ((s)->length < (n))                          \
		return -1;                                  \
	for (i__ = (s)->length - (n) + 1; i__; --i__) { \
		if (!memcmp((s)->buf + i__ - 1, m, n))      \
			return i__ - 1;                         \
	}                                               \
	return -1;                                      \
} while (0)

#if 0
size_t
St_rstr(const String *s, const String *t) {
	RSTR(s, t->buf, t->length);
}
#endif

size_t
St_rstr_m(const String *s, const void *m, size_t n) {
	RSTR(s, m, n);
}

size_t
St_rstr_s(const String *s, const char *tz) {
	size_t length = strlen(tz);

	RSTR(s, tz, length);
}

size_t
St_stro_m(const String *s, size_t off, const void *m, size_t n) {
	size_t i;

	assert(off <= s->length);

	if (n == 0) {
		return off;
	}

	if (n > s->length - off) {
		return -1;
	}

	for (i = off; i < s->length - n; ++i) {
		if (memcmp(s->buf + i, m, n) == 0) {
			return i;
		}
	}
	return -1;
}

size_t
St_rstro_m(const String *s, size_t off, const void *m, size_t n) {
	size_t i;

	assert(off <= s->length);

	if (n == 0) {
		return off;
	}

	if (n > s->length) {
		return -1;
	}

	i = off;
	if (i > s->length - n) {
		i = s->length - n;
	}

	for (; i + 1u; --i) {
		if (memcmp(s->buf + i, m, n) == 0) {
			return i;
		}
	}
	return -1;
}

#define CPY(s, m, n)                                \
do {                                                \
	if ((s)->size - (s)->offset <= (n)) {           \
		OFFSET_OFF(s);                              \
		if ((s)->size <= (n)) {                     \
			(s)->buf = xrealloc((s)->buf, (n) + 1); \
			(s)->size = (n) + 1;                    \
		}                                           \
	}                                               \
	memcpy((s)->buf, m, (s)->length = (n));         \
	(s)->buf[n] = '\0';                             \
} while (0)

void
St_cpy(String *s, const String *t) {
	CPY(s, t->buf, t->length);
}

void
St_cpy_m(String *s, const void *m, size_t n) {
	CPY(s, m, n);
}

void
St_cpy_s(String *s, const char *tz) {
	size_t length = strlen(tz);

	CPY(s, tz, length);
}

void
St_cpy_c(String *s, int c) {
	unsigned char tmp = c;
	CPY(s, &tmp, 1);
}

static void cat(String *s, const void *m, size_t n) {
	if (s->size - s->offset <= s->length + n) {
		OFFSET_OFF(s);
		if (s->size <= s->length + n) {
			do {
				s->size = s->size / 2 * 3 + 1;
			} while (s->size <= s->length + n);
			s->buf = xrealloc(s->buf, s->size);
		}
	}
	memcpy(s->buf + s->length, m, n);
	s->buf[s->length += n] = '\0';
}

void
St_cat(String *s, const String *t) {
	cat(s, t->buf, t->length);
}

void
St_cat_m(String *s, const void *m, size_t n) {
	cat(s, m, n);
}

void
St_cat_s(String *s, const char *tz) {
	cat(s, tz, strlen(tz));
}

void
St_cat_c(String *s, int c) {
	unsigned char tmp = c;
	cat(s, &tmp, 1);
}

#define TAC(s, m, n)                                                      \
do {                                                                      \
	if ((s)->offset >= (n)) {                                             \
		(s)->buf -= (n);                                                  \
		(s)->offset -= (n);                                               \
	} else if ((s)->size <= (s)->length + (n)) {                          \
		(s)->buf -= (s)->offset;                                          \
		(s)->buf = xrealloc((s)->buf, (s)->length + (n) + 1);             \
		(s)->size = (s)->length + (n) + 1;                                \
		memmove((s)->buf + (n), (s)->buf + (s)->offset, (s)->length + 1); \
		(s)->offset = 0;                                                  \
	} else {                                                              \
		memmove((s)->buf + (n), (s)->buf, (s)->length + 1);               \
	}                                                                     \
	memcpy((s)->buf, m, n);                                               \
	(s)->length += (n);                                                   \
} while (0)

#if 0
void
St_tac(String *s, const String *t) {
	TAC(s, t->buf, t->length);
}
#endif

void
St_tac_m(String *s, const void *m, size_t n) {
	TAC(s, m, n);
}

void
St_tac_s(String *s, const char *tz) {
	size_t length = strlen(tz);

	TAC(s, tz, length);
}

void
St_tac_c(String *s, int c) {
	unsigned char tmp = c;
	TAC(s, &tmp, 1);
}

void
St_reverse(String *s) {
	size_t i;
	char tmp;

	for (i = 0; i < s->length / 2; ++i) {
		tmp = s->buf[i];
		s->buf[i] = s->buf[s->length - i - 1];
		s->buf[s->length - i - 1] = tmp;
	}
}

#if 0
void
St_map(String *s, int (*better)(int)) {
	size_t i;
	int tmp;

	for (i = 0; i < s->length; ++i) {
		tmp = better((unsigned char)s->buf[i]);
		if (tmp == EOF) {
			s->buf[s->length = i] = '\0';
			return;
		}
		s->buf[i] = tmp;
	}

	while ((tmp = better(EOF)) != EOF) {
		if (s->size <= s->length + 1) {
			OFFSET_OFF(s);
			XREALLOC(s->buf, s->size * 2);
			s->size *= 2;
		}
		s->buf[s->length++] = tmp;
		s->buf[s->length] = '\0';
	}
}
#endif

void
St_grep(String *s, int (*good)(int)) {
	size_t r, w;

	for (r = w = 0; r < s->length; ++r) {
		if (good((unsigned char)s->buf[r])) {
			s->buf[w++] = s->buf[r];
		}
	}
	s->buf[s->length = w] = '\0';
}

void
St_upper(String *s) {
	size_t i;

	for (i = 0; i < s->length; ++i) {
		s->buf[i] = toupper((unsigned char)s->buf[i]);
	}
}

void
St_lower(String *s) {
	size_t i;

	for (i = 0; i < s->length; ++i) {
		s->buf[i] = tolower((unsigned char)s->buf[i]);
	}
}

void
St_del(String *s, size_t p, size_t n) {
	if (n == 0 || s->length < p)
		return;
	if (s->length < n || s->length < p + n) {
		n = s->length - p;
	}
	if (p + n == s->length) {
		s->buf[p] = '\0';
	} else if (p == 0) {
		s->offset += n;
		s->buf += n;
	} else {
		memmove(s->buf + p, s->buf + n + p, s->length - p - n);
	}
	s->length -= n;
}

#if 0
#define INS(s, p, m, n)                                                       \
do {                                                                          \
	if ((n) == 0 || (s)->length < (p))                                        \
		return;                                                               \
	if ((n) <= (s)->offset) {                                                 \
		(s)->offset -= (n);                                                   \
		(s)->buf -= (n);                                                      \
		memmove((s)->buf, (s)->buf + (n), p);                                 \
	} else {                                                                  \
		if ((s)->size - (s)->offset <= (s)->length + (n)) {                   \
			OFFSET_OFF(s);                                                    \
			XREALLOC((s)->buf, (s)->length + (n) + 1);                        \
			(s)->size = (s)->length + (n) + 1;                                \
		}                                                                     \
		memmove((s)->buf + (p) + (n), (s)->buf + (p), (s)->length - (p) + 1); \
	}                                                                         \
	memcpy((s)->buf + (p), m, n);                                             \
	(s)->length += (n);                                                       \
} while (0)

void
St_ins(String *s, size_t p, const String *t) {
	INS(s, p, t->buf, t->length);
}

void
St_ins_m(String *s, size_t p, const void *m, size_t n) {
	INS(s, p, m, n);
}

void
St_ins_s(String *s, size_t p, const char *tz) {
	size_t length = strlen(tz);

	INS(s, p, tz, length);
}

void
St_ins_c(String *s, size_t p, int c) {
	unsigned char tmp = c;
	INS(s, p, &tmp, 1);
}
#endif

void
St_substr(String *l, String *s, size_t p, size_t n, const String *r) {
	if (l) {
		if (p >= s->length) {
			St_zero(l);
		} else {
			size_t length = n;

			if (p + length > s->length) {
				length = s->length - p;
			}
			St_cpy_m(l, s->buf + p, length);
		}
	}

	if (r) {
		size_t gap = 0;

		if (p + n > s->length) {
			if (p > s->length) {
				n = 0;
				gap = p - s->length;
			} else {
				n = s->length - p;
			}
		}
		St_grow(s, s->length + r->length - n + gap);
		if (gap) {
			memset(s->buf + s->length, '\0', gap);
		} else if (r->length != n && s->length - p - n) {
			memmove(s->buf + p + r->length, s->buf + p + n, s->length - p - n);
		}
		memcpy(s->buf + p, r->buf, r->length);
		s->buf[s->length += r->length - n + gap] = '\0';
	}
}

#if HAVE_VSNPRINTF_P
size_t
St_xprintf(String *s, const char *fmt, ...) {
	va_list ap;
	int tmp;

	va_start(ap, fmt);
	tmp = vsnprintf(s->buf, s->size, fmt, ap);
	va_end(ap);

	if (tmp < 0) {
		do {
			St_grow(s, s->size * 2);

			va_start(ap, fmt);
			tmp = vsnprintf(s->buf, s->size, fmt, ap);
			va_end(ap);
		} while (tmp < 0);
	} else if (tmp + 1u >= s->size) {
		St_grow(s, tmp);
		s->length = 0;

		va_start(ap, fmt);
		tmp = vsnprintf(s->buf, s->size, fmt, ap);
		va_end(ap);

		if (tmp < 0) {
			s->buf[0] = '\0';
			return -1;
		}
	}

	return s->length = tmp;
}
#endif

void
St_num(String *s, double d) {
	#if HAVE_VSNPRINTF_P
		St_xprintf(s, "%.*g", DBL_DIG, d);
	#else
		St_grow(s, 255);
		s->length = sprintf(s->buf, "%.*g", DBL_DIG, d);
	#endif
}

#if 0
size_t
St_write(const String *s, FILE *fp) {
	return ST_WRITE(s, fp);
}
#endif

#define MIN(a, b) ((a) < (b) ? (a) : (b))

size_t
St_read(String *s, FILE *fp, size_t n) {
	char buf[4096];
	size_t red;

	St_zero(s);
	while (n && !feof(fp) && (red = fread(buf, sizeof *buf, MIN(n, sizeof buf / sizeof *buf), fp))) {
		St_cat_m(s, buf, red);
		n -= red;
	}
	return s->length;
}

#if 0
int
St_getline(String *s, FILE *fp, int n) {
	int c;

	OFFSET_OFF(s);
	for (s->length = 0; (c = getc(fp)) != EOF; ++s->length) {
		if (s->size <= s->length + 1) {
			XREALLOC(s->buf, s->size * 2);
			s->size *= 2;
		}
		s->buf[s->length] = c;
		if (c == n)
			break;
	}
	s->buf[s->length] = '\0';

	return s->length != 0;
}

void
St_getfile(String *s, FILE *fp) {
	size_t tmp;

	OFFSET_OFF(s);
	if (s->size <= BUFSIZ) {
		XREALLOC(s->buf, BUFSIZ + 1);
		s->size = BUFSIZ + 1;
	}

	for (s->length = 0; (tmp = fread(s->buf + s->length, 1, BUFSIZ, fp)); ) {
		s->length += tmp;
		if (s->size <= s->length + BUFSIZ + 1) {
			XREALLOC(s->buf, s->size * 2);
			s->size *= 2;
		}
	}
	s->buf[s->length] = '\0';
}
#endif

size_t
St_hash(const String *s, size_t h) {
	return u_hash(St_ptr(s), St_len(s), h);
}