/* GNU Mailutils -- a suite of utilities for electronic mail Copyright (C) 2016-2021 Free Software Foundation, Inc. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #if HAVE_CONFIG_H # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include typedef int (*str_to_c_t) (void *tgt, char const *string, char **errmsg); static int to_string (void *tgt, char const *string, char **errmsg) { char **cptr = tgt; if (string) { *cptr = mu_strdup (string); if (!*cptr) return errno; } else *cptr = NULL; return 0; } #define STR_TO_FUN to_short #define STR_TO_TYPE signed short #define STR_TO_MIN SHRT_MIN #define STR_TO_MAX SHRT_MAX #include "to_sn.c" #define STR_TO_FUN to_ushort #define STR_TO_TYPE unsigned short #define STR_TO_MAX USHRT_MAX #include "to_un.c" #define STR_TO_FUN to_int #define STR_TO_TYPE signed int #define STR_TO_MIN INT_MIN #define STR_TO_MAX INT_MAX #include "to_sn.c" #define STR_TO_FUN to_uint #define STR_TO_TYPE unsigned int #define STR_TO_MAX UINT_MAX #include "to_un.c" #define STR_TO_FUN to_long #define STR_TO_TYPE signed long #define STR_TO_MIN LONG_MIN #define STR_TO_MAX LONG_MAX #include "to_sn.c" #define STR_TO_FUN to_ulong #define STR_TO_TYPE unsigned long #define STR_TO_MAX ULONG_MAX #include "to_un.c" #define STR_TO_FUN to_size_t #define STR_TO_TYPE size_t #define STR_TO_MAX ((size_t)-1) #include "to_un.c" static int time_multiplier (const char *str, unsigned *m, unsigned *plen) { static struct timetab { char *name; unsigned mul; } tab[] = { { "seconds", 1 }, { "minutes", 60 }, { "hours", 60*60 }, { "days", 24*60*60 }, { "weeks", 7*24*60*60 }, { "months", 31*7*24*60*60 }, { NULL } }; struct timetab *p; int slen; for (slen = 0; str[slen]; slen++) if (mu_isspace (str[slen])) break; for (p = tab; p->name; p++) { if (p->name[0] == mu_tolower (str[0])) { int nlen = strlen (p->name); if (nlen > slen) nlen = slen; if (strncasecmp (p->name, str, nlen) == 0) { *m = p->mul; if (plen) *plen = nlen; return 0; } } } return 1; } static int to_time_t (void *tgt, char const *string, char **errmsg) { time_t *ptr = tgt; int rc = 0; time_t interval = 0; while (*string) { char *p; unsigned long n; unsigned mul, len; while (*string && mu_isspace (*string)) string++; if (!mu_isdigit (*string) && time_multiplier (string, &mul, &len) == 0) { n = 1; string += len; } else { n = strtoul (string, &p, 10); if (*p && !mu_isspace (*p)) { string = p; rc = 1; break; } while (*p && mu_isspace (*p)) p++; string = p; if (*string) { if ((rc = time_multiplier (string, &mul, &len))) break; string += len; } else mul = 1; } interval += n * mul; } if (rc) { if (errmsg) mu_asprintf (errmsg, _("invalid time specification near %s"), string); return EINVAL; } *ptr = interval; return 0; } static int to_bool (void *tgt, char const *string, char **errmsg) { int *ptr = tgt; if (strcmp (string, "yes") == 0 || strcmp (string, "on") == 0 || strcmp (string, "t") == 0 || strcmp (string, "true") == 0 || strcmp (string, "1") == 0) *ptr = 1; else if (strcmp (string, "no") == 0 || strcmp (string, "off") == 0 || strcmp (string, "nil") == 0 || strcmp (string, "false") == 0 || strcmp (string, "0") == 0) *ptr = 0; else return EINVAL; return 0; } #if 0 static int to_ipv4 (void *tgt, char const *string, char **errmsg) { struct in_addr *ptr = tgt; struct in_addr addr; if (inet_aton (string, &addr) == 0) { mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, _("not an IPv4")); mu_cfg_error_count++; return 1; } addr.s_addr = ntohl (addr.s_addr); *ptr = addr; return 0; } #endif static int to_cidr (void *tgt, char const *string, char **errmsg) { struct mu_cidr *ptr = tgt; return mu_cidr_from_string (ptr, string); } static int to_incr (void *tgt, char const *string, char **errmsg) { ++*(int*)tgt; return 0; } static int to_hsize (void *tgt, char const *string, char **errmsg) { return mu_strtosize (string, NULL, tgt); } static str_to_c_t str_to_c[] = { [mu_c_string] = to_string, [mu_c_short] = to_short, [mu_c_ushort] = to_ushort, [mu_c_int] = to_int, [mu_c_uint] = to_uint, [mu_c_long] = to_long, [mu_c_ulong] = to_ulong, [mu_c_size] = to_size_t, [mu_c_hsize] = to_hsize, /* FIXME [mu_c_off] = { to_off, generic_dealloc }, */ [mu_c_time] = to_time_t, [mu_c_bool] = to_bool, /* FIXME [mu_c_ipv4] = to_ipv4, */ [mu_c_cidr] = to_cidr, /* FIXME [mu_c_host] = { to_host, generic_dealloc } */ [mu_c_incr] = to_incr, }; char const *mu_c_type_str[] = { [mu_c_string] = "mu_c_string", [mu_c_short] = "mu_c_short", [mu_c_ushort] = "mu_c_ushort", [mu_c_int] = "mu_c_int", [mu_c_uint] = "mu_c_uint", [mu_c_long] = "mu_c_long", [mu_c_ulong] = "mu_c_ulong", [mu_c_size] = "mu_c_size", [mu_c_hsize] = "mu_c_hsize", [mu_c_off] = "mu_c_off", [mu_c_time] = "mu_c_time", [mu_c_bool] = "mu_c_bool", [mu_c_ipv4] = "mu_c_ipv4", [mu_c_cidr] = "mu_c_cidr", [mu_c_host] = "mu_c_host", [mu_c_incr] = "mu_c_incr", [mu_c_void] = "mu_c_void", }; int mu_str_to_c (char const *string, enum mu_c_type type, void *tgt, char **errmsg) { if (errmsg) *errmsg = NULL; if ((size_t)type >= sizeof (str_to_c) / sizeof (str_to_c[0])) return EINVAL; if (!str_to_c[type]) return ENOSYS; return str_to_c[type] (tgt, string, errmsg); }