Reworking layer2 subsystem
[oonf.git] / src-api / common / string.c
1
2 /*
3  * The olsr.org Optimized Link-State Routing daemon(olsrd)
4  * Copyright (c) 2004-2013, the olsr.org team - see HISTORY file
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * * Redistributions of source code must retain the above copyright
12  *   notice, this list of conditions and the following disclaimer.
13  * * Redistributions in binary form must reproduce the above copyright
14  *   notice, this list of conditions and the following disclaimer in
15  *   the documentation and/or other materials provided with the
16  *   distribution.
17  * * Neither the name of olsr.org, olsrd nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  * Visit http://www.olsr.org for more information.
35  *
36  * If you find this software useful feel free to make a donation
37  * to the project. For more information see the website or contact
38  * the copyright holders.
39  *
40  */
41
42 #include <assert.h>
43 #include <ctype.h>
44 #include <errno.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <stdio.h>
48
49 #include "common/string.h"
50
51 static const char *_get_human_readable_u64(char *out,
52     size_t out_len, uint64_t number, const char *unit, int fraction,
53     bool binary, bool raw);
54
55 /**
56  * @param size minimum size of block
57  * @return rounded up block size of STRARRAY_BLOCKSIZE
58  */
59 static INLINE size_t STRARRAY_MEMSIZE(const size_t b) {
60   return (b + STRARRAY_BLOCKSIZE-1) & (~(STRARRAY_BLOCKSIZE - 1));
61 }
62
63 /**
64  * A safer version of strncpy that ensures that the
65  * destination string will be null-terminated if its
66  * length is greater than 0.
67  * @param dest target string buffer
68  * @param src source string buffer
69  * @param size size of target buffer
70  * @return pointer to target buffer
71  */
72 char *
73 strscpy(char *dest, const char *src, size_t size)
74 {
75   if (dest == NULL || src == NULL || size == 0) {
76     return dest;
77   }
78
79   /* src does not need to be null terminated */
80   strncpy(dest, src, size-1);
81   dest[size-1] = 0;
82
83   return dest;
84 }
85
86 /**
87  * A safer version of strncat that ensures that
88  * the target buffer will be null-terminated if
89  * its size is greater than zero.
90  *
91  * If the target buffer is already full, it will
92  * not be changed.
93  * @param dest target string buffer
94  * @param src source string buffer
95  * @param size size of target buffer
96  * @return pointer to target buffer
97  */
98 char *
99 strscat(char *dest, const char *src, size_t size)
100 {
101   size_t l;
102
103   if (dest == NULL || src == NULL || size == 0 || *src == 0) {
104     return dest;
105   }
106
107   l = strlen(dest);
108   if (l < size) {
109     strscpy(dest + l, src, size - l);
110   }
111   return dest;
112 }
113
114 /**
115  * Removes leading and trailing whitespaces from a string.
116  * @param ptr input string to be modified string-pointer
117  * @return pointer to first non-whitespace character in string
118  */
119 char *
120 str_trim (char *ptr) {
121   char *end;
122
123   if (!ptr) {
124     return NULL;
125   }
126
127   /* skip leading whitespaces */
128   while (isspace(*ptr)) {
129     ptr++;
130   }
131
132   /* get end of string */
133   end = ptr + strlen(ptr) - 1;
134
135   /* remove trailing whitespaces */
136   while (end > ptr && isspace(*end)) {
137     *end-- = 0;
138   }
139   return ptr;
140 }
141
142 /**
143  * Check if a string starts with a certain word. The function
144  * is not case sensitive and does NOT modify the input strings.
145  * @param buffer pointer to string
146  * @param word pointer to the word
147  * @return pointer to the string behind the word, NULL if no match
148  */
149 const char *
150 str_hasnextword (const char *buffer, const char *word) {
151   /* sanity check */
152   if (buffer == NULL) {
153     return NULL;
154   }
155
156   /* skip whitespace prefix */
157   while (isblank(*buffer)) {
158     buffer++;
159   }
160
161   while (*word != 0 && *buffer != 0 && !isblank(*buffer) && tolower(*word) == tolower(*buffer)) {
162     word++;
163     buffer++;
164   }
165
166   /* complete match ? */
167   if (*word == 0 && (*buffer == 0 || isblank(*buffer))) {
168     while (isblank(*buffer)) {
169       buffer++;
170     }
171     return buffer;
172   }
173   return NULL;
174 }
175
176 /**
177  * Copies the next word of a constant stringbuffer into
178  * a second buffer.
179  * @param dst pointer to target buffer
180  * @param buffer constant source buffer
181  * @param len length of source buffer
182  * @return pointer to next word behind the copied word
183  */
184 const char *
185 str_cpynextword (char *dst, const char *buffer, size_t len) {
186   size_t i;
187
188   /* sanity check */
189   if (buffer == NULL) {
190     *dst = 0;
191     return NULL;
192   }
193
194   /* skip whitespace prefix */
195   while (isblank(*buffer)) {
196     buffer++;
197   }
198
199   /* copy next word */
200   i = 0;
201   while (*buffer != 0 && !isblank(*buffer) && i < len-1) {
202     dst[i++] = *buffer++;
203   }
204
205   /* terminate */
206   dst[i] = 0;
207
208   /* skip ahead in buffer */
209   while (isblank(*buffer)) {
210     buffer++;
211   }
212
213   if (*buffer) {
214     /* return next word */
215     return buffer;
216   }
217
218   /* end of buffer */
219   return NULL;
220 }
221
222 /**
223  * Printable is defined as all ascii characters >= 32 except
224  * 127 and 255.
225  * @param value stringpointer
226  * @return true if string only contains printable characters,
227  *   false otherwise
228  */
229 bool
230 str_is_printable(const char *value) {
231   const unsigned char *_value;
232
233   _value = (const unsigned char *)value;
234
235   while (*_value) {
236     if (!str_char_is_printable(*_value)) {
237       return false;
238     }
239     _value++;
240   }
241   return true;
242 }
243
244 /**
245  * Copy a string array into another array. This overwrites
246  * all data in the original array.
247  * @param dst destination array
248  * @param src source array
249  * @return 0 if array was copied, -1 if an error happened
250  */
251 int
252 strarray_copy(struct strarray *dst, const struct strarray *src) {
253   char *ptr;
254   size_t block;
255   if (src->value == NULL || src->length == 0) {
256     memset(dst, 0, sizeof(*dst));
257     return 0;
258   }
259
260   block = STRARRAY_MEMSIZE(src->length);
261   ptr = realloc(dst->value, block);
262   if (!ptr) {
263     return -1;
264   }
265
266   memcpy(ptr, src->value, src->length);
267   memset(ptr + src->length, 0, block - src->length);
268   dst->length = src->length;
269   dst->value = ptr;
270   return 0;
271 }
272
273 /**
274  * Appends a string to an existing string array. Only use this
275  * if the string-array value has been allocated with malloc/calloc.
276  * @param array pointer to string array object
277  * @param string pointer to string to append
278  * @return 0 if string was appended, -1 if an error happened
279  */
280 int
281 strarray_append(struct strarray *array, const char *string) {
282   size_t length, new_length;
283   char *ptr;
284
285   length = strlen(string) + 1;
286
287   new_length = array->length + length;
288   ptr = realloc(array->value, STRARRAY_MEMSIZE(new_length));
289   if (ptr == NULL) {
290     return -1;
291   }
292
293   memcpy(ptr + array->length, string, length);
294   array->value = ptr;
295   array->length = new_length;
296   return 0;
297 }
298
299 /**
300  * Put a string to in front of an existing string array. Only use this
301  * if the string-array value has been allocated with malloc/calloc.
302  * @param array pointer to string array object
303  * @param string pointer to string to append
304  * @return 0 if string was appended, -1 if an error happened
305  */
306 int
307 strarray_prepend(struct strarray *array, const char *string) {
308   size_t length, new_length;
309   char *ptr;
310
311   length = strlen(string) + 1;
312
313   new_length = array->length + length;
314   ptr = realloc(array->value, STRARRAY_MEMSIZE(new_length));
315   if (ptr == NULL) {
316     return -1;
317   }
318
319   memmove(ptr + length, ptr, array->length);
320   memcpy(ptr, string, length);
321   array->value = ptr;
322   array->length = new_length;
323   return 0;
324 }
325
326 /**
327  * Remove an element from a string array
328  * @param array pointer to string array object
329  * @param element an element to be removed from the array
330  * @param resize array afterwards
331  */
332 void
333 strarray_remove_ext(struct strarray *array,
334     char *element, bool resize) {
335   char *ptr1;
336   size_t len;
337
338   /* get length of element to remove */
339   len = strlen(element) + 1;
340   if (len == array->length) {
341     strarray_free(array);
342     return;
343   }
344
345   /* adjust length */
346   array->length -= len;
347
348   /* remove element from memory */
349   if (element <= array->value + array->length) {
350     memmove(element, element + len, array->length - (element - array->value));
351   }
352
353   if (!resize) {
354     return;
355   }
356
357   /* adjust memory block */
358   ptr1 = realloc(array->value, STRARRAY_MEMSIZE(array->length));
359   if (ptr1 == NULL) {
360     /* just keep the current memory block */
361     return;
362   }
363
364   /* adjust value pointer to new memory block */
365   array->value = ptr1;
366 }
367
368 /**
369  * @param array pointer to strarray object
370  * @return number of strings in string array
371  */
372 size_t
373 strarray_get_count(const struct strarray *array) {
374   size_t count = 0;
375   char *ptr;
376
377   FOR_ALL_STRINGS(array, ptr) {
378     count ++;
379   }
380   return count;
381 }
382
383 /**
384  * @param array pointer to strarray object
385  * @param idx position of the requested object inside the array
386  * @return string at the specified index, NULL if not found
387  */
388 char *
389 strarray_get(const struct strarray *array, size_t idx) {
390   size_t count = 0;
391   char *ptr;
392
393   FOR_ALL_STRINGS(array, ptr) {
394     if (count == idx) {
395       return ptr;
396     }
397     count ++;
398   }
399   return NULL;
400 }
401
402 /**
403  * Compare to stringarrays
404  * @param a1 pointer to array 1
405  * @param a2 pointer to array 2
406  * @return <0 if a1 is 'smaller' than a2, >0 if a1 is 'larger' than a2,
407  *   0 if both are the same.
408  */
409 int
410 strarray_cmp(const struct strarray *a1, const struct strarray *a2) {
411   int result;
412   size_t min_len;
413
414   if (a1 == NULL || a1->value == NULL) {
415     return (a2 == NULL || a2->value == NULL) ? 0 : -1;
416   }
417   if (a2 == NULL || a2->value == NULL) {
418     return 1;
419   }
420
421   if (a1->length > a2->length) {
422     min_len = a2->length;
423   }
424   else {
425     min_len = a1->length;
426   }
427
428   result = memcmp(a1->value, a2->value, min_len);
429   if (result == 0) {
430     if (a1->length > a2->length) {
431       return 1;
432     }
433     if (a1->length < a2->length) {
434       return -1;
435     }
436   }
437   return result;
438 }
439
440 /**
441  * Converts an unsigned 64 bit integer into a human readable number
442  * in string representation.
443  *
444  * '120000' will become '120 k' for example.
445  *
446  * @param out pointer to output buffer
447  * @param number number to convert.
448  * @param unit unit to be appended at the end, can be NULL
449  * @param maxfraction maximum number of fractional digits
450  * @param binary true if conversion should use 1024 as factor,
451  *   false for default 1000 conversion factor
452  * @param raw true if the whole text conversion should be bypassed
453  *   and only the raw number shall be written, false otherwise
454  * @return pointer to converted string
455  */
456 const char *
457 str_get_human_readable_u64(struct human_readable_str *out,
458     uint64_t number, const char *unit, int fraction,
459     bool binary, bool raw) {
460   return _get_human_readable_u64(
461       out->buf, sizeof(*out), number, unit, fraction, binary, raw);
462 }
463
464 /**
465  * Converts a signed 64 bit integer into a human readable number
466  * in string representation.
467  *
468  * '-120000' will become '-120 k' for example.
469  *
470  * @param out pointer to output buffer
471  * @param number number to convert.
472  * @param unit unit to be appended at the end, can be NULL
473  * @param fraction number of fractional digits of fractional digits
474  * @param binary true if conversion should use 1024 as factor,
475  *   false for default 1000 conversion factor
476  * @param raw true if the whole text conversion should be bypassed
477  *   and only the raw number shall be written, false otherwise
478  * @return pointer to converted string
479  */
480 const char *
481 str_get_human_readable_s64(struct human_readable_str *out,
482     int64_t number, const char *unit, int fraction,
483     bool binary, bool raw) {
484   char *outbuf = out->buf;
485   uint64_t num;
486   size_t len;
487
488   len = sizeof(*out);
489   if (number == INT64_MIN) {
490     *outbuf++ = '-';
491     num = 1ull<<63;
492     len--;
493   }
494   else if (number < 0) {
495     num = (uint64_t)(-number);
496   }
497   else {
498     num = (uint64_t)number;
499   }
500
501   return _get_human_readable_u64(
502       outbuf, len, num, unit, fraction, binary, raw);
503 }
504
505 int
506 str_parse_human_readable_s64(int64_t *dst, const char *hrn, int fractions, bool binary) {
507   const char *ptr;
508   int result;
509   uint64_t u64;
510
511   ptr = hrn;
512   if (*hrn == '-') {
513     ptr++;
514   }
515
516   result = str_parse_human_readable_u64(&u64, ptr, fractions, binary);
517   if (!result) {
518     if (*hrn == '-') {
519       *dst = -((int64_t)u64);
520     }
521     else {
522       *dst = (int64_t)u64;
523     }
524   }
525   return result;
526 }
527
528 int
529 str_parse_human_readable_u64(uint64_t *dst, const char *hrn, int fraction, bool binary) {
530   uint64_t num;
531   uint64_t factor;
532   uint64_t multiplicator;
533   int frac;
534   char *next = NULL;
535
536   errno = 0;
537   num = strtoull(hrn, &next, 10);
538   if (errno) {
539     return -1;
540   }
541
542   if (*next == 0) {
543     *dst = num;
544     return 0;
545   }
546
547   /* Handle fractional part */
548   frac = 0;
549   if (*next == '.') {
550     next++;
551     while (*next >='0' && *next <='9' && frac < fraction) {
552       num *= 10;
553       num += (*next - '0');
554       frac++;
555       next++;
556     }
557   }
558   while (frac++ < fraction) {
559     num *= 10;
560   }
561
562   /* handle spaces */
563   while (*next == ' ') {
564     next++;
565   }
566
567   factor = 1;
568   if (*next) {
569     /* handle iso-prefix */
570     if (next[1] != 0) {
571       return -1;
572     }
573
574     multiplicator = binary ? 1024 : 1000;
575
576     switch (next[0]) {
577       case 'E':
578         factor *= multiplicator;
579         /* no break */
580       case 'P':
581         factor *= multiplicator;
582         /* no break */
583       case 'T':
584         factor *= multiplicator;
585         /* no break */
586       case 'G':
587         factor *= multiplicator;
588         /* no break */
589       case 'M':
590         factor *= multiplicator;
591         /* no break */
592       case 'k':
593         factor *= multiplicator;
594         /* no break */
595       case ' ':
596         break;
597       default:
598         return -1;
599     }
600   }
601
602   if (num > UINT64_MAX / factor) {
603     /* this would be an integer overflow */
604     return -1;
605   }
606
607   *dst = num * factor;
608   return 0;
609 }
610
611 static const char *
612 _get_human_readable_u64(char *out, size_t out_len,
613     uint64_t number, const char *unit, int fraction,
614     bool binary, bool raw) {
615   static const char symbol[] = " kMGTPE";
616   uint64_t step, multiplier, print, n;
617   const char *unit_modifier;
618   size_t idx, len;
619
620   step = binary ? 1024 : 1000;
621   multiplier = 1;
622   unit_modifier = symbol;
623
624   while (fraction-- > 0) {
625     multiplier *= 10;
626   }
627
628   while (!raw && *unit_modifier != 0 && number >= multiplier * step) {
629     multiplier *= step;
630     unit_modifier++;
631   }
632
633   /* print whole */
634   idx = snprintf(out, out_len, "%"PRIu64, number / multiplier);
635   len = idx;
636
637   out[len++] = '.';
638   n = number;
639
640   if (*unit_modifier != ' ') {
641     fraction = 3;
642   }
643
644   while (true) {
645     n = n % multiplier;
646     if (n == 0 || fraction == 0) {
647       break;
648     }
649     fraction--;
650     multiplier /= 10;
651
652     print = n / multiplier;
653
654     assert (print < 10);
655     out[len++] = (char)'0' + (char)(print);
656     if (print) {
657       idx = len;
658     }
659   }
660
661   out[idx++] = ' ';
662   out[idx++] = *unit_modifier;
663   out[idx++] = 0;
664
665   if (unit) {
666     strscat(out, unit, out_len);
667   }
668
669   return out;
670 }