1 /*****************************************************************************
2 * Written by Chris Dunlap <cdunlap@llnl.gov>.
3 * Copyright (C) 2007-2018 Lawrence Livermore National Security, LLC.
4 * Copyright (C) 2001-2007 The Regents of the University of California.
5 * UCRL-CODE-2002-009.
6 *
7 * This file is part of ConMan: The Console Manager.
8 * For details, see <https://dun.github.io/conman/>.
9 *
10 * ConMan is free software: you can redistribute it and/or modify it under
11 * the terms of the GNU General Public License as published by the Free
12 * Software Foundation, either version 3 of the License, or (at your option)
13 * any later version.
14 *
15 * ConMan is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * for more details.
19 *
20 * You should have received a copy of the GNU General Public License along
21 * with ConMan. If not, see <http://www.gnu.org/licenses/>.
22 *****************************************************************************
23 * Refer to "util-str.h" for documentation on public functions.
24 *****************************************************************************/
25
26
27 #if HAVE_CONFIG_H
28 # include <config.h>
29 #endif /* HAVE_CONFIG_H */
30
31 #include <assert.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <pthread.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <time.h>
40 #include "log.h"
41 #include "util-str.h"
42 #include "util.h"
43 #include "wrapper.h"
44
45
46 #define MAX_STR_SIZE 1024
47
48
create_string(const char * str)49 char * create_string(const char *str)
50 {
51 char *p;
52
53 if (!str) {
54 return(NULL);
55 }
56 if (!(p = strdup(str))) {
57 out_of_memory();
58 }
59 return(p);
60 }
61
62
create_format_string(const char * fmt,...)63 char * create_format_string(const char *fmt, ...)
64 {
65 char buf[MAX_STR_SIZE];
66 va_list vargs;
67 char *p;
68
69 if (!fmt) {
70 return(NULL);
71 }
72 va_start(vargs, fmt);
73 vsnprintf(buf, sizeof(buf), fmt, vargs);
74 va_end(vargs);
75
76 buf[sizeof(buf) - 1] = '\0'; /* ensure buf is NUL-terminated */
77
78 if (!(p = strdup(buf))) {
79 out_of_memory();
80 }
81 return(p);
82 }
83
84
replace_string(char ** dst,const char * src)85 int replace_string(char **dst, const char *src)
86 {
87 if (!dst) {
88 return(-1);
89 }
90 if (*dst) {
91 free(*dst);
92 }
93 if (!(*dst = strdup(src))) {
94 out_of_memory();
95 }
96 return(0);
97 }
98
99
destroy_string(char * str)100 void destroy_string(char *str)
101 {
102 if (str) {
103 free(str);
104 }
105 return;
106 }
107
108
is_empty_string(const char * str)109 int is_empty_string(const char *str)
110 {
111 if (!str) {
112 return(-1);
113 }
114 for (; *str; str++) {
115 if (!isspace((int) *str)) {
116 return(0);
117 }
118 }
119 return(1);
120 }
121
122
parse_string(char * src,char ** dst_p,char ** ptr_p,char * quote_p)123 int parse_string(char *src, char **dst_p, char **ptr_p, char *quote_p)
124 {
125 char *p;
126 char *q;
127 char c = 0;
128
129 if (!dst_p) {
130 errno = EINVAL;
131 return(-1);
132 }
133 if (!src || !ptr_p) {
134 *dst_p = NULL;
135 errno = EINVAL;
136 return(-1);
137 }
138 if (*ptr_p == NULL) {
139 *ptr_p = src;
140 }
141 for (p = *ptr_p; *p && isspace((int) *p); p++) {
142 ;
143 }
144 if (*p == '\0') {
145 *dst_p = *ptr_p = p;
146 return(0);
147 }
148 for (q = p+1; *q; q++) {
149 if ((*p == '"') || (*p == '\'')) {
150 if ((*q == *p) && (isspace((int) *(q+1)) || (*(q+1) == '\0'))) {
151 c = *p++;
152 *q++ = '\0';
153 break;
154 }
155 else if (*(q+1) == '\0') {
156 errno = EIO;
157 *dst_p = p;
158 *ptr_p = q + 1;
159 return(-1);
160 }
161 }
162 else if (isspace((int) *q)) {
163 *q++ = '\0';
164 break;
165 }
166 }
167 *dst_p = p;
168 *ptr_p = q;
169 if (quote_p) {
170 *quote_p = c;
171 }
172 return(1);
173 }
174
175
append_format_string(char * dst,size_t size,const char * fmt,...)176 int append_format_string(char *dst, size_t size, const char *fmt, ...)
177 {
178 char *p;
179 size_t num_left;
180 size_t num_orig;
181 va_list vargs;
182 int n;
183
184 if ((dst == NULL) || (fmt == NULL)) {
185 errno = EINVAL;
186 return(-1);
187 }
188 if (size == 0) {
189 return(0);
190 }
191 p = dst;
192 num_left = size;
193 while ((*p != '\0') && (num_left > 0)) {
194 p++;
195 num_left--;
196 }
197 /* If (num_left == 0), dst[] is full but requires null-termination.
198 * If (num_left == 1), dst[] is full but is already null-terminated.
199 */
200 if (num_left <= 1) {
201 dst[size - 1] = '\0';
202 return(-1);
203 }
204 num_orig = p - dst;
205 assert(num_left + num_orig == size);
206
207 va_start(vargs, fmt);
208 n = vsnprintf(p, num_left, fmt, vargs);
209 va_end(vargs);
210
211 if ((n < 0) || ((size_t) n >= num_left)) {
212 return(-1);
213 }
214 return((int) num_orig + n);
215 }
216
217
substitute_string(char * dst,size_t dstlen,const char * src,char c,const char * sub)218 int substitute_string(char *dst, size_t dstlen, const char *src,
219 char c, const char *sub)
220 {
221 const char *p;
222 char *q;
223 int len;
224 int n;
225
226 if (!dst || (dstlen <= 0) || !src || !c) {
227 errno = EINVAL;
228 return (-1);
229 }
230 p = src;
231 q = dst;
232 len = dstlen;
233
234 while (*p && (len > 0)) {
235 if ((*p == '%') && (*(p+1) == c)) {
236 if (sub) {
237 n = strlcpy(q, sub, len);
238 q += n;
239 len -= n;
240 }
241 p += 2;
242 }
243 else {
244 *q++ = *p++;
245 len--;
246 }
247 }
248 if (len > 0) {
249 *q = '\0';
250 return(dstlen - len);
251 }
252 else {
253 dst[dstlen - 1] = '\0';
254 return (-1);
255 }
256 }
257
258
create_long_time_string(time_t t)259 char * create_long_time_string(time_t t)
260 {
261 char *p;
262 struct tm tm;
263 const int len = 32;
264
265 if (!(p = malloc(len))) {
266 out_of_memory();
267 }
268 get_localtime(&t, &tm);
269
270 if (strftime(p, len, "%Y-%m-%d %H:%M:%S %Z", &tm) == 0) {
271 log_err(0, "strftime() failed");
272 }
273 return(p);
274 }
275
276
create_short_time_string(time_t t)277 char * create_short_time_string(time_t t)
278 {
279 char *p;
280 struct tm tm;
281 const int len = 12; /* MM-DD HH:MM + NUL */
282
283 if (!(p = malloc(len))) {
284 out_of_memory();
285 }
286 get_localtime(&t, &tm);
287
288 if (strftime(p, len, "%m-%d %H:%M", &tm) == 0) {
289 log_err(0, "strftime() failed");
290 }
291 return(p);
292 }
293
294
create_time_delta_string(time_t t0,time_t t1)295 char * create_time_delta_string(time_t t0, time_t t1)
296 {
297 long n;
298 int years, weeks, days, hours, minutes, seconds;
299 char buf[25];
300
301 if (t1 == (time_t) -1) {
302 if (time(&t1) == (time_t) -1) {
303 log_err(errno, "time() failed");
304 }
305 }
306 n = difftime(t1, t0);
307 assert(n >= 0);
308
309 seconds = n % 60;
310 n /= 60;
311 minutes = n % 60;
312 n /= 60;
313 hours = n % 24;
314 n /= 24;
315 days = n % 7;
316 n /= 7;
317 weeks = n % 52;
318 n /= 52;
319 years = n;
320
321 if (years > 0) {
322 n = snprintf(buf, sizeof(buf), "%dy%dw%dd%dh%dm%ds",
323 years, weeks, days, hours, minutes, seconds);
324 }
325 else if (weeks > 0) {
326 n = snprintf(buf, sizeof(buf), "%dw%dd%dh%dm%ds",
327 weeks, days, hours, minutes, seconds);
328 }
329 else if (days > 0) {
330 n = snprintf(buf, sizeof(buf), "%dd%dh%dm%ds",
331 days, hours, minutes, seconds);
332 }
333 else if (hours > 0) {
334 n = snprintf(buf, sizeof(buf), "%dh%dm%ds", hours, minutes, seconds);
335 }
336 else if (minutes > 0) {
337 n = snprintf(buf, sizeof(buf), "%dm%ds", minutes, seconds);
338 }
339 else {
340 n = snprintf(buf, sizeof(buf), "%ds", seconds);
341 }
342 assert((n >= 0) && ((size_t) n < sizeof(buf)));
343 return(create_string(buf));
344 }
345
346
write_time_string(time_t t,char * dst,size_t dstlen)347 int write_time_string(time_t t, char *dst, size_t dstlen)
348 {
349 struct tm tm;
350 int n;
351
352 if (dstlen <= 20) { /* "YYYY-MM-DD HH:MM:SS " + NUL */
353 return(0);
354 }
355 get_localtime(&t, &tm);
356
357 if (!(n = strftime(dst, dstlen, "%Y-%m-%d %H:%M:%S ", &tm))) {
358 return(0);
359 }
360 assert(n == 20);
361 return(n);
362 }
363
364
get_localtime(time_t * tPtr,struct tm * tmPtr)365 struct tm * get_localtime(time_t *tPtr, struct tm *tmPtr)
366 {
367 #if ! HAVE_LOCALTIME_R
368
369 static pthread_mutex_t localtimeLock = PTHREAD_MUTEX_INITIALIZER;
370 struct tm *tmTmpPtr;
371
372 #endif /* !HAVE_LOCALTIME_R */
373
374 assert(tPtr != NULL);
375 assert(tmPtr != NULL);
376
377 if (*tPtr == 0) {
378 if (time(tPtr) == (time_t) -1) {
379 log_err(errno, "time() failed");
380 }
381 }
382
383 #if ! HAVE_LOCALTIME_R
384
385 /* localtime() is not thread-safe, so it is protected by a mutex.
386 */
387 x_pthread_mutex_lock(&localtimeLock);
388 if (!(tmTmpPtr = localtime(tPtr))) {
389 log_err(errno, "localtime() failed");
390 }
391 *tmPtr = *tmTmpPtr;
392 x_pthread_mutex_unlock(&localtimeLock);
393
394 #else /* HAVE_LOCALTIME_R */
395
396 if (!localtime_r(tPtr, tmPtr)) {
397 log_err(errno, "localtime_r() failed");
398 }
399
400 #endif /* !HAVE_LOCALTIME_R */
401
402 return(tmPtr);
403 }
404
405
406 #if ! HAVE_STRCASECMP
strcasecmp(const char * s1,const char * s2)407 int strcasecmp(const char *s1, const char *s2)
408 {
409 const char *p, *q;
410
411 p = s1;
412 q = s2;
413 while (*p && toupper((int) *p) == toupper((int) *q)) {
414 p++, q++;
415 }
416 return(toupper((int) *p) - toupper((int) *q));
417 }
418 #endif /* !HAVE_STRCASECMP */
419
420
421 #if ! HAVE_STRNCASECMP
strncasecmp(const char * s1,const char * s2,size_t n)422 int strncasecmp(const char *s1, const char *s2, size_t n)
423 {
424 const char *p, *q;
425
426 if (!n) {
427 return(0);
428 }
429 p = s1;
430 q = s2;
431 while (--n && *p && toupper((int) *p) == toupper((int) *q)) {
432 p++, q++;
433 }
434 return(toupper((int) *p) - toupper((int) *q));
435 }
436 #endif /* !HAVE_STRNCASECMP */
437
438
439 #if ! HAVE_TOINT
toint(int c)440 int toint(int c)
441 {
442 /* Returns the "weight" (0-15) of a hexadecimal digit 'c'.
443 *
444 * Implementation from "C: A Reference Manual, 5e" by Harbison & Steele.
445 */
446 if (c >= '0' && c <= '9') {
447 return(c - '0');
448 }
449 if (c >= 'A' && c <= 'F') {
450 return(c - 'A' + 10);
451 }
452 if (c >= 'a' && c <= 'f') {
453 return(c - 'a' + 10);
454 }
455 return(0);
456 }
457 #endif /* !HAVE_TOINT */
458