Bump liberty
This commit is contained in:
parent
e57939e705
commit
0c4b727961
97
common.c
97
common.c
@ -49,38 +49,6 @@
|
||||
|
||||
// --- To be moved to liberty --------------------------------------------------
|
||||
|
||||
#define LIST_INSERT_WITH_TAIL(head, tail, link, following) \
|
||||
BLOCK_START \
|
||||
if (following) \
|
||||
LIST_APPEND_WITH_TAIL ((head), (following)->prev, (link)); \
|
||||
else \
|
||||
LIST_APPEND_WITH_TAIL ((head), (tail), (link)); \
|
||||
(link)->next = (following); \
|
||||
BLOCK_END
|
||||
|
||||
#define TRIVIAL_STRXFRM(name, fn) \
|
||||
static size_t \
|
||||
name (char *dest, const char *src, size_t n) \
|
||||
{ \
|
||||
size_t len = strlen (src); \
|
||||
while (n-- && (*dest++ = (fn) (*src++))) \
|
||||
; \
|
||||
return len; \
|
||||
}
|
||||
|
||||
static void
|
||||
transform_str (char *s, int (*tolower) (int c))
|
||||
{
|
||||
for (; *s; s++)
|
||||
*s = tolower (*s);
|
||||
}
|
||||
|
||||
static char *
|
||||
str_cut_until (const char *s, const char *alphabet)
|
||||
{
|
||||
return xstrndup (s, strcspn (s, alphabet));
|
||||
}
|
||||
|
||||
static void
|
||||
split_str (const char *s, char delimiter, struct str_vector *out)
|
||||
{
|
||||
@ -102,71 +70,6 @@ str_vector_find (const struct str_vector *v, const char *s)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int
|
||||
strncasecmp_ascii (const char *a, const char *b, size_t n)
|
||||
{
|
||||
int x;
|
||||
while (n-- && (*a || *b))
|
||||
if ((x = tolower_ascii (*(const unsigned char *) a++)
|
||||
- tolower_ascii (*(const unsigned char *) b++)))
|
||||
return x;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
irc_tolower_strict (int c)
|
||||
{
|
||||
if (c == '[') return '{';
|
||||
if (c == ']') return '}';
|
||||
if (c == '\\') return '|';
|
||||
return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
|
||||
}
|
||||
|
||||
TRIVIAL_STRXFRM (irc_strxfrm_strict, irc_tolower_strict)
|
||||
|
||||
static char *
|
||||
resolve_relative_runtime_filename (const char *filename)
|
||||
{
|
||||
struct str path;
|
||||
str_init (&path);
|
||||
|
||||
const char *runtime_dir = getenv ("XDG_RUNTIME_DIR");
|
||||
if (runtime_dir && *runtime_dir == '/')
|
||||
str_append (&path, runtime_dir);
|
||||
else
|
||||
get_xdg_home_dir (&path, "XDG_DATA_HOME", ".local/share");
|
||||
str_append_printf (&path, "/%s/%s", PROGRAM_NAME, filename);
|
||||
|
||||
// Try to create the file's ancestors
|
||||
const char *last_slash = strrchr (path.str, '/');
|
||||
if (last_slash && last_slash != path.str)
|
||||
{
|
||||
char *copy = xstrndup (path.str, last_slash - path.str);
|
||||
(void) mkdir_with_parents (copy, NULL);
|
||||
free (copy);
|
||||
}
|
||||
return str_steal (&path);
|
||||
}
|
||||
|
||||
static char *
|
||||
resolve_filename (const char *filename, char *(*relative_cb) (const char *))
|
||||
{
|
||||
// Absolute path is absolute
|
||||
if (*filename == '/')
|
||||
return xstrdup (filename);
|
||||
|
||||
// We don't want to use wordexp() for this as it may execute /bin/sh
|
||||
if (*filename == '~')
|
||||
{
|
||||
// Paths to home directories ought to be absolute
|
||||
char *expanded = try_expand_tilde (filename + 1);
|
||||
if (expanded)
|
||||
return expanded;
|
||||
print_debug ("failed to expand the home directory in `%s'", filename);
|
||||
}
|
||||
return relative_cb (filename);
|
||||
}
|
||||
|
||||
// --- Logging -----------------------------------------------------------------
|
||||
|
||||
static void
|
||||
|
47
degesch.c
47
degesch.c
@ -2173,7 +2173,7 @@ irc_server_strncmp (struct server *s, const char *a, const char *b, size_t n)
|
||||
static char *
|
||||
irc_cut_nickname (const char *prefix)
|
||||
{
|
||||
return str_cut_until (prefix, "!@");
|
||||
return cstr_cut_until (prefix, "!@");
|
||||
}
|
||||
|
||||
static const char *
|
||||
@ -3896,7 +3896,7 @@ transport_tls_init_cert (struct server *s, SSL *ssl, struct error **e)
|
||||
return true;
|
||||
|
||||
bool result = false;
|
||||
char *path = resolve_config_filename (ssl_cert);
|
||||
char *path = resolve_filename (ssl_cert, resolve_relative_config_filename);
|
||||
if (!path)
|
||||
error_set (e, "%s: %s", "Cannot open file", ssl_cert);
|
||||
// XXX: perhaps we should read the file ourselves for better messages
|
||||
@ -4117,7 +4117,7 @@ irc_fetch_next_nickname (struct server *s)
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (get_config_string (s->config, "nicks"), ',', &v);
|
||||
cstr_split_ignore_empty (get_config_string (s->config, "nicks"), ',', &v);
|
||||
|
||||
char *result = NULL;
|
||||
if (s->nick_counter >= 0 && (size_t) s->nick_counter < v.len)
|
||||
@ -4336,7 +4336,7 @@ irc_initiate_connect (struct server *s)
|
||||
|
||||
struct str_vector servers;
|
||||
str_vector_init (&servers);
|
||||
split_str_ignore_empty (addresses, ',', &servers);
|
||||
cstr_split_ignore_empty (addresses, ',', &servers);
|
||||
|
||||
struct error *e = NULL;
|
||||
if (!irc_initiate_connect_socks (s, &servers, &e) && !e)
|
||||
@ -4513,10 +4513,10 @@ irc_is_highlight (struct server *s, const char *message)
|
||||
// Well, this is rather crude but it should make most users happy.
|
||||
// Ideally we could do this at least in proper Unicode.
|
||||
char *copy = xstrdup (message);
|
||||
transform_str (copy, s->irc_tolower);
|
||||
cstr_transform (copy, s->irc_tolower);
|
||||
|
||||
char *nick = xstrdup (s->irc_user->nickname);
|
||||
transform_str (nick, s->irc_tolower);
|
||||
cstr_transform (nick, s->irc_tolower);
|
||||
|
||||
// Special characters allowed in nicknames by RFC 2812: []\`_^{|} and -
|
||||
// Also excluded from the ASCII: common user channel prefixes: +%@&~
|
||||
@ -4736,7 +4736,7 @@ irc_handle_cap (struct server *s, const struct irc_message *msg)
|
||||
|
||||
const char *args = "";
|
||||
if (msg->params.len > 2)
|
||||
split_str_ignore_empty ((args = msg->params.vector[2]), ' ', &v);
|
||||
cstr_split_ignore_empty ((args = msg->params.vector[2]), ' ', &v);
|
||||
|
||||
const char *subcommand = msg->params.vector[1];
|
||||
if (!strcasecmp_ascii (subcommand, "ACK"))
|
||||
@ -5448,7 +5448,7 @@ irc_try_parse_welcome_for_userhost (struct server *s, const char *m)
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (m, ' ', &v);
|
||||
cstr_split_ignore_empty (m, ' ', &v);
|
||||
for (size_t i = 0; i < v.len; i++)
|
||||
if (irc_try_parse_word_for_userhost (s, v.vector[i]))
|
||||
break;
|
||||
@ -5484,7 +5484,7 @@ irc_handle_rpl_userhost (struct server *s, const struct irc_message *msg)
|
||||
const char *response = msg->params.vector[1];
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (response, ' ', &v);
|
||||
cstr_split_ignore_empty (response, ' ', &v);
|
||||
|
||||
for (size_t i = 0; i < v.len; i++)
|
||||
{
|
||||
@ -5541,7 +5541,7 @@ irc_handle_rpl_namreply (struct server *s, const struct irc_message *msg)
|
||||
// Just push the nicknames to a string vector to process later
|
||||
struct channel *channel = str_map_find (&s->irc_channels, channel_name);
|
||||
if (channel)
|
||||
split_str_ignore_empty (nicks, ' ', &channel->names_buf);
|
||||
cstr_split_ignore_empty (nicks, ' ', &channel->names_buf);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -5828,7 +5828,7 @@ irc_handle_isupport_idchan (struct server *s, char *value)
|
||||
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (value, ',', &v);
|
||||
cstr_split_ignore_empty (value, ',', &v);
|
||||
for (size_t i = 0; i < v.len; i++)
|
||||
{
|
||||
// Not using or validating the numeric part
|
||||
@ -5855,7 +5855,7 @@ irc_handle_isupport_chanmodes (struct server *s, char *value)
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (value, ',', &v);
|
||||
cstr_split_ignore_empty (value, ',', &v);
|
||||
if (v.len >= 4)
|
||||
{
|
||||
free (s->irc_chanmodes_list);
|
||||
@ -6373,7 +6373,7 @@ dump_matching_options
|
||||
for (size_t i = 0; i < output->len; i++)
|
||||
{
|
||||
// Yeah, I know
|
||||
char *key = str_cut_until (output->vector[i], " ");
|
||||
char *key = cstr_cut_until (output->vector[i], " ");
|
||||
if (fnmatch (mask, key, 0))
|
||||
str_vector_remove (output, i--);
|
||||
free (key);
|
||||
@ -6841,7 +6841,7 @@ handle_command_set_assign
|
||||
}
|
||||
for (size_t i = 0; i < all->len; i++)
|
||||
{
|
||||
char *key = str_cut_until (all->vector[i], " ");
|
||||
char *key = cstr_cut_until (all->vector[i], " ");
|
||||
handle_command_set_assign_item (ctx, key, new_, add, remove);
|
||||
free (key);
|
||||
}
|
||||
@ -7018,7 +7018,7 @@ handle_command_ctcp (struct handler_args *a)
|
||||
return false;
|
||||
|
||||
char *tag = cut_word (&a->arguments);
|
||||
transform_str (tag, toupper_ascii);
|
||||
cstr_transform (tag, toupper_ascii);
|
||||
|
||||
if (*a->arguments)
|
||||
irc_send (a->s, "PRIVMSG %s :\x01%s %s\x01", target, tag, a->arguments);
|
||||
@ -7100,7 +7100,7 @@ handle_command_part (struct handler_args *a)
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (cut_word (&a->arguments), ' ', &v);
|
||||
cstr_split_ignore_empty (cut_word (&a->arguments), ' ', &v);
|
||||
for (size_t i = 0; i < v.len; i++)
|
||||
part_channel (a->s, v.vector[i], a->arguments);
|
||||
str_vector_free (&v);
|
||||
@ -7144,7 +7144,7 @@ handle_command_cycle (struct handler_args *a)
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (cut_word (&a->arguments), ' ', &v);
|
||||
cstr_split_ignore_empty (cut_word (&a->arguments), ' ', &v);
|
||||
for (size_t i = 0; i < v.len; i++)
|
||||
cycle_channel (a->s, v.vector[i], a->arguments);
|
||||
str_vector_free (&v);
|
||||
@ -7269,7 +7269,7 @@ mass_channel_mode_mask_list
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (a->arguments, ' ', &v);
|
||||
cstr_split_ignore_empty (a->arguments, ' ', &v);
|
||||
|
||||
// XXX: this may be a bit too trivial; we could map also nicknames
|
||||
// to information from WHO polling or userhost-in-names
|
||||
@ -7312,7 +7312,7 @@ handle_command_invite (struct handler_args *a)
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (a->arguments, ' ', &v);
|
||||
cstr_split_ignore_empty (a->arguments, ' ', &v);
|
||||
|
||||
bool result = !!v.len;
|
||||
for (size_t i = 0; i < v.len; i++)
|
||||
@ -7493,7 +7493,7 @@ handle_command_channel_mode
|
||||
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (a->arguments, ' ', &v);
|
||||
cstr_split_ignore_empty (a->arguments, ' ', &v);
|
||||
mass_channel_mode (a->s, a->channel_name, adding, mode_char, &v);
|
||||
str_vector_free (&v);
|
||||
return true;
|
||||
@ -7822,7 +7822,7 @@ expand_alias_definition (const struct str *definition, const char *arguments)
|
||||
{
|
||||
struct str_vector v;
|
||||
str_vector_init (&v);
|
||||
split_str_ignore_empty (arguments, ' ', &v);
|
||||
cstr_split_ignore_empty (arguments, ' ', &v);
|
||||
|
||||
struct str expanded;
|
||||
str_init (&expanded);
|
||||
@ -8115,7 +8115,7 @@ complete_option (struct app_context *ctx, struct completion *data,
|
||||
char *mask = xstrdup_printf ("%s*", word);
|
||||
for (size_t i = 0; i < options.len; i++)
|
||||
{
|
||||
char *key = str_cut_until (options.vector[i], " ");
|
||||
char *key = cstr_cut_until (options.vector[i], " ");
|
||||
if (!fnmatch (mask, key, 0))
|
||||
str_vector_add_owned (output, key);
|
||||
else
|
||||
@ -8808,7 +8808,8 @@ load_configuration (struct app_context *ctx)
|
||||
struct config_item_ *root = NULL;
|
||||
struct error *e = NULL;
|
||||
|
||||
char *filename = resolve_config_filename (PROGRAM_NAME ".conf");
|
||||
char *filename = resolve_filename
|
||||
(PROGRAM_NAME ".conf", resolve_relative_config_filename);
|
||||
if (filename)
|
||||
root = load_configuration_file (filename, &e);
|
||||
else
|
||||
|
34
kike.c
34
kike.c
@ -1368,7 +1368,7 @@ irc_handle_cap (const struct irc_message *msg, struct client *c)
|
||||
if (msg->params.len > 1)
|
||||
{
|
||||
args.full_params = msg->params.vector[1];
|
||||
split_str_ignore_empty (args.full_params, ' ', &args.params);
|
||||
cstr_split_ignore_empty (args.full_params, ' ', &args.params);
|
||||
}
|
||||
|
||||
struct irc_cap_command *cmd =
|
||||
@ -2151,7 +2151,7 @@ irc_handle_list (const struct irc_message *msg, struct client *c)
|
||||
{
|
||||
struct str_vector channels;
|
||||
str_vector_init (&channels);
|
||||
split_str_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
for (size_t i = 0; i < channels.len; i++)
|
||||
if ((chan = str_map_find (&c->ctx->channels, channels.vector[i]))
|
||||
&& (!(chan->modes & IRC_CHAN_MODE_SECRET)
|
||||
@ -2282,7 +2282,7 @@ irc_handle_names (const struct irc_message *msg, struct client *c)
|
||||
{
|
||||
struct str_vector channels;
|
||||
str_vector_init (&channels);
|
||||
split_str_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
for (size_t i = 0; i < channels.len; i++)
|
||||
if ((chan = str_map_find (&c->ctx->channels, channels.vector[i]))
|
||||
&& (!(chan->modes & IRC_CHAN_MODE_SECRET)
|
||||
@ -2445,7 +2445,7 @@ irc_handle_whois (const struct irc_message *msg, struct client *c)
|
||||
struct str_vector masks;
|
||||
str_vector_init (&masks);
|
||||
const char *masks_str = msg->params.vector[msg->params.len > 1];
|
||||
split_str_ignore_empty (masks_str, ',', &masks);
|
||||
cstr_split_ignore_empty (masks_str, ',', &masks);
|
||||
for (size_t i = 0; i < masks.len; i++)
|
||||
{
|
||||
const char *mask = masks.vector[i];
|
||||
@ -2486,7 +2486,7 @@ irc_handle_whowas (const struct irc_message *msg, struct client *c)
|
||||
|
||||
struct str_vector nicks;
|
||||
str_vector_init (&nicks);
|
||||
split_str_ignore_empty (msg->params.vector[0], ',', &nicks);
|
||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &nicks);
|
||||
|
||||
for (size_t i = 0; i < nicks.len; i++)
|
||||
{
|
||||
@ -2607,7 +2607,7 @@ irc_handle_part (const struct irc_message *msg, struct client *c)
|
||||
const char *reason = msg->params.len > 1 ? msg->params.vector[1] : NULL;
|
||||
struct str_vector channels;
|
||||
str_vector_init (&channels);
|
||||
split_str_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
for (size_t i = 0; i < channels.len; i++)
|
||||
irc_try_part (c, channels.vector[i], reason);
|
||||
str_vector_free (&channels);
|
||||
@ -2658,8 +2658,8 @@ irc_handle_kick (const struct irc_message *msg, struct client *c)
|
||||
struct str_vector users;
|
||||
str_vector_init (&channels);
|
||||
str_vector_init (&users);
|
||||
split_str_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
split_str_ignore_empty (msg->params.vector[1], ',', &users);
|
||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
cstr_split_ignore_empty (msg->params.vector[1], ',', &users);
|
||||
|
||||
if (channels.len == 1)
|
||||
for (size_t i = 0; i < users.len; i++)
|
||||
@ -2787,9 +2787,9 @@ irc_handle_join (const struct irc_message *msg, struct client *c)
|
||||
struct str_vector keys;
|
||||
str_vector_init (&channels);
|
||||
str_vector_init (&keys);
|
||||
split_str_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
cstr_split_ignore_empty (msg->params.vector[0], ',', &channels);
|
||||
if (msg->params.len > 1)
|
||||
split_str_ignore_empty (msg->params.vector[1], ',', &keys);
|
||||
cstr_split_ignore_empty (msg->params.vector[1], ',', &keys);
|
||||
|
||||
for (size_t i = 0; i < channels.len; i++)
|
||||
irc_try_join (c, channels.vector[i],
|
||||
@ -3508,8 +3508,10 @@ irc_initialize_ssl (struct server_context *ctx, struct error **e)
|
||||
|
||||
bool result = false;
|
||||
|
||||
char *cert_path = resolve_config_filename (ssl_cert);
|
||||
char *key_path = resolve_config_filename (ssl_key);
|
||||
char *cert_path = resolve_filename
|
||||
(ssl_cert, resolve_relative_config_filename);
|
||||
char *key_path = resolve_filename
|
||||
(ssl_key, resolve_relative_config_filename);
|
||||
if (!cert_path)
|
||||
error_set (e, "%s: %s", "cannot open file", ssl_cert);
|
||||
else if (!key_path)
|
||||
@ -3530,7 +3532,7 @@ irc_initialize_catalog (struct server_context *ctx, struct error **e)
|
||||
if (!catalog)
|
||||
return true;
|
||||
|
||||
char *path = resolve_config_filename (catalog);
|
||||
char *path = resolve_filename (catalog, resolve_relative_config_filename);
|
||||
if (!path)
|
||||
{
|
||||
error_set (e, "%s: %s", "cannot open file", catalog);
|
||||
@ -3556,7 +3558,7 @@ irc_initialize_motd (struct server_context *ctx, struct error **e)
|
||||
if (!motd)
|
||||
return true;
|
||||
|
||||
char *path = resolve_config_filename (motd);
|
||||
char *path = resolve_filename (motd, resolve_relative_config_filename);
|
||||
if (!path)
|
||||
{
|
||||
error_set (e, "%s: %s", "cannot open file", motd);
|
||||
@ -3608,7 +3610,7 @@ irc_parse_config (struct server_context *ctx, struct error **e)
|
||||
str_vector_init (&fingerprints);
|
||||
const char *operators = str_map_find (&ctx->config, "operators");
|
||||
if (operators)
|
||||
split_str_ignore_empty (operators, ',', &fingerprints);
|
||||
cstr_split_ignore_empty (operators, ',', &fingerprints);
|
||||
for (size_t i = 0; i < fingerprints.len; i++)
|
||||
{
|
||||
const char *key = fingerprints.vector[i];
|
||||
@ -3814,7 +3816,7 @@ irc_setup_listen_fds (struct server_context *ctx, struct error **e)
|
||||
|
||||
struct str_vector ports;
|
||||
str_vector_init (&ports);
|
||||
split_str_ignore_empty (bind_port, ',', &ports);
|
||||
cstr_split_ignore_empty (bind_port, ',', &ports);
|
||||
ctx->listen_fds = xcalloc (ports.len, sizeof *ctx->listen_fds);
|
||||
ctx->listen_events = xcalloc (ports.len, sizeof *ctx->listen_events);
|
||||
for (size_t i = 0; i < ports.len; i++)
|
||||
|
2
liberty
2
liberty
@ -1 +1 @@
|
||||
Subproject commit 34569e2b623df164ee965aa508fed274c7c15aaa
|
||||
Subproject commit 7fa873fb964156e71a00174f50e3f4bc343bcc04
|
11
zyklonb.c
11
zyklonb.c
@ -378,7 +378,8 @@ irc_initialize_ssl (struct bot_context *ctx, struct error **e)
|
||||
const char *ssl_cert = str_map_find (&ctx->config, "ssl_cert");
|
||||
if (ssl_cert)
|
||||
{
|
||||
char *path = resolve_config_filename (ssl_cert);
|
||||
char *path = resolve_filename
|
||||
(ssl_cert, resolve_relative_config_filename);
|
||||
if (!path)
|
||||
print_error ("%s: %s", "cannot open file", ssl_cert);
|
||||
// XXX: perhaps we should read the file ourselves for better messages
|
||||
@ -1141,10 +1142,10 @@ plugin_load_all_from_config (struct bot_context *ctx)
|
||||
struct str_vector plugins;
|
||||
str_vector_init (&plugins);
|
||||
|
||||
split_str_ignore_empty (plugin_list, ',', &plugins);
|
||||
cstr_split_ignore_empty (plugin_list, ',', &plugins);
|
||||
for (size_t i = 0; i < plugins.len; i++)
|
||||
{
|
||||
char *name = strip_str_in_place (plugins.vector[i], " ");
|
||||
char *name = cstr_strip_in_place (plugins.vector[i], " ");
|
||||
|
||||
struct error *e = NULL;
|
||||
if (!plugin_load (ctx, name, &e))
|
||||
@ -1181,10 +1182,10 @@ parse_bot_command (const char *s, const char *command, const char **following)
|
||||
static void
|
||||
split_bot_command_argument_list (const char *arguments, struct str_vector *out)
|
||||
{
|
||||
split_str_ignore_empty (arguments, ',', out);
|
||||
cstr_split_ignore_empty (arguments, ',', out);
|
||||
for (size_t i = 0; i < out->len; )
|
||||
{
|
||||
if (!*strip_str_in_place (out->vector[i], " \t"))
|
||||
if (!*cstr_strip_in_place (out->vector[i], " \t"))
|
||||
str_vector_remove (out, i);
|
||||
else
|
||||
i++;
|
||||
|
Loading…
Reference in New Issue
Block a user