Blender  V2.93
string_utils.c
Go to the documentation of this file.
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 
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 
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 
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 
100 static bool is_char_sep(const char c)
101 {
102  return ELEM(c, '.', ' ', '-', '_');
103 }
104 
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 
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 
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 
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 
345 static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offset)
346 {
347  Link *link;
348 
349  for (link = list->first; link; link = link->next) {
350  if (link != vlink) {
351  if (STREQ(POINTER_OFFSET((const char *)link, name_offset), name)) {
352  return true;
353  }
354  }
355  }
356 
357  return false;
358 }
359 
360 static bool uniquename_unique_check(void *arg, const char *name)
361 {
362  struct {
363  ListBase *lb;
364  void *vlink;
365  int name_offset;
366  } *data = arg;
367  return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset);
368 }
369 
382  ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len)
383 {
384  struct {
385  ListBase *lb;
386  void *vlink;
387  int name_offset;
388  } data;
389  data.lb = list;
390  data.vlink = vlink;
391  data.name_offset = name_offset;
392 
393  BLI_assert(name_len > 1);
394 
395  /* See if we are given an empty string */
396  if (ELEM(NULL, vlink, defname)) {
397  return false;
398  }
399 
401  &data,
402  defname,
403  delim,
404  POINTER_OFFSET(vlink, name_offset),
405  name_len);
406 }
407 
408 /* ------------------------------------------------------------------------- */
420  size_t result_len,
421  const char *strings[],
422  uint strings_len)
423 {
424  char *c = result;
425  char *c_end = &result[result_len - 1];
426  for (uint i = 0; i < strings_len; i++) {
427  const char *p = strings[i];
428  while (*p && (c < c_end)) {
429  *c++ = *p++;
430  }
431  }
432  *c = '\0';
433  return c;
434 }
435 
440  char *result, size_t result_len, char sep, const char *strings[], uint strings_len)
441 {
442  char *c = result;
443  char *c_end = &result[result_len - 1];
444  for (uint i = 0; i < strings_len; i++) {
445  if (i != 0) {
446  if (c < c_end) {
447  *c++ = sep;
448  }
449  }
450  const char *p = strings[i];
451  while (*p && (c < c_end)) {
452  *c++ = *p++;
453  }
454  }
455  *c = '\0';
456  return c;
457 }
458 
462 char *BLI_string_join_arrayN(const char *strings[], uint strings_len)
463 {
464  uint total_len = 1;
465  for (uint i = 0; i < strings_len; i++) {
466  total_len += strlen(strings[i]);
467  }
468  char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
469  char *c = result;
470  for (uint i = 0; i < strings_len; i++) {
471  c += BLI_strcpy_rlen(c, strings[i]);
472  }
473  *c = '\0';
474  return result;
475 }
476 
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 
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 
#define BLI_assert(a)
Definition: BLI_assert.h:58
char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:578
size_t BLI_strcpy_rlen(char *__restrict dst, const char *__restrict src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:201
size_t BLI_strnlen(const char *str, const size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: string.c:878
size_t BLI_snprintf(char *__restrict dst, size_t maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
size_t BLI_strncpy_utf8_rlen(char *__restrict dst, const char *__restrict src, size_t maxncpy) ATTR_NONNULL()
Definition: string_utf8.c:274
bool(* UniquenameCheckCallback)(void *arg, const char *name)
unsigned int uint
Definition: BLI_sys_types.h:83
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
#define STREQ(a, b)
These structs are the foundation for all linked lists in the library system.
Read Guarded memory(de)allocation.
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static int left
static unsigned c
Definition: RandGen.cpp:97
static unsigned a[3]
Definition: RandGen.cpp:92
void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len)
Definition: string_utils.c:159
static bool is_char_sep(const char c)
Definition: string_utils.c:100
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len)
Definition: string_utils.c:130
bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len)
Definition: string_utils.c:381
char * BLI_string_join_arrayN(const char *strings[], uint strings_len)
Definition: string_utils.c:462
char * BLI_string_join_array_by_sep_charN(char sep, const char *strings[], uint strings_len)
Definition: string_utils.c:480
size_t BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
Definition: string_utils.c:55
char * BLI_string_join_array(char *result, size_t result_len, const char *strings[], uint strings_len)
Definition: string_utils.c:419
bool BLI_uniquename_cb(UniquenameCheckCallback unique_check, void *arg, const char *defname, char delim, char *name, size_t name_len)
Definition: string_utils.c:294
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len)
Definition: string_utils.c:109
static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offset)
Definition: string_utils.c:345
char * BLI_string_join_array_by_sep_char_with_tableN(char sep, char *table[], const char *strings[], uint strings_len)
Definition: string_utils.c:508
char * BLI_string_join_array_by_sep_char(char *result, size_t result_len, char sep, const char *strings[], uint strings_len)
Definition: string_utils.c:439
bool BLI_string_is_decimal(const char *string)
Definition: string_utils.c:85
static bool uniquename_unique_check(void *arg, const char *name)
Definition: string_utils.c:360
void * first
Definition: DNA_listBase.h:47
uint len