<p>Harald Welte <strong>merged</strong> this change.</p><p><a href="https://gerrit.osmocom.org/10317">View Change</a></p><div style="white-space:pre-wrap">Approvals:
  Jenkins Builder: Verified
  Harald Welte: Looks good to me, approved

</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">add libosmcore utilities<br><br>osmo_hexdump is particularly useful.<br>previously it was only defined, but not implemented.<br>this cause random behaviour upon call, often resulting in<br>memory corruption.<br><br>Change-Id: Ifd9120fa951f41693903fb657d10826959f1599f<br>---<br>A firmware/libosmocore/source/utils.c<br>1 file changed, 632 insertions(+), 0 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/firmware/libosmocore/source/utils.c b/firmware/libosmocore/source/utils.c</span><br><span>new file mode 100644</span><br><span>index 0000000..3096572</span><br><span>--- /dev/null</span><br><span>+++ b/firmware/libosmocore/source/utils.c</span><br><span>@@ -0,0 +1,632 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2011 by Harald Welte <laforge@gnumonks.org></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2011 by Sylvain Munaut <tnt@246tNt.com></span><br><span style="color: hsl(120, 100%, 40%);">+ * (C) 2014 by Nils O. Selåsdal <noselasd@fiane.dyndns.org></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * All Rights Reserved</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * SPDX-License-Identifier: GPL-2.0+</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software; you can redistribute it and/or modify</span><br><span style="color: hsl(120, 100%, 40%);">+ * it under the terms of the GNU General Public License as published by</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Free Software Foundation; either version 2 of the License, or</span><br><span style="color: hsl(120, 100%, 40%);">+ * (at your option) any later version.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is distributed in the hope that it will be useful,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but WITHOUT ANY WARRANTY; without even the implied warranty of</span><br><span style="color: hsl(120, 100%, 40%);">+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span><br><span style="color: hsl(120, 100%, 40%);">+ * GNU General Public License for more details.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * You should have received a copy of the GNU General Public License along</span><br><span style="color: hsl(120, 100%, 40%);">+ * with this program; if not, write to the Free Software Foundation, Inc.,</span><br><span style="color: hsl(120, 100%, 40%);">+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdbool.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <string.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdint.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <errno.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <stdio.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <inttypes.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/utils.h></span><br><span style="color: hsl(120, 100%, 40%);">+#include <osmocom/core/bit64gen.h></span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! \addtogroup utils</span><br><span style="color: hsl(120, 100%, 40%);">+ * @{</span><br><span style="color: hsl(120, 100%, 40%);">+ * various utility routines</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \file utils.c */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char namebuf[255];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! get human-readable string for given value</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] vs Array of value_string tuples</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] val Value to be converted</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns pointer to human-readable string</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * If val is found in vs, the array's string entry is returned. Otherwise, an</span><br><span style="color: hsl(120, 100%, 40%);">+ * "unknown" string containing the actual value is composed in a static buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ * that is reused across invocations.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *get_value_string(const struct value_string *vs, uint32_t val)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       const char *str = get_value_string_or_null(vs, val);</span><br><span style="color: hsl(120, 100%, 40%);">+  if (str)</span><br><span style="color: hsl(120, 100%, 40%);">+              return str;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ snprintf(namebuf, sizeof(namebuf), "unknown 0x%"PRIx32, val);</span><br><span style="color: hsl(120, 100%, 40%);">+       namebuf[sizeof(namebuf) - 1] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+  return namebuf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! get human-readable string or NULL for given value</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] vs Array of value_string tuples</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] val Value to be converted</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns pointer to human-readable string or NULL if val is not found</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *get_value_string_or_null(const struct value_string *vs,</span><br><span style="color: hsl(120, 100%, 40%);">+                                 uint32_t val)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0;; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (vs[i].value == 0 && vs[i].str == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (vs[i].value == val)</span><br><span style="color: hsl(120, 100%, 40%);">+                       return vs[i].str;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! get numeric value for given human-readable string</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] vs Array of value_string tuples</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] str human-readable string</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns numeric value (>0) or negative numer in case of error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int get_string_value(const struct value_string *vs, const char *str)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      for (i = 0;; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+           if (vs[i].value == 0 && vs[i].str == NULL)</span><br><span style="color: hsl(120, 100%, 40%);">+                    break;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (!strcasecmp(vs[i].str, str))</span><br><span style="color: hsl(120, 100%, 40%);">+                      return vs[i].value;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     return -EINVAL;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert BCD-encoded digit into printable character</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] bcd A single BCD-encoded digit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns single printable character</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char osmo_bcd2char(uint8_t bcd)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (bcd < 0xa)</span><br><span style="color: hsl(120, 100%, 40%);">+             return '0' + bcd;</span><br><span style="color: hsl(120, 100%, 40%);">+     else</span><br><span style="color: hsl(120, 100%, 40%);">+          return 'A' + (bcd - 0xa);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert number in ASCII to BCD value</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] c ASCII character</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns BCD encoded value of character</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t osmo_char2bcd(char c)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        if (c >= '0' && c <= '9')</span><br><span style="color: hsl(120, 100%, 40%);">+               return c - 0x30;</span><br><span style="color: hsl(120, 100%, 40%);">+      else if (c >= 'A' && c <= 'F')</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0xa + (c - 'A');</span><br><span style="color: hsl(120, 100%, 40%);">+       else if (c >= 'a' && c <= 'f')</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0xa + (c - 'a');</span><br><span style="color: hsl(120, 100%, 40%);">+       else</span><br><span style="color: hsl(120, 100%, 40%);">+          return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Parse a string containing hexadecimal digits</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] str string containing ASCII encoded hexadecimal digits</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] b output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] max_len maximum space in output buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns number of parsed octets, or -1 on error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_hexparse(const char *str, uint8_t *b, int max_len)</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  char c;</span><br><span style="color: hsl(120, 100%, 40%);">+       uint8_t v;</span><br><span style="color: hsl(120, 100%, 40%);">+    const char *strpos;</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int nibblepos = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ memset(b, 0x00, max_len);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   for (strpos = str; (c = *strpos); strpos++) {</span><br><span style="color: hsl(120, 100%, 40%);">+         /* skip whitespace */</span><br><span style="color: hsl(120, 100%, 40%);">+         if (c == ' ' || c == '\t' || c == '\n' || c == '\r')</span><br><span style="color: hsl(120, 100%, 40%);">+                  continue;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           /* If the buffer is too small, error out */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (nibblepos >= (max_len << 1))</span><br><span style="color: hsl(120, 100%, 40%);">+                     return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          if (c >= '0' && c <= '9')</span><br><span style="color: hsl(120, 100%, 40%);">+                       v = c - '0';</span><br><span style="color: hsl(120, 100%, 40%);">+          else if (c >= 'a' && c <= 'f')</span><br><span style="color: hsl(120, 100%, 40%);">+                  v = 10 + (c - 'a');</span><br><span style="color: hsl(120, 100%, 40%);">+           else if (c >= 'A' && c <= 'F')</span><br><span style="color: hsl(120, 100%, 40%);">+                  v = 10 + (c - 'A');</span><br><span style="color: hsl(120, 100%, 40%);">+           else</span><br><span style="color: hsl(120, 100%, 40%);">+                  return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          b[nibblepos >> 1] |= v << (nibblepos & 1 ? 0 : 4);</span><br><span style="color: hsl(120, 100%, 40%);">+            nibblepos ++;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   /* In case of uneven amount of digits, the last byte is not complete</span><br><span style="color: hsl(120, 100%, 40%);">+   * and that's an error. */</span><br><span style="color: hsl(120, 100%, 40%);">+        if (nibblepos & 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  return nibblepos >> 1;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char hexd_buff[4096];</span><br><span style="color: hsl(120, 100%, 40%);">+static const char hex_chars[] = "0123456789abcdef";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *_osmo_hexdump(const unsigned char *buf, int len, const char *delim)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ int i;</span><br><span style="color: hsl(120, 100%, 40%);">+        char *cur = hexd_buff;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      hexd_buff[0] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                const char *delimp = delim;</span><br><span style="color: hsl(120, 100%, 40%);">+           int len_remain = sizeof(hexd_buff) - (cur - hexd_buff);</span><br><span style="color: hsl(120, 100%, 40%);">+               if (len_remain < 3)</span><br><span style="color: hsl(120, 100%, 40%);">+                        break;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+              *cur++ = hex_chars[buf[i] >> 4];</span><br><span style="color: hsl(120, 100%, 40%);">+                *cur++ = hex_chars[buf[i] & 0xf];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               while (len_remain > 1 && *delimp) {</span><br><span style="color: hsl(120, 100%, 40%);">+                        *cur++ = *delimp++;</span><br><span style="color: hsl(120, 100%, 40%);">+                   len_remain--;</span><br><span style="color: hsl(120, 100%, 40%);">+         }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           *cur = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     }</span><br><span style="color: hsl(120, 100%, 40%);">+     hexd_buff[sizeof(hexd_buff)-1] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   return hexd_buff;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert a sequence of unpacked bits to ASCII string</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] bits A sequence of unpacked bits</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len Length of bits</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_ubit_dump(const uint8_t *bits, unsigned int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (len > sizeof(hexd_buff)-1)</span><br><span style="color: hsl(120, 100%, 40%);">+             len = sizeof(hexd_buff)-1;</span><br><span style="color: hsl(120, 100%, 40%);">+    memset(hexd_buff, 0, sizeof(hexd_buff));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    for (i = 0; i < len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                char outch;</span><br><span style="color: hsl(120, 100%, 40%);">+           switch (bits[i]) {</span><br><span style="color: hsl(120, 100%, 40%);">+            case 0:</span><br><span style="color: hsl(120, 100%, 40%);">+                       outch = '0';</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 0xff:</span><br><span style="color: hsl(120, 100%, 40%);">+                    outch = '?';</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                case 1:</span><br><span style="color: hsl(120, 100%, 40%);">+                       outch = '1';</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      outch = 'E';</span><br><span style="color: hsl(120, 100%, 40%);">+                  break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             hexd_buff[i] = outch;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+     hexd_buff[sizeof(hexd_buff)-1] = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+   return hexd_buff;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert binary sequence to hexadecimal ASCII string</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] buf pointer to sequence of bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] len length of buf in number of bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns pointer to zero-terminated string</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function will print a sequence of bytes as hexadecimal numbers,</span><br><span style="color: hsl(120, 100%, 40%);">+ * adding one space character between each byte (e.g. "1a ef d9")</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The maximum size of the output buffer is 4096 bytes, i.e. the maximum</span><br><span style="color: hsl(120, 100%, 40%);">+ * number of input bytes that can be printed in one call is 1365!</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_hexdump(const unsigned char *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+       return _osmo_hexdump(buf, len, " ");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert binary sequence to hexadecimal ASCII string</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] buf pointer to sequence of bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] len length of buf in number of bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns pointer to zero-terminated string</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This function will print a sequence of bytes as hexadecimal numbers,</span><br><span style="color: hsl(120, 100%, 40%);">+ * without any space character between each byte (e.g. "1aefd9")</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * The maximum size of the output buffer is 4096 bytes, i.e. the maximum</span><br><span style="color: hsl(120, 100%, 40%);">+ * number of input bytes that can be printed in one call is 2048!</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_hexdump_nospc(const unsigned char *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     return _osmo_hexdump(buf, len, "");</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/* Compat with previous typo to preserve abi */</span><br><span style="color: hsl(120, 100%, 40%);">+char *osmo_osmo_hexdump_nospc(const unsigned char *buf, int len)</span><br><span style="color: hsl(120, 100%, 40%);">+#if defined(__MACH__) && defined(__APPLE__)</span><br><span style="color: hsl(120, 100%, 40%);">+    ;</span><br><span style="color: hsl(120, 100%, 40%);">+#else</span><br><span style="color: hsl(120, 100%, 40%);">+      __attribute__((weak, alias("osmo_hexdump_nospc")));</span><br><span style="color: hsl(120, 100%, 40%);">+#endif</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include <ctype.h></span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert an entire string to lower case</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] out output string, caller-allocated</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] in input string</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_str2lower(char *out, const char *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+    unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < strlen(in); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+           out[i] = tolower((const unsigned char)in[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+ out[strlen(in)] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Convert an entire string to upper case</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] out output string, caller-allocated</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] in input string</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+void osmo_str2upper(char *out, const char *in)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+     for (i = 0; i < strlen(in); i++)</span><br><span style="color: hsl(120, 100%, 40%);">+           out[i] = toupper((const unsigned char)in[i]);</span><br><span style="color: hsl(120, 100%, 40%);">+ out[strlen(in)] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Wishful thinking to generate a constant time compare</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] exp Expected data</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] rel Comparison value</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] count Number of bytes to compare</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns 1 in case \a exp equals \a rel; zero otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Compare count bytes of exp to rel. Return 0 if they are identical, 1</span><br><span style="color: hsl(120, 100%, 40%);">+ * otherwise. Do not return a mismatch on the first mismatching byte,</span><br><span style="color: hsl(120, 100%, 40%);">+ * but always compare all bytes, regardless. The idea is that the amount of</span><br><span style="color: hsl(120, 100%, 40%);">+ * matching bytes cannot be inferred from the time the comparison took. */</span><br><span style="color: hsl(120, 100%, 40%);">+int osmo_constant_time_cmp(const uint8_t *exp, const uint8_t *rel, const int count)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      int x = 0, i;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < count; ++i)</span><br><span style="color: hsl(120, 100%, 40%);">+                x |= exp[i] ^ rel[i];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       /* if x is zero, all data was identical */</span><br><span style="color: hsl(120, 100%, 40%);">+    return x? 1 : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Generic retrieval of 1..8 bytes as big-endian uint64_t</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] data Input data as byte-array</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] data_len Length of \a data in octets</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns uint64_t of \a data interpreted as big-endian</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is like osmo_load64be_ext, except that if data_len is less than</span><br><span style="color: hsl(120, 100%, 40%);">+ * sizeof(uint64_t), the data is interpreted as the least significant bytes</span><br><span style="color: hsl(120, 100%, 40%);">+ * (osmo_load64be_ext loads them as the most significant bytes into the</span><br><span style="color: hsl(120, 100%, 40%);">+ * returned uint64_t). In this way, any integer size up to 64 bits can be</span><br><span style="color: hsl(120, 100%, 40%);">+ * decoded conveniently by using sizeof(), without the need to call specific</span><br><span style="color: hsl(120, 100%, 40%);">+ * numbered functions (osmo_load16, 32, ...). */</span><br><span style="color: hsl(120, 100%, 40%);">+uint64_t osmo_decode_big_endian(const uint8_t *data, size_t data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      uint64_t value = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ while (data_len > 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+             value = (value << 8) + *data;</span><br><span style="color: hsl(120, 100%, 40%);">+           data += 1;</span><br><span style="color: hsl(120, 100%, 40%);">+            data_len -= 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return value;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Generic big-endian encoding of big endian number up to 64bit</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] value unsigned integer value to be stored</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] data_len number of octets </span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns static buffer containing big-endian stored value</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This is like osmo_store64be_ext, except that this returns a static buffer of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the result (for convenience, but not threadsafe). If data_len is less than</span><br><span style="color: hsl(120, 100%, 40%);">+ * sizeof(uint64_t), only the least significant bytes of value are encoded. */</span><br><span style="color: hsl(120, 100%, 40%);">+uint8_t *osmo_encode_big_endian(uint64_t value, size_t data_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     static uint8_t buf[sizeof(uint64_t)];</span><br><span style="color: hsl(120, 100%, 40%);">+ OSMO_ASSERT(data_len <= ARRAY_SIZE(buf));</span><br><span style="color: hsl(120, 100%, 40%);">+  osmo_store64be_ext(value, buf, data_len);</span><br><span style="color: hsl(120, 100%, 40%);">+     return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Copy a C-string into a sized buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] src source string</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[out] dst destination string</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] siz size of the \a dst buffer</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns length of \a src</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copy at most \a siz bytes from \a src to \a dst, ensuring that the result is</span><br><span style="color: hsl(120, 100%, 40%);">+ * NUL terminated. The NUL character is included in \a siz, i.e. passing the</span><br><span style="color: hsl(120, 100%, 40%);">+ * actual sizeof(*dst) is correct.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+size_t osmo_strlcpy(char *dst, const char *src, size_t siz)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  size_t ret = src ? strlen(src) : 0;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (siz) {</span><br><span style="color: hsl(120, 100%, 40%);">+            size_t len = (ret >= siz) ? siz - 1 : ret;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (src)</span><br><span style="color: hsl(120, 100%, 40%);">+                      memcpy(dst, src, len);</span><br><span style="color: hsl(120, 100%, 40%);">+                dst[len] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     return ret;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Validate that a given string is a hex string within given size limits.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Note that each hex digit amounts to a nibble, so if checking for a hex</span><br><span style="color: hsl(120, 100%, 40%);">+ * string to result in N bytes, pass amount of digits as 2*N.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param str  A nul-terminated string to validate, or NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param min_digits  least permitted amount of digits.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param max_digits  most permitted amount of digits.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param require_even  if true, require an even amount of digits.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns true when the hex_str contains only hexadecimal digits (no</span><br><span style="color: hsl(120, 100%, 40%);">+ *          whitespace) and matches the requested length; also true</span><br><span style="color: hsl(120, 100%, 40%);">+ *          when min_digits <= 0 and str is NULL.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+bool osmo_is_hexstr(const char *str, int min_digits, int max_digits,</span><br><span style="color: hsl(120, 100%, 40%);">+                   bool require_even)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     int len;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* Use unsigned char * to avoid a compiler warning of</span><br><span style="color: hsl(120, 100%, 40%);">+  * "error: array subscript has type 'char' [-Werror=char-subscripts]" */</span><br><span style="color: hsl(120, 100%, 40%);">+    const unsigned char *pos = (const unsigned char*)str;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!pos)</span><br><span style="color: hsl(120, 100%, 40%);">+             return min_digits < 1;</span><br><span style="color: hsl(120, 100%, 40%);">+     for (len = 0; *pos && len < max_digits; len++, pos++)</span><br><span style="color: hsl(120, 100%, 40%);">+              if (!isxdigit(*pos))</span><br><span style="color: hsl(120, 100%, 40%);">+                  return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (len < min_digits)</span><br><span style="color: hsl(120, 100%, 40%);">+              return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ /* With not too many digits, we should have reached *str == nul */</span><br><span style="color: hsl(120, 100%, 40%);">+    if (*pos)</span><br><span style="color: hsl(120, 100%, 40%);">+             return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (require_even && (len & 1))</span><br><span style="color: hsl(120, 100%, 40%);">+            return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Determine if a given identifier is valid, i.e. doesn't contain illegal chars</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] str String to validate</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] sep_chars Permitted separation characters between identifiers.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns true in case \a str contains only valid identifiers and sep_chars, false otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+bool osmo_separated_identifiers_valid(const char *str, const char *sep_chars)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ /* characters that are illegal in names */</span><br><span style="color: hsl(120, 100%, 40%);">+    static const char illegal_chars[] = "., {}[]()<>|~\\^`'\"?=;/+*&%$#!";</span><br><span style="color: hsl(120, 100%, 40%);">+   unsigned int i;</span><br><span style="color: hsl(120, 100%, 40%);">+       size_t len;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* an empty string is not a valid identifier */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (!str || (len = strlen(str)) == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+         return false;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       for (i = 0; i < len; i++) {</span><br><span style="color: hsl(120, 100%, 40%);">+                if (sep_chars && strchr(sep_chars, str[i]))</span><br><span style="color: hsl(120, 100%, 40%);">+                   continue;</span><br><span style="color: hsl(120, 100%, 40%);">+             /* check for 7-bit ASCII */</span><br><span style="color: hsl(120, 100%, 40%);">+           if (str[i] & 0x80)</span><br><span style="color: hsl(120, 100%, 40%);">+                        return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         if (!isprint((int)str[i]))</span><br><span style="color: hsl(120, 100%, 40%);">+                    return false;</span><br><span style="color: hsl(120, 100%, 40%);">+         /* check for some explicit reserved control characters */</span><br><span style="color: hsl(120, 100%, 40%);">+             if (strchr(illegal_chars, str[i]))</span><br><span style="color: hsl(120, 100%, 40%);">+                    return false;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   return true;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Determine if a given identifier is valid, i.e. doesn't contain illegal chars</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \param[in] str String to validate</span><br><span style="color: hsl(120, 100%, 40%);">+ *  \returns true in case \a str contains valid identifier, false otherwise</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+bool osmo_identifier_valid(const char *str)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+      return osmo_separated_identifiers_valid(str, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return the string with all non-printable characters escaped.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] str  A string that may contain any characters.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len  Pass -1 to print until nul char, or >= 0 to force a length.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[inout] buf  string buffer to write escaped characters to.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] bufsize  size of \a buf.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf containing an escaped representation, possibly truncated, or str itself.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_escape_str_buf(const char *str, int in_len, char *buf, size_t bufsize)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+   int in_pos = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+       int next_unprintable = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+     int out_pos = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+      char *out = buf;</span><br><span style="color: hsl(120, 100%, 40%);">+      /* -1 to leave space for a final \0 */</span><br><span style="color: hsl(120, 100%, 40%);">+        int out_len = bufsize-1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    if (!str)</span><br><span style="color: hsl(120, 100%, 40%);">+             return "(null)";</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+  if (in_len < 0)</span><br><span style="color: hsl(120, 100%, 40%);">+            in_len = strlen(str);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+       while (in_pos < in_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+          for (next_unprintable = in_pos;</span><br><span style="color: hsl(120, 100%, 40%);">+                    next_unprintable < in_len && isprint((int)str[next_unprintable])</span><br><span style="color: hsl(120, 100%, 40%);">+                   && str[next_unprintable] != '"'</span><br><span style="color: hsl(120, 100%, 40%);">+                  && str[next_unprintable] != '\\';</span><br><span style="color: hsl(120, 100%, 40%);">+                     next_unprintable++);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+           if (next_unprintable == in_len</span><br><span style="color: hsl(120, 100%, 40%);">+                    && in_pos == 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                   return str;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+         while (in_pos < next_unprintable && out_pos < out_len)</span><br><span style="color: hsl(120, 100%, 40%);">+                  out[out_pos++] = str[in_pos++];</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+             if (out_pos == out_len || in_pos == in_len)</span><br><span style="color: hsl(120, 100%, 40%);">+                   goto done;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          switch (str[next_unprintable]) {</span><br><span style="color: hsl(120, 100%, 40%);">+#define BACKSLASH_CASE(c, repr) \</span><br><span style="color: hsl(120, 100%, 40%);">+           case c: \</span><br><span style="color: hsl(120, 100%, 40%);">+                     if (out_pos > out_len-2) \</span><br><span style="color: hsl(120, 100%, 40%);">+                         goto done; \</span><br><span style="color: hsl(120, 100%, 40%);">+                  out[out_pos++] = '\\'; \</span><br><span style="color: hsl(120, 100%, 40%);">+                      out[out_pos++] = repr; \</span><br><span style="color: hsl(120, 100%, 40%);">+                      break</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+               BACKSLASH_CASE('\n', 'n');</span><br><span style="color: hsl(120, 100%, 40%);">+            BACKSLASH_CASE('\r', 'r');</span><br><span style="color: hsl(120, 100%, 40%);">+            BACKSLASH_CASE('\t', 't');</span><br><span style="color: hsl(120, 100%, 40%);">+            BACKSLASH_CASE('\0', '0');</span><br><span style="color: hsl(120, 100%, 40%);">+            BACKSLASH_CASE('\a', 'a');</span><br><span style="color: hsl(120, 100%, 40%);">+            BACKSLASH_CASE('\b', 'b');</span><br><span style="color: hsl(120, 100%, 40%);">+            BACKSLASH_CASE('\v', 'v');</span><br><span style="color: hsl(120, 100%, 40%);">+            BACKSLASH_CASE('\f', 'f');</span><br><span style="color: hsl(120, 100%, 40%);">+            BACKSLASH_CASE('\\', '\\');</span><br><span style="color: hsl(120, 100%, 40%);">+           BACKSLASH_CASE('"', '"');</span><br><span style="color: hsl(120, 100%, 40%);">+#undef BACKSLASH_CASE</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+          default:</span><br><span style="color: hsl(120, 100%, 40%);">+                      out_pos += snprintf(&out[out_pos], out_len - out_pos, "\\%u", (unsigned char)str[in_pos]);</span><br><span style="color: hsl(120, 100%, 40%);">+                      if (out_pos > out_len) {</span><br><span style="color: hsl(120, 100%, 40%);">+                           out_pos = out_len;</span><br><span style="color: hsl(120, 100%, 40%);">+                            goto done;</span><br><span style="color: hsl(120, 100%, 40%);">+                    }</span><br><span style="color: hsl(120, 100%, 40%);">+                     break;</span><br><span style="color: hsl(120, 100%, 40%);">+                }</span><br><span style="color: hsl(120, 100%, 40%);">+             in_pos ++;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+done:</span><br><span style="color: hsl(120, 100%, 40%);">+    out[out_pos] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+  return out;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Return the string with all non-printable characters escaped.</span><br><span style="color: hsl(120, 100%, 40%);">+ * Call osmo_escape_str_buf() with a static buffer.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] str  A string that may contain any characters.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len  Pass -1 to print until nul char, or >= 0 to force a length.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf containing an escaped representation, possibly truncated, or str itself.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_escape_str(const char *str, int in_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return osmo_escape_str_buf(str, in_len, namebuf, sizeof(namebuf));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! Like osmo_escape_str(), but returns double-quotes around a string, or "NULL" for a NULL string.</span><br><span style="color: hsl(120, 100%, 40%);">+ * This allows passing any char* value and get its C representation as string.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] str  A string that may contain any characters.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param[in] len  Pass -1 to print until nul char, or >= 0 to force a length.</span><br><span style="color: hsl(120, 100%, 40%);">+ * \returns buf containing an escaped representation, possibly truncated, or str itself.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_quote_str_buf(const char *str, int in_len, char *buf, size_t bufsize)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+     const char *res;</span><br><span style="color: hsl(120, 100%, 40%);">+      int l;</span><br><span style="color: hsl(120, 100%, 40%);">+        if (!str)</span><br><span style="color: hsl(120, 100%, 40%);">+             return "NULL";</span><br><span style="color: hsl(120, 100%, 40%);">+      if (bufsize < 3)</span><br><span style="color: hsl(120, 100%, 40%);">+           return "<buf-too-small>";</span><br><span style="color: hsl(120, 100%, 40%);">+     buf[0] = '"';</span><br><span style="color: hsl(120, 100%, 40%);">+    res = osmo_escape_str_buf(str, in_len, buf + 1, bufsize - 2);</span><br><span style="color: hsl(120, 100%, 40%);">+ /* if osmo_escape_str_buf() returned the str itself, we need to copy it to buf to be able to</span><br><span style="color: hsl(120, 100%, 40%);">+   * quote it. */</span><br><span style="color: hsl(120, 100%, 40%);">+       if (res == str) {</span><br><span style="color: hsl(120, 100%, 40%);">+             /* max_len = bufsize - two quotes - nul term */</span><br><span style="color: hsl(120, 100%, 40%);">+               int max_len = bufsize - 2 - 1;</span><br><span style="color: hsl(120, 100%, 40%);">+                if (in_len >= 0)</span><br><span style="color: hsl(120, 100%, 40%);">+                   max_len = OSMO_MIN(in_len, max_len);</span><br><span style="color: hsl(120, 100%, 40%);">+          /* It is not allowed to pass unterminated strings into osmo_strlcpy() :/ */</span><br><span style="color: hsl(120, 100%, 40%);">+           strncpy(buf + 1, str, max_len);</span><br><span style="color: hsl(120, 100%, 40%);">+               buf[1 + max_len] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+      }</span><br><span style="color: hsl(120, 100%, 40%);">+     l = strlen(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+      buf[l] = '"';</span><br><span style="color: hsl(120, 100%, 40%);">+    buf[l+1] = '\0'; /* both osmo_escape_str_buf() and max_len above ensure room for '\0' */</span><br><span style="color: hsl(120, 100%, 40%);">+      return buf;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+const char *osmo_quote_str(const char *str, int in_len)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+  return osmo_quote_str_buf(str, in_len, namebuf, sizeof(namebuf));</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! perform an integer square root operation on unsigned 32bit integer.</span><br><span style="color: hsl(120, 100%, 40%);">+ *  This implementation is taken from "Hacker's Delight" Figure 11-1 "Integer square root, Newton's</span><br><span style="color: hsl(120, 100%, 40%);">+ *  method", which can also be found at http://www.hackersdelight.org/hdcodetxt/isqrt.c.txt */</span><br><span style="color: hsl(120, 100%, 40%);">+uint32_t osmo_isqrt32(uint32_t x)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+        uint32_t x1;</span><br><span style="color: hsl(120, 100%, 40%);">+  int s, g0, g1;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+      if (x <= 1)</span><br><span style="color: hsl(120, 100%, 40%);">+                return x;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   s = 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        x1 = x - 1;</span><br><span style="color: hsl(120, 100%, 40%);">+   if (x1 > 0xffff) {</span><br><span style="color: hsl(120, 100%, 40%);">+         s = s + 8;</span><br><span style="color: hsl(120, 100%, 40%);">+            x1 = x1 >> 16;</span><br><span style="color: hsl(120, 100%, 40%);">+  }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (x1 > 0xff) {</span><br><span style="color: hsl(120, 100%, 40%);">+           s = s + 4;</span><br><span style="color: hsl(120, 100%, 40%);">+            x1 = x1 >> 8;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (x1 > 0xf) {</span><br><span style="color: hsl(120, 100%, 40%);">+            s = s + 2;</span><br><span style="color: hsl(120, 100%, 40%);">+            x1 = x1 >> 4;</span><br><span style="color: hsl(120, 100%, 40%);">+   }</span><br><span style="color: hsl(120, 100%, 40%);">+     if (x1 > 0x3) {</span><br><span style="color: hsl(120, 100%, 40%);">+            s = s + 1;</span><br><span style="color: hsl(120, 100%, 40%);">+    }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+   g0 = 1 << s;                      /* g0 = 2**s */</span><br><span style="color: hsl(120, 100%, 40%);">+       g1 = (g0 + (x >> s)) >> 1;  /* g1 = (g0 + x/g0)/2 */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+    /* converges after four to five divisions for arguments up to 16,785,407 */</span><br><span style="color: hsl(120, 100%, 40%);">+   while (g1 < g0) {</span><br><span style="color: hsl(120, 100%, 40%);">+          g0 = g1;</span><br><span style="color: hsl(120, 100%, 40%);">+              g1 = (g0 + (x/g0)) >> 1;</span><br><span style="color: hsl(120, 100%, 40%);">+        }</span><br><span style="color: hsl(120, 100%, 40%);">+     return g0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*! @} */</span><br><span></span><br></pre><p>To view, visit <a href="https://gerrit.osmocom.org/10317">change 10317</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.osmocom.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.osmocom.org/10317"/><meta itemprop="name" content="View Change"/></div></div>

<div style="display:none"> Gerrit-Project: simtrace2 </div>
<div style="display:none"> Gerrit-Branch: master </div>
<div style="display:none"> Gerrit-MessageType: merged </div>
<div style="display:none"> Gerrit-Change-Id: Ifd9120fa951f41693903fb657d10826959f1599f </div>
<div style="display:none"> Gerrit-Change-Number: 10317 </div>
<div style="display:none"> Gerrit-PatchSet: 2 </div>
<div style="display:none"> Gerrit-Owner: Kévin Redon <kredon@sysmocom.de> </div>
<div style="display:none"> Gerrit-Reviewer: Harald Welte <laforge@gnumonks.org> </div>
<div style="display:none"> Gerrit-Reviewer: Jenkins Builder </div>