Index: ossp-pkg/sio/al.c
RCS File: /v/ossp/cvs/ossp-pkg/sio/Attic/al.c,v
co -q -kk -p'1.40' '/v/ossp/cvs/ossp-pkg/sio/Attic/al.c,v' | diff -u - /dev/null -L'ossp-pkg/sio/al.c' 2>/dev/null
--- ossp-pkg/sio/al.c
+++ /dev/null 2025-04-09 16:01:24.000000000 +0200
@@ -1,1317 +0,0 @@
-/*
-** OSSP al -- Assembly Line
-** Copyright (c) 2002 The OSSP Project
-** Copyright (c) 2002 Cable & Wireless Deutschland
-** Copyright (c) 2002 Ralf S. Engelschall
-** Copyright (c) 2002 Michael van Elst
-**
-** This file is part of OSSP al, an abstract datatype of a data buffer
-** that can assemble, move and truncate data but avoids actual copying.
-**
-** Permission to use, copy, modify, and distribute this software for
-** any purpose with or without fee is hereby granted, provided that
-** the above copyright notice and this permission notice appear in all
-** copies.
-**
-** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
-** 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.
-**
-** al.c: assembly line library implementation
-*/
-
-#include
-#include
-#include
-#ifdef TEST
-#include
-#endif
-
-#include "list.h"
-
-#include "al.h"
-
-/* unique library identifier */
-const char al_id[] = "OSSP al";
-
-/* support for OSSP ex based exception throwing */
-#ifdef WITH_EX
-#include "ex.h"
-#define AL_RC(rv) \
- ( (rv) != AL_OK && (ex_catching && !ex_shielding) \
- ? (ex_throw(al_id, NULL, (rv)), (rv)) : (rv) )
-#else
-#define AL_RC(rv) (rv)
-#endif /* WITH_EX */
-
-struct al_buffer_st;
-typedef struct al_buffer_st al_buffer_t;
-
-typedef struct {
- void *(*malloc)(size_t); /* malloc(3) style function (for al_chunk_t) */
- void (*free)(void *); /* free(3) style function (for al_chunk_t) */
- void *(*balloc)(size_t); /* malloc(3) style function (for al_buffer_t) */
- void (*bfree)(void *); /* free(3) style function (for al_buffer_t) */
- size_t new_buffersize; /* default size for memory underlying al_buffer_t */
- int max_freechunks; /* maximum number of cached al_chunk_t objects */
-} al_memops_t;
-
-struct al_st {
- LIST(al_chunk_t) chunks; /* list header for al_chunk_t objects */
- size_t bytes; /* total cached number of bytes in chunk */
- al_memops_t m; /* assembly line memory operations (see above) */
-};
-
-struct al_chunk_st {
- NODE(al_chunk_t) chunks; /* list node for al_chunk_t object chaining */
- al_buffer_t *buf; /* (non-exlusively) referenced buffer object */
- size_t begin; /* offset into buf->mem where data starts */
- size_t end; /* offset into buf->mem where data ends */
- al_label_t label; /* tag data with a label, chunks with distinct labels are not coalesced */
-};
-
-struct al_buffer_st {
- char *mem; /* reference to underlying chunk of data */
- size_t size; /* size of underlying chunk of data */
- int usecount; /* reference count (from al_chunk_t) */
- void (*freemem)(char *p, size_t n, void *u); /* callback function to reclaim memory when it is no longer referenced */
- void *userdata; /* arbitrary pointer to pass context data to the callback function */
-};
-
-struct al_tx_st {
- al_td_t dir; /* traversal direction */
- al_chunk_t *cur; /* current chunk during traveral steps */
- size_t skip; /* number of bytes to skip for traversal */
- size_t togo; /* number of bytes left for traversal */
- al_label_t label; /* label filter or NULL */
- al_chunk_t view; /* synthetic chunk for returning during traversal steps */
-};
-
-/* number of bytes described by a chunk */
-#define AL_CHUNK_LEN(alc) \
- ((alc)->end - (alc)->begin)
-
-/* memory pointer into a chunk, offset must be less than length */
-#define AL_CHUNK_PTR(alc, off) \
- ((alc)->buf->mem + (alc)->begin + (off))
-
-/* number of bytes of a span that are stored in a chunk */
-#define AL_CHUNK_SPAN(alc, off, n) \
- ((n) > (AL_CHUNK_LEN(alc) - (off)) ? \
- (AL_CHUNK_LEN(alc) - (off)) : (n))
-
-/* return chunk label */
-#define AL_CHUNK_LABEL(alc) \
- ((alc)->label)
-
-/* check wether labels match */
-#define AL_SAME_LABEL(alc,label) \
- ((label) == NULL || AL_CHUNK_LABEL(alc) == (label))
-
-/*
- * number of bytes a chunk can be grown to the end
- * we must not grow a chunk in a shared buffer since
- * we do not track other chunks sharing the buffer
- */
-#define AL_CHUNK_RESERVE(alc,label) \
- ( (alc) != NULL \
- ? ( (alc)->buf->usecount > 1 || !AL_SAME_LABEL(alc,label) \
- ? 0 \
- : (alc)->buf->size - (alc)->end) \
- : 0)
-
-/* grow chunk to the end */
-#define AL_RESIZE(al, alc, n) \
- do { (alc)->end += n; (al)->bytes += (n); } while (0)
-
-/*
- * number of bytes a chunk can be grown to the beginning
- * we must not grow a chunk in a shared buffer since
- * we do not track other chunks sharing the buffer
- *
- * empty chunks can be aligned with end
- */
-#define AL_CHUNK_PRESERVE(alc,label) \
- ( (alc) != NULL \
- ? ( (alc)->buf->usecount > 1 || !AL_SAME_LABEL(alc,label) \
- ? 0 \
- : (alc)->end <= (alc)->begin ? \
- (alc)->buf->size \
- : (alc)->begin) \
- : 0)
-
-/*
- * grow chunk to the beginning
- *
- * empty chunks can be aligned with end
- */
-#define AL_PRESIZE(al, alc, n) \
- do { \
- if ((alc)->end <= (alc)->begin) \
- (alc)->end = (alc)->begin = (alc)->buf->size; \
- (alc)->begin -= n; (al)->bytes += (n); \
- } while (0)
-
-/*
- * callback to release buffer memory allocated by the library
- */
-static
-void freemem(char *p, size_t n, void *u)
-{
- void (*f)(void *) = (void (*)(void *))u;
- f(p);
-}
-
-/*
- * allocate backing store and its control structure from heap
- *
- * can be freed when usecount drops to zero
- */
-static al_rc_t
-new_buffer(al_t *al, al_buffer_t **bufp)
-{
- size_t n = al->m.new_buffersize;
- al_buffer_t *buf;
-
- if ((buf = (al_buffer_t *)(al->m.malloc)(sizeof(al_buffer_t))) == NULL)
- return AL_ERR_MEM;
-
- if ((buf->mem = (al->m.balloc)(n)) == NULL) {
- (al->m.free)(buf);
- return AL_ERR_MEM;
- }
-
- buf->freemem = freemem;
- buf->userdata = (void *)al->m.bfree;
- buf->size = n;
- buf->usecount = 0;
-
- *bufp = buf;
- return AL_OK;
-}
-
-static al_rc_t
-dispose_buffer(al_t *al, al_buffer_t *buf)
-{
- /* must not happen */
- if (buf->usecount != 0)
- return AL_ERR_INT;
-
- if (buf->freemem)
- (buf->freemem)(buf->mem, buf->size, buf->userdata);
-
- (al->m.free)(buf);
- return AL_OK;
-}
-
-/*
- * allocate only control structure for backing store from heap
- * and attach to existing memory
- * only the control structure will be freed later
- */
-static
-al_rc_t make_buffer(al_t *al, char *p, size_t n, void (*freemem_cb)(char *, size_t, void *), void *u, al_buffer_t **bufp)
-{
- al_buffer_t *buf;
-
- if ((buf = (al_buffer_t *)(al->m.malloc)(sizeof(al_buffer_t))) == NULL)
- return AL_ERR_MEM;
-
- buf->mem = p;
-
- buf->freemem = freemem_cb;
- buf->userdata = u;
- buf->size = n;
- buf->usecount = 0;
-
- *bufp = buf;
- return AL_OK;
-}
-
-/*
- * allocate chunks from heap and attach to backing store
- * keep some freed chunks in a freelist to avoid expensive malloc()
- * and excessive fragmentation
- * maintain usage count of backing store
- * free backing store when no longer in use, this also includes
- * the case where new_chunk fails and the buffer has no other
- * users
- */
-static struct {
- LIST(al_chunk_t) chunks;
-} alc_freelist;
-static int alc_freecount = 0;
-
-static al_rc_t
-new_chunk(al_t *al, al_buffer_t *buf, al_label_t label, al_chunk_t **alcp)
-{
- al_chunk_t *alc;
-
- if (ISEMPTY(&alc_freelist, chunks)) {
- if ((alc = (al_chunk_t *)(al->m.malloc)(sizeof(al_chunk_t))) == NULL) {
- if (buf->usecount == 0)
- dispose_buffer(al,buf);
- return AL_ERR_MEM;
- }
- } else {
- /* thl: FIXME i would suggest using REMTAIL() here because dispose_chunk
- * puts the latest disposed chunks at the end of the list and
- * those latest data should have a closer approximation to the
- * CPU in terms of internal cache, external cache, RAM and VM
- */
- REMHEAD(&alc_freelist, chunks, alc);
- --alc_freecount;
- }
-
- NODEINIT(alc, chunks);
- alc->buf = buf;
- alc->begin = 0;
- alc->end = 0;
- alc->label = label;
-
- buf->usecount++;
-
- *alcp = alc;
- return AL_OK;
-}
-
-static al_rc_t
-split_chunk(al_t *al, al_chunk_t *orig, size_t off, al_chunk_t **alcp)
-{
- al_rc_t rc;
- al_chunk_t *alc;
- size_t len = AL_CHUNK_LEN(orig);
-
- if (off > len)
- return AL_ERR_ARG;
-
- rc = new_chunk(al, orig->buf, orig->label, &alc);
- if (rc != AL_OK)
- return rc;
-
- alc->begin = orig->begin;
- alc->end = orig->begin+off;
- orig->begin = alc->end;
-
- *alcp = alc;
- return AL_OK;
-}
-
-static void
-dispose_chunk(al_t *al, al_chunk_t *alc)
-{
- alc->buf->usecount--;
- if (alc->buf->usecount == 0)
- dispose_buffer(al,alc->buf);
- alc->buf = NULL;
- alc->label = NULL;
-
- /* stop freelist from growing infinitely */
- if (alc_freecount >= al->m.max_freechunks)
- (al->m.free)(alc);
- else {
- ADDTAIL(&alc_freelist, chunks, alc);
- alc_freecount++;
- }
-}
-
-/*
- * find chunk that represents a particular offset
- * a reference to the chunk is stored in *alcp
- * the relative offset into the chunk is stored in *skipp
- * return AL_OK and *alcp == NULL if positioned exactly to end of list
- * return AL_ERR_EOF when no such chunk can be found
- */
-static al_rc_t
-al_seek(al_t *al, size_t off, al_chunk_t **alcp, size_t *skipp)
-{
- al_chunk_t *cur;
- size_t pos, end;
- size_t chunksize;
-
- if ((al->bytes / 2) >= off) { /* FIXME poor man's heuristic */
- /* forward search */
- pos = 0;
- FOREACH(al,chunks,cur) {
- chunksize = AL_CHUNK_LEN(cur);
- end = pos+chunksize;
- if (pos <= off && off < end) {
- *alcp = cur;
- *skipp = off - pos;
- return AL_OK;
- }
- if (end > off)
- break;
- pos = end;
- }
- /* seek to EOF position is ok */
- if (pos == off) {
- *alcp = NULL;
- *skipp = 0;
- return AL_OK;
- }
- } else {
- /* reverse search */
- pos = al->bytes;
- /* seek to EOF position is ok */
- if (pos == off) {
- *alcp = NULL;
- *skipp = 0;
- return AL_OK;
- }
- FOREACHR(al,chunks,cur) {
- chunksize = AL_CHUNK_LEN(cur);
- end = pos;
- pos -= chunksize;
- if (pos <= off && off < end) {
- *alcp = cur;
- *skipp = off - pos;
- return AL_OK;
- }
- if (pos < off)
- break;
- }
- }
-
- return AL_ERR_EOF;
-}
-
-#ifdef TEST
-static void
-dump(al_t *al)
-{
- al_chunk_t *cur;
- size_t total;
-
- printf("AL: %p\n", al);
- total = 0;
- FOREACH(al,chunks,cur) {
- printf(" C: %p [%p] (%d @ %p + %d < %d (use=%d))\n",
- cur,
- cur->label,
- cur->buf->size,cur->buf->mem,
- cur->begin,cur->end,
- cur->buf->usecount);
- total += AL_CHUNK_LEN(cur);
- }
- printf("size = %d == %d\n",al->bytes,total);
- printf("--\n\n");
-}
-#endif
-
-/****************************************************************************/
-
-/*
- * allocate an empty assembly line
- * dispose all chunks and all allocated backing store
- */
-al_rc_t
-al_create(al_t **alp)
-{
- al_t *al;
-
- /* argument sanity check(s) */
- if (alp == NULL)
- return AL_RC(AL_ERR_ARG);
-
- /* allocate and initialize new assembly line object */
- /* XXX - what malloc ? */
- if ((al = (al_t *)malloc(sizeof(al_t))) == NULL)
- return AL_RC(AL_ERR_MEM);
-
- LISTINIT(al,chunks);
- al->bytes = 0;
-
- /* memory policy */
- al->m.malloc = malloc; /* structure allocation */
- al->m.free = free;
- al->m.balloc = malloc; /* buffer allocation */
- al->m.bfree = free;
-#ifdef TEST
- al->m.new_buffersize = 42;
-#else
- al->m.new_buffersize = 4096;
-#endif
- al->m.max_freechunks = 500;
-
- /* pass object to caller */
- *alp = al;
-
- return AL_OK;
-}
-
-al_rc_t
-al_destroy(al_t *al)
-{
- al_chunk_t *cur, *pred;
-
- /* argument sanity check(s) */
- if (al == NULL)
- return AL_RC(AL_ERR_ARG);
-
- /* free chunks and backing store */
- FOREACHD(al,chunks,cur,pred) {
- REMOVE(al,chunks,cur);
- dispose_chunk(al,cur);
- }
-
- /* free object itself */
- /* XXX - which free() ? */
- free(al);
-
- return AL_OK;
-}
-
-/*
- * copy bytes into buffer, FIFO
- *
- * stops copy operation when a new buffer cannot be created
- * but leaves data structure consistent
- */
-al_rc_t
-al_append_bytes(al_t *al, const char *src, size_t n, al_label_t label)
-{
- al_rc_t rc;
- al_chunk_t *cur;
- al_buffer_t *buf;
- size_t res, step;
- char *dst;
-
- /* argument sanity check(s) */
- if (al == NULL || src == NULL)
- return AL_RC(AL_ERR_ARG);
-
- cur = TAIL(al,chunks);
- res = AL_CHUNK_RESERVE(cur,label);
-
- while (n > 0) {
- if (res == 0) {
- rc = new_buffer(al, &buf);
- if (rc != AL_OK)
- return AL_RC(rc);
- rc = new_chunk(al,buf,label,&cur);
- if (rc != AL_OK)
- return AL_RC(rc);
- res = AL_CHUNK_RESERVE(cur,label);
- ADDTAIL(al, chunks, cur);
- }
- step = n;
- if (step > res)
- step = res;
-
- dst = AL_CHUNK_PTR(cur, AL_CHUNK_LEN(cur));
- memcpy(dst, src, step);
-
- src += step;
- AL_RESIZE(al, cur, step);
- n -= step;
- res = AL_CHUNK_RESERVE(cur,label);
- }
-
- return AL_OK;
-}
-
-/*
- * copy bytes into buffer, LIFO
- *
- * stops copy operation when a new buffer cannot be created
- * but leaves data structure consistent
- */
-al_rc_t
-al_prepend_bytes(al_t *al, const char *src, size_t n, al_label_t label)
-{
- al_rc_t rc;
- al_chunk_t *cur;
- al_buffer_t *buf;
- size_t res, step;
- char *dst;
-
- /* argument sanity check(s) */
- if (al == NULL || src == NULL)
- return AL_RC(AL_ERR_ARG);
-
- cur = HEAD(al,chunks);
- res = AL_CHUNK_PRESERVE(cur,label);
-
- src += n;
-
- while (n > 0) {
- if (res == 0) {
- rc = new_buffer(al, &buf);
- if (rc != AL_OK)
- return AL_RC(rc);
- rc = new_chunk(al,buf,label,&cur);
- if (rc != AL_OK)
- return AL_RC(rc);
- res = AL_CHUNK_PRESERVE(cur,label);
- ADDHEAD(al, chunks, cur);
- }
- step = n;
- if (step > res)
- step = res;
-
- src -= step;
- AL_PRESIZE(al, cur, step);
- n -= step;
- res = AL_CHUNK_PRESERVE(cur,label);
-
- dst = AL_CHUNK_PTR(cur, 0);
- memcpy(dst, src, step);
- }
-
- return AL_OK;
-}
-
-/*
- * append a caller supplied buffer
- *
- * buffer must exist until list is destroyed
- * XXX - buffer can have multiple refs caused by splice operations
- * XXX - some list operations modify the buffer
- *
- */
-al_rc_t al_attach_buffer(al_t *al, char *p, size_t n, al_label_t label,
- void (*freemem_cb)(char *, size_t, void *), void *u)
-{
- al_rc_t rc;
- al_buffer_t *buf;
- al_chunk_t *cur;
-
- /* argument sanity check(s) */
- if (al == NULL || p == NULL || n <= 0)
- return AL_RC(AL_ERR_ARG);
-
- rc = make_buffer(al, p, n, freemem_cb, u, &buf);
- if (rc != AL_OK)
- return AL_RC(rc);
- rc = new_chunk(al,buf,label,&cur);
- if (rc != AL_OK)
- return AL_RC(rc);
- ADDTAIL(al, chunks, cur);
-
- /* validate data in buffer */
- AL_RESIZE(al, cur, n);
-
- return AL_OK;
-}
-
-/*
- * this is the central function to manipulate assembly line
- *
- * cut arbitrary spans from list into a destination buffer (or drop it)
- * insert (destructive move) content from another list into the cut
- *
- * this is analog to perls splice function, except that
- * -> the output is not stored in the target buffer but is appended
- * -> the replacement data is moved and not copied.
- *
- */
-al_rc_t
-al_splice(al_t *al, size_t off, size_t n, al_t *nal, al_t *tal)
-{
- al_rc_t rc;
- al_chunk_t *cur, *start, *end, *next, *ins, *splitbuf;
- size_t pos, skip, len, step;
- int doinsert;
-
- /* argument sanity check(s) */
- if (al == NULL)
- return AL_RC(AL_ERR_ARG);
-
- /* optimization: treat an empty list as no insertion at all */
- doinsert = (nal != NULL) && !ISEMPTY(nal,chunks);
-
- /*
- * seek to beginning, return EOF when seek position does not exist
- * EOD must be a valid seek position so that we can append data
- */
- rc = al_seek(al, off, &cur, &skip);
- if (rc != AL_OK)
- return AL_RC(rc);
-
- /*
- * remember insertion point
- *
- * caveat: if the first chunk is removed from input the insertion
- * point shifts to the next chunk (or EOD -> NULL pointer)
- */
- ins = cur;
-
- /*
- * the inseration point is either behind the list or
- * within the current chunk
- *
- * if it is behind the list:
- * -> insert operation switches to append mode
- *
- * if the insertion point is at the beginning of the current chunk:
- * -> insertion point moves later if the chunk is removed
- *
- * if the inseration point is in the middle of the current chunk:
- * -> chunk is split into two so that the insertion
- * point is at the beginning of the second part
- *
- * insertion point cannot be at EOD of the chunk
- *
- * splitting at this point preserves all data in case the
- * allocation of the split buffer fails
- */
- if (doinsert) {
- if (ins != NULL && skip > 0) {
- rc = split_chunk(al, ins, skip, &splitbuf);
- if (rc != AL_OK)
- return AL_RC(rc);
- INSERT(al,chunks,ins,splitbuf);
- skip = 0;
- }
- }
-
- /*
- * as long as there is data to move
- */
- pos = off;
- while (n > 0 && cur != NULL) {
- next = NEXT(cur, chunks);
- len = AL_CHUNK_LEN(cur);
-
- /*
- * check if partial chunk was selected
- * if skip > 0 we have to preserve bytes at the beginning
- * if skip == 0 && n < len-skip we have to preserve bytes at the end
- */
- if (skip > 0 || n < len - skip) {
-
- /* compute number of bytes to process */
- step = AL_CHUNK_SPAN(cur, skip, n);
-
- /* copy data to target */
- if (tal != NULL) {
- /*
- * XXX - this operation can fail
- */
- size_t before = tal->bytes;
-
- rc = al_append_bytes(tal, AL_CHUNK_PTR(cur, skip),
- step, AL_CHUNK_LABEL(cur));
- if (rc != AL_OK)
- /* correct step size to actual size */
- step = tal->bytes - before;
-
- } else
- rc = AL_OK;
-
- /*
- * cut span from src chunk
- * if skip == 0, simply shrink the chunk from the beginning
- * if skip > 0, compute number of bytes to preserve,
- * align buffer and shrink chunk from the end
- */
- if (skip == 0)
- AL_PRESIZE(al, cur, -step);
- else {
- /* align trailing bytes */
- if (len > (skip+step)) {
- memmove(
- AL_CHUNK_PTR(cur, skip),
- AL_CHUNK_PTR(cur, skip+step),
- len - (skip+step)
- );
- }
- AL_RESIZE(al, cur, -step);
- }
-
- /*
- * bail out from failed al_append_bytes operation above
- *
- */
- if (rc != AL_OK)
- return AL_RC(rc);
- }
- else {
- /*
- * the whole chunk has to be moved,
- *
- * scan ahead for more such chunks to unlink
- * and relink a whole chain in a single operation
- *
- * move the chunks to the target chain
- * manual accounting for total size
- */
-
- /*
- * when the insertion chunk is removed, we have to adjust
- * the insertion point
- *
- * if the insertion chunk was the last chunk we get a NULL
- * next pointer and the insertion method switches to append
- * mode
- */
-
- step = len;
- start = cur;
- end = cur;
-
- if (cur == ins)
- ins = next;
-
- while (next && step + (len = AL_CHUNK_LEN(next)) <= n) {
- step += len;
- end = next;
- next = NEXT(next, chunks);
- if (end == ins)
- ins = next;
- }
- REMOVE2(al, chunks, start, end);
-
- al->bytes -= step;
- if (tal == NULL) {
- do {
- cur = start;
- start = NEXT(cur, chunks);
- dispose_chunk(al, cur);
- } while (cur != end);
- } else {
- ADDTAIL2(tal, chunks, start, end);
- tal->bytes += step;
- }
- }
- n -= step;
- pos += step;
- cur = next;
- skip = 0;
- }
-
- /*
- * now splice in replacement chunks
- */
- if (doinsert) {
- if (ins != NULL) {
- /*
- * complex case where list is inserted
- *
- * the original list has already been modified so
- * that we can simply insert between two chunks
- */
- INSERTLIST(al,chunks,ins,nal);
- } else {
- /*
- * simple case where list end is 'replaced'
- */
- APPENDLIST(al,chunks,nal);
- }
-
- al->bytes += nal->bytes;
- nal->bytes = 0;
-
- }
-
- return AL_OK;
-}
-
-/*
- *
- */
-al_rc_t
-al_setlabel(al_t *al, size_t off, size_t n,
- al_label_t oldlabel, al_label_t newlabel)
-{
- al_rc_t rc;
- al_chunk_t *cur, *splitbuf;
- size_t skip, len;
-
- /* argument sanity check(s) */
- if (al == NULL)
- return AL_RC(AL_ERR_ARG);
-
- /*
- * seek to beginning, return EOF when seek position does not exist
- * EOD must be a valid seek position so that we can append data
- */
- rc = al_seek(al, off, &cur, &skip);
- if (rc != AL_OK)
- return AL_RC(rc);
-
- /*
- * seek to EOD, nothing to label
- */
- if (cur == NULL)
- return AL_OK;
-
- /*
- * if first chunk doesn't need relabeling
- * then skip it, adjust seek size
- *
- * else if offset is not at chunk start
- * then split chunk at offset, continue
- * with second half
- */
- if (!AL_SAME_LABEL(cur, oldlabel) ||
- AL_SAME_LABEL(cur, newlabel)) {
- len = AL_CHUNK_LEN(cur) - skip;
- n = n < len ? 0 : n - len;
- cur = NEXT(cur, chunks);
- } else if (skip > 0) {
- rc = split_chunk(al, cur, skip, &splitbuf);
- if (rc != AL_OK)
- return AL_RC(rc);
- INSERT(al,chunks,cur,splitbuf);
- }
-
- /*
- * for all remaining chunks and bytes
- *
- * if chunk doesn't need relabeling
- * then skip it, adjust size
- *
- * else if chunk isn't covered in total
- * then split chunk at end offset and
- * process first half
- */
- while (n > 0 && cur != NULL) {
- len = AL_CHUNK_LEN(cur);
- if (!AL_SAME_LABEL(cur, oldlabel) ||
- AL_SAME_LABEL(cur, newlabel)) {
- n = n < len ? 0 : n - len;
- } else {
- if (n < len) {
- /*
- * split last chunk at end offset
- */
- rc = split_chunk(al, cur, n, &splitbuf);
- if (rc != AL_OK)
- return AL_RC(rc);
- INSERT(al,chunks,cur,splitbuf);
- cur = splitbuf;
- len = AL_CHUNK_LEN(cur);
- }
- AL_CHUNK_LABEL(cur) = newlabel;
- n -= len;
- }
- cur = NEXT(cur, chunks);
- }
-
- return AL_OK;
-}
-
-/*
- * assembly line traversal requires a context. It needs to be
- * malloced to keep its inner structure private
- */
-al_rc_t
-al_txalloc(al_t *al, al_tx_t **txp)
-{
- al_tx_t *tx;
-
- tx = (al_tx_t*)(al->m.malloc)(sizeof(al_tx_t));
- if (tx == NULL)
- return AL_RC(AL_ERR_MEM);
-
- *txp = tx;
- return AL_OK;
-}
-
-/*
- * free traversal context using proper policy function
- */
-al_rc_t
-al_txfree(al_t *al, al_tx_t *tx)
-{
- (al->m.free)(tx);
- return AL_OK;
-}
-
-/*
- * initiate assembly line traversal
- *
- * - do initial seek, fail if position does not exist
- * - save traversal parameters
- */
-al_rc_t
-al_traverse(al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label, al_tx_t *tx)
-{
- al_rc_t rc;
-
- tx->cur = NULL;
-
- rc = al_seek(al, off, &tx->cur, &tx->skip);
- if (rc != AL_OK)
- return AL_RC(rc);
-
- tx->dir = dir;
- tx->togo = n;
- tx->label = label;
-
- return AL_OK;
-}
-
-/*
- * assembly line traversal step
- *
- * return EOF if at end of assembly line
- * clip view chunk to traversal bounds
- * advance chunk cursor according to traversal direction
- */
-al_rc_t
-al_traverse_next(al_t *al, al_tx_t *tx, al_chunk_t **alcp)
-{
- size_t step;
-
- do {
- if (tx->togo <= 0) /* XXX - togo can be negative from bad input */
- return AL_ERR_EOF;
-
- if (tx->cur == NULL) /* premature EOF */
- return AL_ERR_EOF;
-
- /* compute number of bytes to process */
- step = AL_CHUNK_SPAN(tx->cur, tx->skip, tx->togo);
-
- /*
- * synthetic chunk which is NOT maintained in usecount
- * MUST NOT BE USED for modifications to chunk list
- * MUST NOT BE USED for modifications to chunk size
- * ALLOWED is read access to chunk content
- * ALLOWED is modification in place of chunk content
- */
- tx->view = *(tx->cur);
- tx->view.begin += tx->skip;
- tx->view.end = tx->view.begin + step;
-
- switch (tx->dir) {
- case AL_FORWARD:
- case AL_BACKWARD:
- break;
- case AL_FORWARD_SPAN:
- case AL_BACKWARD_SPAN:
- if (!AL_SAME_LABEL(&tx->view, tx->label)) {
- tx->togo = 0;
- return AL_ERR_EOF;
- }
- break;
- }
-
- switch (tx->dir) {
- case AL_FORWARD:
- case AL_FORWARD_SPAN:
- tx->cur = NEXT(tx->cur,chunks);
- tx->togo -= step;
- tx->skip = 0;
- break;
- case AL_BACKWARD:
- case AL_BACKWARD_SPAN:
- tx->cur = PREV(tx->cur,chunks);
- tx->togo -= step;
- tx->skip = 0;
- break;
- }
- } while (!AL_SAME_LABEL(&tx->view, tx->label));
-
- *alcp = &tx->view;
- return AL_OK;
-}
-
-/*
- * assembly line traversal end
- *
- * to free resources allocated/locked during traversal
- * currently a NOOP
- */
-al_rc_t al_traverse_end(al_t *al, al_tx_t *tx, int final)
-{
- return AL_OK;
-}
-
-/*
- * full assembly line traversal with callback
- *
- * traversal is aborted when callback return != AL_OK
- * reaching EOF (and also aborting with AL_ERR_EOF) is not an error
- *
- * traversal context is kept on stack (XXX ?)
- */
-al_rc_t
-al_traverse_cb(al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label,
- al_rc_t (*cb)(al_chunk_t *, void *), void *u)
-{
- al_rc_t rc;
- al_tx_t tx; /* XXX - private tx structure on stack */
- al_chunk_t *view;
-
- rc = al_traverse(al, off, n, dir, label, &tx);
- if (rc != AL_OK)
- return AL_RC(rc);
-
- while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
- rc = cb(view, u);
- if (rc != AL_OK)
- break;
- }
-
- al_traverse_end(al, &tx, 1);
-
- if (rc != AL_ERR_EOF)
- return AL_RC(rc);
-
- return AL_OK;
-}
-
-/*
- * full assembly line traversal with data copy to linear buffer
- *
- * returns actual number of bytes copied
- *
- * Do not copy if destination pointer is NULL, but still count.
- * This can be used to precalculate the size of the needed linear
- * buffer with n set to some arbitrary huge value.
- *
- * traversal context is kept on stack (XXX ?)
- */
-al_rc_t
-al_flatten(al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label,
- char *dst, size_t *lenp)
-{
- al_rc_t rc;
- al_tx_t tx; /* XXX - private tx structure on stack */
- al_chunk_t *view;
- size_t step, total;
-
- *lenp = 0; /* keep caller on safe side */
-
- rc = al_traverse(al, off, n, dir, label, &tx);
- if (rc != AL_OK)
- return AL_RC(rc);
-
- switch (dir) {
- case AL_FORWARD:
- case AL_FORWARD_SPAN:
- break;
- case AL_BACKWARD:
- case AL_BACKWARD_SPAN:
- dst += n;
- break;
- }
-
- total = 0;
-
- if (dst == NULL) {
- while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK)
- total += AL_CHUNK_LEN(view);
- } else {
- while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
- step = AL_CHUNK_LEN(view);
- switch (dir) {
- case AL_FORWARD:
- case AL_FORWARD_SPAN:
- memmove(dst, AL_CHUNK_PTR(view, 0), step);
- dst += step;
- break;
- case AL_BACKWARD:
- case AL_BACKWARD_SPAN:
- dst -= step;
- memmove(dst, AL_CHUNK_PTR(view, 0), step);
- break;
- }
- total += step;
- }
- }
- *lenp = total;
-
- al_traverse_end(al, &tx, 1);
-
- if (rc != AL_ERR_EOF)
- return AL_RC(rc);
-
- return AL_OK;
-}
-
-/*
- * full assembly line traversal with data copy to target assembly line
- *
- * traversal context is kept on stack (XXX ?)
- */
-al_rc_t
-al_copy(al_t *al, size_t off, size_t n, al_label_t label, al_t *tal)
-{
- al_rc_t rc;
- al_tx_t tx; /* XXX - private tx structure on stack */
- al_chunk_t *view;
- size_t step;
-
- rc = al_traverse(al, off, n, AL_FORWARD, label, &tx);
- if (rc != AL_OK)
- return AL_RC(rc);
-
- while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
- step = AL_CHUNK_LEN(view);
- al_append_bytes(tal, AL_CHUNK_PTR(view, 0), step, AL_CHUNK_LABEL(view));
- }
-
- al_traverse_end(al, &tx, 1);
-
- if (rc != AL_ERR_EOF)
- return AL_RC(rc);
-
- return AL_OK;
-}
-
-/*
- * traverse assembly line and retrieve first chunk
- *
- * traversal context is kept on stack (XXX ?)
- */
-al_rc_t
-al_firstlabel(al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label,
- al_label_t *labelp)
-{
- al_rc_t rc;
- al_tx_t tx; /* XXX - private tx structure on stack */
- al_chunk_t *view;
-
- rc = al_traverse(al, off, n, dir, label, &tx);
- if (rc != AL_OK)
- return AL_RC(rc);
-
- if ((rc = al_traverse_next(al, &tx, &view)) == AL_OK)
- *labelp = AL_CHUNK_LABEL(view);
-
- al_traverse_end(al, &tx, 1);
-
- return rc;
-}
-
-/*
- * traverse assembly line forward and search first chunk
- * that matches label and continue search until end of
- * span of same label
- *
- * return offset to first byte in *offp
- * return size of span to last byte in *spanp
- *
- * traversal context is kept on stack (XXX ?)
- */
-al_rc_t
-al_spanlabel(al_t *al, size_t off, size_t n, al_label_t label,
- size_t *offp, size_t *spanp)
-{
- al_rc_t rc;
- al_tx_t tx; /* XXX - private tx structure on stack */
- al_chunk_t *view;
- size_t len, total, start;
- int have_first;
-
- /*
- * we need to track absolute traversal position,
- * so we have to see all chunks.. no filtering
- * allowed
- */
- rc = al_traverse(al, off, n, AL_FORWARD, NULL, &tx);
- if (rc != AL_OK)
- return AL_RC(rc);
-
- have_first = 0;
- start = 0;
- total = 0;
- while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
- len = AL_CHUNK_LEN(view);
- if (AL_SAME_LABEL(view, label)) {
- if (!have_first) {
- start = total;
- have_first = 1;
- }
- } else if (have_first)
- break;
- total += len;
- }
-
- al_traverse_end(al, &tx, 1);
-
- if (rc != AL_OK && rc != AL_ERR_EOF)
- return AL_RC(rc);
-
- if (!have_first)
- return AL_RC(AL_ERR_EOF);
-
- *offp = off + start;
- *spanp = total - start;
-
- return AL_OK;
-}
-
-/*
- * relay macros to caller
- *
- * al_bytes - total number of bytes in assembly line
- * al_chunk_len - number of bytes in chunk
- * al_chunk_span - clip interval (off,off+n( against chunk length
- * al_chunk_label- return chunk label
- * al_same_label - check if label matches with chunk label
- * al_chunk_ptr - return memory pointer to byte within chunk
- *
- * off must be a valid offset within (0,len(
- */
-
-size_t
-al_bytes(const al_t *al)
-{
- return al->bytes;
-}
-
-size_t
-al_chunk_len(al_chunk_t *alc)
-{
- return AL_CHUNK_LEN(alc);
-}
-
-size_t
-al_chunk_span(al_chunk_t *alc, size_t off, size_t n)
-{
- return AL_CHUNK_SPAN(alc, off, n);
-}
-
-al_label_t
-al_chunk_label(al_chunk_t *alc)
-{
- return AL_CHUNK_LABEL(alc);
-}
-
-int
-al_same_label(al_chunk_t *alc, al_label_t label)
-{
- return AL_SAME_LABEL(alc, label);
-}
-
-char *
-al_chunk_ptr(al_chunk_t *alc, size_t off)
-{
- return AL_CHUNK_PTR(alc, off);
-}
-
-/*
- * convert error code into human readable form
- */
-const char *
-al_error(al_rc_t rc)
-{
- const char *mess;
-
- switch (rc) {
- case AL_OK: mess = "Everything Ok"; break;
- case AL_ERR_ARG: mess = "Invalid Argument"; break;
- case AL_ERR_MEM: mess = "Not Enough Memory"; break;
- case AL_ERR_EOF: mess = "End Of Data"; break;
- case AL_ERR_INT: mess = "Internal Error"; break;
- default: mess = "Invalid Result Code"; break;
- }
-
- return mess;
-}
-
Index: ossp-pkg/sio/al.h
RCS File: /v/ossp/cvs/ossp-pkg/sio/Attic/al.h,v
co -q -kk -p'1.17' '/v/ossp/cvs/ossp-pkg/sio/Attic/al.h,v' | diff -u - /dev/null -L'ossp-pkg/sio/al.h' 2>/dev/null
--- ossp-pkg/sio/al.h
+++ /dev/null 2025-04-09 16:01:24.000000000 +0200
@@ -1,89 +0,0 @@
-/*
-** OSSP al -- Assembly Line
-** Copyright (c) 2002 The OSSP Project
-** Copyright (c) 2002 Cable & Wireless Deutschland
-** Copyright (c) 2002 Ralf S. Engelschall
-** Copyright (c) 2002 Michael van Elst
-**
-** This file is part of OSSP al, an abstract datatype of a data buffer
-** that can assemble, move and truncate data but avoids actual copying.
-**
-** Permission to use, copy, modify, and distribute this software for
-** any purpose with or without fee is hereby granted, provided that
-** the above copyright notice and this permission notice appear in all
-** copies.
-**
-** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
-** 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.
-**
-** al.h: assembly line public API definition
-*/
-
-#ifndef __AL_H__
-#define __AL_H__
-
-typedef enum {
- AL_OK,
- AL_ERR_ARG,
- AL_ERR_MEM,
- AL_ERR_EOF,
- AL_ERR_INT
-} al_rc_t;
-
-struct al_st;
-typedef struct al_st al_t;
-
-struct al_chunk_st;
-typedef struct al_chunk_st al_chunk_t;
-
-typedef void *al_label_t;
-
-typedef enum {
- AL_FORWARD,
- AL_BACKWARD,
- AL_FORWARD_SPAN,
- AL_BACKWARD_SPAN
-} al_td_t;
-
-struct al_tx_st;
-typedef struct al_tx_st al_tx_t;
-
-al_rc_t al_create (al_t **alp);
-al_rc_t al_destroy (al_t *al);
-al_rc_t al_append_bytes (al_t *al, const char *src, size_t n, al_label_t label);
-al_rc_t al_prepend_bytes(al_t *al, const char *src, size_t n, al_label_t label);
-al_rc_t al_attach_buffer(al_t *al, char *p, size_t n, al_label_t label, void (*freemem)(char *, size_t, void *), void *u);
-al_rc_t al_txalloc (al_t *al, al_tx_t **txp);
-al_rc_t al_txfree (al_t *al, al_tx_t *tx);
-al_rc_t al_traverse (al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label, al_tx_t *tx);
-al_rc_t al_traverse_next(al_t *al, al_tx_t *tx, al_chunk_t **alcp);
-al_rc_t al_traverse_end (al_t *al, al_tx_t *tx, int final);
-al_rc_t al_traverse_cb (al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label, al_rc_t (*cb)(al_chunk_t *, void *), void *u);
-al_rc_t al_copy (al_t *al, size_t off, size_t n, al_label_t label, al_t *tal);
-al_rc_t al_splice (al_t *al, size_t off, size_t n, al_t *nal, al_t *tal);
-al_rc_t al_setlabel (al_t *al, size_t off, size_t n, al_label_t oldlabel, al_label_t newlabel);
-al_rc_t al_flatten (al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label, char *dst, size_t *lenp);
-al_rc_t al_firstlabel (al_t *al, size_t off, size_t n, al_td_t dir, al_label_t label, al_label_t *labelp);
-al_rc_t al_spanlabel (al_t *al, size_t off, size_t n, al_label_t label, size_t *offp, size_t *spanp);
-
-size_t al_bytes (const al_t *al);
-size_t al_chunk_len (al_chunk_t *alc);
-al_label_t al_chunk_label(al_chunk_t *alc);
-int al_same_label (al_chunk_t *alc, al_label_t label);
-size_t al_chunk_span (al_chunk_t *alc, size_t off, size_t n);
-char *al_chunk_ptr (al_chunk_t *alc, size_t off);
-
-const char *al_error (al_rc_t rc);
-
-#endif /* __AL_H__ */
-
Index: ossp-pkg/sio/al.pod
RCS File: /v/ossp/cvs/ossp-pkg/sio/Attic/al.pod,v
co -q -kk -p'1.17' '/v/ossp/cvs/ossp-pkg/sio/Attic/al.pod,v' | diff -u - /dev/null -L'ossp-pkg/sio/al.pod' 2>/dev/null
--- ossp-pkg/sio/al.pod
+++ /dev/null 2025-04-09 16:01:24.000000000 +0200
@@ -1,474 +0,0 @@
-##
-## OSSP al - Assembly Line
-## Copyright (c) 2002 The OSSP Project
-## Copyright (c) 2002 Cable & Wireless Deutschland
-## Copyright (c) 2002 Ralf S. Engelschall
-## Copyright (c) 2002 Michael van Elst
-##
-## This file is part of OSSP al, an abstract datatype of a data buffer
-## that can assemble, move and truncate data but avoids actual copying.
-##
-## Permission to use, copy, modify, and distribute this software for
-## any purpose with or without fee is hereby granted, provided that
-## the above copyright notice and this permission notice appear in all
-## copies.
-##
-## THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 AUTHORS AND COPYRIGHT HOLDERS AND THEIR
-## 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.
-##
-## al.pod: assembly line library manual page
-##
-
-=pod
-
-=head1 NAME
-
-B - Assembly Line
-
-=head1 VERSION
-
-B
-
-=head1 SYNOPSIS
-
-=over 4
-
-=item B:
-
-al_rc_t,
-al_t,
-al_tx_t,
-al_td_t,
-al_chunk_t.
-
-=item B:
-
-al_create,
-al_destroy,
-al_append_bytes,
-al_prepend_bytes,
-al_attach_buffer,
-al_splice,
-al_setlabel,
-al_bytes.
-
-=item B:
-
-al_txalloc,
-al_txfree,
-al_traverse,
-al_traverse_next,
-al_traverse_end,
-al_traverse_cb.
-
-=item B:
-
-al_flatten,
-al_copy,
-al_firstlabel,
-al_spanlabel.
-
-=item B:
-
-al_chunk_len,
-al_chunk_span,
-al_chunk_label,
-al_same_label,
-al_chunk_ptr.
-
-=item B:
-
-al_error.
-
-=back
-
-=head1 DESCRIPTION
-
-B defines an abstract type of a data buffer that can
-assemble, move and truncate data but avoids actual copying.
-
-It provides the following key features:
-
-=over 4
-
-=back
-
-=head1 DATA TYPES
-
-B uses six data types in its API:
-
-=over 4
-
-=item B (Return Code Type)
-
-This is an exported enumerated integer type with the following possible
-values:
-
- AL_OK Everything Ok
- AL_ERR_ARG Invalid Argument
- AL_ERR_MEM Not Enough Memory
- AL_ERR_EOF End Of Communication
- AL_ERR_INT Internal Error
-
-=item B (Assembly Line Type)
-
-This is an opaque data type representing a data buffer.
-Only pointers to this abstract data type are used in the API.
-
-=item B (Label Type)
-
-This is an opaque pointer type representing a specific data flavour.
-You can restrict traversal operations to data that was marked with
-the specific flavour. Usually you would cast a pointer to the
-object that maintains the data to B. You may use
-NULL as a label but on traversal NULL matches any label.
-
-=item B (Traversal Context Type)
-
-This is an opaque data type representing the state of a buffer
-traversal operation. Only pointers to this abstract data type are
-used in the API.
-
-=item B (Traversal Direction Type)
-
-This is an exported enumerated integer type with the following possible
-values:
-
- AL_FORWARD traverse assembly line from beginning to end
- AL_BACKWARD traverse assembly line from end to beginning
- AL_FORWARD_SPAN like AL_FORWARD, but stop when label does not match
- AL_BACKWARD_SPAN like AL_BACKWARD, but stop when label does not match
-
-=item B (Chunk Type)
-
-This is an opaque data type representing a chunk of a buffer during
-a traversal operation. Only pointers to this abstract data type are
-used in the API. The B type is used to generate a pointer
-and byte count to access the data in the buffer.
-
-=back
-
-=head1 FUNCTIONS
-
-B provides a bunch of API functions, all modelled after the
-same prototype: "C CIC<(al_>[C]C<_t *,>
-...C<)>". This means every function returns C to indicate its
-success (C) or failure (C) by returning a return code
-(the corresponding describing text can be determined by passing this
-return code to C). Each function name starts with the common
-prefix C and receives a C (or C) object on which
-it operates as its first argument.
-
-=head2 Assembly Line Operations
-
-=over 4
-
-=item al_rc_t B(al_t **I);
-
-Create an assembly line abstraction object.
-The object is stored in I on success.
-
-Example: C
-
-=item al_rc_t B(al_t *I);
-
-Destroy an assembly line abstraction object.
-The object I is invalid after this call succeeded.
-
-Example: C
-
-=item al_rc_t B(al_t *I, const char *I, size_t I, al_label_t I