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