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