chiark / gitweb /
(Slightly scrappy) new playlist box
[disorder] / lib / kvp.c
index 471de78e80bf8fe3cfa9743182904d64a9c22823..45aa03c190f3533540b95f323d473e9e95b0b594 100644 (file)
--- a/lib/kvp.c
+++ b/lib/kvp.c
@@ -1,28 +1,29 @@
 /*
  * This file is part of DisOrder.
 /*
  * This file is part of DisOrder.
- * Copyright (C) 2004, 2005 Richard Kettlewell
+ * Copyright (C) 2004, 2005, 2007, 2008 Richard Kettlewell
  *
  *
- * This program is free software; you can redistribute it and/or modify
+ * 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
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation, either version 3 of the License, or
  * (at your option) any later version.
  * (at your option) any later version.
+ * 
+ * This program 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 General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/** @file lib/kvp.c
+ * @brief Linked list of key-value pairs
  *
  *
- * This program 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
- * General Public License for more details.
+ * Also supports URL encoding/decoding (of raw strings and kvp lists).
  *
  *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
- * USA
+ * For large sets of keys, see @ref lib/hash.c.
  */
 
  */
 
-#include <config.h>
-#include "types.h"
-
-#include <string.h>
-#include <stdio.h>
+#include "common.h"
 
 #include "mem.h"
 #include "kvp.h"
 
 #include "mem.h"
 #include "kvp.h"
 #include "hex.h"
 #include "sink.h"
 
 #include "hex.h"
 #include "sink.h"
 
+/** @brief Decode a URL-encoded string to a ink
+ * @param sink Where to store result
+ * @param ptr Start of string
+ * @param n Length of string
+ * @return 0 on success, non-0 if string could not be decoded or sink write failed
+ */
 int urldecode(struct sink *sink, const char *ptr, size_t n) {
   int c, d1, d2;
   
 int urldecode(struct sink *sink, const char *ptr, size_t n) {
   int c, d1, d2;
   
@@ -56,6 +63,11 @@ int urldecode(struct sink *sink, const char *ptr, size_t n) {
   return 0;
 }
 
   return 0;
 }
 
+/** @brief URL-decode a string
+ * @param ptr Start of URL-encoded string
+ * @param n Length of @p ptr
+ * @return Decoded string (0-terminated)
+ */
 static char *decode(const char *ptr, size_t n) {
   struct dynstr d;
   struct sink *s;
 static char *decode(const char *ptr, size_t n) {
   struct dynstr d;
   struct sink *s;
@@ -68,6 +80,15 @@ static char *decode(const char *ptr, size_t n) {
   return d.vec;
 }
 
   return d.vec;
 }
 
+/** @brief Decode a URL-decoded key-value pair list
+ * @param ptr Start of input string
+ * @param n Length of input string
+ * @return @ref kvp of values from input
+ *
+ * The KVP is in the same order as the original input.
+ *
+ * If the original input contains duplicates names, so will the KVP.
+ */
 struct kvp *kvp_urldecode(const char *ptr, size_t n) {
   struct kvp *kvp, **kk = &kvp, *k;
   const char *q, *r, *top = ptr + n, *next;
 struct kvp *kvp_urldecode(const char *ptr, size_t n) {
   struct kvp *kvp, **kk = &kvp, *k;
   const char *q, *r, *top = ptr + n, *next;
@@ -91,6 +112,12 @@ struct kvp *kvp_urldecode(const char *ptr, size_t n) {
   return kvp;
 }
 
   return kvp;
 }
 
+/** @brief URL-encode a string to a sink
+ * @param sink Where to send output
+ * @param s String to encode
+ * @param n Length of string to encode
+ * @return 0 on success or non-0 if sink write failed
+ */
 int urlencode(struct sink *sink, const char *s, size_t n) {
   unsigned char c;
 
 int urlencode(struct sink *sink, const char *s, size_t n) {
   unsigned char c;
 
@@ -128,7 +155,7 @@ int urlencode(struct sink *sink, const char *s, size_t n) {
  * @param s String to encode
  * @return Encoded string
  */
  * @param s String to encode
  * @return Encoded string
  */
-const char *urlencodestring(const char *s) {
+char *urlencodestring(const char *s) {
   struct dynstr d;
 
   dynstr_init(&d);
   struct dynstr d;
 
   dynstr_init(&d);
@@ -140,17 +167,23 @@ const char *urlencodestring(const char *s) {
 /** @brief URL-decode @p s
  * @param s String to decode
  * @param ns Length of string
 /** @brief URL-decode @p s
  * @param s String to decode
  * @param ns Length of string
- * @return Decoded string
+ * @return Decoded string or NULL
  */
  */
-const char *urldecodestring(const char *s, size_t ns) {
+char *urldecodestring(const char *s, size_t ns) {
   struct dynstr d;
 
   dynstr_init(&d);
   struct dynstr d;
 
   dynstr_init(&d);
-  urldecode(sink_dynstr(&d), s, ns);
+  if(urldecode(sink_dynstr(&d), s, ns))
+    return NULL;
   dynstr_terminate(&d);
   return d.vec;
 }
 
   dynstr_terminate(&d);
   return d.vec;
 }
 
+/** @brief URL-encode a KVP
+ * @param kvp Linked list to encode
+ * @param np Where to store length (or NULL)
+ * @return Newly created string
+ */
 char *kvp_urlencode(const struct kvp *kvp, size_t *np) {
   struct dynstr d;
   struct sink *sink;
 char *kvp_urlencode(const struct kvp *kvp, size_t *np) {
   struct dynstr d;
   struct sink *sink;
@@ -171,6 +204,20 @@ char *kvp_urlencode(const struct kvp *kvp, size_t *np) {
   return d.vec;
 }
 
   return d.vec;
 }
 
+/** @brief Set or remove a value in a @ref kvp
+ * @param kvpp Address of KVP head to modify
+ * @param name Key to search for
+ * @param value New value or NULL to delete
+ * @return 1 if any change was made otherwise 0
+ *
+ * If @p value is not NULL then the first matching key is replaced; if
+ * there was no matching key a new one is added at the end.
+ *
+ * If @p value is NULL then the first matching key is removed.
+ *
+ * If anything actually changes the return value is 1.  If no actual
+ * change is made then 0 is returned instead.
+ */
 int kvp_set(struct kvp **kvpp, const char *name, const char *value) {
   struct kvp *k, **kk;
 
 int kvp_set(struct kvp **kvpp, const char *name, const char *value) {
   struct kvp *k, **kk;
 
@@ -198,12 +245,48 @@ int kvp_set(struct kvp **kvpp, const char *name, const char *value) {
   }
 }
 
   }
 }
 
+/** @brief Look up a value in a @ref kvp
+ * @param kvp Head of KVP linked list
+ * @param name Key to search for
+ * @return Value or NULL
+ *
+ * The returned value is owned by the KVP so must not be modified or
+ * freed.
+ */
 const char *kvp_get(const struct kvp *kvp, const char *name) {
   for(;kvp && strcmp(kvp->name, name); kvp = kvp->next)
     ;
   return kvp ? kvp->value : 0;
 }
 
 const char *kvp_get(const struct kvp *kvp, const char *name) {
   for(;kvp && strcmp(kvp->name, name); kvp = kvp->next)
     ;
   return kvp ? kvp->value : 0;
 }
 
+/** @brief Construct a KVP from arguments
+ * @param name First name
+ * @return Newly created KVP
+ *
+ * Arguments must come in name/value pairs and must be followed by a (char *)0.
+ *
+ * The order of the new KVP is not formally defined though the test
+ * programs rely on it nonetheless so update them if you change it.
+ */
+struct kvp *kvp_make(const char *name, ...) {
+  const char *value;
+  struct kvp *kvp = 0, *k;
+  va_list ap;
+
+  va_start(ap, name);
+  while(name) {
+    value = va_arg(ap, const char *);
+    k = xmalloc(sizeof *k);
+    k->name = name;
+    k->value = value ? xstrdup(value) : "";
+    k->next = kvp;
+    kvp = k;
+    name = va_arg(ap, const char *);
+  }
+  va_end(ap);
+  return kvp;
+}
+
 /*
 Local Variables:
 c-basic-offset:2
 /*
 Local Variables:
 c-basic-offset:2