summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile1
-rw-r--r--queue.h648
-rw-r--r--sfeed_frames.c48
-rw-r--r--sfeed_html.c75
-rw-r--r--sfeed_stats.c40
-rw-r--r--util.h8
6 files changed, 736 insertions, 84 deletions
diff --git a/Makefile b/Makefile
index bf8751f..665681e 100644
--- a/Makefile
+++ b/Makefile
@@ -46,6 +46,7 @@ DOC = \
TODO
HDR = \
compat.h\
+ queue.h\
util.h\
xml.h
diff --git a/queue.h b/queue.h
new file mode 100644
index 0000000..f8f09bf
--- /dev/null
+++ b/queue.h
@@ -0,0 +1,648 @@
+/* $OpenBSD: queue.h,v 1.38 2013/07/03 15:05:21 fgsch Exp $ */
+/* $NetBSD: queue.h,v 1.11 1996/05/16 05:17:14 mycroft Exp $ */
+
+/*
+ * Copyright (c) 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)queue.h 8.5 (Berkeley) 8/20/94
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define _SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * lists, simple queues, tail queues, and circular queues.
+ *
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction. Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A simple queue is headed by a pair of pointers, one the head of the
+ * list and the other to the tail of the list. The elements are singly
+ * linked to save space, so elements can only be removed from the
+ * head of the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the
+ * list. A simple queue may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ */
+
+#if defined(QUEUE_MACRO_DEBUG) || (defined(_KERNEL) && defined(DIAGNOSTIC))
+#define _Q_INVALIDATE(a) (a) = ((void *)-1)
+#else
+#define _Q_INVALIDATE(a)
+#endif
+
+/*
+ * Singly-linked List definitions.
+ */
+#define SLIST_HEAD(name, type) \
+struct name { \
+ struct type *slh_first; /* first element */ \
+}
+
+#define SLIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define SLIST_ENTRY(type) \
+struct { \
+ struct type *sle_next; /* next element */ \
+}
+
+/*
+ * Singly-linked List access methods.
+ */
+#define SLIST_FIRST(head) ((head)->slh_first)
+#define SLIST_END(head) NULL
+#define SLIST_EMPTY(head) (SLIST_FIRST(head) == SLIST_END(head))
+#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
+
+#define SLIST_FOREACH(var, head, field) \
+ for((var) = SLIST_FIRST(head); \
+ (var) != SLIST_END(head); \
+ (var) = SLIST_NEXT(var, field))
+
+#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SLIST_FIRST(head); \
+ (var) && ((tvar) = SLIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Singly-linked List functions.
+ */
+#define SLIST_INIT(head) { \
+ SLIST_FIRST(head) = SLIST_END(head); \
+}
+
+#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
+ (elm)->field.sle_next = (slistelm)->field.sle_next; \
+ (slistelm)->field.sle_next = (elm); \
+} while (0)
+
+#define SLIST_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.sle_next = (head)->slh_first; \
+ (head)->slh_first = (elm); \
+} while (0)
+
+#define SLIST_REMOVE_AFTER(elm, field) do { \
+ (elm)->field.sle_next = (elm)->field.sle_next->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE_HEAD(head, field) do { \
+ (head)->slh_first = (head)->slh_first->field.sle_next; \
+} while (0)
+
+#define SLIST_REMOVE(head, elm, type, field) do { \
+ if ((head)->slh_first == (elm)) { \
+ SLIST_REMOVE_HEAD((head), field); \
+ } else { \
+ struct type *curelm = (head)->slh_first; \
+ \
+ while (curelm->field.sle_next != (elm)) \
+ curelm = curelm->field.sle_next; \
+ curelm->field.sle_next = \
+ curelm->field.sle_next->field.sle_next; \
+ _Q_INVALIDATE((elm)->field.sle_next); \
+ } \
+} while (0)
+
+/*
+ * List definitions.
+ */
+#define LIST_HEAD(name, type) \
+struct name { \
+ struct type *lh_first; /* first element */ \
+}
+
+#define LIST_HEAD_INITIALIZER(head) \
+ { NULL }
+
+#define LIST_ENTRY(type) \
+struct { \
+ struct type *le_next; /* next element */ \
+ struct type **le_prev; /* address of previous next element */ \
+}
+
+/*
+ * List access methods
+ */
+#define LIST_FIRST(head) ((head)->lh_first)
+#define LIST_END(head) NULL
+#define LIST_EMPTY(head) (LIST_FIRST(head) == LIST_END(head))
+#define LIST_NEXT(elm, field) ((elm)->field.le_next)
+
+#define LIST_FOREACH(var, head, field) \
+ for((var) = LIST_FIRST(head); \
+ (var)!= LIST_END(head); \
+ (var) = LIST_NEXT(var, field))
+
+#define LIST_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = LIST_FIRST(head); \
+ (var) && ((tvar) = LIST_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * List functions.
+ */
+#define LIST_INIT(head) do { \
+ LIST_FIRST(head) = LIST_END(head); \
+} while (0)
+
+#define LIST_INSERT_AFTER(listelm, elm, field) do { \
+ if (((elm)->field.le_next = (listelm)->field.le_next) != NULL) \
+ (listelm)->field.le_next->field.le_prev = \
+ &(elm)->field.le_next; \
+ (listelm)->field.le_next = (elm); \
+ (elm)->field.le_prev = &(listelm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.le_prev = (listelm)->field.le_prev; \
+ (elm)->field.le_next = (listelm); \
+ *(listelm)->field.le_prev = (elm); \
+ (listelm)->field.le_prev = &(elm)->field.le_next; \
+} while (0)
+
+#define LIST_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.le_next = (head)->lh_first) != NULL) \
+ (head)->lh_first->field.le_prev = &(elm)->field.le_next;\
+ (head)->lh_first = (elm); \
+ (elm)->field.le_prev = &(head)->lh_first; \
+} while (0)
+
+#define LIST_REMOVE(elm, field) do { \
+ if ((elm)->field.le_next != NULL) \
+ (elm)->field.le_next->field.le_prev = \
+ (elm)->field.le_prev; \
+ *(elm)->field.le_prev = (elm)->field.le_next; \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+#define LIST_REPLACE(elm, elm2, field) do { \
+ if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \
+ (elm2)->field.le_next->field.le_prev = \
+ &(elm2)->field.le_next; \
+ (elm2)->field.le_prev = (elm)->field.le_prev; \
+ *(elm2)->field.le_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.le_prev); \
+ _Q_INVALIDATE((elm)->field.le_next); \
+} while (0)
+
+/*
+ * Simple queue definitions.
+ */
+#define SIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqh_first; /* first element */ \
+ struct type **sqh_last; /* addr of last next element */ \
+}
+
+#define SIMPLEQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).sqh_first }
+
+#define SIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqe_next; /* next element */ \
+}
+
+/*
+ * Simple queue access methods.
+ */
+#define SIMPLEQ_FIRST(head) ((head)->sqh_first)
+#define SIMPLEQ_END(head) NULL
+#define SIMPLEQ_EMPTY(head) (SIMPLEQ_FIRST(head) == SIMPLEQ_END(head))
+#define SIMPLEQ_NEXT(elm, field) ((elm)->field.sqe_next)
+
+#define SIMPLEQ_FOREACH(var, head, field) \
+ for((var) = SIMPLEQ_FIRST(head); \
+ (var) != SIMPLEQ_END(head); \
+ (var) = SIMPLEQ_NEXT(var, field))
+
+#define SIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = SIMPLEQ_FIRST(head); \
+ (var) && ((tvar) = SIMPLEQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Simple queue functions.
+ */
+#define SIMPLEQ_INIT(head) do { \
+ (head)->sqh_first = NULL; \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (head)->sqh_first) == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (head)->sqh_first = (elm); \
+} while (0)
+
+#define SIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqe_next = NULL; \
+ *(head)->sqh_last = (elm); \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+#define SIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqe_next = (listelm)->field.sqe_next) == NULL)\
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+ (listelm)->field.sqe_next = (elm); \
+} while (0)
+
+#define SIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqh_first = (head)->sqh_first->field.sqe_next) == NULL) \
+ (head)->sqh_last = &(head)->sqh_first; \
+} while (0)
+
+#define SIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqe_next = (elm)->field.sqe_next->field.sqe_next) \
+ == NULL) \
+ (head)->sqh_last = &(elm)->field.sqe_next; \
+} while (0)
+
+/*
+ * XOR Simple queue definitions.
+ */
+#define XSIMPLEQ_HEAD(name, type) \
+struct name { \
+ struct type *sqx_first; /* first element */ \
+ struct type **sqx_last; /* addr of last next element */ \
+ unsigned long sqx_cookie; \
+}
+
+#define XSIMPLEQ_ENTRY(type) \
+struct { \
+ struct type *sqx_next; /* next element */ \
+}
+
+/*
+ * XOR Simple queue access methods.
+ */
+#define XSIMPLEQ_XOR(head, ptr) ((__typeof(ptr))((head)->sqx_cookie ^ \
+ (unsigned long)(ptr)))
+#define XSIMPLEQ_FIRST(head) XSIMPLEQ_XOR(head, ((head)->sqx_first))
+#define XSIMPLEQ_END(head) NULL
+#define XSIMPLEQ_EMPTY(head) (XSIMPLEQ_FIRST(head) == XSIMPLEQ_END(head))
+#define XSIMPLEQ_NEXT(head, elm, field) XSIMPLEQ_XOR(head, ((elm)->field.sqx_next))
+
+
+#define XSIMPLEQ_FOREACH(var, head, field) \
+ for ((var) = XSIMPLEQ_FIRST(head); \
+ (var) != XSIMPLEQ_END(head); \
+ (var) = XSIMPLEQ_NEXT(head, var, field))
+
+#define XSIMPLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = XSIMPLEQ_FIRST(head); \
+ (var) && ((tvar) = XSIMPLEQ_NEXT(head, var, field), 1); \
+ (var) = (tvar))
+
+/*
+ * XOR Simple queue functions.
+ */
+#define XSIMPLEQ_INIT(head) do { \
+ arc4random_buf(&(head)->sqx_cookie, sizeof((head)->sqx_cookie)); \
+ (head)->sqx_first = XSIMPLEQ_XOR(head, NULL); \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.sqx_next = (head)->sqx_first) == \
+ XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+ (head)->sqx_first = XSIMPLEQ_XOR(head, (elm)); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.sqx_next = XSIMPLEQ_XOR(head, NULL); \
+ *(XSIMPLEQ_XOR(head, (head)->sqx_last)) = XSIMPLEQ_XOR(head, (elm)); \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+} while (0)
+
+#define XSIMPLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.sqx_next = (listelm)->field.sqx_next) == \
+ XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+ (listelm)->field.sqx_next = XSIMPLEQ_XOR(head, (elm)); \
+} while (0)
+
+#define XSIMPLEQ_REMOVE_HEAD(head, field) do { \
+ if (((head)->sqx_first = XSIMPLEQ_XOR(head, \
+ (head)->sqx_first)->field.sqx_next) == XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = XSIMPLEQ_XOR(head, &(head)->sqx_first); \
+} while (0)
+
+#define XSIMPLEQ_REMOVE_AFTER(head, elm, field) do { \
+ if (((elm)->field.sqx_next = XSIMPLEQ_XOR(head, \
+ (elm)->field.sqx_next)->field.sqx_next) \
+ == XSIMPLEQ_XOR(head, NULL)) \
+ (head)->sqx_last = \
+ XSIMPLEQ_XOR(head, &(elm)->field.sqx_next); \
+} while (0)
+
+
+/*
+ * Tail queue definitions.
+ */
+#define TAILQ_HEAD(name, type) \
+struct name { \
+ struct type *tqh_first; /* first element */ \
+ struct type **tqh_last; /* addr of last next element */ \
+}
+
+#define TAILQ_HEAD_INITIALIZER(head) \
+ { NULL, &(head).tqh_first }
+
+#define TAILQ_ENTRY(type) \
+struct { \
+ struct type *tqe_next; /* next element */ \
+ struct type **tqe_prev; /* address of previous next element */ \
+}
+
+/*
+ * tail queue access methods
+ */
+#define TAILQ_FIRST(head) ((head)->tqh_first)
+#define TAILQ_END(head) NULL
+#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+#define TAILQ_LAST(head, headname) \
+ (*(((struct headname *)((head)->tqh_last))->tqh_last))
+/* XXX */
+#define TAILQ_PREV(elm, headname, field) \
+ (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+#define TAILQ_EMPTY(head) \
+ (TAILQ_FIRST(head) == TAILQ_END(head))
+
+#define TAILQ_FOREACH(var, head, field) \
+ for((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_NEXT(var, field))
+
+#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = TAILQ_FIRST(head); \
+ (var) != TAILQ_END(head) && \
+ ((tvar) = TAILQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+
+#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
+ for((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head); \
+ (var) = TAILQ_PREV(var, headname, field))
+
+#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = TAILQ_LAST(head, headname); \
+ (var) != TAILQ_END(head) && \
+ ((tvar) = TAILQ_PREV(var, headname, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Tail queue functions.
+ */
+#define TAILQ_INIT(head) do { \
+ (head)->tqh_first = NULL; \
+ (head)->tqh_last = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_HEAD(head, elm, field) do { \
+ if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \
+ (head)->tqh_first->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (head)->tqh_first = (elm); \
+ (elm)->field.tqe_prev = &(head)->tqh_first; \
+} while (0)
+
+#define TAILQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.tqe_next = NULL; \
+ (elm)->field.tqe_prev = (head)->tqh_last; \
+ *(head)->tqh_last = (elm); \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
+ (elm)->field.tqe_next->field.tqe_prev = \
+ &(elm)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm)->field.tqe_next; \
+ (listelm)->field.tqe_next = (elm); \
+ (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
+ (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
+ (elm)->field.tqe_next = (listelm); \
+ *(listelm)->field.tqe_prev = (elm); \
+ (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \
+} while (0)
+
+#define TAILQ_REMOVE(head, elm, field) do { \
+ if (((elm)->field.tqe_next) != NULL) \
+ (elm)->field.tqe_next->field.tqe_prev = \
+ (elm)->field.tqe_prev; \
+ else \
+ (head)->tqh_last = (elm)->field.tqe_prev; \
+ *(elm)->field.tqe_prev = (elm)->field.tqe_next; \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+#define TAILQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \
+ (elm2)->field.tqe_next->field.tqe_prev = \
+ &(elm2)->field.tqe_next; \
+ else \
+ (head)->tqh_last = &(elm2)->field.tqe_next; \
+ (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \
+ *(elm2)->field.tqe_prev = (elm2); \
+ _Q_INVALIDATE((elm)->field.tqe_prev); \
+ _Q_INVALIDATE((elm)->field.tqe_next); \
+} while (0)
+
+/*
+ * Circular queue definitions.
+ */
+#define CIRCLEQ_HEAD(name, type) \
+struct name { \
+ struct type *cqh_first; /* first element */ \
+ struct type *cqh_last; /* last element */ \
+}
+
+#define CIRCLEQ_HEAD_INITIALIZER(head) \
+ { CIRCLEQ_END(&head), CIRCLEQ_END(&head) }
+
+#define CIRCLEQ_ENTRY(type) \
+struct { \
+ struct type *cqe_next; /* next element */ \
+ struct type *cqe_prev; /* previous element */ \
+}
+
+/*
+ * Circular queue access methods
+ */
+#define CIRCLEQ_FIRST(head) ((head)->cqh_first)
+#define CIRCLEQ_LAST(head) ((head)->cqh_last)
+#define CIRCLEQ_END(head) ((void *)(head))
+#define CIRCLEQ_NEXT(elm, field) ((elm)->field.cqe_next)
+#define CIRCLEQ_PREV(elm, field) ((elm)->field.cqe_prev)
+#define CIRCLEQ_EMPTY(head) \
+ (CIRCLEQ_FIRST(head) == CIRCLEQ_END(head))
+
+#define CIRCLEQ_FOREACH(var, head, field) \
+ for((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_NEXT(var, field))
+
+#define CIRCLEQ_FOREACH_SAFE(var, head, field, tvar) \
+ for ((var) = CIRCLEQ_FIRST(head); \
+ (var) != CIRCLEQ_END(head) && \
+ ((tvar) = CIRCLEQ_NEXT(var, field), 1); \
+ (var) = (tvar))
+
+#define CIRCLEQ_FOREACH_REVERSE(var, head, field) \
+ for((var) = CIRCLEQ_LAST(head); \
+ (var) != CIRCLEQ_END(head); \
+ (var) = CIRCLEQ_PREV(var, field))
+
+#define CIRCLEQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
+ for ((var) = CIRCLEQ_LAST(head, headname); \
+ (var) != CIRCLEQ_END(head) && \
+ ((tvar) = CIRCLEQ_PREV(var, headname, field), 1); \
+ (var) = (tvar))
+
+/*
+ * Circular queue functions.
+ */
+#define CIRCLEQ_INIT(head) do { \
+ (head)->cqh_first = CIRCLEQ_END(head); \
+ (head)->cqh_last = CIRCLEQ_END(head); \
+} while (0)
+
+#define CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm)->field.cqe_next; \
+ (elm)->field.cqe_prev = (listelm); \
+ if ((listelm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (listelm)->field.cqe_next->field.cqe_prev = (elm); \
+ (listelm)->field.cqe_next = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do { \
+ (elm)->field.cqe_next = (listelm); \
+ (elm)->field.cqe_prev = (listelm)->field.cqe_prev; \
+ if ((listelm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (listelm)->field.cqe_prev->field.cqe_next = (elm); \
+ (listelm)->field.cqe_prev = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_HEAD(head, elm, field) do { \
+ (elm)->field.cqe_next = (head)->cqh_first; \
+ (elm)->field.cqe_prev = CIRCLEQ_END(head); \
+ if ((head)->cqh_last == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm); \
+ else \
+ (head)->cqh_first->field.cqe_prev = (elm); \
+ (head)->cqh_first = (elm); \
+} while (0)
+
+#define CIRCLEQ_INSERT_TAIL(head, elm, field) do { \
+ (elm)->field.cqe_next = CIRCLEQ_END(head); \
+ (elm)->field.cqe_prev = (head)->cqh_last; \
+ if ((head)->cqh_first == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm); \
+ else \
+ (head)->cqh_last->field.cqe_next = (elm); \
+ (head)->cqh_last = (elm); \
+} while (0)
+
+#define CIRCLEQ_REMOVE(head, elm, field) do { \
+ if ((elm)->field.cqe_next == CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm)->field.cqe_prev; \
+ else \
+ (elm)->field.cqe_next->field.cqe_prev = \
+ (elm)->field.cqe_prev; \
+ if ((elm)->field.cqe_prev == CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm)->field.cqe_next; \
+ else \
+ (elm)->field.cqe_prev->field.cqe_next = \
+ (elm)->field.cqe_next; \
+ _Q_INVALIDATE((elm)->field.cqe_prev); \
+ _Q_INVALIDATE((elm)->field.cqe_next); \
+} while (0)
+
+#define CIRCLEQ_REPLACE(head, elm, elm2, field) do { \
+ if (((elm2)->field.cqe_next = (elm)->field.cqe_next) == \
+ CIRCLEQ_END(head)) \
+ (head)->cqh_last = (elm2); \
+ else \
+ (elm2)->field.cqe_next->field.cqe_prev = (elm2); \
+ if (((elm2)->field.cqe_prev = (elm)->field.cqe_prev) == \
+ CIRCLEQ_END(head)) \
+ (head)->cqh_first = (elm2); \
+ else \
+ (elm2)->field.cqe_prev->field.cqe_next = (elm2); \
+ _Q_INVALIDATE((elm)->field.cqe_prev); \
+ _Q_INVALIDATE((elm)->field.cqe_next); \
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/sfeed_frames.c b/sfeed_frames.c
index c72a504..9152cb7 100644
--- a/sfeed_frames.c
+++ b/sfeed_frames.c
@@ -12,13 +12,15 @@
#include <unistd.h>
#include <utime.h>
+#include "queue.h"
#include "util.h"
static int showsidebar = 1; /* show sidebar ? */
static FILE *fpindex = NULL, *fpitems = NULL, *fpmenu = NULL;
static FILE *fpcontent = NULL;
static char *line = NULL;
-static struct feed *feeds = NULL;
+static SLIST_HEAD(fhead, feed) fhead = SLIST_HEAD_INITIALIZER(fhead);
+static struct utimbuf contenttime;
static void
cleanup(void)
@@ -155,6 +157,10 @@ main(int argc, char *argv[])
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" /></head>"
"<body class=\"frame\"><div id=\"items\">", fpitems);
+ if(!(fcur = calloc(1, sizeof(struct feed))))
+ xerr(1, "calloc");
+ SLIST_INSERT_HEAD(&fhead, fcur, entry);
+
while(parseline(&line, &linesize, fields, FieldLast, '\t', stdin) > 0) {
feedname = fields[FieldFeedName];
if(feedname[0] == '\0') {
@@ -164,9 +170,12 @@ main(int argc, char *argv[])
showsidebar = 0;
}
/* first of feed section or new feed section (differ from previous). */
- if(!totalfeeds || (fcur && strcmp(fcur->name, feedname))) {
- /* TODO: makepathname isn't necesary if fields[FieldFeedName] is the same as the previous line */
- /* TODO: move this part below where FieldFeedName is checked if it's different ? */
+ if(!totalfeeds || strcmp(fcur->name, feedname)) {
+ /* TODO:
+ * - makepathname isn't necesary if fields[FieldFeedName]
+ * is the same as the previous line.
+ * - move this part below where FieldFeedName is
+ * checked if it's different ? */
/* make directory for feedname */
if(!(namelen = makepathname(feedname, name, sizeof(name))))
@@ -181,19 +190,16 @@ main(int argc, char *argv[])
if(!(f = calloc(1, sizeof(struct feed))))
xerr(1, "calloc");
+ if(!(f->name = strdup(feedname)))
+ xerr(1, "strdup");
+ SLIST_INSERT_AFTER(fcur, f, entry);
+ fcur = f;
- if(totalfeeds) { /* end previous one. */
+ /* end previous one. */
+ if(totalfeeds) {
fputs("</table>\n", fpitems);
- fcur->next = f;
- fcur = fcur->next;
- } else {
- /* first item. */
- fcur = f;
- feeds = fcur;
}
/* write menu link if new. */
- if(!(fcur->name = strdup(feedname)))
- xerr(1, "strdup");
if(fields[FieldFeedName][0] != '\0') {
fputs("<h2 id=\"", fpitems);
printfeednameid(fcur->name, fpitems);
@@ -274,20 +280,20 @@ main(int argc, char *argv[])
"<link rel=\"stylesheet\" type=\"text/css\" href=\"../style.css\" />\n"
"<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
"</head><body class=\"frame\"><div id=\"sidebar\">", fpmenu);
- for(fcur = feeds; fcur; fcur = fcur->next) {
- if(!fcur->name || fcur->name[0] == '\0')
+
+ SLIST_FOREACH(f, &fhead, entry) {
+ if(!f->name || f->name[0] == '\0')
continue;
- if(fcur->totalnew)
+ if(f->totalnew)
fputs("<a class=\"n\" href=\"items.html#", fpmenu);
else
fputs("<a href=\"items.html#", fpmenu);
- printfeednameid(fcur->name, fpmenu);
+ printfeednameid(f->name, fpmenu);
fputs("\" target=\"items\">", fpmenu);
- if(fcur->totalnew > 0)
+ if(f->totalnew > 0)
fputs("<b><u>", fpmenu);
- fputs(fcur->name, fpmenu);
- fprintf(fpmenu, " (%lu)", fcur->totalnew);
- if(fcur->totalnew > 0)
+ fprintf(fpmenu, "%s (%lu)", f->name, f->totalnew);
+ if(f->totalnew > 0)
fputs("</u></b>", fpmenu);
fputs("</a><br/>\n", fpmenu);
}
diff --git a/sfeed_html.c b/sfeed_html.c
index cda896e..4bd1b4b 100644
--- a/sfeed_html.c
+++ b/sfeed_html.c
@@ -5,10 +5,11 @@
#include <string.h>
#include <time.h>
+#include "queue.h"
#include "util.h"
static int showsidebar = 1; /* show sidebar ? */
-static struct feed *feeds = NULL; /* start of feeds linked-list. */
+static SLIST_HEAD(feedshead, feed) fhead = SLIST_HEAD_INITIALIZER(fhead);
static char *line = NULL;
int
@@ -22,36 +23,39 @@ main(void)
size_t size = 0;
int r;
- comparetime = time(NULL) - (3600 * 24); /* 1 day is old news */
- fputs(
- "<!DOCTYPE HTML>\n"
- "<html>\n"
- "\t<head>\n"
- "\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
- "\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n"
- "\t</head>\n"
- "\t<body class=\"noframe\">\n",
- stdout);
+ /* 1 day old is old news */
+ comparetime = time(NULL) - 86400;
+
+ fputs("<!DOCTYPE HTML>\n"
+ "<html>\n"
+ "\t<head>\n"
+ "\t\t<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />\n"
+ "\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\" />\n"
+ "\t</head>\n"
+ "\t<body class=\"noframe\">\n", stdout);
if(!(fcur = calloc(1, sizeof(struct feed))))
err(1, "calloc");
- feeds = fcur;
+ SLIST_INSERT_HEAD(&fhead, fcur, entry);
while(parseline(&line, &size, fields, FieldLast, '\t', stdin) > 0) {
r = strtotime(fields[FieldUnixTimestamp], &parsedtime);
isnew = (r != -1 && parsedtime >= comparetime) ? 1 : 0;
islink = (fields[FieldLink][0] != '\0') ? 1 : 0;
- /* first of feed section or new feed section. */
- if(!totalfeeds || (fcur && strcmp(fcur->name, fields[FieldFeedName]))) {
+ /* first of feed section or new feed section (differs from
+ * previous one). */
+ if(!totalfeeds || strcmp(fcur->name, fields[FieldFeedName])) {
if(!(f = calloc(1, sizeof(struct feed))))
err(1, "calloc");
+ if(!(f->name = strdup(fields[FieldFeedName])))
+ err(1, "strdup");
+
+ SLIST_INSERT_AFTER(fcur, f, entry);
+ fcur = f;
+
if(totalfeeds) { /* end previous one. */
fputs("</table>\n", stdout);
- fcur->next = f;
- fcur = f;
} else {
- fcur = f;
- feeds = fcur; /* first item. */
if(fields[FieldFeedName][0] == '\0' || !showsidebar) {
/* set nosidebar class on div for styling */
fputs("\t\t<div id=\"items\" class=\"nosidebar\">\n", stdout);
@@ -60,10 +64,6 @@ main(void)
fputs("\t\t<div id=\"items\">\n", stdout);
}
}
- /* TODO: memcpy and make fcur->name static? */
- if(!(fcur->name = strdup(fields[FieldFeedName])))
- err(1, "strdup");
-
if(fields[FieldFeedName][0] != '\0') {
fputs("<h2 id=\"", stdout);
printfeednameid(fcur->name, stdout);
@@ -79,6 +79,7 @@ main(void)
totalnew += isnew;
fcur->totalnew += isnew;
fcur->total++;
+
if(isnew)
fputs("<tr class=\"n\">", stdout);
else
@@ -91,9 +92,11 @@ main(void)
if(islink) {
fputs("<a href=\"", stdout);
if(fields[FieldBaseSiteUrl][0] != '\0')
- printlink(fields[FieldLink], fields[FieldBaseSiteUrl], stdout);
+ printlink(fields[FieldLink],
+ fields[FieldBaseSiteUrl], stdout);
else
- printlink(fields[FieldLink], fields[FieldFeedUrl], stdout);
+ printlink(fields[FieldLink],
+ fields[FieldFeedUrl], stdout);
fputs("\">", stdout);
}
printhtmlencoded(fields[FieldTitle], stdout);
@@ -107,31 +110,27 @@ main(void)
fputs("</table>\n\t\t</div>\n", stdout); /* div items */
if(showsidebar) {
fputs("\t<div id=\"sidebar\">\n\t\t<ul>\n", stdout);
- for(fcur = feeds; fcur; fcur = fcur->next) {
- if(!fcur->name || fcur->name[0] == '\0')
+
+ SLIST_FOREACH(f, &fhead, entry) {
+ if(!f->name || f->name[0] == '\0')
continue;
- if(fcur->totalnew)
+ if(f->totalnew > 0)
fputs("<li class=\"n\"><a href=\"#", stdout);
else
fputs("<li><a href=\"#", stdout);
- printfeednameid(fcur->name, stdout);
+ printfeednameid(f->name, stdout);
fputs("\">", stdout);
- if(fcur->totalnew > 0)
+ if(f->totalnew > 0)
fputs("<b><u>", stdout);
- fputs(fcur->name, stdout);
- fprintf(stdout, " (%lu)", fcur->totalnew);
- if(fcur->totalnew > 0)
+ fprintf(stdout, "%s (%lu)", f->name, f->totalnew);
+ if(f->totalnew > 0)
fputs("</u></b>", stdout);
fputs("</a></li>\n", stdout);
}
fputs("\t\t</ul>\n\t</div>\n", stdout);
}
- fputs(
- "\t</body>\n"
- "\t<title>Newsfeed (",
- stdout);
- fprintf(stdout, "%lu", totalnew);
- fputs(")</title>\n</html>", stdout);
+ fprintf(stdout, "\t</body>\n\t<title>Newsfeed (%lu)</title>\n</html>",
+ totalnew);
return 0;
}
diff --git a/sfeed_stats.c b/sfeed_stats.c
index 958f2ed..ecf970d 100644
--- a/sfeed_stats.c
+++ b/sfeed_stats.c
@@ -5,9 +5,10 @@
#include <string.h>
#include <time.h>
+#include "queue.h"
#include "util.h"
-static struct feed *feeds = NULL; /* start of feeds linked-list. */
+static SLIST_HEAD(fhead, feed) fhead = SLIST_HEAD_INITIALIZER(fhead);
static char *line = NULL;
int
@@ -21,26 +22,26 @@ main(void)
size_t size = 0;
int r;
- comparetime = time(NULL) - (3600 * 24); /* 1 day is old news */
+ /* 1 day is old news */
+ comparetime = time(NULL) - 86400;
if(!(fcur = calloc(1, sizeof(struct feed))))
err(1, "calloc");
- feeds = fcur;
+ SLIST_INSERT_HEAD(&fhead, fcur, entry);
while(parseline(&line, &size, fields, FieldLast, '\t', stdin) > 0) {
r = strtotime(fields[FieldUnixTimestamp], &parsedtime);
isnew = (r != -1 && parsedtime >= comparetime) ? 1 : 0;
/* first of feed section or new feed section. */
- if(!totalfeeds || (fcur && strcmp(fcur->name, fields[FieldFeedName]))) {
+ if(!totalfeeds || strcmp(fcur->name, fields[FieldFeedName])) {
if(!(f = calloc(1, sizeof(struct feed))))
err(1, "calloc");
- if(totalfeeds) { /* end previous one. */
- fcur->next = f;
- fcur = f;
- } else {
- fcur = f;
- feeds = fcur; /* first item. */
- }
+ if(!(f->name = strdup(fields[FieldFeedName])))
+ err(1, "strdup");
+
+ SLIST_INSERT_AFTER(fcur, f, entry);
+ fcur = f;
+
if(r != -1 && parsedtime > timenewest) {
timenewest = parsedtime;
strlcpy(timenewestformat, fields[FieldTimeFormatted],
@@ -51,11 +52,6 @@ main(void)
strlcpy(fcur->timenewestformat, fields[FieldTimeFormatted],
sizeof(fcur->timenewestformat));
}
-
- /* TODO: memcpy and make fcur->name static? */
- if(!(fcur->name = strdup(fields[FieldFeedName])))
- err(1, "strdup");
-
totalfeeds++;
}
totalnew += isnew;
@@ -63,14 +59,14 @@ main(void)
fcur->total++;
totalitems++;
}
- for(fcur = feeds; fcur; fcur = fcur->next) {
- if(!fcur->name || fcur->name[0] == '\0')
+ SLIST_FOREACH(f, &fhead, entry) {
+ if(!f->name || f->name[0] == '\0')
continue;
fprintf(stdout, "%c %-20.20s [%4lu/%-4lu]",
- fcur->totalnew > 0 ? 'N' : ' ',
- fcur->name, fcur->totalnew, fcur->total);
- if(fcur->timenewestformat && fcur->timenewestformat[0])
- fprintf(stdout, " %s", fcur->timenewestformat);
+ f->totalnew > 0 ? 'N' : ' ',
+ f->name, f->totalnew, f->total);
+ if(f->timenewestformat && f->timenewestformat[0])
+ fprintf(stdout, " %s", f->timenewestformat);
putchar('\n');
}
printf(" ================================\n");
diff --git a/util.h b/util.h
index a990c8f..3390589 100644
--- a/util.h
+++ b/util.h
@@ -1,9 +1,11 @@
+#include <stdio.h>
+#include <time.h>
+
#ifdef COMPAT
#include "compat.h"
#endif
-#include <stdio.h>
-#include <time.h>
+#include "queue.h"
#define ISUTF8(c) (((c) & 0xc0) != 0x80)
@@ -14,7 +16,7 @@ struct feed {
unsigned long total; /* total items */
time_t timenewest;
char timenewestformat[64];
- struct feed * next; /* linked list */
+ SLIST_ENTRY(feed) entry;
};
enum { FieldUnixTimestamp = 0, FieldTimeFormatted, FieldTitle, FieldLink,