Skip to content

Commit

Permalink
Inline function calls
Browse files Browse the repository at this point in the history
  • Loading branch information
guillermocalvo committed Sep 28, 2017
1 parent f667b08 commit ae4d8bd
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 134 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "fmt",
"version": "1.0",
"version": "1.1",
"description": "A tiny C string formatting library",
"repo": "guillermocalvo/fmt",
"license": "LGPL",
Expand Down
243 changes: 111 additions & 132 deletions src/fmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* fmt source code file
*
* @version 1.0
* @version 1.1
* @author Copyright (c) 2017 Guillermo Calvo
*
*/
Expand Down Expand Up @@ -44,11 +44,11 @@
# define SKIP_NUMBERS(PTR) while( IS_NUMBER(*(PTR)) ) (PTR)++

# define PRINT_BUILTIN(OUT, PARAM, ARG, POP) ( \
param->flag_width && param->flag_precision ? \
fmt_print_builtin((OUT), (PARAM)->buffer, va_arg(*(ARG), int), va_arg(*(ARG), int), POP) : \
param->flag_width || param->flag_precision ? \
fmt_print_builtin((OUT), (PARAM)->buffer, va_arg(*(ARG), int), POP) : \
fmt_print_builtin((OUT), (PARAM)->buffer, POP) \
PARAM.flag_width && PARAM.flag_precision ? \
fmt_print_builtin((OUT), PARAM.buffer, va_arg(*(ARG), int), va_arg(*(ARG), int), POP) : \
PARAM.flag_width || PARAM.flag_precision ? \
fmt_print_builtin((OUT), PARAM.buffer, va_arg(*(ARG), int), POP) : \
fmt_print_builtin((OUT), PARAM.buffer, POP) \
)

enum fmt_boolean { FMT_FALSE = 0, FMT_TRUE = 1 };
Expand Down Expand Up @@ -123,139 +123,73 @@ int fmt_register_formatter(fmt_formatter formatter, const char * id){
return(FMT_FALSE);
}

/** Find the registered handler by id */
static inline struct fmt_handler * fmt_find_handler(const char * id){

int hash = HASH(id);
struct fmt_handler * handler;
/** Parse next parameter */
static inline int fmt_next_param(const char * format, struct fmt_param * param){

for(handler = handlers; handler < &handlers[FMT_MAX_FORMATTERS]; handler++){
if(handler->hash == hash && strcmp(handler->id, id) == 0){
return(handler);
}
}
for(param->begin = strchr(format, PARAM_MARK); param->begin != NULL; param->begin = strchr(param->begin + 1, PARAM_MARK)){

return(NULL);
}
if(param->begin[1] == PARAM_BEGIN){
/* Parse extended parameter */
size_t length = 0;

/** Print builtin parameter */
static inline int fmt_print_builtin_param(struct fmt_stream * out, struct fmt_param * param, va_list * arg){
param->end = strchr(param->begin + 2, PARAM_END);

int written = FMT_ERROR;
/* check length */
length = (param->end != NULL ? param->end - param->begin - 2 : 0);
if( length > 0 && length < sizeof(param->buffer) ){

switch(param->type){
case TYPE_INT:
switch(param->length){
case LENGTH_L: written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, long int)); break;
case LENGTH_LL: written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, LONG_LONG_INT)); break;
case LENGTH_J: written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, intmax_t)); break;
case LENGTH_Z: written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, size_t)); break;
case LENGTH_T: written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, ptrdiff_t)); break;
default: written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, int)); break;
}
break;
case TYPE_DOUBLE:
if( param->length == LENGTH_L_UC ){
written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, long double));
}else{
written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, double) );
memcpy(param->buffer, param->begin + 2, length);
param->buffer[length] = '\0';
param->options = strchr(param->buffer, PARAM_OPTIONS);
if(param->options != NULL){
*param->options = '\0';
param->options++;
}
param->id = param->buffer;
return(FMT_TRUE);
}
break;
case TYPE_POINTER: written = PRINT_BUILTIN(out, param, arg, va_arg(*arg, void *) ); break;
case TYPE_PERCENT: written = PRINT_BUILTIN(out, param, arg, 0); break;
}

return(written);
}
}else{
/* Parse builtin parameter */
const char * tmp = param->begin + 1;
size_t length;

/** Print extended parameter */
static inline int fmt_print_extended_param(struct fmt_stream * out, struct fmt_param * param, va_list * arg){

struct fmt_handler * handler = fmt_find_handler(param->id);

if(handler == NULL){
(void)fmt_print_builtin(out, "%s@%p", param->id, va_arg(*arg, void *));
return(FMT_ERROR);
}

return( handler->formatter(out, param->id, param->options, arg) );
}

/** Parse builtin parameter */
static inline enum fmt_boolean fmt_builtin_param(struct fmt_param * param){

const char * tmp = param->begin + 1;
size_t length;

/* skip flags */
while(*tmp == '-' || *tmp == '+' || *tmp == ' ' || *tmp == '#' || *tmp == '0'){
tmp++;
}
/* skip minimum field width */
if(( param->flag_width = (*tmp == '*') )){ tmp++; }else{ SKIP_NUMBERS(tmp); }
/* skip precision */
if(*tmp == '.'){
if(( param->flag_precision = (*++tmp == '*') )){ tmp++; }else{ SKIP_NUMBERS(tmp); }
}
/* length modifier */
switch(*tmp){
case 'h': tmp++; if(*tmp == 'h'){ tmp++; param->length = LENGTH_HH; }else{ param->length = LENGTH_H; } break;
case 'l': tmp++; if(*tmp == 'l'){ tmp++; param->length = LENGTH_LL; }else{ param->length = LENGTH_L; } break;
case 'j': tmp++; param->length = LENGTH_J; break;
case 'z': tmp++; param->length = LENGTH_Z; break;
case 't': tmp++; param->length = LENGTH_T; break;
case 'L': tmp++; param->length = LENGTH_L_UC; break;
default: param->length = LENGTH_DEFAULT;
}
/* conversion specifier */
switch(*tmp){
case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'c': param->type = TYPE_INT; break;
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': param->type = TYPE_DOUBLE; break;
case 's': case 'p': case 'n': param->type = TYPE_POINTER; break;
case '%': param->type = TYPE_PERCENT; break;
default: return(FMT_FALSE);
}
/* check length */
length = (tmp - param->begin + 1);
if( length >= sizeof(param->buffer) ){ return(FMT_FALSE); }
/* return builtin parameter */
memcpy(param->buffer, param->begin, length);
param->buffer[length] = '\0';
param->end = tmp;
param->id = NULL;
return(FMT_TRUE);
}

/** Parse extended parameter */
static inline enum fmt_boolean fmt_extended_param(struct fmt_param * param){

size_t length = 0;

param->end = strchr(param->begin + 2, PARAM_END);

/* check length */
length = (param->end != NULL ? param->end - param->begin - 2 : 0);
if( length > 0 && length < sizeof(param->buffer) ){

memcpy(param->buffer, param->begin + 2, length);
param->buffer[length] = '\0';
param->options = strchr(param->buffer, PARAM_OPTIONS);
if(param->options != NULL){
*param->options = '\0';
param->options++;
}
param->id = param->buffer;
return(FMT_TRUE);
}

return(FMT_FALSE);
}

/** Parse next parameter */
static inline int fmt_next_param(const char * format, struct fmt_param * param){

for(param->begin = strchr(format, PARAM_MARK); param->begin != NULL; param->begin = strchr(param->begin + 1, PARAM_MARK)){
if( (param->begin[1] == PARAM_BEGIN ? fmt_extended_param : fmt_builtin_param)(param) ){
/* skip flags */
while(*tmp == '-' || *tmp == '+' || *tmp == ' ' || *tmp == '#' || *tmp == '0'){
tmp++;
}
/* skip minimum field width */
if(( param->flag_width = (*tmp == '*') )){ tmp++; }else{ SKIP_NUMBERS(tmp); }
/* skip precision */
if(*tmp == '.'){
if(( param->flag_precision = (*++tmp == '*') )){ tmp++; }else{ SKIP_NUMBERS(tmp); }
}
/* length modifier */
switch(*tmp){
case 'h': tmp++; if(*tmp == 'h'){ tmp++; param->length = LENGTH_HH; }else{ param->length = LENGTH_H; } break;
case 'l': tmp++; if(*tmp == 'l'){ tmp++; param->length = LENGTH_LL; }else{ param->length = LENGTH_L; } break;
case 'j': tmp++; param->length = LENGTH_J; break;
case 'z': tmp++; param->length = LENGTH_Z; break;
case 't': tmp++; param->length = LENGTH_T; break;
case 'L': tmp++; param->length = LENGTH_L_UC; break;
default: param->length = LENGTH_DEFAULT;
}
/* conversion specifier */
switch(*tmp){
case 'd': case 'i': case 'u': case 'o': case 'x': case 'X': case 'c': param->type = TYPE_INT; break;
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G': case 'a': case 'A': param->type = TYPE_DOUBLE; break;
case 's': case 'p': case 'n': param->type = TYPE_POINTER; break;
case '%': param->type = TYPE_PERCENT; break;
default: return(FMT_FALSE);
}
/* check length */
length = (tmp - param->begin + 1);
if( length >= sizeof(param->buffer) ){ return(FMT_FALSE); }
/* return builtin parameter */
memcpy(param->buffer, param->begin, length);
param->buffer[length] = '\0';
param->end = tmp;
param->id = NULL;
return(FMT_TRUE);
}
}
Expand All @@ -281,7 +215,52 @@ int fmt_vprint(struct fmt_stream * out, const char * format, va_list * arg){
if(result == FMT_ERROR){ return(FMT_ERROR); }else{ written += result; }
}

result = (param.id == NULL ? fmt_print_builtin_param : fmt_print_extended_param)(out, &param, arg);
if(param.id == NULL){
/* print builtin parameter */
result = FMT_ERROR;

switch(param.type){
case TYPE_INT:
switch(param.length){
case LENGTH_L: result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, long int)); break;
case LENGTH_LL: result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, LONG_LONG_INT)); break;
case LENGTH_J: result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, intmax_t)); break;
case LENGTH_Z: result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, size_t)); break;
case LENGTH_T: result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, ptrdiff_t)); break;
default: result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, int)); break;
}
break;
case TYPE_DOUBLE:
if( param.length == LENGTH_L_UC ){
result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, long double));
}else{
result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, double) );
}
break;
case TYPE_POINTER: result = PRINT_BUILTIN(out, param, arg, va_arg(*arg, void *) ); break;
case TYPE_PERCENT: result = PRINT_BUILTIN(out, param, arg, 0); break;
}

}else{
/* print extended parameter */
struct fmt_handler * handler = NULL;
int hash = HASH(param.id);

/* find registered handler by id */
for(handler = handlers; handler < &handlers[FMT_MAX_FORMATTERS]; handler++){
if(handler->hash == hash && strcmp(handler->id, param.id) == 0){
break;
}
}

if(handler < &handlers[FMT_MAX_FORMATTERS]){
result = handler->formatter(out, param.id, param.options, arg);
}else{
(void)fmt_print_builtin(out, "%s@%p", param.id, va_arg(*arg, void *));
result = FMT_ERROR;
}
}

if(result == FMT_ERROR){ return(FMT_ERROR); }else{ written += result; }

format = param.end + 1;
Expand Down
2 changes: 1 addition & 1 deletion src/fmt.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*
* fmt header file
*
* @version 1.0
* @version 1.1
* @author Copyright (c) 2017 Guillermo Calvo
*
*/
Expand Down

0 comments on commit ae4d8bd

Please sign in to comment.