Index: ossp-pkg/sio/al.c RCS File: /v/ossp/cvs/ossp-pkg/sio/Attic/al.c,v rcsdiff -q -kk '-r1.8' '-r1.9' -u '/v/ossp/cvs/ossp-pkg/sio/Attic/al.c,v' 2>/dev/null --- 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; }