1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2017 by the Blender FOundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bli
22 */
23
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_string.h"
31 #include "BLI_string_utf8.h"
32 #include "BLI_string_utils.h"
33 #include "BLI_utildefines.h"
34
35 #include "DNA_listBase.h"
36
37 #ifdef __GNUC__
38 # pragma GCC diagnostic error "-Wsign-conversion"
39 #endif
40
41 /**
42 * Looks for a numeric suffix preceded by delim character on the end of
43 * name, puts preceding part into *left and value of suffix into *nr.
44 * Returns the length of *left.
45 *
46 * Foo.001 -> "Foo", 1
47 * Returning the length of "Foo"
48 *
49 * \param left: Where to return copy of part preceding delim
50 * \param nr: Where to return value of numeric suffix
51 * \param name: String to split
52 * \param delim: Delimiter character
53 * \return Length of \a left
54 */
BLI_split_name_num(char * left,int * nr,const char * name,const char delim)55 size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
56 {
57 const size_t name_len = strlen(name);
58
59 *nr = 0;
60 memcpy(left, name, (name_len + 1) * sizeof(char));
61
62 /* name doesn't end with a delimiter "foo." */
63 if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
64 size_t a = name_len;
65 while (a--) {
66 if (name[a] == delim) {
67 left[a] = '\0'; /* truncate left part here */
68 *nr = atol(name + a + 1);
69 /* casting down to an int, can overflow for large numbers */
70 if (*nr < 0) {
71 *nr = 0;
72 }
73 return a;
74 }
75 if (isdigit(name[a]) == 0) {
76 /* non-numeric suffix - give up */
77 break;
78 }
79 }
80 }
81
82 return name_len;
83 }
84
BLI_string_is_decimal(const char * string)85 bool BLI_string_is_decimal(const char *string)
86 {
87 if (*string == '\0') {
88 return false;
89 }
90
91 /* Keep iterating over the string until a non-digit is found. */
92 while (isdigit(*string)) {
93 string++;
94 }
95
96 /* If the non-digit we found is the terminating \0, everything was digits. */
97 return *string == '\0';
98 }
99
is_char_sep(const char c)100 static bool is_char_sep(const char c)
101 {
102 return ELEM(c, '.', ' ', '-', '_');
103 }
104
105 /**
106 * based on `BLI_split_dirfile()` / `os.path.splitext()`,
107 * `"a.b.c"` -> (`"a.b"`, `".c"`).
108 */
BLI_string_split_suffix(const char * string,char * r_body,char * r_suf,const size_t str_len)109 void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
110 {
111 size_t len = BLI_strnlen(string, str_len);
112 size_t i;
113
114 r_body[0] = r_suf[0] = '\0';
115
116 for (i = len; i > 0; i--) {
117 if (is_char_sep(string[i])) {
118 BLI_strncpy(r_body, string, i + 1);
119 BLI_strncpy(r_suf, string + i, (len + 1) - i);
120 return;
121 }
122 }
123
124 memcpy(r_body, string, len + 1);
125 }
126
127 /**
128 * `"a.b.c"` -> (`"a."`, `"b.c"`)
129 */
BLI_string_split_prefix(const char * string,char * r_pre,char * r_body,const size_t str_len)130 void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
131 {
132 size_t len = BLI_strnlen(string, str_len);
133 size_t i;
134
135 r_body[0] = r_pre[0] = '\0';
136
137 for (i = 1; i < len; i++) {
138 if (is_char_sep(string[i])) {
139 i++;
140 BLI_strncpy(r_pre, string, i + 1);
141 BLI_strncpy(r_body, string + i, (len + 1) - i);
142 return;
143 }
144 }
145
146 BLI_strncpy(r_body, string, len);
147 }
148
149 /**
150 * Finds the best possible flipped (left/right) name.
151 * For renaming; check for unique names afterwards.
152 *
153 * \param r_name: flipped name,
154 * assumed to be a pointer to a string of at least \a name_len size.
155 * \param from_name: original name,
156 * assumed to be a pointer to a string of at least \a name_len size.
157 * \param strip_number: If set, remove number extensions.
158 */
BLI_string_flip_side_name(char * r_name,const char * from_name,const bool strip_number,const size_t name_len)159 void BLI_string_flip_side_name(char *r_name,
160 const char *from_name,
161 const bool strip_number,
162 const size_t name_len)
163 {
164 size_t len;
165 char *prefix = alloca(name_len); /* The part before the facing */
166 char *suffix = alloca(name_len); /* The part after the facing */
167 char *replace = alloca(name_len); /* The replacement string */
168 char *number = alloca(name_len); /* The number extension string */
169 char *index = NULL;
170 bool is_set = false;
171
172 *prefix = *suffix = *replace = *number = '\0';
173
174 /* always copy the name, since this can be called with an uninitialized string */
175 BLI_strncpy(r_name, from_name, name_len);
176
177 len = BLI_strnlen(from_name, name_len);
178 if (len < 3) {
179 /* we don't do names like .R or .L */
180 return;
181 }
182
183 /* We first check the case with a .### extension, let's find the last period */
184 if (isdigit(r_name[len - 1])) {
185 index = strrchr(r_name, '.'); /* last occurrence. */
186 if (index && isdigit(index[1])) { /* doesn't handle case bone.1abc2 correct..., whatever! */
187 if (strip_number == false) {
188 BLI_strncpy(number, index, name_len);
189 }
190 *index = 0;
191 len = BLI_strnlen(r_name, name_len);
192 }
193 }
194
195 BLI_strncpy(prefix, r_name, name_len);
196
197 /* first case; separator . - _ with extensions r R l L */
198 if ((len > 1) && is_char_sep(r_name[len - 2])) {
199 is_set = true;
200 switch (r_name[len - 1]) {
201 case 'l':
202 prefix[len - 1] = 0;
203 strcpy(replace, "r");
204 break;
205 case 'r':
206 prefix[len - 1] = 0;
207 strcpy(replace, "l");
208 break;
209 case 'L':
210 prefix[len - 1] = 0;
211 strcpy(replace, "R");
212 break;
213 case 'R':
214 prefix[len - 1] = 0;
215 strcpy(replace, "L");
216 break;
217 default:
218 is_set = false;
219 }
220 }
221
222 /* case; beginning with r R l L, with separator after it */
223 if (!is_set && is_char_sep(r_name[1])) {
224 is_set = true;
225 switch (r_name[0]) {
226 case 'l':
227 strcpy(replace, "r");
228 BLI_strncpy(suffix, r_name + 1, name_len);
229 prefix[0] = 0;
230 break;
231 case 'r':
232 strcpy(replace, "l");
233 BLI_strncpy(suffix, r_name + 1, name_len);
234 prefix[0] = 0;
235 break;
236 case 'L':
237 strcpy(replace, "R");
238 BLI_strncpy(suffix, r_name + 1, name_len);
239 prefix[0] = 0;
240 break;
241 case 'R':
242 strcpy(replace, "L");
243 BLI_strncpy(suffix, r_name + 1, name_len);
244 prefix[0] = 0;
245 break;
246 default:
247 is_set = false;
248 }
249 }
250
251 if (!is_set && len > 5) {
252 /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
253 if (((index = BLI_strcasestr(prefix, "right")) == prefix) || (index == prefix + len - 5)) {
254 is_set = true;
255 if (index[0] == 'r') {
256 strcpy(replace, "left");
257 }
258 else {
259 strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
260 }
261 *index = 0;
262 BLI_strncpy(suffix, index + 5, name_len);
263 }
264 else if (((index = BLI_strcasestr(prefix, "left")) == prefix) || (index == prefix + len - 4)) {
265 is_set = true;
266 if (index[0] == 'l') {
267 strcpy(replace, "right");
268 }
269 else {
270 strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
271 }
272 *index = 0;
273 BLI_strncpy(suffix, index + 4, name_len);
274 }
275 }
276
277 BLI_snprintf(r_name, name_len, "%s%s%s%s", prefix, replace, suffix, number);
278 }
279
280 /* Unique name utils. */
281
282 /**
283 * Ensures name is unique (according to criteria specified by caller in unique_check callback),
284 * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
285 *
286 * \param unique_check: Return true if name is not unique
287 * \param arg: Additional arg to unique_check--meaning is up to caller
288 * \param defname: To initialize name if latter is empty
289 * \param delim: Delimits numeric suffix in name
290 * \param name: Name to be ensured unique
291 * \param name_len: Maximum length of name area
292 * \return true if there if the name was changed
293 */
BLI_uniquename_cb(UniquenameCheckCallback unique_check,void * arg,const char * defname,char delim,char * name,size_t name_len)294 bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
295 void *arg,
296 const char *defname,
297 char delim,
298 char *name,
299 size_t name_len)
300 {
301 if (name[0] == '\0') {
302 BLI_strncpy(name, defname, name_len);
303 }
304
305 if (unique_check(arg, name)) {
306 char numstr[16];
307 char *tempname = alloca(name_len);
308 char *left = alloca(name_len);
309 int number;
310 size_t len = BLI_split_name_num(left, &number, name, delim);
311 do {
312 /* add 1 to account for \0 */
313 const size_t numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
314
315 /* highly unlikely the string only has enough room for the number
316 * but support anyway */
317 if ((len == 0) || (numlen >= name_len)) {
318 /* number is know not to be utf-8 */
319 BLI_strncpy(tempname, numstr, name_len);
320 }
321 else {
322 char *tempname_buf;
323 tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
324 memcpy(tempname_buf, numstr, numlen);
325 }
326 } while (unique_check(arg, tempname));
327
328 BLI_strncpy(name, tempname, name_len);
329
330 return true;
331 }
332
333 return false;
334 }
335
336 /* little helper macro for BLI_uniquename */
337 #ifndef GIVE_STRADDR
338 # define GIVE_STRADDR(data, offset) (((char *)data) + offset)
339 #endif
340
341 /**
342 * Generic function to set a unique name. It is only designed to be used in situations
343 * where the name is part of the struct.
344 *
345 * For places where this is used, see constraint.c for example...
346 *
347 * \param name_offs: should be calculated using offsetof(structname, membername)
348 * macro from stddef.h
349 */
uniquename_find_dupe(ListBase * list,void * vlink,const char * name,int name_offs)350 static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
351 {
352 Link *link;
353
354 for (link = list->first; link; link = link->next) {
355 if (link != vlink) {
356 if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
357 return true;
358 }
359 }
360 }
361
362 return false;
363 }
364
uniquename_unique_check(void * arg,const char * name)365 static bool uniquename_unique_check(void *arg, const char *name)
366 {
367 struct {
368 ListBase *lb;
369 void *vlink;
370 int name_offs;
371 } *data = arg;
372 return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
373 }
374
375 /**
376 * Ensures that the specified block has a unique name within the containing list,
377 * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
378 *
379 * \param list: List containing the block
380 * \param vlink: The block to check the name for
381 * \param defname: To initialize block name if latter is empty
382 * \param delim: Delimits numeric suffix in name
383 * \param name_offs: Offset of name within block structure
384 * \param name_len: Maximum length of name area
385 */
BLI_uniquename(ListBase * list,void * vlink,const char * defname,char delim,int name_offs,size_t name_len)386 bool BLI_uniquename(
387 ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len)
388 {
389 struct {
390 ListBase *lb;
391 void *vlink;
392 int name_offs;
393 } data;
394 data.lb = list;
395 data.vlink = vlink;
396 data.name_offs = name_offs;
397
398 BLI_assert(name_len > 1);
399
400 /* See if we are given an empty string */
401 if (ELEM(NULL, vlink, defname)) {
402 return false;
403 }
404
405 return BLI_uniquename_cb(
406 uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
407 }
408
409 /* ------------------------------------------------------------------------- */
410 /** \name Join Strings
411 *
412 * For non array versions of these functions, use the macros:
413 * - #BLI_string_join
414 * - #BLI_string_joinN
415 * - #BLI_string_join_by_sep_charN
416 * - #BLI_string_join_by_sep_char_with_tableN
417 *
418 * \{ */
419
BLI_string_join_array(char * result,size_t result_len,const char * strings[],uint strings_len)420 char *BLI_string_join_array(char *result,
421 size_t result_len,
422 const char *strings[],
423 uint strings_len)
424 {
425 char *c = result;
426 char *c_end = &result[result_len - 1];
427 for (uint i = 0; i < strings_len; i++) {
428 const char *p = strings[i];
429 while (*p && (c < c_end)) {
430 *c++ = *p++;
431 }
432 }
433 *c = '\0';
434 return c;
435 }
436
437 /**
438 * A version of #BLI_string_join that takes a separator which can be any character including '\0'.
439 */
BLI_string_join_array_by_sep_char(char * result,size_t result_len,char sep,const char * strings[],uint strings_len)440 char *BLI_string_join_array_by_sep_char(
441 char *result, size_t result_len, char sep, const char *strings[], uint strings_len)
442 {
443 char *c = result;
444 char *c_end = &result[result_len - 1];
445 for (uint i = 0; i < strings_len; i++) {
446 if (i != 0) {
447 if (c < c_end) {
448 *c++ = sep;
449 }
450 }
451 const char *p = strings[i];
452 while (*p && (c < c_end)) {
453 *c++ = *p++;
454 }
455 }
456 *c = '\0';
457 return c;
458 }
459
460 /**
461 * Join an array of strings into a newly allocated, null terminated string.
462 */
BLI_string_join_arrayN(const char * strings[],uint strings_len)463 char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
464 {
465 uint total_len = 1;
466 for (uint i = 0; i < strings_len; i++) {
467 total_len += strlen(strings[i]);
468 }
469 char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
470 char *c = result;
471 for (uint i = 0; i < strings_len; i++) {
472 c += BLI_strcpy_rlen(c, strings[i]);
473 }
474 return result;
475 }
476
477 /**
478 * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
479 */
BLI_string_join_array_by_sep_charN(char sep,const char * strings[],uint strings_len)480 char *BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint strings_len)
481 {
482 uint total_len = 0;
483 for (uint i = 0; i < strings_len; i++) {
484 total_len += strlen(strings[i]) + 1;
485 }
486 if (total_len == 0) {
487 total_len = 1;
488 }
489
490 char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
491 char *c = result;
492 if (strings_len != 0) {
493 for (uint i = 0; i < strings_len; i++) {
494 c += BLI_strcpy_rlen(c, strings[i]);
495 *c = sep;
496 c++;
497 }
498 c--;
499 }
500 *c = '\0';
501 return result;
502 }
503
504 /**
505 * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
506 * The new location of each string is written into this array.
507 */
BLI_string_join_array_by_sep_char_with_tableN(char sep,char * table[],const char * strings[],uint strings_len)508 char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
509 char *table[],
510 const char *strings[],
511 uint strings_len)
512 {
513 uint total_len = 0;
514 for (uint i = 0; i < strings_len; i++) {
515 total_len += strlen(strings[i]) + 1;
516 }
517 if (total_len == 0) {
518 total_len = 1;
519 }
520
521 char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
522 char *c = result;
523 if (strings_len != 0) {
524 for (uint i = 0; i < strings_len; i++) {
525 table[i] = c; /* <-- only difference to BLI_string_join_array_by_sep_charN. */
526 c += BLI_strcpy_rlen(c, strings[i]);
527 *c = sep;
528 c++;
529 }
530 c--;
531 }
532 *c = '\0';
533 return result;
534 }
535
536 /** \} */
537