Compare commits

...

13 Commits

Author SHA1 Message Date
bb30c7d86e Remove .travis.yml
We don't depend on any proprietary services no longer.  I'll have to
make my own replacements with blackjack and hookers.  Until then,
the file stays in the commit log as an example.
2018-06-21 23:58:24 +02:00
47ef2ae5bd Update README 2018-06-21 23:58:03 +02:00
69800a6afb Relicense to 0BSD, update mail address
I've come to the conclusion that copyright mostly just stands in the way
of software development.  In my jurisdiction I cannot give up my own
copyright and 0BSD seems to be the closest thing to public domain.

The updated mail address, also used in my author/committer lines,
is shorter and looks nicer.  People rarely interact anyway.
2018-06-21 23:57:25 +02:00
fe1035633a Describe syntax of advanced configuration w/ PEG 2018-04-19 00:09:46 +02:00
da75b6f735 siphash: silence fall-through warnings 2017-09-26 19:08:13 +02:00
199c56e141 Little improvements 2017-07-24 03:46:06 +02:00
6e9217e5d0 MPD client: +mpd_client_send_command_raw() 2017-06-26 03:35:05 +02:00
3835b6e499 Improve simple_config_update_from_file()
- considerably shorter
 - catch file read errors as we should
 - better error messages, now including the filename
 - disallow empty keys as they are never used
 - allow whitespace before start of comment

NUL characters stop processing now, though.  If anyone cares.
2017-06-22 20:42:44 +02:00
bf534010cb _init() -> _make() where possible 2017-06-22 20:42:44 +02:00
7b0d7a19e5 Cleanup 2017-06-14 23:28:44 +02:00
1dcd259d05 Make config_item_clone() static 2017-06-12 08:33:59 +02:00
03894cae45 Add VIM syntax highlight for "config" 2017-06-12 02:48:42 +02:00
412100289e Improve read_line()
One less useless boolean variable.
2017-06-12 02:48:42 +02:00
13 changed files with 369 additions and 457 deletions

View File

@@ -1,24 +0,0 @@
language: c
notifications:
irc:
channels: "irc.janouch.name#dev"
use_notice: true
skip_join: true
template:
- "%{repository_name}#%{build_number} on %{branch}: %{message}"
- " %{compare_url}"
- " %{build_url}"
on_success: change
on_failure: always
compiler:
- clang
- gcc
before_install:
- sudo apt-get update -qq
before_script:
- mkdir build
- cd build
script:
- cmake .. -DCMAKE_INSTALL_PREFIX=/usr
- make
- ctest -V

View File

@@ -2,10 +2,11 @@ project (liberty C)
cmake_minimum_required (VERSION 2.8.5) cmake_minimum_required (VERSION 2.8.5)
# Moar warnings # Moar warnings
if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC) if ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
# -Wunused-function is pretty annoying here, as everything is static # -Wunused-function is pretty annoying here, as everything is static
set (CMAKE_C_FLAGS "-std=c99 -Wall -Wextra -Wno-unused-function") set (wdisabled "-Wno-unused-function -Wno-implicit-fallthrough")
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUC) set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -Wall -Wextra ${wdisabled}")
endif ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU" OR CMAKE_COMPILER_IS_GNUCC)
# Dependencies # Dependencies
set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) set (CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
@@ -34,15 +35,8 @@ foreach (extra iconv rt)
endif (extra_lib_${extra}) endif (extra_lib_${extra})
endforeach (extra) endforeach (extra)
# Generate a configuration file
# TODO: actualy use the configuration file for something; so far we allow
# for direct inclusion without running this CMakeLists.txt
configure_file (${PROJECT_SOURCE_DIR}/liberty-config.h.in
${PROJECT_BINARY_DIR}/liberty-config.h)
include_directories (${PROJECT_SOURCE_DIR} ${PROJECT_BINARY_DIR})
set (common_sources ${PROJECT_BINARY_DIR}/liberty-config.h)
# Build some unit tests # Build some unit tests
include_directories (${PROJECT_SOURCE_DIR})
enable_testing () enable_testing ()
foreach (name liberty proto) foreach (name liberty proto)
add_executable (test-${name} tests/${name}.c ${common_sources}) add_executable (test-${name} tests/${name}.c ${common_sources})

View File

@@ -1,8 +1,7 @@
Copyright (c) 2014 - 2017, Přemysl Janouch <p.janouch@gmail.com> Copyright (c) 2014 - 2018, Přemysl Janouch <p@janouch.name>
Permission to use, copy, modify, and/or distribute this software for any Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above purpose with or without fee is hereby granted.
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF

View File

@@ -19,18 +19,13 @@ I'm not testing them at all, with the exception of OpenBSD.
Contributing and Support Contributing and Support
------------------------ ------------------------
Use this project's GitHub to report any bugs, request features, or submit pull Use https://git.janouch.name/p/liberty to report any bugs, request features,
requests. If you want to discuss this project, or maybe just hang out with or submit pull requests. `git send-email` is tolerated. If you want to discuss
the developer, feel free to join me at irc://irc.janouch.name, channel #dev. the project, feel free to join me at ircs://irc.janouch.name, channel #dev.
Bitcoin donations: 12r5uEWEgcHC46xd64tt3hHt9EUvYYDHe9 Bitcoin donations are accepted at: 12r5uEWEgcHC46xd64tt3hHt9EUvYYDHe9
License License
------- -------
'liberty' is written by Přemysl Janouch <p.janouch@gmail.com>. This software is released under the terms of the 0BSD license, the text of which
is included within the package along with the list of authors.
You may use the software under the terms of the ISC license, the text of which
is included within the package, or, at your option, you may relicense the work
under the MIT or the Modified BSD License, as listed at the following site:
http://www.gnu.org/licenses/license-list.html

View File

View File

@@ -1,11 +1,10 @@
/* /*
* liberty-proto.c: the ultimate C unlibrary: protocols * liberty-proto.c: the ultimate C unlibrary: protocols
* *
* Copyright (c) 2014 - 2016, Přemysl Janouch <p.janouch@gmail.com> * Copyright (c) 2014 - 2016, Přemysl Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted.
* copyright notice and this permission notice appear in all copies.
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -34,9 +33,7 @@ struct irc_message
static char * static char *
irc_unescape_message_tag (const char *value) irc_unescape_message_tag (const char *value)
{ {
struct str s; struct str s = str_make ();
str_init (&s);
bool escape = false; bool escape = false;
for (const char *p = value; *p; p++) for (const char *p = value; *p; p++)
{ {
@@ -63,8 +60,7 @@ irc_unescape_message_tag (const char *value)
static void static void
irc_parse_message_tags (const char *tags, struct str_map *out) irc_parse_message_tags (const char *tags, struct str_map *out)
{ {
struct strv v; struct strv v = strv_make ();
strv_init (&v);
cstr_split (tags, ";", true, &v); cstr_split (tags, ";", true, &v);
for (size_t i = 0; i < v.len; i++) for (size_t i = 0; i < v.len; i++)
@@ -78,19 +74,16 @@ irc_parse_message_tags (const char *tags, struct str_map *out)
else else
str_map_set (out, key, xstrdup ("")); str_map_set (out, key, xstrdup (""));
} }
strv_free (&v); strv_free (&v);
} }
static void static void
irc_parse_message (struct irc_message *msg, const char *line) irc_parse_message (struct irc_message *msg, const char *line)
{ {
str_map_init (&msg->tags); msg->tags = str_map_make (free);
msg->tags.free = free;
msg->prefix = NULL; msg->prefix = NULL;
msg->command = NULL; msg->command = NULL;
strv_init (&msg->params); msg->params = strv_make ();
// IRC 3.2 message tags // IRC 3.2 message tags
if (*line == '@') if (*line == '@')
@@ -288,14 +281,15 @@ struct http_tokenizer
struct str string; ///< "token" / "quoted-string" content struct str string; ///< "token" / "quoted-string" content
}; };
static void static struct http_tokenizer
http_tokenizer_init (struct http_tokenizer *self, const char *input, size_t len) http_tokenizer_make (const char *input, size_t len)
{ {
memset (self, 0, sizeof *self); return (struct http_tokenizer)
self->input = (const unsigned char *) input; {
self->input_len = len; .input = (const unsigned char *) input,
.input_len = len,
str_init (&self->string); .string = str_make (),
};
} }
static void static void
@@ -428,8 +422,8 @@ http_parse_media_type (const char *media_type,
char **type, char **subtype, struct str_map *parameters) char **type, char **subtype, struct str_map *parameters)
{ {
bool result = false; bool result = false;
struct http_tokenizer t; struct http_tokenizer t =
http_tokenizer_init (&t, media_type, strlen (media_type)); http_tokenizer_make (media_type, strlen (media_type));
if (http_tokenizer_next (&t, true) != HTTP_T_TOKEN) if (http_tokenizer_next (&t, true) != HTTP_T_TOKEN)
goto end; goto end;
@@ -490,8 +484,7 @@ http_parse_upgrade (const char *upgrade, struct http_protocol **out)
struct http_protocol *list = NULL; struct http_protocol *list = NULL;
struct http_protocol *tail = NULL; struct http_protocol *tail = NULL;
struct http_tokenizer t; struct http_tokenizer t = http_tokenizer_make (upgrade, strlen (upgrade));
http_tokenizer_init (&t, upgrade, strlen (upgrade));
enum { enum {
STATE_PROTOCOL_NAME, STATE_PROTOCOL_NAME,
@@ -618,16 +611,16 @@ struct scgi_parser
void *user_data; ///< User data passed to callbacks void *user_data; ///< User data passed to callbacks
}; };
static void static struct scgi_parser
scgi_parser_init (struct scgi_parser *self) scgi_parser_make (void)
{ {
memset (self, 0, sizeof *self); return (struct scgi_parser)
{
str_init (&self->input); .input = str_make (),
str_map_init (&self->headers); .headers = str_map_make (free),
self->headers.free = free; .name = str_make (),
str_init (&self->name); .value = str_make (),
str_init (&self->value); };
} }
static void static void
@@ -728,7 +721,7 @@ scgi_parser_push (struct scgi_parser *self,
self->name.str, str_steal (&self->value)); self->name.str, str_steal (&self->value));
str_reset (&self->name); str_reset (&self->name);
str_init (&self->value); self->value = str_make ();
self->state = SCGI_READING_NAME; self->state = SCGI_READING_NAME;
} }
@@ -827,12 +820,11 @@ struct fcgi_parser
void *user_data; ///< User data void *user_data; ///< User data
}; };
static void static struct fcgi_parser
fcgi_parser_init (struct fcgi_parser *self) fcgi_parser_make (void)
{ {
memset (self, 0, sizeof *self); return (struct fcgi_parser)
str_init (&self->input); { .input = str_make (), .content = str_make () };
str_init (&self->content);
} }
static void static void
@@ -845,8 +837,8 @@ fcgi_parser_free (struct fcgi_parser *self)
static void static void
fcgi_parser_unpack_header (struct fcgi_parser *self) fcgi_parser_unpack_header (struct fcgi_parser *self)
{ {
struct msg_unpacker unpacker; struct msg_unpacker unpacker =
msg_unpacker_init (&unpacker, self->input.str, self->input.len); msg_unpacker_make (self->input.str, self->input.len);
bool success = true; bool success = true;
uint8_t reserved; uint8_t reserved;
@@ -928,11 +920,10 @@ struct fcgi_nv_parser
char *value; ///< The current value, 0-terminated char *value; ///< The current value, 0-terminated
}; };
static void static struct fcgi_nv_parser
fcgi_nv_parser_init (struct fcgi_nv_parser *self) fcgi_nv_parser_make (void)
{ {
memset (self, 0, sizeof *self); return (struct fcgi_nv_parser) { .input = str_make () };
str_init (&self->input);
} }
static void static void
@@ -951,8 +942,8 @@ fcgi_nv_parser_push (struct fcgi_nv_parser *self, const void *data, size_t len)
while (true) while (true)
{ {
struct msg_unpacker unpacker; struct msg_unpacker unpacker =
msg_unpacker_init (&unpacker, self->input.str, self->input.len); msg_unpacker_make (self->input.str, self->input.len);
switch (self->state) switch (self->state)
{ {
@@ -1049,8 +1040,7 @@ fcgi_nv_convert_len (size_t len, struct str *output)
static void static void
fcgi_nv_convert (struct str_map *map, struct str *output) fcgi_nv_convert (struct str_map *map, struct str *output)
{ {
struct str_map_iter iter; struct str_map_iter iter = str_map_iter_make (map);
str_map_iter_init (&iter, map);
while (str_map_iter_next (&iter)) while (str_map_iter_next (&iter))
{ {
const char *name = iter.link->key; const char *name = iter.link->key;
@@ -1089,8 +1079,7 @@ ws_encode_response_key (const char *key)
SHA1 ((unsigned char *) response_key, strlen (response_key), hash); SHA1 ((unsigned char *) response_key, strlen (response_key), hash);
free (response_key); free (response_key);
struct str base64; struct str base64 = str_make ();
str_init (&base64);
base64_encode (hash, sizeof hash, &base64); base64_encode (hash, sizeof hash, &base64);
return str_steal (&base64); return str_steal (&base64);
} }
@@ -1168,11 +1157,10 @@ struct ws_parser
void *user_data; ///< User data for callbacks void *user_data; ///< User data for callbacks
}; };
static void static struct ws_parser
ws_parser_init (struct ws_parser *self) ws_parser_make (void)
{ {
memset (self, 0, sizeof *self); return (struct ws_parser) { .input = str_make () };
str_init (&self->input);
} }
static void static void
@@ -1213,8 +1201,8 @@ ws_parser_push (struct ws_parser *self, const void *data, size_t len)
bool success = false; bool success = false;
str_append_data (&self->input, data, len); str_append_data (&self->input, data, len);
struct msg_unpacker unpacker; struct msg_unpacker unpacker =
msg_unpacker_init (&unpacker, self->input.str, self->input.len); msg_unpacker_make (self->input.str, self->input.len);
while (true) while (true)
switch (self->state) switch (self->state)
@@ -1275,7 +1263,7 @@ ws_parser_push (struct ws_parser *self, const void *data, size_t len)
case WS_PARSER_PAYLOAD: case WS_PARSER_PAYLOAD:
// Move the buffer so that payload data is at the front // Move the buffer so that payload data is at the front
str_remove_slice (&self->input, 0, unpacker.offset); str_remove_slice (&self->input, 0, unpacker.offset);
msg_unpacker_init (&unpacker, self->input.str, self->input.len); unpacker = msg_unpacker_make (self->input.str, self->input.len);
if (self->input.len < self->payload_len) if (self->input.len < self->payload_len)
goto need_data; goto need_data;
@@ -1418,21 +1406,19 @@ struct mpd_client
static void mpd_client_reset (struct mpd_client *self); static void mpd_client_reset (struct mpd_client *self);
static void mpd_client_destroy_connector (struct mpd_client *self); static void mpd_client_destroy_connector (struct mpd_client *self);
static void static struct mpd_client
mpd_client_init (struct mpd_client *self, struct poller *poller) mpd_client_make (struct poller *poller)
{ {
memset (self, 0, sizeof *self); return (struct mpd_client)
{
self->poller = poller; .poller = poller,
self->socket = -1; .socket = -1,
.read_buffer = str_make (),
str_init (&self->read_buffer); .write_buffer = str_make (),
str_init (&self->write_buffer); .data = strv_make (),
.socket_event = poller_fd_make (poller, -1),
strv_init (&self->data); .timeout_timer = poller_timer_make (poller),
};
poller_fd_init (&self->socket_event, poller, -1);
poller_timer_init (&self->timeout_timer, poller);
} }
static void static void
@@ -1694,8 +1680,9 @@ mpd_client_add_task
static void mpd_client_send_command static void mpd_client_send_command
(struct mpd_client *self, const char *command, ...) ATTRIBUTE_SENTINEL; (struct mpd_client *self, const char *command, ...) ATTRIBUTE_SENTINEL;
/// Avoid calling this method directly if you don't want things to explode
static void static void
mpd_client_send_commandv (struct mpd_client *self, char **commands) mpd_client_send_command_raw (struct mpd_client *self, const char *raw)
{ {
// Automatically interrupt idle mode // Automatically interrupt idle mode
if (self->idling) if (self->idling)
@@ -1707,35 +1694,37 @@ mpd_client_send_commandv (struct mpd_client *self, char **commands)
mpd_client_send_command (self, "noidle", NULL); mpd_client_send_command (self, "noidle", NULL);
} }
struct str line;
str_init (&line);
for (; *commands; commands++)
{
if (line.len)
str_append_c (&line, ' ');
if (mpd_client_must_quote (*commands))
mpd_client_quote (*commands, &line);
else
str_append (&line, *commands);
}
if (self->on_io_hook) if (self->on_io_hook)
self->on_io_hook (self->user_data, true, line.str); self->on_io_hook (self->user_data, true, raw);
str_append_c (&line, '\n'); str_append (&self->write_buffer, raw);
str_append_str (&self->write_buffer, &line); str_append_c (&self->write_buffer, '\n');
str_free (&line);
mpd_client_update_poller (self); mpd_client_update_poller (self);
} }
static void
mpd_client_send_commandv (struct mpd_client *self, char **fields)
{
struct str line = str_make ();
for (; *fields; fields++)
{
if (line.len)
str_append_c (&line, ' ');
if (mpd_client_must_quote (*fields))
mpd_client_quote (*fields, &line);
else
str_append (&line, *fields);
}
mpd_client_send_command_raw (self, line.str);
str_free (&line);
}
static void static void
mpd_client_send_command (struct mpd_client *self, const char *command, ...) mpd_client_send_command (struct mpd_client *self, const char *command, ...)
{ {
struct strv v; struct strv v = strv_make ();
strv_init (&v);
va_list ap; va_list ap;
va_start (ap, command); va_start (ap, command);
@@ -1835,9 +1824,7 @@ mpd_client_idle (struct mpd_client *self, unsigned subsystems)
{ {
hard_assert (!self->in_list); hard_assert (!self->in_list);
struct strv v; struct strv v = strv_make ();
strv_init (&v);
strv_append (&v, "idle"); strv_append (&v, "idle");
for (size_t i = 0; i < N_ELEMENTS (mpd_subsystem_names); i++) for (size_t i = 0; i < N_ELEMENTS (mpd_subsystem_names); i++)
if (subsystems & (1 << i)) if (subsystems & (1 << i))
@@ -1864,7 +1851,7 @@ mpd_client_finish_connection (struct mpd_client *self, int socket)
self->socket = socket; self->socket = socket;
self->state = MPD_CONNECTED; self->state = MPD_CONNECTED;
poller_fd_init (&self->socket_event, self->poller, self->socket); self->socket_event = poller_fd_make (self->poller, self->socket);
self->socket_event.dispatcher = mpd_client_on_ready; self->socket_event.dispatcher = mpd_client_on_ready;
self->socket_event.user_data = self; self->socket_event.user_data = self;

View File

@@ -1,11 +1,10 @@
/* /*
* liberty-tui.c: the ultimate C unlibrary: TUI * liberty-tui.c: the ultimate C unlibrary: TUI
* *
* Copyright (c) 2016 - 2017, Přemysl Janouch <p.janouch@gmail.com> * Copyright (c) 2016 - 2017, Přemysl Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted.
* copyright notice and this permission notice appear in all copies.
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -61,8 +60,7 @@ struct attrs
static struct attrs static struct attrs
attrs_decode (const char *value) attrs_decode (const char *value)
{ {
struct strv v; struct strv v = strv_make ();
strv_init (&v);
cstr_split (value, " ", true, &v); cstr_split (value, " ", true, &v);
int colors = 0; int colors = 0;
@@ -110,11 +108,12 @@ struct row_buffer
int total_width; ///< Total width of all characters int total_width; ///< Total width of all characters
}; };
static void static struct row_buffer
row_buffer_init (struct row_buffer *self) row_buffer_make (void)
{ {
memset (self, 0, sizeof *self); struct row_buffer self = {};
ARRAY_INIT_SIZED (self->chars, 256); ARRAY_INIT_SIZED (self.chars, 256);
return self;
} }
static void static void

462
liberty.c
View File

@@ -1,11 +1,10 @@
/* /*
* liberty.c: the ultimate C unlibrary * liberty.c: the ultimate C unlibrary
* *
* Copyright (c) 2014 - 2016, Přemysl Janouch <p.janouch@gmail.com> * Copyright (c) 2014 - 2018, Přemysl Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted.
* copyright notice and this permission notice appear in all copies.
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -383,12 +382,14 @@ struct strv
size_t alloc; size_t alloc;
}; };
static void static struct strv
strv_init (struct strv *self) strv_make (void)
{ {
self->alloc = 4; struct strv self;
self->len = 0; self.alloc = 4;
self->vector = xcalloc (sizeof *self->vector, self->alloc); self.len = 0;
self.vector = xcalloc (sizeof *self.vector, self.alloc);
return self;
} }
static void static void
@@ -406,7 +407,7 @@ static void
strv_reset (struct strv *self) strv_reset (struct strv *self)
{ {
strv_free (self); strv_free (self);
strv_init (self); *self = strv_make ();
} }
static void static void
@@ -481,12 +482,14 @@ struct str
/// long as the allocation is below the given threshold. (Trivial heuristics.) /// long as the allocation is below the given threshold. (Trivial heuristics.)
#define STR_SHRINK_THRESHOLD (1 << 20) #define STR_SHRINK_THRESHOLD (1 << 20)
static void static struct str
str_init (struct str *self) str_make (void)
{ {
self->alloc = 16; struct str self;
self->len = 0; self.alloc = 16;
self->str = strcpy (xmalloc (self->alloc), ""); self.len = 0;
self.str = strcpy (xmalloc (self.alloc), "");
return self;
} }
static void static void
@@ -502,7 +505,7 @@ static void
str_reset (struct str *self) str_reset (struct str *self)
{ {
str_free (self); str_free (self);
str_init (self); *self = str_make ();
} }
static char * static char *
@@ -802,15 +805,17 @@ struct str_map
typedef void (*str_map_free_fn) (void *); typedef void (*str_map_free_fn) (void *);
static void static struct str_map
str_map_init (struct str_map *self) str_map_make (str_map_free_fn free)
{ {
self->alloc = STR_MAP_MIN_ALLOC; struct str_map self;
self->len = 0; self.alloc = STR_MAP_MIN_ALLOC;
self->free = NULL; self.len = 0;
self->key_xfrm = NULL; self.free = free;
self->map = xcalloc (self->alloc, sizeof *self->map); self.key_xfrm = NULL;
self->shrink_lock = false; self.map = xcalloc (self.alloc, sizeof *self.map);
self.shrink_lock = false;
return self;
} }
static void static void
@@ -1003,12 +1008,10 @@ struct str_map_iter
struct str_map_link *link; ///< Current link struct str_map_link *link; ///< Current link
}; };
static void static struct str_map_iter
str_map_iter_init (struct str_map_iter *self, const struct str_map *map) str_map_iter_make (const struct str_map *map)
{ {
self->map = map; return (struct str_map_iter) { .map = map, .next_index = 0, .link = NULL };
self->next_index = 0;
self->link = NULL;
} }
static void * static void *
@@ -1038,13 +1041,15 @@ struct str_map_unset_iter
struct str_map_link *next; ///< Next link struct str_map_link *next; ///< Next link
}; };
static void static struct str_map_unset_iter
str_map_unset_iter_init (struct str_map_unset_iter *self, struct str_map *map) str_map_unset_iter_make (struct str_map *map)
{ {
str_map_iter_init (&self->iter, map); struct str_map_unset_iter self;
self.iter = str_map_iter_make (map);
map->shrink_lock = true; map->shrink_lock = true;
(void) str_map_iter_next (&self->iter); (void) str_map_iter_next (&self.iter);
self->next = self->iter.link; self.next = self.iter.link;
return self;
} }
static void * static void *
@@ -1118,11 +1123,10 @@ struct async_manager
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void static struct async
async_init (struct async *self, struct async_manager *manager) async_make (struct async_manager *manager)
{ {
memset (self, 0, sizeof *self); return (struct async) { .manager = manager };
self->manager = manager;
} }
/// Only allowed from the main thread once the job has been started but before /// Only allowed from the main thread once the job has been started but before
@@ -1266,17 +1270,18 @@ async_manager_cancel_all (struct async_manager *self)
async_manager_dispatch (self); async_manager_dispatch (self);
} }
static void static struct async_manager
async_manager_init (struct async_manager *self) async_manager_make (void)
{ {
memset (self, 0, sizeof *self); struct async_manager self = {};
hard_assert (!pthread_mutex_init (&self->lock, NULL)); hard_assert (!pthread_mutex_init (&self.lock, NULL));
hard_assert (!pthread_cond_init (&self->finished_cond, NULL)); hard_assert (!pthread_cond_init (&self.finished_cond, NULL));
hard_assert (!pipe (self->finished_pipe)); hard_assert (!pipe (self.finished_pipe));
hard_assert (set_blocking (self->finished_pipe[0], false)); hard_assert (set_blocking (self.finished_pipe[0], false));
set_cloexec (self->finished_pipe[0]); set_cloexec (self.finished_pipe[0]);
set_cloexec (self->finished_pipe[1]); set_cloexec (self.finished_pipe[1]);
return self;
} }
static void static void
@@ -1355,12 +1360,14 @@ struct poller_timers
size_t alloc; ///< Number of timers allocated size_t alloc; ///< Number of timers allocated
}; };
static void static struct poller_timers
poller_timers_init (struct poller_timers *self) poller_timers_make (void)
{ {
self->alloc = POLLER_MIN_ALLOC; struct poller_timers self;
self->len = 0; self.alloc = POLLER_MIN_ALLOC;
self->heap = xmalloc (self->alloc * sizeof *self->heap); self.len = 0;
self.heap = xmalloc (self.alloc * sizeof *self.heap);
return self;
} }
static void static void
@@ -2085,12 +2092,11 @@ poller_run (struct poller *self)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void static struct poller_timer
poller_timer_init (struct poller_timer *self, struct poller *poller) poller_timer_make (struct poller *poller)
{ {
memset (self, 0, sizeof *self); return (struct poller_timer)
self->timers = &poller->common.timers; { .timers = &poller->common.timers, .index = -1, };
self->index = -1;
} }
static void static void
@@ -2115,11 +2121,10 @@ poller_timer_reset (struct poller_timer *self)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void static struct poller_idle
poller_idle_init (struct poller_idle *self, struct poller *poller) poller_idle_make (struct poller *poller)
{ {
memset (self, 0, sizeof *self); return (struct poller_idle) { .poller = poller };
self->poller = poller;
} }
static void static void
@@ -2146,13 +2151,10 @@ poller_idle_reset (struct poller_idle *self)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
static void static struct poller_fd
poller_fd_init (struct poller_fd *self, struct poller *poller, int fd) poller_fd_make (struct poller *poller, int fd)
{ {
memset (self, 0, sizeof *self); return (struct poller_fd) { .poller = poller, .index = -1, .fd = fd };
self->poller = poller;
self->index = -1;
self->fd = fd;
} }
static void static void
@@ -2183,12 +2185,12 @@ poller_common_dummy_dispatcher (const struct pollfd *pfd, void *user_data)
static void static void
poller_common_init (struct poller_common *self, struct poller *poller) poller_common_init (struct poller_common *self, struct poller *poller)
{ {
poller_timers_init (&self->timers); self->timers = poller_timers_make ();
self->idle = NULL; self->idle = NULL;
#ifdef LIBERTY_WANT_ASYNC #ifdef LIBERTY_WANT_ASYNC
async_manager_init (&self->async); self->async = async_manager_make ();
poller_fd_init (&self->async_event, poller, self->async.finished_pipe[0]); self->async_event = poller_fd_make (poller, self->async.finished_pipe[0]);
poller_fd_set (&self->async_event, POLLIN); poller_fd_set (&self->async_event, POLLIN);
self->async_event.dispatcher = poller_common_dummy_dispatcher; self->async_event.dispatcher = poller_common_dummy_dispatcher;
self->async_event.user_data = self; self->async_event.user_data = self;
@@ -2289,7 +2291,7 @@ async_getaddrinfo (struct async_manager *manager,
const char *host, const char *service, const struct addrinfo *hints) const char *host, const char *service, const struct addrinfo *hints)
{ {
struct async_getaddrinfo *self = xcalloc (1, sizeof *self); struct async_getaddrinfo *self = xcalloc (1, sizeof *self);
async_init (&self->async, manager); self->async = async_make (manager);
if (host) self->host = xstrdup (host); if (host) self->host = xstrdup (host);
if (service) self->service = xstrdup (service); if (service) self->service = xstrdup (service);
@@ -2353,7 +2355,7 @@ async_getnameinfo (struct async_manager *manager,
const struct sockaddr *sa, socklen_t sa_len, int flags) const struct sockaddr *sa, socklen_t sa_len, int flags)
{ {
struct async_getnameinfo *self = xcalloc (1, sizeof *self); struct async_getnameinfo *self = xcalloc (1, sizeof *self);
async_init (&self->async, manager); self->async = async_make (manager);
self->address = memcpy (xmalloc (sa_len), sa, sa_len); self->address = memcpy (xmalloc (sa_len), sa, sa_len);
self->address_len = sa_len; self->address_len = sa_len;
@@ -2387,12 +2389,10 @@ struct write_queue
size_t len; size_t len;
}; };
static void static struct write_queue
write_queue_init (struct write_queue *self) write_queue_make (void)
{ {
self->head = self->tail = NULL; return (struct write_queue) {};
self->head_offset = 0;
self->len = 0;
} }
static void static void
@@ -2444,11 +2444,10 @@ struct msg_reader
uint64_t offset; ///< Current offset in the buffer uint64_t offset; ///< Current offset in the buffer
}; };
static void static struct msg_reader
msg_reader_init (struct msg_reader *self) msg_reader_make (void)
{ {
str_init (&self->buf); return (struct msg_reader) { .buf = str_make (), .offset = 0 };
self->offset = 0;
} }
static void static void
@@ -2520,12 +2519,10 @@ struct msg_unpacker
size_t len; size_t len;
}; };
static void static struct msg_unpacker
msg_unpacker_init (struct msg_unpacker *self, const void *data, size_t len) msg_unpacker_make (const void *data, size_t len)
{ {
self->data = data; return (struct msg_unpacker) { .data = data, .len = len, .offset = 0 };
self->len = len;
self->offset = 0;
} }
static size_t static size_t
@@ -2600,12 +2597,13 @@ struct msg_writer
struct str buf; ///< Holds the message data struct str buf; ///< Holds the message data
}; };
static void static struct msg_writer
msg_writer_init (struct msg_writer *self) msg_writer_make (void)
{ {
str_init (&self->buf); struct msg_writer self = { .buf = str_make () };
// Placeholder for message length // Placeholder for message length
str_append_data (&self->buf, "\x00\x00\x00\x00" "\x00\x00\x00\x00", 8); str_append_data (&self.buf, "\x00\x00\x00\x00" "\x00\x00\x00\x00", 8);
return self;
} }
static void * static void *
@@ -2765,10 +2763,10 @@ struct utf8_iter
size_t len; ///< How many bytes remain size_t len; ///< How many bytes remain
}; };
static void static struct utf8_iter
utf8_iter_init (struct utf8_iter *self, const char *s) utf8_iter_make (const char *s)
{ {
self->len = strlen ((self->s = s)); return (struct utf8_iter) { .s = s, .len = strlen (s) };
} }
static int32_t static int32_t
@@ -2964,8 +2962,7 @@ strv_join (const struct strv *v, const char *delimiter)
if (!v->len) if (!v->len)
return xstrdup (""); return xstrdup ("");
struct str result; struct str result = str_make ();
str_init (&result);
str_append (&result, v->vector[0]); str_append (&result, v->vector[0]);
for (size_t i = 1; i < v->len; i++) for (size_t i = 1; i < v->len; i++)
str_append_printf (&result, "%s%s", delimiter, v->vector[i]); str_append_printf (&result, "%s%s", delimiter, v->vector[i]);
@@ -2978,8 +2975,7 @@ static char *
xstrdup_printf (const char *format, ...) xstrdup_printf (const char *format, ...)
{ {
va_list ap; va_list ap;
struct str tmp; struct str tmp = str_make ();
str_init (&tmp);
va_start (ap, format); va_start (ap, format);
str_append_vprintf (&tmp, format, ap); str_append_vprintf (&tmp, format, ap);
va_end (ap); va_end (ap);
@@ -3040,23 +3036,19 @@ xstrtoul (unsigned long *out, const char *s, int base)
} }
static bool static bool
read_line (FILE *fp, struct str *s) read_line (FILE *fp, struct str *line)
{ {
str_reset (line);
int c; int c;
bool at_end = true; while ((c = fgetc (fp)) != '\n')
str_reset (s);
while ((c = fgetc (fp)) != EOF)
{ {
at_end = false; if (c == EOF)
if (c == '\r') return line->len != 0;
continue; if (c != '\r')
if (c == '\n') str_append_c (line, c);
break;
str_append_c (s, c);
} }
return true;
return !at_end;
} }
static char * static char *
@@ -3103,8 +3095,7 @@ lock_pid_file (const char *path, struct error **e)
return -1; return -1;
} }
struct str pid; struct str pid = str_make ();
str_init (&pid);
str_append_printf (&pid, "%ld", (long) getpid ()); str_append_printf (&pid, "%ld", (long) getpid ());
if (ftruncate (fd, 0) if (ftruncate (fd, 0)
@@ -3212,8 +3203,7 @@ resolve_relative_filename_generic
static void static void
get_xdg_config_dirs (struct strv *out) get_xdg_config_dirs (struct strv *out)
{ {
struct str config_home; struct str config_home = str_make ();
str_init (&config_home);
get_xdg_home_dir (&config_home, "XDG_CONFIG_HOME", ".config"); get_xdg_home_dir (&config_home, "XDG_CONFIG_HOME", ".config");
strv_append (out, config_home.str); strv_append (out, config_home.str);
str_free (&config_home); str_free (&config_home);
@@ -3227,8 +3217,7 @@ get_xdg_config_dirs (struct strv *out)
static char * static char *
resolve_relative_config_filename (const char *filename) resolve_relative_config_filename (const char *filename)
{ {
struct strv paths; struct strv paths = strv_make ();
strv_init (&paths);
get_xdg_config_dirs (&paths); get_xdg_config_dirs (&paths);
char *result = resolve_relative_filename_generic char *result = resolve_relative_filename_generic
(&paths, PROGRAM_NAME "/", filename); (&paths, PROGRAM_NAME "/", filename);
@@ -3239,8 +3228,7 @@ resolve_relative_config_filename (const char *filename)
static void static void
get_xdg_data_dirs (struct strv *out) get_xdg_data_dirs (struct strv *out)
{ {
struct str data_home; struct str data_home = str_make ();
str_init (&data_home);
get_xdg_home_dir (&data_home, "XDG_DATA_HOME", ".local/share"); get_xdg_home_dir (&data_home, "XDG_DATA_HOME", ".local/share");
strv_append (out, data_home.str); strv_append (out, data_home.str);
str_free (&data_home); str_free (&data_home);
@@ -3254,8 +3242,7 @@ get_xdg_data_dirs (struct strv *out)
static char * static char *
resolve_relative_data_filename (const char *filename) resolve_relative_data_filename (const char *filename)
{ {
struct strv paths; struct strv paths = strv_make ();
strv_init (&paths);
get_xdg_data_dirs (&paths); get_xdg_data_dirs (&paths);
char *result = resolve_relative_filename_generic char *result = resolve_relative_filename_generic
(&paths, PROGRAM_NAME "/", filename); (&paths, PROGRAM_NAME "/", filename);
@@ -3266,9 +3253,7 @@ resolve_relative_data_filename (const char *filename)
static char * static char *
resolve_relative_runtime_filename (const char *filename) resolve_relative_runtime_filename (const char *filename)
{ {
struct str path; struct str path = str_make ();
str_init (&path);
const char *runtime_dir = getenv ("XDG_RUNTIME_DIR"); const char *runtime_dir = getenv ("XDG_RUNTIME_DIR");
if (runtime_dir && *runtime_dir == '/') if (runtime_dir && *runtime_dir == '/')
str_append (&path, runtime_dir); str_append (&path, runtime_dir);
@@ -3294,8 +3279,7 @@ try_expand_tilde (const char *filename)
size_t until_slash = strcspn (filename, "/"); size_t until_slash = strcspn (filename, "/");
if (!until_slash) if (!until_slash)
{ {
struct str expanded; struct str expanded = str_make ();
str_init (&expanded);
str_append_env_path (&expanded, "HOME", false); str_append_env_path (&expanded, "HOME", false);
str_append (&expanded, filename); str_append (&expanded, filename);
return str_steal (&expanded); return str_steal (&expanded);
@@ -3410,11 +3394,10 @@ regex_free (void *regex)
// Adding basic support for subgroups is easy: check `re_nsub' and output into // Adding basic support for subgroups is easy: check `re_nsub' and output into
// a `struct strv' (if all we want is the substrings). // a `struct strv' (if all we want is the substrings).
static void static struct str_map
regex_cache_init (struct str_map *cache) regex_cache_make (void)
{ {
str_map_init (cache); return str_map_make (regex_free);
cache->free = regex_free;
} }
static bool static bool
@@ -3511,14 +3494,10 @@ write_file_safe (const char *filename, const void *data, size_t data_len,
// --- Simple configuration ---------------------------------------------------- // --- Simple configuration ----------------------------------------------------
// The keys are stripped of surrounding whitespace, the values are not. // This is the bare minimum to make an application configurable.
// Keys are stripped of surrounding whitespace, values are not.
struct simple_config_item struct simple_config_item { const char *key, *default_value, *description; };
{
const char *key;
const char *default_value;
const char *description;
};
static void static void
simple_config_load_defaults simple_config_load_defaults
@@ -3536,62 +3515,35 @@ simple_config_update_from_file (struct str_map *config, struct error **e)
{ {
char *filename = resolve_filename char *filename = resolve_filename
(PROGRAM_NAME ".conf", resolve_relative_config_filename); (PROGRAM_NAME ".conf", resolve_relative_config_filename);
if (!filename) struct str s = str_make ();
return true; bool ok = !filename || read_file (filename, &s, e);
size_t line_no = 0;
FILE *fp = fopen (filename, "r"); for (char *x = strtok (s.str, "\r\n"); ok && x; x = strtok (NULL, "\r\n"))
if (!fp)
{ {
error_set (e, "could not open `%s' for reading: %s", line_no++;
filename, strerror (errno)); if (strchr ("#", *(x += strspn (x, " \t"))))
free (filename);
return false;
}
struct str line;
str_init (&line);
bool errors = false;
for (unsigned line_no = 1; read_line (fp, &line); line_no++)
{
char *start = line.str;
if (*start == '#')
continue; continue;
while (isspace (*start)) char *equals = strchr (x, '=');
start++; if (!equals || equals == x)
ok = error_set (e, "%s: malformed line %zu", filename, line_no);
char *end = strchr (start, '='); else
if (end)
{ {
char *value = end + 1; char *end = equals++;
do do *end = '\0'; while (strchr (" \t", *--end));
*end = '\0'; str_map_set (config, x, xstrdup (equals));
while (isspace (*--end));
str_map_set (config, start, xstrdup (value));
}
else if (*start)
{
error_set (e, "line %u in config: %s", line_no, "malformed input");
errors = true;
break;
} }
} }
str_free (&s);
str_free (&line);
fclose (fp);
free (filename); free (filename);
return !errors; return ok;
} }
static char * static char *
write_configuration_file (const char *path_hint, const struct str *data, write_configuration_file (const char *path_hint, const struct str *data,
struct error **e) struct error **e)
{ {
struct str path; struct str path = str_make ();
str_init (&path);
if (path_hint) if (path_hint)
str_append (&path, path_hint); str_append (&path, path_hint);
else else
@@ -3612,9 +3564,7 @@ static char *
simple_config_write_default (const char *path_hint, const char *prolog, simple_config_write_default (const char *path_hint, const char *prolog,
const struct simple_config_item *table, struct error **e) const struct simple_config_item *table, struct error **e)
{ {
struct str data; struct str data = str_make ();
str_init (&data);
if (prolog) if (prolog)
str_append (&data, prolog); str_append (&data, prolog);
@@ -3706,31 +3656,31 @@ opt_handler_free (struct opt_handler *self)
free (self->opt_string); free (self->opt_string);
} }
static void static struct opt_handler
opt_handler_init (struct opt_handler *self, int argc, char **argv, opt_handler_make (int argc, char **argv,
const struct opt *opts, const char *arg_hint, const char *description) const struct opt *opts, const char *arg_hint, const char *description)
{ {
memset (self, 0, sizeof *self); struct opt_handler self =
self->argc = argc; {
self->argv = argv; .argc = argc,
self->arg_hint = arg_hint; .argv = argv,
self->description = description; .arg_hint = arg_hint,
.description = description,
};
size_t len = 0; size_t len = 0;
for (const struct opt *iter = opts; iter->long_name; iter++) for (const struct opt *iter = opts; iter->long_name; iter++)
len++; len++;
self->opts = opts; self.opts = opts;
self->opts_len = len; self.opts_len = len;
self->options = xcalloc (len + 1, sizeof *self->options); self.options = xcalloc (len + 1, sizeof *self.options);
struct str opt_string;
str_init (&opt_string);
struct str opt_string = str_make ();
for (size_t i = 0; i < len; i++) for (size_t i = 0; i < len; i++)
{ {
const struct opt *opt = opts + i; const struct opt *opt = opts + i;
struct option *mapped = self->options + i; struct option *mapped = self.options + i;
mapped->name = opt->long_name; mapped->name = opt->long_name;
if (!opt->arg_hint) if (!opt->arg_hint)
@@ -3752,25 +3702,21 @@ opt_handler_init (struct opt_handler *self, int argc, char **argv,
str_append_c (&opt_string, ':'); str_append_c (&opt_string, ':');
} }
} }
self.opt_string = str_steal (&opt_string);
self->opt_string = str_steal (&opt_string); return self;
} }
static void static void
opt_handler_usage (const struct opt_handler *self, FILE *stream) opt_handler_usage (const struct opt_handler *self, FILE *stream)
{ {
struct str usage; struct str usage = str_make ();
str_init (&usage);
str_append_printf (&usage, "Usage: %s [OPTION]... %s\n", str_append_printf (&usage, "Usage: %s [OPTION]... %s\n",
self->argv[0], self->arg_hint ? self->arg_hint : ""); self->argv[0], self->arg_hint ? self->arg_hint : "");
str_append_printf (&usage, "%s\n\n", self->description); str_append_printf (&usage, "%s\n\n", self->description);
for (size_t i = 0; i < self->opts_len; i++) for (size_t i = 0; i < self->opts_len; i++)
{ {
struct str row; struct str row = str_make ();
str_init (&row);
const struct opt *opt = self->opts + i; const struct opt *opt = self->opts + i;
if (!(opt->flags & OPT_LONG_ONLY)) if (!(opt->flags & OPT_LONG_ONLY))
str_append_printf (&row, " -%c, ", opt->short_name); str_append_printf (&row, " -%c, ", opt->short_name);
@@ -3841,8 +3787,8 @@ static void
test_init (struct test *self, int argc, char **argv) test_init (struct test *self, int argc, char **argv)
{ {
memset (self, 0, sizeof *self); memset (self, 0, sizeof *self);
str_map_init (&self->whitelist); self->whitelist = str_map_make (NULL);
str_map_init (&self->blacklist); self->blacklist = str_map_make (NULL);
// Usually this shouldn't pose a problem but let's make it optional // Usually this shouldn't pose a problem but let's make it optional
self->can_fork = true; self->can_fork = true;
@@ -3858,8 +3804,8 @@ test_init (struct test *self, int argc, char **argv)
{ 0, NULL, NULL, 0, NULL } { 0, NULL, NULL, 0, NULL }
}; };
struct opt_handler oh; struct opt_handler oh =
opt_handler_init (&oh, argc, argv, opts, NULL, "Unit test runner"); opt_handler_make (argc, argv, opts, NULL, "Unit test runner");
int c; int c;
while ((c = opt_handler_get (&oh)) != -1) while ((c = opt_handler_get (&oh)) != -1)
@@ -3929,8 +3875,7 @@ test_add_internal (struct test *self, const char *name, size_t fixture_size,
static bool static bool
str_map_glob_match (struct str_map *self, const char *entry) str_map_glob_match (struct str_map *self, const char *entry)
{ {
struct str_map_iter iter; struct str_map_iter iter = str_map_iter_make (self);
str_map_iter_init (&iter, self);
while (str_map_iter_next (&iter)) while (str_map_iter_next (&iter))
if (!fnmatch (iter.link->key, entry, 0)) if (!fnmatch (iter.link->key, entry, 0))
return true; return true;
@@ -4254,7 +4199,7 @@ connector_init (struct connector *self, struct poller *poller)
memset (self, 0, sizeof *self); memset (self, 0, sizeof *self);
self->poller = poller; self->poller = poller;
self->socket = -1; self->socket = -1;
poller_fd_init (&self->connected_event, poller, self->socket); self->connected_event = poller_fd_make (poller, self->socket);
self->connected_event.user_data = self; self->connected_event.user_data = self;
self->connected_event.dispatcher = (poller_fd_fn) connector_on_ready; self->connected_event.dispatcher = (poller_fd_fn) connector_on_ready;
} }
@@ -4391,6 +4336,32 @@ socket_io_try_write (int socket_fd, struct str *wb)
// This is a more powerful configuration format, adding key-value maps and // This is a more powerful configuration format, adding key-value maps and
// simplifying item validation and dynamic handling of changes. All strings // simplifying item validation and dynamic handling of changes. All strings
// must be encoded in UTF-8. // must be encoded in UTF-8.
//
// The syntax is roughly described by the following parsing expression grammar:
//
// config = entries eof # as if there were implicit curly braces around
// entries = (newline* pair)* newline*
// pair = key newline* lws '=' newline* value (&endobj / newline / eof)
// key = string / !null !boolean lws [A-Za-z_][0-9A-Za-z_]*
// value = object / string / integer / null / boolean
//
// object = lws '{' entries endobj
// endobj = lws '}'
//
// string = lws '"' ('\\' escape / ![\\"] char)* '"'
// char = [\0-\177] # or any Unicode codepoint in the UTF-8 encoding
// escape = [\\"abfnrtv] / [xX][0-9A-Fa-f][0-9A-Fa-f]? / [0-7][0-7]?[0-7]?
//
// integer = lws '-'? [0-9]+ # whatever strtoll() accepts on your system
// null = lws 'null'
// boolean = lws 'yes' / lws 'YES' / lws 'no' / lws 'NO'
// / lws 'on' / lws 'ON' / lws 'off' / lws 'OFF'
// / lws 'true' / lws 'TRUE' / lws 'false' / lws 'FALSE'
//
// newline = lws comment? '\n'
// eof = lws comment? !.
// lws = [ \t\r]* # linear whitespace (plus CR as it is insignificant)
// comment = '#' (!'\n' .)*
enum config_item_type enum config_item_type
{ {
@@ -4531,7 +4502,7 @@ static struct config_item *
config_item_string (const struct str *s) config_item_string (const struct str *s)
{ {
struct config_item *self = config_item_new (CONFIG_ITEM_STRING); struct config_item *self = config_item_new (CONFIG_ITEM_STRING);
str_init (&self->value.string); self->value.string = str_make ();
hard_assert (utf8_validate hard_assert (utf8_validate
(self->value.string.str, self->value.string.len)); (self->value.string.str, self->value.string.len));
if (s) str_append_str (&self->value.string, s); if (s) str_append_str (&self->value.string, s);
@@ -4541,8 +4512,7 @@ config_item_string (const struct str *s)
static struct config_item * static struct config_item *
config_item_string_from_cstr (const char *s) config_item_string_from_cstr (const char *s)
{ {
struct str tmp; struct str tmp = str_make ();
str_init (&tmp);
str_append (&tmp, s); str_append (&tmp, s);
struct config_item *self = config_item_string (&tmp); struct config_item *self = config_item_string (&tmp);
str_free (&tmp); str_free (&tmp);
@@ -4561,8 +4531,7 @@ static struct config_item *
config_item_object (void) config_item_object (void)
{ {
struct config_item *self = config_item_new (CONFIG_ITEM_OBJECT); struct config_item *self = config_item_new (CONFIG_ITEM_OBJECT);
str_map_init (&self->value.object); self->value.object = str_map_make ((str_map_free_fn) config_item_destroy);
self->value.object.free = (void (*)(void *)) config_item_destroy;
return self; return self;
} }
@@ -4632,8 +4601,7 @@ config_item_get (struct config_item *self, const char *path, struct error **e)
{ {
hard_assert (self->type == CONFIG_ITEM_OBJECT); hard_assert (self->type == CONFIG_ITEM_OBJECT);
struct strv v; struct strv v = strv_make ();
strv_init (&v);
cstr_split (path, ".", false, &v); cstr_split (path, ".", false, &v);
struct config_item *result = NULL; struct config_item *result = NULL;
@@ -4772,9 +4740,7 @@ config_item_write_object_innards
{ {
hard_assert (object->type == CONFIG_ITEM_OBJECT); hard_assert (object->type == CONFIG_ITEM_OBJECT);
struct str_map_iter iter; struct str_map_iter iter = str_map_iter_make (&object->value.object);
str_map_iter_init (&iter, &object->value.object);
struct config_item *value; struct config_item *value;
while ((value = str_map_iter_next (&iter))) while ((value = str_map_iter_next (&iter)))
config_item_write_kv_pair (self, iter.link->key, value); config_item_write_kv_pair (self, iter.link->key, value);
@@ -4849,14 +4815,11 @@ struct config_tokenizer
}; };
/// Input has to be null-terminated anyway /// Input has to be null-terminated anyway
static void static struct config_tokenizer
config_tokenizer_init (struct config_tokenizer *self, const char *p, size_t len) config_tokenizer_make (const char *p, size_t len)
{ {
memset (self, 0, sizeof *self); return (struct config_tokenizer)
self->p = p; { .p = p, .len = len, .report_line = true, .string = str_make () };
self->len = len;
self->report_line = true;
str_init (&self->string);
} }
static void static void
@@ -4894,8 +4857,7 @@ static void
config_tokenizer_error (struct config_tokenizer *self, config_tokenizer_error (struct config_tokenizer *self,
struct error **e, const char *format, ...) struct error **e, const char *format, ...)
{ {
struct str description; struct str description = str_make ();
str_init (&description);
va_list ap; va_list ap;
va_start (ap, format); va_start (ap, format);
@@ -5112,15 +5074,16 @@ struct config_parser
bool replace_token; ///< Replace the token bool replace_token; ///< Replace the token
}; };
static void static struct config_parser
config_parser_init (struct config_parser *self, const char *script, size_t len) config_parser_make (const char *script, size_t len)
{ {
memset (self, 0, sizeof *self);
config_tokenizer_init (&self->tokenizer, script, len);
// As reading in tokens may cause exceptions, we wait for the first peek() // As reading in tokens may cause exceptions, we wait for the first peek()
// to replace the initial CONFIG_T_ABORT. // to replace the initial CONFIG_T_ABORT.
self->replace_token = true; return (struct config_parser)
{
.tokenizer = config_tokenizer_make (script, len),
.replace_token = true,
};
} }
static void static void
@@ -5290,9 +5253,7 @@ static struct config_item *
config_item_parse (const char *script, size_t len, config_item_parse (const char *script, size_t len,
bool single_value_only, struct error **e) bool single_value_only, struct error **e)
{ {
struct config_parser parser; struct config_parser parser = config_parser_make (script, len);
config_parser_init (&parser, script, len);
struct config_item *volatile object = NULL; struct config_item *volatile object = NULL;
jmp_buf err; jmp_buf err;
@@ -5325,12 +5286,11 @@ end:
} }
/// Clone an item. Schema assignments aren't retained. /// Clone an item. Schema assignments aren't retained.
struct config_item * static struct config_item *
config_item_clone (struct config_item *self) config_item_clone (struct config_item *self)
{ {
// Oh well, it saves code // Oh well, it saves code
struct str tmp; struct str tmp = str_make ();
str_init (&tmp);
config_item_write (self, false, &tmp); config_item_write (self, false, &tmp);
struct config_item *result = struct config_item *result =
config_item_parse (tmp.str, tmp.len, true, NULL); config_item_parse (tmp.str, tmp.len, true, NULL);
@@ -5343,8 +5303,7 @@ config_read_from_file (const char *filename, struct error **e)
{ {
struct config_item *root = NULL; struct config_item *root = NULL;
struct str data; struct str data = str_make ();
str_init (&data);
if (!read_file (filename, &data, e)) if (!read_file (filename, &data, e))
goto end; goto end;
@@ -5444,9 +5403,7 @@ config_schema_call_changed (struct config_item *item)
{ {
if (item->type == CONFIG_ITEM_OBJECT) if (item->type == CONFIG_ITEM_OBJECT)
{ {
struct str_map_iter iter; struct str_map_iter iter = str_map_iter_make (&item->value.object);
str_map_iter_init (&iter, &item->value.object);
struct config_item *child; struct config_item *child;
while ((child = str_map_iter_next (&iter))) while ((child = str_map_iter_next (&iter)))
config_schema_call_changed (child); config_schema_call_changed (child);
@@ -5482,12 +5439,11 @@ struct config
struct config_item *root; ///< CONFIG_ITEM_OBJECT struct config_item *root; ///< CONFIG_ITEM_OBJECT
}; };
static void static struct config
config_init (struct config *self) config_make (void)
{ {
memset (self, 0, sizeof *self); return (struct config)
str_map_init (&self->modules); { .modules = str_map_make ((str_map_free_fn) config_module_destroy) };
self->modules.free = (str_map_free_fn) config_module_destroy;
} }
static void static void
@@ -5518,9 +5474,7 @@ config_load (struct config *self, struct config_item *root)
config_item_destroy (self->root); config_item_destroy (self->root);
self->root = root; self->root = root;
struct str_map_iter iter; struct str_map_iter iter = str_map_iter_make (&self->modules);
str_map_iter_init (&iter, &self->modules);
struct config_module *module; struct config_module *module;
while ((module = str_map_iter_next (&iter))) while ((module = str_map_iter_next (&iter)))
{ {

26
libertyconf.vim Normal file
View File

@@ -0,0 +1,26 @@
" Since the liberty configuration format is nearly indistinguishable,
" this syntax highlight definition needs to be loaded with `set ft=libertyconf`
if exists("b:current_syntax")
finish
endif
syn match libertyconfError "[^_[:alnum:][:space:]]\+"
syn match libertyconfComment "#.*"
syn match libertyconfSpecial "{\|}\|="
syn match libertyconfNumber "[+-]\=\<\d\+\>"
syn match libertyconfBoolean "\c\<\(true\|yes\|on\|false\|no\|off\)\>"
syn match libertyconfNull "null"
syn match libertyconfEscape display "\\\([xX]\x\{1,2}\|\o\{1,3}\|.\|$\)"
\ contained
syn region libertyconfString start=+"+ skip=+\\\\\|\\"+ end=+"+
\ contains=libertyconfEscape
let b:current_syntax = "libertyconf"
hi def link libertyconfError Error
hi def link libertyconfComment Comment
hi def link libertyconfSpecial Special
hi def link libertyconfNumber Number
hi def link libertyconfBoolean Boolean
hi def link libertyconfNull Constant
hi def link libertyconfEscape SpecialChar
hi def link libertyconfString String

View File

@@ -14,7 +14,7 @@ fakeroot sh -e <<-EOF
url = $url url = $url
builddate = \`date -u +%s\` builddate = \`date -u +%s\`
packager = $author packager = $author
size = \`du -sb --apparent-size | cut -f1\` size = \`du -sb | cut -f1\`
arch = $arch arch = $arch
END END
cd "$wd" && tar cJf "../$target" .PKGINFO * cd "$wd" && tar cJf "../$target" .PKGINFO *

View File

@@ -61,13 +61,13 @@ siphash (const unsigned char key[16], const unsigned char *m, size_t len)
switch (len - blocks) switch (len - blocks)
{ {
case 7: last7 |= (uint64_t) m[i + 6] << 48; case 7: last7 |= (uint64_t) m[i + 6] << 48; // Fall-through
case 6: last7 |= (uint64_t) m[i + 5] << 40; case 6: last7 |= (uint64_t) m[i + 5] << 40; // Fall-through
case 5: last7 |= (uint64_t) m[i + 4] << 32; case 5: last7 |= (uint64_t) m[i + 4] << 32; // Fall-through
case 4: last7 |= (uint64_t) m[i + 3] << 24; case 4: last7 |= (uint64_t) m[i + 3] << 24; // Fall-through
case 3: last7 |= (uint64_t) m[i + 2] << 16; case 3: last7 |= (uint64_t) m[i + 2] << 16; // Fall-through
case 2: last7 |= (uint64_t) m[i + 1] << 8; case 2: last7 |= (uint64_t) m[i + 1] << 8; // Fall-through
case 1: last7 |= (uint64_t) m[i + 0] ; case 1: last7 |= (uint64_t) m[i + 0] ; // Fall-through
default:; default:;
}; };
v3 ^= last7; v3 ^= last7;

View File

@@ -1,11 +1,10 @@
/* /*
* tests/liberty.c * tests/liberty.c
* *
* Copyright (c) 2015 - 2016, Přemysl Janouch <p.janouch@gmail.com> * Copyright (c) 2015 - 2016, Přemysl Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted.
* copyright notice and this permission notice appear in all copies.
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -158,9 +157,7 @@ test_list_with_tail (void)
static void static void
test_strv (void) test_strv (void)
{ {
struct strv v; struct strv v = strv_make ();
strv_init (&v);
strv_append_owned (&v, xstrdup ("xkcd")); strv_append_owned (&v, xstrdup ("xkcd"));
strv_reset (&v); strv_reset (&v);
@@ -168,8 +165,7 @@ test_strv (void)
{ "123", "456", "a", "bc", "def", "ghij", "klmno", "pqrstu" }; { "123", "456", "a", "bc", "def", "ghij", "klmno", "pqrstu" };
// Add the first two items via another vector // Add the first two items via another vector
struct strv w; struct strv w = strv_make ();
strv_init (&w);
strv_append_args (&w, a[0], a[1], NULL); strv_append_args (&w, a[0], a[1], NULL);
strv_append_vector (&v, w.vector); strv_append_vector (&v, w.vector);
strv_free (&w); strv_free (&w);
@@ -196,15 +192,13 @@ test_str (void)
{ {
uint8_t x[] = { 0x12, 0x34, 0x56, 0x78, 0x11, 0x22, 0x33, 0x44 }; uint8_t x[] = { 0x12, 0x34, 0x56, 0x78, 0x11, 0x22, 0x33, 0x44 };
struct str s; struct str s = str_make ();
str_init (&s);
str_reserve (&s, MEGA); str_reserve (&s, MEGA);
str_append_data (&s, x, sizeof x); str_append_data (&s, x, sizeof x);
str_remove_slice (&s, 4, 4); str_remove_slice (&s, 4, 4);
soft_assert (s.len == 4); soft_assert (s.len == 4);
struct str t; struct str t = str_make ();
str_init (&t);
str_append_str (&t, &s); str_append_str (&t, &s);
str_append (&t, "abc"); str_append (&t, "abc");
str_append_c (&t, 'd'); str_append_c (&t, 'd');
@@ -265,10 +259,8 @@ static void
test_str_map (void) test_str_map (void)
{ {
// Put two reference counted objects in the map under case-insensitive keys // Put two reference counted objects in the map under case-insensitive keys
struct str_map m; struct str_map m = str_map_make (free_counter);
str_map_init (&m);
m.key_xfrm = tolower_ascii_strxfrm; m.key_xfrm = tolower_ascii_strxfrm;
m.free = free_counter;
int *a = make_counter (); int *a = make_counter ();
int *b = make_counter (); int *b = make_counter ();
@@ -282,8 +274,7 @@ test_str_map (void)
soft_assert (str_map_find (&m, "DEFghi") == b); soft_assert (str_map_find (&m, "DEFghi") == b);
// Check that we can iterate over both of them // Check that we can iterate over both of them
struct str_map_iter iter; struct str_map_iter iter = str_map_iter_make (&m);
str_map_iter_init (&iter, &m);
bool met_a = false; bool met_a = false;
bool met_b = false; bool met_b = false;
@@ -310,8 +301,7 @@ test_str_map (void)
free_counter (b); free_counter (b);
// Iterator test with a high number of items // Iterator test with a high number of items
str_map_init (&m); m = str_map_make (free);
m.free = free;
for (size_t i = 0; i < 100 * 100; i++) for (size_t i = 0; i < 100 * 100; i++)
{ {
@@ -319,8 +309,7 @@ test_str_map (void)
str_map_set (&m, x, x); str_map_set (&m, x, x);
} }
struct str_map_unset_iter unset_iter; struct str_map_unset_iter unset_iter = str_map_unset_iter_make (&m);
str_map_unset_iter_init (&unset_iter, &m);
while ((str_map_unset_iter_next (&unset_iter))) while ((str_map_unset_iter_next (&unset_iter)))
{ {
unsigned long x; unsigned long x;
@@ -342,9 +331,7 @@ test_utf8 (void)
soft_assert ( utf8_validate (valid, sizeof valid)); soft_assert ( utf8_validate (valid, sizeof valid));
soft_assert (!utf8_validate (invalid, sizeof invalid)); soft_assert (!utf8_validate (invalid, sizeof invalid));
struct utf8_iter iter; struct utf8_iter iter = utf8_iter_make ("fóọ");
utf8_iter_init (&iter, "fóọ");
size_t ch_len; size_t ch_len;
hard_assert (utf8_iter_next (&iter, &ch_len) == 'f' && ch_len == 1); hard_assert (utf8_iter_next (&iter, &ch_len) == 'f' && ch_len == 1);
hard_assert (utf8_iter_next (&iter, &ch_len) == 0x00F3 && ch_len == 2); hard_assert (utf8_iter_next (&iter, &ch_len) == 0x00F3 && ch_len == 2);
@@ -358,8 +345,8 @@ test_base64 (void)
for (size_t i = 0; i < N_ELEMENTS (data); i++) for (size_t i = 0; i < N_ELEMENTS (data); i++)
data[i] = i; data[i] = i;
struct str encoded; str_init (&encoded); struct str encoded = str_make ();
struct str decoded; str_init (&decoded); struct str decoded = str_make ();
base64_encode (data, sizeof data, &encoded); base64_encode (data, sizeof data, &encoded);
soft_assert (base64_decode (encoded.str, false, &decoded)); soft_assert (base64_decode (encoded.str, false, &decoded));
@@ -430,9 +417,9 @@ test_async (void)
{ {
struct test_async_data data; struct test_async_data data;
memset (&data, 0, sizeof data); memset (&data, 0, sizeof data);
async_manager_init (&data.manager); data.manager = async_manager_make ();
async_init (&data.busyloop, &data.manager); data.busyloop = async_make (&data.manager);
data.busyloop.execute = on_busyloop_execute; data.busyloop.execute = on_busyloop_execute;
data.busyloop.destroy = on_busyloop_destroy; data.busyloop.destroy = on_busyloop_destroy;
async_run (&data.busyloop); async_run (&data.busyloop);
@@ -542,7 +529,7 @@ test_connector_fixture_init
// Make it so that we immediately accept all connections // Make it so that we immediately accept all connections
poller_init (&self->poller); poller_init (&self->poller);
poller_fd_init (&self->listening_event, &self->poller, self->listening_fd); self->listening_event = poller_fd_make (&self->poller, self->listening_fd);
self->listening_event.dispatcher = test_connector_on_client; self->listening_event.dispatcher = test_connector_on_client;
self->listening_event.user_data = (poller_fd_fn) self; self->listening_event.user_data = (poller_fd_fn) self;
poller_fd_set (&self->listening_event, POLLIN); poller_fd_set (&self->listening_event, POLLIN);

View File

@@ -1,11 +1,10 @@
/* /*
* tests/proto.c * tests/proto.c
* *
* Copyright (c) 2015, Přemysl Janouch <p.janouch@gmail.com> * Copyright (c) 2015, Přemysl Janouch <p@janouch.name>
* *
* Permission to use, copy, modify, and/or distribute this software for any * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above * purpose with or without fee is hereby granted.
* copyright notice and this permission notice appear in all copies.
* *
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
@@ -43,8 +42,7 @@ test_irc (void)
irc_parse_message (&msg, "@first=a\\:\\s\\r\\n\\\\;2nd " irc_parse_message (&msg, "@first=a\\:\\s\\r\\n\\\\;2nd "
":srv hi there :good m8 :how are you?"); ":srv hi there :good m8 :how are you?");
struct str_map_iter iter; struct str_map_iter iter = str_map_iter_make (&msg.tags);
str_map_iter_init (&iter, &msg.tags);
soft_assert (msg.tags.len == 2); soft_assert (msg.tags.len == 2);
char *value; char *value;
@@ -79,8 +77,7 @@ test_irc (void)
static void static void
test_http_parser (void) test_http_parser (void)
{ {
struct str_map parameters; struct str_map parameters = str_map_make (NULL);
str_map_init (&parameters);
parameters.key_xfrm = tolower_ascii_strxfrm; parameters.key_xfrm = tolower_ascii_strxfrm;
char *type = NULL; char *type = NULL;
@@ -135,8 +132,7 @@ test_scgi_parser_on_content (void *user_data, const void *data, size_t len)
static void static void
test_scgi_parser (void) test_scgi_parser (void)
{ {
struct scgi_parser parser; struct scgi_parser parser = scgi_parser_make ();
scgi_parser_init (&parser);
parser.on_headers_read = test_scgi_parser_on_headers_read; parser.on_headers_read = test_scgi_parser_on_headers_read;
parser.on_content = test_scgi_parser_on_content; parser.on_content = test_scgi_parser_on_content;
parser.user_data = &parser; parser.user_data = &parser;
@@ -181,8 +177,7 @@ test_websockets (void)
soft_assert (!strcmp (accept, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo=")); soft_assert (!strcmp (accept, "s3pPLMBiTxaQ9kYGzzhZRbK+xOo="));
free (accept); free (accept);
struct ws_parser parser; struct ws_parser parser = ws_parser_make ();
ws_parser_init (&parser);
parser.on_frame_header = test_websockets_on_frame_header; parser.on_frame_header = test_websockets_on_frame_header;
parser.on_frame = test_websockets_on_frame; parser.on_frame = test_websockets_on_frame;
parser.user_data = &parser; parser.user_data = &parser;