/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2014 Free Software Foundation, Inc.
+ Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012, 2014,
+ 2020 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
#include <unistr.h>
#include "libpspp/cast.h"
+#include "libpspp/i18n.h"
#include "libpspp/message.h"
#include "libpspp/pool.h"
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);
}
}
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 *
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)
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;
}
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;
}
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
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. */
{
if (new_len > old_len)
ds_extend (st, ds_length (st) + (new_len - old_len));
+
+ assert (ds_length (st) >= ofs + old_len);
+
memmove (ds_data (st) + (ofs + new_len),
ds_data (st) + (ofs + old_len),
ds_length (st) - (ofs + old_len));
va_end (args);
}
-
-/* Formats FORMAT as a printf string, using fmt_func (a snprintf like function)
- and appends the result to ST. */
-static void
-ds_put_vformat_int (struct string *st, const char *format, va_list args_,
- int (*fmt_func) (char *, size_t, const char *, va_list))
+/* Formats FORMAT as a printf string and appends the result to ST. */
+void
+ds_put_vformat (struct string *st, const char *format, va_list args_)
{
int avail, needed;
va_list args;
va_copy (args, args_);
avail = st->ss.string != NULL ? st->capacity - st->ss.length + 1 : 0;
- needed = fmt_func (st->ss.string + st->ss.length, avail, format, args);
+ needed = vsnprintf (st->ss.string + st->ss.length, avail, format, args);
va_end (args);
if (needed >= avail)
{
va_copy (args, args_);
- fmt_func (ds_put_uninit (st, needed), needed + 1, format, args);
+ vsnprintf (ds_put_uninit (st, needed), needed + 1, format, args);
va_end (args);
}
else
avail = st->capacity - st->ss.length + 1;
va_copy (args, args_);
- needed = fmt_func (ds_end (st), avail, format, args);
+ needed = vsnprintf (ds_end (st), avail, format, args);
va_end (args);
}
st->ss.length += needed;
}
}
-
-static int
-vasnwrapper (char *str, size_t size, const char *format, va_list ap)
-{
- c_vasnprintf (str, &size, format, ap);
- return size;
-}
-
-/* Formats FORMAT as a printf string and appends the result to ST. */
-void
-ds_put_vformat (struct string *st, const char *format, va_list args_)
-{
- ds_put_vformat_int (st, format, args_, vsnprintf);
-}
-
/* Formats FORMAT as a printf string, as if in the C locale,
and appends the result to ST. */
void
-ds_put_c_vformat (struct string *st, const char *format, va_list args_)
+ds_put_c_vformat (struct string *st, const char *format, va_list args)
{
- ds_put_vformat_int (st, format, args_, vasnwrapper);
+ char buf[128];
+ size_t len = sizeof buf;
+ char *output = c_vasnprintf (buf, &len, format, args);
+ if (output)
+ {
+ ds_put_cstr (st, output);
+ if (output != buf)
+ free (output);
+ }
}
/* Appends byte CH to ST. */
const char *orig = ds_cstr (st);
const char *rel = relocate (orig);
- if ( orig != rel)
+ if (orig != rel)
{
ds_clear (st);
ds_put_cstr (st, rel);