--- al.c 2002/10/14 15:44:03 1.8
+++ al.c 2002/10/15 13:13:06 1.9
@@ -507,6 +507,9 @@
/*
* 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)
{
@@ -516,15 +519,19 @@
size_t res, step;
char *dst;
+ /* argument sanity check(s) */
+ if (al == NULL || src == NULL || n < 0)
+ return AL_RC(AL_ERR_ARG);
+
cur = TAIL(al,chunks);
res = AL_CHUNK_RESERVE(cur);
while (n > 0) {
if (res == 0) {
rc = new_buffer(al, &buf);
- /* XXX handle error */
+ if (rc != AL_OK) return AL_RC(rc);
rc = new_chunk(al,buf,&cur);
- /* XXX handle error */
+ if (rc != AL_OK) return AL_RC(rc);
res = AL_CHUNK_RESERVE(cur);
ADDTAIL(al, chunks, cur);
}
@@ -546,6 +553,9 @@
/*
* 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)
{
@@ -555,6 +565,10 @@
size_t res, step;
char *dst;
+ /* argument sanity check(s) */
+ if (al == NULL || src == NULL || n < 0)
+ return AL_RC(AL_ERR_ARG);
+
cur = HEAD(al,chunks);
res = AL_CHUNK_PRESERVE(cur);
@@ -563,9 +577,9 @@
while (n > 0) {
if (res == 0) {
rc = new_buffer(al, &buf);
- if (rc != AL_OK) return rc;
+ if (rc != AL_OK) return AL_RC(rc);
rc = new_chunk(al,buf,&cur);
- if (rc != AL_OK) return rc;
+ if (rc != AL_OK) return AL_RC(rc);
res = AL_CHUNK_PRESERVE(cur);
ADDHEAD(al, chunks, cur);
}
@@ -599,10 +613,14 @@
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, &buf);
- if (rc != AL_OK) return rc;
+ if (rc != AL_OK) return AL_RC(rc);
rc = new_chunk(al,buf, &cur);
- if (rc != AL_OK) return rc;
+ if (rc != AL_OK) return AL_RC(rc);
ADDTAIL(al, chunks, cur);
/* validate data in buffer */
@@ -625,17 +643,51 @@
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, *next;
+ al_chunk_t *cur, *next, *ins, *splitbuf;
size_t pos, skip, len, step;
+ int doinsert;
+
+ /* argument sanity check(s) */
+ if (al == NULL || n < 0)
+ 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 rc;
+ 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;
- /* as long as there is data to move */
+ /*
+ * if the first chunk is not removed completely it needs to be
+ * split into two halves to allow insertion of new chunks later
+ * from nal
+ *
+ * splitting at this point preserves all data in case the
+ * allocation of the split buffer fails
+ */
+ if (doinsert) {
+ if (ins != NULL && skip > 0 && skip+n < AL_CHUNK_LEN(ins)) {
+ rc = split_chunk(al, ins, skip, &splitbuf);
+ if (rc != AL_OK) return AL_RC(rc);
+ INSERT(al,chunks,ins,splitbuf);
+ }
+ }
+
+ /*
+ * as long as there is data to move
+ */
pos = off;
while (n > 0 && cur != NULL) {
next = NEXT(cur, chunks);
@@ -651,8 +703,22 @@
/* compute number of bytes to process */
step = AL_CHUNK_SPAN(cur, skip, n);
- if (tal != NULL)
- al_append_bytes(tal, AL_CHUNK_PTR(cur, skip), step);
+ /* 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);
+ if (rc != AL_OK) {
+ /* correct step size to actual size */
+ step = tal->bytes - before;
+ }
+
+ } else {
+ rc = AL_OK;
+ }
/*
* cut span from src chunk
@@ -674,6 +740,12 @@
AL_RESIZE(al, cur, -step);
}
+ /*
+ * bail out from failed al_append_bytes operation above
+ *
+ */
+ if (rc != AL_OK) return AL_RC(rc);
+
} else {
/*
@@ -683,6 +755,18 @@
*/
step = len;
REMOVE(al, chunks, cur);
+
+ /*
+ * when the insertion point is removed, we have to adjust
+ * the insertion point
+ *
+ * if the insertion point was the last chunk we get a NULL
+ * next pointer and the insertion method switches to APPEND
+ * mode
+ */
+ if (cur == ins)
+ ins = next;
+
al->bytes -= step;
if (tal == NULL) {
dispose_chunk(al, cur);
@@ -701,39 +785,26 @@
/*
* now splice in replacement chunks
*/
- if (nal && !ISEMPTY(nal,chunks)) {
- al_chunk_t *ins;
-
- /* rewind */
- rc = al_seek(al, off, &ins, &skip);
- if (rc != AL_OK) return rc;
-
- if (ins == NULL) {
+ if (doinsert) {
+ if (ins != NULL) {
/*
- * simple case where list end is 'replaced'
+ * complex case where list is inserted
+ *
+ * the original list has already been modified so
+ * that we can simply insert between two chunks
*/
- APPENDLIST(al,chunks,nal);
-
+ INSERTLIST(al,chunks,ins,nal);
} else {
-
/*
- * if beginning and end were in same chunk we have to split this
- * chunk in two for a copyless insert operation
+ * simple case where list end is 'replaced'
*/
- if (skip > 0) {
- al_chunk_t *twin;
- rc = split_chunk(al, ins, skip, &twin);
- if (rc != AL_OK) return rc;
-
- INSERT(al,chunks,ins,twin);
- }
- INSERTLIST(al,chunks,ins,nal);
-
+ APPENDLIST(al,chunks,nal);
}
al->bytes += nal->bytes;
nal->bytes = 0;
+
}
return AL_OK;
@@ -749,7 +820,7 @@
txp = (al_tx_t*)(al->m.malloc)(sizeof(al_tx_t));
if (txp == NULL)
- return AL_ERR_MEM;
+ return AL_RC(AL_ERR_MEM);
*txpp = txp;
return AL_OK;
@@ -777,7 +848,7 @@
txp->cur = NULL;
rc = al_seek(al, off, &txp->cur, &txp->skip);
- if (rc != AL_OK) return rc;
+ if (rc != AL_OK) return AL_RC(rc);
txp->dir = dir;
txp->togo = n;
@@ -848,7 +919,7 @@
al_chunk_t *view;
rc = al_traverse(al, off, n, dir, &tx);
- if (rc != AL_OK) return rc;
+ if (rc != AL_OK) return AL_RC(rc);
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
rc = cb(view, u);
@@ -857,7 +928,7 @@
}
if (rc != AL_ERR_EOF)
- return rc;
+ return AL_RC(rc);
return AL_OK;
}
@@ -879,7 +950,7 @@
*lenp = 0; /* keep caller on safe side */
rc = al_traverse(al, off, n, AL_FORWARD, &tx);
- if (rc != AL_OK) return rc;
+ if (rc != AL_OK) return AL_RC(rc);
total = 0;
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
@@ -891,7 +962,7 @@
*lenp = total;
if (rc != AL_ERR_EOF)
- return rc;
+ return AL_RC(rc);
return AL_OK;
}
@@ -909,7 +980,7 @@
size_t step;
rc = al_traverse(al, off, n, AL_FORWARD, &tx);
- if (rc != AL_OK) return rc;
+ if (rc != AL_OK) return AL_RC(rc);
while ((rc = al_traverse_next(al, &tx, &view)) == AL_OK) {
step = AL_CHUNK_LEN(view);
@@ -917,7 +988,7 @@
}
if (rc != AL_ERR_EOF)
- return rc;
+ return AL_RC(rc);
return AL_OK;
}
|