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}