1 /*
2  * Copyright (c) 2011 NLNet Labs. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
19  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
21  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
22  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
23  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 /**
28  *
29  * String utilities
30  */
31 
32 #include "config.h"
33 #include "str.h"
34 #include "log.h"
35 
36 #include <errno.h>
37 #include <assert.h>
38 #include <stdio.h> /* snprintf() */
39 #include <stdlib.h>
40 #include <string.h> /* strlen(), strcpy() */
41 #include <ctype.h> /* isspace() */
42 
43 #include <unistd.h>
44 #include <getopt.h>
45 
46 static const char *module_str = "str";
47 
48 int
ods_str_explode(char * buf,int argc,const char * argv[])49 ods_str_explode(char *buf, int argc, const char *argv[])
50 {
51     int narg = 0;
52     char *p = strtok(buf, " ");
53     while(p != NULL) {
54         if (narg > argc)
55             return -1;
56         argv[narg] = p;
57         p = strtok(NULL, " ");
58         narg++;
59     }
60     return narg;
61 }
62 
63 /**
64  * Concatenate characters without custom allocators.
65  *
66  * Will always allocate at least 1 byte (when catting empty strings) so
67  * result should always be freed by the caller.
68  *
69  * \param[in] argc, number of strings in argv.
70  * \param[in] argv, storage of strings. Must not be NULL;
71  * \param[in] delim, delimiter used to join the strings.
72  * \return string, may be empty string.
73  */
74 char *
ods_strcat_delim(int argc,char * argv[],char delim)75 ods_strcat_delim(int argc, char* argv[], char delim)
76 {
77     int i, pos = 0, len = 1;
78     char *cat;
79 
80     assert(argv);
81 
82     for (i = 0; i < argc; i++)
83         len += strlen(argv[i]) + 1;
84     cat = (char *) malloc(len * sizeof (char));
85     memset(cat, delim, len-1);
86     for (i = 0; i < argc; i++) {
87         memcpy(cat+pos, argv[i], strlen(argv[i]));
88         pos += strlen(argv[i]) + 1;
89     }
90     cat[len-1] = '\0';
91     return cat;
92 }
93 
94 /**
95  * Remove leading and trailing whitespace.
96  * enforcer used ods_str_trim(s,0)
97  */
98 char *
ods_str_trim(char * str,int keep_newline)99 ods_str_trim(char *str, int keep_newline)
100 {
101     int has_newline = 0;
102     char *start, *end;
103     if (str) {
104         end = str + strlen(str); /* points at \0 */
105 
106         for (start = str; start<end; start++) {
107             if (!isspace(*start)) break;
108         }
109         for (; end > start; end--) {
110             if (*(end-1) == '\n') has_newline = 1;
111             if (!isspace(*(end-1))) break;
112         }
113         memmove(str, start, end-start);
114         if(has_newline && keep_newline) {
115             str[(end++)-start] = '\n';
116         }
117         str[end-start] = '\0';
118     }
119     return str;
120 }
121 
122 /**
123  * Version of ctime_r that does not feature a trailing '\n' character
124  *
125  */
126 char *
ods_ctime_r(char * buf,size_t nbuf,time_t t)127 ods_ctime_r(char *buf, size_t nbuf, time_t t)
128 {
129 #if 0
130     struct tm datetime;
131     if (localtime_r(&t,&datetime) == NULL) {
132         ods_log_error("[%s] time_datestamp: localtime_r() failed",
133                       module_str);
134         return NULL;
135     }
136     snprintf(buf, nbuf, "%4.4d-%2.2d-%2.2d %2.2d:%2.2d:%2.2d",
137              1900+datetime.tm_year, datetime.tm_mon + 1, datetime.tm_mday,
138              datetime.tm_hour, datetime.tm_min, datetime.tm_sec);
139     return buf;
140 #else
141     if (nbuf>=26 && buf!=NULL) {
142         char *p;
143         char *pbeg = ctime_r(&t,buf);
144         char *pend = pbeg ? (pbeg+strlen(pbeg)) : pbeg;
145         if (pbeg >= pend) {
146             ods_log_error("[%s] time_datestamp: ctime_r() failed",
147                           module_str);
148             return NULL;
149         }
150         /* strip trailing space characters including '\n' from time string */
151         for (p=pend-1; p>=pbeg && isspace(*p); --p) {
152             *p = '\0';
153         }
154     }
155     return buf;
156 #endif
157 }
158