summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--meson.build1
-rw-r--r--src/color.c8
-rw-r--r--src/compgen.c98
-rw-r--r--src/compgen.h3
-rw-r--r--src/entry.h2
-rw-r--r--src/history.c224
-rw-r--r--src/history.h31
-rw-r--r--src/main.c82
-rw-r--r--src/string_vec.c16
-rw-r--r--src/string_vec.h7
-rw-r--r--src/surface.c4
-rw-r--r--src/tofi.h1
-rw-r--r--src/xmalloc.c26
-rw-r--r--src/xmalloc.h3
14 files changed, 379 insertions, 127 deletions
diff --git a/meson.build b/meson.build
index ea1db95..e00635b 100644
--- a/meson.build
+++ b/meson.build
@@ -67,6 +67,7 @@ sources = files(
'src/egl.c',
'src/entry.c',
'src/gl.c',
+ 'src/history.c',
'src/ipc.c',
'src/log.c',
'src/string_vec.c',
diff --git a/src/color.c b/src/color.c
index f6b3275..0ccd5b8 100644
--- a/src/color.c
+++ b/src/color.c
@@ -40,9 +40,9 @@ struct color hex_to_color(const char *hex)
}
return (struct color) {
- .r = ((val & 0xFF000000u) >> 24) / 255.0f,
- .g = ((val & 0x00FF0000u) >> 16) / 255.0f,
- .b = ((val & 0x0000FF00u) >> 8) / 255.0f,
- .a = ((val & 0x000000FFu) >> 0) / 255.0f,
+ .r = (float)((val & 0xFF000000u) >> 24) / 255.0f,
+ .g = (float)((val & 0x00FF0000u) >> 16) / 255.0f,
+ .b = (float)((val & 0x0000FF00u) >> 8) / 255.0f,
+ .a = (float)((val & 0x000000FFu) >> 0) / 255.0f,
};
}
diff --git a/src/compgen.c b/src/compgen.c
index 8190a21..f514d66 100644
--- a/src/compgen.c
+++ b/src/compgen.c
@@ -4,74 +4,25 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include "history.h"
#include "log.h"
#include "string_vec.h"
#include "xmalloc.h"
-static const char *default_state_dir = ".local/state";
-static const char *histfile_basename = "tofi-history";
-
-static char *get_histfile_path() {
- char *histfile_name;
- const char *state_path = getenv("XDG_STATE_HOME");
- if (state_path == NULL) {
- const char *home = getenv("HOME");
- if (home == NULL) {
- log_error("Couldn't retrieve HOME from environment.\n");
- exit(EXIT_FAILURE);
- }
- size_t len = strlen(home) + 1
- + strlen(default_state_dir) + 1
- + strlen(histfile_basename) + 1;
- histfile_name = xmalloc(len);
- snprintf(
- histfile_name,
- len,
- "%s/%s/%s",
- home,
- default_state_dir,
- histfile_basename);
- } else {
- size_t len = strlen(state_path) + 1
- + strlen(histfile_basename) + 1;
- histfile_name = xmalloc(len);
- snprintf(
- histfile_name,
- len,
- "%s/%s",
- state_path,
- histfile_basename);
- }
- return histfile_name;
-
-}
-
-static void load_history()
-{
- char *name = get_histfile_path();
- FILE *histfile = fopen(name, "rb");
-
- free(name);
-
- if (histfile == NULL) {
- return;
- }
-
-}
-
-struct string_vec compgen()
+struct string_vec compgen(struct history *history)
{
- load_history();
log_debug("Retrieving PATH.\n");
const char *env_path = getenv("PATH");
if (env_path == NULL) {
log_error("Couldn't retrieve PATH from environment.\n");
exit(EXIT_FAILURE);
}
+
struct string_vec programs = string_vec_create();
- char *path = strdup(env_path);
+ char *path = xstrdup(env_path);
char *saveptr = NULL;
char *path_entry = strtok_r(path, ":", &saveptr);
+
log_debug("Scanning PATH for binaries.\n");
while (path_entry != NULL) {
DIR *dir = opendir(path_entry);
@@ -96,10 +47,49 @@ struct string_vec compgen()
path_entry = strtok_r(NULL, ":", &saveptr);
}
free(path);
+
log_debug("Sorting results.\n");
string_vec_sort(&programs);
+
log_debug("Making unique.\n");
string_vec_uniq(&programs);
+
+ log_debug("Moving already known programs to the front.\n");
+ /*
+ * Remove any programs in our history from the generated list, and
+ * store which ones we found in to_add.
+ * Removal is done without changing the count, as we're about to re-add
+ * them at the front.
+ */
+ struct string_vec to_add = string_vec_create();
+ for (size_t i = 0; i < history->count; i++) {
+ char **res = string_vec_find(&programs, history->buf[i].name);
+ if (res == NULL) {
+ continue;
+ }
+ free(*res);
+ *res = NULL;
+ string_vec_add(&to_add, history->buf[i].name);
+ }
+
+ /* Sort the vector to push the removed entries to the end. */
+ string_vec_sort(&programs);
+
+ /*
+ * Move the results down by the number of items we want to add. There's
+ * guaranteed to be enough space to do this, as we just removed that
+ * many items.
+ */
+ memmove(
+ &programs.buf[to_add.count],
+ programs.buf,
+ (programs.count - to_add.count) * sizeof(programs.buf[0]));
+
+ /* Add our history to the front in order. */
+ for (size_t i = 0; i < to_add.count; i++) {
+ programs.buf[i] = xstrdup(to_add.buf[i]);
+ }
+ string_vec_destroy(&to_add);
log_debug("Done.\n");
return programs;
}
diff --git a/src/compgen.h b/src/compgen.h
index b3b54b5..502bcb5 100644
--- a/src/compgen.h
+++ b/src/compgen.h
@@ -1,8 +1,9 @@
#ifndef COMPGEN_H
#define COMPGEN_H
+#include "history.h"
#include "string_vec.h"
-struct string_vec compgen();
+struct string_vec compgen(struct history *history);
#endif /* COMPGEN_H */
diff --git a/src/entry.h b/src/entry.h
index 6d4023f..6efe773 100644
--- a/src/entry.h
+++ b/src/entry.h
@@ -3,6 +3,7 @@
#include <pango/pangocairo.h>
#include "color.h"
+#include "history.h"
#include "image.h"
#include "surface.h"
#include "string_vec.h"
@@ -30,6 +31,7 @@ struct entry {
struct string_vec results;
struct string_vec commands;
+ struct history history;
/* Options */
uint32_t font_size;
diff --git a/src/history.c b/src/history.c
new file mode 100644
index 0000000..8cb9eaf
--- /dev/null
+++ b/src/history.c
@@ -0,0 +1,224 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "history.h"
+#include "log.h"
+#include "xmalloc.h"
+
+static const char *default_state_dir = ".local/state";
+static const char *histfile_basename = "tofi-history";
+
+[[nodiscard]]
+static struct history history_create(void);
+static bool mkdirp(const char *path);
+
+static char *get_histfile_path() {
+ char *histfile_name = NULL;
+ const char *state_path = getenv("XDG_STATE_HOME");
+ if (state_path == NULL) {
+ const char *home = getenv("HOME");
+ if (home == NULL) {
+ log_error("Couldn't retrieve HOME from environment.\n");
+ return NULL;
+ }
+ size_t len = strlen(home) + 1
+ + strlen(default_state_dir) + 1
+ + strlen(histfile_basename) + 1;
+ histfile_name = xmalloc(len);
+ snprintf(
+ histfile_name,
+ len,
+ "%s/%s/%s",
+ home,
+ default_state_dir,
+ histfile_basename);
+ } else {
+ size_t len = strlen(state_path) + 1
+ + strlen(histfile_basename) + 1;
+ histfile_name = xmalloc(len);
+ snprintf(
+ histfile_name,
+ len,
+ "%s/%s",
+ state_path,
+ histfile_basename);
+ }
+ return histfile_name;
+
+}
+
+struct history history_load()
+{
+ struct history vec = history_create();
+ char *histfile_name = get_histfile_path();
+ if (histfile_name == NULL) {
+ return vec;
+ }
+
+ FILE *histfile = fopen(histfile_name, "rb");
+ free(histfile_name);
+
+ if (histfile == NULL) {
+ return vec;
+ }
+
+ if (fseek(histfile, 0, SEEK_END) != 0) {
+ log_error("Error seeking in history file: %s.\n", strerror(errno));
+ fclose(histfile);
+ return vec;
+ }
+ size_t len = ftell(histfile);
+ if (fseek(histfile, 0, SEEK_SET) != 0) {
+ log_error("Error seeking in history file: %s.\n", strerror(errno));
+ fclose(histfile);
+ return vec;
+ }
+
+ char *buf = xmalloc(len);
+ fread(buf, 1, len, histfile);
+ fclose(histfile);
+
+ char *saveptr = NULL;
+ char *tok = strtok_r(buf, " ", &saveptr);
+ while (tok != NULL) {
+ size_t run_count = strtoull(tok, NULL, 10);
+ tok = strtok_r(NULL, "\n", &saveptr);
+ if (tok == NULL) {
+ break;
+ }
+ history_add(&vec, tok);
+ vec.buf[vec.count - 1].run_count = run_count;
+ tok = strtok_r(NULL, " ", &saveptr);
+ }
+
+ free(buf);
+ return vec;
+}
+
+void history_save(struct history *history)
+{
+ char *histfile_name = get_histfile_path();
+ if (histfile_name == NULL) {
+ return;
+ }
+
+ /* Create the path if necessary. */
+ if (!mkdirp(histfile_name)) {
+ return;
+ }
+
+ /* Use open rather than fopen to ensure the proper permissions. */
+ int histfd = open(histfile_name, O_WRONLY | O_CREAT, 0600);
+ FILE *histfile = fdopen(histfd, "wb");
+ if (histfile == NULL) {
+ return;
+ }
+
+ for (size_t i = 0; i < history->count; i++) {
+ fprintf(histfile, "%zu %s\n", history->buf[i].run_count, history->buf[i].name);
+ }
+
+ fclose(histfile);
+ free(histfile_name);
+}
+
+struct history history_create(void)
+{
+ struct history vec = {
+ .count = 0,
+ .size = 16,
+ .buf = xcalloc(16, sizeof(struct program))
+ };
+ return vec;
+}
+
+void history_destroy(struct history *restrict vec)
+{
+ for (size_t i = 0; i < vec->count; i++) {
+ free(vec->buf[i].name);
+ }
+ free(vec->buf);
+}
+
+void history_add(struct history *restrict vec, const char *restrict str)
+{
+ /*
+ * If the program's already in our vector, just increment the count and
+ * move the program up if needed.
+ */
+ for (size_t i = 0; i < vec->count; i++) {
+ if (!strcmp(vec->buf[i].name, str)) {
+ vec->buf[i].run_count++;
+ size_t count = vec->buf[i].run_count;
+ if (i > 0 && count <= vec->buf[i-1].run_count) {
+ return;
+ }
+ /* We need to move the program up the list */
+ size_t j = i;
+ while (j > 0 && count > vec->buf[j-1].run_count) {
+ j--;
+ }
+ struct program tmp = vec->buf[i];
+ memmove(&vec->buf[j+1], &vec->buf[j], (i - j) * sizeof(struct program));
+ vec->buf[j] = tmp;
+ return;
+ }
+ }
+
+ /* Otherwise add it to the end with a run count of 1 */
+ if (vec->count == vec->size) {
+ vec->size *= 2;
+ vec->buf = xrealloc(vec->buf, vec->size * sizeof(vec->buf[0]));
+ }
+ vec->buf[vec->count].name = xstrdup(str);
+ vec->buf[vec->count].run_count = 1;
+ vec->count++;
+}
+
+void history_remove(struct history *restrict vec, const char *restrict str)
+{
+ for (size_t i = 0; i < vec->count; i++) {
+ if (!strcmp(vec->buf[i].name, str)) {
+ free(vec->buf[i].name);
+ if (i < vec->count - 1) {
+ memmove(&vec->buf[i], &vec->buf[i+1], (vec->count - i) * sizeof(struct program));
+ }
+ vec->count--;
+ return;
+ }
+ }
+}
+
+bool mkdirp(const char *path)
+{
+ struct stat statbuf;
+ if (stat(path, &statbuf) == 0) {
+ /* If the history file exists, we don't need to do anything. */
+ return true;
+ }
+
+ /*
+ * Walk down the path, creating directories as we go.
+ * This works by repeatedly finding the next / in path, then calling
+ * mkdir() on the string up to that point.
+ */
+ char *tmp = xstrdup(path);
+ char *cursor = tmp;
+ while ((cursor = strchr(cursor + 1, '/')) != NULL) {
+ *cursor = '\0';
+ log_debug("Creating directory %s\n", tmp);
+ if (mkdir(tmp, 0700) != 0 && errno != EEXIST) {
+ log_error("Error creating history file path: %s.\n", strerror(errno));
+ free(tmp);
+ return false;
+ }
+ *cursor = '/';
+ }
+ free(tmp);
+ return true;
+}
diff --git a/src/history.h b/src/history.h
new file mode 100644
index 0000000..3be757f
--- /dev/null
+++ b/src/history.h
@@ -0,0 +1,31 @@
+#ifndef HISTORY_H
+#define HISTORY_H
+
+#include <stddef.h>
+
+struct program {
+ char *restrict name;
+ size_t run_count;
+};
+
+struct history {
+ size_t count;
+ size_t size;
+ struct program *buf;
+};
+
+[[gnu::nonnull]]
+void history_destroy(struct history *restrict vec);
+
+[[gnu::nonnull]]
+void history_add(struct history *restrict vec, const char *restrict str);
+
+//[[gnu::nonnull]]
+//void history_remove(struct history *restrict vec, const char *restrict str);
+
+[[nodiscard]]
+struct history history_load(void);
+
+void history_save(struct history *history);
+
+#endif /* HISTORY_H */
diff --git a/src/main.c b/src/main.c
index 95f16dc..514d6f2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -29,32 +29,6 @@
#undef MAX
#define MAX(a, b) ((a) > (b) ? (a) : (b))
-
-static void resize(struct tofi *tofi)
-{
- struct surface *surface = &tofi->window.surface;
-
- /*
- * Resize the main window.
- * EGL wants actual pixel width / height, so we have to scale the
- * values provided by Wayland.
- */
- surface->width = tofi->window.width * tofi->window.scale;
- surface->height = tofi->window.height * tofi->window.scale;
-
- /*
- * Need to redraw the background at the new size. This entails a
- * wl_surface_commit, so no need to do so explicitly here.
- */
- tofi->window.surface.redraw = true;
-
- /*
- * Center the entry.
- * Wayland wants "surface-local" width / height, so we have to divide
- * the entry's pixel size by the scale factor.
- */
-}
-
static void zwlr_layer_surface_configure(
void *data,
struct zwlr_layer_surface_v1 *zwlr_layer_surface,
@@ -72,7 +46,22 @@ static void zwlr_layer_surface_configure(
if (width != tofi->window.width || height != tofi->window.height) {
tofi->window.width = width;
tofi->window.height = height;
- tofi->window.resize = true;
+
+ /*
+ * Resize the main window.
+ * EGL wants actual pixel width / height, so we have to scale the
+ * values provided by Wayland.
+ */
+ tofi->window.surface.width =
+ tofi->window.width * tofi->window.scale;
+ tofi->window.surface.height =
+ tofi->window.height * tofi->window.scale;
+
+ /*
+ * Need to redraw the background at the new size. This entails a
+ * wl_surface_commit, so no need to do so explicitly here.
+ */
+ tofi->window.surface.redraw = true;
}
zwlr_layer_surface_v1_ack_configure(
tofi->window.zwlr_layer_surface,
@@ -202,8 +191,7 @@ static void wl_keyboard_key(
)
{
tofi->closed = true;
- } else if (entry->input_length > 0
- && (sym == XKB_KEY_Return || sym == XKB_KEY_KP_Enter)) {
+ } else if (sym == XKB_KEY_Return || sym == XKB_KEY_KP_Enter) {
tofi->submit = true;
return;
}
@@ -535,7 +523,6 @@ static void usage()
"Usage: tofi [options]\n"
" -u, --user=NAME The user to login as.\n"
" -c, --command=COMMAND The command to run on login.\n"
-" -b, --background-image=PATH An image to use as the background.\n"
" -B, --background-color=COLOR Color of the background.\n"
" -o, --outline-width=VALUE Width of the border outlines in pixels.\n"
" -O, --outline-color=COLOR Color of the border outlines.\n"
@@ -565,7 +552,7 @@ int main(int argc, char *argv[])
.username = "nobody",
.command = "false",
.window = {
- .background_color = {0.89, 0.8, 0.824, 1.0},
+ .background_color = {0.89f, 0.8f, 0.824f, 1.0f},
.scale = 1,
.width = 640,
.height = 480,
@@ -574,20 +561,21 @@ int main(int argc, char *argv[])
.border = {
.width = 6,
.outline_width = 2,
- .color = {0.976, 0.149, 0.447, 1.0},
- .outline_color = {0.031, 0.031, 0.0, 1.0},
+ .color = {0.976f, 0.149f, 0.447f, 1.0f},
+ .outline_color = {0.031f, 0.031f, 0.0f, 1.0f},
},
.font_name = "Sans Bold",
.font_size = 24,
.padding = 8,
.num_characters = 12,
- .background_color = {0.106, 0.114, 0.118, 1.0},
- .foreground_color = {1.0, 1.0, 1.0, 1.0}
+ .background_color = {0.106f, 0.114f, 0.118f, 1.0f},
+ .foreground_color = {1.0f, 1.0f, 1.0f, 1.0f}
}
}
};
- tofi.window.entry.commands = compgen();
+ tofi.window.entry.history = history_load();
+ tofi.window.entry.commands = compgen(&tofi.window.entry.history);
tofi.window.entry.results = string_vec_copy(&tofi.window.entry.commands);
@@ -790,9 +778,6 @@ int main(int argc, char *argv[])
wl_display_roundtrip(tofi.wl_display);
log_debug("Third roundtrip done.\n");
- /* Call resize() just to center the entry properly. */
- resize(&tofi);
-
/*
* Initialise the Pango & Cairo structures for rendering the entry.
* Cairo needs to know the size of the surface it's creating, and
@@ -825,21 +810,13 @@ int main(int argc, char *argv[])
&tofi.window.entry.background_color,
&tofi.window.entry.image);
- /*
- * We've just rendered everything and resized, so we don't need to do
- * it again right now.
- */
- tofi.window.resize = false;
+ /* We've just rendered, so we don't need to do it again right now. */
tofi.window.surface.redraw = false;
while (wl_display_dispatch(tofi.wl_display) != -1) {
if (tofi.closed) {
break;
}
- if (tofi.window.resize) {
- resize(&tofi);
- tofi.window.resize = false;
- }
if (tofi.window.surface.redraw) {
surface_draw(
&tofi.window.surface,
@@ -848,10 +825,15 @@ int main(int argc, char *argv[])
tofi.window.surface.redraw = false;
}
if (tofi.submit) {
+ tofi.submit = false;
if (tofi.window.entry.results.count > 0) {
printf("%s\n", tofi.window.entry.results.buf[0]);
+ history_add(
+ &tofi.window.entry.history,
+ tofi.window.entry.results.buf[0]);
+ history_save(&tofi.window.entry.history);
+ break;
}
- break;
}
}
@@ -879,6 +861,8 @@ int main(int argc, char *argv[])
xkb_keymap_unref(tofi.xkb_keymap);
xkb_context_unref(tofi.xkb_context);
wl_registry_destroy(tofi.wl_registry);
+ string_vec_destroy(&tofi.window.entry.commands);
+ history_destroy(&tofi.window.entry.history);
#endif
/*
* For release builds, skip straight to display disconnection and quit.
diff --git a/src/string_vec.c b/src/string_vec.c
index d3ac9fe..3c77f6f 100644
--- a/src/string_vec.c
+++ b/src/string_vec.c
@@ -1,4 +1,5 @@
-#define _GNU_SOURCE
+#define _GNU_SOURCE /* Required for strcasecmp */
+#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "string_vec.h"
@@ -7,8 +8,8 @@
static int cmpstringp(const void *restrict a, const void *restrict b)
{
/*
- * We receive pointers to the array elements (which are pointers to
- * char), so convert and dereference them for comparison.
+ * For qsort we receive pointers to the array elements (which are
+ * pointers to char), so convert and dereference them for comparison.
*/
const char *restrict str1 = *(const char **)a;
const char *restrict str2 = *(const char **)b;
@@ -52,7 +53,7 @@ struct string_vec string_vec_copy(struct string_vec *restrict vec)
};
for (size_t i = 0; i < vec->count; i++) {
- copy.buf[i] = strdup(vec->buf[i]);
+ copy.buf[i] = xstrdup(vec->buf[i]);
}
return copy;
@@ -64,7 +65,7 @@ void string_vec_add(struct string_vec *restrict vec, const char *restrict str)
vec->size *= 2;
vec->buf = xrealloc(vec->buf, vec->size * sizeof(vec->buf[0]));
}
- vec->buf[vec->count] = strdup(str);
+ vec->buf[vec->count] = xstrdup(str);
vec->count++;
}
@@ -87,6 +88,11 @@ void string_vec_uniq(struct string_vec *restrict vec)
vec->count = count;
}
+char **string_vec_find(struct string_vec *restrict vec, const char * str)
+{
+ return bsearch(&str, vec->buf, vec->count, sizeof(vec->buf[0]), cmpstringp);
+}
+
struct string_vec string_vec_filter(
const struct string_vec *restrict vec,
const char *restrict substr)
diff --git a/src/string_vec.h b/src/string_vec.h
index 7ebcb53..a5f00d5 100644
--- a/src/string_vec.h
+++ b/src/string_vec.h
@@ -3,11 +3,6 @@
#include <stddef.h>
-struct program {
- char *name;
- size_t run_count;
-};
-
struct string_vec {
size_t count;
size_t size;
@@ -27,6 +22,8 @@ void string_vec_sort(struct string_vec *restrict vec);
void string_vec_uniq(struct string_vec *restrict vec);
+char **string_vec_find(struct string_vec *restrict vec, const char *str);
+
[[nodiscard]]
struct string_vec string_vec_filter(
const struct string_vec *restrict vec,
diff --git a/src/surface.c b/src/surface.c
index cbc6c94..8052d5e 100644
--- a/src/surface.c
+++ b/src/surface.c
@@ -44,8 +44,8 @@ void surface_draw(
(double)surface->width / texture->width,
(double)surface->height / texture->height
);
- uint32_t width = (uint32_t)(scale * texture->width);
- uint32_t height = (uint32_t)(scale * texture->height);
+ int32_t width = (int32_t)(scale * texture->width);
+ int32_t height = (int32_t)(scale * texture->height);
int32_t x = -((int32_t)width - (int32_t)surface->width) / 2;
int32_t y = -((int32_t)height - (int32_t)surface->height) / 2;
diff --git a/src/tofi.h b/src/tofi.h
index 3ea66f3..87c0dfe 100644
--- a/src/tofi.h
+++ b/src/tofi.h
@@ -40,7 +40,6 @@ struct tofi {
uint32_t width;
uint32_t height;
uint32_t scale;
- bool resize;
} window;
/* Keyboard state */
diff --git a/src/xmalloc.c b/src/xmalloc.c
index 8a08cb8..1c2a9dc 100644
--- a/src/xmalloc.c
+++ b/src/xmalloc.c
@@ -1,4 +1,5 @@
#include <stdio.h>
+#include <string.h>
#include "log.h"
#include "xmalloc.h"
@@ -7,10 +8,10 @@ void *xmalloc(size_t size)
void *ptr = malloc(size);
if (ptr != NULL) {
- log_debug("Allocated %zu bytes.\n", size);
+ //log_debug("Allocated %zu bytes.\n", size);
return ptr;
} else {
- fputs("Out of memory, exiting.", stderr);
+ log_error("Out of memory, exiting.\n");
exit(EXIT_FAILURE);
}
}
@@ -20,10 +21,10 @@ void *xcalloc(size_t nmemb, size_t size)
void *ptr = calloc(nmemb, size);
if (ptr != NULL) {
- log_debug("Allocated %zux%zu bytes.\n", nmemb, size);
+ //log_debug("Allocated %zux%zu bytes.\n", nmemb, size);
return ptr;
} else {
- fputs("Out of memory, exiting.", stderr);
+ log_error("Out of memory, exiting.\n");
exit(EXIT_FAILURE);
}
}
@@ -33,10 +34,23 @@ void *xrealloc(void *ptr, size_t size)
ptr = realloc(ptr, size);
if (ptr != NULL) {
- log_debug("Reallocated to %zu bytes.\n", size);
+ //log_debug("Reallocated to %zu bytes.\n", size);
return ptr;
} else {
- fputs("Out of memory, exiting.", stderr);
+ log_error("Out of memory, exiting.\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+char *xstrdup(const char *s)
+{
+ char *ptr = strdup(s);
+
+ if (ptr != NULL) {
+ //log_debug("Allocated %zu bytes.\n", size);
+ return ptr;
+ } else {
+ log_error("Out of memory, exiting.\n");
exit(EXIT_FAILURE);
}
}
diff --git a/src/xmalloc.h b/src/xmalloc.h
index a661004..747509c 100644
--- a/src/xmalloc.h
+++ b/src/xmalloc.h
@@ -11,4 +11,7 @@ void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *ptr, size_t size);
+__attribute__((malloc))
+char *xstrdup(const char *s);
+
#endif /* XMALLOC_H */