Xinqi Bao's Git

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