aboutsummaryrefslogtreecommitdiffstats
path: root/src/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/util.c')
-rw-r--r--src/util.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/src/util.c b/src/util.c
new file mode 100644
index 0000000..2ae3a9f
--- /dev/null
+++ b/src/util.c
@@ -0,0 +1,171 @@
+/* See LICENSE file for copyright and license details. */
+#include "util.h"
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+
+char *argv0;
+
+static void
+xvprintf(const char *fmt, va_list ap)
+{
+ if (argv0 && strncmp(fmt, "usage", strlen("usage")))
+ fprintf(stderr, "%s: ", argv0);
+
+ vfprintf(stderr, fmt, ap);
+
+ if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
+ fputc(' ', stderr);
+ perror(NULL);
+ }
+}
+
+void
+eprintf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xvprintf(fmt, ap);
+ va_end(ap);
+
+ exit(1);
+}
+
+void
+enprintf(int status, const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xvprintf(fmt, ap);
+ va_end(ap);
+
+ exit(status);
+}
+
+void
+weprintf(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ xvprintf(fmt, ap);
+ va_end(ap);
+}
+
+
+int
+tollu(const char *s, unsigned long long int min, unsigned long long int max, unsigned long long int *out)
+{
+ char *end;
+ errno = 0;
+ if (*s == '-') {
+ errno = ERANGE;
+ return -1;
+ }
+ if (tolower(*s) == 'x' || *s == '#')
+ *out = strtoull(s + 1, &end, 16);
+ else if (*s == '0' && tolower(s[1]) == 'x')
+ *out = strtoull(s + 2, &end, 16);
+ else if (*s == '0' && tolower(s[1]) == 'o')
+ *out = strtoull(s + 2, &end, 8);
+ else if (*s == '0' && tolower(s[1]) == 'b')
+ *out = strtoull(s + 2, &end, 2);
+ else
+ *out = strtoull(s, &end, 10);
+ if (errno)
+ return -1;
+ if (*end) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (*out < min || *out > max) {
+ errno = ERANGE;
+ return -1;
+ }
+ return 0;
+}
+
+int
+tolli(const char *s, long long int min, long long int max, long long int *out)
+{
+ char *end;
+ int sign = 1;
+ unsigned long long int inter;
+ errno = 0;
+ if (*s == '-') {
+ s++;
+ sign = -1;
+ }
+ if (tollu(s, 0, ULLONG_MAX, &inter))
+ return -1;
+ if (sign > 0) {
+ if (max < 0 || inter > (unsigned long long int)max)
+ goto erange;
+ *out = (long long int)inter;
+ if (*out < min)
+ goto erange;
+ } else {
+#if LLONG_MIN == -LLONG_MAX
+ if (inter > -LLONG_MIN)
+ goto erange;
+#else
+ if (inter > (unsigned long long int)LLONG_MAX + 1ULL)
+ goto erange;
+#endif
+ *out = -(long long int)inter;
+ if (*out < min || *out > max)
+ goto erange;
+ }
+ return 0;
+
+erange:
+ errno = ERANGE;
+ return -1;
+}
+
+
+int
+fshut(FILE *fp, const char *fname)
+{
+ int ret = 0;
+
+ /* fflush() is undefined for input streams by ISO C,
+ * but not POSIX 2008 if you ignore ISO C overrides.
+ * Leave it unchecked and rely on the following
+ * functions to detect errors.
+ */
+ fflush(fp);
+
+ if (ferror(fp) && !ret) {
+ weprintf("ferror %s:", fname);
+ ret = 1;
+ }
+
+ if (fclose(fp) && !ret) {
+ weprintf("fclose %s:", fname);
+ ret = 1;
+ }
+
+ return ret;
+}
+
+void
+enfshut(int status, FILE *fp, const char *fname)
+{
+ if (fshut(fp, fname))
+ exit(status);
+}
+
+void
+efshut(FILE *fp, const char *fname)
+{
+ enfshut(1, fp, fname);
+}