Last active
August 29, 2015 13:56
-
-
Save aktau/9206304 to your computer and use it in GitHub Desktop.
aktau C-style
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This file is part of neovim. | |
* | |
* (c) 2014 The neovim authors | |
* | |
* For the full copyright and license information, please view the LICENSE | |
* file that was distributed with the source code. | |
* | |
* It might be handy to define a few macro's for early quit, which could save a | |
* lot of lines. Many projects define such things and it increases readability if | |
* used judiciously. Though I can understand how people are against it as well. | |
* | |
* These can be based on Zed Shaw's macros: http://c.learncodethehardway.org/book/ex20.html | |
*/ | |
#include <string.h> | |
#include "zmalloc.h" /* zmalloc from redis */ | |
struct buffer { | |
size_t length; | |
size_t capacity; | |
char *memory; | |
}; | |
/* clears the buffer | |
* | |
* returns 1 for succes, an error code otherwise */ | |
static int bufClear(struct buffer *buf) { | |
/* early exit */ | |
if (buffer == NULL) { | |
return -ENULL; | |
} | |
/* just set the length to zero, then we don't have to | |
* clear the memory. */ | |
buf->length = 0; | |
return 1; | |
} | |
/* ensures `buf` has enough space to store `size` bytes | |
* | |
* returns the allocated size on succes, an error code otherwise */ | |
static int bufEnsureSpace(struct buffer *buf, size_t size) { | |
if (buf == NULL) { | |
return -ENULL; | |
} | |
/* if the buffer already has enough capacity, just return */ | |
if (buf->capacity > size) { | |
return 1; | |
} | |
const size_t adjsize = size * 1.61; | |
buf->memory = zrealloc(buf->memory, adjsize); | |
if (buf->memory == NULL) { | |
return -ENOMEM; | |
} | |
buf->capacity = adjsize; | |
return adjsize; | |
} | |
/* will split buffer `orig` into `orig` and `other`. | |
* | |
* returns 1 for succes, an error code otherwise */ | |
static int bufSplitInPLace(struct buffer *orig, struct buffer *other) { | |
if (orig == NULL || other == NULL) { | |
return -ENULL; | |
} | |
const size_t halfLength = orig->length / 2; | |
const size_t restLength = orig->length - halfLength; | |
/* ensure sufficient space */ | |
int ensure = bufEnsureSpace(other, halfLength); | |
if (ensure <= 0) { | |
return ensure; | |
} | |
/* copy second half of `orig` into `other` */ | |
memcpy(other->memory, orig->memory + halfLength, restLength); | |
other->length = restLength; | |
/* truncate the original */ | |
orig->length = halfLength; | |
return 1; | |
} | |
/* returns 1 for success, an error code for failure */ | |
static int parseCommand(const char *cmd, size_t len) { | |
int ok = 1; | |
size_t pos = 0; | |
while (pos != len) { | |
ASSERT(pos <= len); /* this should catch some potential bugs */ | |
char symb = cmd[pos]; | |
switch (symb) { | |
case ':': | |
/* just a regular :-command */ | |
if (haveScripting) { | |
/* pass to the scripting engine first */ | |
} | |
else { | |
/* handle internally */ | |
} | |
break; | |
case '@': | |
/* oh, it's an @-command! */ | |
break; | |
} | |
++pos; | |
} | |
return ok; | |
} | |
/* macro'd version, a disadvantage is that it's macro, an advantage is that is flattens | |
* a lot of code. */ | |
/* returns the error code if there is an error */ | |
#define RETURN_ERROR(val) \ | |
do {\ | |
if ((val) <= 0) { \ | |
return (val); \ | |
} \ | |
} while (0); | |
/* returns `val` if `cond` is true */ | |
#define RETURN_COND(cond, val) \ | |
do {\ | |
if ((cond)) { \ | |
return (val); \ | |
} \ | |
} while (0); | |
/* jumps to the error handling code if there is an error */ | |
#define HANDLE_ERROR(val) \ | |
do {\ | |
if ((val) <= 0) { \ | |
goto error; \ | |
} \ | |
} while (0); | |
/* clears the buffer | |
* | |
* returns 1 for succes, an error code otherwise */ | |
static int bufClear(struct buffer *buf) { | |
RETURN_COND(buffer == NULL, -ENULL); | |
/* just set the length to zero, then we don't have to | |
* clear the memory. */ | |
buf->length = 0; | |
return 1; | |
} | |
/* ensures `buf` has enough space to store `size` bytes | |
* | |
* returns the allocated size on succes, an error code otherwise */ | |
static int bufEnsureSpace(struct buffer *buf, size_t size) { | |
RETURN_COND(buffer == NULL, -ENULL); /* NULL check */ | |
RETURN_COND(buf->capacity > size, 1); /* if the buffer already has enough capacity, return success */ | |
const size_t adjsize = size * 1.61; | |
buf->memory = zrealloc(buf->memory, adjsize); | |
RETURN_COND(buf->memory == NULL, -ENOMEM); /* couldn't alloc */ | |
buf->capacity = adjsize; | |
return adjsize; | |
} | |
/* will split buffer `orig` into `orig` and `other`. | |
* | |
* returns 1 for succes, an error code otherwise */ | |
static int bufSplitInPLace(struct buffer *orig, struct buffer *other) { | |
RETURN_COND(buffer == NULL || other == NULL, -ENULL); /* NULL check */ | |
const size_t halfLength = orig->length / 2; | |
const size_t restLength = orig->length - halfLength; | |
/* ensure sufficient space */ | |
int ensure = bufEnsureSpace(other, halfLength); | |
RETURN_ERROR(ensure); | |
/* copy second half of `orig` into `other` */ | |
memcpy(other->memory, orig->memory + halfLength, restLength); | |
other->length = restLength; /* set the copied length */ | |
orig->length = halfLength; /* truncate the original */ | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment