#include "string.h"
#include "error.h"
+/**
+ * Reallocate an array, abort on failure or bugs.
+ *
+ * \param ptr Pointer to the memory block, may be NULL.
+ * \param nmemb Number of elements.
+ * \param size The size of one element in bytes.
+ *
+ * A wrapper for realloc(3) which aborts on invalid arguments or integer
+ * overflow. The wrapper also terminates the current process on allocation
+ * errors, so the caller does not need to check for failure.
+ *
+ * \return A pointer to newly allocated memory which is suitably aligned for
+ * any kind of variable and may be different from ptr.
+ *
+ * \sa realloc(3).
+ */
+__must_check void *arr_realloc(void *ptr, size_t nmemb, size_t size)
+{
+ size_t pr;
+
+ assert(size > 0);
+ assert(nmemb > 0);
+ assert(!__builtin_mul_overflow(nmemb, size, &pr));
+ assert(pr != 0);
+ ptr = realloc(ptr, pr);
+ assert(ptr);
+ return ptr;
+}
+
+/**
+ * Allocate an array, abort on failure or bugs.
+ *
+ * \param nmemb See \ref arr_realloc().
+ * \param size See \ref arr_realloc().
+ *
+ * Like \ref arr_realloc(), this aborts on invalid arguments, integer overflow
+ * and allocation errors.
+ *
+ * \return A pointer to newly allocated memory which is suitably aligned for
+ * any kind of variable.
+ *
+ * \sa See \ref arr_realloc().
+ */
+__must_check __malloc void *arr_alloc(size_t nmemb, size_t size)
+{
+ return arr_realloc(NULL, nmemb, size);
+}
+
+/**
+ * Allocate and initialize an array, abort on failure or bugs.
+ *
+ * \param nmemb See \ref arr_realloc().
+ * \param size See \ref arr_realloc().
+ *
+ * This calls \ref arr_alloc() and zeroes-out the array.
+ *
+ * \return See \ref arr_alloc().
+ */
+__must_check __malloc void *arr_zalloc(size_t nmemb, size_t size)
+{
+ void *ptr = arr_alloc(nmemb, size);
+
+ /*
+ * This multiplication can not overflow because the above call to \ref
+ * arr_alloc() aborts on overflow.
+ */
+ memset(ptr, 0, nmemb * size);
+ return ptr;
+}
+
+/**
+ * Allocate and initialize memory.
+ *
+ * \param size The desired new size.
+ *
+ * \return A pointer to the allocated and zeroed-out memory, which is suitably
+ * aligned for any kind of variable.
+ *
+ * \sa \ref alloc(), calloc(3).
+ */
+__must_check void *zalloc(size_t size)
+{
+ return arr_zalloc(1, size);
+}
+
/**
* Paraslash's version of realloc().
*
*/
__must_check void *para_realloc(void *p, size_t size)
{
- /*
- * No need to check for NULL pointers: If p is NULL, the call
- * to realloc is equivalent to malloc(size)
- */
- assert(size);
- if (!(p = realloc(p, size))) {
- PARA_EMERG_LOG("realloc failed (size = %zu), aborting\n",
- size);
- exit(EXIT_FAILURE);
- }
- return p;
+ return arr_realloc(p, 1, size);
}
/**
*/
__must_check __malloc void *alloc(size_t size)
{
- void *p;
-
- assert(size);
- p = malloc(size);
- if (!p) {
- PARA_EMERG_LOG("malloc failed (size = %zu), aborting\n",
- size);
- exit(EXIT_FAILURE);
- }
- return p;
-}
-
-/**
- * Paraslash's version of calloc().
- *
- * \param size The desired new size.
- *
- * A wrapper for calloc(3) which exits on errors.
- *
- * \return A pointer to the allocated and zeroed-out memory, which is suitably
- * aligned for any kind of variable.
- *
- * \sa calloc(3)
- */
-__must_check __malloc void *para_calloc(size_t size)
-{
- void *ret = alloc(size);
-
- memset(ret, 0, size);
- return ret;
+ return arr_alloc(1, size);
}
/**
}
/**
- * Get the home directory of the current user.
+ * Return the expansion of $HOME/.paraslash.
+ *
+ * \return A pointer to memory that must not be freed by the caller. If the
+ * environment variable HOME is unset or empty, the function prints an error
+ * message and aborts.
*
- * \return A dynamically allocated string that must be freed by the caller. If
- * the home directory could not be found, this function returns "/tmp".
+ * \sa getenv(3), getuid(2).
*/
-__must_check __malloc char *para_homedir(void)
+const char *get_confdir(void)
{
- struct passwd *pw = getpwuid(getuid());
- return para_strdup(pw? pw->pw_dir : "/tmp");
+ static const char *dot_para;
+ const char *home;
+
+ if (dot_para)
+ return dot_para;
+ home = getenv("HOME");
+ if (!home || !*home) {
+ PARA_EMERG_LOG("fatal: HOME is unset or empty");
+ exit(EXIT_FAILURE);
+ }
+ dot_para = make_message("%s/.paraslash", home);
+ return dot_para;
}
/**
return 1;
}
-static inline int loglevel_equal(const char *arg, const char * const ll)
-{
- return !strncasecmp(arg, ll, strlen(ll));
-}
-
-/**
- * Compute the loglevel number from its name.
- *
- * \param txt The name of the loglevel (debug, info, ...).
- *
- * \return The numeric representation of the loglevel name.
- */
-int get_loglevel_by_name(const char *txt)
-{
- if (loglevel_equal(txt, "debug"))
- return LL_DEBUG;
- if (loglevel_equal(txt, "info"))
- return LL_INFO;
- if (loglevel_equal(txt, "notice"))
- return LL_NOTICE;
- if (loglevel_equal(txt, "warning"))
- return LL_WARNING;
- if (loglevel_equal(txt, "error"))
- return LL_ERROR;
- if (loglevel_equal(txt, "crit"))
- return LL_CRIT;
- if (loglevel_equal(txt, "emerg"))
- return LL_EMERG;
- return -E_BAD_LL;
-}
-
static int get_next_word(const char *buf, const char *delim, char **word)
{
enum line_state_flags {LSF_HAVE_WORD = 1, LSF_BACKSLASH = 2,
static int create_argv_offset(int offset, const char *buf, const char *delim,
char ***result)
{
- char *word, **argv = alloc((offset + 1) * sizeof(char *));
+ char *word, **argv = arr_zalloc(offset + 1, sizeof(char *));
const char *p;
int i, ret;
- for (i = 0; i < offset; i++)
- argv[i] = NULL;
- for (p = buf; p && *p; p += ret, i++) {
+ for (p = buf, i = offset; p && *p; p += ret, i++) {
ret = get_next_word(p, delim, &word);
if (ret < 0)
goto err;
if (!ret)
break;
- argv = para_realloc(argv, (i + 2) * sizeof(char*));
+ argv = arr_realloc(argv, i + 2, sizeof(char*));
argv[i] = word;
}
argv[i] = NULL;
return create_argv_offset(1, buf, delim, result);
}
-/**
- * Find out if the given string is contained in the arg vector.
- *
- * \param arg The string to look for.
- * \param argv The array to search.
- *
- * \return The first index whose value equals \a arg, or \p -E_ARG_NOT_FOUND if
- * arg was not found in \a argv.
- */
-int find_arg(const char *arg, char **argv)
-{
- int i;
-
- if (!argv)
- return -E_ARG_NOT_FOUND;
- for (i = 0; argv[i]; i++)
- if (strcmp(arg, argv[i]) == 0)
- return i;
- return -E_ARG_NOT_FOUND;
-}
-
/**
* Compile a regular expression.
*
return -ERRNO_TO_PARA_ERROR(errno);
if (num_wchars == 0)
return 0;
- dest = alloc((num_wchars + 1) * sizeof(*dest));
+ dest = arr_alloc(num_wchars + 1, sizeof(*dest));
src = s;
memset(&state, 0, sizeof(state));
num_wchars = mbsrtowcs(dest, &src, num_wchars, &state);
num_wchars = mbsrtowcs(NULL, &src, 0, &state);
if (num_wchars == (size_t)-1)
return -ERRNO_TO_PARA_ERROR(errno);
- wcs = alloc((num_wchars + 1) * sizeof(*wcs));
+ wcs = arr_alloc(num_wchars + 1, sizeof(*wcs));
memset(&state, 0, sizeof(state));
num_wchars = mbsrtowcs(wcs, &src, num_wchars + 1, &state);
assert(num_wchars != (size_t)-1);