src/buffer.c

changeset 1138
29672c777a28
parent 1135
f79415d974d3
equal deleted inserted replaced
1137:61939929030a 1138:29672c777a28
266 buffer->size = buffer->pos; 266 buffer->size = buffer->pos;
267 } 267 }
268 return nitems; 268 return nitems;
269 } 269 }
270 270
271 size_t len; 271 size_t len, total_flushed = 0;
272 cx_buffer_write_retry:
272 if (cx_szmul(size, nitems, &len)) { 273 if (cx_szmul(size, nitems, &len)) {
273 errno = EOVERFLOW; 274 errno = EOVERFLOW;
274 return 0; 275 return total_flushed;
275 } 276 }
276 if (buffer->pos > SIZE_MAX - len) { 277 if (buffer->pos > SIZE_MAX - len) {
277 errno = EOVERFLOW; 278 errno = EOVERFLOW;
278 return 0; 279 return total_flushed;
279 } 280 }
281
280 size_t required = buffer->pos + len; 282 size_t required = buffer->pos + len;
281
282 bool perform_flush = false; 283 bool perform_flush = false;
283 if (required > buffer->capacity) { 284 if (required > buffer->capacity) {
284 if (buffer->flags & CX_BUFFER_AUTO_EXTEND) { 285 if (buffer->flags & CX_BUFFER_AUTO_EXTEND) {
285 if (buffer->flush != NULL && required > buffer->flush->threshold) { 286 if (buffer->flush != NULL && required > buffer->flush->threshold) {
286 perform_flush = true; 287 perform_flush = true;
287 } else { 288 } else {
288 if (cxBufferMinimumCapacity(buffer, required)) { 289 if (cxBufferMinimumCapacity(buffer, required)) {
289 return 0; // LCOV_EXCL_LINE 290 return total_flushed; // LCOV_EXCL_LINE
290 } 291 }
291 } 292 }
292 } else { 293 } else {
293 if (buffer->flush != NULL) { 294 if (buffer->flush != NULL) {
294 perform_flush = true; 295 perform_flush = true;
303 } 304 }
304 } 305 }
305 306
306 // check here and not above because of possible truncation 307 // check here and not above because of possible truncation
307 if (len == 0) { 308 if (len == 0) {
308 return 0; 309 return total_flushed;
309 } 310 }
310 311
311 // check if we need to copy 312 // check if we need to copy
312 if (buffer_copy_on_write(buffer)) return 0; 313 if (buffer_copy_on_write(buffer)) return 0;
313 314
314 // perform the operation 315 // perform the operation
315 if (perform_flush) { 316 if (perform_flush) {
316 size_t items_flush; 317 size_t items_flushed;
317 if (buffer->pos == 0) { 318 if (buffer->pos == 0) {
318 // if we don't have data in the buffer, but are instructed 319 // if we don't have data in the buffer, but are instructed
319 // to flush, it means that we are supposed to relay the data 320 // to flush, it means that we are supposed to relay the data
320 items_flush = cx_buffer_flush_helper(buffer, ptr, size, nitems); 321 items_flushed = cx_buffer_flush_helper(buffer, ptr, size, nitems);
321 if (items_flush == 0) { 322 if (items_flushed == 0) {
322 // we needed to relay data, but could not flush anything 323 // we needed to relay data, but could not flush anything
323 // i.e. we have to give up to avoid endless trying 324 // i.e. we have to give up to avoid endless trying
324 return 0; 325 return 0;
325 } 326 }
326 size_t ritems = nitems - items_flush; 327 nitems -= items_flushed;
327 if (ritems > 0) { 328 total_flushed += items_flushed;
328 const unsigned char *rest = ptr; 329 if (nitems > 0) {
329 rest += items_flush * size; 330 ptr = ((unsigned char*)ptr) + items_flushed * size;
330 return items_flush + cxBufferWrite(rest, size, ritems, buffer); 331 goto cx_buffer_write_retry;
331 } else {
332 return items_flush;
333 } 332 }
333 return total_flushed;
334 } else { 334 } else {
335 items_flush = cx_buffer_flush_impl(buffer, size); 335 items_flushed = cx_buffer_flush_impl(buffer, size);
336 if (items_flush == 0) { 336 if (items_flushed == 0) {
337 // flush target is full, let's try to truncate 337 // flush target is full, let's try to truncate
338 size_t remaining_space; 338 size_t remaining_space;
339 if (buffer->flags & CX_BUFFER_AUTO_EXTEND) { 339 if (buffer->flags & CX_BUFFER_AUTO_EXTEND) {
340 remaining_space = buffer->flush->threshold > buffer->pos 340 remaining_space = buffer->flush->threshold > buffer->pos
341 ? buffer->flush->threshold - buffer->pos 341 ? buffer->flush->threshold - buffer->pos
345 ? buffer->capacity - buffer->pos 345 ? buffer->capacity - buffer->pos
346 : 0; 346 : 0;
347 } 347 }
348 nitems = remaining_space / size; 348 nitems = remaining_space / size;
349 if (nitems == 0) { 349 if (nitems == 0) {
350 return 0; 350 return total_flushed;
351 } 351 }
352 } 352 }
353 return cxBufferWrite(ptr, size, nitems, buffer); 353 goto cx_buffer_write_retry;
354 } 354 }
355 } else { 355 } else {
356 memcpy(buffer->bytes + buffer->pos, ptr, len); 356 memcpy(buffer->bytes + buffer->pos, ptr, len);
357 buffer->pos += len; 357 buffer->pos += len;
358 if (buffer->pos > buffer->size) { 358 if (buffer->pos > buffer->size) {
359 buffer->size = buffer->pos; 359 buffer->size = buffer->pos;
360 } 360 }
361 return nitems; 361 return total_flushed + nitems;
362 } 362 }
363
364 } 363 }
365 364
366 size_t cxBufferAppend( 365 size_t cxBufferAppend(
367 const void *ptr, 366 const void *ptr,
368 size_t size, 367 size_t size,

mercurial