shithub: mc

ref: 100ed8406343f027aa442e79fe59c653c8fc02a4
dir: /util/util.c/

View raw version
#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#include "util.h"

/* malloc wrappers */
void *zalloc(size_t sz)
{
	void *mem;

	mem = calloc(1, sz);
	if (!mem && sz)
		die("Out of memory");
	return mem;
}

void *xalloc(size_t sz)
{
	void *mem;

	mem = malloc(sz);
	if (!mem && sz)
		die("Out of memory");
	return mem;
}

void *zrealloc(void *mem, size_t oldsz, size_t sz)
{
	char *p;

	p = xrealloc(mem, sz);
	if (sz > oldsz)
		memset(&p[oldsz], 0, sz - oldsz);
	return p;
}

void *xrealloc(void *mem, size_t sz)
{
	mem = realloc(mem, sz);
	if (!mem && sz)
		die("Out of memory");
	return mem;
}


/* Some systems don't have strndup. */
char *strdupn(char *s, size_t len)
{
	char *ret;

	ret = xalloc(len + 1);
	memcpy(ret, s, len);
	ret[len] = '\0';
	return ret;
}

char *strjoin(char *u, char *v)
{
	size_t n;
	char *s;

	n = strlen(u) + strlen(v) + 1;
	s = xalloc(n);
	bprintf(s, n + 1, "%s%s", u, v);
	return s;
}

void *memdup(void *mem, size_t len)
{
	void *ret;

        if (!mem)
            return NULL;
	ret = xalloc(len);
	return memcpy(ret, mem, len);
}

/* lists */
void lappend(void *l, size_t *len, void *n)
{
	void ***pl;

	pl = l;
	*pl = xrealloc(*pl, (*len + 1) * sizeof(void *));
	(*pl)[*len] = n;
	(*len)++;
}

void *lpop(void *l, size_t *len)
{
	void ***pl;
	void *v;

	pl = l;
	(*len)--;
	v = (*pl)[*len];
	*pl = xrealloc(*pl, *len * sizeof(void *));
	return v;
}

void linsert(void *p, size_t *len, size_t idx, void *v)
{
	void ***pl, **l;

	pl = p;
	*pl = xrealloc(*pl, (*len + 1) * sizeof(void *));
	l = *pl;

	memmove(&l[idx + 1], &l[idx], (*len - idx) * sizeof(void *));
	l[idx] = v;
	(*len)++;
}

void ldel(void *p, size_t *len, size_t idx)
{
	void ***pl, **l;

	assert(p != NULL);
	assert(idx < *len);
	pl = p;
	l = *pl;
	memmove(&l[idx], &l[idx + 1], (*len - idx - 1) * sizeof(void *));
	(*len)--;
	*pl = xrealloc(l, *len * sizeof(void *));
}

void lcat(void *dst, size_t *ndst, void *src, size_t nsrc)
{
	size_t i;
	void ***d, **s;

	d = dst;
	s = src;
	for (i = 0; i < nsrc; i++)
		lappend(d, ndst, s[i]);
}

void lfree(void *l, size_t *len)
{
	void ***pl;

	assert(l != NULL);
	pl = l;
	free(*pl);
	*pl = NULL;
	*len = 0;
}

/* endian packing */
void be64(vlong v, byte buf[8])
{
	buf[0] = (v >> 56) & 0xff;
	buf[1] = (v >> 48) & 0xff;
	buf[2] = (v >> 40) & 0xff;
	buf[3] = (v >> 32) & 0xff;
	buf[4] = (v >> 24) & 0xff;
	buf[5] = (v >> 16) & 0xff;
	buf[6] = (v >> 8) & 0xff;
	buf[7] = (v >> 0) & 0xff;
}

vlong host64(byte buf[8])
{
	vlong v = 0;

	v |= ((vlong)buf[0] << 56LL);
	v |= ((vlong)buf[1] << 48LL);
	v |= ((vlong)buf[2] << 40LL);
	v |= ((vlong)buf[3] << 32LL);
	v |= ((vlong)buf[4] << 24LL);
	v |= ((vlong)buf[5] << 16LL);
	v |= ((vlong)buf[6] << 8LL);
	v |= ((vlong)buf[7] << 0LL);
	return v;
}

void be32(long v, byte buf[4])
{
	buf[0] = (v >> 24) & 0xff;
	buf[1] = (v >> 16) & 0xff;
	buf[2] = (v >> 8) & 0xff;
	buf[3] = (v >> 0) & 0xff;
}

long host32(byte buf[4])
{
	int32_t v = 0;
	v |= ((long)buf[0] << 24);
	v |= ((long)buf[1] << 16);
	v |= ((long)buf[2] << 8);
	v |= ((long)buf[3] << 0);
	return v;
}

void wrbuf(FILE *fd, void *p, size_t sz)
{
	size_t n;
	char *buf;

	n = 0;
	buf = p;
	while (n < sz) {
		n += fwrite(buf + n, 1, sz - n, fd);
		if (feof(fd))
			die("Unexpected EOF");
		if (ferror(fd))
			die("Error writing");
	}
}

void rdbuf(FILE *fd, void *buf, size_t sz)
{
	size_t n;

	n = sz;
	while (n > 0) {
		n -= fread(buf, 1, n, fd);
		if (feof(fd))
			die("Unexpected EOF");
		if (ferror(fd))
			die("Error writing");
	}
}

void wrbyte(FILE *fd, char val)
{
	if (fputc(val, fd) == EOF)
		die("Unexpected EOF");
}

char rdbyte(FILE *fd)
{
	int c;
	c = fgetc(fd);
	if (c == EOF)
		die("Unexpected EOF");
	return c;
}

void wrint(FILE *fd, long val)
{
	byte buf[4];
	be32(val, buf);
	wrbuf(fd, buf, 4);
}

long rdint(FILE *fd)
{
	byte buf[4];
	rdbuf(fd, buf, 4);
	return host32(buf);
}

void wrstr(FILE *fd, char *val)
{
	size_t len;

	if (!val) {
		wrint(fd, -1);
	} else {
		wrint(fd, strlen(val));
		len = strlen(val);
		wrbuf(fd, val, len);
	}
}

char *rdstr(FILE *fd)
{
	ssize_t len;
	char *s;

	len = rdint(fd);
	if (len == -1) {
		return NULL;
	} else {
		s = xalloc(len + 1);
		rdbuf(fd, s, len);
		s[len] = '\0';
		return s;
	}
}

void wrlenstr(FILE *fd, Str str)
{
	wrint(fd, str.len);
	wrbuf(fd, str.buf, str.len);
}

void rdlenstr(FILE *fd, Str *str)
{
	str->len = rdint(fd);
	str->buf = xalloc(str->len + 1);
	rdbuf(fd, str->buf, str->len);
	str->buf[str->len] = '\0';
}

void wrflt(FILE *fd, double val)
{
	byte buf[8];
	/* Assumption: We have 'val' in 64 bit IEEE format */
	union {
		uvlong ival;
		double fval;
	} u;

	u.fval = val;
	be64(u.ival, buf);
	wrbuf(fd, buf, 8);
}

double rdflt(FILE *fd)
{
	byte buf[8];
	union {
		uvlong ival;
		double fval;
	} u;

	if (fread(buf, 8, 1, fd) < 8)
		die("Unexpected EOF");
	u.ival = host64(buf);
	return u.fval;
}

size_t bprintf(char *buf, size_t sz, char *fmt, ...)
{
	va_list ap;
	size_t n;

	va_start(ap, fmt);
	n = vsnprintf(buf, sz, fmt, ap);
	if (n >= sz)
		n = sz;
	va_end(ap);

	return n;
}

void wrbool(FILE *fd, int val) { wrbyte(fd, val); }

int rdbool(FILE *fd) { return rdbyte(fd); }

char *swapsuffix(char *buf, size_t sz, char *s, char *suf, char *swap)
{
	size_t slen, suflen, swaplen;

	slen = strlen(s);
	suflen = strlen(suf);
	swaplen = strlen(swap);

	if (slen < suflen)
		return NULL;
	if (slen + swaplen >= sz)
		die("swapsuffix: buf too small");

	buf[0] = '\0';
	/* if we have matching suffixes */
	if (suflen < slen && !strcmp(suf, &s[slen - suflen])) {
		strncat(buf, s, slen - suflen);
		strncat(buf, swap, swaplen);
	} else {
		bprintf(buf, sz, "%s%s", s, swap);
	}

	return buf;
}

size_t max(size_t a, size_t b)
{
	if (a > b)
		return a;
	else
		return b;
}

size_t min(size_t a, size_t b)
{
	if (a < b)
		return a;
	else
		return b;
}

size_t align(size_t sz, size_t a)
{
	/* align to 0 just returns sz */
	if (a == 0)
		return sz;
	return (sz + a - 1) & ~(a - 1);
}

void indentf(int depth, char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vfindentf(stdout, depth, fmt, ap);
	va_end(ap);
}

void findentf(FILE *fd, int depth, char *fmt, ...)
{
	va_list ap;
	va_start(ap, fmt);
	vfindentf(fd, depth, fmt, ap);
	va_end(ap);
}

void vfindentf(FILE *fd, int depth, char *fmt, va_list ap)
{
	ssize_t i;

	for (i = 0; i < depth; i++)
		fprintf(fd, "\t");
	vfprintf(fd, fmt, ap);
}

static int optinfo(Optctx *ctx, char arg, int *take, int *mand)
{
	char *s;

	for (s = ctx->optstr; *s != '\0'; s++) {
		if (*s == arg) {
			s++;
			if (*s == ':') {
				*take = 1;
				*mand = 1;
				return 1;
			} else if (*s == '?') {
				*take = 1;
				*mand = 0;
				return 1;
			} else {
				*take = 0;
				*mand = 0;
				return 1;
			}
		}
	}
	return 0;
}

static int findnextopt(Optctx *ctx)
{
	size_t i;

	for (i = ctx->argidx + 1; i < ctx->noptargs; i++) {
		if (ctx->optargs[i][0] == '-')
			goto foundopt;
		else
			lappend(&ctx->args, &ctx->nargs, ctx->optargs[i]);
	}
	ctx->finished = 1;
	return 0;
foundopt:
	ctx->argidx = i;
	ctx->curarg = ctx->optargs[i] + 1; /* skip initial '-' */
	return 1;
}

void optinit(Optctx *ctx, char *optstr, char **optargs, size_t noptargs)
{
	ctx->args = NULL;
	ctx->nargs = 0;

	ctx->optstr = optstr;
	ctx->optargs = optargs;
	ctx->noptargs = noptargs;
	ctx->optdone = 0;
	ctx->finished = 0;
	ctx->argidx = 0;
	ctx->curarg = "";
	findnextopt(ctx);
}

int optnext(Optctx *ctx)
{
	int take, mand;
	int c;

	c = *ctx->curarg;
	ctx->curarg++;
	if (!optinfo(ctx, c, &take, &mand)) {
		printf("Unexpected argument %c\n", *ctx->curarg);
		exit(1);
	}

	ctx->optarg = NULL;
	if (take) {
		if (*ctx->curarg) {
			ctx->optarg = ctx->curarg;
			ctx->curarg += strlen(ctx->optarg);
		} else if (ctx->argidx < ctx->noptargs - 1) {
			ctx->optarg = ctx->optargs[ctx->argidx + 1];
			ctx->argidx++;
		} else if (mand) {
			fprintf(stderr, "expected argument for %c\n", *ctx->curarg);
		}
		findnextopt(ctx);
	} else {
		if (*ctx->curarg == '\0')
			findnextopt(ctx);
	}
	return c;
}

int optdone(Optctx *ctx) { return *ctx->curarg == '\0' && ctx->finished; }