/** * Read data from the pmsg list into supplied buffer. Copied data is * removed from the list. * * @param slist the pmsg list * @param buf start of buffer where data must be copied * @param len length of buffer * * @return amount of copied bytes. */ size_t pmsg_slist_read(slist_t *slist, void *buf, size_t len) { slist_iter_t *iter; size_t remain = len; void *p; g_assert(slist != NULL); iter = slist_iter_removable_on_head(slist); p = buf; while (remain != 0 && slist_iter_has_item(iter)) { pmsg_t *mb = slist_iter_current(iter); int n; n = pmsg_read(mb, p, remain); remain -= n; p = ptr_add_offset(p, n); if (0 == pmsg_size(mb)) { /* Fully copied message */ pmsg_free(mb); slist_iter_remove(iter); /* Warning: moves to next */ } else { break; /* No need to continue on partial copy */ } } slist_iter_free(&iter); return len - remain; }
/** * Discard `n_bytes' from the pmsg_t buffer slist and free all completely * discarded buffers. */ void pmsg_slist_discard(slist_t *slist, size_t n_bytes) { slist_iter_t *iter; g_assert(slist); iter = slist_iter_removable_on_head(slist); while (n_bytes > 0) { pmsg_t *mb; size_t size; g_assert(slist_iter_has_item(iter)); mb = slist_iter_current(iter); pmsg_check_consistency(mb); size = pmsg_size(mb); if (size > n_bytes) { pmsg_discard(mb, n_bytes); break; } else { pmsg_free(mb); n_bytes -= size; slist_iter_remove(iter); } } slist_iter_free(&iter); }
/** * Creates an iovec from a singly-linked list of pmsg_t buffers. * It should be freed via hfree(). * * NOTE: The iovec will hold no more than MAX_IOV_COUNT items. That means * the iovec might not cover the whole buffered data. This limit * is applied because writev() could fail with EINVAL otherwise * which would simply add more unnecessary complexity. */ iovec_t * pmsg_slist_to_iovec(slist_t *slist, int *iovcnt_ptr, size_t *size_ptr) { iovec_t *iov; size_t held = 0; int n; g_assert(slist); n = slist_length(slist); if (n > 0) { slist_iter_t *iter; int i; n = MIN(n, MAX_IOV_COUNT); iov = halloc(n * sizeof *iov); iter = slist_iter_before_head(slist); for (i = 0; i < n; i++) { pmsg_t *mb; size_t size; mb = slist_iter_next(iter); pmsg_check_consistency(mb); size = pmsg_size(mb); g_assert(size > 0); held += size; iovec_set(&iov[i], deconstify_pointer(pmsg_read_base(mb)), size); } slist_iter_free(&iter); } else { iov = NULL; } if (iovcnt_ptr) { *iovcnt_ptr = MAX(0, n); } if (size_ptr) { *size_ptr = held; } return iov; }
/** * Dump field on specified file descriptor. */ static void hfield_dump(const header_field_t *h, FILE *out) { slist_iter_t *iter; bool first; header_field_check(h); g_assert(h->lines); fprintf(out, "%s: ", h->name); first = TRUE; iter = slist_iter_on_head(h->lines); for (/* NOTHING */; slist_iter_has_item(iter); slist_iter_next(iter)) { const char *s; if (first) first = FALSE; else fputs(" ", out); /* Continuation line */ s = slist_iter_current(iter); if (is_printable_iso8859_string(s)) { fputs(s, out); } else { char buf[80]; const char *p = s; int c; size_t len = strlen(s); str_bprintf(buf, sizeof buf, "<%u non-printable byte%s>", (unsigned) len, plural(len)); fputs(buf, out); while ((c = *p++)) { if (is_ascii_print(c) || is_ascii_space(c)) fputc(c, out); else fputc('.', out); /* Less visual clutter than '?' */ } } fputc('\n', out); } slist_iter_free(&iter); }
/** * Returns the size of the data held in the buffer list. */ size_t pmsg_slist_size(const slist_t *slist) { slist_iter_t *iter; size_t size = 0; g_assert(slist != NULL); iter = slist_iter_before_head(slist); while (slist_iter_has_next(iter)) { const pmsg_t *mb; mb = slist_iter_next(iter); pmsg_check_consistency(mb); size += pmsg_size(mb); } slist_iter_free(&iter); return size; }