/* PSPP - a program for statistical analysis.
- Copyright (C) 1997-9, 2000, 2006, 2009, 2010, 2011, 2012 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 "libpspp/message.h"
#include "libpspp/pool.h"
+#include "gl/c-ctype.h"
+#include "gl/c-vasnprintf.h"
#include "gl/relocatable.h"
#include "gl/minmax.h"
#include "gl/xalloc.h"
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)
dst[dst_len] = '\0';
}
-/* Converts each byte in S to uppercase. */
+/* Converts each byte in S to uppercase.
+
+ This is suitable only for ASCII strings. Use utf8_to_upper() for UTF-8
+ strings.*/
void
str_uppercase (char *s)
{
for (; *s != '\0'; s++)
- *s = toupper ((unsigned char) *s);
+ *s = c_toupper ((unsigned char) *s);
}
-/* Converts each byte in S to lowercase. */
+/* Converts each byte in S to lowercase.
+
+ This is suitable only for ASCII strings. Use utf8_to_lower() for UTF-8
+ strings.*/
void
str_lowercase (char *s)
{
for (; *s != '\0'; s++)
- *s = tolower ((unsigned char) *s);
+ *s = c_tolower ((unsigned char) *s);
}
/* Converts NUMBER into a string in 26-adic notation in BUFFER,
- which has room for SIZE bytes. Returns true if successful,
- false if NUMBER, plus a trailing null, is too large to fit in
- the available space.
+ which has room for SIZE bytes. Uses uppercase if UPPERCASE is
+ true, otherwise lowercase, Returns true if successful, false
+ if NUMBER, plus a trailing null, is too large to fit in the
+ available space.
26-adic notation is "spreadsheet column numbering": 1 = A, 2 =
B, 3 = C, ... 26 = Z, 27 = AA, 28 = AB, 29 = AC, ...
For more information, see
http://en.wikipedia.org/wiki/Bijective_numeration. */
bool
-str_format_26adic (unsigned long int number, char buffer[], size_t size)
+str_format_26adic (unsigned long int number, bool uppercase,
+ char buffer[], size_t size)
{
+ const char *alphabet
+ = uppercase ? "ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "abcdefghijklmnopqrstuvwxyz";
size_t length = 0;
while (number-- > 0)
{
if (length >= size)
goto overflow;
- buffer[length++] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"[number % 26];
+ buffer[length++] = alphabet[number % 26];
number /= 26;
}
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)
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
{
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 as if in the C locale and appends the result to ST. */
+void
+ds_put_c_format (struct string *st, const char *format, ...)
+{
+ va_list args;
+
+ va_start (args, format);
+ ds_put_c_vformat (st, format, args);
+ va_end (args);
+}
+
/* 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_)
if (needed >= avail)
{
va_copy (args, args_);
- vsprintf (ds_put_uninit (st, needed), format, args);
+ vsnprintf (ds_put_uninit (st, needed), needed + 1, format, args);
va_end (args);
}
else
}
}
+/* 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)
+{
+ 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. */
void
ds_put_byte (struct string *st, int ch)
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);