summaryrefslogtreecommitdiffstats
path: root/lib/vio_fifo.c
diff options
context:
space:
mode:
authorChris Hall <GMCH@hestia.halldom.com>2010-03-16 01:35:19 +0000
committerChris Hall <GMCH@hestia.halldom.com>2010-03-16 01:35:19 +0000
commitd87a9d74eab06082ea49313083ffa0aa41f666f9 (patch)
tree7c6f7ae0be39683b7c90ea298454ec28d49406cb /lib/vio_fifo.c
parent05fb7fd0421b395c089bb08dd0e0d78d3746b8cf (diff)
downloadquagga-d87a9d74eab06082ea49313083ffa0aa41f666f9.tar.bz2
quagga-d87a9d74eab06082ea49313083ffa0aa41f666f9.tar.xz
Major update
bgpd/bgp_advertise.c bgpd/bgp_advertise.h The adj_in and adj_out objects are now put on a list based on the peer to whom the route belongs. The adj_in and adj_out objects also now point to the bgp_node which they are routes for. This substantially reduces the work needed to shut down a peer. bgpd/bgp_damp.c Changes to adj_in and adj_out forced small change to macros used in bgp_damp.c to manage its lists. bgpd/bgp_debug.c Replaced direct access to vty->node by the required vty_get_node(). bgpd/bgp_dump.c Changes to the names of fields in bgp_info structures. bgpd/bgp_engine.h Modified the debug and trace functions. bgpd/bgp_fsm.c Make use of sockunion2str() consistent with common usage. Improved some documentation. bgpd/bgp_main.c Use the newly extended qpn_add_hook_function() facility. bgpd/bgp_mplsvpn.c Changes to the names of fields in bgp_info structures. bgpd/bgp_msg_read.c Bug fix: correct handling of capability code length. Improvement: better casting in calculation of message length. bgpd/bgp_msg_write.c Bug fix: correct byte ordering of bgp_id in open message. bgpd/bgp_network.c Bug fix: correct handling of incoming connections. Takes advantage of improvements in sockunion.c. bgpd/bgp_nexthop.c Changes to the names of fields in bgp_info structures. bgpd/bgp_open_state.c Remove mistaken #include of memtypes.h bgpd/bgp_packet.c Improvements to handling of withdrawing routes for peers. bgpd/bgp_peer.c Tidying up the state of peers as they are enabled and disabled. Improvements to handling of withdrawing routes for peers. bgpd/bgp_peer.h Adding list bases for lists of routes originated by the peer. bgpd/bgp_peer_index.c Bug fix: correct freeing of peer indexes. bgpd/bgp_route.c Implement lists of bgp_info based in the owning peer. Adjust for name changes to bgp_info fields. Reimplemented all the clearing functions to use the lists of items that belong to the peer -- rather than searching route tables for stuff to withdraw. Changed work queue handling for added/changed routes, so that queues run through existing items, rather than having queues of auxiliary items -- lower memory overhead. bgpd/bgp_route.h Added fields to bgp_info to allow all bgp_info originated by each peer to live on lists based in the peer. And changed the name of existing fields to avoid confusion. bgpd/bgp_routemap.c Removing redundant code and fixing a memory leak. bgpd/bgp_table.h Based work queue for added/changed routes directly in the table, rather than having auxiliary structures. bgpd/bgp_vty.c Use vty_get_node() and vty_set_node() rather than direct access to the vty field. bgpd/bgpd.c Implement changes to route clearing. bgpd/bgpd.h Changes to work queue handling. lib/buffer.c Changes to allow embedded buffer structures. lib/buffer.h Moved struct buffer here so that could have embedded buffer structurs. lib/command.c Substantial tidy up and document exercise. Restructured the top level command processing and finding of descriptions and command completion. Removal of unpleasant messing around with the insides of vector structures. Movement of some command actions to vty.c. Uses uty.h to pick up the "private" functions from vty.c et al. lib/command.h Moved the "node" values to node_type.h, so that can use an enum node_type in places where cannot include command.h. lib/command_queue.c Updated to cope with the called command changing the node value. Improved handling of revoked commands, so the the command line handler does not get stuck waiting for a command to complete which has been revoked ! lib/command_queue.h Improved message format. lib/if.c Use vty_set_node(). lib/keychain.c Use vty_set_node(). new lib/keystroke.c new lib/keystroke.h New code to implement a keystroke FIFO. This moves some complexity out of the command handler. The handling of mixtures of escapes and Telnet IACs is tightened up. It would be possible to extend this to, say, UTF-8. Regularises the "stealing" of keystrokes for the "--more--" output handling... which was a bit hit and miss. new lib/list_util.c new lib/list_util.h New code to implement various forms of linked list, where the list pointers are embedded in structures. lib/log.c Changed the handling of log messages, so that all types of log output (except syslog) use the same message buffer scheme, and the message is constructed once and once only. Changes to the handling of VTY_LOCK() etc. Uses uty.h to pick up the "private" functions from vty.c et al. lib/log.h Changes to the buffering of log messages. new lib/mem_tracker.c New code to track memory allocation/deallocation, for debug purposes. lib/memory.c lib/memory.h Updated to allow the use of the mem_tracker. lib/memtypes.awk Made the memtypes into a named enum MTYPE. lib/memtypes.c Various new memory types. lib/mqueue.c lib/mqueue.h Add mqueue_finish function for close-down. lib/network.c lib/network.h Added non-blocking read_nb() and write_nb(). new lib/node_type.h As above. lib/plist.c Remove vty_puts() which wasn't a good idea. lib/qlib_init.c Added qps_init() to first stage and mqueue_finish to finish. lib/qpnexus.c lib/qpnexus.h More flexible hooks for in_thread_init and in_thread_final. lib/qpselect.c lib/qpselect.h Added qps_start_up() to build the required maps once and for all. Added qdebug to control the debug checks and validation. Improved validation and test functions. new lib/qstring.c new lib/qstring.h New code for limited flexible string handling. lib/qtimers.c Added qdebug to control the debug checks and validation. lib/routemap.c Use vty_set_node(). lib/sockunion.c lib/sockunion.h Tidied up and regularised the handling of sin_len and sin6_len. Created common function for setting port into socket. Created common function for initialisation/allocation of new sockunion. Reduced various functions by using common sub-functions. Rationalised some code. Added sockunion_listen() and sockunion_new_sockaddr(). Renamed sockunion_new() to sockunion_new_prefix(). Improved some logging messages. Added documentation. new lib/uty.h Functions etc. used only by vty/command/log/vty_io and vty_cli. lib/vector.c lib/vector.h Added vector_t type. Removed VECTOR_INDEX, vector_only_wrapper_free() and vector_only_index_free() -- following improvement of code in command.c. Added vector_set_min_length(), vector_set_new_min_length() and vector_length() functions. new lib/vio_fifo.c new lib/vio_fifo.h New code to manage simple FIFO of indefinite length. lib/vty.c lib/vty.h Reworked. Broken into vty.c, vty_io.c and vty_cli.c. new lib/vty_cli.c new lib/vty_cli.h CLI handling parts of the vty family. new lib/vty_io.c new lib/vty_io.h I/O parts of the vty family. lib/workqueue.h Introduced tyedefs for the various call-back entries. new tests/test-list_util.c Tests for the list-util stuff. vtysh/vtysh.c Small change to interface for cmd_execute_command()
Diffstat (limited to 'lib/vio_fifo.c')
-rw-r--r--lib/vio_fifo.c572
1 files changed, 572 insertions, 0 deletions
diff --git a/lib/vio_fifo.c b/lib/vio_fifo.c
new file mode 100644
index 00000000..fb62f192
--- /dev/null
+++ b/lib/vio_fifo.c
@@ -0,0 +1,572 @@
+/* VTY I/O FIFO
+ * Copyright (C) 2010 Chris Hall (GMCH), Highwayman
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2, or (at your
+ * option) any later version.
+ *
+ * GNU Zebra 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 GNU Zebra; see the file COPYING. If not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stddef.h>
+#include <string.h>
+
+#include "vio_fifo.h"
+#include "list_util.h"
+
+#include "memory.h"
+#include "zassert.h"
+
+/*==============================================================================
+ * VTY I/O FIFO manages an arbitrary length byte-wise FIFO buffer.
+ *
+ * The FIFO is arranged as lumps of some given size. Lumps are allocated
+ * as and when necessary, and released once emptied.
+ *
+ * The last lump is never released. So, it may be that only one lump is
+ * ever needed.
+ *
+ *------------------------------------------------------------------------------
+ * Implementation notes:
+ *
+ * The FIFO is initialised with all pointers NULL -- so with no lumps at all.
+ *
+ * Once a lump has been allocated there is always one lump in the FIFO.
+ *
+ * The following are expected to be true:
+ *
+ * * put_ptr == get_ptr => FIFO empty
+ *
+ * * put_ptr == tail->end -- at all times (NULL when no lumps)
+ *
+ * put_ptr >= tail->data ) otherwise something is broken
+ * put_ptr <= tail->end )
+ *
+ * * get_ptr == head->end -- when there is more than one lump
+ * get_ptr <= put_ptr -- when there is only one lump
+ *
+ * get_ptr >= head->data ) otherwise something is broken
+ * get_ptr <= head->end )
+ *
+ * * put_ptr == put_end => tail lump is full
+ * put_ptr < put_end => space exists in the tail lump
+ * put_ptr > put_end => broken
+ *
+ * * get_ptr == get_end => head lump is empty
+ * BUT if there is only one lump, make sure that
+ * get_end == put_ptr.
+ * get_ptr < get_end => data exists in the head lump
+ * get_ptr > get_end => broken
+ *
+ * Note that:
+ *
+ * * when the get_ptr reaches the put_ptr the pointers are reset to the
+ * start of the one and only lump.
+ *
+ * Everywhere that the get_ptr is moved, must check for meeting the
+ * put_ptr and reset pointers. At the same time, when reaches the end of
+ * a lump, gets rid of it.
+ *
+ * * when advancing the put_ptr does not check for advancing the get_end.
+ *
+ * The one exception to this, is that when the put_ptr advances to a new
+ * block, if there was one lump, sets the get_end to the end of that block.
+ *
+ * Everywhere that the get_end is used, must check for there being one
+ * lump and the possibility that put_ptr has changed.
+ */
+
+/*==============================================================================
+ * Initialisation, allocation and freeing of FIFO and lumps thereof.
+ */
+
+/* Return default size, or given size rounded up to 16 byte boundary */
+static size_t
+vio_fifo_size(size_t size)
+{
+ if (size == 0)
+ return 4096 ;
+ else
+ return ((size + 16 - 1) / 16) * 16 ;
+} ;
+
+/*==============================================================================
+ * Initialise VTY I/O FIFO -- allocating if required.
+ */
+extern vio_fifo
+vio_fifo_init_new(vio_fifo vf, size_t size)
+{
+ if (vf == NULL)
+ vf = XCALLOC(MTYPE_VIO_FIFO, sizeof(vio_fifo_t)) ;
+ else
+ memset(vf, 0, sizeof(vio_fifo_t)) ;
+
+ /* Zeroising the the vio_fifo_t has set:
+ *
+ * lump -- base pair, both pointers NULL => list is empty
+ *
+ * put_ptr -- NULL ) no lump to put anything into
+ * put_end -- NULL ) put_ptr == put_end => no room in current lump
+ *
+ * get_ptr -- NULL ) no lump to get anything from
+ * get_end -- NULL ) get_ptr -- get_end => nothing left in current lump
+ *
+ * ALSO put_ptr == get_ptr => FIFO is empty !
+ */
+
+ vf->size = vio_fifo_size(size) ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ return vf ;
+}
+
+/*------------------------------------------------------------------------------
+ * Free contents of given FIFO, and free FIFO structure as well, if required.
+ *
+ * Does nothing if given a NULL pointer -- must already have been freed !
+ *
+ * If does not free the FIFO structure, resets it all empty.
+ *
+ * See also: vio_fifo_reset_keep(vio_fifo)
+ * vio_fifo_reset_free(vio_fifo)
+ */
+extern vio_fifo
+vio_fifo_reset(vio_fifo vf, int free_structure)
+{
+ vio_fifo_lump lump ;
+
+ if (vf == NULL)
+ return NULL ;
+
+ while (ddl_pop(&lump, vf->base, list) != NULL)
+ XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
+
+ if (free_structure)
+ XFREE(MTYPE_VIO_FIFO, vf) ; /* sets vf = NULL */
+ else
+ vio_fifo_init_new(vf, vf->size) ;
+
+ return vf ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Set FIFO empty, discarding current contents -- will continue to use the FIFO.
+ */
+extern void
+vio_fifo_set_empty(vio_fifo vf)
+{
+ vio_fifo_lump lump ;
+
+ assert(vf != NULL) ;
+
+ while (ddl_head(vf->base) != ddl_tail(vf->base))
+ {
+ ddl_pop(&lump, vf->base, list) ;
+ XFREE(MTYPE_VIO_FIFO_LUMP, lump) ;
+ } ;
+
+ lump = ddl_head(vf->base) ;
+ if (lump != NULL)
+ {
+ vf->get_ptr = vf->get_end = vf->put_ptr = lump->data ;
+ vf->put_end = lump->end ;
+ } ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Allocate another lump for putting into.
+ *
+ * Call when (vf->put_ptr >= vf->put_end) -- asserts that the pointers are equal.
+ *
+ * Set the put_ptr/put_end pointers to point at the new lump.
+ *
+ * If this is the first lump allocated, set the get_ptr/get_end pointers too.
+ *
+ * If have just filled the first lump on the list, update the get_end pointer
+ * to reflect the fact that the out lump is now full.
+ */
+extern void
+vio_fifo_lump_new(vio_fifo vf)
+{
+ vio_fifo_lump lump ;
+ size_t size ;
+ int first_alloc ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ passert(vf->put_ptr == vf->put_end) ; /* must be end of tail lump */
+
+ lump = ddl_tail(vf->base) ;
+
+ /* When there is only one lump, the get_end tracks the put_ptr.
+ * But when there is more than one lump, it must be the end of that lump.
+ */
+ if (vf->one)
+ vf->get_end = lump->end ;
+
+ first_alloc = (lump == NULL) ; /* extra initialisation needed */
+
+ if (first_alloc)
+ assert(vf->put_ptr == NULL) ; /* must all be NULL together */
+ else
+ assert(vf->put_ptr == lump->end) ; /* must be end of tail lump */
+
+ size = vio_fifo_size(vf->size) ;
+ lump = XMALLOC(MTYPE_VIO_FIFO_LUMP, offsetof(vio_fifo_lump_t, data[size])) ;
+ lump->end = (char*)lump->data + vf->size ;
+
+ ddl_append(vf->base, lump, list) ;
+
+ vf->one = first_alloc ;
+
+ vf->put_ptr = lump->data ;
+ vf->put_end = lump->end ;
+
+ if (first_alloc)
+ {
+ vf->get_ptr = vf->put_ptr ; /* get_ptr == put_ptr => empty */
+ vf->get_end = vf->put_ptr ;
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+} ;
+
+/*==============================================================================
+ * Put data to the FIFO.
+ */
+
+/*------------------------------------------------------------------------------
+ * Store 'n' bytes -- allocate new lump if current is exhausted.
+ */
+extern void
+vio_fifo_put(vio_fifo vf, const char* src, size_t n)
+{
+ size_t take ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ while (n > 0)
+ {
+ if (vf->put_ptr >= vf->put_end)
+ vio_fifo_lump_new(vf) ; /* traps broken vf->put_ptr > vf->put_end */
+
+ take = (vf->put_end - vf->put_ptr) ;
+ if (take > n)
+ take = n ;
+
+ memcpy(vf->put_ptr, src, take) ;
+ vf->put_ptr += take ;
+
+ src += take ;
+ n -= take ;
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+} ;
+
+/*==============================================================================
+ * Get data from the FIFO.
+ */
+
+static bool vio_fifo_get_next_lump(vio_fifo vf) ;
+
+/*------------------------------------------------------------------------------
+ * Get ready to read something out of the FIFO.
+ *
+ * Makes sure vf->get_end is up to date (if required) and if the FIFO is not
+ * empty, makes sure vf->get_ptr points at the next byte to be read.
+ *
+ * Returns: true <=> there is something in the FIFO.
+ */
+static inline bool
+vio_fifo_get_ready(vio_fifo vf)
+{
+ if (vf->one)
+ vf->get_end = vf->put_ptr ; /* make sure have everything */
+
+ if (vf->get_ptr >= vf->get_end)
+ if (!vio_fifo_get_next_lump(vf))
+ return 0 ; /* quit now if nothing there */
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ return 1 ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get upto 'n' bytes.
+ *
+ * Returns: number of bytes got -- may be zero.
+ */
+extern size_t
+vio_fifo_get(vio_fifo vf, void* dst, size_t n)
+{
+ size_t have ;
+ void* dst_in ;
+
+ if (!vio_fifo_get_ready(vf))
+ return 0 ; /* quit now if nothing there */
+
+ dst_in = dst ;
+ while (n > 0)
+ {
+ have = vf->get_end - vf->get_ptr ;
+
+ if (have > n)
+ have = n ;
+
+ memcpy(dst, vf->get_ptr, have) ;
+ vf->get_ptr += have ;
+ dst = (char*)dst + have ;
+
+ if (vf->get_ptr >= vf->get_end) /* deal with exhausted lump */
+ if (!vio_fifo_get_next_lump(vf))
+ break ; /* quit if nothing more to come */
+
+ n -= have ;
+ } ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ return (char*)dst - (char*)dst_in ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get byte -- the long winded way.
+ *
+ * See the inline vio_fifo_get_byte().
+ *
+ * The version is used when the get_ptr is at or just before the end of the
+ * current lump. Looks after all the necessary pointer updates associated with
+ * hitting end of lump, or hitting end of FIFO.
+ *
+ * Returns: 0x00..0xFF -- byte value (as an int)
+ * -1 => FIFO is empty.
+ */
+
+extern int
+vio_fifo_get_next_byte(vio_fifo vf)
+{
+ unsigned char u ;
+
+ if (!vio_fifo_get_ready(vf))
+ return -1 ; /* quit now if nothing there */
+
+ u = *vf->get_ptr++ ;
+
+ /* As soon as reach the end want either to discard empty lump, or reset
+ * the pointers.
+ */
+ if (vf->get_ptr >= vf->get_end) /* deal with exhausted lump */
+ vio_fifo_get_next_lump(vf) ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ return u ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Get pointer to a lump of bytes.
+ *
+ * Returns: address of next byte to get, *have = number of bytes available
+ * or: NULL => FIFO is empty, *have = 0
+ *
+ * If the FIFO is not empty, will return pointer to at least one byte.
+ *
+ * Returns number of bytes to the end of the current lump. There may be
+ * further lumps beyond the current one.
+ */
+extern void*
+vio_fifo_get_lump(vio_fifo vf, size_t* have)
+{
+ if (!vio_fifo_get_ready(vf))
+ {
+ *have = 0 ;
+ return NULL ;
+ } ;
+
+ *have = (vf->get_end - vf->get_ptr) ;
+ return vf->get_ptr ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Advance FIFO to position reached.
+ *
+ * Having done vio_fifo_get_lump(), can take any number of bytes (up to the
+ * number that "have"), then call this function to advance the pointers.
+ *
+ * The "here" argument must the the address returned by vio_fifo_get_lump()
+ * plus the number of bytes taken.
+ */
+extern void
+vio_fifo_got_upto(vio_fifo vf, void* here)
+{
+ vf->get_ptr = here ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ if (vf->get_ptr >= vf->get_end)
+ vio_fifo_get_next_lump(vf) ;
+} ;
+
+/*------------------------------------------------------------------------------
+ * Move on to next lump to get stuff from.
+ *
+ * Advance pointers etc. so that have at least one byte available, unless
+ * the FIFO is entirely empty.
+ *
+ * This should be called if (vf->get_ptr >= vf->get_end) -- asserts that
+ * these are equal !
+ *
+ * NB: when there is only one block, it may be that get_end is out of date,
+ * and should be advanced to the current put_ptr position.
+ *
+ * That is done here, but may be worth updating get_end before testing
+ * against get_ptr.
+ *
+ * Returns: true <=> at least one byte in FIFO.
+ *
+ * NB: if finds that the FIFO is empty, resets the pointers to the start
+ * of the last lump.
+ */
+static bool
+vio_fifo_get_next_lump(vio_fifo vf)
+{
+ vio_fifo_lump head ;
+ vio_fifo_lump tail ;
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+ assert(vf->get_ptr == vf->get_end) ;
+
+ head = ddl_head(vf->base) ; /* current lump for put */
+ tail = ddl_tail(vf->base) ; /* current lump for get */
+
+ /* Deal with case of one lump only */
+ if (vf->one)
+ {
+ assert( (head != NULL)
+ && (head == tail) ) ;
+
+ if (vf->get_ptr == vf->put_ptr)
+ {
+ /* FIFO is empty -- reset pointers and exit */
+ vf->get_ptr = vf->get_end = vf->put_ptr = head->data ;
+ assert(vf->put_end == head->end) ;
+
+ return 0 ; /* FIFO empty */
+ } ;
+
+ /* Had an out of date vf->get_end */
+ assert(vf->get_end < vf->put_ptr) ;
+ vf->get_end = vf->put_ptr ;
+
+ return 1 ; /* FIFO not empty after all */
+ } ;
+
+ /* Deal with case of not yet allocated */
+ if (head == NULL)
+ {
+ assert( (tail == NULL)
+ && (vf->put_ptr == vf->get_ptr) );
+
+ return 0 ; /* FIFO empty */
+ } ;
+
+ /* Deal with (remaining) case of two or more lumps */
+ assert(vf->get_ptr == head->end) ;
+
+ ddl_del_head(vf->base, list) ;
+ XFREE(MTYPE_VIO_FIFO_LUMP, head) ;
+
+ head = ddl_head(vf->base) ;
+ assert(head != NULL) ;
+
+ vf->one = (head == tail) ;
+
+ vf->get_ptr = head->data ; /* at start of next lump */
+
+ if (vf->one)
+ vf->get_end = vf->put_ptr ; /* up to current put */
+ else
+ vf->get_end = head->end ; /* up to end of lump */
+
+ VIO_FIFO_DEBUG_VERIFY(vf) ;
+
+ return (vf->get_ptr < vf->get_end) ;
+} ;
+
+/*==============================================================================
+ * For debug purposes -- verify the state of the given FIFO
+ */
+Private void
+vio_fifo_verify(vio_fifo vf)
+{
+ vio_fifo_lump head ;
+ vio_fifo_lump tail ;
+
+ head = ddl_head(vf->base) ;
+ tail = ddl_tail(vf->base) ;
+
+ /* If nothing allocated, should all be NULL & !vf->one */
+ /* If something allocated, tail must not be NULL */
+ if (head == NULL)
+ {
+ if ( (tail != NULL)
+ || (vf->put_ptr != NULL)
+ || (vf->put_end != NULL)
+ || (vf->get_ptr != NULL)
+ || (vf->get_end != NULL)
+ || (vf->one) )
+ zabort("nothing allocated, but not all NULL") ;
+ return ;
+ }
+ else
+ {
+ if (tail == NULL)
+ zabort("head pointer not NULL, but tail pointer is") ;
+ } ;
+
+ /* Check that all the pointers are within respective lumps
+ *
+ * Know that put_end is always tail->end, but get_end need not be.
+ * */
+ if ( (tail->data > vf->put_ptr)
+ || (vf->put_ptr > vf->put_end)
+ || (vf->put_end != tail->end) )
+ zabort("put pointers outside the tail lump") ;
+
+ if ( (head->data > vf->get_ptr)
+ || (vf->get_ptr > vf->get_end)
+ || (vf->get_end > head->end) )
+ zabort("get pointers outside the head lump") ;
+
+ /* If head == tail, should be vf->one, etc. */
+ if (head == tail)
+ {
+ if (!vf->one)
+ zabort("have one lump, but !vf->one") ;
+
+ if (vf->get_end > vf->put_ptr)
+ zabort("get_end is greater than put_ptr when vf->one") ;
+ }
+ else
+ {
+ if (vf->one)
+ zabort("have two or more lumps, but vf->one is true") ;
+
+ if (vf->get_end != head->end)
+ zabort("get_end is not head->end when !vf->one") ;
+ }
+} ;