/* 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 *
\f
/* Substrings. */
-/* Returns a substring whose contents are the CNT bytes
+/* Returns a substring whose contents are the N bytes
starting at the (0-based) position START in SS. */
struct substring
-ss_substr (struct substring ss, size_t start, size_t cnt)
+ss_substr (struct substring ss, size_t start, size_t n)
{
if (start < ss.length)
- return ss_buffer (ss.string + start, MIN (cnt, ss.length - start));
+ return ss_buffer (ss.string + start, MIN (n, ss.length - start));
else
return ss_buffer (ss.string + ss.length, 0);
}
-/* Returns a substring whose contents are the first CNT
+/* Returns a substring whose contents are the first N
bytes in SS. */
struct substring
-ss_head (struct substring ss, size_t cnt)
+ss_head (struct substring ss, size_t n)
{
- return ss_buffer (ss.string, MIN (cnt, ss.length));
+ return ss_buffer (ss.string, MIN (n, ss.length));
}
-/* Returns a substring whose contents are the last CNT bytes
+/* Returns a substring whose contents are the last N bytes
in SS. */
struct substring
-ss_tail (struct substring ss, size_t cnt)
+ss_tail (struct substring ss, size_t n)
{
- if (cnt < ss.length)
- return ss_buffer (ss.string + (ss.length - cnt), cnt);
+ if (n < ss.length)
+ return ss_buffer (ss.string + (ss.length - n), n);
else
return ss;
}
new->length = old.length;
}
-/* Allocates room for a CNT-byte string in NEW. */
+/* Allocates room for a N-byte string in NEW. */
void
-ss_alloc_uninit (struct substring *new, size_t cnt)
+ss_alloc_uninit (struct substring *new, size_t n)
{
- new->string = xmalloc (cnt);
- new->length = cnt;
+ new->string = xmalloc (n);
+ new->length = n;
}
void
new->string[old.length] = '\0';
}
-/* Allocates room for a CNT-byte string in NEW in POOL. */
+/* Allocates room for a N-byte string in NEW in POOL. */
void
-ss_alloc_uninit_pool (struct substring *new, size_t cnt, struct pool *pool)
+ss_alloc_uninit_pool (struct substring *new, size_t n, struct pool *pool)
{
- new->string = pool_alloc_unaligned (pool, cnt);
- new->length = cnt;
+ new->string = pool_alloc_unaligned (pool, n);
+ new->length = n;
}
/* Frees the string that SS points to. */
free (ss->string);
}
-/* Truncates SS to at most CNT bytes in length. */
+/* 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 N bytes in length. */
void
-ss_truncate (struct substring *ss, size_t cnt)
+ss_truncate (struct substring *ss, size_t n)
{
- if (ss->length > cnt)
- ss->length = cnt;
+ if (ss->length > n)
+ ss->length = n;
}
/* Removes trailing bytes in TRIM_SET from SS.
size_t
ss_rtrim (struct substring *ss, struct substring trim_set)
{
- size_t cnt = 0;
- while (cnt < ss->length
+ size_t n = 0;
+ while (n < ss->length
&& ss_find_byte (trim_set,
- ss->string[ss->length - cnt - 1]) != SIZE_MAX)
- cnt++;
- ss->length -= cnt;
- return cnt;
+ ss->string[ss->length - n - 1]) != SIZE_MAX)
+ n++;
+ ss->length -= n;
+ return n;
}
/* Removes leading bytes in TRIM_SET from SS.
size_t
ss_ltrim (struct substring *ss, struct substring trim_set)
{
- size_t cnt = ss_span (*ss, trim_set);
- ss_advance (ss, cnt);
- return cnt;
+ size_t n = ss_span (*ss, trim_set);
+ ss_advance (ss, n);
+ return n;
}
/* Trims leading and trailing bytes in TRIM_SET from SS. */
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;
}
-/* Removes the first CNT bytes from SS. */
+/* Removes the first N bytes from SS. */
void
-ss_advance (struct substring *ss, size_t cnt)
+ss_advance (struct substring *ss, size_t n)
{
- if (cnt > ss->length)
- cnt = ss->length;
- ss->string += cnt;
- ss->length -= cnt;
+ if (n > ss->length)
+ n = ss->length;
+ ss->string += n;
+ ss->length -= n;
}
/* If the first byte in SS is C, removes it and returns true.
return ss_match_byte (ss, delimiter);
}
-/* Stores the first CNT bytes in SS in OUT (or fewer, if SS
- is shorter than CNT bytes). Trims the same bytes
- from the beginning of SS. Returns CNT. */
+/* Stores the first N bytes in SS in OUT (or fewer, if SS
+ is shorter than N bytes). Trims the same bytes
+ from the beginning of SS. Returns N. */
size_t
-ss_get_bytes (struct substring *ss, size_t cnt, struct substring *out)
+ss_get_bytes (struct substring *ss, size_t n, struct substring *out)
{
- *out = ss_head (*ss, cnt);
- ss_advance (ss, cnt);
- return cnt;
+ *out = ss_head (*ss, n);
+ ss_advance (ss, n);
+ return n;
}
/* Parses and removes an optionally signed decimal integer from
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
return st->ss;
}
-/* Returns a substring that contains CNT bytes from ST
+/* Returns a substring that contains N bytes from ST
starting at position START.
If START is greater than or equal to the length of ST, then
- the substring will be the empty string. If START + CNT
+ the substring will be the empty string. If START + N
exceeds the length of ST, then the substring will only be
ds_length(ST) - START bytes long. */
struct substring
-ds_substr (const struct string *st, size_t start, size_t cnt)
+ds_substr (const struct string *st, size_t start, size_t n)
{
- return ss_substr (ds_ss (st), start, cnt);
+ return ss_substr (ds_ss (st), start, n);
}
-/* Returns a substring that contains the first CNT bytes in
- ST. If CNT exceeds the length of ST, then the substring will
+/* Returns a substring that contains the first N bytes in
+ ST. If N exceeds the length of ST, then the substring will
contain all of ST. */
struct substring
-ds_head (const struct string *st, size_t cnt)
+ds_head (const struct string *st, size_t n)
{
- return ss_head (ds_ss (st), cnt);
+ return ss_head (ds_ss (st), n);
}
-/* Returns a substring that contains the last CNT bytes in
- ST. If CNT exceeds the length of ST, then the substring will
+/* Returns a substring that contains the last N bytes in
+ ST. If N exceeds the length of ST, then the substring will
contain all of ST. */
struct substring
-ds_tail (const struct string *st, size_t cnt)
+ds_tail (const struct string *st, size_t n)
{
- return ss_tail (ds_ss (st), cnt);
+ return ss_tail (ds_ss (st), n);
}
/* Ensures that ST can hold at least MIN_CAPACITY bytes plus a null
size_t
ds_ltrim (struct string *st, struct substring trim_set)
{
- size_t cnt = ds_span (st, trim_set);
- if (cnt > 0)
- ds_assign_substring (st, ds_substr (st, cnt, SIZE_MAX));
- return cnt;
+ size_t n = ds_span (st, trim_set);
+ if (n > 0)
+ ds_assign_substring (st, ds_substr (st, n, SIZE_MAX));
+ return n;
}
/* Trims leading and trailing bytes in TRIM_SET from ST.
size_t
ds_trim (struct string *st, struct substring trim_set)
{
- size_t cnt = ds_rtrim (st, trim_set);
- return cnt + ds_ltrim (st, trim_set);
+ size_t n = ds_rtrim (st, trim_set);
+ return n + ds_ltrim (st, trim_set);
}
/* If the last byte in ST is C, removes it and returns true.
return true;
}
-/* Attempts to read SIZE * CNT bytes from STREAM and append them
+/* Attempts to read SIZE * N bytes from STREAM and append them
to ST.
Returns true if all the requested data was read, false otherwise. */
bool
-ds_read_stream (struct string *st, size_t size, size_t cnt, FILE *stream)
+ds_read_stream (struct string *st, size_t size, size_t n, FILE *stream)
{
if (size != 0)
{
- size_t try_bytes = xtimes (cnt, size);
+ size_t try_bytes = xtimes (n, size);
if (size_in_bounds_p (xsum (ds_length (st), try_bytes)))
{
char *buffer = ds_put_uninit (st, try_bytes);
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));
ds_put_uninit (st, 1)[0] = ch;
}
-/* Appends CNT copies of byte CH to ST. */
+/* Appends N copies of byte CH to ST. */
void
-ds_put_byte_multiple (struct string *st, int ch, size_t cnt)
+ds_put_byte_multiple (struct string *st, int ch, size_t n)
{
- memset (ds_put_uninit (st, cnt), ch, cnt);
+ memset (ds_put_uninit (st, n), ch, n);
}
/* Appends Unicode code point UC to ST in UTF-8 encoding. */
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);