92 lines
1.9 KiB
C++
92 lines
1.9 KiB
C++
|
|
#include "io.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
struct IOBlock {
|
|
IOBlock *next;
|
|
ssize_t used, size;
|
|
unsigned char data[];
|
|
};
|
|
|
|
IOBlock* newIOBlock() {
|
|
const ssize_t amount = 512*1024; // avoid fragmentation: 128kb is the standard M_MMAP_THRESHOLD
|
|
IOBlock* b = (IOBlock*) malloc(amount);
|
|
if (!b) abort();
|
|
b->size = amount - sizeof(*b);
|
|
b->used = 0;
|
|
b->next = NULL;
|
|
return b;
|
|
}
|
|
|
|
// frees block list
|
|
static void blocksToVector(IOBlock *blocks, ssize_t total, std::vector<unsigned char> &buf) {
|
|
buf.reserve(std::max<ssize_t>(total+1, 512*1024)); // try forcing mmap
|
|
buf.resize(total);
|
|
(&buf.at(0))[total] = '\0';
|
|
ssize_t pos = 0;
|
|
IOBlock *prev = 0;
|
|
for (IOBlock *cur = blocks; cur; prev = cur, cur = cur->next) {
|
|
free(prev);
|
|
if (cur->used > 0) {
|
|
memcpy(&buf.at(pos), cur->data, cur->used);
|
|
pos += cur->used;
|
|
}
|
|
}
|
|
free(prev);
|
|
}
|
|
|
|
void readAll(int fd, std::vector<unsigned char> &buf) {
|
|
IOBlock *first = newIOBlock();
|
|
IOBlock *cur = first;
|
|
ssize_t total = 0;
|
|
for (;;) {
|
|
ssize_t avail;
|
|
for (;;) {
|
|
avail = cur->size - cur->used;
|
|
if (0 != avail) break;
|
|
cur->next = newIOBlock();
|
|
cur = cur->next;
|
|
}
|
|
|
|
ssize_t len = read(fd, cur->data + cur->used, avail);
|
|
if (0 == len) break; /* eof */
|
|
if (0 > len) {
|
|
perror("read failed");
|
|
abort();
|
|
}
|
|
cur->used += len;
|
|
total += len;
|
|
}
|
|
blocksToVector(first, total, buf);
|
|
}
|
|
|
|
void readLine(int fd, std::vector<unsigned char> &buf) {
|
|
IOBlock *first = newIOBlock();
|
|
IOBlock *cur = first;
|
|
ssize_t total = 0;
|
|
for (;;) {
|
|
if (cur->size == cur->used) {
|
|
cur->next = newIOBlock();
|
|
cur = cur->next;
|
|
}
|
|
|
|
ssize_t len = read(fd, cur->data + cur->used, 1);
|
|
if (0 == len) break; /* eof */
|
|
if (0 > len) {
|
|
perror("read failed");
|
|
abort();
|
|
}
|
|
if (cur->data[cur->used] == '\n' || cur->data[cur->used] == '\r') break;
|
|
cur->used += 1;
|
|
total += 1;
|
|
}
|
|
blocksToVector(first, total, buf);
|
|
}
|