1
|
|
/*
|
2
|
|
* The MIT License (MIT)
|
3
|
|
*
|
4
|
|
* Copyright (c) 2019 Erik Moqvist
|
5
|
|
*
|
6
|
|
* Permission is hereby granted, free of charge, to any person
|
7
|
|
* obtaining a copy of this software and associated documentation
|
8
|
|
* files (the "Software"), to deal in the Software without
|
9
|
|
* restriction, including without limitation the rights to use, copy,
|
10
|
|
* modify, merge, publish, distribute, sublicense, and/or sell copies
|
11
|
|
* of the Software, and to permit persons to whom the Software is
|
12
|
|
* furnished to do so, subject to the following conditions:
|
13
|
|
*
|
14
|
|
* The above copyright notice and this permission notice shall be
|
15
|
|
* included in all copies or substantial portions of the Software.
|
16
|
|
*
|
17
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
18
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
19
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
20
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
21
|
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
22
|
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
23
|
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
24
|
|
* SOFTWARE.
|
25
|
|
*
|
26
|
|
* This file is part of the humanfriendly project.
|
27
|
|
*/
|
28
|
|
|
29
|
|
#include <stdlib.h>
|
30
|
|
#include <string.h>
|
31
|
|
#include <stdbool.h>
|
32
|
|
#include <stdio.h>
|
33
|
|
#include <errno.h>
|
34
|
|
#include <limits.h>
|
35
|
|
#include <pwd.h>
|
36
|
|
#include "hf.h"
|
37
|
|
|
38
|
|
#define TIME_UNITS_MAX 7
|
39
|
|
|
40
|
1
|
static void hf_null_last(char *buf_p, size_t size)
|
41
|
|
{
|
42
|
1
|
buf_p[size - 1] = '\0';
|
43
|
|
}
|
44
|
|
|
45
|
0
|
static int char_in_string(char c, const char *str_p)
|
46
|
|
{
|
47
|
0
|
while (*str_p != '\0') {
|
48
|
0
|
if (c == *str_p) {
|
49
|
0
|
return (1);
|
50
|
|
}
|
51
|
|
|
52
|
0
|
str_p++;
|
53
|
|
}
|
54
|
|
|
55
|
0
|
return (0);
|
56
|
|
}
|
57
|
|
|
58
|
1
|
char *hf_get_username(char *buf_p, size_t size, const char *default_p)
|
59
|
|
{
|
60
|
|
char *res_p;
|
61
|
|
struct passwd *passwd_p;
|
62
|
|
|
63
|
1
|
res_p = buf_p;
|
64
|
1
|
passwd_p = getpwuid(geteuid());
|
65
|
|
|
66
|
1
|
if (passwd_p == NULL) {
|
67
|
1
|
if (default_p == NULL) {
|
68
|
1
|
res_p = NULL;
|
69
|
|
} else {
|
70
|
1
|
strncpy(buf_p, default_p, size);
|
71
|
|
}
|
72
|
|
} else {
|
73
|
1
|
strncpy(buf_p, passwd_p->pw_name, size);
|
74
|
|
|
75
|
1
|
if (size > 0) {
|
76
|
1
|
hf_null_last(buf_p, size);
|
77
|
|
}
|
78
|
|
}
|
79
|
|
|
80
|
1
|
hf_null_last(buf_p, size);
|
81
|
|
|
82
|
1
|
return (res_p);
|
83
|
|
}
|
84
|
|
|
85
|
1
|
char *hf_get_hostname(char *buf_p, size_t size, const char *default_p)
|
86
|
|
{
|
87
|
|
int res;
|
88
|
|
char *res_p;
|
89
|
|
|
90
|
1
|
res_p = buf_p;
|
91
|
1
|
res = gethostname(buf_p, size);
|
92
|
|
|
93
|
1
|
if (res != 0) {
|
94
|
1
|
if (default_p == NULL) {
|
95
|
1
|
res_p = NULL;
|
96
|
|
} else {
|
97
|
1
|
strncpy(buf_p, default_p, size);
|
98
|
|
}
|
99
|
|
}
|
100
|
|
|
101
|
1
|
hf_null_last(buf_p, size);
|
102
|
|
|
103
|
1
|
return (res_p);
|
104
|
|
}
|
105
|
|
|
106
|
|
/* Common time units, used for formatting of time spans. */
|
107
|
|
struct time_unit_t {
|
108
|
|
unsigned long divider;
|
109
|
|
const char *unit_p;
|
110
|
|
};
|
111
|
|
|
112
|
|
static struct time_unit_t time_units[TIME_UNITS_MAX] = {
|
113
|
|
{
|
114
|
|
.divider = 60 * 60 * 24 * 7 * 52 * 1000ul,
|
115
|
|
.unit_p = "y"
|
116
|
|
},
|
117
|
|
{
|
118
|
|
.divider = 60 * 60 * 24 * 7 * 1000ul,
|
119
|
|
.unit_p = "w"
|
120
|
|
},
|
121
|
|
{
|
122
|
|
.divider = 60 * 60 * 24 * 1000ul,
|
123
|
|
.unit_p = "d"
|
124
|
|
},
|
125
|
|
{
|
126
|
|
.divider = 60 * 60 * 1000ul,
|
127
|
|
.unit_p = "h"
|
128
|
|
},
|
129
|
|
{
|
130
|
|
.divider = 60 * 1000ul,
|
131
|
|
.unit_p = "m"
|
132
|
|
},
|
133
|
|
{
|
134
|
|
.divider = 1000ul,
|
135
|
|
.unit_p = "s"
|
136
|
|
},
|
137
|
|
{
|
138
|
|
.divider = 1ul,
|
139
|
|
.unit_p = "ms"
|
140
|
|
}
|
141
|
|
};
|
142
|
|
|
143
|
1
|
static const char *get_delimiter(bool is_first, bool is_last)
|
144
|
|
{
|
145
|
1
|
if (is_first) {
|
146
|
1
|
return ("");
|
147
|
1
|
} else if (is_last) {
|
148
|
1
|
return (" and ");
|
149
|
|
} else {
|
150
|
1
|
return (", ");
|
151
|
|
}
|
152
|
|
}
|
153
|
|
|
154
|
1
|
char *hf_format_timespan(char *buf_p,
|
155
|
|
size_t size,
|
156
|
|
unsigned long long timespan_ms)
|
157
|
|
{
|
158
|
|
int i;
|
159
|
|
int res;
|
160
|
|
unsigned long long count;
|
161
|
|
size_t offset;
|
162
|
|
|
163
|
1
|
strncpy(buf_p, "", size);
|
164
|
1
|
offset = 0;
|
165
|
|
|
166
|
1
|
for (i = 0; i < TIME_UNITS_MAX; i++) {
|
167
|
1
|
count = (timespan_ms / time_units[i].divider);
|
168
|
1
|
timespan_ms -= (count * time_units[i].divider);
|
169
|
|
|
170
|
1
|
if (count == 0) {
|
171
|
1
|
continue;
|
172
|
|
}
|
173
|
|
|
174
|
1
|
res = snprintf(&buf_p[offset],
|
175
|
|
size - offset,
|
176
|
|
"%s%llu%s",
|
177
|
1
|
get_delimiter(strlen(buf_p) == 0, timespan_ms == 0),
|
178
|
|
count,
|
179
|
|
time_units[i].unit_p);
|
180
|
1
|
hf_null_last(buf_p, size);
|
181
|
|
|
182
|
1
|
if (res > 0) {
|
183
|
1
|
offset += (size_t)res;
|
184
|
|
}
|
185
|
|
}
|
186
|
|
|
187
|
1
|
if (strlen(buf_p) == 0) {
|
188
|
1
|
strncpy(buf_p, "0s", size);
|
189
|
1
|
hf_null_last(buf_p, size);
|
190
|
|
}
|
191
|
|
|
192
|
1
|
return (buf_p);
|
193
|
|
}
|
194
|
|
|
195
|
1
|
long hf_string_to_long(const char *string_p,
|
196
|
|
long minimum,
|
197
|
|
long maximum,
|
198
|
|
long default_value,
|
199
|
|
int base)
|
200
|
|
{
|
201
|
|
long value;
|
202
|
|
char *end_p;
|
203
|
|
|
204
|
1
|
errno = 0;
|
205
|
1
|
value = strtol(string_p, &end_p, base);
|
206
|
|
|
207
|
1
|
if ((errno != 0) && (value == 0)) {
|
208
|
0
|
value = default_value;
|
209
|
1
|
} else if (end_p == string_p) {
|
210
|
1
|
value = default_value;
|
211
|
1
|
} else if (*end_p != '\0') {
|
212
|
1
|
value = default_value;
|
213
|
|
}
|
214
|
|
|
215
|
1
|
if (value < minimum) {
|
216
|
1
|
value = minimum;
|
217
|
|
}
|
218
|
|
|
219
|
1
|
if (value > maximum) {
|
220
|
1
|
value = maximum;
|
221
|
|
}
|
222
|
|
|
223
|
1
|
return (value);
|
224
|
|
}
|
225
|
|
|
226
|
1
|
char *hf_buffer_to_string(char *dst_p,
|
227
|
|
size_t dst_size,
|
228
|
|
const void *src_p,
|
229
|
|
size_t src_size)
|
230
|
|
{
|
231
|
1
|
if (src_size > 0) {
|
232
|
1
|
if (src_size > (dst_size - 1)) {
|
233
|
1
|
src_size = (dst_size - 1);
|
234
|
|
}
|
235
|
|
|
236
|
1
|
memcpy(dst_p, src_p, src_size);
|
237
|
|
}
|
238
|
|
|
239
|
1
|
dst_p[src_size] = '\0';
|
240
|
|
|
241
|
1
|
return (dst_p);
|
242
|
|
}
|
243
|
|
|
244
|
0
|
char *hf_strip(char *str_p, const char *strip_p)
|
245
|
|
{
|
246
|
|
char *begin_p;
|
247
|
|
size_t length;
|
248
|
|
|
249
|
|
/* Strip whitespace characters by default. */
|
250
|
0
|
if (strip_p == NULL) {
|
251
|
0
|
strip_p = "\t\n\x0b\x0c\r ";
|
252
|
|
}
|
253
|
|
|
254
|
|
/* String leading characters. */
|
255
|
0
|
while ((*str_p != '\0') && char_in_string(*str_p, strip_p)) {
|
256
|
0
|
str_p++;
|
257
|
|
}
|
258
|
|
|
259
|
0
|
begin_p = str_p;
|
260
|
|
|
261
|
|
/* Strip training characters. */
|
262
|
0
|
length = strlen(str_p);
|
263
|
0
|
str_p += (length - 1);
|
264
|
|
|
265
|
0
|
while ((str_p >= begin_p) && char_in_string(*str_p, strip_p)) {
|
266
|
0
|
*str_p = '\0';
|
267
|
0
|
str_p--;
|
268
|
|
}
|
269
|
|
|
270
|
0
|
return (begin_p);
|
271
|
|
}
|
272
|
|
|
273
|
1
|
void *hf_file_read_all(const char *path_p, size_t *size_p)
|
274
|
|
{
|
275
|
|
FILE *file_p;
|
276
|
|
void *buf_p;
|
277
|
|
long file_size;
|
278
|
|
|
279
|
1
|
file_p = fopen(path_p, "rb");
|
280
|
|
|
281
|
1
|
if (file_p == NULL) {
|
282
|
1
|
return (NULL);
|
283
|
|
}
|
284
|
|
|
285
|
1
|
if (fseek(file_p, 0, SEEK_END) != 0) {
|
286
|
0
|
goto out1;
|
287
|
|
}
|
288
|
|
|
289
|
1
|
file_size = ftell(file_p);
|
290
|
|
|
291
|
1
|
if (file_size == -1) {
|
292
|
0
|
goto out1;
|
293
|
|
}
|
294
|
|
|
295
|
1
|
if (size_p != NULL) {
|
296
|
1
|
*size_p = (size_t)file_size;
|
297
|
|
}
|
298
|
|
|
299
|
1
|
if (file_size > 0) {
|
300
|
1
|
buf_p = malloc((size_t)file_size);
|
301
|
|
|
302
|
1
|
if (buf_p == NULL) {
|
303
|
0
|
goto out1;
|
304
|
|
}
|
305
|
|
|
306
|
1
|
if (fseek(file_p, 0, SEEK_SET) != 0) {
|
307
|
0
|
goto out2;
|
308
|
|
}
|
309
|
|
|
310
|
1
|
if (fread(buf_p, (size_t)file_size, 1, file_p) != 1) {
|
311
|
1
|
goto out2;
|
312
|
|
}
|
313
|
|
} else {
|
314
|
1
|
buf_p = malloc(1);
|
315
|
|
}
|
316
|
|
|
317
|
1
|
fclose(file_p);
|
318
|
|
|
319
|
1
|
return (buf_p);
|
320
|
|
|
321
|
|
out2:
|
322
|
1
|
free(buf_p);
|
323
|
|
|
324
|
|
out1:
|
325
|
1
|
fclose(file_p);
|
326
|
|
|
327
|
1
|
return (NULL);
|
328
|
|
}
|