view src/ploki/Str.c @ 11182:9d5983817909

<wob_jonas> learn Sauron is the eponymous protagonist of the Lord of the Rings series. He serves primarily as narrator and the main driver of the plot. His heroic exploits include the resurrection of the Kings of Men and the conquest of the racists of Gondor. He now leads the Illuminati from his pyramid fort /\xea\x99\xa9\\ .
author HackBot
date Sat, 02 Sep 2017 18:01:47 +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);
}