#include "parse.h" static const size_t max_ssize_t = (((size_t)1) << (sizeof(size_t)*8-1))-1; /* Read an asciiz string from the byte stream, up to len bytes (including the 0 terminator). */ /* Return number of bytes consumed (excluding the 0 terminator), i.e. strlen(dest) */ /* If there is no 0 byte in these len bytes, set error flag in stream and return -1. */ /* Calling this function with len==0 is an error. */ /* destsize will be clamped to the maximum number representable in ssize_t */ ssize_t prs_asciiz(struct bytestream* bs, char* dest, size_t len) { size_t i; /* The maximum value of ssize_t is half that of size_t. * So we arbitrarily decide to limit len to it here. */ if (len>max_ssize_t) len=max_ssize_t; if (len==0) { bs->cur = 1; // mark bytestream state as erroneous bs->max = 0; return -1; } for (i=0; i+1cur<=bs->max) ? (ssize_t)i : -1; } /* if we get here, we read len-1 bytes and there was no 0 byte. */ if ((dest[i] = bs_peek(bs))) { // the loop went till i+1cur = 1; bs->max = 0; // but still write 0 terminator to dest dest[i] = 0; return -1; } else { bs_get(bs); // the next byte was 0, so consume it return i; } } #ifdef UNITTEST #include #undef UNITTEST #include "buffer/bs_init_membuf.c" #include "buffer/bs_get.c" #include "buffer/bs_err.c" #include "buffer/bs_peek.c" // we use membuf here, mock buffer stuff away ssize_t buffer_getc(buffer* b,char* x) { return 0; } ssize_t buffer_peekc(buffer* b,char* x) { return 0; } int main() { struct bytestream bs = BS_FROM_MEMBUF("fnord\n\0x",8); char buf[100]; assert(prs_asciiz(&bs, buf, sizeof buf) == 6); // return value should be strlen("fnord\n") assert(!memcmp(buf,"fnord\n",7)); // returned string should be "fnord\n" with 0 terminator assert(bs_get(&bs) == 'x'); // should have consumed the 0 terminator from bytestream bs_init_membuf(&bs, "fnord\n\0x", 8); assert(prs_asciiz(&bs, buf, 5) == -1); // no 0 terminator in first 5 bytes, expect error assert(!memcmp(buf,"fnor",5)); // expect 4 bytes + 0 terminator in dest buf assert(bs_err(&bs)); // bytestream should be in error state now } #endif