Xinqi Bao's Git

Refactor keymap.c
[slstatus.git] / util.c
1 /* See LICENSE file for copyright and license details. */
2 #include <errno.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7
8 #include "util.h"
9
10 char *argv0;
11
12 static void
13 verr(const char *fmt, va_list ap)
14 {
15 if (argv0 && strncmp(fmt, "usage", sizeof("usage") - 1)) {
16 fprintf(stderr, "%s: ", argv0);
17 }
18
19 vfprintf(stderr, fmt, ap);
20
21 if (fmt[0] && fmt[strlen(fmt) - 1] == ':') {
22 fputc(' ', stderr);
23 perror(NULL);
24 } else {
25 fputc('\n', stderr);
26 }
27 }
28
29 void
30 warn(const char *fmt, ...)
31 {
32 va_list ap;
33
34 va_start(ap, fmt);
35 verr(fmt, ap);
36 va_end(ap);
37 }
38
39 void
40 die(const char *fmt, ...)
41 {
42 va_list ap;
43
44 va_start(ap, fmt);
45 verr(fmt, ap);
46 va_end(ap);
47
48 exit(1);
49 }
50
51 static int
52 evsnprintf(char *str, size_t size, const char *fmt, va_list ap)
53 {
54 int ret;
55
56 ret = vsnprintf(str, size, fmt, ap);
57
58 if (ret < 0) {
59 warn("vsnprintf:");
60 return -1;
61 } else if ((size_t)ret >= size) {
62 warn("vsnprintf: Output truncated");
63 return -1;
64 }
65
66 return ret;
67 }
68
69 int
70 esnprintf(char *str, size_t size, const char *fmt, ...)
71 {
72 va_list ap;
73 int ret;
74
75 va_start(ap, fmt);
76 ret = evsnprintf(str, size, fmt, ap);
77 va_end(ap);
78
79 return ret;
80 }
81
82 const char *
83 bprintf(const char *fmt, ...)
84 {
85 va_list ap;
86 int ret;
87
88 va_start(ap, fmt);
89 ret = evsnprintf(buf, sizeof(buf), fmt, ap);
90 va_end(ap);
91
92 return (ret < 0) ? NULL : buf;
93 }
94
95 const char *
96 fmt_human(size_t num, int base)
97 {
98 double scaled;
99 size_t i, prefixlen;
100 const char **prefix;
101 const char *prefix_1000[] = { "", "k", "M", "G", "T", "P", "E", "Z", "Y" };
102 const char *prefix_1024[] = { "", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei",
103 "Zi", "Yi" };
104
105 switch (base) {
106 case 1000:
107 prefix = prefix_1000;
108 prefixlen = LEN(prefix_1000);
109 break;
110 case 1024:
111 prefix = prefix_1024;
112 prefixlen = LEN(prefix_1024);
113 break;
114 default:
115 warn("fmt_human: Invalid base");
116 return NULL;
117 }
118
119 scaled = num;
120 for (i = 0; i < prefixlen && scaled >= base; i++) {
121 scaled /= base;
122 }
123
124 return bprintf("%.1f%s", scaled, prefix[i]);
125 }
126
127 int
128 pscanf(const char *path, const char *fmt, ...)
129 {
130 FILE *fp;
131 va_list ap;
132 int n;
133
134 if (!(fp = fopen(path, "r"))) {
135 warn("fopen '%s':", path);
136 return -1;
137 }
138 va_start(ap, fmt);
139 n = vfscanf(fp, fmt, ap);
140 va_end(ap);
141 fclose(fp);
142
143 return (n == EOF) ? -1 : n;
144 }