sfeed

Simple RSS and Atom feed parser
git clone https://git.sinitax.com/codemadness/sfeed
Log | Files | Refs | README | LICENSE | Upstream | sfeed.txt

commit 445549c0a2710a3fe50659d6270694d71ecf87d2
parent 7c6893ff05476410b369ee6a967a65e7b3ee754f
Author: Hiltjo Posthuma <hiltjo@codemadness.org>
Date:   Mon,  5 Jan 2015 12:15:14 +0100

add and use BSD queue.h, cleanup

Diffstat:
MMakefile | 1+
Aqueue.h | 648+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msfeed_frames.c | 48+++++++++++++++++++++++++++---------------------
Msfeed_html.c | 75+++++++++++++++++++++++++++++++++++++--------------------------------------
Msfeed_stats.c | 40++++++++++++++++++----------------------
Mutil.h | 8+++++---
6 files changed, 736 insertions(+), 84 deletions(-)

diff --git 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 @@ -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 @@ -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 @@ -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 @@ -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 @@ -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,