1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <glib.h>
5 
6 #include "str_util.h"
7 #include "math_util.h"
8 
9 
10 /*** private functions ******************************************************/
11 
convert_sentence_case(const char * str)12 static char *convert_sentence_case(const char *str)
13 {
14 	int result_size = strlen(str) + 12;
15 	char *result = malloc(result_size);
16 	const char *r = str;
17 	char *w = result;
18 
19 	while (*r) {
20 		int len;
21 		gunichar c = g_utf8_get_char(r);
22 
23 		/* ensure there is room for at least 1 more character */
24 		if (w - result + 7 > result_size) {
25 			int offset = w - result;
26 			result_size += max(6, 0.5 * result_size);
27 			result = realloc(result, result_size);
28 			w = result + offset;
29 		}
30 
31 		if (r == str)
32 			len = g_unichar_to_utf8(g_unichar_toupper(c), w);
33 		else
34 			len = g_unichar_to_utf8(g_unichar_tolower(c), w);
35 		w += len;
36 
37 		r = g_utf8_next_char(r);
38 	}
39 
40 	*w = 0;
41 
42 	return result;
43 }
44 
convert_title_case(const char * str)45 static char *convert_title_case(const char *str)
46 {
47 	int result_size = strlen(str) + 12;
48 	char *result = malloc(result_size);
49 	const char *r = str;
50 	char *w = result;
51 	gboolean upcase_next = TRUE;
52 
53 	while (*r) {
54 		int len;
55 		gunichar c = g_utf8_get_char(r);
56 
57 		/* ensure there is room for at least 1 more character */
58 		if (w - result + 7 > result_size) {
59 			int offset = w - result;
60 			result_size += max(6, 0.5 * result_size);
61 			result = realloc(result, result_size);
62 			w = result + offset;
63 		}
64 
65 		if (upcase_next)
66 			len = g_unichar_to_utf8(g_unichar_toupper(c), w);
67 		else
68 			len = g_unichar_to_utf8(g_unichar_tolower(c), w);
69 		w += len;
70 
71 		upcase_next = !g_unichar_isalnum(c) && c != '\'';
72 
73 		r = g_utf8_next_char(r);
74 	}
75 
76 	*w = 0;
77 
78 	return result;
79 }
80 
81 
82 /*** public functions *******************************************************/
83 
str_convert_case(const char * str,int conv)84 char *str_convert_case(const char *str, int conv)
85 {
86 	switch (conv) {
87 		case CASE_CONV_NONE: {
88 			return strdup(str);
89 		}
90 		case CASE_CONV_LOWER: {
91 			return g_utf8_strdown(str, -1);
92 		}
93 		case CASE_CONV_UPPER: {
94 			return g_utf8_strup(str, -1);
95 		}
96 		case CASE_CONV_SENTENCE: {
97 			return convert_sentence_case(str);
98 		}
99 		case CASE_CONV_TITLE: {
100 			return convert_title_case(str);
101 		}
102 		default: {
103 			fprintf(stderr, "str_convert_case: unrecognized convertion type (%i)\n", conv);
104 			return NULL;
105 		}
106 	}
107 }
108 
109 
str_replace_char(const char * str,gunichar orig,gunichar repl)110 char *str_replace_char(const char *str, gunichar orig, gunichar repl)
111 {
112 	int result_size = strlen(str) + 6;
113 	char *result = malloc(result_size);
114 	const char *r = str;
115 	char *w = result;
116 
117 	while (*r) {
118 		int len;
119 		gunichar c = g_utf8_get_char(r);
120 
121 		/* ensure there is room for at least 1 more character */
122 		if (w - result + 7 > result_size) {
123 			int offset = w - result;
124 			result_size += max(6, 0.5 * result_size);
125 			result = realloc(result, result_size);
126 			w = result + offset;
127 		}
128 
129 		if (c == orig)
130 			len = g_unichar_to_utf8(repl, w);
131 		else
132 			len = g_unichar_to_utf8(c, w);
133 		w += len;
134 
135 		r = g_utf8_next_char(r);
136 	}
137 
138 	*w = 0;
139 
140 	return result;
141 }
142 
143 
str_remove_char(const char * str,gunichar rem)144 char *str_remove_char(const char *str, gunichar rem)
145 {
146 	char *result = malloc(strlen(str) + 1);
147 	const char *r = str;
148 	char *w = result;
149 
150 	while (*r) {
151 		gunichar c = g_utf8_get_char(r);
152 		if (c != rem) {
153 			int len = g_unichar_to_utf8(c, w);
154 			w += len;
155 		}
156 
157 		r = g_utf8_next_char(r);
158 	}
159 
160 	*w = 0;
161 
162 	return result;
163 }
164 
str_rtrim(char * str)165 void str_rtrim(char *str)
166 {
167 	int len = strlen(str);
168 	char *last = str + len;
169 	char *curr = last - 1;
170 
171 	if (len == 0)
172 		return;
173 
174 	while (*curr == ' ' || *curr == '\t' || *curr == '\r' || *curr == '\n') {
175 		last = curr;
176 		curr = g_utf8_find_prev_char(str, curr);
177 		if (curr == NULL)
178 			break;
179 	}
180 
181 	*last = 0;
182 }
183 
str_ltrim(char * str)184 void str_ltrim(char *str)
185 {
186 	char *pos = str;
187 
188 	while (*pos && (*pos == ' ' || *pos == '\t' || *pos == '\r' || *pos == '\n')) {
189 		pos = g_utf8_find_next_char(pos, NULL);
190 	}
191 
192 	if (pos != str) {
193 		size_t size = strlen(str) - (pos-str) + 1;
194 		memmove(str, pos, size);
195 	}
196 }
197 
str_trim(char * str)198 void str_trim(char *str)
199 {
200 	str_rtrim(str);
201 	str_ltrim(str);
202 }
203 
204 
str_strnchr(const char * s,char c,int n)205 char *str_strnchr(const char *s, char c, int n)
206 {
207 	int p = (int)s;
208 	int count = 0;
209 
210 	while (*(char *)p) {
211 		if (*(char *)p == c)
212 			if (++count == n)
213 				return (char *)p;
214 		p++;
215 	}
216 	return NULL;
217 }
218 
str_strnrchr(const char * s,char c,int n)219 char *str_strnrchr(const char *s, char c, int n)
220 {
221 	int p = (int)s + strlen(s);
222 	int count = 0;
223 
224 	while (p >= (int)s) {
225 		if (*(char *)p == c)
226 			if (++count == n)
227 				return (char *)p;
228 		p--;
229 	}
230 	return NULL;
231 }
232 
str_safe_strncpy(char * dest,const char * src,size_t n)233 char *str_safe_strncpy(char *dest, const char *src, size_t n)
234 {
235 	char *end;
236 
237 	if (n <= 0)
238 		return NULL;
239 
240 	strncpy(dest, src, n);
241 	dest[n-1] = 0;
242 
243 	/* may have left an incomplete multibyte character at the end */
244 	if (!g_utf8_validate(dest, -1, (const char **)&end))
245 		*end = 0;
246 
247 	return dest;
248 }
249 
250 
str_ascii_tolower(char * str)251 void str_ascii_tolower(char *str)
252 {
253 	char *p;
254 	for (p = str; *p ; p++)
255 		*p = g_ascii_tolower(*p);
256 }
257 
str_ascii_toupper(char * str)258 void str_ascii_toupper(char *str)
259 {
260 	char *p;
261 	for (p = str; *p ; p++)
262 		*p = g_ascii_toupper(*p);
263 }
264 
265 
str_ascii_replace_char(char * str,char orig,char repl)266 void str_ascii_replace_char(char *str, char orig, char repl)
267 {
268 	char *p;
269 	for (p = str; *p; p++)
270 		if (*p == orig)
271 			*p = repl;
272 }
273 
274