main shrubtools / nviz / util.c
  1#include <errno.h>
  2#include <stdarg.h>
  3#include <stdlib.h>
  4#include <stdint.h>
  5#include <stdio.h>
  6#include <string.h>
  7#include "util.h"
  8
  9extern const char *argv0;
 10
 11static void
 12vwarn(const char *fmt, va_list ap)
 13{
 14	fprintf(stderr, "%s: ", argv0);
 15	vfprintf(stderr, fmt, ap);
 16	if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
 17		putc(' ', stderr);
 18		perror(NULL);
 19	} else {
 20		putc('\n', stderr);
 21	}
 22}
 23
 24void
 25warn(const char *fmt, ...)
 26{
 27	va_list ap;
 28
 29	va_start(ap, fmt);
 30	vwarn(fmt, ap);
 31	va_end(ap);
 32}
 33
 34void
 35fatal(const char *fmt, ...)
 36{
 37	va_list ap;
 38
 39	va_start(ap, fmt);
 40	vwarn(fmt, ap);
 41	va_end(ap);
 42	exit(1);
 43}
 44
 45void *
 46xmalloc(size_t n)
 47{
 48	void *p;
 49
 50	p = malloc(n);
 51	if (!p)
 52		fatal("malloc:");
 53
 54	return p;
 55}
 56
 57static void *
 58reallocarray_(void *p, size_t n, size_t m)
 59{
 60	if (m && n > SIZE_MAX / m) {
 61		errno = ENOMEM;
 62		return NULL;
 63	}
 64	return realloc(p, n * m);
 65}
 66
 67void *
 68xreallocarray(void *p, size_t n, size_t m)
 69{
 70	p = reallocarray_(p, n, m);
 71	if (!p)
 72		fatal("reallocarray:");
 73
 74	return p;
 75}
 76
 77char *
 78xmemdup(const char *s, size_t n)
 79{
 80	char *p;
 81
 82	p = xmalloc(n);
 83	memcpy(p, s, n);
 84
 85	return p;
 86}
 87
 88int
 89xasprintf(char **s, const char *fmt, ...)
 90{
 91	va_list ap;
 92	int ret;
 93	size_t n;
 94
 95	va_start(ap, fmt);
 96	ret = vsnprintf(NULL, 0, fmt, ap);
 97	va_end(ap);
 98	if (ret < 0)
 99		fatal("vsnprintf:");
100	n = ret + 1;
101	*s = xmalloc(n);
102	va_start(ap, fmt);
103	ret = vsnprintf(*s, n, fmt, ap);
104	va_end(ap);
105	if (ret < 0 || (size_t)ret >= n)
106		fatal("vsnprintf:");
107
108	return ret;
109}
110
111void
112bufadd(struct buffer *buf, char c)
113{
114	if (buf->len >= buf->cap) {
115		buf->cap = buf->cap ? buf->cap * 2 : 1 << 8;
116		buf->data = realloc(buf->data, buf->cap);
117		if (!buf->data)
118			fatal("realloc:");
119	}
120	buf->data[buf->len++] = c;
121}
122
123struct string *
124mkstr(size_t n)
125{
126	struct string *str;
127
128	str = xmalloc(sizeof(*str) + n + 1);
129	str->n = n;
130
131	return str;
132}
133
134void
135delevalstr(void *ptr)
136{
137	struct evalstring *str = ptr, *p;
138
139	while (str) {
140		p = str;
141		str = str->next;
142		if (p->var)
143			free(p->var);
144		else
145			free(p->str);
146		free(p);
147	}
148}
149
150void
151canonpath(struct string *path)
152{
153	char *component[60];
154	int n;
155	char *s, *d, *end;
156
157	if (path->n == 0)
158		fatal("empty path");
159	s = d = path->s;
160	end = path->s + path->n;
161	n = 0;
162	if (*s == '/') {
163		++s;
164		++d;
165	}
166	while (s < end) {
167		switch (s[0]) {
168		case '/':
169			++s;
170			continue;
171		case '.':
172			switch (s[1]) {
173			case '\0': case '/':
174				s += 2;
175				continue;
176			case '.':
177				if (s[2] != '/' && s[2] != '\0')
178					break;
179				if (n > 0) {
180					d = component[--n];
181				} else {
182					*d++ = s[0];
183					*d++ = s[1];
184					*d++ = s[2];
185				}
186				s += 3;
187				continue;
188			}
189		}
190		if (n == countof(component))
191			fatal("path has too many components: %s", path->s);
192		component[n++] = d;
193		while (*s != '/' && *s != '\0')
194			*d++ = *s++;
195		*d++ = *s++;
196	}
197	if (d == path->s) {
198		*d++ = '.';
199		*d = '\0';
200	} else {
201		*--d = '\0';
202	}
203	path->n = d - path->s;
204}
205
206int
207writefile(const char *name, struct string *s)
208{
209	FILE *f;
210	int ret;
211
212	f = fopen(name, "w");
213	if (!f) {
214		warn("open %s:", name);
215		return -1;
216	}
217	ret = 0;
218	if (s && (fwrite(s->s, 1, s->n, f) != s->n || fflush(f) != 0)) {
219		warn("write %s:", name);
220		ret = -1;
221	}
222	fclose(f);
223
224	return ret;
225}