first commit
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include "defs.h"
|
||||
#include "bpalloc.h"
|
||||
|
||||
#if USING_VALGRIND
|
||||
#include <valgrind/memcheck.h>
|
||||
#endif
|
||||
|
||||
#define CHUNK_SIZE 4096
|
||||
#define PADDING 8
|
||||
|
||||
typedef struct BPAllocChunk BPAllocChunk;
|
||||
struct BPAllocChunk {
|
||||
BPAllocChunk *prev;
|
||||
char body[];
|
||||
};
|
||||
|
||||
struct xBPAlloc {
|
||||
int flags;
|
||||
void *userp;
|
||||
void *(*fn_malloc)(void *userp, int size);
|
||||
void (*fn_free )(void *userp, void *addr);
|
||||
int minsize, size, used;
|
||||
BPAllocChunk *tail;
|
||||
};
|
||||
|
||||
enum {
|
||||
FG_STATIC = 1,
|
||||
};
|
||||
|
||||
static void *default_fn_malloc(void *userp, int size);
|
||||
static void default_fn_free (void *userp, void *addr);
|
||||
|
||||
BPAlloc *BPAlloc_Init(int chunk_size)
|
||||
{
|
||||
return BPAlloc_Init2(-1, chunk_size, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
BPAlloc *BPAlloc_Init2(int first_size, int chunk_size,
|
||||
void *userp,
|
||||
void *(*fn_malloc)(void *userp, int size),
|
||||
void (*fn_free )(void *userp, void *addr))
|
||||
{
|
||||
if(chunk_size < 0)
|
||||
chunk_size = CHUNK_SIZE;
|
||||
|
||||
if(first_size < 0)
|
||||
first_size = chunk_size;
|
||||
|
||||
if(fn_malloc == NULL)
|
||||
{
|
||||
userp = NULL;
|
||||
fn_malloc = default_fn_malloc;
|
||||
fn_free = default_fn_free;
|
||||
}
|
||||
|
||||
void *temp = fn_malloc(userp, sizeof(BPAlloc) + sizeof(BPAllocChunk) + first_size + PADDING);
|
||||
|
||||
if(temp == NULL)
|
||||
return NULL;
|
||||
|
||||
BPAlloc *alloc = temp;
|
||||
|
||||
BPAllocChunk *chunk = (BPAllocChunk*) (alloc + 1);
|
||||
chunk->prev = NULL;
|
||||
|
||||
alloc->flags = 0;
|
||||
alloc->used = 0;
|
||||
alloc->size = first_size;
|
||||
alloc->tail = chunk;
|
||||
alloc->minsize = chunk_size;
|
||||
alloc->userp = userp;
|
||||
alloc->fn_malloc = fn_malloc;
|
||||
alloc->fn_free = fn_free;
|
||||
|
||||
#if USING_VALGRIND
|
||||
VALGRIND_CREATE_MEMPOOL(alloc, PADDING, 0);
|
||||
#endif
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
BPAlloc *BPAlloc_Init3(void *mem, int mem_size, int chunk_size,
|
||||
void *userp,
|
||||
void *(*fn_malloc)(void *userp, int size),
|
||||
void (*fn_free )(void *userp, void *addr))
|
||||
{
|
||||
assert(mem != NULL);
|
||||
assert(mem_size >= 0);
|
||||
|
||||
if(chunk_size < 0)
|
||||
chunk_size = CHUNK_SIZE;
|
||||
|
||||
if(fn_malloc == NULL)
|
||||
{
|
||||
userp = NULL;
|
||||
fn_malloc = default_fn_malloc;
|
||||
fn_free = default_fn_free;
|
||||
}
|
||||
|
||||
int required = sizeof(BPAlloc)
|
||||
+ sizeof(BPAllocChunk)
|
||||
+ PADDING;
|
||||
|
||||
if(mem_size < required)
|
||||
// Not enough memory was provided.
|
||||
return NULL;
|
||||
|
||||
BPAlloc *alloc = mem;
|
||||
|
||||
BPAllocChunk *chunk = (BPAllocChunk*) (alloc + 1);
|
||||
chunk->prev = NULL;
|
||||
|
||||
alloc->flags = FG_STATIC;
|
||||
alloc->used = 0;
|
||||
alloc->size = mem_size - sizeof(BPAlloc) - sizeof(BPAllocChunk);
|
||||
alloc->tail = chunk;
|
||||
alloc->minsize = chunk_size;
|
||||
alloc->userp = userp;
|
||||
alloc->fn_malloc = fn_malloc;
|
||||
alloc->fn_free = fn_free;
|
||||
|
||||
#if USING_VALGRIND
|
||||
VALGRIND_CREATE_MEMPOOL(alloc, PADDING, 0);
|
||||
#endif
|
||||
|
||||
return alloc;
|
||||
}
|
||||
|
||||
void BPAlloc_Free(BPAlloc *alloc)
|
||||
{
|
||||
assert(alloc != NULL);
|
||||
|
||||
#if USING_VALGRIND
|
||||
VALGRIND_DESTROY_MEMPOOL(alloc);
|
||||
#endif
|
||||
|
||||
BPAllocChunk *chunk = alloc->tail;
|
||||
|
||||
while(chunk->prev)
|
||||
{
|
||||
BPAllocChunk *prev = chunk->prev;
|
||||
|
||||
if(alloc->fn_free)
|
||||
alloc->fn_free(alloc->userp, chunk);
|
||||
|
||||
chunk = prev;
|
||||
}
|
||||
|
||||
if(!(alloc->flags & FG_STATIC))
|
||||
if(alloc->fn_free)
|
||||
alloc->fn_free(alloc->userp, alloc);
|
||||
}
|
||||
|
||||
void *BPAlloc_Malloc(BPAlloc *alloc, int req_size)
|
||||
{
|
||||
assert(alloc != NULL);
|
||||
assert(req_size >= 0);
|
||||
|
||||
alloc->used += PADDING;
|
||||
|
||||
if(alloc->used & 7)
|
||||
alloc->used = (alloc->used & ~7) + 8;
|
||||
|
||||
if(alloc->used + req_size > alloc->size)
|
||||
{
|
||||
// If the chunk size is lower than the
|
||||
// requested size, then set the chunk
|
||||
// size to the requested size.
|
||||
int chunk_size = MAX(alloc->minsize, req_size + PADDING);
|
||||
|
||||
assert(alloc->fn_malloc != NULL);
|
||||
BPAllocChunk *chunk = alloc->fn_malloc(alloc->userp, sizeof(BPAllocChunk) + chunk_size);
|
||||
|
||||
if(chunk == NULL)
|
||||
return NULL;
|
||||
|
||||
chunk->prev = alloc->tail;
|
||||
alloc->tail = chunk;
|
||||
alloc->size = chunk_size;
|
||||
alloc->used = PADDING;
|
||||
|
||||
if(alloc->used & 7)
|
||||
alloc->used = (alloc->used & ~7) + 8;
|
||||
}
|
||||
|
||||
void *addr = alloc->tail->body + alloc->used;
|
||||
|
||||
assert(((intptr_t) addr) % 8 == 0);
|
||||
|
||||
alloc->used += req_size;
|
||||
|
||||
#if USING_VALGRIND
|
||||
VALGRIND_MEMPOOL_ALLOC(alloc, addr, req_size);
|
||||
// VALGRIND_MAKE_MEM_NOACCESS((char*) addr - PADDING, PADDING);
|
||||
// VALGRIND_MAKE_MEM_NOACCESS((char*) addr + req_size, PADDING);
|
||||
#endif
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
static void *default_fn_malloc(void *userp, int size)
|
||||
{
|
||||
assert(userp == NULL);
|
||||
assert(size >= 0);
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void default_fn_free(void *userp, void *addr)
|
||||
{
|
||||
assert(userp == NULL);
|
||||
|
||||
free(addr);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#ifndef BPALLOC_H
|
||||
#define BPALLOC_H
|
||||
typedef struct xBPAlloc BPAlloc;
|
||||
BPAlloc* BPAlloc_Init(int chunk_size);
|
||||
BPAlloc* BPAlloc_Init2(int first_size, int chunk_size, void *userp, void *(*fn_malloc)(void *userp, int size), void (*fn_free )(void *userp, void *addr));
|
||||
BPAlloc* BPAlloc_Init3(void *mem, int mem_size, int chunk_size, void *userp, void *(*fn_malloc)(void *userp, int size), void (*fn_free )(void *userp, void *addr));
|
||||
void BPAlloc_Free(BPAlloc *alloc);
|
||||
void* BPAlloc_Malloc(BPAlloc *alloc, int req_size);
|
||||
#endif
|
||||
@@ -0,0 +1,177 @@
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "bucketlist.h"
|
||||
#include "defs.h"
|
||||
|
||||
#define MIN_BUCKET_SIZE 4096
|
||||
|
||||
typedef struct Bucket Bucket;
|
||||
struct Bucket {
|
||||
Bucket* next;
|
||||
int size,
|
||||
used,
|
||||
aidx;
|
||||
char body[];
|
||||
};
|
||||
|
||||
struct xBucketList {
|
||||
BPAlloc *alloc;
|
||||
Bucket *head,
|
||||
*tail;
|
||||
int size;
|
||||
};
|
||||
|
||||
BucketList *BucketList_New(BPAlloc *alloc)
|
||||
{
|
||||
assert(alloc != NULL);
|
||||
|
||||
BucketList *blist = BPAlloc_Malloc(alloc, sizeof(BucketList) + sizeof(Bucket) + MIN_BUCKET_SIZE);
|
||||
|
||||
if(blist == NULL)
|
||||
return NULL;
|
||||
|
||||
Bucket *head = (Bucket*) (blist + 1);
|
||||
head->next = NULL;
|
||||
head->size = MIN_BUCKET_SIZE;
|
||||
head->used = 0;
|
||||
head->aidx = 0;
|
||||
|
||||
blist->alloc = alloc;
|
||||
blist->head = head;
|
||||
blist->tail = head;
|
||||
blist->size = 0;
|
||||
return blist;
|
||||
}
|
||||
|
||||
int BucketList_Size(BucketList *blist)
|
||||
{
|
||||
return blist->size;
|
||||
}
|
||||
|
||||
static Bucket *make_bucket(BPAlloc *alloc, int size)
|
||||
{
|
||||
Bucket *new_bucket = BPAlloc_Malloc(alloc, sizeof(Bucket) + size);
|
||||
|
||||
if(new_bucket == NULL)
|
||||
return NULL;
|
||||
|
||||
// Initialize it.
|
||||
new_bucket->next = NULL;
|
||||
new_bucket->size = size;
|
||||
new_bucket->used = 0;
|
||||
new_bucket->aidx = -1;
|
||||
return new_bucket;
|
||||
}
|
||||
|
||||
static void append_bucket(BucketList *blist, Bucket *new_bucket)
|
||||
{
|
||||
new_bucket->aidx = blist->size;
|
||||
blist->tail->next = new_bucket;
|
||||
blist->tail = new_bucket;
|
||||
}
|
||||
|
||||
_Bool BucketList_Append(BucketList *blist, const void *data, int size)
|
||||
{
|
||||
assert(blist != NULL);
|
||||
assert(size >= 0);
|
||||
|
||||
int not_copied_yet = size;
|
||||
|
||||
while(not_copied_yet > 0)
|
||||
{
|
||||
// Copy until there's nothing left
|
||||
// or until the current bucket is
|
||||
// full. If the bucket is already
|
||||
// full, add another one.
|
||||
|
||||
int left_in_bucket = blist->tail->size - blist->tail->used;
|
||||
|
||||
if(left_in_bucket == 0)
|
||||
{
|
||||
Bucket *new_bucket = make_bucket(blist->alloc, MIN_BUCKET_SIZE);
|
||||
|
||||
if(new_bucket == NULL)
|
||||
return 0;
|
||||
|
||||
append_bucket(blist, new_bucket);
|
||||
}
|
||||
|
||||
// Decide how much to copy.
|
||||
int copying = MIN(not_copied_yet, left_in_bucket);
|
||||
|
||||
// Copy into the bucket.
|
||||
{
|
||||
char *dst = blist->tail->body + blist->tail->used;
|
||||
|
||||
if(data == NULL)
|
||||
memset(dst, 0, copying);
|
||||
else
|
||||
memcpy(dst, data + size - not_copied_yet, copying);
|
||||
|
||||
blist->tail->used += copying;
|
||||
}
|
||||
|
||||
not_copied_yet -= copying;
|
||||
}
|
||||
|
||||
blist->size += size;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void *BucketList_Append2(BucketList *blist, const void *data, int size)
|
||||
{
|
||||
assert(blist != NULL);
|
||||
assert(size >= 0);
|
||||
|
||||
// If the data doesn't fit inside the
|
||||
// current bucket, add another one with
|
||||
// enough space.
|
||||
if(blist->tail->used + size > blist->tail->size)
|
||||
{
|
||||
int bucket_size = MAX(MIN_BUCKET_SIZE, size);
|
||||
|
||||
Bucket *new_bucket = make_bucket(blist->alloc, bucket_size);
|
||||
|
||||
if(new_bucket == NULL)
|
||||
return 0;
|
||||
|
||||
append_bucket(blist, new_bucket);
|
||||
}
|
||||
|
||||
void *addr = blist->tail->body + blist->tail->used;
|
||||
|
||||
// Do the copying.
|
||||
if(data == NULL)
|
||||
memset(addr, 0, size);
|
||||
else
|
||||
memcpy(addr, data, size);
|
||||
|
||||
blist->tail->used += size;
|
||||
blist->size += size;
|
||||
return addr;
|
||||
}
|
||||
|
||||
void BucketList_Copy(BucketList *blist, void *dest, int len)
|
||||
{
|
||||
assert(blist != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
if(len < 0)
|
||||
len = blist->size;
|
||||
|
||||
int copied = 0;
|
||||
|
||||
Bucket *bucket = blist->head;
|
||||
|
||||
while(bucket && copied < len)
|
||||
{
|
||||
int copying = MIN(len - copied, bucket->used);
|
||||
assert(copying >= 0);
|
||||
|
||||
memcpy((char*) dest + copied, bucket->body, copying);
|
||||
|
||||
copied += copying;
|
||||
bucket = bucket->next;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef BUCKETLIST_H
|
||||
#define BUCKETLIST_H
|
||||
#include "bpalloc.h"
|
||||
typedef struct xBucketList BucketList;
|
||||
BucketList *BucketList_New(BPAlloc *alloc);
|
||||
int BucketList_Size(BucketList *blist);
|
||||
void BucketList_Copy(BucketList *blist, void *dest, int len);
|
||||
_Bool BucketList_Append (BucketList *blist, const void *data, int size);
|
||||
void *BucketList_Append2(BucketList *blist, const void *data, int size);
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <assert.h>
|
||||
|
||||
#ifndef MAX
|
||||
#define MAX(x, y) ((x) > (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(x, y) ((x) < (y) ? (x) : (y))
|
||||
#endif
|
||||
|
||||
#ifndef NULL
|
||||
#define NULL ((void*) 0)
|
||||
#endif
|
||||
|
||||
#define UNREACHABLE assert(0);
|
||||
|
||||
#define membersizeof(type, member) (sizeof(((type*) 0)->member))
|
||||
@@ -0,0 +1,88 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include "error.h"
|
||||
|
||||
void Error_Init(Error *err)
|
||||
{
|
||||
memset(err, 0, sizeof (Error));
|
||||
}
|
||||
|
||||
void Error_Init2(Error *err, void (*on_report)(Error *err))
|
||||
{
|
||||
memset(err, 0, sizeof (Error));
|
||||
err->on_report = on_report;
|
||||
}
|
||||
|
||||
void Error_Free(Error *err)
|
||||
{
|
||||
if(err->message2 != err->message)
|
||||
free(err->message);
|
||||
memset(err, 0, sizeof (Error));
|
||||
}
|
||||
|
||||
void _Error_Report(Error *err, _Bool internal,
|
||||
const char *file, const char *func, int line,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
_Error_Report2(err, internal, file, func, line, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void _Error_Report2(Error *err, _Bool internal,
|
||||
const char *file, const char *func, int line,
|
||||
const char *fmt, va_list va)
|
||||
{
|
||||
assert(err);
|
||||
assert(file);
|
||||
assert(func);
|
||||
assert(line > 0);
|
||||
assert(fmt);
|
||||
assert(err->occurred == 0);
|
||||
|
||||
err->occurred = 1;
|
||||
err->internal = internal;
|
||||
err->file = file;
|
||||
err->func = func;
|
||||
err->line = line;
|
||||
|
||||
va_list va2;
|
||||
va_copy(va2, va);
|
||||
|
||||
int p = vsnprintf(err->message2, sizeof(err->message2), fmt, va);
|
||||
|
||||
assert(p > -1);
|
||||
|
||||
if((unsigned int) p > sizeof(err->message2)-1)
|
||||
{
|
||||
char *temp = malloc(p+1);
|
||||
|
||||
if(temp == NULL)
|
||||
{
|
||||
err->truncated = 1;
|
||||
err->message = err->message2;
|
||||
err->length = sizeof(err->message2)-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(temp, p+1, fmt, va2);
|
||||
err->truncated = 0;
|
||||
err->message = temp;
|
||||
err->length = p;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
err->truncated = 0;
|
||||
err->message = err->message2;
|
||||
err->length = p;
|
||||
}
|
||||
|
||||
va_end(va2);
|
||||
|
||||
if(err->on_report)
|
||||
err->on_report(err);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef ERROR_H
|
||||
#define ERROR_H
|
||||
#include <stdarg.h>
|
||||
|
||||
typedef struct Error Error;
|
||||
|
||||
struct Error {
|
||||
void (*on_report)(Error *err);
|
||||
_Bool occurred,
|
||||
internal,
|
||||
truncated;
|
||||
int length;
|
||||
char* message;
|
||||
char message2[256];
|
||||
const char *file,
|
||||
*func;
|
||||
int line;
|
||||
};
|
||||
|
||||
void Error_Init(Error *err);
|
||||
void Error_Init2(Error *err, void (*on_report)(Error *err));
|
||||
void Error_Free(Error *err);
|
||||
#define Error_Report(err, internal, fmt, ...) _Error_Report(err, internal, __FILE__, __func__, __LINE__, fmt, ## __VA_ARGS__)
|
||||
void _Error_Report (Error *err, _Bool internal, const char *file, const char *func, int line, const char *fmt, ...);
|
||||
void _Error_Report2(Error *err, _Bool internal, const char *file, const char *func, int line, const char *fmt, va_list va);
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#include <stdint.h>
|
||||
#include "hash.h"
|
||||
|
||||
int hashbytes(unsigned char *str, int len)
|
||||
{
|
||||
int x = (intptr_t) str; // just to not use 0.
|
||||
|
||||
x ^= *str << 7;
|
||||
|
||||
for(int i = 0; i < len; i += 1)
|
||||
x = (1000003UL * x) ^ *str++;
|
||||
|
||||
x ^= len;
|
||||
|
||||
if(x == -1)
|
||||
x = -2;
|
||||
|
||||
return x;
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
#ifndef HASH_H
|
||||
#define HASH_H
|
||||
int hashbytes(unsigned char *str, int len);
|
||||
#endif
|
||||
@@ -0,0 +1,106 @@
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include "promise.h"
|
||||
#include "defs.h"
|
||||
|
||||
typedef struct Gap Gap;
|
||||
struct Gap {
|
||||
Gap *next;
|
||||
void *dest;
|
||||
void *userp;
|
||||
void (*callback)(void*);
|
||||
};
|
||||
|
||||
struct xPromise {
|
||||
BPAlloc *alloc;
|
||||
_Bool set;
|
||||
Gap *gaps;
|
||||
int size;
|
||||
char body[];
|
||||
};
|
||||
|
||||
Promise *Promise_New(BPAlloc *alloc, int size)
|
||||
{
|
||||
assert(alloc != NULL);
|
||||
assert(size >= 0);
|
||||
|
||||
Promise *promise = BPAlloc_Malloc(alloc, sizeof(Promise) + size);
|
||||
|
||||
if(promise == NULL)
|
||||
return NULL;
|
||||
|
||||
promise->alloc = alloc;
|
||||
promise->set = 0;
|
||||
promise->gaps = NULL;
|
||||
promise->size = size;
|
||||
return promise;
|
||||
}
|
||||
|
||||
unsigned int Promise_Size(Promise *promise)
|
||||
{
|
||||
return promise->size;
|
||||
}
|
||||
|
||||
void Promise_Delete(Promise *promise)
|
||||
{
|
||||
assert(promise->set == 1);
|
||||
}
|
||||
|
||||
void Promise_Resolve(Promise *promise, const void *data, int size)
|
||||
{
|
||||
assert(size >= 0);
|
||||
assert(size == promise->size);
|
||||
assert(promise->set == 0);
|
||||
|
||||
memcpy(promise->body, data, size);
|
||||
promise->set = 1;
|
||||
|
||||
Gap *gap = promise->gaps;
|
||||
while(gap)
|
||||
{
|
||||
memcpy(gap->dest, data, size);
|
||||
|
||||
if(gap->callback)
|
||||
gap->callback(gap->userp);
|
||||
|
||||
gap = gap->next;
|
||||
}
|
||||
|
||||
promise->gaps = NULL;
|
||||
}
|
||||
|
||||
_Bool Promise_Subscribe(Promise *promise, void *dest)
|
||||
{
|
||||
assert(promise != NULL);
|
||||
assert(dest != NULL);
|
||||
return Promise_Subscribe2(promise, dest, NULL, NULL);
|
||||
}
|
||||
|
||||
_Bool Promise_Subscribe2(Promise *promise, void *dest, void *userp, void (*callback)(void*))
|
||||
{
|
||||
assert(promise != NULL);
|
||||
assert(dest != NULL);
|
||||
|
||||
if(promise->set == 0)
|
||||
{
|
||||
Gap *gap = BPAlloc_Malloc(promise->alloc, sizeof(Gap));
|
||||
|
||||
if(gap == NULL)
|
||||
return 0;
|
||||
|
||||
gap->next = promise->gaps;
|
||||
gap->dest = dest;
|
||||
gap->userp = userp;
|
||||
gap->callback = callback;
|
||||
promise->gaps = gap;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(dest, promise->body, promise->size);
|
||||
|
||||
if(callback)
|
||||
callback(userp);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef PROMISE_H
|
||||
#define PROMISE_H
|
||||
#include "bpalloc.h"
|
||||
typedef struct xPromise Promise;
|
||||
Promise *Promise_New(BPAlloc *alloc, int size);
|
||||
unsigned int Promise_Size(Promise *promise);
|
||||
void Promise_Delete(Promise *promise);
|
||||
void Promise_Resolve(Promise *promise, const void *data, int size);
|
||||
_Bool Promise_Subscribe(Promise *promise, void *dest);
|
||||
_Bool Promise_Subscribe2(Promise *promise, void *dest, void *userp, void (*callback)(void*));
|
||||
#endif
|
||||
@@ -0,0 +1,160 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "source.h"
|
||||
|
||||
struct xSource {
|
||||
char *name;
|
||||
char *body;
|
||||
int size;
|
||||
int refs;
|
||||
};
|
||||
|
||||
Source *Source_Copy(Source *s)
|
||||
{
|
||||
s->refs += 1;
|
||||
return s;
|
||||
}
|
||||
|
||||
void Source_Free(Source *s)
|
||||
{
|
||||
s->refs -= 1;
|
||||
assert(s->refs >= 0);
|
||||
|
||||
if(s->refs == 0)
|
||||
free(s);
|
||||
}
|
||||
|
||||
const char *Source_GetName(const Source *s)
|
||||
{
|
||||
return s->name;
|
||||
}
|
||||
|
||||
const char *Source_GetBody(const Source *s)
|
||||
{
|
||||
return s->body;
|
||||
}
|
||||
|
||||
unsigned int Source_GetSize(const Source *s)
|
||||
{
|
||||
return s->size;
|
||||
}
|
||||
|
||||
Source *Source_FromFile(const char *file, Error *error)
|
||||
{
|
||||
assert(file != NULL);
|
||||
|
||||
// Open the file and get it's size.
|
||||
// at the end of the block, the file
|
||||
// cursor will point at the start of
|
||||
// the file.
|
||||
FILE *fp;
|
||||
int size;
|
||||
{
|
||||
fp = fopen(file, "rb");
|
||||
|
||||
if(fp == NULL)
|
||||
{
|
||||
if(errno == ENOENT)
|
||||
Error_Report(error, 0, "File \"%s\" doesn't exist", file);
|
||||
else
|
||||
Error_Report(error, 1, "Call to fopen failed (%s, errno = %d)", strerror(errno), errno);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(fseek(fp, 0, SEEK_END))
|
||||
{
|
||||
Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno);
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size = ftell(fp);
|
||||
|
||||
if(size < 0)
|
||||
{
|
||||
Error_Report(error, 1, "Call to ftell failed (%s, errno = %d)", strerror(errno), errno);
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(fseek(fp, 0, SEEK_END))
|
||||
{
|
||||
Error_Report(error, 1, "Call to fseek failed (%s, errno = %d)", strerror(errno), errno);
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate the source structure.
|
||||
Source *s;
|
||||
{
|
||||
int namel = strlen(file);
|
||||
|
||||
s = malloc(sizeof(Source) + namel + size + 2);
|
||||
|
||||
if(s == NULL)
|
||||
{
|
||||
Error_Report(error, 1, "No memory");
|
||||
fclose(fp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->name = (char*) (s + 1);
|
||||
s->body = s->name + namel + 1;
|
||||
}
|
||||
|
||||
// Copy the name into it.
|
||||
strcpy(s->name, file);
|
||||
s->size = size;
|
||||
s->refs = 1;
|
||||
|
||||
// Now copy the file contents into it.
|
||||
{
|
||||
int p = fread(s->body, 1, size, fp);
|
||||
|
||||
if(p != size)
|
||||
{
|
||||
Error_Report(error, 1, "Call to fread failed, %d bytes out of %d were read (%s, errno = %d)", p, size, strerror(errno), errno);
|
||||
fclose(fp);
|
||||
free(s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
s->body[s->size] = '\0';
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return s;
|
||||
}
|
||||
|
||||
Source *Source_FromString(const char *name, const char *body, int size, Error *error)
|
||||
{
|
||||
assert(body != NULL);
|
||||
|
||||
if(size < 0)
|
||||
size = strlen(body);
|
||||
|
||||
int namel = name ? strlen(name) : 0;
|
||||
|
||||
void *memory = malloc(sizeof(Source) + namel + size + 2);
|
||||
|
||||
if(memory == NULL)
|
||||
{
|
||||
Error_Report(error, 1, "No memory");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Source *s = memory;
|
||||
s->name = (char*) (s + 1);
|
||||
s->body = s->name + namel + 1;
|
||||
s->size = size;
|
||||
s->refs = 1;
|
||||
|
||||
if(name)
|
||||
strcpy(s->name, name);
|
||||
strncpy(s->body, body, size);
|
||||
return s;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#ifndef SOURCE_H
|
||||
#define SOURCE_H
|
||||
#include "error.h"
|
||||
typedef struct xSource Source;
|
||||
Source *Source_Copy(Source *s);
|
||||
void Source_Free(Source *s);
|
||||
const char *Source_GetName(const Source *s);
|
||||
const char *Source_GetBody(const Source *s);
|
||||
unsigned int Source_GetSize(const Source *s);
|
||||
Source *Source_FromFile(const char *file, Error *error);
|
||||
Source *Source_FromString(const char *name, const char *body, int size, Error *error);
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
#include <stdlib.h>
|
||||
#include "stack.h"
|
||||
#include "defs.h"
|
||||
|
||||
struct xStack {
|
||||
unsigned int size, used;
|
||||
void *body[];
|
||||
};
|
||||
|
||||
void *Stack_New(int size)
|
||||
{
|
||||
if(size < 0)
|
||||
size = 1024;
|
||||
|
||||
Stack *s = malloc(sizeof(Stack) + sizeof(void*) * size);
|
||||
|
||||
if(s == NULL)
|
||||
return NULL;
|
||||
|
||||
s->size = size;
|
||||
s->used = 0;
|
||||
return s;
|
||||
}
|
||||
|
||||
void *Stack_Top(Stack *s, int n)
|
||||
{
|
||||
assert(n <= 0);
|
||||
|
||||
if(s->used == 0)
|
||||
return NULL;
|
||||
|
||||
if((int) s->used + n - 1 < 0)
|
||||
return NULL;
|
||||
|
||||
return s->body[s->used + n - 1];
|
||||
}
|
||||
|
||||
_Bool Stack_Pop(Stack *s, unsigned int n)
|
||||
{
|
||||
if(s->used < n)
|
||||
return 0;
|
||||
|
||||
s->used -= n;
|
||||
return 1;
|
||||
}
|
||||
|
||||
_Bool Stack_Push(Stack *s, void *item)
|
||||
{
|
||||
assert(s != NULL);
|
||||
assert(item != NULL);
|
||||
|
||||
if(s->used == s->size)
|
||||
return 0;
|
||||
|
||||
s->body[s->used] = item;
|
||||
s->used += 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Stack_Free(Stack *s)
|
||||
{
|
||||
free(s);
|
||||
}
|
||||
|
||||
unsigned int Stack_Size(Stack *s)
|
||||
{
|
||||
return s->used;
|
||||
}
|
||||
|
||||
unsigned int Stack_Capacity(Stack *s)
|
||||
{
|
||||
return s->size;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef STACK_H
|
||||
#define STACK_H
|
||||
typedef struct xStack Stack;
|
||||
void *Stack_New(int size);
|
||||
void *Stack_Top(Stack *s, int n);
|
||||
_Bool Stack_Pop(Stack *s, unsigned int n);
|
||||
_Bool Stack_Push(Stack *s, void *item);
|
||||
void Stack_Free(Stack *s);
|
||||
unsigned int Stack_Size(Stack *s);
|
||||
unsigned int Stack_Capacity(Stack *s);
|
||||
#endif
|
||||
Reference in New Issue
Block a user