39CTASSERT(
sizeof (
double) ==
sizeof (
unsigned long long));
63static void conf_set_common(conf_t *
conf,
const char *key,
64 const char *fmt, ...) PRINTF_ATTR(3);
65static
int conf_write_impl(const conf_t *
conf,
void *fp,
size_t bufsz,
66 bool_t compressed, bool_t is_buf);
69conf_key_compar(const
void *a, const
void *b)
72 int c = strcmp(ka->key, kb->key);
121 ASSERT(conf_from != NULL);
125 key =
AVL_NEXT(&conf_from->tree, key)) {
177 FILE *fp = fopen(filename,
"rb");
190 if (fread(gz_magic, 1,
sizeof (gz_magic), fp) !=
sizeof (gz_magic)) {
197 if (gz_magic[0] == 0x1f && gz_magic[1] == 0x8b) {
198 gzFile gz_fp = gzopen(filename,
"r");
227 memset(&ck->data, 0, sizeof (ck->data));
252conf_parse_line(
char *line, conf_t *
conf)
258 conf_key_type_t type;
259 bool unescape =
false;
264 sep = strstr(line,
"`");
266 type = CONF_KEY_DATA;
269 sep = strstr(line,
"%=");
277 sep = strstr(line,
"=");
291 strcpy(srch.key, line);
305 if (type == CONF_KEY_STR) {
307 strcpy(ck->str, &sep[1]);
311 size_t l = strlen(&sep[1]);
319 ck->data.sz = sz_dec;
340 unsigned linenum = 0;
342 FILE *f_fp = compressed ? NULL : fp;
343 gzFile gz_fp = compressed ? fp : NULL;
346 while (compressed ? !gzeof(gz_fp) : !feof(f_fp)) {
348 if (parser_get_next_gzline(gz_fp, &line, &linecap,
358 if (!conf_parse_line(line,
conf))
387 uint8_t *tmpbuf = NULL;
399 if (((
const uint8_t *)buf)[cap - 1] ==
'\0') {
403 memcpy(tmpbuf, buf, cap);
405 instr = (
char *)tmpbuf;
411 lines =
strsplit(instr,
"\n",
true, &n_lines);
412 for (
size_t i = 0; i < n_lines; i++) {
417 comment = strchr(lines[i],
'#');
420 comment = strstr(lines[i],
"--");
424 if (lines[i][0] !=
'\0') {
425 if (!conf_parse_line(lines[i],
conf)) {
475 FILE *fp = fopen(filename_tmp,
"wb");
481 res = (conf_write_impl(
conf, fp, 0, B_FALSE, B_FALSE) >= 0);
484 gzFile fp = gzopen(filename_tmp,
"w");
490 res = (conf_write_impl(
conf, fp, 0, B_TRUE, B_FALSE) >= 0);
500 if (!ReplaceFileA(filename, filename_tmp, NULL,
501 REPLACEFILE_IGNORE_MERGE_ERRORS |
502 REPLACEFILE_IGNORE_ACL_ERRORS, NULL, NULL)) {
503 win_perror(GetLastError(),
"Error writing %s: "
504 "ReplaceFile failed", filename);
507 rename_err = rename(filename_tmp, filename);
510 rename_err = rename(filename_tmp, filename);
512 if (rename_err != 0) {
513 logMsg(
"Error writing %s: atomic rename failed: %s",
514 filename, strerror(errno));
545 int res = conf_write_impl(
conf, buf, cap, B_FALSE, B_TRUE);
548 return ((
size_t)res);
552needs_escape(
const char *str)
556 for (
unsigned i = 0, n = strlen(str); i < n; i++) {
557 if ((i == 0 && isspace(str[i])) ||
558 (i + 1 == n && isspace(str[i]))) {
562 if (str[i] < 32 || str[i] ==
'#' || str[i] ==
'%' ||
572conf_write_impl(
const conf_t *
conf,
void *fp,
size_t bufsz,
573 bool_t compressed, bool_t is_buf)
575#define SNPRINTF_ADV(...) \
577 int req_here = snprintf(buf, (fp + bufsz) - buf, __VA_ARGS__); \
578 ASSERT3S(req_here, >=, 0); \
579 req_total += req_here; \
580 buf = MIN(buf + req_here, fp + bufsz); \
583 char *data_buf = NULL;
585 ASSERT(fp != NULL || (is_buf && bufsz == 0));
586 void *buf = (is_buf ? fp : NULL);
587 FILE *f_fp = compressed ? NULL : fp;
588 gzFile gz_fp = compressed ? fp : NULL;
589 size_t req_total = 0;
591 CURL *curl = curl_easy_init();
596 if (!compressed && !is_buf &&
597 fprintf(f_fp,
"# libacfutils configuration file - "
598 "DO NOT EDIT!\n") < 0) {
605 if (!needs_escape(ck->str)) {
607 SNPRINTF_ADV(
"%s = %s\n",
609 }
else if ((compressed ?
610 gzprintf(gz_fp,
"%s = %s\n", ck->key,
612 fprintf(f_fp,
"%s = %s\n", ck->key,
617 char *str = curl_easy_escape(curl, ck->str, 0);
619 SNPRINTF_ADV(
"%s %%= %s\n",
621 }
else if ((compressed ?
622 gzprintf(gz_fp,
"%s %%= %s\n", ck->key,
624 fprintf(f_fp,
"%s %%= %s\n", ck->key,
632 case CONF_KEY_DATA: {
642 data_buf[act] =
'\0';
644 SNPRINTF_ADV(
"%s`%s\n", ck->key, data_buf);
645 }
else if (compressed) {
646 gzwrite(gz_fp, ck->key, strlen(ck->key));
647 gzwrite(gz_fp,
"`", 1);
648 gzwrite(gz_fp, data_buf, strlen(data_buf));
649 gzwrite(gz_fp,
"\n", 1);
651 fprintf(f_fp,
"%s`%s\n", ck->key, data_buf);
660 curl_easy_cleanup(curl);
667 curl_easy_cleanup(curl);
679 return (conf_write_impl(
conf, fp, 0, B_FALSE, B_FALSE));
711 ck = conf_find(
conf, key, NULL);
712 if (ck == NULL || ck->type != CONF_KEY_STR)
724conf_get_i(
const conf_t *
conf,
const char *key,
int *value)
731 ck = conf_find(
conf, key, NULL);
732 if (ck == NULL || ck->type != CONF_KEY_STR)
734 *value = atoi(ck->str);
751 ck = conf_find(
conf, key, NULL);
752 if (ck == NULL || ck->type != CONF_KEY_STR)
754 *value = atoll(ck->str);
771 ck = conf_find(
conf, key, NULL);
772 if (ck == NULL || ck->type != CONF_KEY_STR)
774 if (strcmp(ck->str,
"nan") == 0) {
778 return (sscanf(ck->str,
"%lf", value) == 1);
793 ck = conf_find(
conf, key, NULL);
794 if (ck == NULL || ck->type != CONF_KEY_STR)
796 if (strcmp(ck->str,
"nan") == 0) {
800 return (sscanf(ck->str,
"%f", value) == 1);
819 unsigned long long x;
824 ck = conf_find(
conf, key, NULL);
825 if (ck == NULL || ck->type != CONF_KEY_STR)
828#pragma GCC diagnostic push
829#pragma GCC diagnostic ignored "-Wformat"
830#pragma GCC diagnostic ignored "-Wformat-extra-args"
832 if (sscanf(ck->str,
"%llx", &x) != 1)
835#pragma GCC diagnostic pop
837#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
840 memcpy(value, &x,
sizeof (
double));
857 ck = conf_find(
conf, key, NULL);
858 if (ck == NULL || ck->type != CONF_KEY_STR)
860 *value = (strcmp(ck->str,
"true") == 0 ||
861 strcmp(ck->str,
"1") == 0 ||
862 strcmp(ck->str,
"yes") == 0);
871conf_get_b2(
const conf_t *
conf,
const char *key,
bool *value)
908 ASSERT(buf != NULL || cap == 0);
910 ck = conf_find(
conf, key, NULL);
911 if (ck == NULL || ck->type != CONF_KEY_DATA)
913 ASSERT(ck->data.buf != NULL);
915 memcpy(buf, ck->data.buf, MIN(ck->data.sz, cap));
917 return (ck->data.sz);
935 ck = conf_find(
conf, key, &where);
951 ck->type = CONF_KEY_STR;
960conf_set_common(conf_t *
conf,
const char *key,
const char *fmt, ...)
978 ck->type = CONF_KEY_STR;
979 n = vsnprintf(NULL, 0, fmt, ap1);
982 (void) vsnprintf(ck->str, n + 1, fmt, ap2);
996 conf_set_common(
conf, key,
"%i", value);
1009#pragma GCC diagnostic push
1010#pragma GCC diagnostic ignored "-Wformat"
1011#pragma GCC diagnostic ignored "-Wformat-extra-args"
1013 conf_set_common(
conf, key,
"%lld", value);
1015#pragma GCC diagnostic pop
1031 conf_set_common(
conf, key,
"%.15f", value);
1046 conf_set_common(
conf, key,
"%.12f", value);
1057 unsigned long long x;
1061 memcpy(&x, &value,
sizeof (value));
1062#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
1066#pragma GCC diagnostic push
1067#pragma GCC diagnostic ignored "-Wformat"
1068#pragma GCC diagnostic ignored "-Wformat-extra-args"
1070 conf_set_common(
conf, key,
"%llx", x);
1072#pragma GCC diagnostic pop
1085 conf_set_common(
conf, key,
"%s", value ?
"true" :
"false");
1092conf_set_b2(conf_t *
conf,
const char *key,
bool value)
1096 conf_set_common(
conf, key,
"%s", value ?
"true" :
"false");
1116 ck = conf_find(
conf, key, &where);
1117 if (buf == NULL || sz == 0) {
1134 ck->type = CONF_KEY_DATA;
1136 memcpy(ck->data.buf, buf, sz);
1140#define VARIABLE_GET(getfunc, last_arg, ...) \
1146 va_start(ap, last_arg); \
1148 l = vsnprintf(NULL, 0, fmt, ap); \
1149 key = safe_malloc(l + 1); \
1150 vsnprintf(key, l + 1, fmt, ap2); \
1151 res = getfunc(conf, key, __VA_ARGS__); \
1158#define VARIABLE_SET(setfunc, last_arg, ...) \
1163 va_start(ap, last_arg); \
1165 l = vsnprintf(NULL, 0, fmt, ap); \
1166 key = safe_malloc(l + 1); \
1167 vsnprintf(key, l + 1, fmt, ap2); \
1168 setfunc(conf, key, __VA_ARGS__); \
1197 VARIABLE_GET(conf_get_i, value, value);
1260 ASSERT(buf != NULL || cap == 0);
1280conf_get_b2_v(
const conf_t *
conf,
const char *fmt,
bool *value, ...)
1285 VARIABLE_GET(conf_get_b2, value, value);
1293conf_set_str_v(conf_t *
conf,
const char *fmt,
const char *value, ...)
1297 VARIABLE_SET(conf_set_str, value, value);
1430 }
while (ck != NULL && ck->type != CONF_KEY_STR);
#define ASSERT3S(x, op, y)
void * avl_destroy_nodes(avl_tree_t *tree, void **cookie)
void * avl_first(const avl_tree_t *tree)
void avl_remove(avl_tree_t *tree, void *node)
void avl_insert(avl_tree_t *tree, void *node, avl_index_t where)
void avl_create(avl_tree_t *tree, int(*compar)(const void *, const void *), size_t size, size_t offset)
#define AVL_NEXT(tree, node)
void avl_destroy(avl_tree_t *tree)
void * avl_find(const avl_tree_t *tree, const void *node, avl_index_t *where)
#define BASE64_ENC_SIZE(__raw_size__)
size_t lacf_base64_encode(const uint8_t *raw, size_t raw_size, uint8_t *encoded)
#define BASE64_DEC_SIZE(__enc_size__)
ssize_t lacf_base64_decode(const uint8_t *encoded, size_t encoded_size, uint8_t *raw)
bool_t conf_get_da(const conf_t *conf, const char *key, double *value)
void conf_set_b(conf_t *conf, const char *key, bool_t value)
bool_t conf_get_lli_v(const conf_t *conf, const char *fmt, long long *value,...)
bool_t conf_get_d_v(const conf_t *conf, const char *fmt, double *value,...)
void conf_set_data_v(conf_t *conf, const char *fmt, const void *buf, size_t sz,...)
void conf_set_f(conf_t *conf, const char *key, float value)
bool_t conf_get_i_v(const conf_t *conf, const char *fmt, int *value,...)
bool_t conf_get_lli(const conf_t *conf, const char *key, long long *value)
void conf_set_da(conf_t *conf, const char *key, double value)
void conf_set_str(conf_t *conf, const char *key, const char *value)
void conf_set_data(conf_t *conf, const char *key, const void *buf, size_t sz)
bool_t conf_get_da_v(const conf_t *conf, const char *fmt, double *value,...)
bool_t conf_get_d(const conf_t *conf, const char *key, double *value)
bool_t conf_write(const conf_t *conf, FILE *fp)
void conf_set_d_v(conf_t *conf, const char *fmt, double value,...)
bool_t conf_get_b(const conf_t *conf, const char *key, bool_t *value)
void conf_set_lli_v(conf_t *conf, const char *fmt, long long value,...)
bool_t conf_walk(const conf_t *conf, const char **key, const char **value, void **cookie)
void conf_set_i_v(conf_t *conf, const char *fmt, int value,...)
conf_t * conf_read2(void *fp, int *errline, bool_t compressed)
conf_t * conf_read_buf(const void *buf, size_t cap, int *errline)
void conf_merge(const conf_t *conf_from, conf_t *conf_to)
bool_t conf_get_b_v(const conf_t *conf, const char *fmt, bool_t *value,...)
void conf_set_da_v(conf_t *conf, const char *fmt, double value,...)
conf_t * conf_read_file(const char *filename, int *errline)
void conf_set_f_v(conf_t *conf, const char *fmt, double value,...)
bool_t conf_get_str_v(const conf_t *conf, const char *fmt, const char **value,...)
conf_t * conf_read(FILE *fp, int *errline)
size_t conf_get_data_v(const conf_t *conf, const char *fmt, void *buf, size_t cap,...)
bool_t conf_get_f(const conf_t *conf, const char *key, float *value)
void conf_free(conf_t *conf)
void conf_set_i(conf_t *conf, const char *key, int value)
bool_t conf_get_f_v(const conf_t *conf, const char *fmt, float *value,...)
bool_t conf_write_file(const conf_t *conf, const char *filename)
void conf_set_b_v(conf_t *conf, const char *fmt, bool_t value,...)
bool_t conf_write_file2(const conf_t *conf, const char *filename, bool_t compressed)
bool_t conf_get_str(const conf_t *conf, const char *key, const char **value)
conf_t * conf_create_empty(void)
void conf_set_d(conf_t *conf, const char *key, double value)
size_t conf_get_data(const conf_t *conf, const char *key, void *buf, size_t cap)
size_t conf_write_buf(const conf_t *conf, void *buf, size_t cap)
conf_t * conf_create_copy(const conf_t *conf2)
void conf_set_lli(conf_t *conf, const char *key, long long value)
char ** strsplit(const char *input, const char *sep, bool_t skip_empty, size_t *num)
void unescape_percent(char *str)
static ssize_t parser_get_next_line(FILE *fp, char **linep, size_t *linecap, unsigned *linenum)
static char * sprintf_alloc(const char *fmt,...)
void free_strlist(char **comps, size_t num)
void strtolower(char *str)
bool_t file_exists(const char *path, bool_t *isdir)
static void strip_space(char *line)
static char * safe_strdup(const char *str2)
static void * safe_calloc(size_t nmemb, size_t size)
static void * safe_malloc(size_t size)