X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Flibpspp%2Fstr.c;h=86e7fd9199a5b9e22fba9fa2ac2eec4e9e7ff1c7;hb=e609c7d767ffd600fd844327b292590259cbb0de;hp=3fa2fbe9a75fbe48d0ed75dc48a1b32916b0ef88;hpb=d6fb2728eb8a99e89165c45d8e5d4a482114d3a0;p=pspp diff --git a/src/libpspp/str.c b/src/libpspp/str.c index 3fa2fbe9a7..86e7fd9199 100644 --- a/src/libpspp/str.c +++ b/src/libpspp/str.c @@ -1,5 +1,6 @@ /* 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 @@ -189,7 +190,7 @@ buf_copy_rpad (char *dst, size_t dst_size, void str_copy_rpad (char *dst, size_t dst_size, const char *src) { - if (dst_size > 0) + if (dst_size > 0) { size_t src_len = strlen (src); if (src_len < dst_size - 1) @@ -300,6 +301,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 * @@ -391,6 +425,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) @@ -510,7 +553,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; } @@ -691,6 +734,14 @@ ss_last (struct substring ss) return ss.length > 0 ? (unsigned char) ss.string[ss.length - 1] : EOF; } +/* Returns true if SS starts with PREFIX, false otherwise. */ +bool +ss_starts_with (struct substring ss, struct substring prefix) +{ + return (ss.length >= prefix.length + && !memcmp (ss.string, prefix.string, prefix.length)); +} + /* Returns true if SS ends with SUFFIX, false otherwise. */ bool ss_ends_with (struct substring ss, struct substring suffix) @@ -729,10 +780,20 @@ 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; } +/* Returns the offset in HAYSTACK of the first instance of NEEDLE, + or SIZE_MAX if NEEDLE does not occur in HAYSTACK. */ +size_t +ss_find_substring (struct substring haystack, struct substring needle) +{ + const char *p = memmem (haystack.string, haystack.length, + needle.string, needle.length); + return p != NULL ? p - haystack.string : SIZE_MAX; +} + /* Compares A and B and returns a strcmp()-type comparison result. */ int @@ -1462,7 +1523,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. */ @@ -1492,6 +1554,9 @@ ds_splice_uninit (struct string *st, { 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)); @@ -1522,25 +1587,22 @@ ds_put_c_format (struct string *st, const char *format, ...) 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 @@ -1553,34 +1615,27 @@ ds_put_vformat_int (struct string *st, const char *format, va_list args_, 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, +/* 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. */ @@ -1613,7 +1668,7 @@ ds_relocate (struct string *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);