-
-/* rand_upto_inclusive_
- Room for improvement: constrain bits of randomness consumed, based on #limit
- also maybe read chunks of randomness at a time
- */
-static
-unsigned long rand_upto_inclusive_(unsigned long limit) {
- unsigned long randomness;
-
- if (limit == 0)
- return 0;
-
- if (rand_fd_ != -1) {
- ssize_t len;
-
- len = read(rand_fd_, &randomness, sizeof randomness);
- if (len == sizeof randomness) {
- randomness %= limit + 1;
-
- return randomness;
- }
- NOTIFY_ERROR("%s(%d, %zu):%zd:%s", "read", rand_fd_, sizeof randomness, len, (len < 0) ? strerror(errno) : ( (len == 0) ? "EOF" : "not enough read consecutively") );
- }
-
- /* fall back to dumb randomness */
- randomness = mrand48();
- randomness %= limit + 1;
-
- return randomness;
-}
-
-
-static
-int rand_init_(char *rand_file) {
- srand48(time(NULL) ^ getpid());
- if (rand_file) {
- rand_fd_ = open(rand_file, O_RDONLY);
- if (rand_fd_ == -1) {
- NOTIFY_ERROR("%s('%s'):%s", "open", rand_file, strerror(errno));
- return -1;
- }
- }
- return 0;
-}
-
-
-static
-buf_t buf_new_(size_t sz) {
- buf_t buf = malloc(sz + sizeof *buf);
- if (buf) {
- buf->buf_sz = sz;
- buf->buf_start = buf->buf_used = 0;
- memset(buf->buf, 0, sz);
- }
- return buf;
-}
-
-
-static
-void buf_rebase_(buf_t buf) {
- if (buf->buf_start == 0)
- return;
- memmove(buf->buf, buf->buf + buf->buf_start, buf->buf_used);
- buf->buf_start = 0;
-}
-
-
-static
-int buf_makeroom_(buf_t *pbuf, size_t roomfor) {
- size_t new_sz;
- void *tmp_ptr;
-
- assert(pbuf != NULL);
-
- if (*pbuf == NULL) {
- *pbuf = buf_new_(roomfor);
- if (*pbuf == NULL) {
- return -1;
- }
- }
-
- buf_rebase_(*pbuf);
-
- if (BUF_ROOM(*pbuf) >= roomfor)
- return 0;
-
- new_sz = (*pbuf)->buf_used + roomfor;
- tmp_ptr = realloc(*pbuf, new_sz + sizeof **pbuf);
- if (tmp_ptr == NULL) {
- NOTIFY_ERROR("%s:%s", "realloc", strerror(errno));
- return -1;
- }
- *pbuf = tmp_ptr;
- (*pbuf)->buf_sz = new_sz;
-
- return 0;
-}
-
-
-static
-int buf_range_dup_or_append_(buf_t src, size_t src_skip, size_t n, buf_t *dst) {
- assert(src != NULL);
- assert(dst != NULL);
- assert(src_skip + n <= src->buf_used);
-
- if (buf_makeroom_(dst, n)) {
- return -1;
- }
-
- memcpy((*dst)->buf + (*dst)->buf_used, src->buf + src->buf_start + src_skip, n);
- (*dst)->buf_used += n;
-
- return 0;
-}
-
-
-/* buf_flense_
- Starting after #src_offset characters, scan through #src, stopping at
- the first character matching #delimiter, whereupon all the characters
- leading up to #delimiter are copied into *#dst if #dst is not NULL. #src
- becomes the characters following #delimiter.
- Returns the number of characters flensed from #src.
-
- Room for improvement:
- If flensed segment is more than half the buffer, copy remainder of src
- into dst, then return src, leaving dst in its place.
-*/
-static
-ssize_t buf_flense_(buf_t *src, size_t src_offset, int delimiter, buf_t *dst) {
- const size_t delimiter_len = 1;
- size_t i;
-
- assert(src != NULL);
- assert(src_offset <= (*src)->buf_used);
-
- NOTIFY_DEBUG("src_offset:%zu", src_offset);
- D_BUF("src ", *src);
- D_BUF("dst ", dst ? *dst : NULL);
-
- for (i = src_offset; i < (*src)->buf_used; i++) {
- if ((*src)->buf[(*src)->buf_start + i] == delimiter) {
-
- if (dst != NULL) {
- if (buf_range_dup_or_append_((*src), 0, i, dst)) {
- return -1;
- }
- }
-
- (*src)->buf_start += i + delimiter_len;
- (*src)->buf_used -= i + delimiter_len;
-
- D_BUF("src ", *src);
- D_BUF("dst ", dst ? *dst : NULL);
- return i + delimiter_len;
- }
- }
-
- return 0;
-}
-
-#ifdef TEST
-
-static const char buf_flense_testdata1[] = "a\nbc\ndef\nghij\nklmno\npqr\ns\ntuv\nwxyz0\n1234\n567\n89\n0leftovers";
-static const char buf_flense_testdata2[] = "\n\nfoo\nbar\n\n";
-
-struct buf_flense_expected_result_ {
- ssize_t r;
- const char *buf;
-} buf_flense_expected1[] = {
- { 1 + 1, "a" },
- { 2 + 1, "bc" },
- { 3 + 1, "def" },
- { 4 + 1, "ghij" },
- { 5 + 1, "klmno" },
- { 3 + 1, "pqr" },
- { 1 + 1, "s" },
- { 3 + 1, "tuv" },
- { 5 + 1, "wxyz0" },
- { 4 + 1, "1234" },
- { 3 + 1, "567" },
- { 2 + 1, "89" },
- { 0, "0leftovers" },
-}, buf_flense_expected2[] = {
- { 0 + 1, "" },
- { 0 + 1, "" },
- { 3 + 1, "foo" },
- { 3 + 1, "bar" },
- { 0 + 1, "" },
- { 0, "" },
-};
-
-struct test_buf_flense_data_ {
- const char *src;
- const struct buf_flense_expected_result_ *expected;
-} test_buf_flense_data1 = {
- .src = buf_flense_testdata1,
- .expected = buf_flense_expected1,
-}, test_buf_flense_data2 = {
- .src = buf_flense_testdata2,
- .expected = buf_flense_expected2,
-};
-
-static int test_buf_flense_(void *test_arg, void *suite_arg) {
- (void)suite_arg;
- struct test_buf_flense_data_ *test_data = (struct test_buf_flense_data_ *)test_arg;
- const char testdata_len = strlen(test_data->src);
- const struct buf_flense_expected_result_ *next_result = test_data->expected;
- int retval = 0;
- buf_t src;
-
- TEST_INFO("initializing src buffer with %zu characters", testdata_len);
- src = buf_new_(testdata_len);
- if (src == NULL) {
- TEST_ERROR("%s:%s", "new_buf_", "failed");
- return -1;
- }
- memcpy(src->buf, test_data->src, testdata_len);
- src->buf_used += testdata_len;
-
- D_BUF("src ", src);
-
- for (;;) {
- ssize_t r;
- buf_t dst = NULL;
-
- r = buf_flense_(&src, 0, '\n', &dst);
- if (r != next_result->r) {
- TEST_ERROR("result '%zd' does not match expected result '%zd'", r, next_result->r);
- retval = -1;
- }
- if (r == 0) {
- TEST_INFO("finished flensing");
- break;
- }
-
- if (strlen(next_result->buf) > dst->buf_used) {
- TEST_ERROR("flensed buffer smaller than expected result '%s'", next_result->buf);
- D_BUF("dst ", dst);
- retval = -1;
- } else if (memcmp(next_result->buf, dst->buf + dst->buf_start, strlen(next_result->buf))) {
- TEST_ERROR("flensed buffer does not match expected result '%s'", next_result->buf);
- D_BUF("dst ", dst);
- retval = -1;
- }
-
- TEST_INFO("flensed: '%.*s'", (int)dst->buf_used, dst->buf + dst->buf_start);
-
- memset(dst, 0, dst->buf_sz + sizeof *dst);
- free(dst);
- dst = NULL;
-
- next_result++;
- }
- if (strlen(next_result->buf) > src->buf_used) {
- TEST_ERROR("remaining buffer smaller than expected result '%s'", next_result->buf);
- D_BUF("src ", src);
- retval = -1;
- } else if (memcmp(next_result->buf, src->buf + src->buf_start, strlen(next_result->buf))) {
- TEST_ERROR("remaining buffer does not match expected result '%s'", next_result->buf);
- D_BUF("src ", src);
- retval = -1;
- }
-
- TEST_INFO("remains: '%.*s'", (int)src->buf_used, src->buf + src->buf_start);
-
- memset(src, 0, src->buf_sz + sizeof *src);
- free(src);
- src = NULL;
-
- return retval;
-}
-#endif /* TEST */
-
-
-/* reservoir_remember_
- Remember #line, forgetting a line if more than #num_lines have already
- been remembered. Remembers them in random order.