string-util.c revision 11c3a36649e5e5e77db499c92f3cdcbd619efd3a
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/***
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering This file is part of systemd.
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering Copyright 2010 Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart 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
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
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 Poettering***/
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <errno.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <stdarg.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <stdint.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <stdio.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include <stdlib.h>
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "alloc-util.h"
9eb977db5b89b44f254ab40c1876a76b7d7ea2d0Kay Sievers#include "gunicode.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "macro.h"
a5c32cff1f56afe6f0c6c70d91a88a7a8238b2d7Harald Hoyer#include "string-util.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "utf8.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering#include "util.h"
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringint strcmp_ptr(const char *a, const char *b) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Like strcmp(), but tries to make sense of NULL pointers */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (a && b)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return strcmp(a, b);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!a && b)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return -1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (a && !b)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 1;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return 0;
2b6bf07dd23bb467099d213c97b3875c5e453491Zbigniew Jędrzejewski-Szmek}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar* endswith(const char *s, const char *postfix) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering size_t sl, pl;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(postfix);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering sl = strlen(s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering pl = strlen(postfix);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (pl == 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return (char*) s + sl;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (sl < pl)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (memcmp(s + sl - pl, postfix, pl) != 0)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return (char*) s + sl - pl;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering}
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poetteringchar* endswith_no_case(const char *s, const char *postfix) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering size_t sl, pl;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(postfix);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering sl = strlen(s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering pl = strlen(postfix);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (pl == 0)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return (char*) s + sl;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (sl < pl)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (strcasecmp(s + sl - pl, postfix) != 0)
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return (char*) s + sl - pl;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar* first_word(const char *s, const char *word) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering size_t sl, wl;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *p;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(word);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
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. */
90b2de37b80603168f4e9c9c81cff7eea4efa21aZbigniew Jędrzejewski-Szmek
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering sl = strlen(s);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering wl = strlen(word);
90b2de37b80603168f4e9c9c81cff7eea4efa21aZbigniew Jędrzejewski-Szmek
90b2de37b80603168f4e9c9c81cff7eea4efa21aZbigniew Jędrzejewski-Szmek if (sl < wl)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (wl == 0)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return (char*) s;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (memcmp(s, word, wl) != 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering p = s + wl;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (*p == 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return (char*) p;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (!strchr(WHITESPACE, *p))
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering p += strspn(p, WHITESPACE);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return (char*) p;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringstatic size_t strcspn_escaped(const char *s, const char *reject) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering bool escaped = false;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering int n;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (n=0; s[n]; n++) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (escaped)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering escaped = false;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else if (s[n] == '\\')
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering escaped = true;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering else if (strchr(reject, s[n]))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* if s ends in \, return index of previous char */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return n - escaped;
90b2de37b80603168f4e9c9c81cff7eea4efa21aZbigniew Jędrzejewski-Szmek}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering/* Split a string into words. */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringconst char* split(const char **state, size_t *l, const char *separator, bool quoted) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *current;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering current = *state;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!*current) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(**state == '\0');
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering }
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek current += strspn(current, separator);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!*current) {
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek *state = current;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (quoted && strchr("\'\"", *current)) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering char quotechars[2] = {*current, '\0'};
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
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 */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *state = current;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *state = current++ + *l + 2;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else if (quoted) {
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek *l = strcspn_escaped(current, separator);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (current[*l] && !strchr(separator, current[*l])) {
de0671ee7fe465e108f62dcbbbe9366f81dd9e9aZbigniew Jędrzejewski-Szmek /* unfinished escape */
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering *state = current;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *state = current + *l;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *l = strcspn(current, separator);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *state = current + *l;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return current;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar *strnappend(const char *s, const char *suffix, size_t b) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering size_t a;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering char *r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!s && !suffix)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return strdup("");
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (!s)
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return strndup(suffix, b);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (!suffix)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering return strdup(s);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering assert(s);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering assert(suffix);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering a = strlen(s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (b > ((size_t) -1) - a)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = new(char, a+b+1);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (!r)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering memcpy(r, s, a);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering memcpy(r+a, suffix, b);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r[a+b] = 0;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poetteringchar *strappend(const char *s, const char *suffix) {
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return strnappend(s, suffix, suffix ? strlen(suffix) : 0);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering}
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykrynchar *strjoin(const char *x, ...) {
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn va_list ap;
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn size_t l;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering char *r, *p;
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering va_start(ap, x);
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn if (x) {
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn l = strlen(x);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
a34faf579d2be139b0b9e8cd0c73ad4d918ef736Lukas Nykryn for (;;) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *t;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering size_t n;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering t = va_arg(ap, const char *);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (!t)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering n = strlen(t);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (n > ((size_t) -1) - l) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering va_end(ap);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering l += n;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering l = 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering va_end(ap);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r = new(char, l+1);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!r)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (x) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering p = stpcpy(r, x);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering va_start(ap, x);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering for (;;) {
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering const char *t;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering t = va_arg(ap, const char *);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (!t)
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering break;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering p = stpcpy(p, t);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering va_end(ap);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering } else
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering r[0] = 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return r;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar *strstrip(char *s) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering char *e;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
d2e54fae5ca7a0f71b5ac8b356a589ff0a09ea0aKay Sievers /* Drops trailing whitespace. Modifies the string in
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering * place. Returns pointer to first non-space character */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering s += strspn(s, WHITESPACE);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering for (e = strchr(s, 0); e > s; e --)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (!strchr(WHITESPACE, e[-1]))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering break;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *e = 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return s;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar *delete_chars(char *s, const char *bad) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering char *f, *t;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering /* Drops all whitespace, regardless where in the string */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering for (f = s, t = s; *f; f++) {
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering if (strchr(bad, *f))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering continue;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *(t++) = *f;
718db96199eb307751264e4163555662c9a389faLennart Poettering }
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering *t = 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return s;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar *truncate_nl(char *s) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(s);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering s[strcspn(s, NEWLINE)] = 0;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return s;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringchar *ascii_strlower(char *t) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering char *p;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering assert(t);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (p = t; *p; p++)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (*p >= 'A' && *p <= 'Z')
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering *p = *p - 'A' + 'a';
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return t;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poetteringbool chars_intersect(const char *a, const char *b) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *p;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* Returns true if any of the chars in a are in b. */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering for (p = a; *p; p++)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (strchr(b, *p))
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return true;
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return false;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering}
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poetteringbool string_has_cc(const char *p, const char *ok) {
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering const char *t;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering assert(p);
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering /*
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.
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering */
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering for (t = p; *t; t++) {
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering if (ok && strchr(ok, *t))
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering continue;
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering
2c4f86c1298f402220965682ab0e7729e150a562Lennart Poettering if (*t > 0 && *t < ' ')
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return true;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (*t == 127)
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return true;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering }
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return false;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering}
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poetteringstatic char *ascii_ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering size_t x;
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering char *r;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering assert(s);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering assert(percent <= 100);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering assert(new_length >= 3);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering if (old_length <= 3 || old_length <= new_length)
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering return strndup(s, old_length);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering r = new0(char, new_length+1);
cc3773810855956bad92337cee8fa193584ab62eLennart Poettering if (!r)
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering return NULL;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering x = (new_length * percent) / 100;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering if (x > new_length - 3)
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering x = new_length - 3;
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering memcpy(r, s, x);
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering r[x] = '.';
409133be63387fc04d927e8aecd2f6ba03d2f143Lennart Poettering r[x+1] = '.';
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering r[x+2] = '.';
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering memcpy(r + x + 3,
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering s + old_length - (new_length - x - 3),
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering new_length - x - 3);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering return r;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering}
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering
85a428c69465b047731b6abb5005f01824f1444eLennart Poetteringchar *ellipsize_mem(const char *s, size_t old_length, size_t new_length, unsigned percent) {
85a428c69465b047731b6abb5005f01824f1444eLennart Poettering size_t x;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering char *e;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering const char *i, *j;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering unsigned k, len, len2;
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering assert(s);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering assert(percent <= 100);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering assert(new_length >= 3);
c7b5eb98e8eeafe63a079ee3c51e9670872437aeLennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering /* if no multibyte characters use ascii_ellipsize_mem for speed */
ec202eae8e84a4c99f054f771cb832046cb8769fShawn Landden if (ascii_is_valid(s))
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering return ascii_ellipsize_mem(s, old_length, new_length, percent);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (old_length <= 3 || old_length <= new_length)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return strndup(s, old_length);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering x = (new_length * percent) / 100;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (x > new_length - 3)
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering x = new_length - 3;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering k = 0;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering for (i = s; k < x && i < s + old_length; i = utf8_next_char(i)) {
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering int c;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering c = utf8_encoded_to_unichar(i);
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering if (c < 0)
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering return NULL;
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering k += unichar_iswide(c) ? 2 : 1;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering }
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering if (k > x) /* last character was wide and went over quota */
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering x ++;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering for (j = s + old_length; k < new_length && j > i; ) {
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering int c;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering j = utf8_prev_char(j);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering c = utf8_encoded_to_unichar(j);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering if (c < 0)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return NULL;
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering k += unichar_iswide(c) ? 2 : 1;
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek }
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering assert(i <= j);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek /* we don't actually need to ellipsize */
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek if (i == j)
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering return memdup(s, old_length + 1);
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek
4943c1c94ba751c98763f4232b4350481b22c90aLennart Poettering /* make space for ellipsis */
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek j = utf8_next_char(j);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek len = i - s;
beaafb2ea6be591882aef21fe19b88e3b2461087Lennart Poettering len2 = s + old_length - j;
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek e = new(char, len + 3 + len2 + 1);
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering if (!e)
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek return NULL;
8e7fd6ade44ce5dde0867ba748c7978ed1206865Lennart Poettering
a2a5291b3f5ab6ed4c92f51d0fd10a03047380d8Zbigniew Jędrzejewski-Szmek /*
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 */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering memcpy(e, s, len);
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering e[len] = 0xe2; /* tri-dot ellipsis: … */
f8e2fb7b14e53f5a4bcfd66d26910af1dee185c6Lennart Poettering e[len + 1] = 0x80;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering e[len + 2] = 0xa6;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering memcpy(e + len + 3, j, len2 + 1);
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering return e;
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering}
eecd1362f7f4de432483b5d77c56726c3621a83aLennart Poettering
char *ellipsize(const char *s, size_t length, unsigned percent) {
return ellipsize_mem(s, strlen(s), length, percent);
}
bool nulstr_contains(const char*nulstr, const char *needle) {
const char *i;
if (!nulstr)
return false;
NULSTR_FOREACH(i, nulstr)
if (streq(i, needle))
return true;
return false;
}
char* strshorten(char *s, size_t l) {
assert(s);
if (l < strlen(s))
s[l] = 0;
return s;
}
char *strreplace(const char *text, const char *old_string, const char *new_string) {
const char *f;
char *t, *r;
size_t l, old_len, new_len;
assert(text);
assert(old_string);
assert(new_string);
old_len = strlen(old_string);
new_len = strlen(new_string);
l = strlen(text);
r = new(char, l+1);
if (!r)
return NULL;
f = text;
t = r;
while (*f) {
char *a;
size_t d, nl;
if (!startswith(f, old_string)) {
*(t++) = *(f++);
continue;
}
d = t - r;
nl = l - old_len + new_len;
a = realloc(r, nl + 1);
if (!a)
goto oom;
l = nl;
r = a;
t = r + d;
t = stpcpy(t, new_string);
f += old_len;
}
*t = 0;
return r;
oom:
free(r);
return NULL;
}
char *strip_tab_ansi(char **ibuf, size_t *_isz) {
const char *i, *begin = NULL;
enum {
STATE_OTHER,
STATE_ESCAPE,
STATE_BRACKET
} state = STATE_OTHER;
char *obuf = NULL;
size_t osz = 0, isz;
FILE *f;
assert(ibuf);
assert(*ibuf);
/* Strips ANSI color and replaces TABs by 8 spaces */
isz = _isz ? *_isz : strlen(*ibuf);
f = open_memstream(&obuf, &osz);
if (!f)
return NULL;
for (i = *ibuf; i < *ibuf + isz + 1; i++) {
switch (state) {
case STATE_OTHER:
if (i >= *ibuf + isz) /* EOT */
break;
else if (*i == '\x1B')
state = STATE_ESCAPE;
else if (*i == '\t')
fputs(" ", f);
else
fputc(*i, f);
break;
case STATE_ESCAPE:
if (i >= *ibuf + isz) { /* EOT */
fputc('\x1B', f);
break;
} else if (*i == '[') {
state = STATE_BRACKET;
begin = i + 1;
} else {
fputc('\x1B', f);
fputc(*i, f);
state = STATE_OTHER;
}
break;
case STATE_BRACKET:
if (i >= *ibuf + isz || /* EOT */
(!(*i >= '0' && *i <= '9') && *i != ';' && *i != 'm')) {
fputc('\x1B', f);
fputc('[', f);
state = STATE_OTHER;
i = begin-1;
} else if (*i == 'm')
state = STATE_OTHER;
break;
}
}
if (ferror(f)) {
fclose(f);
free(obuf);
return NULL;
}
fclose(f);
free(*ibuf);
*ibuf = obuf;
if (_isz)
*_isz = osz;
return obuf;
}
char *strextend(char **x, ...) {
va_list ap;
size_t f, l;
char *r, *p;
assert(x);
l = f = *x ? strlen(*x) : 0;
va_start(ap, x);
for (;;) {
const char *t;
size_t n;
t = va_arg(ap, const char *);
if (!t)
break;
n = strlen(t);
if (n > ((size_t) -1) - l) {
va_end(ap);
return NULL;
}
l += n;
}
va_end(ap);
r = realloc(*x, l+1);
if (!r)
return NULL;
p = r + f;
va_start(ap, x);
for (;;) {
const char *t;
t = va_arg(ap, const char *);
if (!t)
break;
p = stpcpy(p, t);
}
va_end(ap);
*p = 0;
*x = r;
return r + l;
}
char *strrep(const char *s, unsigned n) {
size_t l;
char *r, *p;
unsigned i;
assert(s);
l = strlen(s);
p = r = malloc(l * n + 1);
if (!r)
return NULL;
for (i = 0; i < n; i++)
p = stpcpy(p, s);
*p = 0;
return r;
}
int split_pair(const char *s, const char *sep, char **l, char **r) {
char *x, *a, *b;
assert(s);
assert(sep);
assert(l);
assert(r);
if (isempty(sep))
return -EINVAL;
x = strstr(s, sep);
if (!x)
return -EINVAL;
a = strndup(s, x - s);
if (!a)
return -ENOMEM;
b = strdup(x + strlen(sep));
if (!b) {
free(a);
return -ENOMEM;
}
*l = a;
*r = b;
return 0;
}
int free_and_strdup(char **p, const char *s) {
char *t;
assert(p);
/* Replaces a string pointer with an strdup()ed new string,
* possibly freeing the old one. */
if (streq_ptr(*p, s))
return 0;
if (s) {
t = strdup(s);
if (!t)
return -ENOMEM;
} else
t = NULL;
free(*p);
*p = t;
return 1;
}
#pragma GCC push_options
#pragma GCC optimize("O0")
void* memory_erase(void *p, size_t l) {
volatile uint8_t* x = (volatile uint8_t*) p;
/* This basically does what memset() does, but hopefully isn't
* optimized away by the compiler. One of those days, when
* glibc learns memset_s() we should replace this call by
* memset_s(), but until then this has to do. */
for (; l > 0; l--)
*(x++) = 'x';
return p;
}
#pragma GCC pop_options
char* string_erase(char *x) {
if (!x)
return NULL;
/* A delicious drop of snake-oil! To be called on memory where
* we stored passphrases or so, after we used them. */
return memory_erase(x, strlen(x));
}
char *string_free_erase(char *s) {
return mfree(string_erase(s));
}
bool string_is_safe(const char *p) {
const char *t;
if (!p)
return false;
for (t = p; *t; t++) {
if (*t > 0 && *t < ' ') /* no control characters */
return false;
if (strchr(QUOTES "\\\x7f", *t))
return false;
}
return true;
}