Cleanup: comments (long lines) in blenlib
[blender.git] / source / blender / blenlib / intern / string_utils.c
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 <string.h>
26 #include <stdlib.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  */
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       else if (isdigit(name[a]) == 0) {
76         /* non-numeric suffix - give up */
77         break;
78       }
79     }
80   }
81
82   return name_len;
83 }
84
85 static bool is_char_sep(const char c)
86 {
87   return ELEM(c, '.', ' ', '-', '_');
88 }
89
90 /**
91  * based on `BLI_split_dirfile()` / `os.path.splitext()`,
92  * `"a.b.c"` -> (`"a.b"`, `".c"`).
93  */
94 void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
95 {
96   size_t len = BLI_strnlen(string, str_len);
97   size_t i;
98
99   r_body[0] = r_suf[0] = '\0';
100
101   for (i = len; i > 0; i--) {
102     if (is_char_sep(string[i])) {
103       BLI_strncpy(r_body, string, i + 1);
104       BLI_strncpy(r_suf, string + i, (len + 1) - i);
105       return;
106     }
107   }
108
109   memcpy(r_body, string, len + 1);
110 }
111
112 /**
113  * `"a.b.c"` -> (`"a."`, `"b.c"`)
114  */
115 void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
116 {
117   size_t len = BLI_strnlen(string, str_len);
118   size_t i;
119
120   r_body[0] = r_pre[0] = '\0';
121
122   for (i = 1; i < len; i++) {
123     if (is_char_sep(string[i])) {
124       i++;
125       BLI_strncpy(r_pre, string, i + 1);
126       BLI_strncpy(r_body, string + i, (len + 1) - i);
127       return;
128     }
129   }
130
131   BLI_strncpy(r_body, string, len);
132 }
133
134 /**
135  * Finds the best possible flipped (left/right) name.
136  * For renaming; check for unique names afterwards.
137  *
138  * \param r_name: flipped name,
139  * assumed to be a pointer to a string of at least \a name_len size.
140  * \param from_name: original name,
141  * assumed to be a pointer to a string of at least \a name_len size.
142  * \param strip_number: If set, remove number extensions.
143  */
144 void BLI_string_flip_side_name(char *r_name,
145                                const char *from_name,
146                                const bool strip_number,
147                                const size_t name_len)
148 {
149   size_t len;
150   char *prefix = alloca(name_len);  /* The part before the facing */
151   char *suffix = alloca(name_len);  /* The part after the facing */
152   char *replace = alloca(name_len); /* The replacement string */
153   char *number = alloca(name_len);  /* The number extension string */
154   char *index = NULL;
155   bool is_set = false;
156
157   *prefix = *suffix = *replace = *number = '\0';
158
159   /* always copy the name, since this can be called with an uninitialized string */
160   BLI_strncpy(r_name, from_name, name_len);
161
162   len = BLI_strnlen(from_name, name_len);
163   if (len < 3) {
164     /* we don't do names like .R or .L */
165     return;
166   }
167
168   /* We first check the case with a .### extension, let's find the last period */
169   if (isdigit(r_name[len - 1])) {
170     index = strrchr(r_name, '.');      // last occurrence
171     if (index && isdigit(index[1])) {  // doesnt handle case bone.1abc2 correct..., whatever!
172       if (strip_number == false) {
173         BLI_strncpy(number, index, name_len);
174       }
175       *index = 0;
176       len = BLI_strnlen(r_name, name_len);
177     }
178   }
179
180   BLI_strncpy(prefix, r_name, name_len);
181
182   /* first case; separator . - _ with extensions r R l L  */
183   if ((len > 1) && is_char_sep(r_name[len - 2])) {
184     is_set = true;
185     switch (r_name[len - 1]) {
186       case 'l':
187         prefix[len - 1] = 0;
188         strcpy(replace, "r");
189         break;
190       case 'r':
191         prefix[len - 1] = 0;
192         strcpy(replace, "l");
193         break;
194       case 'L':
195         prefix[len - 1] = 0;
196         strcpy(replace, "R");
197         break;
198       case 'R':
199         prefix[len - 1] = 0;
200         strcpy(replace, "L");
201         break;
202       default:
203         is_set = false;
204     }
205   }
206
207   /* case; beginning with r R l L, with separator after it */
208   if (!is_set && is_char_sep(r_name[1])) {
209     is_set = true;
210     switch (r_name[0]) {
211       case 'l':
212         strcpy(replace, "r");
213         BLI_strncpy(suffix, r_name + 1, name_len);
214         prefix[0] = 0;
215         break;
216       case 'r':
217         strcpy(replace, "l");
218         BLI_strncpy(suffix, r_name + 1, name_len);
219         prefix[0] = 0;
220         break;
221       case 'L':
222         strcpy(replace, "R");
223         BLI_strncpy(suffix, r_name + 1, name_len);
224         prefix[0] = 0;
225         break;
226       case 'R':
227         strcpy(replace, "L");
228         BLI_strncpy(suffix, r_name + 1, name_len);
229         prefix[0] = 0;
230         break;
231       default:
232         is_set = false;
233     }
234   }
235
236   if (!is_set && len > 5) {
237     /* hrms, why test for a separator? lets do the rule 'ultimate left or right' */
238     if (((index = BLI_strcasestr(prefix, "right")) == prefix) || (index == prefix + len - 5)) {
239       is_set = true;
240       if (index[0] == 'r') {
241         strcpy(replace, "left");
242       }
243       else {
244         strcpy(replace, (index[1] == 'I') ? "LEFT" : "Left");
245       }
246       *index = 0;
247       BLI_strncpy(suffix, index + 5, name_len);
248     }
249     else if (((index = BLI_strcasestr(prefix, "left")) == prefix) || (index == prefix + len - 4)) {
250       is_set = true;
251       if (index[0] == 'l') {
252         strcpy(replace, "right");
253       }
254       else {
255         strcpy(replace, (index[1] == 'E') ? "RIGHT" : "Right");
256       }
257       *index = 0;
258       BLI_strncpy(suffix, index + 4, name_len);
259     }
260   }
261
262   BLI_snprintf(r_name, name_len, "%s%s%s%s", prefix, replace, suffix, number);
263 }
264
265 /* Unique name utils. */
266
267 /**
268  * Ensures name is unique (according to criteria specified by caller in unique_check callback),
269  * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
270  *
271  * \param unique_check: Return true if name is not unique
272  * \param arg: Additional arg to unique_check--meaning is up to caller
273  * \param defname: To initialize name if latter is empty
274  * \param delim: Delimits numeric suffix in name
275  * \param name: Name to be ensured unique
276  * \param name_len: Maximum length of name area
277  * \return true if there if the name was changed
278  */
279 bool BLI_uniquename_cb(UniquenameCheckCallback unique_check,
280                        void *arg,
281                        const char *defname,
282                        char delim,
283                        char *name,
284                        size_t name_len)
285 {
286   if (name[0] == '\0') {
287     BLI_strncpy(name, defname, name_len);
288   }
289
290   if (unique_check(arg, name)) {
291     char numstr[16];
292     char *tempname = alloca(name_len);
293     char *left = alloca(name_len);
294     int number;
295     size_t len = BLI_split_name_num(left, &number, name, delim);
296     do {
297       /* add 1 to account for \0 */
298       const size_t numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
299
300       /* highly unlikely the string only has enough room for the number
301        * but support anyway */
302       if ((len == 0) || (numlen >= name_len)) {
303         /* number is know not to be utf-8 */
304         BLI_strncpy(tempname, numstr, name_len);
305       }
306       else {
307         char *tempname_buf;
308         tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
309         memcpy(tempname_buf, numstr, numlen);
310       }
311     } while (unique_check(arg, tempname));
312
313     BLI_strncpy(name, tempname, name_len);
314
315     return true;
316   }
317
318   return false;
319 }
320
321 /* little helper macro for BLI_uniquename */
322 #ifndef GIVE_STRADDR
323 #  define GIVE_STRADDR(data, offset) (((char *)data) + offset)
324 #endif
325
326 /**
327  * Generic function to set a unique name. It is only designed to be used in situations
328  * where the name is part of the struct.
329  *
330  * For places where this is used, see constraint.c for example...
331  *
332  * \param name_offs: should be calculated using offsetof(structname, membername)
333  * macro from stddef.h
334  */
335 static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
336 {
337   Link *link;
338
339   for (link = list->first; link; link = link->next) {
340     if (link != vlink) {
341       if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
342         return true;
343       }
344     }
345   }
346
347   return false;
348 }
349
350 static bool uniquename_unique_check(void *arg, const char *name)
351 {
352   struct {
353     ListBase *lb;
354     void *vlink;
355     int name_offs;
356   } *data = arg;
357   return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
358 }
359
360 /**
361  * Ensures that the specified block has a unique name within the containing list,
362  * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
363  *
364  * \param list: List containing the block
365  * \param vlink: The block to check the name for
366  * \param defname: To initialize block name if latter is empty
367  * \param delim: Delimits numeric suffix in name
368  * \param name_offs: Offset of name within block structure
369  * \param name_len: Maximum length of name area
370  */
371 bool BLI_uniquename(
372     ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len)
373 {
374   struct {
375     ListBase *lb;
376     void *vlink;
377     int name_offs;
378   } data;
379   data.lb = list;
380   data.vlink = vlink;
381   data.name_offs = name_offs;
382
383   BLI_assert(name_len > 1);
384
385   /* See if we are given an empty string */
386   if (ELEM(NULL, vlink, defname)) {
387     return false;
388   }
389
390   return BLI_uniquename_cb(
391       uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
392 }
393
394 /* ------------------------------------------------------------------------- */
395 /** \name Join Strings
396  *
397  * For non array versions of these functions, use the macros:
398  * - #BLI_string_joinN
399  * - #BLI_string_join_by_sep_charN
400  * - #BLI_string_join_by_sep_char_with_tableN
401  *
402  * \{ */
403
404 /**
405  * Join an array of strings into a newly allocated, null terminated string.
406  */
407 char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
408 {
409   uint total_len = 1;
410   for (uint i = 0; i < strings_len; i++) {
411     total_len += strlen(strings[i]);
412   }
413   char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
414   char *c = result;
415   for (uint i = 0; i < strings_len; i++) {
416     c += BLI_strcpy_rlen(c, strings[i]);
417   }
418   return result;
419 }
420
421 /**
422  * A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
423  */
424 char *BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint strings_len)
425 {
426   uint total_len = 0;
427   for (uint i = 0; i < strings_len; i++) {
428     total_len += strlen(strings[i]) + 1;
429   }
430   if (total_len == 0) {
431     total_len = 1;
432   }
433
434   char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
435   char *c = result;
436   if (strings_len != 0) {
437     for (uint i = 0; i < strings_len; i++) {
438       c += BLI_strcpy_rlen(c, strings[i]);
439       *c = sep;
440       c++;
441     }
442     c--;
443   }
444   *c = '\0';
445   return result;
446 }
447
448 /**
449  * A version of #BLI_string_join_array_by_sep_charN that takes a table array.
450  * The new location of each string is written into this array.
451  */
452 char *BLI_string_join_array_by_sep_char_with_tableN(char sep,
453                                                     char *table[],
454                                                     const char *strings[],
455                                                     uint strings_len)
456 {
457   uint total_len = 0;
458   for (uint i = 0; i < strings_len; i++) {
459     total_len += strlen(strings[i]) + 1;
460   }
461   if (total_len == 0) {
462     total_len = 1;
463   }
464
465   char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
466   char *c = result;
467   if (strings_len != 0) {
468     for (uint i = 0; i < strings_len; i++) {
469       table[i] = c; /* <-- only difference to BLI_string_join_array_by_sep_charN. */
470       c += BLI_strcpy_rlen(c, strings[i]);
471       *c = sep;
472       c++;
473     }
474     c--;
475   }
476   *c = '\0';
477   return result;
478 }
479
480 /** \} */