string-util.c revision 11c3a36649e5e5e77db499c92f3cdcbd619efd3a
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering This file is part of systemd.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Copyright 2010 Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering systemd is free software; you can redistribute it and/or modify it
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering under the terms of the GNU Lesser General Public License as published by
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering (at your option) any later version.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering systemd is distributed in the hope that it will be useful, but
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Lesser General Public License for more details.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering You should have received a copy of the GNU Lesser General Public License
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringint strcmp_ptr(const char *a, const char *b) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Like strcmp(), but tries to make sense of NULL pointers */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar* endswith(const char *s, const char *postfix) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return (char*) s + sl;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (memcmp(s + sl - pl, postfix, pl) != 0)
cc3773810855956bad92337cee8fa193584ab62eLennart Poetteringchar* endswith_no_case(const char *s, const char *postfix) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return (char*) s + sl;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (strcasecmp(s + sl - pl, postfix) != 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar* first_word(const char *s, const char *word) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *p;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Checks if the string starts with the specified word, either
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering * followed by NUL or by whitespace. Returns a pointer to the
90b2de37b80603168f4e9c9c81cff7eea4efa21aZbigniew Jędrzejewski-Szmek * NUL or the first character after the whitespace. */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return (char*) s;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return (char*) p;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return (char*) p;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic size_t strcspn_escaped(const char *s, const char *reject) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (n=0; s[n]; n++) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else if (s[n] == '\\')
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* if s ends in \, return index of previous char */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/* Split a string into words. */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringconst char* split(const char **state, size_t *l, const char *separator, bool quoted) {
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek current += strspn(current, separator);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (quoted && strchr("\'\"", *current)) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering *l = strcspn_escaped(current + 1, quotechars);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (current[*l + 1] == '\0' || current[*l + 1] != quotechars[0] ||
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering (current[*l + 2] && !strchr(separator, current[*l + 2]))) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* right quote missing or garbage at the end */
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek *l = strcspn_escaped(current, separator);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (current[*l] && !strchr(separator, current[*l])) {
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek /* unfinished escape */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar *strnappend(const char *s, const char *suffix, size_t b) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poetteringchar *strappend(const char *s, const char *suffix) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykrynchar *strjoin(const char *x, ...) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *t;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering const char *t;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar *strstrip(char *s) {
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers /* Drops trailing whitespace. Modifies the string in
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * place. Returns pointer to first non-space character */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering for (e = strchr(s, 0); e > s; e --)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar *delete_chars(char *s, const char *bad) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Drops all whitespace, regardless where in the string */
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering for (f = s, t = s; *f; f++) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (p = t; *p; p++)
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poetteringbool chars_intersect(const char *a, const char *b) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *p;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Returns true if any of the chars in a are in b. */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (p = a; *p; p++)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringbool string_has_cc(const char *p, const char *ok) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *t;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering * Check if a string contains control characters. If 'ok' is
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering * non-NULL it may be a string containing additional CCs to be
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering * considered OK.
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering for (t = p; *t; t++) {
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering if (*t > 0 && *t < ' ')
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (*t == 127)
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poetteringstatic char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering if (old_length <= 3 || old_length <= new_length)
85a428c69465b047731b6abb5005f01824f1444eLennart Poetteringchar *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering const char *i, *j;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* if no multibyte characters use ascii_ellipsize_mem for speed */
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return ascii_ellipsize_mem(s, old_length, new_length, percent);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (old_length <= 3 || old_length <= new_length)
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (k > x) /* last character was wide and went over quota */
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering for (j = s + old_length; k < new_length && j > i; ) {
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek /* we don't actually need to ellipsize */
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering /* make space for ellipsis */
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek e = new(char, len + 3 + len2 + 1);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering printf("old_length=%zu new_length=%zu x=%zu len=%u len2=%u k=%u\n",
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering old_length, new_length, x, len, len2, k);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering e[len] = 0xe2; /* tri-dot ellipsis: … */
if (!nulstr)
assert(s);
if (l < strlen(s))
return NULL;
f = text;
goto oom;
l = nl;
f += old_len;
oom:
free(r);
return NULL;
FILE *f;
return NULL;
switch (state) {
case STATE_OTHER:
fputc(*i, f);
case STATE_ESCAPE:
fputc(*i, f);
case STATE_BRACKET:
if (ferror(f)) {
fclose(f);
return NULL;
fclose(f);
if (_isz)
return obuf;
char *strextend(char **x, ...) {
size_t f, l;
assert(x);
l = f = *x ? strlen(*x) : 0;
size_t n;
n = strlen(t);
return NULL;
return NULL;
p = stpcpy(p, t);
char *strrep(const char *s, unsigned n) {
size_t l;
assert(s);
l = strlen(s);
return NULL;
p = stpcpy(p, s);
assert(s);
assert(l);
assert(r);
return -EINVAL;
return -EINVAL;
a = strndup(s, x - s);
return -ENOMEM;
free(a);
return -ENOMEM;
int free_and_strdup(char **p, const char *s) {
assert(p);
if (streq_ptr(*p, s))
t = strdup(s);
return -ENOMEM;
t = NULL;
free(*p);
char* string_erase(char *x) {
return NULL;
char *string_free_erase(char *s) {
bool string_is_safe(const char *p) {