chiark / gitweb /
disorder.h: more consistent approach to function attributes
[disorder] / lib / queue.c
index db28687923996b11e86afba979e35dfe16eec0fe..c592f5a13a4e949f516e7106550dcf014720ac70 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * This file is part of DisOrder.
- * Copyright (C) 2004-2009 Richard Kettlewell
+ * Copyright (C) 2004-2009, 2011, 2013 Richard Kettlewell
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -30,6 +30,7 @@
 #include "syscalls.h"
 #include "table.h"
 #include "printf.h"
+#include "vector.h"
 
 const char *const playing_states[] = {
   "failed",
@@ -76,8 +77,9 @@ static int unmarshall_long(char *data, struct queue_entry *q,
                           size_t offset,
                           void (*error_handler)(const char *, void *),
                           void *u) {
+  char errbuf[1024];
   if(xstrtol(&VALUE(q, offset, long), data, 0, 0)) {
-    error_handler(strerror(errno), u);
+    error_handler(format_error(ec_errno, errno, errbuf, sizeof errbuf), u);
     return -1;
   }
   return 0;
@@ -89,17 +91,23 @@ static const char *marshall_long(const struct queue_entry *q, size_t offset) {
 
   n = byte_snprintf(buffer, sizeof buffer, "%ld", VALUE(q, offset, long));
   if(n < 0)
-    fatal(errno, "error converting int");
+    disorder_fatal(errno, "error converting int");
   else if((size_t)n >= sizeof buffer)
-    fatal(0, "long converted to decimal is too long");
+    disorder_fatal(0, "long converted to decimal is too long");
   return xstrdup(buffer);
 }
 
+static void free_none(struct queue_entry attribute((unused)) *q,
+                      size_t attribute((unused)) offset) {
+}
+
+#define free_long free_none
+
 static int unmarshall_string(char *data, struct queue_entry *q,
                             size_t offset,
                             void attribute((unused)) (*error_handler)(const char *, void *),
                             void attribute((unused)) *u) {
-  VALUE(q, offset, char *) = data;
+  VALUE(q, offset, char *) = xstrdup(data);
   return 0;
 }
 
@@ -107,14 +115,19 @@ static const char *marshall_string(const struct queue_entry *q, size_t offset) {
   return VALUE(q, offset, char *);
 }
 
+static void free_string(struct queue_entry *q, size_t offset) {
+  xfree(VALUE(q, offset, char *));
+}
+
 static int unmarshall_time_t(char *data, struct queue_entry *q,
                             size_t offset,
                             void (*error_handler)(const char *, void *),
                             void *u) {
   long_long ul;
+  char errbuf[1024];
 
   if(xstrtoll(&ul, data, 0, 0)) {
-    error_handler(strerror(errno), u);
+    error_handler(format_error(ec_errno, errno, errbuf, sizeof errbuf), u);
     return -1;
   }
   VALUE(q, offset, time_t) = ul;
@@ -128,12 +141,14 @@ static const char *marshall_time_t(const struct queue_entry *q, size_t offset) {
   n = byte_snprintf(buffer, sizeof buffer,
                    "%"PRIdMAX, (intmax_t)VALUE(q, offset, time_t));
   if(n < 0)
-    fatal(errno, "error converting time");
+    disorder_fatal(errno, "error converting time");
   else if((size_t)n >= sizeof buffer)
-    fatal(0, "time converted to decimal is too long");
+    disorder_fatal(0, "time converted to decimal is too long");
   return xstrdup(buffer);
 }
 
+#define free_time_t free_none
+
 static int unmarshall_state(char *data, struct queue_entry *q,
                            size_t offset,
                            void (*error_handler)(const char *, void *),
@@ -176,15 +191,29 @@ static const char *marshall_origin(const struct queue_entry *q, size_t offset) {
   return track_origins[VALUE(q, offset, enum track_origin)];
 }
 
-#define F(n, h) { #n, offsetof(struct queue_entry, n), marshall_##h, unmarshall_##h }
+#define free_state free_none
+#define free_origin free_none
+
+#define F(n, h) { #n, offsetof(struct queue_entry, n), marshall_##h, unmarshall_##h, free_##h }
 
-static const struct field {
+/** @brief A field in a @ref queue_entry */
+static const struct queue_field {
+  /** @brief Field name */
   const char *name;
+
+  /** @brief Offset of value in @ref queue_entry structure */
   size_t offset;
+
+  /** @brief Marshaling function */
   const char *(*marshall)(const struct queue_entry *q, size_t offset);
+
+  /** @brief Unmarshaling function */
   int (*unmarshall)(char *data, struct queue_entry *q, size_t offset,
                    void (*error_handler)(const char *, void *),
                    void *u);
+
+  /** @brief Destructor */
+  void (*free)(struct queue_entry *q, size_t offset);
 } fields[] = {
   /* Keep this table sorted. */
   F(expected, time_t),
@@ -199,17 +228,20 @@ static const struct field {
   F(when, time_t),
   F(wstat, long)
 };
+#define NFIELDS (sizeof fields / sizeof *fields)
 
 int queue_unmarshall(struct queue_entry *q, const char *s,
                     void (*error_handler)(const char *, void *),
                     void *u) {
   char **vec;
-  int nvec;
+  int nvec, rc;
 
   q->pid = -1;                          /* =none */
   if(!(vec = split(s, &nvec, SPLIT_QUOTES, error_handler, u)))
     return -1;
-  return queue_unmarshall_vec(q, nvec, vec, error_handler, u);
+  rc = queue_unmarshall_vec(q, nvec, vec, error_handler, u);
+  free_strings(nvec, vec);
+  return rc;
 }
 
 int queue_unmarshall_vec(struct queue_entry *q, int nvec, char **vec,
@@ -258,6 +290,17 @@ char *queue_marshall(const struct queue_entry *q) {
   return r;
 }
 
+void queue_free(struct queue_entry *q, int rest) {
+  unsigned n;
+  if(!q)
+    return;
+  if(rest)
+    queue_free(q->next, rest);
+  for(n = 0; n < NFIELDS; ++n)
+    fields[n].free(q, fields[n].offset);
+  xfree(q);
+}
+
 /*
 Local Variables:
 c-basic-offset:2