treewide: Replace <name>_cnt by n_<name>s and <name>_cap by allocated_<name>.
[pspp] / src / libpspp / str.c
index c227f7f6989da54c915b82884f6b6ee453a63ebf..3c094902509426266cf97eb1caef393dc976451f 100644 (file)
@@ -26,6 +26,7 @@
 #include <unistr.h>
 
 #include "libpspp/cast.h"
+#include "libpspp/i18n.h"
 #include "libpspp/message.h"
 #include "libpspp/pool.h"
 
@@ -143,9 +144,9 @@ buf_copy_str_lpad (char *dst, size_t dst_size, const char *src, char pad)
     memcpy (dst, src, dst_size);
   else
     {
-      size_t pad_cnt = dst_size - src_len;
-      memset (&dst[0], pad, pad_cnt);
-      memcpy (dst + pad_cnt, src, src_len);
+      size_t n_pad = dst_size - src_len;
+      memset (&dst[0], pad, n_pad);
+      memcpy (dst + n_pad, src, src_len);
     }
 }
 
@@ -301,6 +302,39 @@ overflow:
   return false;
 }
 
+/* Copies IN to buffer OUT with size OUT_SIZE, appending a null terminator.  If
+   IN is too long for OUT, or if IN contains a new-line, replaces the tail with
+   "...".
+
+   OUT_SIZE must be at least 16. */
+void
+str_ellipsize (struct substring in, char *out, size_t out_size)
+{
+  assert (out_size >= 16);
+
+  size_t out_maxlen = out_size - 1;
+  if (in.length > out_maxlen - 3)
+    out_maxlen -= 3;
+
+  size_t out_len = 0;
+  while (out_len < in.length
+         && in.string[out_len] != '\n'
+         && in.string[out_len] != '\0'
+         && (in.string[out_len] != '\r'
+             || out_len + 1 >= in.length
+             || in.string[out_len + 1] != '\n'))
+    {
+      int mblen = u8_mblen (CHAR_CAST (const uint8_t *, in.string + out_len),
+                            in.length - out_len);
+      if (mblen < 0 || out_len + mblen > out_maxlen)
+        break;
+      out_len += mblen;
+    }
+
+  memcpy (out, in.string, out_len);
+  strcpy (&out[out_len], out_len < in.length ? "..." : "");
+}
+
 /* Sets the SIZE bytes starting at BLOCK to C,
    and returns the byte following BLOCK. */
 void *
@@ -392,6 +426,15 @@ ss_dealloc (struct substring *ss)
   free (ss->string);
 }
 
+/* Exchanges the contents of A and B. */
+void
+ss_swap (struct substring *a, struct substring *b)
+{
+  struct substring tmp = *a;
+  *a = *b;
+  *b = tmp;
+}
+
 /* Truncates SS to at most CNT bytes in length. */
 void
 ss_truncate (struct substring *ss, size_t cnt)
@@ -511,7 +554,7 @@ ss_tokenize (struct substring ss, struct substring delimiters,
   ss_get_bytes (&ss, ss_cspan (ss, delimiters), token);
 
   found_token = ss_length (*token) > 0;
-  *save_idx += ss_length (*token) + found_token;
+  *save_idx += ss_length (*token) + (found_token?1:0);
   return found_token;
 }
 
@@ -738,7 +781,7 @@ ss_cspan (struct substring ss, struct substring stop_set)
 size_t
 ss_find_byte (struct substring ss, char c)
 {
-  const char *p = memchr (ss.string, c, ss.length);
+  const char *p = memchr (ss.string, (int) c, ss.length);
   return p != NULL ? p - ss.string : SIZE_MAX;
 }
 
@@ -886,6 +929,22 @@ ss_at_mblen (struct substring s, size_t ofs)
   else
     return 0;
 }
+
+size_t
+ss_utf8_count_columns (struct substring s)
+{
+  return utf8_count_columns (s.string, s.length);
+}
+
+/* Returns a substring of S starting at 0-based display column START and
+   running for N display columns. */
+struct substring
+ss_utf8_columns (struct substring s, size_t start, size_t n)
+{
+  ss_advance (&s, utf8_columns_to_bytes (s.string, s.length, start));
+  s.length = utf8_columns_to_bytes (s.string, s.length, n);
+  return s;
+}
 \f
 /* Initializes ST as an empty string. */
 void
@@ -1481,7 +1540,8 @@ ds_put_cstr (struct string *st, const char *s)
 void
 ds_put_substring (struct string *st, struct substring ss)
 {
-  memcpy (ds_put_uninit (st, ss_length (ss)), ss_data (ss), ss_length (ss));
+  if (ss.length)
+    memcpy (ds_put_uninit (st, ss_length (ss)), ss_data (ss), ss_length (ss));
 }
 
 /* Returns ds_end(ST) and THEN increases the length by INCR. */